mindustry logic execution, map- and schematic- parsing and rendering
unit deser, take two (#9)
and final take
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/block/mod.rs | 4 | ||||
| -rw-r--r-- | src/block/payload.rs | 9 | ||||
| -rw-r--r-- | src/block/units.rs | 2 | ||||
| -rw-r--r-- | src/data/entity_mapping.rs | 13 | ||||
| -rw-r--r-- | src/data/map.rs | 11 | ||||
| -rw-r--r-- | src/data/mod.rs | 22 | ||||
| -rw-r--r-- | src/lib.rs | 7 | ||||
| -rw-r--r-- | src/unit/mod.rs | 118 |
9 files changed, 131 insertions, 57 deletions
@@ -1,6 +1,6 @@ [package] name = "mindus" -version = "4.0.9" +version = "4.0.10" edition = "2021" description = "A library for working with mindustry data formats (eg schematics and maps) (fork of plandustry)" authors = [ diff --git a/src/block/mod.rs b/src/block/mod.rs index f48a62d..dda19a5 100644 --- a/src/block/mod.rs +++ b/src/block/mod.rs @@ -328,7 +328,7 @@ impl Block { /// should you send context to [`image`]? #[must_use] #[inline] - pub fn wants_context(&self) -> bool { + pub const fn wants_context(&self) -> bool { use BlockLogicEnum::*; matches!( self.logic, @@ -936,7 +936,7 @@ make_register! { "water-extractor" -> BasicBlock::new(2, true, cost!(Copper: 30, Lead: 30, Metaglass: 30, Graphite: 30)); "oil-extractor" -> BasicBlock::new(3, true, cost!(Copper: 150, Lead: 115, Graphite: 175, Thorium: 115, Silicon: 75)); "vent-condenser" -> ProductionBlock::new(3, true, cost!(Graphite: 20, Beryllium: 60)); - "cliff-crusher" -> WallDrillBlock::new(2, false, cost!(Beryllium: 100, Graphite: 40)); + "cliff-crusher" => WallDrillBlock::new(2, false, cost!(Beryllium: 100, Graphite: 40)); "plasma-bore" => DrillBlock::new(2, false, cost!(Beryllium: 40)); "large-plasma-bore" => DrillBlock::new(3, false, cost!(Silicon: 100, Oxide: 25, Beryllium: 100, Tungsten: 70)); "impact-drill" -> DrillBlock::new(4, true, cost!(Silicon: 70, Beryllium: 90, Graphite: 60)); diff --git a/src/block/payload.rs b/src/block/payload.rs index 300e366..48b8e67 100644 --- a/src/block/payload.rs +++ b/src/block/payload.rs @@ -64,7 +64,8 @@ make_simple!( base.overlay(& load!(concat "over" => n which is ["payload-router" | "reinforced-payload-router"], s)); } base - } // read_payload_router + }, + read_payload_router ); #[derive(Clone, Copy, Debug, Eq, PartialEq)] @@ -203,7 +204,7 @@ pub(crate) fn read_payload_block(buff: &mut DataRead) -> Result<(), DataReadErro /// - if type == 2 (paylood unit): /// - id: [`u8`] /// - call [`UnitClass::read`](crate::data::entity_mapping::UnitClass::read) -fn read_payload(buff: &mut DataRead) -> Result<(), DataReadError> { +pub fn read_payload(buff: &mut DataRead) -> Result<(), DataReadError> { if !buff.read_bool()? { return Ok(()); } @@ -213,9 +214,11 @@ fn read_payload(buff: &mut DataRead) -> Result<(), DataReadError> { match t { BLOCK => { let b = buff.read_u16()?; + buff.skip(1)?; let b = BlockEnum::try_from(b).unwrap_or(BlockEnum::Router); let block = BLOCK_REGISTRY.get(b.get_name()).unwrap(); - block.logic.read(&mut Build::new(block), buff)?; + let mut b = Build::new(block); + let _ = b.read(buff); } UNIT => { let u = buff.read_u8()? as usize; diff --git a/src/block/units.rs b/src/block/units.rs index 4af1a64..1fe0ade 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::unit; -use crate::{block::*, Serializable}; // fn is_pay(b: &str) -> bool { // matches!( diff --git a/src/data/entity_mapping.rs b/src/data/entity_mapping.rs index eda8479..beed2b4 100644 --- a/src/data/entity_mapping.rs +++ b/src/data/entity_mapping.rs @@ -1,15 +1,18 @@ #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum UnitClass { Block, + // same read impl as block Legs, Elevated, Crawl, + Boat, + Tank, + Air, + // different read impl from block Mech, Tethered, Payload, Bomb, - Boat, - Tank, } pub static ID: [Option<UnitClass>; 47] = amap::amap! { @@ -17,10 +20,12 @@ pub static ID: [Option<UnitClass>; 47] = amap::amap! { 24 => UnitClass::Legs, 45 => UnitClass::Elevated, 46 => UnitClass::Crawl, - 4 => UnitClass::Mech, 36 => UnitClass::Tethered, - 5 => UnitClass::Payload, + 5 | 23 | 26 => UnitClass::Payload, 39 => UnitClass::Bomb, 20 => UnitClass::Boat, 43 => UnitClass::Tank, + 4 | 17 | 19 | 32 => UnitClass::Mech, + 21 | 29 | 33 => UnitClass::Legs, + 3 | 16 | 18 | 0 | 30 | 31 => UnitClass::Air, }; diff --git a/src/data/map.rs b/src/data/map.rs index edb3cb2..c4ad43d 100644 --- a/src/data/map.rs +++ b/src/data/map.rs @@ -84,7 +84,7 @@ use crate::team::{self, Team}; #[cfg(doc)] use crate::{block::content, data::*, fluid, item, modifier, unit}; -use super::Serializable; +use super::{entity_mapping, Serializable}; use crate::content::Content; use crate::utils::image::ImageUtils; @@ -655,7 +655,14 @@ impl<'l> Serializable for Map<'l> { // read world entities (#412). eg units for _ in 0..buff.read_u32()? { let len = buff.read_u16()? as usize; - buff.skip(len)?; + let id = buff.read_u8()? as usize; + let Some(&Some(u)) = entity_mapping::ID.get(id) else { + buff.skip(len - 1)?; + continue; + // return Ok(()); + }; + buff.skip(4)?; + let _ = u.read(buff)?; } Ok::<(), ReadError>(()) })?; diff --git a/src/data/mod.rs b/src/data/mod.rs index 85cbbd6..0cd1d66 100644 --- a/src/data/mod.rs +++ b/src/data/mod.rs @@ -139,28 +139,26 @@ impl<'d> DataRead<'d> { } else { self.read_u16()? as usize }; - self.read = 0; + let rb4 = self.read; let r = f(self); + let read = self.read - rb4; match r { Err(e) => { // skip this chunk - assert!( - len >= self.read, - "overread; supposed to read {len}; read {}", - self.read - ); - let n = len - self.read; + assert!(len >= read, "overread; supposed to read {len}; read {read}"); + let n = len - read; if n != 0 { #[cfg(debug_assertions)] - println!( - "supposed to read {len}; read {} - skipping excess", - self.read - ); + println!("supposed to read {len}; read {read} - skipping excess"); self.skip(n)?; }; Err(e) } - Ok(_) => Ok(()), + Ok(_) => { + debug_assert!(len >= read, "overread; supposed to read {len}; read {read}"); + debug_assert!((len - read) == 0, "supposed to read {len}; read {read}"); + Ok(()) + } } } @@ -8,7 +8,12 @@ let_chains, effects )] -#![allow(clippy::missing_safety_doc, clippy::missing_const_for_fn, clippy::perf)] +#![warn( + clippy::missing_safety_doc, + clippy::missing_const_for_fn, + clippy::dbg_macro, + clippy::perf +)] pub mod block; mod content; pub mod data; diff --git a/src/unit/mod.rs b/src/unit/mod.rs index b6db959..c7d66bf 100644 --- a/src/unit/mod.rs +++ b/src/unit/mod.rs @@ -1,6 +1,7 @@ //! units //! //! [source](https://github.com/Anuken/Mindustry/blob/master/core/src/mindustry/content/UnitTypes.java) +use crate::block::payload::read_payload; use crate::content::content_enum; use crate::data::command::UnitCommand; use crate::data::dynamic::DynData; @@ -177,36 +178,89 @@ impl UnitClass { 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()?; - // TODO apparently i fucked up my impl - // 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: Type::Alpha, - }) + match self { + Self::Block + | Self::Legs + | Self::Elevated + | Self::Crawl + | Self::Boat + | Self::Tank + | Self::Air => { + 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()?; + read_tile(buff)?; + read_mounts(buff)?; + } + Self::Mech => { + buff.skip(4)?; // base rotation + 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()?; + read_tile(buff)?; + read_mounts(buff)?; + } + Self::Payload => { + 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()?; + read_tile(buff)?; + read_mounts(buff)?; + for _ in 0..buff.read_i32()? { + // recursion more! + // this is unreliable, as read_payload may not read the full block. + // if read_plans reports a error, with a payload unit, this is why + let _ = read_payload(buff); + } + } + Self::Bomb => { + 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()?; + buff.skip(4)?; // lifetime + read_tile(buff)?; + read_mounts(buff)?; + } + Self::Tethered => { + buff.skip(4)?; + 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()?; + read_tile(buff)?; + read_mounts(buff)?; + for _ in 0..buff.read_i32()? { + // recursion more! + read_payload(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] +/// - iterate [`u8`] /// - ability: [`f32`] fn read_abilities(buff: &mut DataRead) -> Result<(), ReadError> { let n = buff.read_u8()? as usize; @@ -225,7 +279,7 @@ fn read_tile(buff: &mut DataRead) -> Result<(), ReadError> { /// - x aim: [`f32`] /// - y aim: [`f32`] fn read_mounts(buff: &mut DataRead) -> Result<(), ReadError> { - let n = dbg!(buff.read_u8()? as usize); + let n = buff.read_u8()? as usize; buff.skip(n * 9) } @@ -235,7 +289,7 @@ fn read_mounts(buff: &mut DataRead) -> Result<(), ReadError> { /// - iterate `plan_count` /// - call [`read_plan`] fn read_plans(buff: &mut DataRead) -> Result<(), ReadError> { - let used = dbg!(buff.read_i32()?); + let used = buff.read_i32()?; if used == -1 { return Ok(()); } @@ -280,12 +334,14 @@ fn read_stack(buff: &mut DataRead) -> Result<(Option<Item>, u32), ReadError> { /// format: /// - iterate [`i32`] /// - status: [`u16`] attempt into [`Status`] +/// - duration: [`f32`] 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; + let this = Status::try_from(buff.read_u16()?); + buff.skip(4)?; + if let Ok(s) = this && i < 3 { + status[i as usize] = s; } } Ok(status) |