mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/logic.rs')
-rw-r--r--src/block/logic.rs139
1 files changed, 138 insertions, 1 deletions
diff --git a/src/block/logic.rs b/src/block/logic.rs
index 79941c4..8a6b447 100644
--- a/src/block/logic.rs
+++ b/src/block/logic.rs
@@ -2,9 +2,12 @@
use std::borrow::Cow;
use std::string::FromUtf8Error;
+use image::{Rgb, RgbImage};
+
use crate::block::simple::*;
use crate::block::*;
use crate::data::dynamic::DynType;
+
use crate::data::{self, CompressError, DataRead, DataWrite};
make_simple!(LogicBlock);
@@ -20,13 +23,147 @@ make_register! {
"memory-bank" => LogicBlock::new(2, true, cost!(Copper: 30, Graphite: 80, Silicon: 80, PhaseFabric: 30));
"logic-display" => LogicBlock::new(3, true, cost!(Lead: 100, Metaglass: 50, Silicon: 50));
"large-logic-display" => LogicBlock::new(6, true, cost!(Lead: 200, Metaglass: 100, Silicon: 150, PhaseFabric: 75));
- // todo canvas (cost!(Silicon: 30, Beryllium: 10))
+ "canvas" => CanvasBlock::new(2, true, cost!(Silicon: 30, Beryllium: 10), 12);
// editor only
"world-processor" => LogicBlock::new(1, true, &[]);
"world-message" => MessageLogic::new(1, true, &[]);
"world-cell" => LogicBlock::new(1, true, &[]);
}
+pub struct CanvasBlock {
+ size: u8,
+ symmetric: bool,
+ build_cost: BuildCost,
+ canvas_size: u8,
+}
+
+macro_rules! h {
+ ($x:literal) => {
+ Rgb(color_hex::color_from_hex!($x))
+ };
+}
+const PALETTE: &[Rgb<u8>; 8] = &[
+ h!("#362944"),
+ h!("#c45d9f"),
+ h!("#e39aac"),
+ h!("#f0dab1"),
+ h!("#6461c2"),
+ h!("#2ba9b4"),
+ h!("#93d4b5"),
+ h!("#f0f6e8"),
+];
+
+impl CanvasBlock {
+ #[must_use]
+ pub const fn new(size: u8, symmetric: bool, build_cost: BuildCost, canvas_size: u8) -> Self {
+ assert!(size != 0, "invalid size");
+ assert!(canvas_size != 0, "invalid size");
+ Self {
+ canvas_size,
+ size,
+ symmetric,
+ build_cost,
+ }
+ }
+
+ state_impl!(pub RgbImage);
+}
+
+impl BlockLogic for CanvasBlock {
+ impl_block!();
+
+ fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError> {
+ Ok(DynData::Empty)
+ }
+
+ fn deserialize_state(&self, data: DynData) -> Result<Option<State>, DeserializeError> {
+ match data {
+ DynData::ByteArray(b) => {
+ let mut p = RgbImage::new(self.canvas_size as u32, self.canvas_size as u32);
+ for i in 0..(self.canvas_size * self.canvas_size) as usize {
+ let offset = i * 3;
+ let mut n = 0;
+ for i in 0..3 {
+ let word = (i + offset) >> 3;
+ n |= (((b[word] & (1 << ((i + offset) & 7))) != 0) as u8) << i;
+ }
+ p.put_pixel(
+ i as u32 % self.canvas_size as u32,
+ i as u32 / self.canvas_size as u32,
+ PALETTE[n as usize],
+ )
+ }
+ Ok(Some(Self::create_state(p)))
+ }
+ _ => Err(DeserializeError::InvalidType {
+ have: data.get_type(),
+ expect: DynType::String,
+ }),
+ }
+ }
+
+ fn clone_state(&self, state: &State) -> State {
+ Box::new(Self::get_state(state).clone())
+ }
+
+ fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> {
+ let mut o = vec![0; self.canvas_size as usize * self.canvas_size as usize * 3];
+ let p = Self::get_state(state);
+ for i in 0..(self.canvas_size * self.canvas_size) as usize {
+ let color = p.get_pixel(
+ i as u32 % self.canvas_size as u32,
+ i as u32 / self.canvas_size as u32,
+ );
+ let index = PALETTE.iter().position(|v| v == color).unwrap();
+ let offset = i * 3;
+ for i in 0..3 {
+ let word = (i + offset) >> 3;
+ if index >> i & 1 == 0 {
+ o[word] &= !(1 << ((i + offset) & 7));
+ } else {
+ o[word] |= 1 << ((i + offset) & 7);
+ }
+ }
+ }
+ Ok(DynData::ByteArray(o))
+ }
+
+ /// i thought about drawing the borders and stuff but it felt like too much work
+ fn draw(
+ &self,
+ c: &str,
+ n: &str,
+ state: Option<&State>,
+ _: Option<&RenderingContext>,
+ ) -> Option<ImageHolder> {
+ if let Some(state) = state {
+ let state = self.clone_state(state);
+ let p = state.downcast::<RgbImage>().unwrap();
+ // SAFETY: canvas_size cannot be 0, so width & height musnt be 0, and size cannot be 0
+ let p = unsafe {
+ DynamicImage::from(
+ RgbImage::from_raw(
+ self.canvas_size as u32,
+ self.canvas_size as u32,
+ p.into_raw(),
+ )
+ .unwrap(),
+ )
+ .into_rgba8()
+ .scale((self.size as u32 * 32) - 14)
+ };
+ let mut borders = load(c, n).unwrap().to_owned();
+ borders.overlay(&p, 7, 7);
+ return Some(ImageHolder::from(borders));
+ }
+
+ Some(ImageHolder::from(RgbaImage::new(
+ self.size as u32 * 32,
+ self.size as u32 * 32,
+ )))
+ }
+}
+
pub struct MessageLogic {
size: u8,
symmetric: bool,