mindustry logic execution, map- and schematic- parsing and rendering
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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::data::GridPos;
use crate::data::dynamic::{DynData, DynType};
use crate::unit;

const GROUND_UNITS: &[unit::Type] = &[unit::Type::Dagger, unit::Type::Crawler, unit::Type::Nova];
const AIR_UNITS: &[unit::Type] = &[unit::Type::Flare, unit::Type::Mono];
const NAVAL_UNITS: &[unit::Type] = &[unit::Type::Risso, unit::Type::Retusa];

make_register!
(
	GROUND_FACTORY: "ground-factory" => AssemblerBlock::new(3, false, GROUND_UNITS);
	AIR_FACTORY: "air-factory" => AssemblerBlock::new(3, false, AIR_UNITS);
	NAVAL_FACTORY: "naval-factory" => AssemblerBlock::new(3, false, NAVAL_UNITS);
	ADDITIVE_RECONSTRUCTOR: "additive-reconstructor" => SimpleBlock::new(3, false);
	MULTIPLICATIVE_RECONSTRUCTOR: "multiplicative-reconstructor" => SimpleBlock::new(5, false);
	EXPONENTIAL_RECONSTRUCTOR: "exponential-reconstructor" => SimpleBlock::new(7, false);
	TETRATIVE_RECONSTRUCTOR: "tetrative-reconstructor" => SimpleBlock::new(9, false);
	REPAIR_POINT: "repair-point" => SimpleBlock::new(1, true);
	REPAIR_TURRET: "repair-turret" => SimpleBlock::new(2, true);
	PAYLOAD_CONVEYOR: "payload-conveyor" => SimpleBlock::new(3, false);
	PAYLOAD_ROUTER: "payload-router" => SimpleBlock::new(3, false);
	// sandbox only
	PAYLOAD_SOURCE: "payload-source" => SimpleBlock::new(5, false); // TODO config: block/unit
	PAYLOAD_VOID: "payload-void" => SimpleBlock::new(5, true);
);

pub struct AssemblerBlock
{
	size: u8,
	symmetric: bool,
	valid: &'static [unit::Type],
}

impl AssemblerBlock
{
	pub const fn new(size: u8, symmetric: bool, valid: &'static [unit::Type]) -> Self
	{
		if size == 0
		{
			panic!("invalid size");
		}
		if valid.is_empty()
		{
			panic!("no valid units");
		}
		if valid.len() > i32::MAX as usize
		{
			panic!("too many valid units");
		}
		Self{size, symmetric, valid}
	}
	
	state_impl!(pub Option<unit::Type>);
}

impl BlockLogic for AssemblerBlock
{
	fn get_size(&self) -> u8
	{
		self.size
	}
	
	fn is_symmetric(&self) -> bool
	{
		self.symmetric
	}
	
	fn data_from_i32(&self, _: i32, _: GridPos) -> Result<DynData, DataConvertError>
	{
		Ok(DynData::Int(-1))
	}
	
	fn deserialize_state(&self, data: DynData) -> Result<Option<Box<dyn Any>>, DeserializeError>
	{
		match data
		{
			DynData::Empty => Ok(Some(Self::create_state(None))),
			DynData::Int(idx) =>
			{
				if idx == -1
				{
					Ok(Some(Self::create_state(None)))
				}
				else if idx >= 0 && idx < self.valid.len() as i32
				{
					Ok(Some(Self::create_state(Some(self.valid[idx as usize]))))
				}
				else
				{
					Err(DeserializeError::Custom(Box::new(AssemblerDeserializeError{idx, count: self.valid.len() as i32})))
				}
			},
			_ => Err(DeserializeError::InvalidType{have: data.get_type(), expect: DynType::Int}),
		}
	}
	
	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>
	{
		if let Some(state) = Self::get_state(state)
		{
			for (i, curr) in self.valid.iter().enumerate()
			{
				if curr == state
				{
					return Ok(DynData::Int(i as i32));
				}
			}
			Err(SerializeError::Custom(Box::new(AssemblerSerializeError(*state))))
		}
		else
		{
			Ok(DynData::Int(-1))
		}
	}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AssemblerDeserializeError
{
	pub idx: i32,
	pub count: i32,
}

impl fmt::Display for AssemblerDeserializeError
{
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
	{
		write!(f, "invalid unit index ({}, #valid: {})", self.idx, self.count)
	}
}

impl Error for AssemblerDeserializeError {}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AssemblerSerializeError(unit::Type);

impl fmt::Display for AssemblerSerializeError
{
	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
	{
		write!(f, "invalid unit ({:?}) is not valid", self.0)
	}
}

impl Error for AssemblerSerializeError {}