mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/map.rs')
| -rw-r--r-- | src/data/map.rs | 221 |
1 files changed, 169 insertions, 52 deletions
diff --git a/src/data/map.rs b/src/data/map.rs index 18944a1..04938d8 100644 --- a/src/data/map.rs +++ b/src/data/map.rs @@ -14,7 +14,7 @@ //! - string map (`u16` for map len, iterate each, read `utf`) //! - content header section `<u32>`: //! - iterate `i8` (should = `8`)' -//! - the type: `i8` (0: item, block: 1, liquid: 4, status: 5, unit: 6, weather: 7, sector: 9, planet: 13//! - item count: `u1\'6` (item: 22, block: 412, liquid: 11, status: 21, unit: 66, weather: 6, sector: 35, planet: 7) +//! - 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) //! - these types all have their own modules: [`item`], [`content`], [`fluid`], [`modifier`], [`mod@unit`], [`weather`], [`sector`], [`planet`] //! - iterate `u16` //! - name: `utf` @@ -41,7 +41,7 @@ //! - chunk len: `u16` //! - if block == building: //! - revision: `i8` -//! - tile.build.readAll +//! - [`read`] //! - else skip `chunk len` //! - or data //! - data: `i8` @@ -74,13 +74,13 @@ use std::ops::{Index, IndexMut}; use thiserror::Error; use crate::block::content::Type as BlockEnum; -use crate::block::{environment, Block, BlockRegistry, Rotation}; +use crate::block::{environment, Block, BlockRegistry, Rotation, State}; use crate::data::dynamic::DynSerializer; use crate::data::renderer::*; use crate::data::DataRead; use crate::fluid::Type as Fluid; use crate::item::{storage::Storage, Type as Item}; -use crate::team::Team; +use crate::team::{self, Team}; #[cfg(doc)] use crate::{block::content, data::*, fluid, item, modifier, unit}; @@ -109,6 +109,7 @@ impl<'l> Tile<'l> { fn set_block(&mut self, block: &'l Block) { self.build = Some(Build { block, + state: None, items: Storage::new(), liquids: Storage::new(), rotation: Rotation::Up, @@ -142,9 +143,9 @@ impl<'l> Tile<'l> { } pub fn floor_image(&self, context: Option<&RenderingContext>) -> ImageHolder { - let mut i = self.floor.image(None, context).own(); + let mut i = self.floor.image(None, context, Rotation::Up).own(); if let Some(ore) = self.ore { - i.overlay(ore.image(None, context).borrow(), 0, 0); + i.overlay(ore.image(None, context, Rotation::Up).borrow(), 0, 0); } ImageHolder::from(i) } @@ -203,78 +204,180 @@ impl<'l> BlockState<'l> for Option<Tile<'_>> { } /// a build on a tile in a map -#[derive(Debug, Clone)] pub struct Build<'l> { pub block: &'l Block, pub items: Storage<Item>, pub liquids: Storage<Fluid>, + pub state: Option<State>, // pub health: f32, pub rotation: Rotation, pub team: Team, pub data: i8, } -impl Build<'_> { +impl std::fmt::Debug for Build<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Build<{block}>", block = self.block.name(),) + } +} + +impl Clone for Build<'_> { + fn clone(&self) -> Self { + Self { + block: self.block, + items: self.items.clone(), + liquids: self.liquids.clone(), + state: match self.state { + None => None, + Some(ref s) => Some(self.block.clone_state(s)), + }, + rotation: self.rotation, + team: self.team, + data: self.data, + } + } +} + +impl<'l> Build<'l> { + pub fn new(block: &'l Block) -> Build<'l> { + Self { + block, + items: Default::default(), + liquids: Default::default(), + state: Default::default(), + rotation: Rotation::Up, + team: team::SHARDED, + data: 0, + } + } + pub fn image(&self, context: Option<&RenderingContext>) -> ImageHolder { - self.block.image(None, context) + self.block + .image(self.state.as_ref(), context, self.rotation) + } + + pub fn name(&self) -> &str { + self.block.name() } pub fn read( &mut self, buff: &mut DataRead<'_>, - _reg: &BlockRegistry, - _map: &EntityMapping, + reg: &BlockRegistry, + map: &EntityMapping, ) -> Result<(), ReadError> { // health - let _ = buff.read_f32()?; // 4 - let rot = buff.read_u8()?; // 5 - self.rotation = Rotation::try_from(rot & 127).unwrap_or(Rotation::Up); - if (rot & 128) == 0 { - return Err(ReadError::Version(rot & 128)); + let _ = buff.read_f32()?; + let rot = buff.read_i8()? as i16; + // team + let _ = buff.read_i8()?; + self.rotation = Rotation::try_from((rot & 127) as u8).unwrap_or(Rotation::Up); + let mut mask = 0; + let mut version = 0; + if rot & 128 != 0 { + version = buff.read_u8()?; + if version < 3 { + return Err(ReadError::Version(version)); + } + buff.skip(1)?; + mask = buff.read_u8()?; } - let _t = buff.read_u8()?; // 6 - let _v = buff.read_u8()?; // 7 - let _mask = buff.read_u8()?; // 8 - - // if (mask & 1) != 0 { - // self.items.clear(); - // // 10 - // for _ in 0..dbg!(buff.read_u16()?) { - // let item = buff.read_u16()?; - // let amount = buff.read_u32()?; - // if let Ok(item) = Item::try_from(item) { - // self.items.set(item, amount); - // } - // } - // } - // if mask & 2 == 0 { - // let n = buff.read_u16()? as usize; - // buff.skip((n * 4) + 1)?; - // } - // if mask & 4 == 0 { - // self.liquids.clear(); - // for _ in 0..buff.read_u16()? { - // let fluid = buff.read_u16()?; - // let amount = buff.read_f32()?; - // if let Ok(fluid) = Fluid::try_from(fluid) { - // self.liquids.set(fluid, (amount * 100.0) as u32); - // } - // } - // } + const ITEMS: u8 = 1; + const POWER: u8 = 2; + const LIQUIDS: u8 = 4; + + if mask & ITEMS != 0 { + read_items(buff, &mut self.items)?; + } + if mask & POWER != 0 { + read_power(buff)?; + } + if mask & LIQUIDS != 0 { + read_liquids(buff, &mut self.liquids)?; + } // "efficiency"? - // let _ = buff.read_u8()?; - // let _ = buff.read_u8()?; - // visible flags - // let _ = buff.read_i64()?; + buff.skip(2)?; + if version == 4 { + // visible flags for fog + buff.skip(4)?; + } + // "overridden by subclasses" + self.block.logic.read(self, reg, map, buff)?; // implementation not complete, simply error, causing the remaining bytes in the chunk to be skipped (TODO finish impl) Err(ReadError::Version(0x0)) - // "overridden by subclasses" - // self.block.read(buff, reg, map)?; // Ok(()) } } +/// format: +/// - iterate [`u16`] +/// - item: [`u16`] as [`Item`] +/// - amount: [`u32`] +/// +fn read_items(from: &mut DataRead, to: &mut Storage<Item>) -> Result<(), ReadError> { + to.clear(); + for _ in 0..from.read_u16()? { + let item = from.read_u16()?; + let amount = from.read_u32()?; + if let Ok(item) = Item::try_from(item) { + to.set(item, amount); + } + } + Ok(()) +} + +/// format: +/// - iterate [`u16`] +/// - liquid: [`u16`] as [`Fluid`] +/// - amount: [`f32`] +fn read_liquids(from: &mut DataRead, to: &mut Storage<Fluid>) -> Result<(), ReadError> { + to.clear(); + for _ in 0..from.read_u16()? { + let fluid = from.read_u16()?; + let amount = from.read_f32()?; + if let Ok(fluid) = Fluid::try_from(fluid) { + to.set(fluid, (amount * 100.0) as u32); + } + } + Ok(()) +} + +/// format: +/// - iterate [`u16`] +/// - link: [`i32`] +/// - status: [`f32`] +fn read_power(from: &mut DataRead) -> Result<(), ReadError> { + let n = from.read_u16()? as usize; + from.skip((n + 1) * 4)?; + Ok(()) +} + +#[test] +fn test_read_items() { + let mut s = Storage::new(); + read_items( + &mut DataRead::new(&[ + 0, 6, 0, 0, 0, 0, 2, 187, 0, 1, 0, 0, 1, 154, 0, 2, 0, 0, 15, 160, 0, 3, 0, 0, 0, 235, + 0, 6, 0, 0, 1, 46, 0, 12, 0, 0, 1, 81, 255, 255, + ]), + &mut s, + ) + .unwrap(); + assert!(s.get_total() == 5983); +} + +#[test] +fn test_read_liquids() { + let mut s = Storage::new(); + read_liquids( + &mut DataRead::new(&[0, 1, 0, 0, 67, 111, 247, 126, 255, 255]), + &mut s, + ) + .unwrap(); + assert!(s.get(Fluid::Water) == 23996); +} + /// a map. /// ## Does not support serialization yet! #[derive(Debug)] @@ -473,8 +576,18 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { } if entity { if central { + let mut output = [0u8; 2]; + output.copy_from_slice(&buff.data[..2]); + let n = u16::from_be_bytes(output) as usize; let _ = buff.read_chunk(false, |buff| { + #[cfg(debug_assertions)] + println!( + "reading {:?} {:?}", + map[i].build.as_ref().unwrap(), + &buff.data[1..n] + ); let _ = buff.read_i8()?; + map[i] .build .as_mut() @@ -505,13 +618,15 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { })?; 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_i16()? as u8; + 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)); } + // read team block plans (ghosts) (SaveVersion.java#389) for _ in 0..buff.read_u32()? { buff.skip(4)?; for _ in 0..buff.read_u32()? { @@ -519,6 +634,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { let _ = DynSerializer::deserialize(&mut DynSerializer, buff)?; } } + // read world entities (#412). eg units for _ in 0..buff.read_u32()? { let len = buff.read_u16()? as usize; let ty = buff.read_u8()?; @@ -533,6 +649,7 @@ impl<'l> Serializer<Map<'l>> for MapSerializer<'l> { })?; // skip custom chunks buff.skip_chunk()?; + println!("desered"); Ok(m.unwrap()) } |