factorio_bitpacker/
lib.rs

1use std::collections::HashMap;
2use std::io;
3use std::io::Read;
4
5use factorio_blueprint::objects::{
6  Blueprint, ControlBehavior, ControlFilter, Entity, EntityConnections, EntityNumber,
7  OneBasedIndex, Position, SignalID, SignalIDType,
8};
9
10use itertools::Itertools;
11use noisy_float::types::R64;
12
13/// The primary signal dictionary
14pub const SIGNALS: [(&str, SignalIDType); 256] = [
15  ("signal-1", SignalIDType::Virtual),
16  ("signal-2", SignalIDType::Virtual),
17  ("signal-3", SignalIDType::Virtual),
18  ("signal-4", SignalIDType::Virtual),
19  ("signal-5", SignalIDType::Virtual),
20  ("signal-6", SignalIDType::Virtual),
21  ("signal-7", SignalIDType::Virtual),
22  ("signal-8", SignalIDType::Virtual),
23  ("signal-9", SignalIDType::Virtual),
24  ("signal-0", SignalIDType::Virtual),
25  ("signal-A", SignalIDType::Virtual),
26  ("signal-B", SignalIDType::Virtual),
27  ("signal-C", SignalIDType::Virtual),
28  ("signal-D", SignalIDType::Virtual),
29  ("signal-E", SignalIDType::Virtual),
30  ("signal-F", SignalIDType::Virtual),
31  ("signal-G", SignalIDType::Virtual),
32  ("signal-H", SignalIDType::Virtual),
33  ("signal-I", SignalIDType::Virtual),
34  ("signal-J", SignalIDType::Virtual),
35  ("signal-K", SignalIDType::Virtual),
36  ("signal-L", SignalIDType::Virtual),
37  ("signal-M", SignalIDType::Virtual),
38  ("signal-N", SignalIDType::Virtual),
39  ("signal-O", SignalIDType::Virtual),
40  ("signal-P", SignalIDType::Virtual),
41  ("signal-Q", SignalIDType::Virtual),
42  ("signal-R", SignalIDType::Virtual),
43  ("signal-S", SignalIDType::Virtual),
44  ("signal-T", SignalIDType::Virtual),
45  ("signal-U", SignalIDType::Virtual),
46  ("signal-V", SignalIDType::Virtual),
47  ("signal-W", SignalIDType::Virtual),
48  ("signal-X", SignalIDType::Virtual),
49  ("signal-Y", SignalIDType::Virtual),
50  ("signal-Z", SignalIDType::Virtual),
51  ("signal-red", SignalIDType::Virtual),
52  ("signal-green", SignalIDType::Virtual),
53  ("signal-blue", SignalIDType::Virtual),
54  ("signal-yellow", SignalIDType::Virtual),
55  ("signal-pink", SignalIDType::Virtual),
56  ("signal-cyan", SignalIDType::Virtual),
57  ("signal-check", SignalIDType::Virtual),
58  ("signal-info", SignalIDType::Virtual),
59  ("signal-dot", SignalIDType::Virtual),
60  ("water", SignalIDType::Fluid),
61  ("crude-oil", SignalIDType::Fluid),
62  ("steam", SignalIDType::Fluid),
63  ("heavy-oil", SignalIDType::Fluid),
64  ("light-oil", SignalIDType::Fluid),
65  ("petroleum-gas", SignalIDType::Fluid),
66  ("sulfuric-acid", SignalIDType::Fluid),
67  ("lubricant", SignalIDType::Fluid),
68  ("wooden-chest", SignalIDType::Item),
69  ("iron-chest", SignalIDType::Item),
70  ("steel-chest", SignalIDType::Item),
71  ("storage-tank", SignalIDType::Item),
72  ("transport-belt", SignalIDType::Item),
73  ("fast-transport-belt", SignalIDType::Item),
74  ("express-transport-belt", SignalIDType::Item),
75  ("underground-belt", SignalIDType::Item),
76  ("fast-underground-belt", SignalIDType::Item),
77  ("express-underground-belt", SignalIDType::Item),
78  ("splitter", SignalIDType::Item),
79  ("fast-splitter", SignalIDType::Item),
80  ("express-splitter", SignalIDType::Item),
81  ("burner-inserter", SignalIDType::Item),
82  ("inserter", SignalIDType::Item),
83  ("long-handed-inserter", SignalIDType::Item),
84  ("fast-inserter", SignalIDType::Item),
85  ("filter-inserter", SignalIDType::Item),
86  ("stack-inserter", SignalIDType::Item),
87  ("stack-filter-inserter", SignalIDType::Item),
88  ("small-electric-pole", SignalIDType::Item),
89  ("medium-electric-pole", SignalIDType::Item),
90  ("big-electric-pole", SignalIDType::Item),
91  ("substation", SignalIDType::Item),
92  ("pipe", SignalIDType::Item),
93  ("pipe-to-ground", SignalIDType::Item),
94  ("pump", SignalIDType::Item),
95  ("rail", SignalIDType::Item),
96  ("train-stop", SignalIDType::Item),
97  ("rail-signal", SignalIDType::Item),
98  ("rail-chain-signal", SignalIDType::Item),
99  ("locomotive", SignalIDType::Item),
100  ("cargo-wagon", SignalIDType::Item),
101  ("fluid-wagon", SignalIDType::Item),
102  ("artillery-wagon", SignalIDType::Item),
103  ("car", SignalIDType::Item),
104  ("tank", SignalIDType::Item),
105  ("spidertron", SignalIDType::Item),
106  ("spidertron-remote", SignalIDType::Item),
107  ("logistic-robot", SignalIDType::Item),
108  ("construction-robot", SignalIDType::Item),
109  ("logistic-chest-active-provider", SignalIDType::Item),
110  ("logistic-chest-passive-provider", SignalIDType::Item),
111  ("logistic-chest-storage", SignalIDType::Item),
112  ("logistic-chest-buffer", SignalIDType::Item),
113  ("logistic-chest-requester", SignalIDType::Item),
114  ("roboport", SignalIDType::Item),
115  ("small-lamp", SignalIDType::Item),
116  ("red-wire", SignalIDType::Item),
117  ("green-wire", SignalIDType::Item),
118  ("arithmetic-combinator", SignalIDType::Item),
119  ("decider-combinator", SignalIDType::Item),
120  ("constant-combinator", SignalIDType::Item),
121  ("power-switch", SignalIDType::Item),
122  ("programmable-speaker", SignalIDType::Item),
123  ("stone-brick", SignalIDType::Item),
124  ("concrete", SignalIDType::Item),
125  ("hazard-concrete", SignalIDType::Item),
126  ("refined-concrete", SignalIDType::Item),
127  ("refined-hazard-concrete", SignalIDType::Item),
128  ("landfill", SignalIDType::Item),
129  ("cliff-explosives", SignalIDType::Item),
130  ("repair-pack", SignalIDType::Item),
131  ("blueprint", SignalIDType::Item),
132  ("deconstruction-planner", SignalIDType::Item),
133  ("upgrade-planner", SignalIDType::Item),
134  ("blueprint-book", SignalIDType::Item),
135  ("boiler", SignalIDType::Item),
136  ("steam-engine", SignalIDType::Item),
137  ("solar-panel", SignalIDType::Item),
138  ("accumulator", SignalIDType::Item),
139  ("nuclear-reactor", SignalIDType::Item),
140  ("heat-pipe", SignalIDType::Item),
141  ("heat-exchanger", SignalIDType::Item),
142  ("steam-turbine", SignalIDType::Item),
143  ("burner-mining-drill", SignalIDType::Item),
144  ("electric-mining-drill", SignalIDType::Item),
145  ("offshore-pump", SignalIDType::Item),
146  ("pumpjack", SignalIDType::Item),
147  ("stone-furnace", SignalIDType::Item),
148  ("steel-furnace", SignalIDType::Item),
149  ("electric-furnace", SignalIDType::Item),
150  ("assembling-machine-1", SignalIDType::Item),
151  ("assembling-machine-2", SignalIDType::Item),
152  ("assembling-machine-3", SignalIDType::Item),
153  ("oil-refinery", SignalIDType::Item),
154  ("chemical-plant", SignalIDType::Item),
155  ("centrifuge", SignalIDType::Item),
156  ("lab", SignalIDType::Item),
157  ("beacon", SignalIDType::Item),
158  ("speed-module", SignalIDType::Item),
159  ("speed-module-2", SignalIDType::Item),
160  ("speed-module-3", SignalIDType::Item),
161  ("effectivity-module", SignalIDType::Item),
162  ("effectivity-module-2", SignalIDType::Item),
163  ("effectivity-module-3", SignalIDType::Item),
164  ("productivity-module", SignalIDType::Item),
165  ("productivity-module-2", SignalIDType::Item),
166  ("productivity-module-3", SignalIDType::Item),
167  ("wood", SignalIDType::Item),
168  ("coal", SignalIDType::Item),
169  ("stone", SignalIDType::Item),
170  ("iron-ore", SignalIDType::Item),
171  ("copper-ore", SignalIDType::Item),
172  ("uranium-ore", SignalIDType::Item),
173  ("raw-fish", SignalIDType::Item),
174  ("iron-plate", SignalIDType::Item),
175  ("copper-plate", SignalIDType::Item),
176  ("solid-fuel", SignalIDType::Item),
177  ("steel-plate", SignalIDType::Item),
178  ("plastic-bar", SignalIDType::Item),
179  ("sulfur", SignalIDType::Item),
180  ("battery", SignalIDType::Item),
181  ("explosives", SignalIDType::Item),
182  ("crude-oil-barrel", SignalIDType::Item),
183  ("heavy-oil-barrel", SignalIDType::Item),
184  ("light-oil-barrel", SignalIDType::Item),
185  ("lubricant-barrel", SignalIDType::Item),
186  ("petroleum-gas-barrel", SignalIDType::Item),
187  ("sulfuric-acid-barrel", SignalIDType::Item),
188  ("water-barrel", SignalIDType::Item),
189  ("copper-cable", SignalIDType::Item),
190  ("iron-stick", SignalIDType::Item),
191  ("iron-gear-wheel", SignalIDType::Item),
192  ("empty-barrel", SignalIDType::Item),
193  ("electronic-circuit", SignalIDType::Item),
194  ("advanced-circuit", SignalIDType::Item),
195  ("processing-unit", SignalIDType::Item),
196  ("engine-unit", SignalIDType::Item),
197  ("electric-engine-unit", SignalIDType::Item),
198  ("flying-robot-frame", SignalIDType::Item),
199  ("satellite", SignalIDType::Item),
200  ("rocket-control-unit", SignalIDType::Item),
201  ("low-density-structure", SignalIDType::Item),
202  ("rocket-fuel", SignalIDType::Item),
203  ("nuclear-fuel", SignalIDType::Item),
204  ("uranium-235", SignalIDType::Item),
205  ("uranium-238", SignalIDType::Item),
206  ("uranium-fuel-cell", SignalIDType::Item),
207  ("used-up-uranium-fuel-cell", SignalIDType::Item),
208  ("automation-science-pack", SignalIDType::Item),
209  ("logistic-science-pack", SignalIDType::Item),
210  ("military-science-pack", SignalIDType::Item),
211  ("chemical-science-pack", SignalIDType::Item),
212  ("production-science-pack", SignalIDType::Item),
213  ("utility-science-pack", SignalIDType::Item),
214  ("space-science-pack", SignalIDType::Item),
215  ("pistol", SignalIDType::Item),
216  ("submachine-gun", SignalIDType::Item),
217  ("shotgun", SignalIDType::Item),
218  ("combat-shotgun", SignalIDType::Item),
219  ("rocket-launcher", SignalIDType::Item),
220  ("flamethrower", SignalIDType::Item),
221  ("land-mine", SignalIDType::Item),
222  ("firearm-magazine", SignalIDType::Item),
223  ("piercing-rounds-magazine", SignalIDType::Item),
224  ("uranium-rounds-magazine", SignalIDType::Item),
225  ("shotgun-shell", SignalIDType::Item),
226  ("piercing-shotgun-shell", SignalIDType::Item),
227  ("cannon-shell", SignalIDType::Item),
228  ("explosive-cannon-shell", SignalIDType::Item),
229  ("uranium-cannon-shell", SignalIDType::Item),
230  ("explosive-uranium-cannon-shell", SignalIDType::Item),
231  ("artillery-shell", SignalIDType::Item),
232  ("rocket", SignalIDType::Item),
233  ("explosive-rocket", SignalIDType::Item),
234  ("atomic-bomb", SignalIDType::Item),
235  ("flamethrower-ammo", SignalIDType::Item),
236  ("grenade", SignalIDType::Item),
237  ("cluster-grenade", SignalIDType::Item),
238  ("poison-capsule", SignalIDType::Item),
239  ("slowdown-capsule", SignalIDType::Item),
240  ("defender-capsule", SignalIDType::Item),
241  ("distractor-capsule", SignalIDType::Item),
242  ("destroyer-capsule", SignalIDType::Item),
243  ("light-armor", SignalIDType::Item),
244  ("heavy-armor", SignalIDType::Item),
245  ("modular-armor", SignalIDType::Item),
246  ("power-armor", SignalIDType::Item),
247  ("power-armor-mk2", SignalIDType::Item),
248  ("solar-panel-equipment", SignalIDType::Item),
249  ("fusion-reactor-equipment", SignalIDType::Item),
250  ("battery-equipment", SignalIDType::Item),
251  ("battery-mk2-equipment", SignalIDType::Item),
252  ("belt-immunity-equipment", SignalIDType::Item),
253  ("exoskeleton-equipment", SignalIDType::Item),
254  ("personal-roboport-equipment", SignalIDType::Item),
255  ("personal-roboport-mk2-equipment", SignalIDType::Item),
256  ("night-vision-equipment", SignalIDType::Item),
257  ("energy-shield-equipment", SignalIDType::Item),
258  ("energy-shield-mk2-equipment", SignalIDType::Item),
259  ("personal-laser-defense-equipment", SignalIDType::Item),
260  ("discharge-defense-equipment", SignalIDType::Item),
261  ("discharge-defense-remote", SignalIDType::Item),
262  ("stone-wall", SignalIDType::Item),
263  ("gate", SignalIDType::Item),
264  ("gun-turret", SignalIDType::Item),
265  ("laser-turret", SignalIDType::Item),
266  ("flamethrower-turret", SignalIDType::Item),
267  ("artillery-turret", SignalIDType::Item),
268  ("artillery-targeting-remote", SignalIDType::Item),
269  ("radar", SignalIDType::Item),
270  ("rocket-silo", SignalIDType::Item),
271];
272
273pub fn pack_read<R: Read>(mut from: R) -> Result<Blueprint, io::Error> {
274  let mut buf = Vec::new();
275  from.read_to_end(&mut buf)?;
276
277  let chunks = buf
278    .iter()
279    .chunks(4);
280
281  let mut words = chunks
282    .into_iter()
283    .map(|word| {
284      let (b1, b2, b3, b4) = word.pad_using(4, |_| &0).cloned().collect_tuple().unwrap();
285      u32::from_le_bytes([b1, b2, b3, b4])
286    });
287
288  Ok(pack(&mut words))
289}
290
291pub fn pack<I: Iterator<Item = u32>>(iter: &mut I) -> Blueprint {
292  let entities = iter
293    .chunks(SIGNALS.len())
294    .into_iter()
295    .enumerate()
296    .map(move |(cluster_n, words)| {
297      words
298        .zip(SIGNALS.into_iter())
299        .chunks(20)
300        .into_iter()
301        .map(|signals| {
302          let filters = signals
303            .enumerate()
304            .map(|(signal_n, (word, (signal, signal_type)))| {
305              ControlFilter {
306                signal: SignalID { name: signal.to_owned(), type_: signal_type },
307                index: OneBasedIndex::new(signal_n + 1).unwrap(),
308                // safe transmute from u32 to i32
309                count: i32::from_le_bytes(word.to_le_bytes()),
310              }
311            })
312            .collect::<Vec<_>>();
313
314          ControlBehavior {
315            arithmetic_conditions: None,
316            decider_conditions: None,
317            filters: Some(filters),
318            is_on: Some(true),
319          }
320        })
321        .enumerate()
322        .map(move |(ent_n, control)| Entity {
323          entity_number: EntityNumber::new((&cluster_n + 1) * (ent_n + 1)).unwrap(),
324          name: "constant-combinator".to_owned(),
325          position: {
326            let n = &ent_n % 7;
327            let r = &ent_n / 7 + &cluster_n * 2;
328
329            Position { x: R64::new(r as f64), y: R64::new(n as f64) }
330          },
331          direction: Some(4), // south
332          connections: Some(EntityConnections::NumberIdx(HashMap::new())),
333          control_behavior: Some(control),
334          orientation: None,
335          items: None,
336          recipe: None,
337          bar: None,
338          inventory: None,
339          infinity_settings: None,
340          type_: None,
341          input_priority: None,
342          output_priority: None,
343          filter: None,
344          filters: None,
345          filter_mode: None,
346          override_stack_size: None,
347          drop_position: None,
348          pickup_position: None,
349          request_filters: None,
350          request_from_buffers: None,
351          parameters: None,
352          alert_parameters: None,
353          auto_launch: None,
354          variation: None,
355          color: None,
356          station: None,
357        })
358        .collect::<Vec<_>>()
359    })
360    .map(|vec| vec.into_iter())
361    .flatten()
362    .collect::<Vec<_>>();
363
364  Blueprint {
365    item: "blueprint".to_owned(),
366    label: "auto generated".to_owned(),
367    label_color: None,
368    entities,
369    tiles: vec![],
370    icons: vec![],
371    schedules: vec![],
372    version: 1u64 << (64 - 16) | 1u64 << (64 - 32) | 46u64 << (64 - 16) | 59110u64,
373  }
374}