mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/transport.rs')
| -rw-r--r-- | src/block/transport.rs | 150 |
1 files changed, 147 insertions, 3 deletions
diff --git a/src/block/transport.rs b/src/block/transport.rs index 7c3f4c1..7840961 100644 --- a/src/block/transport.rs +++ b/src/block/transport.rs @@ -16,15 +16,15 @@ make_register! PLASTANIUM_CONVEYOR: "plastanium-conveyor" => SimpleBlock::new(1, false); ARMORED_CONVEYOR: "armored-conveyor" => SimpleBlock::new(1, false); 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 + BRIDGE_CONVEYOR: "bridge-conveyor" => BridgeBlock::new(1, false, 4, true); + PHASE_CONVEYOR: "phase-conveyor" => BridgeBlock::new(1, false, 12, true); 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 + MASS_DRIVER: "mass-driver" => BridgeBlock::new(3, true, 55, false); // sandbox only ITEM_SOURCE: "item-source" => ItemBlock::new(1, true); ITEM_VOID: "item-void" => SimpleBlock::new(1, true); @@ -161,3 +161,147 @@ impl Error for ItemDeserializeError } } } + +pub struct BridgeBlock +{ + size: u8, + symmetric: bool, + range: u16, + ortho: bool, +} + +type Point2 = (i32, i32); + +impl BridgeBlock +{ + pub const fn new(size: u8, symmetric: bool, range: u16, ortho: bool) -> Self + { + if size == 0 + { + panic!("invalid size"); + } + if range == 0 + { + panic!("invalid range"); + } + Self{size, symmetric, range, ortho} + } + + state_impl!(pub Option<Point2>); +} + +impl BlockLogic for BridgeBlock +{ + fn get_size(&self) -> u8 + { + self.size + } + + fn is_symmetric(&self) -> bool + { + self.symmetric + } + + fn data_from_i32(&self, config: i32, pos: GridPos) -> Result<DynData, DataConvertError> + { + let (x, y) = ((config >> 16) as i16, config as i16); + if x < 0 || y < 0 + { + return Err(DataConvertError(Box::new(BridgeConvertError{x, y}))); + } + let dx = x as i32 - pos.0 as i32; + let dy = y as i32 - pos.1 as i32; + Ok(DynData::Point2(dx, dy)) + } + + fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError> + { + match data + { + DynData::Empty => Ok(Some(Self::create_state(None))), + DynData::Point2(dx, dy) => + { + if self.ortho + { + if dx != 0 + { + if dy != 0 + { + return Err(DeserializeError::Custom(Box::new(BridgeDeserializeError::NonOrthogonal(dx, dy)))); + } + else + { + if dx > self.range as i32 || dx < -(self.range as i32) + { + return Err(DeserializeError::Custom(Box::new(BridgeDeserializeError::TooFar{dx, dy, max: self.range}))); + } + } + } + else + { + if dy > self.range as i32 || dy < -(self.range as i32) + { + return Err(DeserializeError::Custom(Box::new(BridgeDeserializeError::TooFar{dx, dy, max: self.range}))); + } + } + } + // can't check range otherwise, it depends on the target's size + Ok(Some(Self::create_state(Some((dx, dy))))) + }, + _ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::Point2}), + } + } + + 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((dx, dy)) => Ok(DynData::Point2(*dx, *dy)), + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct BridgeConvertError +{ + pub x: i16, + pub y: i16, +} + +impl fmt::Display for BridgeConvertError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + write!(f, "invalid coordinate ({} / {}) for bridge", self.x, self.y) + } +} + +impl Error for BridgeConvertError {} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BridgeDeserializeError +{ + TooFar{dx: i32, dy: i32, max: u16}, + NonOrthogonal(i32, i32), +} + +impl fmt::Display for BridgeDeserializeError +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + Self::TooFar{dx, dy, max} => write!(f, "bridge target ({dx} / {dy}) too far (max {max})"), + Self::NonOrthogonal(dx, dy) => write!(f, "bridge can only move orthogonally (got {dx} / {dy})"), + } + } +} + +impl Error for BridgeDeserializeError {} |