Skip to content
Snippets Groups Projects
actions.rs 6.78 KiB
Newer Older
use bevy::prelude::*;
Kat Marchán's avatar
Kat Marchán committed

use crate::ActionEnt;

#[derive(Debug)]
pub struct ActionRunnerWrapper(pub(crate) Box<dyn ActionRunner>);
#[derive(Debug, Clone, Eq, PartialEq)]
Kat Marchán's avatar
Kat Marchán committed
pub enum ActionState {
    Init,
    Requested,
    Executing,
    Cancelled,
    Success,
    Failure,
}

impl ActionState {
    pub fn new() -> Self {
        Self::default()
    }

    pub(crate) fn build(builder: Box<dyn Action>, actor: Entity, cmd: &mut Commands) -> ActionEnt {
        let action_ent = ActionEnt(cmd.spawn().id());
        let manager_wrapper = ActionRunnerWrapper(builder.build(actor, action_ent, cmd));
        cmd.entity(action_ent.0)
            .insert(ActionState::default())
            .insert(manager_wrapper);
        cmd.entity(actor).push_children(&[action_ent.0]);
Kat Marchán's avatar
Kat Marchán committed
        action_ent
    }
}

impl Default for ActionState {
    fn default() -> Self {
        Self::Init
    }
}

/**
This trait defines new actions. In general, you should use the [derive macro](derive.Action.html) instead.
*/
#[typetag::deserialize]
pub trait Action: std::fmt::Debug + Send + Sync {
    fn build(
        self: Box<Self>,
        actor: Entity,
        action_ent: ActionEnt,
        cmd: &mut Commands,
    ) -> Box<dyn ActionRunner>;
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);
Kat Marchán's avatar
Kat Marchán committed
}

#[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>();
        }
    }
}