1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
use specs::{
    Component, DenseVecStorage, Entity, Join, LazyUpdate, Read, ReadStorage, System,
    WriteStorage,
};

use crate::{
    actions::{Action, ActionState},
    considerations::Consideration,
    measures::Measure,
    pickers::Picker,
};

#[derive(Debug, Clone)]
pub struct ActionEnt(pub Entity);

#[derive(Debug, Clone)]
pub struct ConsiderationEnt(pub Entity);

#[derive(Debug, Clone, Default)]
pub struct Utility {
    pub value: f32,
    pub weight: f32,
}

// Contains different types of Considerations and Actions
#[derive(Debug)]
pub struct Choice {
    pub name: String,
    pub measure: Box<dyn Measure>,
    pub considerations: Vec<ConsiderationEnt>,
    pub action: ActionEnt,
}
impl Choice {
    pub fn calculate<'a>(&self, considerations: &ReadStorage<'a, Consideration>) -> f32 {
        self.measure.calculate(
            self.considerations
                .iter()
                .map(|choice_cons| {
                    &considerations
                        .get(choice_cons.0.clone())
                        .expect("Where did the consideration go?")
                        .utility
                })
                .collect(),
        )
    }
}

#[derive(Component, Debug)]
pub struct Thinker {
    pub name: String,
    pub picker: Box<dyn Picker>,
    pub default_action: Option<ActionEnt>,
    pub choices: Vec<Choice>,
    pub parent: Option<Entity>,
    pub current_action: Option<ActionEnt>,
}

pub struct ThinkerSystem;

impl<'a> System<'a> for ThinkerSystem {
    type SystemData = (
        WriteStorage<'a, Thinker>,
        ReadStorage<'a, Consideration>,
        WriteStorage<'a, Action>,
        Read<'a, LazyUpdate>,
    );
    fn run(&mut self, (mut thinkers, considerations, mut actions, lazy): Self::SystemData) {
        for thinker in (&mut thinkers).join() {
            // TODO: Maybe clean up current_action here before doing anything else?
            //
            // Think about what action we're supposed to be taking. We do this
            // every tick, because we might change our mind.
            if let Some(picked_action_ent) = thinker.picker.pick(&thinker.choices, &considerations)
            {
                // ...and then execute it (details below).
                exec_picked_action(thinker, &picked_action_ent, &mut actions, &lazy);
            } else if let Some(default_action_ent) = &thinker.default_action {
                // Otherwise, let's just execute the default one! (if it's there)
                let default_action_ent = default_action_ent.clone();
                exec_picked_action(thinker, &default_action_ent, &mut actions, &lazy);
            }
        }
    }
}

fn exec_picked_action(
    thinker: &mut Thinker,
    picked_action_ent: &ActionEnt,
    actions: &mut WriteStorage<Action>,
    lazy: &Read<LazyUpdate>,
) {
    // If we do find one, then we need to grab the corresponding
    // component for it. The "action" that `picker.pick()` returns
    // is just a newtype for an Entity.
    //
    // This should usually be true. It's definitely a bug if we
    // accidentally forgot to create, or we deleted the action
    // entity. For now, we're just gonna panic if it's not there.
    let picked_action = actions.get_mut(picked_action_ent.0.clone()).expect("Couldn't find an Action component corresponding to an Action entity. This is definitely a bug.");

    // Now we check the current action. We need to check if we picked the same one as the previous tick.
    //
    // TODO: I don't know where the right place to put this is
    // (maybe not in this logic), but we do need some kind of
    // oscillation protection so we're not just bouncing back and
    // forth between the same couple of actions.
    if let Some(current) = &mut thinker.current_action {
        if current.0 != picked_action_ent.0 {
            // So we've picked a different action than we were
            // currently executing. Just like before, we grab the
            // actual Action component (and we assume it exists).
            let curr_action = actions.get_mut(picked_action_ent.0.clone()).expect("Couldn't find a component corresponding to the current action. This is definitely a bug.");
            // If the action is executing, or was requested, we
            // need to cancel it to make sure it stops. The Action
            // system will take care of resetting its state as
            // needed.
            match curr_action.state {
                ActionState::Executing | ActionState::Requested => {
                    curr_action.state = ActionState::Cancelled;
                }
                _ => {}
            };
            // Finally, since we're doing a new action, we set its
            // Entity as the new current Action!
            *current = picked_action_ent.clone();
        } else {
            // Otherwise, it turns out we want to keep executing
            // the same action. Just in case, we go ahead and set
            // it as Requested if for some reason it had finished
            // but the Action System hasn't gotten around to
            // cleaning it up.
            //
            // TODO: Is this the right thing to do? Should we only
            // do `Requested` if the state is `Init`?
            match picked_action.state {
                ActionState::Init
                | ActionState::Cancelled
                | ActionState::Success
                | ActionState::Failure => {
                    picked_action.factory.add(
                        thinker.parent.expect("Where's the parent?...").clone(),
                        picked_action_ent.clone(),
                        lazy,
                    );
                    picked_action.state = ActionState::Requested;
                }
                _ => {}
            }
        }
    } else {
        // This branch arm is called when there's no
        // current_action in the thinker. The logic here is pretty
        // straightforward -- we set the action, Request it, and
        // that's it.
        picked_action.factory.add(
            thinker.parent.expect("Where's the parent?...").clone(),
            picked_action_ent.clone(),
            lazy,
        );
        thinker.current_action = Some(picked_action_ent.clone());
        picked_action.state = ActionState::Requested;
    }
}