Refactor into different crates
This commit is contained in:
parent
94473c64e0
commit
dfdeae5638
82 changed files with 624 additions and 647 deletions
59
factorio-blueprint/src/belt.rs
Normal file
59
factorio-blueprint/src/belt.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use factorio_core::{pathfield::PathField, prelude::*};
|
||||
|
||||
use crate::misc::Beltspeed;
|
||||
|
||||
use super::{BlueprintEntity, BlueprintPosition};
|
||||
|
||||
pub fn convert_belt_to_blueprint(
|
||||
belt: &PathField,
|
||||
speed: &Beltspeed,
|
||||
nextfree: &mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> + use<> {
|
||||
match belt {
|
||||
PathField::Belt { pos, dir } => {
|
||||
*nextfree += 1;
|
||||
vec![
|
||||
BlueprintEntity::builder(
|
||||
speed.string(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
PathField::Underground { pos, dir, len } => {
|
||||
*nextfree += 2;
|
||||
let endpos = pos.in_direction(dir, *len as PositionType);
|
||||
vec![
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 2,
|
||||
BlueprintPosition::new(pos.x as f64 + 0.5, pos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("input".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
BlueprintEntity::builder(
|
||||
speed.string_underground(),
|
||||
*nextfree - 1,
|
||||
BlueprintPosition::new(endpos.x as f64 + 0.5, endpos.y as f64 + 0.5),
|
||||
)
|
||||
.underground_type("output".to_string())
|
||||
.direction(dir.get_index() * 4)
|
||||
.build(),
|
||||
]
|
||||
.into_iter()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_to_blueprint<'p, 's, 'n>(
|
||||
path: &'p [PathField],
|
||||
speed: &'s Beltspeed,
|
||||
nextfree: &'n mut u32,
|
||||
) -> impl Iterator<Item = BlueprintEntity> + use<'p, 's, 'n> {
|
||||
path.iter()
|
||||
.flat_map(|b| convert_belt_to_blueprint(b, speed, nextfree))
|
||||
}
|
||||
28
factorio-blueprint/src/bin/decode_blueprint.rs
Normal file
28
factorio-blueprint/src/bin/decode_blueprint.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use clap::Parser;
|
||||
use factorio_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());
|
||||
}
|
||||
}
|
||||
40
factorio-blueprint/src/lib.rs
Normal file
40
factorio-blueprint/src/lib.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
use base64::Engine;
|
||||
use base64::engine::general_purpose::STANDARD;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use std::io::Cursor;
|
||||
use std::io::Read;
|
||||
|
||||
pub mod misc;
|
||||
|
||||
pub mod structs;
|
||||
pub mod belt;
|
||||
|
||||
pub use structs::*;
|
||||
|
||||
pub fn decode(s: &str) -> String {
|
||||
let raw = s.trim().as_bytes();
|
||||
assert!(raw[0] == b'0');
|
||||
|
||||
let u = BASE64_STANDARD.decode(&raw[1..]).unwrap();
|
||||
|
||||
let mut o = String::new();
|
||||
|
||||
flate2::bufread::ZlibDecoder::new(Cursor::new(u))
|
||||
.read_to_string(&mut o)
|
||||
.unwrap();
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
pub fn encode(s: &str) -> String {
|
||||
let mut u = Vec::new();
|
||||
flate2::bufread::ZlibEncoder::new(Cursor::new(s), flate2::Compression::new(9))
|
||||
.read_to_end(&mut u)
|
||||
.unwrap();
|
||||
|
||||
let mut o = String::from("0");
|
||||
|
||||
STANDARD.encode_string(u, &mut o);
|
||||
|
||||
o
|
||||
}
|
||||
82
factorio-blueprint/src/misc.rs
Normal file
82
factorio-blueprint/src/misc.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
use clap::ValueEnum;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
pub enum Beltspeed {
|
||||
Normal,
|
||||
Fast,
|
||||
Express,
|
||||
Turbo,
|
||||
}
|
||||
|
||||
impl Beltspeed {
|
||||
pub fn string(self) -> String {
|
||||
match self {
|
||||
Beltspeed::Normal => "transport-belt",
|
||||
Beltspeed::Fast => "fast-transport-belt",
|
||||
Beltspeed::Express => "express-transport-belt",
|
||||
Beltspeed::Turbo => "turbo-transport-belt",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub fn string_underground(self) -> String {
|
||||
match self {
|
||||
Beltspeed::Normal => "underground-belt",
|
||||
Beltspeed::Fast => "fast-underground-belt",
|
||||
Beltspeed::Express => "express-underground-belt",
|
||||
Beltspeed::Turbo => "turbo-underground-belt",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub fn string_splitter(self) -> String {
|
||||
match self {
|
||||
Beltspeed::Normal => "splitter",
|
||||
Beltspeed::Fast => "fast-splitter",
|
||||
Beltspeed::Express => "express-splitter",
|
||||
Beltspeed::Turbo => "turbo-splitter",
|
||||
}
|
||||
.to_owned()
|
||||
}
|
||||
|
||||
pub fn halve(self) -> Self {
|
||||
match self {
|
||||
Beltspeed::Normal => Beltspeed::Normal,
|
||||
Beltspeed::Fast => Beltspeed::Normal,
|
||||
Beltspeed::Express => Beltspeed::Fast,
|
||||
Beltspeed::Turbo => Beltspeed::Fast,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn halvings(self, i: usize) -> Self {
|
||||
let mut s = self;
|
||||
for _ in 0..i {
|
||||
s = s.halve();
|
||||
}
|
||||
s
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ValueEnum)]
|
||||
pub enum Belttype {
|
||||
Full,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl Belttype {
|
||||
pub fn contains_left(self) -> bool {
|
||||
match self {
|
||||
Belttype::Full => true,
|
||||
Belttype::Left => true,
|
||||
Belttype::Right => false,
|
||||
}
|
||||
}
|
||||
pub fn contains_right(self) -> bool {
|
||||
match self {
|
||||
Belttype::Full => true,
|
||||
Belttype::Left => false,
|
||||
Belttype::Right => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
303
factorio-blueprint/src/structs.rs
Normal file
303
factorio-blueprint/src/structs.rs
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use bon::Builder;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
static VERSION: u64 = calculate_version(2, 0, 19, 173);
|
||||
|
||||
const fn calculate_version(major: u16, minor: u16, patch: u16, dev: u16) -> u64 {
|
||||
((major as u64) << 48) | ((minor as u64) << 32) | ((patch as u64) << 16) | (dev as u64)
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum BlueprintString {
|
||||
#[serde(rename = "blueprint_book")]
|
||||
BlueprintBook(BlueprintBook),
|
||||
#[serde(rename = "blueprint")]
|
||||
Blueprint(Blueprint),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
|
||||
pub struct BlueprintBook {
|
||||
#[builder(skip = "blueprint-book".to_owned())]
|
||||
item: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
label: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
label_color: Option<BlueprintColor>,
|
||||
blueprints: Vec<BlueprintBookEntry>,
|
||||
active_index: i32,
|
||||
#[builder(skip = VERSION)]
|
||||
version: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintBookEntry {
|
||||
#[serde(flatten)]
|
||||
entry: BlueprintString,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
impl BlueprintBookEntry {
|
||||
pub fn new(entry: BlueprintString, index: u32) -> Self {
|
||||
Self { entry, index }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Builder)]
|
||||
pub struct Blueprint {
|
||||
#[builder(skip = "blueprint".to_owned())]
|
||||
item: String,
|
||||
label: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
label_color: Option<BlueprintColor>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
entities: Vec<BlueprintEntity>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
tiles: Vec<BlueprintTile>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
icons: Vec<BlueprintIcon>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
schedules: Vec<serde_json::Value>,
|
||||
#[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>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
#[builder(default)]
|
||||
wires: Vec<[u32; 4]>,
|
||||
#[builder(skip = VERSION)]
|
||||
version: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, 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, Clone, Builder)]
|
||||
pub struct BlueprintEntity {
|
||||
#[builder(start_fn)]
|
||||
name: String,
|
||||
#[builder(start_fn)]
|
||||
pub entity_number: u32,
|
||||
#[builder(start_fn)]
|
||||
pub position: BlueprintPosition,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
direction: 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<()>,
|
||||
#[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", 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, Clone)]
|
||||
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, Clone, Builder)]
|
||||
pub struct BlueprintItemID {
|
||||
#[builder(start_fn)]
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintItem {
|
||||
in_inventory: Vec<BlueprintInventoryLocation>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
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, Clone)]
|
||||
pub struct BlueprintInventory {
|
||||
filters: Vec<BlueprintItemFilter>,
|
||||
bar: u16,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintConnection {
|
||||
#[serde(rename = "1")]
|
||||
first: Option<BlueprintConnectionPoint>,
|
||||
#[serde(rename = "2")]
|
||||
second: Option<BlueprintConnectionPoint>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintConnectionPoint {
|
||||
#[serde(default)]
|
||||
red: Vec<BlueprintConnectionData>,
|
||||
#[serde(default)]
|
||||
green: Vec<BlueprintConnectionData>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub struct BlueprintConnectionData {
|
||||
entity_id: u64,
|
||||
circuit_id: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintItemFilter {
|
||||
name: String,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintLogisticFilter {
|
||||
name: String,
|
||||
index: u32,
|
||||
count: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintSpeakerParameter {
|
||||
playback_volume: f64,
|
||||
playback_globally: bool,
|
||||
allow_polyphony: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintSpeakerAlertParameter {
|
||||
show_alert: bool,
|
||||
show_on_map: bool,
|
||||
icon_signal_id: BlueprintSignalID,
|
||||
alert_message: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintSignalID {
|
||||
name: String,
|
||||
#[serde(rename = "type")]
|
||||
signal_type: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub struct BlueprintPosition {
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
}
|
||||
|
||||
impl BlueprintPosition {
|
||||
pub fn new(x: f64, y: f64) -> Self {
|
||||
BlueprintPosition { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintIcon {
|
||||
index: u32,
|
||||
signal: BlueprintSignalID,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintTile {
|
||||
name: String,
|
||||
position: BlueprintPosition,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct BlueprintColor {
|
||||
r: f32,
|
||||
g: f32,
|
||||
b: f32,
|
||||
a: f32,
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue