mindustry logic execution, map- and schematic- parsing and rendering
Use custom state data for blocks
KosmosPrime 2023-01-08
parent 4c84186 · commit 131e2c3
-rw-r--r--src/block/mod.rs36
-rw-r--r--src/block/simple.rs31
-rw-r--r--src/data/schematic.rs60
3 files changed, 108 insertions, 19 deletions
diff --git a/src/block/mod.rs b/src/block/mod.rs
index e2e07da..bcd475e 100644
--- a/src/block/mod.rs
+++ b/src/block/mod.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
use std::borrow::Cow;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
@@ -21,15 +22,15 @@ pub trait BlockLogic
{
fn get_size(&self) -> u8;
- fn is_symmetric(&self) -> bool
- {
- true
- }
+ fn is_symmetric(&self) -> bool;
- fn state_from_i32(&self, _config: i32) -> DynData
- {
- DynData::Empty
- }
+ fn data_from_i32(&self, config: i32) -> DynData;
+
+ fn deserialize_state(&self, data: DynData) -> Option<Box<dyn Any>>;
+
+ fn clone_state(&self, state: &dyn Any) -> Box<dyn Any>;
+
+ fn serialize_state(&self, state: &dyn Any) -> DynData;
}
pub struct Block
@@ -60,9 +61,24 @@ impl Block
self.logic.is_symmetric()
}
- pub fn state_from_i32(&self, config: i32) -> DynData
+ pub fn data_from_i32(&self, config: i32) -> DynData
+ {
+ self.logic.data_from_i32(config)
+ }
+
+ pub fn deserialize_state(&self, data: DynData) -> Option<Box<dyn Any>>
+ {
+ self.logic.deserialize_state(data)
+ }
+
+ pub fn clone_state(&self, state: &dyn Any) -> Box<dyn Any>
+ {
+ self.logic.clone_state(state)
+ }
+
+ pub fn serialize_state(&self, state: &dyn Any) -> DynData
{
- self.logic.state_from_i32(config)
+ self.logic.serialize_state(state)
}
}
diff --git a/src/block/simple.rs b/src/block/simple.rs
index ebbcc92..330ee7f 100644
--- a/src/block/simple.rs
+++ b/src/block/simple.rs
@@ -1,4 +1,33 @@
+use std::any::{Any, type_name};
+
use crate::block::BlockLogic;
+use crate::data::dynamic::DynData;
+
+macro_rules!gen_state_empty
+{
+ () =>
+ {
+ fn data_from_i32(&self, _: i32) -> DynData
+ {
+ DynData::Empty
+ }
+
+ fn deserialize_state(&self, _: DynData) -> Option<Box<dyn Any>>
+ {
+ None
+ }
+
+ fn clone_state(&self, _: &dyn Any) -> Box<dyn Any>
+ {
+ panic!("{} has no custom state", type_name::<Self>())
+ }
+
+ fn serialize_state(&self, _: &dyn Any) -> DynData
+ {
+ DynData::Empty
+ }
+ };
+}
pub struct SimpleBlock
{
@@ -25,4 +54,6 @@ impl BlockLogic for SimpleBlock
{
self.symmetric
}
+
+ gen_state_empty!();
}
diff --git a/src/data/schematic.rs b/src/data/schematic.rs
index eeae352..4cdad07 100644
--- a/src/data/schematic.rs
+++ b/src/data/schematic.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::fmt::{self, Write};
@@ -14,12 +15,11 @@ use crate::data::dynamic::{self, DynSerializer, DynData};
pub const MAX_DIMENSION: u16 = 128;
pub const MAX_BLOCKS: u32 = 128 * 128;
-#[derive(Clone)]
pub struct Placement
{
pos: GridPos,
block: &'static Block,
- state: DynData,
+ state: Option<Box<dyn Any>>,
rot: Rotation,
}
@@ -35,13 +35,27 @@ impl Placement
self.block
}
- pub fn get_state(&self) -> &DynData
+ pub fn get_state(&self) -> Option<&dyn Any>
{
- &self.state
+ match self.state
+ {
+ None => None,
+ Some(ref b) => Some(b.as_ref()),
+ }
}
- pub fn set_state(&mut self, state: DynData) -> DynData
+ pub fn get_state_mut(&mut self) -> Option<&mut dyn Any>
{
+ match self.state
+ {
+ None => None,
+ Some(ref mut b) => Some(b.as_mut()),
+ }
+ }
+
+ pub fn set_state(&mut self, data: DynData) -> Option<Box<dyn Any>>
+ {
+ let state = self.block.deserialize_state(data);
std::mem::replace(&mut self.state, state)
}
@@ -56,6 +70,25 @@ impl Placement
}
}
+// manual impl because trait objects cannot be cloned
+impl Clone for Placement
+{
+ fn clone(&self) -> Self
+ {
+ Self
+ {
+ pos: self.pos,
+ block: self.block,
+ state: match self.state
+ {
+ None => None,
+ Some(ref s) => Some(self.block.clone_state(s)),
+ },
+ rot: self.rot,
+ }
+ }
+}
+
#[derive(Clone)]
pub struct Schematic
{
@@ -213,7 +246,7 @@ impl Schematic
else {self.lookup[x + y * (self.width as usize)] = val;}
}
- pub fn set(&mut self, x: u16, y: u16, block: &'static Block, state: DynData, rot: Rotation) -> Result<&Placement, PlaceError>
+ pub fn set(&mut self, x: u16, y: u16, block: &'static Block, data: DynData, rot: Rotation) -> Result<&Placement, PlaceError>
{
let sz = block.get_size() as u16;
let off = (sz - 1) / 2;
@@ -228,6 +261,7 @@ impl Schematic
if self.is_region_empty(x - off, y - off, sz, sz)
{
let idx = self.blocks.len();
+ let state = block.deserialize_state(data);
self.blocks.push(Placement{pos: GridPos(x, y), block, state, rot});
self.fill_lookup(x as usize, y as usize, block.get_size() as usize, Some(idx));
Ok(&self.blocks[idx])
@@ -235,7 +269,7 @@ impl Schematic
else {Err(PlaceError::Overlap{x, y})}
}
- pub fn replace(&mut self, x: u16, y: u16, block: &'static Block, state: DynData, rot: Rotation, collect: bool)
+ pub fn replace(&mut self, x: u16, y: u16, block: &'static Block, data: DynData, rot: Rotation, collect: bool)
-> Result<Option<Vec<Placement>>, PlaceError>
{
let sz = block.get_size() as u16;
@@ -264,6 +298,7 @@ impl Schematic
}
}
let idx = self.blocks.len();
+ let state = block.deserialize_state(data);
self.blocks.push(Placement{pos: GridPos(x, y), block, state, rot});
self.fill_lookup(x as usize, y as usize, sz as usize, Some(idx));
Ok(result)
@@ -276,12 +311,14 @@ impl Schematic
None =>
{
let idx = self.blocks.len();
+ let state = block.deserialize_state(data);
self.blocks.push(Placement{pos: GridPos(x, y), block, state, rot});
self.lookup[pos] = Some(idx);
Ok(if collect {Some(Vec::new())} else {None})
},
Some(idx) =>
{
+ let state = block.deserialize_state(data);
let prev = std::mem::replace(&mut self.blocks[idx], Placement{pos: GridPos(x, y), block, state, rot});
self.fill_lookup(prev.pos.0 as usize, prev.pos.1 as usize, prev.block.get_size() as usize, None);
self.fill_lookup(x as usize, y as usize, sz as usize, Some(idx));
@@ -734,7 +771,7 @@ impl<'l> Serializer<Schematic> for SchematicSerializer<'l>
let block = block_table[idx as usize];
let config = if version < 1
{
- block.state_from_i32(rbuff.read_i32()?)
+ block.data_from_i32(rbuff.read_i32()?)
}
else {DynSerializer.deserialize(&mut rbuff)?};
let rot = Rotation::from(rbuff.read_u8()?);
@@ -795,7 +832,12 @@ impl<'l> Serializer<Schematic> for SchematicSerializer<'l>
{
rbuff.write_i8(block_map[curr.block.get_name()] as i8)?;
rbuff.write_u32(u32::from(curr.pos))?;
- DynSerializer.serialize(&mut rbuff, &curr.state)?;
+ let data = match curr.state
+ {
+ None => DynData::Empty,
+ Some(ref s) => curr.block.serialize_state(s.as_ref()),
+ };
+ DynSerializer.serialize(&mut rbuff, &data)?;
rbuff.write_u8(curr.rot.into())?;
num += 1;
}