diff --git a/big-brain-derive/src/action.rs b/big-brain-derive/src/action.rs index e023bdd8a8ac126a048ebc62c8ace6a441905547..e03bd477b246204695efb9c6b775aeeadce86740 100644 --- a/big-brain-derive/src/action.rs +++ b/big-brain-derive/src/action.rs @@ -72,7 +72,7 @@ impl ToTokens for Action { mod big_brain_action_builder { use super::#ident as Comp; - use big_brain::{typetag, serde::Deserialize, Action, ActionManager, bevy::prelude::{Entity, Commands}, ActionEnt}; + use big_brain::{typetag, serde::Deserialize, Action, ActionRunner, bevy::prelude::{Entity, Commands}, ActionEnt}; #[derive(Debug, Deserialize)] struct #ident { @@ -81,12 +81,12 @@ impl ToTokens for Action { #[typetag::deserialize] impl Action for #ident { - fn build(self: Box<Self>, actor: Entity, action_ent: ActionEnt, cmd: &mut Commands) -> Box<dyn ActionManager> { + fn build(self: Box<Self>, actor: Entity, action_ent: ActionEnt, cmd: &mut Commands) -> Box<dyn ActionRunner> { self } } - impl ActionManager for #ident { + impl ActionRunner for #ident { fn activate(&self, actor: Entity, action_ent: ActionEnt, cmd: &mut Commands) { cmd.entity(action_ent.0).insert(Comp { #(#field_assignments),* diff --git a/src/actions.rs b/src/actions.rs index 2096209ae7670ea39d24c0ee620d41a82fdf826e..6b8b2a7e7810f9532fc539b8a9071acc4a3b19c3 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -3,7 +3,7 @@ use bevy::prelude::*; use crate::ActionEnt; #[derive(Debug)] -pub struct ActionManagerWrapper(pub(crate) Box<dyn ActionManager>); +pub struct ActionRunnerWrapper(pub(crate) Box<dyn ActionRunner>); #[derive(Debug, Clone, Eq, PartialEq)] pub enum ActionState { @@ -22,7 +22,7 @@ impl ActionState { pub(crate) fn build(builder: Box<dyn Action>, actor: Entity, cmd: &mut Commands) -> ActionEnt { let action_ent = ActionEnt(cmd.spawn().id()); - let manager_wrapper = ActionManagerWrapper(builder.build(actor, action_ent, cmd)); + let manager_wrapper = ActionRunnerWrapper(builder.build(actor, action_ent, cmd)); cmd.entity(action_ent.0) .insert(ActionState::default()) .insert(manager_wrapper); @@ -47,10 +47,144 @@ pub trait Action: std::fmt::Debug + Send + Sync { actor: Entity, action_ent: ActionEnt, cmd: &mut Commands, - ) -> Box<dyn ActionManager>; + ) -> Box<dyn ActionRunner>; } -pub trait ActionManager: std::fmt::Debug + Send + Sync { +pub trait ActionRunner: std::fmt::Debug + Send + Sync { fn activate(&self, actor: Entity, action: ActionEnt, cmd: &mut Commands); fn deactivate(&self, action: ActionEnt, cmd: &mut Commands); } + +#[derive(Debug)] +pub struct Steps { + steps: Vec<ActionEnt>, + active_step: usize, +} + +pub fn steps_system( + mut cmd: Commands, + mut steps_q: Query<(Entity, &Parent, &mut Steps)>, + mut states: Query<&mut ActionState>, + runners: Query<&ActionRunnerWrapper>, +) { + use ActionState::*; + for (seq_ent, Parent(actor), mut steps_action) in steps_q.iter_mut() { + let current_state = states.get_mut(seq_ent).expect("uh oh").clone(); + match current_state { + Requested => { + // Begin at the beginning + let step_ent = steps_action.steps[steps_action.active_step]; + let step_runner = runners.get(step_ent.0).expect("oops"); + let mut step_state = states.get_mut(step_ent.0).expect("oops"); + step_runner.0.activate(*actor, step_ent, &mut cmd); + *step_state = Requested; + let mut current_state = states.get_mut(seq_ent).expect("uh oh"); + *current_state = Executing; + } + Executing => { + let mut step_state = states + .get_mut(steps_action.steps[steps_action.active_step].0) + .expect("bug"); + match *step_state { + Init => { + // Request it! This... should not really happen? But just in case I'm missing something... :) + *step_state = Requested; + } + Executing | Requested => { + // do nothing. Everything's running as it should. + } + Cancelled | Failure => { + // Cancel ourselves + let step_ent = steps_action.steps[steps_action.active_step]; + let step_state = step_state.clone(); + let step_runner = runners.get(step_ent.0).expect("oops"); + step_runner.0.deactivate(step_ent, &mut cmd); + let mut seq_state = states.get_mut(seq_ent).expect("idk"); + *seq_state = step_state; + } + Success if steps_action.active_step == steps_action.steps.len() - 1 => { + // We're done! Let's just be successful + let step_ent = steps_action.steps[steps_action.active_step]; + let step_state = step_state.clone(); + let step_runner = runners.get(step_ent.0).expect("oops"); + step_runner.0.deactivate(step_ent, &mut cmd); + let mut seq_state = states.get_mut(seq_ent).expect("idk"); + *seq_state = step_state; + } + Success => { + // Deactivate current step and go to the next step + let step_ent = steps_action.steps[steps_action.active_step]; + let step_runner = runners.get(step_ent.0).expect("oops"); + step_runner.0.deactivate(step_ent, &mut cmd); + + steps_action.active_step += 1; + let step_ent = steps_action.steps[steps_action.active_step]; + let step_runner = runners.get(step_ent.0).expect("oops"); + let mut step_state = states.get_mut(step_ent.0).expect("oops"); + step_runner.0.activate(*actor, step_ent, &mut cmd); + *step_state = ActionState::Requested; + } + } + } + Cancelled => { + // Cancel current action + let step_ent = steps_action.steps[steps_action.active_step]; + let step_runner = runners.get(step_ent.0).expect("oops"); + let mut step_state = states.get_mut(step_ent.0).expect("oops"); + step_runner.0.activate(*actor, step_ent, &mut cmd); + *step_state = ActionState::Cancelled; + } + Init | Success | Failure => { + // Do nothing. + } + } + } +} + +mod seq_action { + use super::*; + use serde::Deserialize; + + #[derive(Debug, Deserialize)] + struct Steps { + steps: Vec<Box<dyn Action>>, + } + + #[typetag::deserialize] + impl Action for Steps { + fn build( + self: Box<Self>, + actor: Entity, + _action_ent: ActionEnt, + cmd: &mut Commands, + ) -> Box<dyn ActionRunner> { + let runner = StepsRunner { + steps: self + .steps + .into_iter() + .map(|builder| ActionState::build(builder, actor, cmd)) + .collect(), + }; + let children: Vec<_> = runner.steps.iter().map(|x| x.0).collect(); + cmd.entity(actor).push_children(&children[..]); + Box::new(runner) + } + } + + #[derive(Debug)] + struct StepsRunner { + steps: Vec<ActionEnt>, + } + + impl ActionRunner for StepsRunner { + fn activate(&self, _actor: Entity, action_ent: ActionEnt, cmd: &mut Commands) { + cmd.entity(action_ent.0).insert(super::Steps { + active_step: 0, + steps: self.steps.clone(), + }); + } + fn deactivate(&self, action_ent: ActionEnt, cmd: &mut Commands) { + cmd.entity(action_ent.0).remove::<super::Steps>(); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index ddb48e8dc3bcfbb0ef37b629277eb4e0ffbcc0d3..22e33379a7cc59f84e49c5077ace13b622bf8487 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ pub struct BigBrainPlugin; impl Plugin for BigBrainPlugin { fn build(&self, app: &mut AppBuilder) { app.add_system(thinker_system.system()); + app.add_system(steps_system.system()); app.add_system(fixed_score_system.system()); app.add_system(all_or_nothing_system.system()); app.add_system(sum_of_scorers_system.system()); diff --git a/src/thinker.rs b/src/thinker.rs index d4ef4ddc9be35d953255d7385d97815e80e95cb5..dc095d062723acd6b535c2336229d23805f85c90 100644 --- a/src/thinker.rs +++ b/src/thinker.rs @@ -6,7 +6,7 @@ use bevy::prelude::*; use serde::Deserialize; use crate::{ - actions::{self, Action, ActionManager, ActionManagerWrapper, ActionState}, + actions::{self, Action, ActionRunner, ActionRunnerWrapper, ActionState}, choices::{Choice, ChoiceBuilder}, scorers::Score, pickers::Picker, @@ -64,7 +64,7 @@ impl Action for builder::Thinker { actor: Entity, action_ent: ActionEnt, cmd: &mut Commands, - ) -> Box<dyn ActionManager> { + ) -> Box<dyn ActionRunner> { let choices = self .choices .into_iter() @@ -80,7 +80,7 @@ impl Action for builder::Thinker { current_action: None, }); cmd.entity(actor).push_children(&[action_ent.0]); - Box::new(ThinkerManager) + Box::new(ThinkerRunner) } } @@ -88,9 +88,9 @@ impl Action for builder::Thinker { pub struct ActiveThinker(bool); #[derive(Debug)] -pub struct ThinkerManager; +pub struct ThinkerRunner; -impl ActionManager for ThinkerManager { +impl ActionRunner for ThinkerRunner { fn activate(&self, _: Entity, action_ent: ActionEnt, cmd: &mut Commands) { cmd.entity(action_ent.0) .insert(ActiveThinker(false)) @@ -125,7 +125,7 @@ pub fn thinker_system( mut thinker_q: Query<(Entity, &Parent, &mut Thinker, &ActiveThinker)>, utilities: Query<&Score>, mut action_states: Query<&mut actions::ActionState>, - builder_wrappers: Query<&ActionManagerWrapper>, + builder_wrappers: Query<&ActionRunnerWrapper>, ) { let start = Instant::now(); for (thinker_ent, Parent(actor), mut thinker, active_thinker) in thinker_q.iter_mut().skip(iterations.index) { @@ -222,7 +222,7 @@ fn exec_picked_action( thinker: &mut Mut<Thinker>, picked_action_ent: &ActionEnt, states: &mut Query<&mut ActionState>, - builder_wrappers: &Query<&ActionManagerWrapper>, + builder_wrappers: &Query<&ActionRunnerWrapper>, ) { // If we do find one, then we need to grab the corresponding // component for it. The "action" that `picker.pick()` returns