mindustry logic execution, map- and schematic- parsing and rendering
map v8
| -rw-r--r-- | mindus/Cargo.toml | 2 | ||||
| -rw-r--r-- | mindus/src/block/content.rs | 20 | ||||
| -rw-r--r-- | mindus/src/content.rs | 11 | ||||
| -rw-r--r-- | mindus/src/data/map.rs | 81 | ||||
| -rw-r--r-- | mindus/src/data/renderer.rs | 8 | ||||
| -rw-r--r-- | mindus/src/exe/map.rs | 6 | ||||
| -rw-r--r-- | mindus/src/lib.rs | 1 | ||||
| -rw-r--r-- | mindus/src/unit.rs | 23 |
8 files changed, 113 insertions, 39 deletions
diff --git a/mindus/Cargo.toml b/mindus/Cargo.toml index 6610afc..7871249 100644 --- a/mindus/Cargo.toml +++ b/mindus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mindus" -version = "5.0.32" +version = "5.0.33" edition = "2021" description = "A library for working with mindustry data formats (eg schematics and maps) (fork of plandustry)" authors = [ diff --git a/mindus/src/block/content.rs b/mindus/src/block/content.rs index d25c83f..5fdb007 100644 --- a/mindus/src/block/content.rs +++ b/mindus/src/block/content.rs @@ -6,6 +6,8 @@ content_enum! { { "air", "spawn", + "remove-wall", + "remove-ore", "cliff", "build1", "build2", @@ -69,6 +71,8 @@ content_enum! { "yellow-stone-vent", "red-stone-vent", "crystalline-vent", + "stone-vent", + "basalt-vent", "redmat", "bluemat", "grass", @@ -184,6 +188,7 @@ content_enum! { "slag-heater", "phase-heater", "heat-redirector", + "small-heat-redirector", "heat-router", "slag-incinerator", "carbide-crucible", @@ -309,6 +314,7 @@ content_enum! { "oil-extractor", "vent-condenser", "cliff-crusher", + "large-cliff-crusher", "plasma-bore", "large-plasma-bore", "impact-drill", @@ -365,8 +371,8 @@ content_enum! { "ship-fabricator", "mech-fabricator", "tank-refabricator", - "mech-refabricator", "ship-refabricator", + "mech-refabricator", "prime-refabricator", "tank-assembler", "ship-assembler", @@ -401,6 +407,8 @@ content_enum! { "legacy-unit-factory-ground", "command-center", "launch-pad", + "advanced-launch-pad", + "landing-pad", "interplanetary-accelerator", "message", "switch", @@ -411,20 +419,12 @@ content_enum! { "memory-bank", "logic-display", "large-logic-display", + "tile-logic-display", "canvas", "reinforced-message", "world-processor", "world-cell", "world-message", - - - - // shouldn't really exist - "large-cliff-crusher", - "small-heat-redirector", - "advanced-launch-pad", - "landing-pad", "world-switch", - "tile-logic-display", } } diff --git a/mindus/src/content.rs b/mindus/src/content.rs index 60e1ca3..10d612b 100644 --- a/mindus/src/content.rs +++ b/mindus/src/content.rs @@ -66,6 +66,17 @@ macro_rules! content_enum { impl $tname { pub const ALL: [Self; $crate::content::count_exprs!($($val)+)] = [$(Self::[<$val:camel>]),+]; + + pub (crate) fn by_name(name:&str)-> Option<Self> { + static MAPPER: std::sync::LazyLock<std::collections::HashMap<&str, $tname>> = std::sync::LazyLock::new( + || std::collections::HashMap::from_iter( + [ + $(($val, $tname::[<$val:camel>]),)+ + ] + ) + ); + MAPPER.get(name).copied() + } } impl $crate::content::Content for $tname { diff --git a/mindus/src/data/map.rs b/mindus/src/data/map.rs index f848f95..bb49804 100644 --- a/mindus/src/data/map.rs +++ b/mindus/src/data/map.rs @@ -8,14 +8,14 @@ //! //! ZLIB compressed stream contains: //! - header: 4b = `MSCH` [`MapReader::header`] -//! - version: `u32` (should be 7) [`MapReader::version`] +//! - version: `u32` (should be 7+) [`MapReader::version`] //! - tag section `<u32>` [`MapReader::tags`] //! - 1 byte of idk (skip) //! - string map (`u16` for map len, iterate each, read `utf`) -//! - content header section `<u32>`: [`MapReader::skip`] -//! - iterate `i8` (should = `8`)' +//! - content header section `<u32>`: [`MapReader::content`] (note: if map v8, will use [`BlockEnum`] and skip reading this) +//! - iterate `i8` (should = `10`)' //! - the type: `i8` (0: item, block: 1, liquid: 4, status: 5, unit: 6, weather: 7, sector: 9, planet: 13 -//! - item count: `u16` (item: 22, block: 412, liquid: 11, status: 21, unit: 66, weather: 6, sector: 35, planet: 7) +//! - item count: `u16` (item: 22, block: 422, liquid: 11, status: 21, unit: 66, weather: 6, sector: 35, planet: 7) //! - these types all have their own modules: [`item`], [`content`], [`fluid`], [`modifier`], [`mod@unit`], [`weather`], [`sector`], [`planet`] //! - iterate `u16` //! - name: `utf` @@ -70,6 +70,7 @@ //! - continue //! - id: `u32` //! - entity read +//! - markers section (v8) use std::collections::HashMap; use std::ops::CoroutineState::*; use std::ops::{Coroutine, Index, IndexMut}; @@ -520,7 +521,7 @@ pub enum ReadError { #[error("unsupported version ({0})")] Version(u8), #[error("unknown block {0:?}")] - NoSuchBlock(String), + NoSuchBlock(u16), #[error("failed to read block data")] ReadState(#[from] super::dynamic::ReadError), } @@ -569,13 +570,13 @@ pub enum EntityData { } macro_rules! tiles { - ($count:ident, $me:ident, $w: ident) => { + ($count:ident, $me:ident, $w: ident,$r:ident) => { let mut i = 0; while i < $count { let floor_id = $me.buff.read_u16()?; let overlay_id = $me.buff.read_u16()?; - let floor = BlockEnum::try_from(floor_id).unwrap_or(BlockEnum::Stone); - let ore = BlockEnum::try_from(overlay_id).unwrap_or(BlockEnum::Air); + let &floor = $r.get(floor_id as usize).unwrap_or(&BlockEnum::Stone); + let &ore = $r.get(overlay_id as usize).unwrap_or(&BlockEnum::Air); yield $w::Tile { floor, ore }; let consecutives = $me.buff.read_u8()? as usize; for _ in 0..consecutives { @@ -587,6 +588,7 @@ macro_rules! tiles { }; } +pub type Registrar = [BlockEnum; BlockEnum::ALL.len()]; impl MapReader { pub fn new(buff: &mut DataRead<'_>) -> Result<Self, ReadError> { let backing = buff.deflate()?; @@ -604,9 +606,8 @@ impl MapReader { } pub fn version(&mut self) -> Result<u32, ReadError> { - // NOTE: will change to 8 soon let x = self.buff.read_u32()?; - (x == 7) + (x == 7 || x == 8) .then_some(x) .ok_or(ReadError::Version(x.try_into().unwrap_or(0))) } @@ -622,6 +623,31 @@ impl MapReader { Ok(tags) } + pub fn content(&mut self, version: u32) -> Result<Registrar, ReadError> { + let mut registrar = BlockEnum::ALL; + let n = self.buff.read_u32()?; + if version < 8 { + for _ in 0..self.buff.read_i8()? { + let ty = self.buff.read_u8()?; + for index in 0..self.buff.read_u16()? as usize { + if ty == 1 { + let name = self.buff.read_utf()?; + registrar + .get_mut(index) + .map(|x| *x = BlockEnum::by_name(name).unwrap_or(BlockEnum::Air)); + } else { + let n = self.buff.read_u16()?; + self.buff.skip(n as usize)?; + } + } + } + dbg!(registrar); + } else { + self.buff.skip(n as _)?; + } + Ok(registrar) + } + pub fn tags_alloc(&mut self) -> Result<HashMap<String, String>, ReadError> { let mut tags = HashMap::new(); self.buff @@ -645,6 +671,7 @@ impl MapReader { pub fn thin_map( &mut self, + r: Registrar, ) -> Result< impl Coroutine<(), Return = Result<(), ReadError>, Yield = ThinMapData> + '_, ReadError, @@ -662,7 +689,7 @@ impl MapReader { let w = w as usize; let h = h as usize; let count = w * h; - tiles!(count, self, ThinMapData); + tiles!(count, self, ThinMapData, r); let mut i = 0; while i < count { @@ -675,8 +702,9 @@ impl MapReader { } else { false }; - let block = BlockEnum::try_from(block_id) - .map_err(|_| ReadError::NoSuchBlock(block_id.to_string()))?; + let block = *r + .get(block_id as usize) + .ok_or(ReadError::NoSuchBlock(block_id))?; let block = block.to_block(); let Some(block) = block else { let consecutives = self.buff.read_u8()?; @@ -724,8 +752,12 @@ impl MapReader { Ok(map) } - pub fn collect_map(&mut self, tags: HashMap<String, String>) -> Result<Map, ReadError> { - let mut co = self.map()?; + pub fn collect_map( + &mut self, + tags: HashMap<String, String>, + r: Registrar, + ) -> Result<Map, ReadError> { + let mut co = self.map(r)?; let (w, h) = match Pin::new(&mut co).resume(()) { Yielded(MapData::Init { width, height }) => (width as usize, height as usize), Complete(Err(x)) => return Err(x), @@ -771,6 +803,7 @@ impl MapReader { pub fn map( &mut self, + r: Registrar, ) -> Result<impl Coroutine<(), Return = Result<(), ReadError>, Yield = MapData> + '_, ReadError> { let len = self.buff.read_u32()? as usize; @@ -787,7 +820,7 @@ impl MapReader { let w = w as usize; let h = h as usize; let count = w * h; - tiles!(count, self, MapData); + tiles!(count, self, MapData, r); let mut i = 0; while i < count { @@ -800,8 +833,9 @@ impl MapReader { } else { false }; - let block = BlockEnum::try_from(block_id) - .map_err(|_| ReadError::NoSuchBlock(block_id.to_string()))?; + let block = r + .get(block_id as usize) + .ok_or(ReadError::NoSuchBlock(block_id))?; let block = block.to_block(); let Some(block) = block else { let consecutives = self.buff.read_u8()?; @@ -930,11 +964,16 @@ impl Serializable for Map { fn deserialize(buff: &mut DataRead<'_>) -> Result<Map, Self::ReadError> { let mut buff = MapReader::new(buff)?; buff.header()?; - buff.version()?; + let v = buff.version()?; let tags = buff.tags_alloc()?; - buff.skip()?; - let mut m = buff.collect_map(tags)?; + let r = buff.content(v)?; + + let mut m = buff.collect_map(tags, r)?; m.entities = buff.collect_entities()?; + if v == 8 { + // skip marker region + buff.skip()?; + } // skip custom chunks buff.skip()?; diff --git a/mindus/src/data/renderer.rs b/mindus/src/data/renderer.rs index ee5e66b..b5f3006 100644 --- a/mindus/src/data/renderer.rs +++ b/mindus/src/data/renderer.rs @@ -7,6 +7,7 @@ use super::schematic::Schematic; use super::GridPos; use crate::block::content::Type; use crate::color_mapping::BLOCK2COLOR; +use crate::data::map::Registrar; use crate::team::Team; pub(crate) use crate::utils::*; use crate::Map; @@ -365,9 +366,10 @@ pub fn draw_units( /// Will walk through the map section. use [`draw_units`] after, if you like. pub fn draw_map_single( map: &mut crate::data::map::MapReader, + r: Registrar, ) -> Result<(Image<Box<[u8]>, 3>, (u16, u16)), super::map::ReadError> { use std::ops::CoroutineState::*; - let mut co = map.thin_map()?; + let mut co = map.thin_map(r)?; let (w, h) = match Pin::new(&mut co).resume(()) { Yielded(ThinMapData::Init { width, height }) => (width, height), Complete(Err(x)) => return Err(x), @@ -485,11 +487,13 @@ pub fn draw_map_single( } /// Draws a map in a single pass. Uses the silly team color thing that mindustry has. +/// probably broken- if you want to use this ask me to update the block2color pub fn draw_map_simple( map: &mut crate::data::map::MapReader, + r: Registrar, ) -> Result<(Image<Box<[u8]>, 3>, (u16, u16)), super::map::ReadError> { use std::ops::CoroutineState::*; - let mut co = map.thin_map()?; + let mut co = map.thin_map(r)?; let (w, h) = match Pin::new(&mut co).resume(()) { Yielded(ThinMapData::Init { width, height }) => (width, height), Complete(Err(x)) => return Err(x), diff --git a/mindus/src/exe/map.rs b/mindus/src/exe/map.rs index 96b14f0..09719bd 100644 --- a/mindus/src/exe/map.rs +++ b/mindus/src/exe/map.rs @@ -12,12 +12,12 @@ pub fn main(args: Args) { match (|| { let mut m = MapReader::new(&mut DataRead::new(&s))?; m.header()?; - m.version()?; + let v = m.version()?; let t = m.tags()?; dbg!(&t); println!("rendering {}", t.get("name").unwrap_or(&"<unknown>")); - m.skip()?; - let (mut img, sz) = mindus::data::renderer::draw_map_single(&mut m)?; + let r = m.content(v)?; + let (mut img, sz) = mindus::data::renderer::draw_map_single(&mut m, r)?; mindus::data::renderer::draw_units(&mut m, img.as_mut(), sz)?; Ok::<_, mindus::data::map::ReadError>(img) })() { diff --git a/mindus/src/lib.rs b/mindus/src/lib.rs index caf657b..ad3a532 100644 --- a/mindus/src/lib.rs +++ b/mindus/src/lib.rs @@ -1,5 +1,6 @@ //! crate for dealing with mindustry #![feature( + inherent_associated_types, maybe_uninit_write_slice, stmt_expr_attributes, generic_const_exprs, diff --git a/mindus/src/unit.rs b/mindus/src/unit.rs index b35e3a8..6a27b1d 100644 --- a/mindus/src/unit.rs +++ b/mindus/src/unit.rs @@ -153,7 +153,7 @@ impl Controller { Ok(match buff.read_u8()? { 0 => Controller::Player(buff.read_i32()?), 3 => Controller::Logic(buff.read_i32()?), - 6 => { + t @ (4 | 6 | 7 | 8) => { let has_attack = buff.read_bool()?; let pos = if buff.read_bool()? { Some((buff.read_f32()?, buff.read_f32()?)) @@ -174,12 +174,31 @@ impl Controller { } else { None }; + if let 7 | 8 = t { + for _ in 0..buff.read_u8()? { + match buff.read_u8()? { + 0 | 1 => { + buff.read_u32()?; + } + 2 => { + buff.read_f32()?; + buff.read_f32()?; + } + _ => {} + } + } + } + if t == 8 { + // stance + buff.read_u8()?; + } Controller::Command { target, pos, command, } } + 5 => Controller::Assembler, _ => Controller::Assembler, }) } @@ -193,7 +212,7 @@ pub struct Unit { impl UnitClass { pub fn read(self, buff: &mut DataRead) -> Result<Unit, ReadError> { - buff.skip(2)?; + let _rev = buff.read_u16()?; let mut state = UnitState::default(); read_abilities(buff)?; state.ammo = buff.read_f32()?; |