mindustry logic execution, map- and schematic- parsing and rendering
Implement item block state
| -rw-r--r-- | src/block/base.rs | 3 | ||||
| -rw-r--r-- | src/block/transport.rs | 150 |
2 files changed, 147 insertions, 6 deletions
diff --git a/src/block/base.rs b/src/block/base.rs index 71e03c4..4541cfd 100644 --- a/src/block/base.rs +++ b/src/block/base.rs @@ -1,5 +1,6 @@ use crate::block::make_register; use crate::block::simple::SimpleBlock; +use crate::block::transport::ItemBlock; make_register! ( @@ -14,7 +15,7 @@ make_register! CORE_NUCLEUS: "core-nucleus" => SimpleBlock::new(5, true); CONTAINER: "container" => SimpleBlock::new(2, true); VAULT: "vault" => SimpleBlock::new(3, true); - UNLOADER: "unloader" => SimpleBlock::new(1, true); // TODO config: item + UNLOADER: "unloader" => ItemBlock::new(1, true); ILLUMINATOR: "illuminator" => SimpleBlock::new(1, true); // TODO config: color LAUNCH_PAD: "launch-pad" => SimpleBlock::new(3, true); ); diff --git a/src/block/transport.rs b/src/block/transport.rs index cb34232..7c3f4c1 100644 --- a/src/block/transport.rs +++ b/src/block/transport.rs @@ -1,5 +1,13 @@ -use crate::block::make_register; -use crate::block::simple::SimpleBlock; +use std::any::Any; +use std::error::Error; +use std::fmt; + +use crate::block::{BlockLogic, DataConvertError, DeserializeError, make_register, SerializeError}; +use crate::block::simple::{SimpleBlock, state_impl}; +use crate::content; +use crate::data::GridPos; +use crate::data::dynamic::{DynData, DynType}; +use crate::item; make_register! ( @@ -10,14 +18,146 @@ make_register! JUNCTION: "junction" => SimpleBlock::new(1, true); BRIDGE_CONVEYOR: "bridge-conveyor" => SimpleBlock::new(1, false); // TODO config: destination PHASE_CONVEYOR: "phase-conveyor" => SimpleBlock::new(1, false); // TODO config: destination - SORTER: "sorter" => SimpleBlock::new(1, true); // TODO config: item - INVERTED_SORTER: "inverted-sorter" => SimpleBlock::new(1, true); // TODO config: item + SORTER: "sorter" => ItemBlock::new(1, true); + INVERTED_SORTER: "inverted-sorter" => ItemBlock::new(1, true); ROUTER: "router" => SimpleBlock::new(1, true); DISTRIBUTOR: "distributor" => SimpleBlock::new(2, true); OVERFLOW_GATE: "overflow-gate" => SimpleBlock::new(1, true); UNDERFLOW_GATE: "underflow-gate" => SimpleBlock::new(1, true); MASS_DRIVER: "mass-driver" => SimpleBlock::new(3, true); // TODO config: destination // sandbox only - ITEM_SOURCE: "item-source" => SimpleBlock::new(1, true); // TODO config: item + ITEM_SOURCE: "item-source" => ItemBlock::new(1, true); ITEM_VOID: "item-void" => SimpleBlock::new(1, true); ); + +pub struct ItemBlock +{ + size: u8, + symmetric: bool, +} + +impl ItemBlock +{ + pub const fn new(size: u8, symmetric: bool) -> Self + { + if size == 0 + { + panic!("invalid size"); + } + Self{size, symmetric} + } + + state_impl!(pub Option<item::Type>); +} + +impl BlockLogic for ItemBlock +{ + fn get_size(&self) -> u8 + { + self.size + } + + fn is_symmetric(&self) -> bool + { + self.symmetric + } + + fn data_from_i32(&self, config: i32, _: GridPos) -> Result<DynData, DataConvertError> + { + if config < 0 || config > u16::MAX as i32 + { + return Err(DataConvertError(Box::new(ItemConvertError(config)))); + } + Ok(DynData::Content(content::Type::Item, config as u16)) + } + + fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> + { + match data + { + DynData::Empty => Ok(Some(Self::create_state(None))), + DynData::Content(content::Type::Item, id) => Ok(Some(Self::create_state(Some(ItemDeserializeError::forward(item::Type::try_from(id))?)))), + DynData::Content(have, ..) => Err(DeserializeError::Custom(Box::new(ItemDeserializeError::ContentType(have)))), + _ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::Content}), + } + } + + fn clone_state(&self, state: &dyn Any) -> Box<dyn Any> + { + let state = Self::get_state(state); + Box::new(Self::create_state(*state)) + } + + fn serialize_state(&self, state: &dyn Any) -> Result<DynData, SerializeError> + { + match Self::get_state(state) + { + None => Ok(DynData::Empty), + Some(item) => Ok(DynData::Content(content::Type::Item, (*item).into())), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct ItemConvertError(pub i32); + +impl fmt::Display for ItemConvertError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "invalid config ({}) for item", self.0) + } +} + +impl Error for ItemConvertError {} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum ItemDeserializeError +{ + ContentType(content::Type), + NotFound(item::TryFromU16Error), +} + +impl ItemDeserializeError +{ + pub fn forward<T, E: Into<Self>>(result: Result<T, E>) -> Result<T, DeserializeError> + { + match result + { + Ok(v) => Ok(v), + Err(e) => Err(DeserializeError::Custom(Box::new(e.into()))), + } + } +} + +impl From<item::TryFromU16Error> for ItemDeserializeError +{ + fn from(err: item::TryFromU16Error) -> Self + { + Self::NotFound(err) + } +} + +impl fmt::Display for ItemDeserializeError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + Self::ContentType(have) => write!(f, "expected content {:?} but got {have:?}", content::Type::Item), + Self::NotFound(e) => e.fmt(f), + } + } +} + +impl Error for ItemDeserializeError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + Self::NotFound(e) => Some(e), + _ => None, + } + } +} |