1use noisy_float::types::{R32, R64};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use crate::Container;
5
6const DEFAULT_VERSION: u64 = 77310525440;
7
8pub type Prototype = String;
9pub type EntityNumber = OneBasedIndex;
10pub type ItemStackIndex = u16;
11pub type ItemCountType = u32;
12pub type GraphicsVariation = u8;
13pub type OneBasedIndex = std::num::NonZeroUsize;
14
15#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
16#[serde(default)]
17pub struct BlueprintBook {
19 pub item: String,
20 #[serde(skip_serializing_if = "Option::is_none")]
21 pub label: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
23 pub label_color: Option<Color>,
24 pub blueprints: Vec<BlueprintBookBlueprintValue>,
25 pub active_index: usize,
26 pub version: u64,
27}
28
29impl Default for BlueprintBook {
30 fn default() -> BlueprintBook {
31 BlueprintBook {
32 item: "blueprint-book".into(),
33 version: DEFAULT_VERSION,
34 label: Default::default(),
35 label_color: Default::default(),
36 blueprints: Default::default(),
37 active_index: Default::default(),
38 }
39 }
40}
41
42#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
43#[serde(rename_all = "snake_case")]
44pub struct BlueprintBookBlueprintValue {
45 pub index: usize,
46 #[serde(flatten)]
47 pub item: Container,
48}
49
50#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
51#[serde(default)]
52pub struct Blueprint {
54 pub item: String,
55 pub label: String,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub label_color: Option<Color>,
58 pub entities: Vec<Entity>,
59 pub tiles: Vec<Tile>,
60 pub icons: Vec<Icon>,
61 pub schedules: Vec<Schedule>,
62 pub version: u64,
63}
64
65impl Default for Blueprint {
66 fn default() -> Blueprint {
67 Blueprint {
68 item: "blueprint".into(),
69 version: DEFAULT_VERSION,
70 label: Default::default(),
71 label_color: Default::default(),
72 entities: Default::default(),
73 tiles: Default::default(),
74 icons: Default::default(),
75 schedules: Default::default(),
76 }
77 }
78}
79
80#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
81pub struct Icon {
83 pub index: OneBasedIndex,
84 pub signal: SignalID,
85}
86
87#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
88pub struct SignalID {
90 pub name: Prototype,
91 #[serde(rename = "type")]
92 pub type_: SignalIDType,
93}
94
95#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
96#[serde(rename_all = "snake_case")]
97pub enum SignalIDType {
98 Item,
99 Fluid,
100 Virtual,
101}
102
103#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
104pub struct Entity {
106 pub entity_number: EntityNumber,
107 pub name: Prototype,
108 pub position: Position,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub direction: Option<u8>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub orientation: Option<R64>,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 pub connections: Option<EntityConnections>,
115 #[serde(skip_serializing_if = "Option::is_none")]
116 pub control_behavior: Option<ControlBehavior>,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub items: Option<ItemRequest>,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub recipe: Option<Prototype>,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub bar: Option<ItemStackIndex>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub inventory: Option<Inventory>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub infinity_settings: Option<InfinitySettings>,
127 #[serde(rename = "type")]
128 #[serde(skip_serializing_if = "Option::is_none")]
129 pub type_: Option<EntityType>,
130 #[serde(skip_serializing_if = "Option::is_none")]
131 pub input_priority: Option<EntityPriority>,
132 #[serde(skip_serializing_if = "Option::is_none")]
133 pub output_priority: Option<EntityPriority>,
134 #[serde(skip_serializing_if = "Option::is_none")]
135 pub filter: Option<Prototype>,
136 #[serde(skip_serializing_if = "Option::is_none")]
137 pub filters: Option<Vec<ItemFilter>>,
138 #[serde(skip_serializing_if = "Option::is_none")]
139 pub filter_mode: Option<EntityFilterMode>,
140 #[serde(skip_serializing_if = "Option::is_none")]
141 pub override_stack_size: Option<u8>,
142 #[serde(skip_serializing_if = "Option::is_none")]
143 pub drop_position: Option<Position>,
144 #[serde(skip_serializing_if = "Option::is_none")]
145 pub pickup_position: Option<Position>,
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub request_filters: Option<Vec<LogisticFilter>>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub request_from_buffers: Option<bool>,
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub parameters: Option<SpeakerParameter>,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub alert_parameters: Option<SpeakerAlertParameter>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub auto_launch: Option<bool>,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub variation: Option<GraphicsVariation>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub color: Option<Color>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub station: Option<String>,
162}
163
164#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
165pub struct ControlBehavior {
167 #[serde(skip_serializing_if = "Option::is_none")]
168 pub arithmetic_conditions: Option<ArithmeticConditions>,
170 #[serde(skip_serializing_if = "Option::is_none")]
171 pub decider_conditions: Option<DeciderConditions>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub filters: Option<Vec<ControlFilter>>,
176 #[serde(skip_serializing_if = "Option::is_none")]
177 pub is_on: Option<bool>
179}
180
181#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
182pub struct ArithmeticConditions {
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub first_constant: Option<i32>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub first_signal: Option<SignalID>,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub second_constant: Option<i32>,
190 #[serde(skip_serializing_if = "Option::is_none")]
191 pub second_signal: Option<SignalID>,
192 pub operation: String,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub output_signal: Option<SignalID>
195}
196
197#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
198pub struct DeciderConditions {
200 #[serde(skip_serializing_if = "Option::is_none")]
201 pub first_signal: Option<SignalID>,
202 #[serde(skip_serializing_if = "Option::is_none")]
203 pub second_signal: Option<SignalID>,
204 #[serde(skip_serializing_if = "Option::is_none")]
205 pub constant: Option<i32>,
206 pub comparator: String,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub output_signal: Option<SignalID>,
209 #[serde(skip_serializing_if = "Option::is_none")]
210 pub copy_count_from_input: Option<bool>
211}
212
213#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
214#[serde(untagged)]
215pub enum EntityConnections {
216 StringIdx(HashMap<String, Connection>),
217 NumberIdx(HashMap<OneBasedIndex, Connection>),
218}
219
220#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
221#[serde(rename_all = "snake_case")]
222pub enum EntityType {
223 Input,
224 Output,
225 Item,
226}
227
228#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
229#[serde(rename_all = "snake_case")]
230pub enum EntityPriority {
231 Left,
232 Right,
233}
234
235#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
236#[serde(rename_all = "snake_case")]
237pub enum EntityFilterMode {
238 Whitelist,
239 Blacklist,
240}
241
242#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
243pub struct Inventory {
245 pub filters: Vec<ItemFilter>,
246 #[serde(skip_serializing_if = "Option::is_none")]
247 pub bar: Option<ItemStackIndex>,
248}
249
250#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
251pub struct Schedule {
253 pub schedule: Vec<ScheduleRecord>,
254 pub locomotives: Vec<EntityNumber>,
255}
256
257#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
258pub struct ScheduleRecord {
260 pub station: String,
261 pub wait_conditions: Vec<WaitCondition>,
262}
263
264#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
265pub struct WaitCondition {
267 #[serde(rename = "type")]
268 pub type_: WaitConditionType,
269 pub compare_type: CompareType,
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub ticks: Option<u64>,
272 #[serde(skip_serializing_if = "Option::is_none")]
273 pub condition: Option<CircuitCondition>,
274}
275
276#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
277#[serde(rename_all = "snake_case")]
278pub enum WaitConditionType {
279 Time,
280 Inactivity,
281 Full,
282 Empty,
283 ItemCount,
284 Circuit,
285 RobotsInactive,
286 FluidCount,
287 PassengerPresent,
288 PassengerNotPresent,
289}
290
291#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
292#[serde(rename_all = "snake_case")]
293pub enum CompareType {
294 And,
295 Or,
296}
297
298#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
299pub struct CircuitCondition;
300
301#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
302pub struct Tile {
304 pub name: Prototype,
305 pub position: Position,
306}
307
308#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
309pub struct Position {
311 pub x: R64,
312 pub y: R64,
313}
314
315pub type Connection = ConnectionPoint;
317
318#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
319pub struct ConnectionPoint {
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub red: Option<Vec<ConnectionData>>,
323 #[serde(skip_serializing_if = "Option::is_none")]
324 pub green: Option<Vec<ConnectionData>>,
325}
326
327#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
328pub struct ConnectionData {
330 pub entity_id: EntityNumber,
331 #[serde(skip_serializing_if = "Option::is_none")]
334 pub circuit_id: Option<i32>,
335}
336
337#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
339#[serde(untagged)]
340pub enum ItemRequest {
341 Compact(HashMap<Prototype, ItemCountType>),
342 Verbose(Vec<ItemRequestVerbose>),
343}
344
345#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
346pub struct ItemRequestVerbose {
347 pub item: Prototype,
348 pub count: ItemCountType,
349}
350
351#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
352pub struct ItemFilter {
354 pub name: Prototype,
355 pub index: OneBasedIndex,
356}
357
358#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
359pub struct InfinitySettings {
361 pub remove_unfiltered_items: bool,
362 #[serde(skip_serializing_if = "Option::is_none")]
363 pub filters: Option<Vec<InfinityFilter>>,
364}
365
366#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
367pub struct InfinityFilter {
369 pub name: Prototype,
370 pub count: ItemCountType,
371 pub mode: InfinityFilterMode,
372 pub index: OneBasedIndex,
373}
374
375#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize)]
376#[serde(rename_all = "kebab-case")]
377pub enum InfinityFilterMode {
378 AtLeast,
379 AtMost,
380 Exactly,
381}
382
383#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
384pub struct LogisticFilter {
386 pub name: Prototype,
387 pub index: OneBasedIndex,
388 pub count: ItemCountType,
389}
390
391#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
392pub struct ControlFilter {
394 pub signal: SignalID,
395 pub index: OneBasedIndex,
396 pub count: i32,
397}
398
399#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
400pub struct SpeakerParameter {
402 pub playback_volume: R64,
403 pub playback_globally: bool,
404 pub allow_polyphony: bool,
405}
406
407#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
408pub struct SpeakerAlertParameter {
410 pub show_alert: bool,
411 pub show_on_map: bool,
412 #[serde(skip_serializing_if = "Option::is_none")]
413 pub icon_signal_id: Option<SignalID>,
414 pub alert_message: String,
415}
416
417#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
418pub struct Color {
420 pub r: R32,
421 pub g: R32,
422 pub b: R32,
423 pub a: R32,
424}