mindustry logic execution, map- and schematic- parsing and rendering
add controller type 9
| -rw-r--r-- | mindus/src/data/map.rs | 10 | ||||
| -rw-r--r-- | mindus/src/data/mod.rs | 12 | ||||
| -rw-r--r-- | mindus/src/lib.rs | 4 | ||||
| -rw-r--r-- | mindus/src/unit.rs | 69 |
4 files changed, 73 insertions, 22 deletions
diff --git a/mindus/src/data/map.rs b/mindus/src/data/map.rs index 826bf43..e3f9c37 100644 --- a/mindus/src/data/map.rs +++ b/mindus/src/data/map.rs @@ -923,13 +923,21 @@ impl MapReader { yield EntityData::Length(n); for _ in 0..n { let len = self.buff.read_u16()? as usize; + let rb4 = self.buff.read; let id = self.buff.read_u8()? as usize; let Some(&Some(u)) = entity_mapping::ID.get(id) else { self.buff.skip(len - 1)?; continue; }; - self.buff.skip(4)?; + _ = self.buff.read_u32()?; yield EntityData::Data(u.read(&mut self.buff)?); + let read = self.buff.read - rb4; + debug_assert!(len >= read, "overread; supposed to read {len}; read {read}"); + let n = len - read; + if n != 0 && cfg!(debug_assertions) { + dbg!("underread: skipping {n} bytes"); + } + self.buff.skip(n)?; } let read = self.buff.read - rb4; debug_assert!(len >= read, "overread; supposed to read {len}; read {read}"); diff --git a/mindus/src/data/mod.rs b/mindus/src/data/mod.rs index 20f19e0..9f7959f 100644 --- a/mindus/src/data/mod.rs +++ b/mindus/src/data/mod.rs @@ -3,6 +3,7 @@ use flate2::{ Compress, CompressError as CError, Compression, Decompress, DecompressError as DError, FlushCompress, FlushDecompress, Status, }; +use std::backtrace::Backtrace; use std::collections::HashMap; use std::error::Error; use std::fmt; @@ -77,6 +78,7 @@ impl<'d> DataRead<'d> { .ok_or(ReadError::Underflow { need: n, have: self.data.len(), + bt: Backtrace::capture(), }) .inspect(|_| self.read += n) } @@ -95,6 +97,7 @@ impl<'d> DataRead<'d> { self.data = self.data.get(n..).ok_or(ReadError::Underflow { need: n, have: self.data.len(), + bt: Backtrace::capture(), })?; self.read += n; Ok(()) @@ -187,8 +190,13 @@ pub enum DecompressError { #[derive(Debug, Error)] pub enum ReadError { - #[error("buffer underflow (expected {need} but got {have})")] - Underflow { need: usize, have: usize }, + #[error("buffer underflow (expected {need} but got {have}) ({bt})")] + Underflow { + need: usize, + have: usize, + + bt: Backtrace, + }, #[error("expected {0}")] Expected(&'static str), #[error("malformed utf8 in string")] diff --git a/mindus/src/lib.rs b/mindus/src/lib.rs index db900c2..b65dd16 100644 --- a/mindus/src/lib.rs +++ b/mindus/src/lib.rs @@ -1,6 +1,8 @@ //! crate for dealing with mindustry #![feature( + error_generic_member_access, maybe_uninit_write_slice, + try_trait_v2_residual, stmt_expr_attributes, generic_const_exprs, iter_from_coroutine, @@ -9,6 +11,8 @@ likely_unlikely, portable_simd, derive_const, + try_trait_v2, + try_blocks, const_from, coroutines )] diff --git a/mindus/src/unit.rs b/mindus/src/unit.rs index 0343b5b..57b9e12 100644 --- a/mindus/src/unit.rs +++ b/mindus/src/unit.rs @@ -1,6 +1,8 @@ //! units //! //! [source](https://github.com/Anuken/Mindustry/blob/master/core/src/mindustry/content/UnitTypes.java) +use std::ops::{ControlFlow, Try}; + use crate::Serializable; use crate::block::payload::read_payload; use crate::content::content_enum; @@ -116,6 +118,39 @@ pub struct UnitState { pub position: (f32, f32), pub controller: Controller, } +// pub trait TryThen { +// fn try_then<O: Try<Output = Option<T>, Residual = E>, T, E, R: Try<Output = T, Residual = E>>( +// self, +// then: impl FnMut() -> R, +// ) -> O; +// } +// impl TryThen for bool { +// fn try_then< +// O: Try<Output = Option<T>, Residual = E>, +// T, +// E, +// R: Try<Output = T, Residual = E>, +// >( +// self, +// mut then: impl FnMut() -> R, +// ) { +// match self { +// false => O::from_output(None), +// true => match then().branch() { +// ControlFlow::Continue(x) => O::from_output(Some(x)), +// ControlFlow::Break(x) => O::from_residual(x), +// }, +// } +// } +// } +pub trait TryThen { + fn try_then<T, E>(self, f: impl FnMut() -> Result<T, E>) -> Result<Option<T>, E>; +} +impl TryThen for bool { + fn try_then<T, E>(self, mut f: impl FnMut() -> Result<T, E>) -> Result<Option<T>, E> { + self.then_some(()).map(|()| f()).transpose() + } +} #[derive(Default, Debug)] pub enum Controller { @@ -153,28 +188,20 @@ impl Controller { Ok(match buff.read_u8()? { 0 => Controller::Player(buff.read_i32()?), 3 => Controller::Logic(buff.read_i32()?), - t @ (4 | 6 | 7 | 8) => { + t @ (4 | 6 | 7 | 8 | 9) => { 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 { + let pos = buff + .read_bool()? + .try_then::<_, ReadError>(|| try { (buff.read_f32()?, buff.read_f32()?) })?; + let target = has_attack.try_then::<_, ReadError>(|| try { buff.skip(1)?; - Some(buff.read_i32()?) - } else { - None - }; + buff.read_i32()? + })?; 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 - }; - if let 7 | 8 = t { + let command = u8::try_from(n) + .ok() + .and_then(|x| UnitCommand::try_from(x).ok()); + if let 7 | 8 | 9 = t { for _ in 0..buff.read_u8()? { match buff.read_u8()? { 0 | 1 => { @@ -191,6 +218,9 @@ impl Controller { if t == 8 { // stance buff.read_u8()?; + } else if t == 9 { + let stances = buff.read_u8()?; + buff.skip(stances as _)?; } Controller::Command { target, @@ -334,6 +364,7 @@ fn read_mounts(buff: &mut DataRead) -> Result<(), ReadError> { /// - call [`read_plan`] fn read_plans(buff: &mut DataRead) -> Result<(), ReadError> { let used = buff.read_i32()?; + dbg!(used); if used == -1 { return Ok(()); } |