use bevy::prelude::*;
use issun_core::mechanics::propagation::{PropagationEvent, PropagationGraph, PropagationInput};
use issun_core::mechanics::Mechanic;
use std::marker::PhantomData;
use super::systems::{log_propagation_events, propagation_step_system};
use super::types::{
NodeSeverity, PropagationEventWrapper, PropagationGraphResource, PropagationStateComponent,
};
pub struct PropagationPluginV2<M>
where
M: Mechanic<
Config = PropagationGraph,
State = issun_core::mechanics::propagation::PropagationState,
Input = PropagationInput,
Event = PropagationEvent,
>,
{
pub graph: PropagationGraph,
_phantom: PhantomData<M>,
}
impl<M> PropagationPluginV2<M>
where
M: Mechanic<
Config = PropagationGraph,
State = issun_core::mechanics::propagation::PropagationState,
Input = PropagationInput,
Event = PropagationEvent,
>,
{
pub fn new(graph: PropagationGraph) -> Self {
Self {
graph,
_phantom: PhantomData,
}
}
}
impl<M> Plugin for PropagationPluginV2<M>
where
M: Mechanic<
Config = PropagationGraph,
State = issun_core::mechanics::propagation::PropagationState,
Input = PropagationInput,
Event = PropagationEvent,
> + Send
+ Sync
+ 'static,
{
fn build(&self, app: &mut App) {
app.insert_resource(PropagationGraphResource::new(self.graph.clone()));
app.register_type::<NodeSeverity>();
app.add_message::<PropagationEventWrapper>();
app.world_mut().spawn(PropagationStateComponent::<M>::new());
app.add_systems(
Update,
(propagation_step_system::<M>, log_propagation_events),
);
info!(
"PropagationPluginV2 initialized with mechanic: {}",
std::any::type_name::<M>()
);
}
}
#[cfg(test)]
mod tests {
use super::*;
use issun_core::mechanics::propagation::prelude::*;
type TestPropagation = LinearPropagationMechanic;
#[test]
fn test_plugin_builds() {
let mut app = App::new();
app.add_plugins(bevy::MinimalPlugins);
let graph = PropagationGraph::new(vec![PropagationEdge::new(
"A".to_string(),
"B".to_string(),
0.5,
)]);
app.add_plugins(PropagationPluginV2::<TestPropagation>::new(graph));
assert!(app.world().contains_resource::<PropagationGraphResource>());
let state_count = app
.world_mut()
.query::<&PropagationStateComponent<TestPropagation>>()
.iter(app.world())
.count();
assert_eq!(state_count, 1);
}
#[test]
fn test_full_propagation_flow() {
let mut app = App::new();
app.add_plugins(bevy::MinimalPlugins);
let graph = PropagationGraph::new(vec![PropagationEdge::new(
"A".to_string(),
"B".to_string(),
0.5,
)]);
app.add_plugins(PropagationPluginV2::<TestPropagation>::new(graph));
app.world_mut()
.spawn(NodeSeverity::new("A".to_string(), 100.0));
app.world_mut()
.spawn(NodeSeverity::new("B".to_string(), 0.0));
app.update();
let mut events = app
.world_mut()
.resource_mut::<Messages<PropagationEventWrapper>>();
let event_list: Vec<_> = events.drain().collect();
assert_eq!(event_list.len(), 2);
match &event_list[0].event {
PropagationEvent::PressureCalculated { node, pressure } => {
assert_eq!(node, "B");
assert!((pressure - 0.5).abs() < 0.001);
}
_ => panic!("Expected PressureCalculated"),
}
match &event_list[1].event {
PropagationEvent::InitialInfection {
node,
initial_severity,
} => {
assert_eq!(node, "B");
assert_eq!(*initial_severity, 20);
}
_ => panic!("Expected InitialInfection"),
}
}
#[test]
fn test_complex_graph() {
let mut app = App::new();
app.add_plugins(bevy::MinimalPlugins);
let graph = PropagationGraph::new(vec![
PropagationEdge::new("A".to_string(), "B".to_string(), 0.4),
PropagationEdge::new("A".to_string(), "C".to_string(), 0.3),
PropagationEdge::new("B".to_string(), "D".to_string(), 0.2),
PropagationEdge::new("C".to_string(), "D".to_string(), 0.2),
]);
app.add_plugins(PropagationPluginV2::<TestPropagation>::new(graph));
app.world_mut()
.spawn(NodeSeverity::new("A".to_string(), 100.0));
app.world_mut()
.spawn(NodeSeverity::new("B".to_string(), 0.0));
app.world_mut()
.spawn(NodeSeverity::new("C".to_string(), 0.0));
app.world_mut()
.spawn(NodeSeverity::new("D".to_string(), 0.0));
app.update();
let mut events = app
.world_mut()
.resource_mut::<Messages<PropagationEventWrapper>>();
let event_list: Vec<_> = events.drain().collect();
assert_eq!(event_list.len(), 4);
}
}