mindustry logic execution, map- and schematic- parsing and rendering
Implement fluid block state
| -rw-r--r-- | src/block/fluid.rs | 146 |
1 files changed, 143 insertions, 3 deletions
diff --git a/src/block/fluid.rs b/src/block/fluid.rs index 5ce966f..6a159c2 100644 --- a/src/block/fluid.rs +++ b/src/block/fluid.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::fluid; make_register! ( @@ -16,6 +24,138 @@ make_register! BRIDGE_CONDUIT: "bridge-conduit" => SimpleBlock::new(1, true); // TODO config: destination PHASE_CONDUIT: "phase-conduit" => SimpleBlock::new(1, true); // TODO config: destination // sandbox only - LIQUID_SOURCE: "liquid-source" => SimpleBlock::new(1, true); // TODO config: fluid + LIQUID_SOURCE: "liquid-source" => FluidBlock::new(1, true); LIQUID_VOID: "liquid-void" => SimpleBlock::new(1, true); ); + +pub struct FluidBlock +{ + size: u8, + symmetric: bool, +} + +impl FluidBlock +{ + pub const fn new(size: u8, symmetric: bool) -> Self + { + if size == 0 + { + panic!("invalid size"); + } + Self{size, symmetric} + } + + state_impl!(pub Option<fluid::Type>); +} + +impl BlockLogic for FluidBlock +{ + 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(FluidConvertError(config)))); + } + Ok(DynData::Content(content::Type::Fluid, 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::Fluid, id) => Ok(Some(Self::create_state(Some(FluidDeserializeError::forward(fluid::Type::try_from(id))?)))), + DynData::Content(have, ..) => Err(DeserializeError::Custom(Box::new(FluidDeserializeError::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(fluid) => Ok(DynData::Content(content::Type::Fluid, (*fluid).into())), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct FluidConvertError(pub i32); + +impl fmt::Display for FluidConvertError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "invalid config ({}) for fluid", self.0) + } +} + +impl Error for FluidConvertError {} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum FluidDeserializeError +{ + ContentType(content::Type), + NotFound(fluid::TryFromU16Error), +} + +impl FluidDeserializeError +{ + 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<fluid::TryFromU16Error> for FluidDeserializeError +{ + fn from(err: fluid::TryFromU16Error) -> Self + { + Self::NotFound(err) + } +} + +impl fmt::Display for FluidDeserializeError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + Self::ContentType(have) => write!(f, "expected content {:?} but got {have:?}", content::Type::Fluid), + Self::NotFound(e) => e.fmt(f), + } + } +} + +impl Error for FluidDeserializeError +{ + fn source(&self) -> Option<&(dyn Error + 'static)> + { + match self + { + Self::NotFound(e) => Some(e), + _ => None, + } + } +} |