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

stop leaking Scorers and Actions?

Fixes: https://github.com/zkat/big-brain/issues/12

I *think* this fixes it, but I need to test it more
thoroughly and make sure everything is actually ok
parent 01270a4f
No related branches found
No related tags found
No related merge requests found
...@@ -78,9 +78,9 @@ fn drink_action_system( ...@@ -78,9 +78,9 @@ fn drink_action_system(
// usually happen because the target action changed (due to a different // usually happen because the target action changed (due to a different
// Scorer winning). But you can also cancel the actions yourself by // Scorer winning). But you can also cancel the actions yourself by
// setting the state in the Action system. // setting the state in the Action system.
mut query: Query<(&Parent, &mut ActionState), With<Drink>>, mut query: Query<(&Actor, &mut ActionState), With<Drink>>,
) { ) {
for (Parent(actor), mut state) in query.iter_mut() { for (Actor(actor), mut state) in query.iter_mut() {
// Use the drink_action's actor to look up the corresponding Thirst. // Use the drink_action's actor to look up the corresponding Thirst.
if let Ok(mut thirst) = thirsts.get_mut(*actor) { if let Ok(mut thirst) = thirsts.get_mut(*actor) {
match *state { match *state {
...@@ -128,9 +128,9 @@ impl ScorerBuilder for ThirstyBuilder { ...@@ -128,9 +128,9 @@ impl ScorerBuilder for ThirstyBuilder {
pub fn thirsty_scorer_system( pub fn thirsty_scorer_system(
thirsts: Query<&Thirst>, thirsts: Query<&Thirst>,
// Same dance with the Parent here, but now Big Brain has added a Score component! // Same dance with the Parent here, but now Big Brain has added a Score component!
mut query: Query<(&Parent, &mut Score), With<Thirsty>>, mut query: Query<(&Actor, &mut Score), With<Thirsty>>,
) { ) {
for (Parent(actor), mut score) in query.iter_mut() { for (Actor(actor), mut score) in query.iter_mut() {
if let Ok(thirst) = thirsts.get(*actor) { if let Ok(thirst) = thirsts.get(*actor) {
// This is really what the job of a Scorer is. To calculate a // This is really what the job of a Scorer is. To calculate a
// generic Utility value that the Big Brain engine will compare // generic Utility value that the Big Brain engine will compare
...@@ -153,13 +153,15 @@ pub fn init_entities(mut cmd: Commands) { ...@@ -153,13 +153,15 @@ pub fn init_entities(mut cmd: Commands) {
let actor = cmd.spawn().insert(Thirst::new(70.0, 2.0)).id(); let actor = cmd.spawn().insert(Thirst::new(70.0, 2.0)).id();
// And finally, we put all the pieces together! // And finally, we put all the pieces together!
Thinker::build() let thinker = Thinker::build()
.picker(FirstToScore { threshold: 80.0 }) .picker(FirstToScore { threshold: 80.0 })
// Note that what we pass in are _builders_, not components! // Note that what we pass in are _builders_, not components!
.when(Thirsty::build(), Drink::build()) .when(Thirsty::build(), Drink::build())
// .attach will do all the necessary work of attaching this component // .attach will do all the necessary work of attaching this component
// and hooking it up to the AI system. // and hooking it up to the AI system.
.attach(&mut cmd, actor); .attach(&mut cmd, actor);
// TODO: this is a footgun and a pita. Please ignore.
cmd.entity(actor).push_children(&[thinker]);
} }
fn main() { fn main() {
......
...@@ -2,7 +2,7 @@ use std::sync::Arc; ...@@ -2,7 +2,7 @@ use std::sync::Arc;
use bevy::prelude::*; use bevy::prelude::*;
use crate::ActionEnt; use crate::{ActionEnt, Actor};
#[derive(Debug, Clone, Eq, PartialEq)] #[derive(Debug, Clone, Eq, PartialEq)]
pub enum ActionState { pub enum ActionState {
...@@ -42,8 +42,7 @@ pub trait ActionBuilder: std::fmt::Debug + Send + Sync { ...@@ -42,8 +42,7 @@ pub trait ActionBuilder: std::fmt::Debug + Send + Sync {
fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity); fn build(&self, cmd: &mut Commands, action: Entity, actor: Entity);
fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity { fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity {
let action_ent = ActionEnt(cmd.spawn().id()); let action_ent = ActionEnt(cmd.spawn().id());
cmd.entity(action_ent.0).insert(ActionState::new()); cmd.entity(action_ent.0).insert(ActionState::new()).insert(Actor(actor));
cmd.entity(actor).push_children(&[action_ent.0]);
self.build(cmd, action_ent.0, actor); self.build(cmd, action_ent.0, actor);
action_ent.0 action_ent.0
} }
...@@ -68,7 +67,7 @@ impl ActionBuilder for StepsBuilder { ...@@ -68,7 +67,7 @@ impl ActionBuilder for StepsBuilder {
active_step: 0, active_step: 0,
active_ent: ActionEnt(child_action), active_ent: ActionEnt(child_action),
steps: self.steps.clone(), steps: self.steps.clone(),
}); }).push_children(&[child_action]);
} }
} }
#[derive(Debug)] #[derive(Debug)]
...@@ -86,11 +85,11 @@ impl Steps { ...@@ -86,11 +85,11 @@ impl Steps {
pub fn steps_system( pub fn steps_system(
mut cmd: Commands, mut cmd: Commands,
mut steps_q: Query<(Entity, &Parent, &mut Steps)>, mut steps_q: Query<(Entity, &Actor, &mut Steps)>,
mut states: Query<&mut ActionState>, mut states: Query<&mut ActionState>,
) { ) {
use ActionState::*; use ActionState::*;
for (seq_ent, Parent(actor), mut steps_action) in steps_q.iter_mut() { for (seq_ent, Actor(actor), mut steps_action) in steps_q.iter_mut() {
let current_state = states.get_mut(seq_ent).expect("uh oh").clone(); let current_state = states.get_mut(seq_ent).expect("uh oh").clone();
match current_state { match current_state {
Requested => { Requested => {
...@@ -131,6 +130,7 @@ pub fn steps_system( ...@@ -131,6 +130,7 @@ pub fn steps_system(
steps_action.active_step += 1; steps_action.active_step += 1;
let step_builder = steps_action.steps[steps_action.active_step].clone(); let step_builder = steps_action.steps[steps_action.active_step].clone();
let step_ent = step_builder.attach(&mut cmd, *actor); let step_ent = step_builder.attach(&mut cmd, *actor);
cmd.entity(seq_ent).push_children(&[step_ent]);
let mut step_state = states.get_mut(step_ent).expect("oops"); let mut step_state = states.get_mut(step_ent).expect("oops");
*step_state = ActionState::Requested; *step_state = ActionState::Requested;
} }
......
...@@ -36,7 +36,9 @@ impl ChoiceBuilder { ...@@ -36,7 +36,9 @@ impl ChoiceBuilder {
} }
} }
pub fn build(&self, cmd: &mut Commands, actor: Entity) -> Choice { pub fn build(&self, cmd: &mut Commands, actor: Entity, parent: Entity) -> Choice {
let scorer_ent = self.when.attach(cmd, actor);
cmd.entity(parent).push_children(&[scorer_ent]);
Choice { Choice {
scorer: ScorerEnt(self.when.attach(cmd, actor)), scorer: ScorerEnt(self.when.attach(cmd, actor)),
action: ActionBuilderWrapper::new(self.then.clone()), action: ActionBuilderWrapper::new(self.then.clone()),
......
...@@ -2,7 +2,7 @@ use std::sync::Arc; ...@@ -2,7 +2,7 @@ use std::sync::Arc;
use bevy::prelude::*; use bevy::prelude::*;
use crate::ScorerEnt; use crate::{Actor, ScorerEnt};
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct Score(pub(crate) f32); pub struct Score(pub(crate) f32);
...@@ -23,8 +23,9 @@ pub trait ScorerBuilder: std::fmt::Debug + Sync + Send { ...@@ -23,8 +23,9 @@ pub trait ScorerBuilder: std::fmt::Debug + Sync + Send {
fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity); fn build(&self, cmd: &mut Commands, scorer: Entity, actor: Entity);
fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity { fn attach(&self, cmd: &mut Commands, actor: Entity) -> Entity {
let scorer_ent = cmd.spawn().id(); let scorer_ent = cmd.spawn().id();
cmd.entity(scorer_ent).insert(Score::default()); cmd.entity(scorer_ent)
cmd.entity(actor).push_children(&[scorer_ent]); .insert(Score::default())
.insert(Actor(actor));
self.build(cmd, scorer_ent, actor); self.build(cmd, scorer_ent, actor);
scorer_ent scorer_ent
} }
...@@ -114,6 +115,7 @@ impl ScorerBuilder for AllOrNothingBuilder { ...@@ -114,6 +115,7 @@ impl ScorerBuilder for AllOrNothingBuilder {
.collect(); .collect();
cmd.entity(scorer) cmd.entity(scorer)
.insert(Score::default()) .insert(Score::default())
.push_children(&scorers[..])
.insert(super::AllOrNothing { .insert(super::AllOrNothing {
threshold: self.threshold, threshold: self.threshold,
scorers: scorers.into_iter().map(ScorerEnt).collect(), scorers: scorers.into_iter().map(ScorerEnt).collect(),
......
...@@ -12,6 +12,9 @@ use crate::{ ...@@ -12,6 +12,9 @@ use crate::{
scorers::{Score, ScorerBuilder}, scorers::{Score, ScorerBuilder},
}; };
#[derive(Debug, Clone, Copy)]
pub struct Actor(pub Entity);
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ActionEnt(pub Entity); pub struct ActionEnt(pub Entity);
...@@ -74,7 +77,7 @@ impl ActionBuilder for ThinkerBuilder { ...@@ -74,7 +77,7 @@ impl ActionBuilder for ThinkerBuilder {
let choices = self let choices = self
.choices .choices
.iter() .iter()
.map(|choice| choice.build(cmd, actor)) .map(|choice| choice.build(cmd, actor, action_ent))
.collect(); .collect();
cmd.entity(action_ent) cmd.entity(action_ent)
.insert(Thinker { .insert(Thinker {
...@@ -116,12 +119,12 @@ impl Default for ThinkerIterations { ...@@ -116,12 +119,12 @@ impl Default for ThinkerIterations {
pub fn thinker_system( pub fn thinker_system(
mut cmd: Commands, mut cmd: Commands,
mut iterations: Local<ThinkerIterations>, mut iterations: Local<ThinkerIterations>,
mut thinker_q: Query<(Entity, &Parent, &mut Thinker, &ActiveThinker)>, mut thinker_q: Query<(Entity, &Actor, &mut Thinker, &ActiveThinker)>,
utilities: Query<&Score>, utilities: Query<&Score>,
mut action_states: Query<&mut actions::ActionState>, mut action_states: Query<&mut actions::ActionState>,
) { ) {
let start = Instant::now(); let start = Instant::now();
for (thinker_ent, Parent(actor), mut thinker, active_thinker) in for (thinker_ent, Actor(actor), mut thinker, active_thinker) in
thinker_q.iter_mut().skip(iterations.index) thinker_q.iter_mut().skip(iterations.index)
{ {
iterations.index += 1; iterations.index += 1;
...@@ -189,7 +192,7 @@ pub fn thinker_system( ...@@ -189,7 +192,7 @@ pub fn thinker_system(
actions::ActionState::Init actions::ActionState::Init
| actions::ActionState::Success | actions::ActionState::Success
| actions::ActionState::Failure => { | actions::ActionState::Failure => {
cmd.entity(current.0 .0).despawn_recursive(); cmd.entity(current.0.0).despawn_recursive();
thinker.current_action = None; thinker.current_action = None;
} }
_ => { _ => {
......
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