mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/units.rs')
| -rw-r--r-- | src/block/units.rs | 241 |
1 files changed, 159 insertions, 82 deletions
diff --git a/src/block/units.rs b/src/block/units.rs index 708902d..c3def54 100644 --- a/src/block/units.rs +++ b/src/block/units.rs @@ -1,10 +1,12 @@ //! unit creation related blocks use thiserror::Error; -use super::payload::read_payload_block; +use super::payload::{read_payload_block, read_payload_seq}; use crate::block::simple::*; use crate::block::*; -use crate::data::dynamic::DynType; +use crate::data::command::UnitCommand; +use crate::data::dynamic::{DynType, DynSerializer}; +use crate::data::Serializer; use crate::unit; // fn is_pay(b: &str) -> bool { @@ -33,75 +35,36 @@ use crate::unit; // ) // } -make_simple!(ConstructorBlock, |_, name, _, _, rot: Rotation, s| { - let mut base = load!(from name which is ["additive-reconstructor" | "multiplicative-reconstructor" | "exponential-reconstructor" | "tetrative-reconstructor" | "tank-refabricator" | "mech-refabricator" | "ship-refabricator" | "prime-refabricator" | "tank-assembler" | "ship-assembler" | "mech-assembler"], s); - let times = rot.rotated(false).count(); - if !name.contains("assembler") { - let mut out = load!(s -> match name { - "additive-reconstructor" => "factory-out-3", - "multiplicative-reconstructor" => "factory-out-5", - "tank-refabricator" | "mech-refabricator" | "ship-refabricator" => - "factory-out-3-dark", - "exponential-reconstructor" => "factory-out-7", - "prime-refabricator" | "tank-assembler" | "ship-assembler" | "mech-assembler" => - "factory-out-5-dark", - "tetrative-reconstructor" => "factory-out-9", - }); - base.overlay(out.rotate(times)); +make_simple!(AssemblerBlock, |_, name, _, _, rot: Rotation, s| { + let mut base = + load!(from name which is ["tank-assembler" | "ship-assembler" | "mech-assembler"], s); + base.overlay( + match rot { + Rotation::Up | Rotation::Right => load!(concat side1 => name which is ["tank-assembler" | "ship-assembler" | "mech-assembler"], s), + Rotation::Down | Rotation::Left => load!(concat side2 => name which is ["tank-assembler" | "ship-assembler" | "mech-assembler"], s) + } + .rotate(rot.rotated(false).count()), + ); + base.overlay(load!(concat top => name which is ["tank-assembler" | "ship-assembler" | "mech-assembler"], s).borrow()); + base +}, |_, reg, map, buff| read_assembler(reg, map, buff)); - let mut r#in = load!(s -> match name { - "additive-reconstructor" => "factory-in-3", - "multiplicative-reconstructor" => "factory-in-5", - "tank-refabricator" | "mech-refabricator" | "ship-refabricator" => - "factory-in-3-dark", - "exponential-reconstructor" => "factory-in-7", - "prime-refabricator" | "tank-assembler" | "ship-assembler" | "mech-assembler" => - "factory-in-5-dark", - "tetrative-reconstructor" => "factory-in-9", - }); - base.overlay(r#in.rotate(times)); - } +/// format: +/// - call [`read_payload_block`] +/// - progress: [`f32`] +/// - iterate [`u8`] +/// - read: [`i32`] +/// - call [`read_payload_seq`] +/// - point: ([`f32`], [`f32`]) (maybe [`NaN`](f32::NAN)) +fn read_assembler(reg: &BlockRegistry, map: &EntityMapping, buff: &mut DataRead) -> Result<(), DataReadError> { + read_payload_block(reg, map, buff)?; + buff.skip(4)?; + let n = buff.read_u8()? as usize; + buff.skip(n * 4)?; + read_payload_seq(buff)?; + buff.skip(8) +} - // TODO: the context cross is too small - // for i in 0..4u8 { - // if let Some((b, rot)) = dbg!(ctx.cross[i as usize]) { - // if rot.mirrored(true, true) != ctx.rotation && match rot { - // Rotation::Up => i == 3, - // Rotation::Right => i == 4, - // Rotation::Down => i == 0, - // Rotation::Left => i == 2, - // } && is_pay(b.name()) - // { - // let r = unsafe { std::mem::transmute::<u8, Rotation>(i) } - // .mirrored(true, true) - // .rotated(false); - // let mut input = input.clone(); - // input.rotate(r.count()); - // base.overlay(&input); - // } - // } - // } - - base.overlay(load!(concat top => name which is ["additive-reconstructor" | "multiplicative-reconstructor" | "exponential-reconstructor" | "tetrative-reconstructor" | "tank-refabricator" | "mech-refabricator" | "ship-refabricator" | "prime-refabricator" | "tank-assembler" | "ship-assembler" | "mech-assembler"], s).borrow()); - if matches!(name, "mech-assembler" | "tank-assembler" | "ship-assembler") { - base.overlay( - match rot { - Rotation::Up | Rotation::Right => load!(s -> match name { - "mech-assembler" => "mech-assembler-side1", - "tank-assembler" => "tank-assembler-side1", - "ship-assembler" => "ship-assembler-side1", - }), - _ => load!(s -> match name { - "mech-assembler" => "mech-assembler-side2", - "tank-assembler" => "tank-assembler-side2", - "ship-assembler" => "ship-assembler-side2", - }), - } - .rotate(times), - ); - } - base -}); make_simple!(AssemblerModule, |_, _, _, _, rot: Rotation, scl| { let mut base = load!("basic-assembler-module", scl); base.overlay( @@ -112,7 +75,8 @@ make_simple!(AssemblerModule, |_, _, _, _, rot: Rotation, scl| { .rotate(rot.rotated(false).count()), ); base -}); +}, |_, reg, map, buff| read_payload_block(reg, map, buff)); + make_simple!( RepairTurret => |scl| { let mut bot = load!("block-2", scl); @@ -130,9 +94,9 @@ const AIR_UNITS: &[unit::Type] = &[unit::Type::Flare, unit::Type::Mono]; const NAVAL_UNITS: &[unit::Type] = &[unit::Type::Risso, unit::Type::Retusa]; make_register! { - "ground-factory" => AssemblerBlock::new(3, false, cost!(Copper: 50, Lead: 120, Silicon: 80), GROUND_UNITS); - "air-factory" => AssemblerBlock::new(3, false, cost!(Copper: 60, Lead: 70), AIR_UNITS); - "naval-factory" => AssemblerBlock::new(3, false, cost!(Copper: 150, Lead: 130, Metaglass: 120), NAVAL_UNITS); + "ground-factory" => UnitFactory::new(3, false, cost!(Copper: 50, Lead: 120, Silicon: 80), GROUND_UNITS); + "air-factory" => UnitFactory::new(3, false, cost!(Copper: 60, Lead: 70), AIR_UNITS); + "naval-factory" => UnitFactory::new(3, false, cost!(Copper: 150, Lead: 130, Metaglass: 120), NAVAL_UNITS); "additive-reconstructor" => ConstructorBlock::new(3, false, cost!(Copper: 200, Lead: 120, Silicon: 90)); "multiplicative-reconstructor" => ConstructorBlock::new(5, false, cost!(Lead: 650, Titanium: 350, Thorium: 650, Silicon: 450)); "exponential-reconstructor" => ConstructorBlock::new(7, false, @@ -141,29 +105,142 @@ make_register! { cost!(Lead: 4000, Thorium: 1000, Silicon: 3000, Plastanium: 600, PhaseFabric: 600, SurgeAlloy: 800)); "repair-point" => RepairTurret::new(1, true, cost!(Copper: 30, Lead: 30, Silicon: 20)); "repair-turret" => RepairTurret::new(2, true, cost!(Thorium: 80, Silicon: 90, Plastanium: 60)); - "tank-fabricator" => AssemblerBlock::new(3, true, cost!(Silicon: 200, Beryllium: 150), &[unit::Type::Stell]); - "ship-fabricator" => AssemblerBlock::new(3, true, cost!(Silicon: 250, Beryllium: 200), &[unit::Type::Elude]); - "mech-fabricator" => AssemblerBlock::new(3, true, cost!(Silicon: 200, Graphite: 300, Tungsten: 60), &[unit::Type::Merui]); + "tank-fabricator" => UnitFactory::new(3, true, cost!(Silicon: 200, Beryllium: 150), &[unit::Type::Stell]); + "ship-fabricator" => UnitFactory::new(3, true, cost!(Silicon: 250, Beryllium: 200), &[unit::Type::Elude]); + "mech-fabricator" => UnitFactory::new(3, true, cost!(Silicon: 200, Graphite: 300, Tungsten: 60), &[unit::Type::Merui]); "tank-refabricator" => ConstructorBlock::new(3, true, cost!(Beryllium: 200, Tungsten: 80, Silicon: 100)); "mech-refabricator" => ConstructorBlock::new(3, true, cost!(Beryllium: 250, Tungsten: 120, Silicon: 150)); "ship-refabricator" => ConstructorBlock::new(3, true, cost!(Beryllium: 200, Tungsten: 100, Silicon: 150, Oxide: 40)); "prime-refabricator" => ConstructorBlock::new(5, true, cost!(Thorium: 250, Oxide: 200, Tungsten: 200, Silicon: 400)); - "tank-assembler" => ConstructorBlock::new(5, true, cost!(Thorium: 500, Oxide: 150, Carbide: 80, Silicon: 500)); - "ship-assembler" => ConstructorBlock::new(5, true, cost!(Carbide: 100, Oxide: 200, Tungsten: 500, Silicon: 800, Thorium: 400)); - "mech-assembler" => ConstructorBlock::new(5, true, cost!(Carbide: 200, Thorium: 600, Oxide: 200, Tungsten: 500, Silicon: 900)); // smh collaris + "tank-assembler" => AssemblerBlock::new(5, true, cost!(Thorium: 500, Oxide: 150, Carbide: 80, Silicon: 500)); + "ship-assembler" => AssemblerBlock::new(5, true, cost!(Carbide: 100, Oxide: 200, Tungsten: 500, Silicon: 800, Thorium: 400)); + "mech-assembler" => AssemblerBlock::new(5, true, cost!(Carbide: 200, Thorium: 600, Oxide: 200, Tungsten: 500, Silicon: 900)); // smh collaris "basic-assembler-module" => AssemblerModule::new(5, true, cost!(Carbide: 300, Thorium: 500, Oxide: 200, PhaseFabric: 400)); // the dummy block "unit-repair-tower" -> BasicBlock::new(2, true, cost!(Graphite: 90, Silicon: 90, Tungsten: 80)); } -pub struct AssemblerBlock { +pub struct ConstructorBlock { + size: u8, + symmetric: bool, + build_cost: BuildCost, +} + +impl ConstructorBlock { + #[must_use] + pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost) -> Self { + assert!(size != 0, "invalid size"); + Self { + size, + symmetric, + build_cost, + } + } + + state_impl!(pub Option<UnitCommand>); +} + +impl BlockLogic for ConstructorBlock { + impl_block!(); + + fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { + Ok(DynData::Empty) + } + + fn deserialize_state(&self, data: DynData) -> Result<Option<State>, DeserializeError> { + match data { + DynData::Empty => Ok(Some(Self::create_state(None))), + DynData::UnitCommand(u) => Ok(Some(Self::create_state(Some(u)))), + _ => Err(DeserializeError::InvalidType { have: data.get_type(), expect: DynType::UnitCommand }) + } + } + + fn clone_state(&self, state: &State) -> State { + Box::new(*Self::get_state(state)) + } + + fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> { + Ok(Self::get_state(state).map_or(DynData::Empty, DynData::UnitCommand)) + } + + fn draw( + &self, + name: &str, + _: Option<&State>, + _: Option<&RenderingContext>, + rot: Rotation, + s: Scale, + ) -> ImageHolder { + let mut base = load!(from name which is ["additive-reconstructor" | "multiplicative-reconstructor" | "exponential-reconstructor" | "tetrative-reconstructor" | "tank-refabricator" | "mech-refabricator" | "ship-refabricator" | "prime-refabricator"], s); + let times = rot.rotated(false).count(); + let mut out = load!(s -> match name { + "additive-reconstructor" => "factory-out-3", + "multiplicative-reconstructor" => "factory-out-5", + "tank-refabricator" | "mech-refabricator" | "ship-refabricator" => + "factory-out-3-dark", + "exponential-reconstructor" => "factory-out-7", + "prime-refabricator" => "factory-out-5-dark", + "tetrative-reconstructor" => "factory-out-9", + }); + base.overlay(out.rotate(times)); + + let mut r#in = load!(s -> match name { + "additive-reconstructor" => "factory-in-3", + "multiplicative-reconstructor" => "factory-in-5", + "tank-refabricator" | "mech-refabricator" | "ship-refabricator" => + "factory-in-3-dark", + "exponential-reconstructor" => "factory-in-7", + "prime-refabricator" => "factory-in-5-dark", + "tetrative-reconstructor" => "factory-in-9", + }); + base.overlay(r#in.rotate(times)); + + // TODO: the context cross is too small + // for i in 0..4u8 { + // if let Some((b, rot)) = dbg!(ctx.cross[i as usize]) { + // if rot.mirrored(true, true) != ctx.rotation && match rot { + // Rotation::Up => i == 3, + // Rotation::Right => i == 4, + // Rotation::Down => i == 0, + // Rotation::Left => i == 2, + // } && is_pay(b.name()) + // { + // let r = unsafe { std::mem::transmute::<u8, Rotation>(i) } + // .mirrored(true, true) + // .rotated(false); + // let mut input = input.clone(); + // input.rotate(r.count()); + // base.overlay(&input); + // } + // } + // } + + base.overlay(load!(concat top => name which is ["additive-reconstructor" | "multiplicative-reconstructor" | "exponential-reconstructor" | "tetrative-reconstructor" | "tank-refabricator" | "mech-refabricator" | "ship-refabricator" | "prime-refabricator"], s).borrow()); + base + } + + /// format: + /// - call [`read_payload_block`] + /// - progress: [`f32`] + /// - point: ([`f32`], [`f32`]) (maybe [`NaN`](f32::NAN)) + /// - command: [`DynData::UnitCommand`] + fn read(&self,b: &mut Build,reg: &BlockRegistry,map: &EntityMapping,buff: &mut DataRead,) -> Result<(),DataReadError> { + read_payload_block(reg,map, buff)?; + buff.skip(12)?; + // TODO handlerr + b.state = self.deserialize_state(DynSerializer.deserialize(buff).unwrap()).unwrap(); + Ok(()) + } +} + +pub struct UnitFactory { size: u8, symmetric: bool, build_cost: BuildCost, valid: &'static [unit::Type], } -impl AssemblerBlock { +impl UnitFactory { #[must_use] pub const fn new( size: u8, @@ -185,7 +262,7 @@ impl AssemblerBlock { state_impl!(pub Option<unit::Type>); } -impl BlockLogic for AssemblerBlock { +impl BlockLogic for UnitFactory { impl_block!(); fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { |