diff --git a/factorio-blueprint-generator/src/balancer.rs b/factorio-blueprint-generator/src/balancer.rs index f285e2a..da03af7 100644 --- a/factorio-blueprint-generator/src/balancer.rs +++ b/factorio-blueprint-generator/src/balancer.rs @@ -82,16 +82,16 @@ pub fn generate_4_lane_balancer2() -> Blueprint { let splitter_pos = [(0, 0), (2, 0), (1, 1), (1, 4), (0, 7), (2, 7)]; for (x, y) in splitter_pos { - b.add_entity(Entity::new( - "splitter", + b.add_entity(Entity::new_splitter( + Beltspeed::Normal, Position::new(x, y), Direction::Up, - Position::new(2, 1), )); } b.add_path(&balancer_path(), Beltspeed::Normal); + b.transform(Transformation::new(Direction::Right, Position::new(0, 0))); b.to_blueprint() } diff --git a/factorio-blueprint-generator/src/bin/balancer_blueprint.rs b/factorio-blueprint-generator/src/bin/balancer_blueprint.rs index c9414f9..92195ef 100644 --- a/factorio-blueprint-generator/src/bin/balancer_blueprint.rs +++ b/factorio-blueprint-generator/src/bin/balancer_blueprint.rs @@ -6,7 +6,7 @@ fn main() { let b2 = BlueprintString::Blueprint(generate_4_lane_balancer2()); println!("{}", serde_json::to_string_pretty(&b).unwrap()); - println!("{}", serde_json::to_string_pretty(&b).unwrap()); + println!("{}", serde_json::to_string_pretty(&b2).unwrap()); println!("{}", encode(&serde_json::to_string(&b).unwrap())); println!("{}", encode(&serde_json::to_string(&b2).unwrap())); diff --git a/factorio-blueprint-generator/src/bin/station.rs b/factorio-blueprint-generator/src/bin/station.rs index e4d4895..d40e568 100644 --- a/factorio-blueprint-generator/src/bin/station.rs +++ b/factorio-blueprint-generator/src/bin/station.rs @@ -69,7 +69,7 @@ fn main() { ); inner_inner_b.push(BlueprintBookEntry::new( - BlueprintString::Blueprint(blueprint), + BlueprintString::Blueprint(blueprint.to_blueprint()), l as u32, )); } @@ -119,14 +119,10 @@ fn main() { beltspeed, belttype, } => { - let b = BlueprintString::Blueprint(basic_station( - load, - locomotives, - length, - outputs, - beltspeed, - belttype, - )); + let b = BlueprintString::Blueprint( + basic_station(load, locomotives, length, outputs, beltspeed, belttype) + .to_blueprint(), + ); // println!("{}", serde_json::to_string_pretty(&b).unwrap()); diff --git a/factorio-blueprint-generator/src/binary_merger.rs b/factorio-blueprint-generator/src/binary_merger.rs index 9dc1b22..09e53f0 100644 --- a/factorio-blueprint-generator/src/binary_merger.rs +++ b/factorio-blueprint-generator/src/binary_merger.rs @@ -1,27 +1,19 @@ -use factorio_blueprint::{BlueprintEntity, BlueprintPosition}; -use factorio_core::beltoptions::Beltspeed; +use factorio_blueprint::abstraction::{Blueprint, Entity}; +use factorio_core::{beltoptions::Beltspeed, prelude::*}; pub fn merger( reverse: bool, beltspeed: Beltspeed, - offset_x: f64, - offset_y: f64, - outer_offset: u32, intervall: usize, outputs: usize, lines: usize, -) -> Vec { +) -> Blueprint { let section_size = lines / outputs; assert!(lines % outputs == 0); assert!(section_size.is_power_of_two()); assert!(outputs <= lines); - let flip = match reverse { - true => 8, - false => 0, - }; - - let mut e = Vec::new(); + let mut b = Blueprint::new(); // output and merging for o in 0..outputs { @@ -31,37 +23,30 @@ pub fn merger( let depth = o + i.count_ones() as usize; for j in 0..depth { - let offset = outer_offset + e.len() as u32; - e.push( - BlueprintEntity::builder( - stubspeed.string(), - offset, - BlueprintPosition::new( - (intervall * (i + o * section_size)) as f64 + offset_x, - offset_y - j as f64, - ), - ) - .direction(flip) - .build(), - ); + b.add_entity(Entity::new_belt( + stubspeed, + Position::new( + (intervall * (i + o * section_size)) as PositionType, + -(j as PositionType), + ), + match reverse { + true => Direction::Down, + false => Direction::Up, + }, + )); } - let offset = outer_offset + e.len() as u32; - e.push( - BlueprintEntity::builder( - stubspeed.string(), - offset, - BlueprintPosition::new( - (intervall * (i + o * section_size)) as f64 + offset_x, - offset_y - depth as f64, - ), - ) - .direction(match reverse { - true => 8, - false => 12, - }) - .build(), - ); + b.add_entity(Entity::new_belt( + stubspeed, + Position::new( + (intervall * (i + o * section_size)) as PositionType, + -(depth as PositionType), + ), + match reverse { + true => Direction::Down, + false => Direction::Left, + }, + )); } // merger @@ -70,53 +55,53 @@ pub fn merger( let mergespeed = beltspeed.halvings((section_size.ilog2() as usize) - i); for j in 0..(section_size / p) { let depth = o + j.count_ones() as usize; - let offset = outer_offset + e.len() as u32; - e.push( - BlueprintEntity::builder( - mergespeed.string_splitter(), - offset, - BlueprintPosition::new( - (intervall * (j * p + o * section_size)) as f64 - i as f64 + offset_x, - offset_y - i as f64 + 0.5 - depth as f64, + + b.add_entity(Entity::new_splitter( + mergespeed, + Position::new( + (intervall * (j * p + o * section_size)) as PositionType + - i as PositionType, + 0 - i as PositionType - depth as PositionType + !reverse as PositionType, + ), + match reverse { + true => Direction::Right, + false => Direction::Left, + }, + )); + + for l in 0..(7 * p / 2) { + b.add_entity(Entity::new_belt( + mergespeed.halve(), + Position::new( + (intervall * (j * p + o * section_size) + l + 1) as PositionType + - i as PositionType, + 0 - i as PositionType - depth as PositionType, ), - ) - .direction(12 - flip) - .build(), - ); - e.extend((0..(7 * p / 2)).map(|l| { - BlueprintEntity::builder( - mergespeed.halve().string(), - offset + 1 + l as u32, - BlueprintPosition::new( - (intervall * (j * p + o * section_size)) as f64 - i as f64 - + offset_x - + l as f64 - + 1.0, - offset_y - i as f64 - depth as f64, - ), - ) - .direction(12 - flip) - .build() - })); + match reverse { + true => Direction::Right, + false => Direction::Left, + }, + )); + } } } // connect - let offset = outer_offset + e.len() as u32; let step = o + section_size.ilog2() as usize; - e.extend((0..(7 * o * section_size)).map(|l| { - BlueprintEntity::builder( - beltspeed.string(), - offset + l as u32, - BlueprintPosition::new( - l as f64 + offset_x - section_size.ilog2() as f64, - offset_y - step as f64, + for l in 0..(7 * o * section_size) { + b.add_entity(Entity::new_belt( + beltspeed, + Position::new( + l as PositionType - section_size.ilog2() as PositionType, + -(step as PositionType), ), - ) - .direction(12 - flip) - .build() - })); + match reverse { + true => Direction::Right, + false => Direction::Left, + }, + )); + } } - e + b } diff --git a/factorio-blueprint-generator/src/station.rs b/factorio-blueprint-generator/src/station.rs index 91aa3a2..9e7b7f3 100644 --- a/factorio-blueprint-generator/src/station.rs +++ b/factorio-blueprint-generator/src/station.rs @@ -1,286 +1,169 @@ -use factorio_blueprint::{Blueprint, BlueprintEntity, BlueprintPosition}; -use factorio_core::beltoptions::{Beltspeed, Belttype}; +use factorio_blueprint::abstraction::{Blueprint, ElectricPoleType, Entity, InserterType, Quality}; +use factorio_core::{ + beltoptions::{Beltspeed, Belttype}, + prelude::*, +}; use crate::binary_merger::merger; -pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Vec, f64) { +pub fn unloader(beltspeed: Beltspeed, belttype: Belttype) -> (Blueprint, PositionType) { + let mut b = Blueprint::new(); + if beltspeed == Beltspeed::Normal { - let mut e = vec![ - BlueprintEntity::builder( - "fast-transport-belt".to_owned(), - 0, - BlueprintPosition::new(3.5, -1.5), - ) - .build(), - ]; + b.add_entity(Entity::new_belt( + Beltspeed::Fast, + Position::new(3, -2), + Direction::Up, + )); if belttype.contains_left() { - let offset = e.len() as u32; - e.extend_from_slice(&[ - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset, - BlueprintPosition::new(5.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 1, - BlueprintPosition::new(5.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - offset + 2, - BlueprintPosition::new(4.5, -1.5), - ) - .direction(4) - .build(), - ]); + b.add_entity(Entity::new_unknown( + "steel-chest", + Position::new(5, -2), + Direction::Up, + Position::new(1, 1), + )); + b.add_entity(Entity::new_inserter( + InserterType::Bulk, + None, + Position::new(5, -1), + Direction::Down, + )); + + b.add_entity(Entity::new_inserter( + InserterType::Fast, + None, + Position::new(4, -2), + Direction::Right, + )); } if belttype.contains_right() { - let offset = e.len() as u32; - e.extend_from_slice(&[ - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset, - BlueprintPosition::new(1.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 1, - BlueprintPosition::new(1.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - "fast-inserter".to_owned(), - offset + 2, - BlueprintPosition::new(2.5, -1.5), - ) - .direction(12) - .build(), - ]); + b.add_entity(Entity::new_unknown( + "steel-chest", + Position::new(1, -2), + Direction::Up, + Position::new(1, 1), + )); + b.add_entity(Entity::new_inserter( + InserterType::Bulk, + None, + Position::new(1, -1), + Direction::Down, + )); + + b.add_entity(Entity::new_inserter( + InserterType::Fast, + None, + Position::new(2, -2), + Direction::Left, + )); } - (e, -2.5) + (b, -3) } else { let (belt_inserter, stack_size, quality) = match beltspeed { Beltspeed::Normal => unreachable!(), - Beltspeed::Fast => ("fast-inserter", None, None), - Beltspeed::Express => ("bulk-inserter", Some(8), None), - Beltspeed::Turbo => ("fast-inserter", None, Some(String::from("epic"))), + Beltspeed::Fast => (InserterType::Fast, None, Quality::Normal), + Beltspeed::Express => (InserterType::Bulk, Some(8), Quality::Normal), + Beltspeed::Turbo => (InserterType::Bulk, None, Quality::Epic), + }; + + b.add_entity(Entity::new_belt( + beltspeed, + Position::new(3, -4), + Direction::Up, + )); + + let mut s = |x, beltdir| { + b.add_entity(Entity::new_belt(beltspeed, Position::new(x, -4), beltdir)); + b.add_entity( + Entity::new_inserter( + belt_inserter, + stack_size, + Position::new(x, -3), + Direction::Down, + ) + .quality(quality), + ); + b.add_entity(Entity::new_unknown( + "steel-chest", + Position::new(x, -2), + Direction::Up, + Position::new(1, 1), + )); + b.add_entity(Entity::new_inserter( + InserterType::Bulk, + None, + Position::new(x, -1), + Direction::Down, + )); }; - let mut e = vec![ - BlueprintEntity::builder(beltspeed.string(), 0, BlueprintPosition::new(3.5, -3.5)) - .build(), - ]; if belttype.contains_left() { - let offset = e.len() as u32; - e.extend_from_slice(&[ - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset, - BlueprintPosition::new(1.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 1, - BlueprintPosition::new(1.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - offset + 2, - BlueprintPosition::new(1.5, -2.5), - ) - .direction(8) - .maybe_override_stack_size(stack_size) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - beltspeed.string(), - offset + 3, - BlueprintPosition::new(1.5, -3.5), - ) - .direction(4) - .build(), - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset + 4, - BlueprintPosition::new(2.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 5, - BlueprintPosition::new(2.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - offset + 6, - BlueprintPosition::new(2.5, -2.5), - ) - .direction(8) - .maybe_override_stack_size(stack_size) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - beltspeed.string(), - offset + 7, - BlueprintPosition::new(2.5, -3.5), - ) - .direction(4) - .build(), - ]); + s(1, Direction::Right); + s(2, Direction::Right); } if belttype.contains_right() { - let offset = e.len() as u32; - e.extend_from_slice(&[ - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset, - BlueprintPosition::new(4.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 1, - BlueprintPosition::new(4.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - offset + 2, - BlueprintPosition::new(4.5, -2.5), - ) - .direction(8) - .maybe_override_stack_size(stack_size) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - beltspeed.string(), - offset + 3, - BlueprintPosition::new(4.5, -3.5), - ) - .direction(12) - .build(), - BlueprintEntity::builder( - "steel-chest".to_owned(), - offset + 4, - BlueprintPosition::new(5.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - offset + 5, - BlueprintPosition::new(5.5, -0.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - offset + 6, - BlueprintPosition::new(5.5, -2.5), - ) - .direction(8) - .maybe_override_stack_size(stack_size) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - beltspeed.string(), - offset + 7, - BlueprintPosition::new(5.5, -3.5), - ) - .direction(12) - .build(), - ]); + s(4, Direction::Left); + s(5, Direction::Left); } - (e, -4.5) + (b, -5) } } -pub fn one_loader(beltspeed: Beltspeed) -> (Vec, f64) { +pub fn one_loader(beltspeed: Beltspeed) -> (Blueprint, PositionType) { let (belt_inserter, quality) = match beltspeed { - Beltspeed::Normal => ("fast-inserter", None), - Beltspeed::Fast => ("bulk-inserter", Some(String::from("uncommon"))), - Beltspeed::Express => ("bulk-inserter", Some(String::from("rare"))), - Beltspeed::Turbo => ("bulk-inserter", Some(String::from("legendary"))), + Beltspeed::Normal => (InserterType::Fast, Quality::Normal), + Beltspeed::Fast => (InserterType::Bulk, Quality::Uncommon), + Beltspeed::Express => (InserterType::Bulk, Quality::Rare), + Beltspeed::Turbo => (InserterType::Bulk, Quality::Legendary), }; - ( - vec![ - BlueprintEntity::builder( - beltspeed.string_splitter(), - 0, - BlueprintPosition::new(4.0, -4.5), - ) - .direction(8) - .build(), - BlueprintEntity::builder(beltspeed.string(), 1, BlueprintPosition::new(2.5, -3.5)) - .direction(12) - .build(), - BlueprintEntity::builder(beltspeed.string(), 2, BlueprintPosition::new(3.5, -3.5)) - .direction(12) - .build(), - BlueprintEntity::builder(beltspeed.string(), 3, BlueprintPosition::new(4.5, -3.5)) - .direction(4) - .build(), - BlueprintEntity::builder(beltspeed.string(), 4, BlueprintPosition::new(5.5, -3.5)) - .direction(4) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - 5, - BlueprintPosition::new(2.5, -2.5), - ) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - belt_inserter.to_owned(), - 6, - BlueprintPosition::new(5.5, -2.5), - ) - .maybe_quality(quality.clone()) - .build(), - BlueprintEntity::builder( - "steel-chest".to_owned(), - 7, - BlueprintPosition::new(2.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "steel-chest".to_owned(), - 8, - BlueprintPosition::new(5.5, -1.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 9, - BlueprintPosition::new(2.5, -0.5), - ) - .build(), - BlueprintEntity::builder( - "bulk-inserter".to_owned(), - 10, - BlueprintPosition::new(5.5, -0.5), - ) - .build(), - ], - -5.5, - ) + let mut b = Blueprint::new(); + + b.add_entity(Entity::new_splitter( + beltspeed, + Position::new(4, -5), + Direction::Down, + )); + b.add_entity(Entity::new_belt( + beltspeed, + Position::new(3, -4), + Direction::Left, + )); + b.add_entity(Entity::new_belt( + beltspeed, + Position::new(4, -4), + Direction::Right, + )); + + let mut s = |x, beltdir| { + b.add_entity(Entity::new_belt(beltspeed, Position::new(x, -4), beltdir)); + b.add_entity( + Entity::new_inserter(belt_inserter, None, Position::new(x, -3), Direction::Up) + .quality(quality), + ); + b.add_entity(Entity::new_unknown( + "steel-chest", + Position::new(x, -2), + Direction::Up, + Position::new(1, 1), + )); + b.add_entity(Entity::new_inserter( + InserterType::Bulk, + None, + Position::new(x, -1), + Direction::Up, + )); + }; + + s(2, Direction::Left); + s(5, Direction::Right); + + (b, -6) } pub fn basic_station( @@ -296,85 +179,87 @@ pub fn basic_station( assert!(section_size.is_power_of_two()); assert!(outputs <= length); - let mut e = Vec::new(); + let mut blueprint = Blueprint::new(); let global_x_offset = locomotives * 7; // electric poles + let mut poles = Vec::new(); for l in 1..=(length + locomotives) { - e.push( - BlueprintEntity::builder( - "medium-electric-pole".to_owned(), - l as u32 - 1, - BlueprintPosition::new((7 * l) as f64 + 0.5, -1.5), - ) - .build(), - ); + poles.push(blueprint.add_entity(Entity::new_electric_pole( + ElectricPoleType::Medium, + Position::new(7 * l as PositionType, -2), + ))); + } + + for (&a, &b) in poles.iter().zip(poles[1..].iter()) { + blueprint.add_wire(a, 5, b, 5); } // unloader - let (unloader, output_y) = match load { + + let (_, output_y) = match load { false => unloader( beltspeed.halvings((length / outputs).ilog2() as usize), belttype, ), true => one_loader(beltspeed.halvings((length / outputs).ilog2() as usize)), }; - - let offset = e.len(); for l in 0..length { - e.extend(unloader.iter().cloned().map(|mut e| { - e.position.x += (7 * l + global_x_offset) as f64; - e.entity_number += (offset + unloader.len() * l) as u32; - e - })); + let (mut unloader, _) = match load { + false => unloader( + beltspeed.halvings((length / outputs).ilog2() as usize), + belttype, + ), + true => one_loader(beltspeed.halvings((length / outputs).ilog2() as usize)), + }; + + unloader.transform(Transformation::new( + Direction::Up, + Position::new((7 * l + global_x_offset) as PositionType, 0), + )); + + blueprint.add_blueprint(unloader); } // train stop - let offset = e.len(); - e.push( - BlueprintEntity::builder( - "train-stop".to_owned(), - offset as u32, - BlueprintPosition::new(1.0, -1.0), - ) - .direction(12) - .build(), - ); + blueprint.add_entity(Entity::new_unknown( + "train-stop", + Position::new(0, -2), + Direction::Left, + Position::new(2, 2), + )); // rails for l in 0..((length * 7 + global_x_offset + 1) / 2) { - let offset = e.len() as u32; - e.push( - BlueprintEntity::builder( - "straight-rail".to_owned(), - offset, - BlueprintPosition::new(2.0 * l as f64 + 1.0, 1.0), - ) - .direction(4) - .build(), - ); + blueprint.add_entity(Entity::new_unknown( + "straight-rail", + Position::new(2 * l as PositionType, 0), + Direction::Right, + Position::new(2, 2), + )); } // output and merging - e.extend(merger( - load, - beltspeed, - global_x_offset as f64 + 3.5, - output_y, - e.len() as u32, - 7, - outputs, - length, + + let mut m = merger(load, beltspeed, 7, outputs, length); + + m.transform(Transformation::new( + Direction::Up, + Position::new(global_x_offset as PositionType + 3, output_y), )); - Blueprint::builder() - .label("station".to_owned()) - .entities(e) - .wires( - (0..((length + locomotives - 1) as u32)) - .map(|i| [i, 5, i + 1, 5]) - .collect(), - ) - .build() + blueprint.add_blueprint(m); + // e.extend(merger( + // load, + // beltspeed, + // global_x_offset as f64 + 3.5, + // output_y, + // e.len() as u32, + // 7, + // outputs, + // length, + // )); + + blueprint } diff --git a/factorio-blueprint/src/abstraction.rs b/factorio-blueprint/src/abstraction.rs index 7163e63..9aaa0b4 100644 --- a/factorio-blueprint/src/abstraction.rs +++ b/factorio-blueprint/src/abstraction.rs @@ -1,9 +1,9 @@ use factorio_core::{ beltoptions::Beltspeed, pathfield::PathField, - prelude::{Direction, Position, PositionType}, + prelude::{Direction, Position, PositionType, Transformable, Transformation}, }; -use std::{collections::HashMap, str::FromStr, sync::atomic::AtomicUsize}; +use std::{collections::HashMap, sync::atomic::AtomicUsize}; use crate::{BlueprintEntity, BlueprintPosition}; @@ -13,33 +13,220 @@ pub enum UndergroundType { Output, } +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum InserterType { + Burner, + Normal, + Fast, + Bulk, + Stack, +} + +impl InserterType { + fn string(&self) -> String { + match self { + InserterType::Burner => "burner-inserter", + InserterType::Normal => "inserter", + InserterType::Fast => "fast-inserter", + InserterType::Bulk => "bulk-inserter", + InserterType::Stack => "stack-inserter", + } + .to_owned() + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum ElectricPoleType { + Small, + Medium, + Big, + Substation, +} + +impl ElectricPoleType { + fn string(&self) -> String { + match self { + ElectricPoleType::Small => "small-electric-pole", + ElectricPoleType::Medium => "medium-electric-pole", + ElectricPoleType::Big => "big-electric-pole", + ElectricPoleType::Substation => "substation", + } + .to_owned() + } + + fn size(&self) -> Position { + match self { + ElectricPoleType::Small | ElectricPoleType::Medium => Position::new(1, 1), + ElectricPoleType::Big | ElectricPoleType::Substation => Position::new(2, 2), + } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum Quality { + Normal, + Uncommon, + Rare, + Epic, + Legendary, +} + pub struct Entity { - name: String, + entity: EntityType, position: Position, direction: Direction, - size: Position, - underground_type: Option, + quality: Quality, +} + +pub enum EntityType { + Belt(Beltspeed), + UndergroundBelt(Beltspeed, UndergroundType), + Splitter(Beltspeed), + ElectricPole(ElectricPoleType), + Inserter { + inserter_type: InserterType, + override_stack_size: Option, + }, + Unknown { + name: String, + size: Position, + misc: HashMap, + }, } impl Entity { - pub fn new( + pub fn new(entity: EntityType, position: Position, direction: Direction) -> Self { + Self { + entity, + position, + direction, + quality: Quality::Normal, + } + } + + pub fn new_belt(beltspeed: Beltspeed, position: Position, direction: Direction) -> Self { + Self::new(EntityType::Belt(beltspeed), position, direction) + } + + pub fn new_underground_belt( + beltspeed: Beltspeed, + underground_type: UndergroundType, + position: Position, + direction: Direction, + ) -> Self { + Self::new( + EntityType::UndergroundBelt(beltspeed, underground_type), + position, + direction, + ) + } + + pub fn new_splitter(beltspeed: Beltspeed, position: Position, direction: Direction) -> Self { + Self::new(EntityType::Splitter(beltspeed), position, direction) + } + + pub fn new_inserter( + inserter_type: InserterType, + override_stack_size: Option, + position: Position, + direction: Direction, + ) -> Self { + Self::new( + EntityType::Inserter { + inserter_type, + override_stack_size, + }, + position, + direction, + ) + } + + pub fn new_electric_pole(electric_pole_type: ElectricPoleType, position: Position) -> Self { + Self::new( + EntityType::ElectricPole(electric_pole_type), + position, + Direction::Up, + ) + } + + pub fn new_unknown( name: impl AsRef, position: Position, direction: Direction, size: Position, ) -> Self { - Self { - name: name.as_ref().to_owned(), + Self::new( + EntityType::Unknown { + name: name.as_ref().to_owned(), + size, + misc: HashMap::new(), + }, position, direction, - size, - underground_type: None, + ) + } + + pub fn quality(mut self, quality: Quality) -> Self { + self.quality = quality; + self + } + + pub fn get_name(&self) -> String { + match &self.entity { + EntityType::Belt(beltspeed) => beltspeed.string(), + EntityType::UndergroundBelt(beltspeed, _underground_type) => { + beltspeed.string_underground() + } + EntityType::Splitter(beltspeed) => beltspeed.string_splitter(), + EntityType::Unknown { + name, + size: _, + misc: _, + } => name.clone(), + EntityType::ElectricPole(electric_pole_type) => electric_pole_type.string(), + EntityType::Inserter { + inserter_type, + override_stack_size: _, + } => inserter_type.string(), } } - pub fn underground_type(mut self, underground_type: UndergroundType) -> Self { - self.underground_type = Some(underground_type); - self + pub fn get_maybe_underground_type_string(&self) -> Option { + match &self.entity { + EntityType::UndergroundBelt(_, underground_type) => match underground_type { + UndergroundType::Input => Some(String::from("input")), + UndergroundType::Output => Some(String::from("output")), + }, + _ => None, + } + } + + pub fn get_maybe_override_stack_size(&self) -> Option { + match &self.entity { + EntityType::Inserter { + inserter_type: _, + override_stack_size, + } => *override_stack_size, + _ => None, + } + } + + pub fn size(&self) -> Position { + match &self.entity { + EntityType::Splitter(_) => Position::new(2, 1), + EntityType::Unknown { + name: _, + size, + misc: _, + } => *size, + EntityType::ElectricPole(electric_pole_type) => electric_pole_type.size(), + _ => Position::new(1, 1), + } + } + + pub fn transform(&mut self, transform: Transformation) { + self.position = self.position.transform(transform); + self.direction = self.direction.transform(transform); } } @@ -51,6 +238,7 @@ static ENTITY_COUNTER: AtomicUsize = AtomicUsize::new(0); pub struct Blueprint { entities: Vec<(EntityKey, Entity)>, keys: HashMap, + wires: Vec<(EntityKey, u8, EntityKey, u8)>, } impl Blueprint { @@ -58,6 +246,7 @@ impl Blueprint { Self { entities: Vec::new(), keys: HashMap::new(), + wires: Vec::new(), } } @@ -79,49 +268,50 @@ impl Blueprint { for &p in path { match p { PathField::Belt { pos, dir } => { - self.add_entity(Entity::new( - beltspeed.string(), - pos, - dir, - Position::new(1, 1), - )); + self.add_entity(Entity::new_belt(beltspeed, pos, dir)); } PathField::Underground { pos, dir, len } => { - self.add_entity( - Entity::new( - beltspeed.string_underground(), - pos, - dir, - Position::new(1, 1), - ) - .underground_type(UndergroundType::Input), - ); - self.add_entity( - Entity::new( - beltspeed.string_underground(), - pos.in_direction(&dir, len as PositionType), - dir, - Position::new(1, 1), - ) - .underground_type(UndergroundType::Output), - ); + self.add_entity(Entity::new_underground_belt( + beltspeed, + UndergroundType::Input, + pos, + dir, + )); + self.add_entity(Entity::new_underground_belt( + beltspeed, + UndergroundType::Output, + pos.in_direction(&dir, len as PositionType), + dir, + )); } }; } } + pub fn add_wire(&mut self, a: EntityKey, endpoint_a: u8, b: EntityKey, endpoint_b: u8) { + self.wires.push((a, endpoint_a, b, endpoint_b)); + } + + pub fn add_blueprint(&mut self, other: Self) { + self.entities.extend(other.entities); + self.keys.extend(other.keys); + self.wires.extend(other.wires); + } + pub fn to_blueprint(&self) -> super::Blueprint { let entities = self .entities .iter() .enumerate() .map(|(i, (_, e))| { + let size = (e.size() - Position::new(1, 1)) + .transform(Transformation::new(e.direction, Position::new(0, 0))); BlueprintEntity::builder( - e.name.clone(), + e.get_name(), i as u32 + 1, BlueprintPosition::new( - e.position.x as f64 + 0.5 * e.size.x as f64, - e.position.y as f64 + 0.5 * e.size.y as f64, + e.position.x as f64 + 0.5 * size.x as f64 + 0.5, + e.position.y as f64 + 0.5 * size.y as f64 + 0.5, ), ) .direction(match e.direction { @@ -130,19 +320,37 @@ impl Blueprint { Direction::Down => 8, Direction::Left => 12, }) - .maybe_underground_type(e.underground_type.map(|u| match u { - UndergroundType::Input => String::from("input"), - UndergroundType::Output => String::from("output"), - })) + .maybe_underground_type(e.get_maybe_underground_type_string()) + .maybe_override_stack_size(e.get_maybe_override_stack_size()) .build() }) .collect(); + let wires = self + .wires + .iter() + .map(|&(a, endpoint_a, b, endpoint_b)| { + [ + self.keys[&a] as u32 + 1, + endpoint_a as u32, + self.keys[&b] as u32 + 1, + endpoint_b as u32, + ] + }) + .collect(); + super::Blueprint::builder() .label(String::from("test")) .entities(entities) + .wires(wires) .build() } + + pub fn transform(&mut self, transform: Transformation) { + for (_, e) in &mut self.entities { + e.transform(transform); + } + } } impl Default for Blueprint {