mindustry logic execution, map- and schematic- parsing and rendering
add controller type 9
bendn 6 months ago
parent 7fe51c1 · commit 90b052d
-rw-r--r--mindus/src/data/map.rs10
-rw-r--r--mindus/src/data/mod.rs12
-rw-r--r--mindus/src/lib.rs4
-rw-r--r--mindus/src/unit.rs69
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(());
}