Add train generation and builder for blueprints
This commit is contained in:
parent
3ec2d34f65
commit
6ac0cab8d5
7 changed files with 338 additions and 18 deletions
95
Cargo.lock
generated
95
Cargo.lock
generated
|
|
@ -1,6 +1,6 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
|
|
@ -225,6 +225,31 @@ version = "2.5.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b81e1519b0d82120d2fd469d5bfb2919a9361c48b02d82d04befc1cdd2002452"
|
||||
|
||||
[[package]]
|
||||
name = "bon"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a636f83af97c6946f3f5cf5c268ec02375bf5efd371110292dfd57961f57a509"
|
||||
dependencies = [
|
||||
"bon-macros",
|
||||
"rustversion",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bon-macros"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7eaf1bfaa5b8d512abfd36d0c432591fef139d3de9ee54f1f839ea109d70d33"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"ident_case",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "built"
|
||||
version = "0.7.4"
|
||||
|
|
@ -448,6 +473,41 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"darling_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_core"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||
dependencies = [
|
||||
"fnv",
|
||||
"ident_case",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"strsim",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "darling_macro"
|
||||
version = "0.20.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||
dependencies = [
|
||||
"darling_core",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.13.0"
|
||||
|
|
@ -491,6 +551,7 @@ name = "factorio_blueprint"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bon",
|
||||
"clap 4.5.17",
|
||||
"criterion",
|
||||
"flate2",
|
||||
|
|
@ -609,6 +670,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||
|
||||
[[package]]
|
||||
name = "image"
|
||||
version = "0.25.2"
|
||||
|
|
@ -1029,10 +1096,20 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.86"
|
||||
name = "prettyplease"
|
||||
version = "0.2.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.92"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
|
@ -1282,6 +1359,12 @@ dependencies = [
|
|||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248"
|
||||
|
||||
[[package]]
|
||||
name = "rusty-fork"
|
||||
version = "0.3.0"
|
||||
|
|
@ -1450,9 +1533,9 @@ checksum = "b7401a30af6cb5818bb64852270bb722533397edcfc7344954a38f420819ece2"
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.77"
|
||||
version = "2.0.89"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ harness = false
|
|||
|
||||
[dependencies]
|
||||
base64 = "0.21.5"
|
||||
bon = "3.0.2"
|
||||
clap = { version = "4.4.8", features = ["derive"] }
|
||||
flate2 = "1.0.28"
|
||||
image = "0.25.2"
|
||||
|
|
|
|||
14
examples/train_blueprint.rs
Normal file
14
examples/train_blueprint.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
use factorio_blueprint::blueprint::{train::generate_train, BlueprintString};
|
||||
|
||||
fn main() {
|
||||
let b = generate_train(2, 4, true, true);
|
||||
|
||||
let b = BlueprintString::Blueprint(b);
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&b).unwrap());
|
||||
|
||||
println!(
|
||||
"{}",
|
||||
factorio_blueprint::blueprint::encode(&serde_json::to_string(&b).unwrap())
|
||||
);
|
||||
}
|
||||
29
src/bin/decode_blueprint.rs
Normal file
29
src/bin/decode_blueprint.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
use base64::prelude::*;
|
||||
use clap::Parser;
|
||||
use factorio_blueprint::blueprint::{decode, encode};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
struct Args {
|
||||
filename: PathBuf,
|
||||
#[arg(short, long)]
|
||||
encode: bool,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = Args::parse();
|
||||
|
||||
let s = std::fs::read_to_string(args.filename).unwrap();
|
||||
|
||||
if args.encode {
|
||||
let j: serde_json::Value = serde_json::from_str(&s).unwrap();
|
||||
let d = encode(&serde_json::to_string(&j).unwrap());
|
||||
println!("{}", d);
|
||||
} else {
|
||||
let d = decode(&s);
|
||||
|
||||
let j: serde_json::Value = serde_json::from_str(&d).unwrap();
|
||||
|
||||
println!("{}", serde_json::to_string_pretty(&j).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use base64::Engine;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
|
|
@ -7,11 +8,13 @@ pub mod structs;
|
|||
|
||||
pub use structs::*;
|
||||
|
||||
pub mod train;
|
||||
|
||||
pub fn decode(s: &str) -> String {
|
||||
let raw = s.as_bytes();
|
||||
let raw = s.trim().as_bytes();
|
||||
assert!(raw[0] == b'0');
|
||||
|
||||
let u = STANDARD.decode(&raw[1..]).unwrap();
|
||||
let u = BASE64_STANDARD.decode(&raw[1..]).unwrap();
|
||||
|
||||
let mut o = String::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use bon::Builder;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
|
|
@ -28,63 +29,164 @@ pub struct BlueprintBookEntry {
|
|||
index: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Builder)]
|
||||
pub struct Blueprint {
|
||||
#[builder(skip = "blueprint".to_owned())]
|
||||
item: String,
|
||||
label: Option<String>,
|
||||
label: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
label_color: Option<BlueprintColor>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
entities: Vec<BlueprintEntity>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
tiles: Vec<BlueprintTile>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
icons: Vec<BlueprintIcon>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
schedules: Vec<BlueprintSchedule>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
stock_connections: Vec<BlueprintStockConnection>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
description: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
snap_to_grid: Option<BlueprintPosition>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
absolute_snapping: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
position_relative_to_grid: Option<BlueprintPosition>,
|
||||
version: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Builder)]
|
||||
pub struct BlueprintStockConnection {
|
||||
#[builder(start_fn)]
|
||||
stock: u32,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
front: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
back: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Builder)]
|
||||
pub struct BlueprintEntity {
|
||||
entity_number: u64,
|
||||
#[builder(start_fn)]
|
||||
name: String,
|
||||
#[builder(start_fn)]
|
||||
entity_number: u32,
|
||||
#[builder(start_fn)]
|
||||
position: BlueprintPosition,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
direciton: Option<u8>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
orientation: Option<f32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
connections: Option<BlueprintConnection>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
neighbours: Option<Vec<u64>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
control_behaviour: Option<()>,
|
||||
items: Option<HashMap<String, u32>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
items: Option<Vec<BlueprintItemRequest>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
recipe: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
bar: Option<u64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
inventory: Option<BlueprintInventory>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
infinity_settings: Option<()>,
|
||||
#[serde(rename = "type")]
|
||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||
underground_type: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
input_priority: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
output_priority: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
filter: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
filters: Option<Vec<BlueprintItemFilter>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
filter_mode: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
override_stack_size: Option<u8>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
drop_position: Option<BlueprintPosition>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pickup_position: Option<BlueprintPosition>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
request_filters: Option<Vec<BlueprintLogisticFilter>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
request_from_buffers: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
parameters: Option<BlueprintSpeakerParameter>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
alert_parameters: Option<BlueprintSpeakerAlertParameter>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
auto_launch: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
variation: Option<u8>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
color: Option<BlueprintColor>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
station: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
manuel_trains_limit: Option<u32>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
switch_state: Option<bool>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tags: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BlueprintItemRequest {
|
||||
id: BlueprintItemID,
|
||||
items: BlueprintItem,
|
||||
}
|
||||
|
||||
impl BlueprintItemRequest {
|
||||
pub fn new(id: BlueprintItemID, items: Vec<BlueprintInventoryLocation>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
items: BlueprintItem {
|
||||
in_inventory: items,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Builder)]
|
||||
pub struct BlueprintItemID {
|
||||
#[builder(start_fn)]
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BlueprintItem {
|
||||
in_inventory: Vec<BlueprintInventoryLocation>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BlueprintInventoryLocation {
|
||||
count: u32,
|
||||
inventory: u32,
|
||||
stack: u32,
|
||||
}
|
||||
|
||||
impl BlueprintInventoryLocation {
|
||||
pub fn new(count: u32, inventory: u32, stack: u32) -> Self {
|
||||
Self {
|
||||
count,
|
||||
inventory,
|
||||
stack,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BlueprintInventory {
|
||||
filters: Vec<BlueprintItemFilter>,
|
||||
|
|
@ -154,6 +256,12 @@ pub struct BlueprintPosition {
|
|||
y: f64,
|
||||
}
|
||||
|
||||
impl BlueprintPosition {
|
||||
pub fn new(x: f64, y: f64) -> Self {
|
||||
BlueprintPosition { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct BlueprintIcon {
|
||||
index: u32,
|
||||
|
|
|
|||
82
src/blueprint/train.rs
Normal file
82
src/blueprint/train.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use super::{
|
||||
Blueprint, BlueprintEntity, BlueprintInventoryLocation, BlueprintItemID, BlueprintItemRequest,
|
||||
BlueprintPosition, BlueprintStockConnection,
|
||||
};
|
||||
|
||||
pub fn generate_train(locomotives: u32, wagons: u32, rails: bool, fluid: bool) -> Blueprint {
|
||||
let mut e = Vec::new();
|
||||
|
||||
for i in 0..locomotives {
|
||||
e.push(
|
||||
BlueprintEntity::builder(
|
||||
"locomotive".to_owned(),
|
||||
i + 1,
|
||||
BlueprintPosition::new(1.0, 3.5 + 7.0 * i as f64),
|
||||
)
|
||||
.items(vec![BlueprintItemRequest::new(
|
||||
BlueprintItemID::builder("rocket-fuel".to_owned()).build(),
|
||||
vec![BlueprintInventoryLocation::new(5, 1, 0)],
|
||||
)])
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
for i in 0..wagons {
|
||||
e.push(
|
||||
BlueprintEntity::builder(
|
||||
if fluid {
|
||||
"fluid-wagon".to_owned()
|
||||
} else {
|
||||
"cargo-wagon".to_owned()
|
||||
},
|
||||
locomotives + i + 1,
|
||||
BlueprintPosition::new(1.0, 3.5 + 7.0 * (locomotives + i) as f64),
|
||||
)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
if rails {
|
||||
for i in 0..((locomotives + wagons) * 7).div_ceil(2) {
|
||||
e.push(
|
||||
BlueprintEntity::builder(
|
||||
"straight-rail".to_owned(),
|
||||
locomotives + wagons + i + 1,
|
||||
BlueprintPosition::new(1.0, 1.0 + 2.0 * i as f64),
|
||||
)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let mut stock_connections = Vec::new();
|
||||
|
||||
if locomotives + wagons > 1 {
|
||||
stock_connections.push(BlueprintStockConnection::builder(1).back(2).build());
|
||||
for i in 2..=(locomotives + wagons - 1) {
|
||||
stock_connections.push(
|
||||
BlueprintStockConnection::builder(i)
|
||||
.front(i - 1)
|
||||
.back(i + 1)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
stock_connections.push(
|
||||
BlueprintStockConnection::builder(locomotives + wagons)
|
||||
.front(locomotives + wagons - 1)
|
||||
.build(),
|
||||
);
|
||||
}
|
||||
|
||||
Blueprint::builder()
|
||||
.label("train".to_string())
|
||||
.entities(e)
|
||||
.stock_connections(stock_connections)
|
||||
.version(562949954797573)
|
||||
.snap_to_grid(BlueprintPosition::new(
|
||||
4.0,
|
||||
2.0 * ((locomotives + wagons) * 7).div_ceil(2) as f64,
|
||||
))
|
||||
.build()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue