Refactor into different crates

This commit is contained in:
hal8174 2025-01-18 17:30:55 +01:00
parent 94473c64e0
commit dfdeae5638
82 changed files with 624 additions and 647 deletions

View 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))
}

View 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());
}
}

View 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
}

View 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,
}
}
}

View 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,
}