Skip to content
Snippets Groups Projects
Unverified Commit a5bc5b74 authored by Kat Marchán's avatar Kat Marchán
Browse files

added Steps action for action sequences

parent f86664a1
No related branches found
No related tags found
No related merge requests found
......@@ -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),*
......
......@@ -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>();
}
}
}
......@@ -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());
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment