mindustry logic execution, map- and schematic- parsing and rendering
Implement bridge block state
KosmosPrime 2023-01-22
parent 8f3ce5a · commit 94749f5
-rw-r--r--src/block/fluid.rs5
-rw-r--r--src/block/transport.rs150
2 files changed, 150 insertions, 5 deletions
diff --git a/src/block/fluid.rs b/src/block/fluid.rs
index 6a159c2..6174eee 100644
--- a/src/block/fluid.rs
+++ b/src/block/fluid.rs
@@ -4,6 +4,7 @@ use std::fmt;
use crate::block::{BlockLogic, DataConvertError, DeserializeError, make_register, SerializeError};
use crate::block::simple::{SimpleBlock, state_impl};
+use crate::block::transport::BridgeBlock;
use crate::content;
use crate::data::GridPos;
use crate::data::dynamic::{DynData, DynType};
@@ -21,8 +22,8 @@ make_register!
LIQUID_CONTAINER: "liquid-container" => SimpleBlock::new(2, true);
LIQUID_TANK: "liquid-tank" => SimpleBlock::new(3, true);
LIQUID_JUNCTION: "liquid-junction" => SimpleBlock::new(1, true);
- BRIDGE_CONDUIT: "bridge-conduit" => SimpleBlock::new(1, true); // TODO config: destination
- PHASE_CONDUIT: "phase-conduit" => SimpleBlock::new(1, true); // TODO config: destination
+ BRIDGE_CONDUIT: "bridge-conduit" => BridgeBlock::new(1, true, 4, true);
+ PHASE_CONDUIT: "phase-conduit" => BridgeBlock::new(1, true, 12, true);
// sandbox only
LIQUID_SOURCE: "liquid-source" => FluidBlock::new(1, true);
LIQUID_VOID: "liquid-void" => SimpleBlock::new(1, true);
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 {}