1use crate::wiring::{Circuit, WiringElement};
2use common::{
3 comp::{LightEmitter, PhysicsState, Pos},
4 event, event_emitters,
5 resources::EntitiesDiedLastTick,
6};
7use common_ecs::{Job, Origin, Phase, System};
8use common_state::BlockChange;
9use hashbrown::HashMap;
10use specs::{
11 Entities, Entity, Join, LendJoin, Read, ReadStorage, SystemData, Write, WriteStorage, shred,
12};
13
14#[derive(SystemData)]
15pub struct ReadData<'a> {
16 entities: Entities<'a>,
17 circuits: ReadStorage<'a, Circuit>,
18 pos: ReadStorage<'a, Pos>,
19 physics_states: ReadStorage<'a, PhysicsState>,
20 entities_died_last_tick: Read<'a, EntitiesDiedLastTick>,
21}
22
23event_emitters! {
24 struct Events[Emitters] {
25 shoot: event::ShootEvent,
26 }
27}
28
29#[derive(Default)]
31pub struct Sys;
32impl<'a> System<'a> for Sys {
33 type SystemData = (
34 ReadData<'a>,
35 Events<'a>,
36 WriteStorage<'a, WiringElement>,
37 WriteStorage<'a, LightEmitter>, Write<'a, BlockChange>,
39 );
40
41 const NAME: &'static str = "wiring";
42 const ORIGIN: Origin = Origin::Server;
43 const PHASE: Phase = Phase::Create;
44
45 fn run(
46 _job: &mut Job<Self>,
47 (read_data, events, mut wiring_elements, mut light_emitters, mut block_change): Self::SystemData,
48 ) {
49 let mut emitters = events.get_emitters();
50
51 let computed_outputs: HashMap<Entity, HashMap<String, f32>> = (
55 &read_data.entities,
56 &wiring_elements,
57 read_data.physics_states.maybe(),
58 read_data.pos.maybe(),
59 )
60 .join()
61 .map(|(entity, wiring_element, physics_state, pos)| {
62 (
63 entity,
64 wiring_element
65 .outputs
66 .iter()
67 .map(|(key, output_formula)| {
68 (
69 key.to_string(),
71 output_formula.compute_output(
73 &wiring_element.inputs,
74 physics_state,
75 &read_data.entities_died_last_tick.0,
76 pos,
77 ),
78 )
79 })
80 .collect::<HashMap<_, _>>(),
81 )
82 })
83 .collect();
84
85 (read_data.circuits)
88 .join()
89 .flat_map(|circuit| circuit.wires.iter())
90 .for_each(|wire| {
91 let input_value = computed_outputs
93 .get(&wire.input.entity)
94 .and_then(|e| e.get(&wire.input.name))
95 .unwrap_or(&0.0);
96
97 if let Some(wiring_element) = wiring_elements.get_mut(wire.output.entity) {
100 wiring_element
101 .inputs
102 .insert(wire.output.name.clone(), *input_value);
103 }
104 });
105
106 (
108 &read_data.entities,
109 &mut wiring_elements,
110 read_data.physics_states.maybe(),
111 (&mut light_emitters).maybe(),
112 read_data.pos.maybe(),
113 )
114 .lend_join()
115 .for_each(
116 |(entity, wiring_element, physics_state, mut light_emitter, pos)| {
117 wiring_element
118 .actions
119 .iter()
120 .filter(|wiring_action| {
121 wiring_action.formula.compute_output(
124 &wiring_element.inputs,
125 physics_state,
126 &read_data.entities_died_last_tick.0,
127 pos,
128 ) >= wiring_action.threshold
129 })
130 .for_each(|wiring_action| {
131 wiring_action.apply_effects(
133 entity,
134 &wiring_element.inputs,
135 physics_state,
136 &read_data.entities_died_last_tick.0,
137 &mut emitters,
138 pos,
139 &mut block_change,
140 light_emitter.as_deref_mut(),
141 );
142 })
143 },
144 )
145 }
146}