mindustry logic execution, map- and schematic- parsing and rendering
fill the other arm of `read_payload` (#8)
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/block/defense.rs | 6 | ||||
| -rw-r--r-- | src/block/distribution.rs | 28 | ||||
| -rw-r--r-- | src/block/drills.rs | 2 | ||||
| -rw-r--r-- | src/block/liquid.rs | 1 | ||||
| -rw-r--r-- | src/block/logic.rs | 6 | ||||
| -rw-r--r-- | src/block/mod.rs | 7 | ||||
| -rw-r--r-- | src/block/payload.rs | 103 | ||||
| -rw-r--r-- | src/block/power.rs | 8 | ||||
| -rw-r--r-- | src/block/production.rs | 6 | ||||
| -rw-r--r-- | src/block/simple.rs | 7 | ||||
| -rw-r--r-- | src/block/turrets.rs | 10 | ||||
| -rw-r--r-- | src/block/units.rs | 28 | ||||
| -rw-r--r-- | src/block/walls.rs | 1 | ||||
| -rw-r--r-- | src/data/entity_mapping.rs | 26 | ||||
| -rw-r--r-- | src/data/map.rs | 41 | ||||
| -rw-r--r-- | src/data/mod.rs | 1 | ||||
| -rw-r--r-- | src/data/schematic.rs | 3 | ||||
| -rw-r--r-- | src/modifier.rs | 6 | ||||
| -rw-r--r-- | src/team.rs | 2 | ||||
| -rw-r--r-- | src/unit/mod.rs | 217 |
21 files changed, 348 insertions, 162 deletions
@@ -17,6 +17,7 @@ flate2 = { version = "1.0", features = ["zlib"], default-features = false } base64 = "0.21" paste = "1.0" strconv = "0.1" +amap = "0.1" image = { version = "0.24", features = [], default-features = false, optional = true } color-hex = "0.2" thiserror = "1.0" diff --git a/src/block/defense.rs b/src/block/defense.rs index b1548bc..19d067f 100644 --- a/src/block/defense.rs +++ b/src/block/defense.rs @@ -1,9 +1,9 @@ //! defense use crate::block::simple::{cost, make_simple, BasicBlock}; use crate::block::*; -make_simple!(HeatedBlock => |_, _, _, buff: &mut DataRead| read_heated(buff)); -make_simple!(RadarBlock => |_, _, _, buff: &mut DataRead| buff.skip(4)); -make_simple!(ShieldBlock => |_, _, _, buff: &mut DataRead| read_shield(buff)); +make_simple!(HeatedBlock => |_, _, buff: &mut DataRead| read_heated(buff)); +make_simple!(RadarBlock => |_, _, buff: &mut DataRead| buff.skip(4)); +make_simple!(ShieldBlock => |_, _, buff: &mut DataRead| read_shield(buff)); make_register! { "mender" -> HeatedBlock::new(1, true, cost!(Copper: 25, Lead: 30)); "mend-projector" -> HeatedBlock::new(2, true, cost!(Copper: 50, Lead: 100, Titanium: 25, Silicon: 40)); diff --git a/src/block/distribution.rs b/src/block/distribution.rs index 7186535..6b83d90 100644 --- a/src/block/distribution.rs +++ b/src/block/distribution.rs @@ -9,7 +9,7 @@ use crate::item; make_simple!( ConveyorBlock, |_, name, _, ctx: Option<&RenderingContext>, rot, s| tile(ctx.unwrap(), name, rot, s), - |_, _, _, buff: &mut DataRead| { + |_, _, buff: &mut DataRead| { // format: // - amount: `i32` // - iterate amount: @@ -28,14 +28,14 @@ make_simple!( make_simple!( DuctBlock, |_, name, _, ctx: Option<&RenderingContext>, rot, s| tile(ctx.unwrap(), name, rot, s), - |_, _, _, buff: &mut DataRead| { + |_, _, buff: &mut DataRead| { // format: // - rec_dir: `i8` buff.skip(1) } ); -make_simple!(JunctionBlock => |_, _, _, buff| { read_directional_item_buffer(buff) }); +make_simple!(JunctionBlock => |_, _, buff| { read_directional_item_buffer(buff) }); make_simple!(SimpleDuctBlock, |_, name, _, _, rot: Rotation, s| { let mut base = load!("duct-base", s); let mut top = load!(from name which is ["overflow-duct" "underflow-duct"], s); @@ -118,15 +118,19 @@ make_simple!( // format: // - link: `i32` // - cooldown: `f32` - |_, _, _, buff: &mut DataRead| buff.skip(8) + |_, _, buff: &mut DataRead| buff.skip(8) +); +make_simple!( + SurgeRouter, + |_, _, _, _, r: Rotation, s| { + let mut base = load!("surge-router", s); + unsafe { base.overlay(load!("top", s).rotate(r.rotated(false).count())) }; + base + }, + |_, _, buff: &mut DataRead| buff.skip(2) ); -make_simple!(SurgeRouter, |_, _, _, _, r: Rotation, s| { - let mut base = load!("surge-router", s); - unsafe { base.overlay(load!("top", s).rotate(r.rotated(false).count())) }; - base -}); // format: id: [`i32`] -make_simple!(UnitCargoLoader => |_, _, _, buff: &mut DataRead| buff.skip(4)); +make_simple!(UnitCargoLoader => |_, _, buff: &mut DataRead| buff.skip(4)); make_register! { "conveyor" => ConveyorBlock::new(1, false, cost!(Copper: 1)); @@ -262,7 +266,6 @@ impl BlockLogic for ItemBlock { &self, b: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { match b.block.name() { @@ -437,7 +440,6 @@ impl BlockLogic for BridgeBlock { &self, t: &mut Build, r: &super::BlockRegistry, - e: &crate::data::map::EntityMapping, buff: &mut crate::data::DataRead, ) -> Result<(), crate::data::ReadError> { match t.block.name() { @@ -445,7 +447,7 @@ impl BlockLogic for BridgeBlock { "phase-conveyor" | "phase-conduit" | "bridge-conduit" => read_item_bridge(buff)?, "mass-driver" => buff.skip(9)?, "payload-mass-driver" | "large-payload-mass-driver" => { - crate::block::payload::read_payload_block(r, e, buff)?; + crate::block::payload::read_payload_block(r, buff)?; buff.skip(19)?; } // no state? diff --git a/src/block/drills.rs b/src/block/drills.rs index 4558666..3674e47 100644 --- a/src/block/drills.rs +++ b/src/block/drills.rs @@ -13,7 +13,7 @@ make_simple!( }; base }, - |_, _, _, buff: &mut DataRead| read_drill(buff) + |_, _, buff: &mut DataRead| read_drill(buff) ); make_simple!(WallDrillBlock, |_, _, _, _, rot: Rotation, scl| { let mut base = load!("cliff-crusher", scl); diff --git a/src/block/liquid.rs b/src/block/liquid.rs index d20fb47..ec6978e 100644 --- a/src/block/liquid.rs +++ b/src/block/liquid.rs @@ -127,7 +127,6 @@ impl BlockLogic for FluidBlock { &self, b: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { let f = buff.read_u16()?; diff --git a/src/block/logic.rs b/src/block/logic.rs index a099765..153f637 100644 --- a/src/block/logic.rs +++ b/src/block/logic.rs @@ -10,7 +10,7 @@ use crate::data::{self, CompressError, DataRead, DataWrite}; make_simple!( MemoryBlock => - |_, _, _, buff: &mut DataRead| { + |_, _, buff: &mut DataRead| { // format: // - iterate [`u32`] // - memory: [`f64`] @@ -181,7 +181,6 @@ impl BlockLogic for CanvasBlock { &self, build: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { let n = buff.read_i32()? as usize; @@ -256,7 +255,6 @@ impl BlockLogic for MessageLogic { &self, b: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { b.state = Some(Self::create_state(buff.read_utf()?.to_string())); @@ -310,7 +308,6 @@ impl BlockLogic for SwitchLogic { &self, build: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { build.state = Some(Self::create_state(buff.read_bool()?)); @@ -416,7 +413,6 @@ impl BlockLogic for ProcessorLogic { &self, b: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { let n = buff.read_u32()? as usize; diff --git a/src/block/mod.rs b/src/block/mod.rs index 15b6d97..daf9ad1 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -8,7 +8,7 @@ use std::error::Error; use std::fmt; use crate::data::dynamic::{DynData, DynType}; -use crate::data::map::{Build, EntityMapping}; +use crate::data::map::Build; use crate::data::{self, renderer::*, CompressError}; use crate::data::{DataRead, GridPos, ReadError as DataReadError}; use crate::item::storage::ItemStorage; @@ -73,6 +73,7 @@ disp! { ConnectorBlock, ItemTurret, ConveyorBlock, + PayloadRouter, WallDrillBlock, DrillBlock, NuclearGeneratorBlock, @@ -213,7 +214,6 @@ pub trait BlockLogic { &self, build: &mut Build, reg: &BlockRegistry, - mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { Ok(()) @@ -412,10 +412,9 @@ impl Block { &self, build: &mut Build, reg: &BlockRegistry, - mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { - self.logic.read(build, reg, mapping, buff) + self.logic.read(build, reg, buff) } } diff --git a/src/block/payload.rs b/src/block/payload.rs index 6a8ef11..fef2246 100644 --- a/src/block/payload.rs +++ b/src/block/payload.rs @@ -7,6 +7,7 @@ use crate::block::simple::*; use crate::block::{self, *}; use crate::content::{self, Content}; use crate::data::dynamic::DynType; +use crate::data::entity_mapping; use crate::data::ReadError; use crate::unit; @@ -56,13 +57,24 @@ make_simple!( }, read_payload_conveyor ); -// make_simple!(PayloadRouter => read_payload_router); + +make_simple!( + PayloadRouter, + |_, n, _, _, r: Rotation, s| { + let mut base = load!(from n which is ["payload-router" | "reinforced-payload-router"], s); + unsafe { + base.rotate(r.rotated(false).count()); + base.overlay(& load!(concat "over" => n which is ["payload-router" | "reinforced-payload-router"], s)); + } + base + } // read_payload_router +); make_register! { "payload-conveyor" => PayloadConveyor::new(3, false, cost!(Copper: 10, Graphite: 10)); - "payload-router" => PayloadBlock::new(3, false, cost!(Copper: 10, Graphite: 15)); + "payload-router" => PayloadRouter::new(3, false, cost!(Copper: 10, Graphite: 15)); "reinforced-payload-conveyor" => PayloadConveyor::new(3, false, cost!(Tungsten: 10)); - "reinforced-payload-router" => PayloadBlock::new(3, false, cost!(Tungsten: 15)); + "reinforced-payload-router" => PayloadRouter::new(3, false, cost!(Tungsten: 15)); "payload-mass-driver" -> BridgeBlock::new(3, true, cost!(Tungsten: 120, Silicon: 120, Graphite: 50), 700, false); "large-payload-mass-driver" -> BridgeBlock::new(5, true, cost!(Thorium: 200, Tungsten: 200, Silicon: 200, Graphite: 100, Oxide: 30), 1100, false); "small-deconstructor" => SimplePayloadBlock::new(3, true, cost!(Beryllium: 100, Silicon: 100, Oxide: 40, Graphite: 80)); @@ -116,31 +128,19 @@ impl BlockLogic for PayloadBlock { r: Rotation, s: Scale, ) -> ImageHolder<4> { - match name { - "payload-router" | "reinforced-payload-router" => { - let mut base = - load!(from name which is ["payload-router" | "reinforced-payload-router"], s); - unsafe { - base.rotate(r.rotated(false).count()); - base.overlay(& load!(concat "over" => name which is ["payload-router" | "reinforced-payload-router"], s)); - } - base - } - _ => { - let mut base = load!(from name which is ["constructor" | "large-constructor" | "payload-source"], s); - let mut out = load!(s -> match name { - "constructor" => "factory-out-3", - "large-constructor" => "factory-out-5-dark", - _ => "factory-out-5", - }); - unsafe { - out.rotate(r.rotated(false).count()); - base.overlay(&out); - base.overlay(&load!(concat "top" => name which is ["constructor" | "large-constructor" | "payload-source"], s)) - }; - base - } - } + let mut base = + load!(from name which is ["constructor" | "large-constructor" | "payload-source"], s); + let mut out = load!(s -> match name { + "constructor" => "factory-out-3", + "large-constructor" => "factory-out-5-dark", + _ => "factory-out-5", + }); + unsafe { + out.rotate(r.rotated(false).count()); + base.overlay(&out); + base.overlay(&load!(concat "top" => name which is ["constructor" | "large-constructor" | "payload-source"], s)) + }; + base } fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> { @@ -185,25 +185,23 @@ impl BlockLogic for PayloadBlock { fn read_payload_router( b: &mut Build, reg: &BlockRegistry, - entity_mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { - read_payload_conveyor(b, reg, entity_mapping, buff)?; + read_payload_conveyor(b, reg, buff)?; buff.skip(4) } /// format: -/// - [skip(4)](`DataRead::skip`) +/// - [`skip(4)`](`DataRead::skip`) /// - rot: [`f32`] /// - become [`read_payload`] fn read_payload_conveyor( _: &mut Build, reg: &BlockRegistry, - entity_mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { buff.skip(8)?; - read_payload(reg, entity_mapping, buff) + read_payload(reg, buff) } /// format: @@ -220,11 +218,10 @@ pub(crate) fn read_payload_seq(buff: &mut DataRead) -> Result<(), DataReadError> /// - become [`read_payload`] pub(crate) fn read_payload_block( reg: &BlockRegistry, - entity_mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { buff.skip(12)?; - read_payload(reg, entity_mapping, buff) + read_payload(reg, buff) } /// format: @@ -237,12 +234,8 @@ pub(crate) fn read_payload_block( /// - [`BlockLogic::read`] (recursion :ferrisHmm:), /// - if type == 2 (paylood unit): /// - id: [`u8`] -/// - unit read???????? TODO -fn read_payload( - reg: &BlockRegistry, - entity_mapping: &crate::data::map::EntityMapping, - buff: &mut DataRead, -) -> Result<(), DataReadError> { +/// - call [`UnitClass::read`](crate::data::entity_mapping::UnitClass::read) +fn read_payload(reg: &BlockRegistry, buff: &mut DataRead) -> Result<(), DataReadError> { if !buff.read_bool()? { return Ok(()); } @@ -254,16 +247,14 @@ fn read_payload( let b = buff.read_u16()?; let b = BlockEnum::try_from(b).unwrap_or(BlockEnum::Router); let block = reg.get(b.get_name()).unwrap(); - block - .logic - .read(&mut Build::new(block), reg, entity_mapping, buff)?; + block.logic.read(&mut Build::new(block), reg, buff)?; } UNIT => { - let u = buff.read_u8()?; - let Some(_u) = entity_mapping.get(&u) else { + let u = buff.read_u8()? as usize; + let Some(&Some(u)) = entity_mapping::ID.get(u) else { return Err(ReadError::Expected("map entry")); }; - // unit::Type::try_from(u).unwrap_or(unit::Type::Alpha).read(todo!()); + let _ = u.read(buff)?; } _ => return Err(ReadError::Expected("0 | 1")), } @@ -272,8 +263,6 @@ fn read_payload( #[cfg(test)] mod tests { - use std::collections::HashMap; - use crate::registry::Registry; use super::*; @@ -282,24 +271,12 @@ mod tests { let mut reg = Registry::default(); register(&mut reg); let mut r = DataRead::new(&[0, 0, 0, 0, 0, 0, 0, 0, 0]); - read_payload_conveyor( - &mut Build::new(&PAYLOAD_CONVEYOR), - ®, - &HashMap::default(), - &mut r, - ) - .unwrap(); + read_payload_conveyor(&mut Build::new(&PAYLOAD_CONVEYOR), ®, &mut r).unwrap(); assert!(r.read_bool().is_err()); let mut r = DataRead::new(&[ 65, 198, 232, 0, 67, 51, 255, 249, 1, 1, 0, 157, 0, 67, 197, 128, 0, 128, 1, 3, ]); - read_payload_conveyor( - &mut Build::new(&PAYLOAD_CONVEYOR), - ®, - &HashMap::default(), - &mut r, - ) - .unwrap(); + read_payload_conveyor(&mut Build::new(&PAYLOAD_CONVEYOR), ®, &mut r).unwrap(); assert!(r.read_bool().is_err()); } } diff --git a/src/block/power.rs b/src/block/power.rs index 62f32f8..b316afb 100644 --- a/src/block/power.rs +++ b/src/block/power.rs @@ -5,9 +5,9 @@ use crate::block::simple::*; use crate::block::*; use crate::data::dynamic::DynType; -make_simple!(GeneratorBlock => |_, _, _, buff: &mut DataRead| read_generator(buff)); -make_simple!(NuclearGeneratorBlock => |_, _, _, buff: &mut DataRead| read_nuclear(buff)); -make_simple!(ImpactReactorBlock => |_, _, _, buff: &mut DataRead| read_impact(buff)); +make_simple!(GeneratorBlock => |_, _, buff: &mut DataRead| read_generator(buff)); +make_simple!(NuclearGeneratorBlock => |_, _, buff: &mut DataRead| read_nuclear(buff)); +make_simple!(ImpactReactorBlock => |_, _, buff: &mut DataRead| read_impact(buff)); make_simple!( Neoplasia, |_, _, _, _, rot: Rotation, scl| { @@ -23,7 +23,7 @@ make_simple!( }; base }, - |_, _, _, buff: &mut DataRead| read_heater(buff) + |_, _, buff: &mut DataRead| read_heater(buff) ); make_simple!(DiodeBlock, |_, _, _, _, rot: Rotation, s| { let mut base = load!("diode", s); diff --git a/src/block/production.rs b/src/block/production.rs index cd48482..ee435a6 100644 --- a/src/block/production.rs +++ b/src/block/production.rs @@ -44,7 +44,7 @@ make_register! { } // format: call [`read_production_block`], seed: [`i32`] -make_simple!(SeparatorBlock => |_, _, _, buff: &mut DataRead| buff.skip(12)); +make_simple!(SeparatorBlock => |_, _, buff: &mut DataRead| buff.skip(12)); make_simple!( ProductionBlock, @@ -70,7 +70,7 @@ make_simple!( } base }, - |b: &mut Build<'_>, _, _, buff: &mut DataRead| { + |b: &mut Build<'_>, _, buff: &mut DataRead| { // format: // - progress: `f32` // - warmup: `f32` @@ -92,7 +92,7 @@ make_simple!( }; base }, - |_, _, _, buff: &mut DataRead| { + |_, _, buff: &mut DataRead| { // format: // - progress: `f32` // - warmup: `f32` diff --git a/src/block/simple.rs b/src/block/simple.rs index 5c4c326..b100b15 100644 --- a/src/block/simple.rs +++ b/src/block/simple.rs @@ -96,16 +96,15 @@ macro_rules! make_simple { &self, build: &mut crate::data::map::Build, reg: &crate::block::BlockRegistry, - entity_mapping: &crate::data::map::EntityMapping, buff: &mut crate::data::DataRead, ) -> Result<(), crate::data::ReadError> { #[allow(clippy::redundant_closure_call)] - $read(build, reg, entity_mapping, buff) + $read(build, reg, buff) } } }; ($name: ident, $draw: expr) => { - crate::block::simple::make_simple!($name, $draw, |_, _, _, _| Ok(())); + crate::block::simple::make_simple!($name, $draw, |_, _, _| Ok(())); }; ($name: ident, $draw: expr, $read: expr) => { crate::block::simple::make_simple!($name, $draw, $read); @@ -120,7 +119,7 @@ macro_rules! make_simple { crate::block::simple::make_simple!( $name, |_, _, _, _, _, scl| $draw(scl), - |_, _, _, _| Ok(()) + |_, _, _| Ok(()) ); }; ($name: ident) => { diff --git a/src/block/turrets.rs b/src/block/turrets.rs index 3e65ebe..3759c90 100644 --- a/src/block/turrets.rs +++ b/src/block/turrets.rs @@ -35,11 +35,11 @@ make_register! { "smite" -> ItemTurret::new(5, true, cost!(Oxide: 200, SurgeAlloy: 400, Silicon: 800, Carbide: 500, PhaseFabric: 300)); } -make_simple!(Turret => |_, _, _, buff: &mut DataRead| read_turret(buff)); -make_simple!(PointDefenseTurret => |_, _, _, buff: &mut DataRead| read_point_defense_turret(buff)); -make_simple!(ContinousTurret => |_, _, _, buff: &mut DataRead| read_continous_turret(buff)); -make_simple!(TractorBeamTurret => |_, _, _, buff: &mut DataRead| read_tractor_beam_turret(buff)); -make_simple!(ItemTurret => |_, _, _, buff: &mut DataRead| read_item_turret(buff)); +make_simple!(Turret => |_, _, buff: &mut DataRead| read_turret(buff)); +make_simple!(PointDefenseTurret => |_, _, buff: &mut DataRead| read_point_defense_turret(buff)); +make_simple!(ContinousTurret => |_, _, buff: &mut DataRead| read_continous_turret(buff)); +make_simple!(TractorBeamTurret => |_, _, buff: &mut DataRead| read_tractor_beam_turret(buff)); +make_simple!(ItemTurret => |_, _, buff: &mut DataRead| read_item_turret(buff)); /// format: /// - call [`read_turret`] diff --git a/src/block/units.rs b/src/block/units.rs index 83b39af..d482a2c 100644 --- a/src/block/units.rs +++ b/src/block/units.rs @@ -3,10 +3,10 @@ use thiserror::Error; use super::payload::{read_payload_block, read_payload_seq}; use crate::block::simple::*; -use crate::block::*; use crate::data::command::UnitCommand; -use crate::data::dynamic::DynType; +use crate::data::dynamic::{DynSerializer, DynType}; use crate::unit; +use crate::{block::*, Serializer}; // fn is_pay(b: &str) -> bool { // matches!( @@ -51,7 +51,7 @@ make_simple!( }; base }, - |_, reg, map, buff| read_assembler(reg, map, buff) + |_, reg, buff| read_assembler(reg, buff) ); /// format: @@ -61,12 +61,8 @@ make_simple!( /// - 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)?; +fn read_assembler(reg: &BlockRegistry, buff: &mut DataRead) -> Result<(), DataReadError> { + read_payload_block(reg, buff)?; buff.skip(4)?; let n = buff.read_u8()? as usize; buff.skip(n * 4)?; @@ -89,11 +85,11 @@ make_simple!( }; base }, - |_, reg, map, buff| read_payload_block(reg, map, buff) + |_, reg, buff| read_payload_block(reg, buff) ); make_simple!( - RepairTurret => |_, _, _, buff: &mut DataRead| { + RepairTurret => |_, _, buff: &mut DataRead| { buff.skip(4) // rotation: [`f32`] } ); @@ -238,13 +234,12 @@ impl BlockLogic for ConstructorBlock { &self, _: &mut Build, reg: &BlockRegistry, - map: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { - read_payload_block(reg, map, buff)?; + read_payload_block(reg, buff)?; buff.skip(12)?; - // TODO uncomment when read_payload_block impl finished - // b.state = self.deserialize_state(DynSerializer.deserialize(buff).unwrap()).unwrap(); + self.deserialize_state(DynSerializer.deserialize(buff).unwrap()) + .unwrap(); Ok(()) } } @@ -360,10 +355,9 @@ impl BlockLogic for UnitFactory { &self, _: &mut Build, reg: &BlockRegistry, - mapping: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { - read_payload_block(reg, mapping, buff)?; + read_payload_block(reg, buff)?; buff.skip(14) } } diff --git a/src/block/walls.rs b/src/block/walls.rs index 4eaad5c..6b14cda 100644 --- a/src/block/walls.rs +++ b/src/block/walls.rs @@ -109,7 +109,6 @@ impl BlockLogic for DoorBlock { &self, build: &mut Build, _: &BlockRegistry, - _: &EntityMapping, buff: &mut DataRead, ) -> Result<(), DataReadError> { build.state = Some(Self::create_state(buff.read_bool()?)); diff --git a/src/data/entity_mapping.rs b/src/data/entity_mapping.rs new file mode 100644 index 0000000..eda8479 --- /dev/null +++ b/src/data/entity_mapping.rs @@ -0,0 +1,26 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum UnitClass { + Block, + Legs, + Elevated, + Crawl, + Mech, + Tethered, + Payload, + Bomb, + Boat, + Tank, +} + +pub static ID: [Option<UnitClass>; 47] = amap::amap! { + 2 => UnitClass::Block, + 24 => UnitClass::Legs, + 45 => UnitClass::Elevated, + 46 => UnitClass::Crawl, + 4 => UnitClass::Mech, + 36 => UnitClass::Tethered, + 5 => UnitClass::Payload, + 39 => UnitClass::Bomb, + 20 => UnitClass::Boat, + 43 => UnitClass::Tank, +}; diff --git a/src/data/map.rs b/src/data/map.rs index 4e7cb9e..f515687 100644 --- a/src/data/map.rs +++ b/src/data/map.rs @@ -41,7 +41,7 @@ //! - chunk len: `u16` //! - if block == building: //! - revision: `i8` -//! - [`read`] +//! - [`Build::read`] //! - else skip `chunk len` //! - or data //! - data: `i8` @@ -105,7 +105,6 @@ macro_rules! lo { } }; } -pub type EntityMapping = HashMap<u8, Box<dyn Content>>; impl<'l> Tile<'l> { #[must_use] pub const fn new(floor: BlockEnum, ore: BlockEnum) -> Self { @@ -305,12 +304,7 @@ impl<'l> Build<'l> { self.block.name() } - pub fn read( - &mut self, - buff: &mut DataRead<'_>, - reg: &BlockRegistry, - map: &EntityMapping, - ) -> Result<(), ReadError> { + pub fn read(&mut self, buff: &mut DataRead<'_>, reg: &BlockRegistry) -> Result<(), ReadError> { // health let _ = buff.read_f32()?; let rot = buff.read_i8()? as i16; @@ -344,7 +338,7 @@ impl<'l> Build<'l> { buff.skip(4)?; } // "overridden by subclasses" - self.block.read(self, reg, map, buff)?; + self.block.read(self, reg, buff)?; // implementation not complete, simply error, causing the remaining bytes in the chunk to be skipped (TODO finish impl) Err(ReadError::Version(0x0)) // Ok(()) @@ -610,10 +604,8 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { .ok_or_else(|| ReadError::NoSuchBlock(block.to_string()))?, ) }; - if central { - if let Some(block) = block { - map[i].set_block(block); - } + if central && let Some(block) = block { + map[i].set_block(block); } if entity { if central { @@ -624,12 +616,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { println!("reading {:?}", map[i].build.as_ref().unwrap()); let _ = buff.read_i8()?; - map[i] - .build - .as_mut() - .unwrap() - // map not initialized yet - .read(buff, self.0, &HashMap::new())?; + map[i].build.as_mut().unwrap().read(buff, self.0)?; Ok::<(), ReadError>(()) }); } @@ -652,15 +639,11 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { m = Some(map); Ok::<(), ReadError>(()) })?; - let mut mapping = EntityMapping::new(); buff.read_chunk(true, |buff| { // read entity mapping (SaveVersion.java#436) for _ in 0..buff.read_u16()? { - let id = buff.read_u16()? as u8; - let nam = buff.read_utf()?; - dbg!(nam); - mapping.insert(id, Box::new(Item::Copper)); - // mapping.push(content::Type::get_name(nam)); + buff.skip(2)?; + let _ = buff.read_utf()?; } // read team block plans (ghosts) (SaveVersion.java#389) for _ in 0..buff.read_u32()? { @@ -673,13 +656,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { // read world entities (#412). eg units for _ in 0..buff.read_u32()? { let len = buff.read_u16()? as usize; - let ty = buff.read_u8()?; - if !mapping.contains_key(&ty) { - buff.skip(len - 1)?; - continue; - } - let _id = buff.read_u32()?; - // TODO + buff.skip(len)?; } Ok::<(), ReadError>(()) })?; diff --git a/src/data/mod.rs b/src/data/mod.rs index 0583ea4..3eccbd1 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -13,6 +13,7 @@ pub(crate) mod autotile; mod base64; pub mod command; pub mod dynamic; +pub mod entity_mapping; pub mod map; pub mod planet; pub mod renderer; diff --git a/src/data/schematic.rs b/src/data/schematic.rs index 31888c2..7ad2a67 100644 --- a/src/data/schematic.rs +++ b/src/data/schematic.rs @@ -61,9 +61,6 @@ impl<'l> Placement<'l> { } /// draws this placement in particular - /// - /// # Safety - /// UB if called before [`warmup`](crate::warmup) #[must_use] pub fn image( &self, diff --git a/src/modifier.rs b/src/modifier.rs index bf1d867..7f9777e 100644 --- a/src/modifier.rs +++ b/src/modifier.rs @@ -28,3 +28,9 @@ content_enum! { "invincible", } } + +impl Default for Type { + fn default() -> Self { + Self::None + } +} diff --git a/src/team.rs b/src/team.rs index 35a651f..a10209f 100644 --- a/src/team.rs +++ b/src/team.rs @@ -2,7 +2,7 @@ use std::fmt; use crate::content::{Content, Type}; -#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Default)] pub struct Team(u8); impl Team { diff --git a/src/unit/mod.rs b/src/unit/mod.rs index 603b376..f96f5a3 100644 --- a/src/unit/mod.rs +++ b/src/unit/mod.rs @@ -2,10 +2,17 @@ //! //! [source](https://github.com/Anuken/Mindustry/blob/master/core/src/mindustry/content/UnitTypes.java) use crate::content::content_enum; +use crate::data::command::UnitCommand; +use crate::data::dynamic::DynSerializer; +use crate::data::entity_mapping::UnitClass; +use crate::data::{DataRead, ReadError}; +use crate::item::Type as Item; +use crate::modifier::Type as Status; +use crate::team::Team; +use crate::Serializer; content_enum! { - pub enum Type / Unit for u16 | TryFromU16Error - { + pub enum Type / Unit for u16 | TryFromU16Error { "dagger", "mace", "fortress", @@ -73,3 +80,209 @@ content_enum! { "scathe-missile", } } + +#[derive(Default, Debug)] +pub struct UnitState { + pub ammo: f32, + pub elevation: f32, + pub flag: i64, + pub health: f32, + pub is_shooting: bool, + pub rotation: f32, + pub shield: f32, + pub stack: (Option<Item>, u32), + /// how many status can you realistically be afflicted with + pub status: [Status; 3], + pub team: Team, + pub velocity: (f32, f32), + pub position: (f32, f32), + pub controller: Controller, +} + +#[derive(Default, Debug)] +pub enum Controller { + Player(i32), + Logic(i32), + Command { + target: Option<i32>, + pos: Option<(f32, f32)>, + command: Option<UnitCommand>, + }, + #[default] + Assembler, +} + +impl Controller { + /// format: + /// - match [`u8`] + /// - (0): player + /// - player: [`i32`] + /// + /// - (3): logic ai + /// - position: [`i32`] + /// + /// - (6): command + /// - has_attack: [`bool`] + /// - has_pos: [`bool`] + /// - if `has_pos`: + /// - pos: ([`f32`], [`f32`]) + /// - if `has_attack`: + /// - ty: [`i8`] + /// - target_id: [`i32`] + /// - command: [`i8`] attempt as [`UnitCommand`] + /// - (_): assembler + fn read(buff: &mut DataRead) -> Result<Controller, ReadError> { + Ok(match buff.read_u8()? { + 0 => Controller::Player(buff.read_i32()?), + 3 => Controller::Logic(buff.read_i32()?), + 6 => { + let has_attack = buff.read_bool()?; + let pos = if buff.read_bool()? { + Some((buff.read_f32()?, buff.read_f32()?)) + } else { + None + }; + let target = if has_attack { + buff.skip(1)?; + Some(buff.read_i32()?) + } else { + None + }; + let n = buff.read_i8()?; + let command = if let Ok(n) = u8::try_from(n) && let Ok(u) = UnitCommand::try_from(n) { + Some(u) + } else { + None + }; + Controller::Command { + target, + pos, + command, + } + } + _ => Controller::Assembler, + }) + } +} + +#[derive(Debug)] +pub struct Unit { + pub state: UnitState, + pub ty: Type, +} + +impl UnitClass { + pub fn read(self, buff: &mut DataRead) -> Result<Unit, ReadError> { + buff.skip(2)?; + let mut state = UnitState::default(); + read_abilities(buff)?; + state.ammo = buff.read_f32()?; + state.controller = Controller::read(buff)?; + state.elevation = buff.read_f32()?; + state.flag = buff.read_i64()?; + state.health = buff.read_f32()?; + state.is_shooting = buff.read_bool()?; + dbg!(&state); + read_tile(buff)?; + read_mounts(buff)?; + read_plans(buff)?; + state.rotation = buff.read_f32()?; + state.shield = buff.read_f32()?; + buff.skip(1)?; // spawned_by_core + state.stack = read_stack(buff)?; + state.status = read_status(buff)?; + state.team = Team::of(buff.read_u8()?); + let ty = Type::try_from(buff.read_u16()?).unwrap(); + buff.skip(1)?; // update_building + state.velocity = (buff.read_f32()?, buff.read_f32()?); + state.position = (buff.read_f32()?, buff.read_f32()?); + + Ok(Unit { state, ty }) + } +} + +/// format: +/// - iterate [u8] +/// - ability: [`f32`] +fn read_abilities(buff: &mut DataRead) -> Result<(), ReadError> { + let n = buff.read_u8()? as usize; + buff.skip(n * 4) +} + +/// format: +/// - tile: [`i32`] +fn read_tile(buff: &mut DataRead) -> Result<(), ReadError> { + buff.skip(4) +} + +/// format: +/// - iterate [`u8`] +/// - state: [`u8`] +/// - x aim: [`f32`] +/// - y aim: [`f32`] +fn read_mounts(buff: &mut DataRead) -> Result<(), ReadError> { + let n = dbg!(buff.read_u8()? as usize); + buff.skip(n * 9) +} + +/// format: +/// - plan count: [`i32`] +/// - plan_count == -1 => return +/// - iterate `plan_count` +/// - call [`read_plan`] +fn read_plans(buff: &mut DataRead) -> Result<(), ReadError> { + let used = dbg!(buff.read_i32()?); + if used == -1 { + return Ok(()); + } + for _ in 0..used { + read_plan(buff)?; + } + Ok(()) +} + +/// format: +/// - ty: [`u8`] +/// - position: [`i32`] +/// - if ty != 1 +/// - block: [`u16`] +/// - rotation: [`i8`] +/// - has_config: [`bool`] +/// - config: [`DynData`](crate::data::dynamic::DynData) +fn read_plan(buff: &mut DataRead) -> Result<(), ReadError> { + let ty = buff.read_u8()?; + buff.skip(4)?; + if ty != 1 { + buff.skip(4)?; + let _ = DynSerializer.deserialize(buff).unwrap(); + } + Ok(()) +} + +/// format: +/// - item: [`i16`] attempt into [`Item`] +/// - count: [`u32`] +fn read_stack(buff: &mut DataRead) -> Result<(Option<Item>, u32), ReadError> { + let n = buff.read_i16()?; + Ok(( + (n != -1).then(|| Item::try_from(n as u16).unwrap()), + buff.read_u32()?, + )) +} + +/// read the status. +/// i take only 3 +/// +/// format: +/// - iterate [`i32`] +/// - status: [`u16`] attempt into [`Status`] +fn read_status(buff: &mut DataRead) -> Result<[Status; 3], ReadError> { + let mut status = [Status::None, Status::None, Status::None]; + for i in 0..buff.read_i32()? { + let this = Status::try_from(buff.read_u16()?).unwrap_or_default(); + if i < 3 { + status[i as usize] = this; + } + } + Ok(status) +} |