mindustry logic execution, map- and schematic- parsing and rendering
fill the other arm of `read_payload` (#8)
bendn 2023-08-17
parent e1ec9c6 · commit dc9bfdf
-rw-r--r--Cargo.toml1
-rw-r--r--src/block/defense.rs6
-rw-r--r--src/block/distribution.rs28
-rw-r--r--src/block/drills.rs2
-rw-r--r--src/block/liquid.rs1
-rw-r--r--src/block/logic.rs6
-rw-r--r--src/block/mod.rs7
-rw-r--r--src/block/payload.rs103
-rw-r--r--src/block/power.rs8
-rw-r--r--src/block/production.rs6
-rw-r--r--src/block/simple.rs7
-rw-r--r--src/block/turrets.rs10
-rw-r--r--src/block/units.rs28
-rw-r--r--src/block/walls.rs1
-rw-r--r--src/data/entity_mapping.rs26
-rw-r--r--src/data/map.rs41
-rw-r--r--src/data/mod.rs1
-rw-r--r--src/data/schematic.rs3
-rw-r--r--src/modifier.rs6
-rw-r--r--src/team.rs2
-rw-r--r--src/unit/mod.rs217
21 files changed, 348 insertions, 162 deletions
diff --git a/Cargo.toml b/Cargo.toml
index ce01234..d40ff8e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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),
- &reg,
- &HashMap::default(),
- &mut r,
- )
- .unwrap();
+ read_payload_conveyor(&mut Build::new(&PAYLOAD_CONVEYOR), &reg, &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),
- &reg,
- &HashMap::default(),
- &mut r,
- )
- .unwrap();
+ read_payload_conveyor(&mut Build::new(&PAYLOAD_CONVEYOR), &reg, &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)
+}