use crate::prelude::*;
use beet_core::prelude::*;
#[action(on_start, on_next)]
#[derive(Default, Component, Deref, DerefMut, Reflect)]
#[reflect(Default, Component)]
#[require(PreventPropagateEnd)]
pub struct Parallel(pub HashSet<Entity>);
fn on_start(
ev: On<GetOutcome>,
mut commands: Commands,
mut query: Query<(&mut Parallel, &Children)>,
) -> Result {
let target = ev.target();
let (mut action, children) = query.get_mut(target)?;
action.clear();
if children.is_empty() {
commands.entity(target).trigger_target(Outcome::Pass);
return Ok(());
}
for child in children.iter() {
commands.entity(child).trigger_target(GetOutcome);
}
Ok(())
}
fn on_next(
ev: On<ChildEnd<Outcome>>,
mut commands: Commands,
mut query: Query<(&mut Parallel, &Children)>,
) -> Result {
let target = ev.target();
let child = ev.child();
if ev.is_fail() {
commands.entity(target).trigger_target(ev.value().clone());
return Ok(());
}
let (mut action, children) = query.get_mut(target)?;
action.insert(child);
if action.len() == children.len() {
commands.entity(target).trigger_target(ev.value().clone());
}
Ok(())
}
#[cfg(test)]
mod test {
use crate::prelude::*;
use beet_core::prelude::*;
#[test]
fn fails() {
let mut world = ControlFlowPlugin::world();
let on_result = collect_on_result(&mut world);
let on_run = collect_on_run(&mut world);
world
.spawn((Name::new("root"), Parallel::default(), children![
(Name::new("child1"), EndWith(Outcome::Pass)),
(Name::new("child2"), EndWith(Outcome::Fail)),
]))
.trigger_target(GetOutcome)
.flush();
on_run.get().xpect_eq(vec![
"root".to_string(),
"child1".to_string(),
"child2".to_string(),
]);
on_result.get().xpect_eq(vec![
("child1".to_string(), Outcome::Pass),
("child2".to_string(), Outcome::Fail),
("root".to_string(), Outcome::Fail),
]);
}
#[test]
fn succeeds() {
let mut world = ControlFlowPlugin::world();
let on_result = collect_on_result(&mut world);
let on_run = collect_on_run(&mut world);
world
.spawn((Name::new("root"), Parallel::default(), children![
(Name::new("child1"), EndWith(Outcome::Pass)),
(Name::new("child2"), EndWith(Outcome::Pass)),
]))
.trigger_target(GetOutcome)
.flush();
on_run.get().xpect_eq(vec![
"root".to_string(),
"child1".to_string(),
"child2".to_string(),
]);
on_result.get().xpect_eq(vec![
("child1".to_string(), Outcome::Pass),
("child2".to_string(), Outcome::Pass),
("root".to_string(), Outcome::Pass),
]);
}
}