mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/data/map.rs')
-rw-r--r--src/data/map.rs221
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())
}