mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/block/logic.rs')
-rw-r--r--src/block/logic.rs226
1 files changed, 160 insertions, 66 deletions
diff --git a/src/block/logic.rs b/src/block/logic.rs
index 8a6b447..ee9445e 100644
--- a/src/block/logic.rs
+++ b/src/block/logic.rs
@@ -5,12 +5,23 @@ use std::string::FromUtf8Error;
use image::{Rgb, RgbImage};
use crate::block::simple::*;
-use crate::block::*;
-use crate::data::dynamic::DynType;
+use crate::data::dynamic::{DynSerializer, DynType};
+use crate::{block::*, Serializer};
use crate::data::{self, CompressError, DataRead, DataWrite};
make_simple!(LogicBlock);
+make_simple!(
+ MemoryBlock,
+ |_, _, _, _, _, _| None,
+ |_, _, _, buff: &mut DataRead| {
+ // format:
+ // - iterate [`u32`]
+ // - memory: [`f64`]
+ let n = buff.read_u32()? as usize;
+ buff.skip(n * 8)
+ }
+);
make_register! {
"reinforced-message" => MessageLogic::new(1, true, cost!(Graphite: 10, Beryllium: 5));
@@ -19,15 +30,15 @@ make_register! {
"micro-processor" => ProcessorLogic::new(1, true, cost!(Copper: 90, Lead: 50, Silicon: 50));
"logic-processor" => ProcessorLogic::new(2, true, cost!(Lead: 320, Graphite: 60, Thorium: 50, Silicon: 80));
"hyper-processor" => ProcessorLogic::new(3, true, cost!(Lead: 450, Thorium: 75, Silicon: 150, SurgeAlloy: 50));
- "memory-cell" => LogicBlock::new(1, true, cost!(Copper: 30, Graphite: 30, Silicon: 30));
- "memory-bank" => LogicBlock::new(2, true, cost!(Copper: 30, Graphite: 80, Silicon: 80, PhaseFabric: 30));
+ "memory-cell" => MemoryBlock::new(1, true, cost!(Copper: 30, Graphite: 30, Silicon: 30));
+ "memory-bank" => MemoryBlock::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));
"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, &[]);
+ "world-cell" => MemoryBlock::new(1, true, &[]);
}
pub struct CanvasBlock {
@@ -69,6 +80,24 @@ impl CanvasBlock {
state_impl!(pub RgbImage);
}
+fn deser_canvas_image(b: Vec<u8>, size: usize) -> RgbImage {
+ let mut p = RgbImage::new(size as u32, size as u32);
+ for i in 0..(size * size) {
+ 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 % size as u32,
+ i as u32 / size as u32,
+ PALETTE[n as usize],
+ )
+ }
+ p
+}
+
impl BlockLogic for CanvasBlock {
impl_block!();
@@ -78,23 +107,10 @@ impl BlockLogic for CanvasBlock {
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)))
- }
+ DynData::ByteArray(b) => Ok(Some(Self::create_state(deser_canvas_image(
+ b,
+ self.canvas_size as usize,
+ )))),
_ => Err(DeserializeError::InvalidType {
have: data.get_type(),
expect: DynType::String,
@@ -135,6 +151,7 @@ impl BlockLogic for CanvasBlock {
n: &str,
state: Option<&State>,
_: Option<&RenderingContext>,
+ _: Rotation,
) -> Option<ImageHolder> {
if let Some(state) = state {
let state = self.clone_state(state);
@@ -162,6 +179,26 @@ impl BlockLogic for CanvasBlock {
self.size as u32 * 32,
)))
}
+
+ /// format:
+ /// - len: [`i32`]
+ /// - read(len) -> [`deser_canvas_image`]
+ fn read(
+ &self,
+ build: &mut Build,
+ _: &BlockRegistry,
+ _: &EntityMapping,
+ buff: &mut DataRead,
+ ) -> Result<(), DataReadError> {
+ let n = buff.read_i32()? as usize;
+ let mut b = vec![0; n];
+ buff.read_bytes(&mut b)?;
+ build.state = Some(Self::create_state(deser_canvas_image(
+ b,
+ self.canvas_size as usize,
+ )));
+ Ok(())
+ }
}
pub struct MessageLogic {
@@ -213,6 +250,17 @@ impl BlockLogic for MessageLogic {
fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> {
Ok(DynData::String(Some(Self::get_state(state).clone())))
}
+
+ fn read(
+ &self,
+ b: &mut Build,
+ _: &BlockRegistry,
+ _: &EntityMapping,
+ buff: &mut DataRead,
+ ) -> Result<(), DataReadError> {
+ b.state = Some(Self::create_state(buff.read_utf()?.to_string()));
+ Ok(())
+ }
}
pub struct SwitchLogic {
@@ -257,13 +305,40 @@ impl BlockLogic for SwitchLogic {
Box::new(*Self::get_state(state))
}
- fn mirror_state(&self, _: &mut State, _: bool, _: bool) {}
-
- fn rotate_state(&self, _: &mut State, _: bool) {}
-
fn serialize_state(&self, state: &State) -> Result<DynData, SerializeError> {
Ok(DynData::Boolean(*Self::get_state(state)))
}
+
+ fn read(
+ &self,
+ build: &mut Build,
+ _: &BlockRegistry,
+ _: &EntityMapping,
+ buff: &mut DataRead,
+ ) -> Result<(), DataReadError> {
+ build.state = Some(Self::create_state(buff.read_bool()?));
+ Ok(())
+ }
+
+ fn draw(
+ &self,
+ _: &str,
+ _: &str,
+ state: Option<&State>,
+ _: Option<&RenderingContext>,
+ _: Rotation,
+ ) -> Option<ImageHolder> {
+ let base = load("logic", "switch").unwrap();
+ if let Some(state) = state {
+ if *Self::get_state(state) {
+ let mut base = base.clone();
+ let on = load("logic", "switch-on").unwrap();
+ base.overlay(&on, 0, 0);
+ return Some(ImageHolder::from(base));
+ }
+ }
+ Some(ImageHolder::from(base))
+ }
}
pub struct ProcessorLogic {
@@ -286,6 +361,36 @@ impl ProcessorLogic {
state_impl!(pub ProcessorState);
}
+fn read_decompressed(buff: &mut DataRead) -> Result<ProcessorState, ProcessorDeserializeError> {
+ let ver = buff.read_u8()?;
+ if ver != 1 {
+ return Err(ProcessorDeserializeError::Version(ver));
+ }
+
+ let code_len = buff.read_u32()? as usize;
+ if !(0..=500 * 1024).contains(&code_len) {
+ return Err(ProcessorDeserializeError::CodeLength(code_len));
+ }
+ let mut code = vec![];
+ code.resize(code_len, 0);
+ buff.read_bytes(&mut code)?;
+ let code = String::from_utf8(code)?;
+ let link_cnt = buff.read_u32()? as usize;
+ let mut links = vec![];
+ links.reserve(link_cnt);
+ for _ in 0..link_cnt {
+ let name = buff.read_utf()?;
+ let x = buff.read_i16()?;
+ let y = buff.read_i16()?;
+ links.push(ProcessorLink {
+ name: String::from(name),
+ x,
+ y,
+ });
+ }
+ Ok(ProcessorState { code, links })
+}
+
impl BlockLogic for ProcessorLogic {
impl_block!();
@@ -299,43 +404,11 @@ impl BlockLogic for ProcessorLogic {
DynData::ByteArray(arr) => {
let input = arr.as_ref();
let buff = DataRead::new(input).deflate()?;
- let mut buff = DataRead::new(&buff);
- let ver = ProcessorDeserializeError::forward(buff.read_u8())?;
- if ver != 1 {
- return Err(DeserializeError::Custom(Box::new(
- ProcessorDeserializeError::Version(ver),
- )));
- }
-
- let code_len = ProcessorDeserializeError::forward(buff.read_i32())?;
- if !(0..=500 * 1024).contains(&code_len) {
- return Err(DeserializeError::Custom(Box::new(
- ProcessorDeserializeError::CodeLength(code_len),
- )));
- }
- let mut code = Vec::<u8>::new();
- code.resize(code_len as usize, 0);
- ProcessorDeserializeError::forward(buff.read_bytes(&mut code))?;
- let code = ProcessorDeserializeError::forward(String::from_utf8(code))?;
- let link_cnt = ProcessorDeserializeError::forward(buff.read_i32())?;
- if link_cnt < 0 {
- return Err(DeserializeError::Custom(Box::new(
- ProcessorDeserializeError::LinkCount(link_cnt),
- )));
- }
- let mut links = Vec::<ProcessorLink>::new();
- links.reserve(link_cnt as usize);
- for _ in 0..link_cnt {
- let name = ProcessorDeserializeError::forward(buff.read_utf())?;
- let x = ProcessorDeserializeError::forward(buff.read_i16())?;
- let y = ProcessorDeserializeError::forward(buff.read_i16())?;
- links.push(ProcessorLink {
- name: String::from(name),
- x,
- y,
- });
- }
- Ok(Some(Self::create_state(ProcessorState { code, links })))
+ Ok(Some(Self::create_state(
+ ProcessorDeserializeError::forward(read_decompressed(&mut DataRead::new(
+ &buff,
+ )))?,
+ )))
}
_ => Err(DeserializeError::InvalidType {
have: data.get_type(),
@@ -344,6 +417,29 @@ impl BlockLogic for ProcessorLogic {
}
}
+ fn read(
+ &self,
+ b: &mut Build,
+ _: &BlockRegistry,
+ _: &EntityMapping,
+ buff: &mut DataRead,
+ ) -> Result<(), DataReadError> {
+ let n = buff.read_u32()? as usize;
+ let mut v = vec![0; n];
+ buff.read_bytes(&mut v)?;
+ v = DataRead::new(&v).deflate().unwrap();
+ b.state = Some(Self::create_state(
+ read_decompressed(&mut DataRead::new(&v)).unwrap(),
+ ));
+ for _ in 0..buff.read_u32()? {
+ let _ = buff.read_utf()?;
+ let _ = DynSerializer.deserialize(buff).unwrap();
+ }
+ let memory = buff.read_u32()? as usize;
+ buff.skip(memory * 8)?;
+ Ok(())
+ }
+
fn clone_state(&self, state: &State) -> State {
Box::new(Self::get_state(state).clone())
}
@@ -396,9 +492,7 @@ pub enum ProcessorDeserializeError {
#[error("unsupported version ({0})")]
Version(u8),
#[error("invalid code length ({0})")]
- CodeLength(i32),
- #[error("invalid link count {0}")]
- LinkCount(i32),
+ CodeLength(usize),
}
impl ProcessorDeserializeError {