veloren/server/src/sys/wiring/compute_outputs.rs

163 lines
4.5 KiB
Rust
Raw Normal View History

2021-04-15 16:28:16 +00:00
use super::WiringData;
use crate::wiring::{Logic, LogicKind, OutputFormula};
2021-05-05 13:54:24 +00:00
use common::{
comp::{PhysicsState, Pos},
resources::EntitiesDiedLastTick,
};
2021-04-15 16:28:16 +00:00
use hashbrown::HashMap;
2021-05-05 13:54:24 +00:00
use rand_distr::num_traits::ToPrimitive;
use specs::{join::Join, Entity, Read};
2021-04-15 16:28:16 +00:00
use tracing::warn;
pub fn compute_outputs(system_data: &WiringData) -> HashMap<Entity, HashMap<String, f32>> {
let WiringData {
entities,
wiring_elements,
physics_states,
2021-05-05 13:54:24 +00:00
entities_died_last_tick,
pos,
2021-04-15 16:28:16 +00:00
..
} = system_data;
2021-05-05 13:54:24 +00:00
(
&*entities,
wiring_elements,
physics_states.maybe(),
pos.maybe(),
)
2021-04-15 16:28:16 +00:00
.join()
2021-05-05 13:54:24 +00:00
.map(|(entity, wiring_element, physics_state, pos)| {
2021-04-15 16:28:16 +00:00
(
entity,
wiring_element
.outputs
.iter()
.map(
|(key, output_formula)| {
compute_output_with_key(
key,
output_formula,
&wiring_element.inputs,
2021-05-05 14:13:38 +00:00
physics_state,
2021-05-05 13:54:24 +00:00
entities_died_last_tick,
pos,
2021-04-15 16:28:16 +00:00
)
}, // (String, f32)
)
.collect::<HashMap<_, _>>(),
)
})
.collect()
}
2021-05-05 13:54:24 +00:00
#[allow(clippy::too_many_arguments)]
2021-04-15 16:28:16 +00:00
pub fn compute_output_with_key(
// yes, this function is defined only to make one place
// look a bit nicer
// Don't discuss.
key: &str,
output_formula: &OutputFormula,
inputs: &HashMap<String, f32>,
2021-05-05 14:13:38 +00:00
physics_state: Option<&PhysicsState>,
2021-05-05 13:54:24 +00:00
entities_died_last_tick: &Read<EntitiesDiedLastTick>,
pos: Option<&Pos>,
2021-04-15 16:28:16 +00:00
) -> (String, f32) {
(
key.to_string(),
2021-05-05 13:54:24 +00:00
compute_output(
output_formula,
inputs,
physics_state,
entities_died_last_tick,
pos,
),
2021-04-15 16:28:16 +00:00
)
}
2021-05-05 13:54:24 +00:00
#[allow(clippy::too_many_arguments)]
2021-04-15 16:28:16 +00:00
pub fn compute_output(
output_formula: &OutputFormula,
inputs: &HashMap<String, f32>,
2021-05-05 14:13:38 +00:00
physics_state: Option<&PhysicsState>,
2021-05-05 13:54:24 +00:00
entities_died_last_tick: &Read<EntitiesDiedLastTick>,
pos: Option<&Pos>,
2021-04-15 16:28:16 +00:00
) -> f32 {
match output_formula {
OutputFormula::Constant { value } => *value,
OutputFormula::Input { name } => *inputs.get(name).unwrap_or(&0.0),
OutputFormula::Logic(logic) => {
output_formula_logic(logic, inputs, physics_state, entities_died_last_tick, pos)
2021-04-15 16:28:16 +00:00
},
OutputFormula::SineWave { .. } => {
warn!("Not implemented OutputFormula::SineWave");
0.0
},
2021-05-05 14:13:38 +00:00
OutputFormula::OnCollide { value } => output_formula_on_collide(value, physics_state),
2021-04-15 16:28:16 +00:00
OutputFormula::OnInteract { .. } => {
warn!("Not implemented OutputFormula::OnInteract");
0.0
},
2021-05-05 13:54:24 +00:00
OutputFormula::OnDeath { value, radius } => {
output_formula_on_death(value, radius, entities_died_last_tick, pos)
},
2021-04-15 16:28:16 +00:00
}
}
2021-05-05 14:13:38 +00:00
fn output_formula_on_collide(value: &f32, physics_state: Option<&PhysicsState>) -> f32 {
if let Some(ps) = physics_state {
2021-04-15 16:28:16 +00:00
if !ps.touch_entities.is_empty() {
return *value;
}
}
0.0
}
2021-05-05 13:54:24 +00:00
fn output_formula_on_death(
value: &f32,
radius: &f32,
entities_died_last_tick: &Read<EntitiesDiedLastTick>,
pos: Option<&Pos>,
) -> f32 {
if let Some(pos_of_entity) = pos {
return *value
* entities_died_last_tick
.0
.iter()
.filter(|(_, dead_pos)| pos_of_entity.0.distance(dead_pos.0) <= *radius)
.count()
.to_f32()
.unwrap_or(0.0);
}
0.0
}
#[allow(clippy::too_many_arguments)]
fn output_formula_logic(
logic: &Logic,
inputs: &HashMap<String, f32>,
physics_state: Option<&PhysicsState>,
entities_died_last_tick: &Read<EntitiesDiedLastTick>,
pos: Option<&Pos>,
) -> f32 {
let left = compute_output(
&logic.left,
inputs,
physics_state,
entities_died_last_tick,
pos,
);
let right = compute_output(
&logic.right,
inputs,
physics_state,
entities_died_last_tick,
pos,
);
match logic.kind {
LogicKind::Max => f32::max(left, right),
LogicKind::Min => f32::min(left, right),
LogicKind::Sub => left - right,
LogicKind::Sum => left + right,
LogicKind::Mul => left * right,
}
}