From a6d7653650b61aa002fccf449e7a517b30c4c0d8 Mon Sep 17 00:00:00 2001 From: andriyDev Date: Sat, 11 Jan 2025 22:38:40 -0800 Subject: [PATCH] Make `State` pub(crate). Users shouldn't be messing with the internal state of the behavior tree. That could result in the behavior tree producing all sorts of strange behavior. --- bonsai/src/bt.rs | 10 +- bonsai/src/lib.rs | 2 +- bonsai/src/sequence.rs | 2 +- bonsai/src/state.rs | 2 +- bonsai/src/visualizer.rs | 2 +- bonsai/src/when_all.rs | 2 +- bonsai/tests/behavior_tests.rs | 150 ++++++++++++------------- bonsai/tests/dynamic_behavior_tests.rs | 50 ++++----- 8 files changed, 101 insertions(+), 119 deletions(-) diff --git a/bonsai/src/bt.rs b/bonsai/src/bt.rs index 9e7f04b..f72ea3e 100644 --- a/bonsai/src/bt.rs +++ b/bonsai/src/bt.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; use crate::visualizer::NodeType; -use crate::{ActionArgs, Behavior, State, Status, UpdateEvent}; +use crate::{state::State, ActionArgs, Behavior, Status, UpdateEvent}; use petgraph::dot::{Config, Dot}; use petgraph::Graph; @@ -32,7 +32,7 @@ impl BlackBoard { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BT { /// constructed behavior tree - pub state: State, + state: State, /// keep the initial state initial_behavior: Behavior, /// blackboard @@ -78,12 +78,6 @@ impl BT { &mut self.bb } - /// Retrieve a mutable reference to the internal state - /// of the Behavior Tree - pub fn get_state(bt: &mut BT) -> &mut State { - &mut bt.state - } - /// The behavior tree is a stateful data structure in which the immediate /// state of the BT is allocated and updated in heap memory through the lifetime /// of the BT. The state of the BT is said to be `transient` meaning upon entering diff --git a/bonsai/src/lib.rs b/bonsai/src/lib.rs index 1e710af..933bedc 100644 --- a/bonsai/src/lib.rs +++ b/bonsai/src/lib.rs @@ -125,7 +125,7 @@ pub use behavior::Behavior::{ pub use bt::BT; pub use event::{Event, Timer, UpdateArgs, UpdateEvent}; -pub use state::{ActionArgs, State, RUNNING}; +pub use state::{ActionArgs, RUNNING}; pub use status::Status::{self, Failure, Running, Success}; mod behavior; diff --git a/bonsai/src/sequence.rs b/bonsai/src/sequence.rs index e51f697..15e3139 100644 --- a/bonsai/src/sequence.rs +++ b/bonsai/src/sequence.rs @@ -1,5 +1,5 @@ use crate::status::Status::*; -use crate::{event::UpdateEvent, ActionArgs, Behavior, State, Status, RUNNING}; +use crate::{event::UpdateEvent, state::State, ActionArgs, Behavior, Status, RUNNING}; pub struct SequenceArgs<'a, A, E, F, B> { pub select: bool, diff --git a/bonsai/src/state.rs b/bonsai/src/state.rs index 9886477..57157d0 100644 --- a/bonsai/src/state.rs +++ b/bonsai/src/state.rs @@ -28,7 +28,7 @@ pub struct ActionArgs<'a, E: 'a, A: 'a> { /// Keeps track of a behavior. #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub enum State { +pub(crate) enum State { /// Executes an action. ActionState(A), /// Converts `Success` into `Failure` and vice versa. diff --git a/bonsai/src/visualizer.rs b/bonsai/src/visualizer.rs index 0c267ef..96c9e91 100644 --- a/bonsai/src/visualizer.rs +++ b/bonsai/src/visualizer.rs @@ -1,5 +1,5 @@ #![allow(dead_code, unused_imports, unused_variables)] -use crate::{Behavior, Select, Sequence, State, BT}; +use crate::{state::State, Behavior, Select, Sequence, BT}; use petgraph::{graph::Graph, stable_graph::NodeIndex, Direction::Outgoing}; use std::{collections::VecDeque, fmt::Debug}; diff --git a/bonsai/src/when_all.rs b/bonsai/src/when_all.rs index 3e3954f..8a1df76 100644 --- a/bonsai/src/when_all.rs +++ b/bonsai/src/when_all.rs @@ -1,5 +1,5 @@ use crate::status::Status::*; -use crate::{event::UpdateEvent, ActionArgs, State, Status, RUNNING}; +use crate::{event::UpdateEvent, state::State, ActionArgs, Status, RUNNING}; // `WhenAll` and `WhenAny` share same algorithm. // diff --git a/bonsai/tests/behavior_tests.rs b/bonsai/tests/behavior_tests.rs index 543e14e..c685f45 100644 --- a/bonsai/tests/behavior_tests.rs +++ b/bonsai/tests/behavior_tests.rs @@ -1,7 +1,7 @@ use crate::behavior_tests::TestActions::{Dec, Inc, LessThan, LessThanRunningSuccess}; use bonsai_bt::{ - Action, ActionArgs, After, AlwaysSucceed, Event, Failure, If, Invert, Select, Sequence, State, Status::Running, - Success, UpdateArgs, Wait, WaitForever, WhenAll, While, WhileAll, + Action, ActionArgs, After, AlwaysSucceed, Event, Failure, If, Invert, Select, Sequence, Status::Running, Success, + UpdateArgs, Wait, WaitForever, WhenAll, While, WhileAll, BT, }; /// Some test actions. @@ -18,67 +18,59 @@ enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: i32, dt: f64, state: &mut State) -> (i32, bonsai_bt::Status, f64) { +fn tick(mut acc: i32, dt: f64, state: &mut BT) -> (i32, bonsai_bt::Status, f64) { let e: Event = UpdateArgs { dt }.into(); println!("acc {}", acc); - let (s, t) = state.tick( - &e, - &mut (), - &mut |args: ActionArgs, _| match *args.action { - Inc => { - acc += 1; + let (s, t) = state.tick(&e, &mut |args: ActionArgs, _| match *args.action { + Inc => { + acc += 1; + (Success, args.dt) + } + Dec => { + acc -= 1; + (Success, args.dt) + } + LessThan(v) => { + println!("inside less than with acc: {}", acc); + if acc < v { + println!("success {}<{}", acc, v); (Success, args.dt) + } else { + println!("failure {}>={}", acc, v); + (Failure, args.dt) } - Dec => { - acc -= 1; + } + TestActions::LessThanRunningSuccess(v) => { + println!("inside LessThanRunningSuccess with acc: {}", acc); + if acc < v { + println!("success {}<{}", acc, v); + (Running, args.dt) + } else { + println!("failure {}>={}", acc, v); (Success, args.dt) } - LessThan(v) => { - println!("inside less than with acc: {}", acc); - if acc < v { - println!("success {}<{}", acc, v); - (Success, args.dt) - } else { - println!("failure {}>={}", acc, v); - (Failure, args.dt) - } - } - TestActions::LessThanRunningSuccess(v) => { - println!("inside LessThanRunningSuccess with acc: {}", acc); - if acc < v { - println!("success {}<{}", acc, v); - (Running, args.dt) - } else { - println!("failure {}>={}", acc, v); - (Success, args.dt) - } - } - }, - ); + } + }); println!("status: {:?} dt: {}", s, t); (acc, s, t) } // A test state machine that can increment and decrement. -fn tick_with_ref(acc: &mut i32, dt: f64, state: &mut State) { +fn tick_with_ref(acc: &mut i32, dt: f64, state: &mut BT) { let e: Event = UpdateArgs { dt }.into(); - state.tick( - &e, - &mut (), - &mut |args: ActionArgs, _| match *args.action { - Inc => { - *acc += 1; - (Success, args.dt) - } - Dec => { - *acc -= 1; - (Success, args.dt) - } - TestActions::LessThanRunningSuccess(_) | LessThan(_) => todo!(), - }, - ); + state.tick(&e, &mut |args: ActionArgs, _| match *args.action { + Inc => { + *acc += 1; + (Success, args.dt) + } + Dec => { + *acc -= 1; + (Success, args.dt) + } + TestActions::LessThanRunningSuccess(_) | LessThan(_) => todo!(), + }); } // Each action that terminates immediately @@ -90,7 +82,7 @@ fn test_immediate_termination() { let mut a: i32 = 0; let seq = Sequence(vec![Action(Inc), Action(Inc)]); - let mut state = State::new(seq); + let mut state = BT::new(seq, ()); tick_with_ref(&mut a, 0.0, &mut state); assert_eq!(a, 2); tick_with_ref(&mut a, 1.0, &mut state); @@ -107,7 +99,7 @@ fn while_wait_sequence_twice() { Box::new(Wait(2.001)), vec![Sequence(vec![Wait(0.5), Action(Inc), Wait(0.5), Action(Inc)])], ); - let mut state = State::new(w); + let mut state = BT::new(w, ()); tick_with_ref(&mut a, 1.0, &mut state); assert_eq!(a, 2); tick_with_ref(&mut a, 1.0, &mut state); @@ -123,7 +115,7 @@ fn while_wait_sequence_twice() { fn wait_sec() { let a: i32 = 0; let seq = Sequence(vec![Wait(1.0), Action(Inc)]); - let mut state = State::new(seq); + let mut state = BT::new(seq, ()); let (a, _, _) = tick(a, 1.0, &mut state); assert_eq!(a, 1); } @@ -134,7 +126,7 @@ fn wait_sec() { fn wait_half_sec() { let a: i32 = 0; let seq = Sequence(vec![Wait(1.0), Action(Inc)]); - let mut state = State::new(seq); + let mut state = BT::new(seq, ()); let (a, _, _) = tick(a, 0.5, &mut state); assert_eq!(a, 0); let (a, _, _) = tick(a, 0.5, &mut state); @@ -146,7 +138,7 @@ fn wait_half_sec() { fn sequence_of_one_event() { let a: i32 = 0; let seq = Sequence(vec![Action(Inc)]); - let mut state = State::new(seq); + let mut state = BT::new(seq, ()); let (a, _, _) = tick(a, 1.0, &mut state); assert_eq!(a, 1); } @@ -156,7 +148,7 @@ fn sequence_of_one_event() { fn wait_two_waits() { let a: i32 = 0; let seq = Sequence(vec![Wait(0.5), Wait(0.5), Action(Inc)]); - let mut state = State::new(seq); + let mut state = BT::new(seq, ()); let (a, _, _) = tick(a, 1.0, &mut state); assert_eq!(a, 1); } @@ -166,7 +158,7 @@ fn wait_two_waits() { fn loop_ten_times() { let a: i32 = 0; let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]); - let mut state = State::new(rep); + let mut state = BT::new(rep, ()); // sample after 10 seconds let (a, _, _) = tick(a, 10.0, &mut state); @@ -181,7 +173,7 @@ fn when_all_wait() { WhenAll(vec![Wait(0.5), Wait(1.0)]), Action(Inc), ]); - let mut state = State::new(all); + let mut state = BT::new(all, ()); let (a, _, _) = tick(a, 0.5, &mut state); assert_eq!(a, 0); let (a, _, _) = tick(a, 0.5, &mut state); @@ -195,7 +187,7 @@ fn while_wait_sequence() { Box::new(Wait(9.999999)), vec![Sequence(vec![Wait(0.5), Action(Inc), Wait(0.5), Action(Inc)])], ); - let mut state = State::new(w); + let mut state = BT::new(w, ()); for _ in 0..100 { (a, _, _) = tick(a, 0.1, &mut state); } @@ -207,7 +199,7 @@ fn while_wait_sequence() { fn while_wait_forever_sequence() { let mut a: i32 = 0; let w = While(Box::new(WaitForever), vec![Sequence(vec![Action(Inc), Wait(1.0)])]); - let mut state = State::new(w); + let mut state = BT::new(w, ()); (a, _, _) = tick(a, 1.001, &mut state); assert_eq!(a, 2); } @@ -221,7 +213,7 @@ fn test_if_less_than() { Box::new(Action(Dec)), // else ); - let mut state = State::new(_if); + let mut state = BT::new(_if, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 2); @@ -248,7 +240,7 @@ fn when_all_if() { let _while = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]); let w = WhenAll(vec![_if, _while]); - let mut state = State::new(w); + let mut state = BT::new(w, ()); // sample state after 8 seconds let (a, _, _) = tick(a, 8.0, &mut state); @@ -263,7 +255,7 @@ fn when_all_if() { fn test_alter_wait_time() { let a: i32 = 0; let rep = While(Box::new(Wait(50.0)), vec![Wait(0.5), Action(Inc), Wait(0.5)]); - let mut state = State::new(rep); + let mut state = BT::new(rep, ()); // sample after 10 seconds let (a, _, _) = tick(a, 10.0, &mut state); @@ -274,7 +266,7 @@ fn test_alter_wait_time() { fn test_select_succeed_on_first() { let a: i32 = 0; let sel = Select(vec![Action(Inc), Action(Inc), Action(Inc)]); - let mut state = State::new(sel); + let mut state = BT::new(sel, ()); let (a, _, _) = tick(a, 0.1, &mut state); assert_eq!(a, 1); @@ -286,7 +278,7 @@ fn test_select_succeed_on_first() { fn test_select_no_state_reset() { let a: i32 = 3; let sel = Select(vec![Action(LessThan(1)), Action(Dec), Action(Inc)]); - let mut state = State::new(sel); + let mut state = BT::new(sel, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 2); @@ -307,7 +299,7 @@ fn test_select_with_state_reset() { let a: i32 = 3; let sel = Select(vec![Action(LessThan(1)), Action(Dec), Action(Inc)]); let sel_clone = sel.clone(); - let mut state = State::new(sel); + let mut state = BT::new(sel, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 2); @@ -320,7 +312,7 @@ fn test_select_with_state_reset() { assert_eq!(s, Success); // reset state - state = State::new(sel_clone); + state = BT::new(sel_clone, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 0); @@ -332,7 +324,7 @@ fn test_select_and_when_all() { let a: i32 = 3; let sel = Select(vec![Action(LessThan(1)), Action(Dec), Action(Inc)]); let whenall = WhenAll(vec![Wait(0.35), sel]); - let mut state = State::new(whenall); + let mut state = BT::new(whenall, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 2); @@ -347,7 +339,7 @@ fn test_select_and_invert() { let a: i32 = 3; let sel = Invert(Box::new(Select(vec![Action(LessThan(1)), Action(Dec), Action(Inc)]))); let whenall = WhenAll(vec![Wait(0.35), sel]); - let mut state = State::new(whenall); + let mut state = BT::new(whenall, ()); // Running + Failure = Failure let (a, s, _) = tick(a, 0.1, &mut state); @@ -375,7 +367,7 @@ fn test_allways_succeed() { Wait(0.5), ]); let behavior = AlwaysSucceed(Box::new(sel)); - let mut state = State::new(behavior); + let mut state = BT::new(behavior, ()); let (a, s, _) = tick(a, 0.1, &mut state); assert_eq!(a, 3); @@ -395,7 +387,7 @@ fn test_allways_succeed() { fn test_after_all_succeed_in_order() { let a: i32 = 0; let after = After(vec![Action(Inc), Wait(0.1), Wait(0.2)]); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let (a, s, dt) = tick(a, 0.1, &mut state); @@ -414,7 +406,7 @@ fn test_after_all_succeed_in_order() { fn test_after_all_succeed_out_of_order() { let a: i32 = 0; let after = After(vec![Action(Inc), Wait(0.2), Wait(0.1)]); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let (a, s, dt) = tick(a, 0.05, &mut state); @@ -435,7 +427,7 @@ fn test_repeat_sequence() { let a: i32 = 0; let after = WhileAll(Box::new(Action(LessThanRunningSuccess(5))), vec![Action(Inc)]); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let (a, s, dt) = tick(a, 0.0, &mut state); @@ -459,7 +451,7 @@ fn test_repeat_sequence_double_running() { Action(LessThan(0)), // failure ], ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let mut current_value = 0; loop { @@ -489,7 +481,7 @@ fn test_repeat_sequence2() { Action(Dec), // success... 2 ], ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let mut current_value = 0; let mut current_status; @@ -523,7 +515,7 @@ fn test_repeat_sequence3() { Action(Dec), ], ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let mut current_value = 0; let mut current_status; @@ -559,7 +551,7 @@ fn test_repeat_sequence_nested() { dec2, // -2 ], // == 3 ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let mut current_value = 0; let mut current_status; @@ -586,7 +578,7 @@ fn test_repeat_sequence_fail() { Box::new(Action(LessThanRunningSuccess(5))), vec![Action(Dec), Action(LessThan(0))], ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); let (a, s, dt) = tick(a, 0.0, &mut state); assert_eq!(a, 3); assert_eq!(s, Failure); @@ -603,7 +595,7 @@ fn test_repeat_sequence_timed() { Box::new(Action(LessThanRunningSuccess(steps))), vec![Wait(time_step), Action(Inc)], ); - let mut state = State::new(after); + let mut state = BT::new(after, ()); // increment 3 times let (a, s, dt) = tick(a, time_step * 3.0, &mut state); @@ -622,5 +614,5 @@ fn test_repeat_sequence_timed() { fn test_repeat_sequence_empty() { let after = WhileAll(Box::new(Action(LessThanRunningSuccess(0))), vec![]); // panics because no behaviors... - let _state = State::new(after); + let _state = BT::new(after, ()); } diff --git a/bonsai/tests/dynamic_behavior_tests.rs b/bonsai/tests/dynamic_behavior_tests.rs index 4c77bee..f682ee7 100644 --- a/bonsai/tests/dynamic_behavior_tests.rs +++ b/bonsai/tests/dynamic_behavior_tests.rs @@ -1,5 +1,5 @@ use crate::dynamic_behavior_tests::TestActions::{DynamicWait, Inc}; -use bonsai_bt::{Action, ActionArgs, Event, State, Success, UpdateArgs, Wait, While, RUNNING}; +use bonsai_bt::{Action, ActionArgs, Event, Success, UpdateArgs, Wait, While, BT, RUNNING}; type Times = Vec; /// Some test actions. @@ -12,37 +12,33 @@ enum TestActions { } // A test state machine that can increment and decrement. -fn tick(mut acc: usize, dt: f64, t: &mut f64, counter: &mut usize, state: &mut State) -> usize { +fn tick(mut acc: usize, dt: f64, t: &mut f64, counter: &mut usize, state: &mut BT) -> usize { let e: Event = UpdateArgs { dt }.into(); - let (_s, _t) = state.tick( - &e, - &mut (), - &mut |args: ActionArgs, _| match args.action { - Inc => { - acc += 1; - (Success, args.dt) + let (_s, _t) = state.tick(&e, &mut |args: ActionArgs, _| match args.action { + Inc => { + acc += 1; + (Success, args.dt) + } + DynamicWait(times) => { + // reset dynamic timer + if *counter >= times.len() { + *counter = 0 } - DynamicWait(times) => { - // reset dynamic timer - if *counter >= times.len() { - *counter = 0 - } - let wait_t = times[counter.to_owned()]; + let wait_t = times[counter.to_owned()]; - if *t + dt >= wait_t { - let time_overdue = *t + dt - wait_t; - *counter += 1; - *t = -dt; - (Success, time_overdue) - } else { - *t += dt; - RUNNING - } + if *t + dt >= wait_t { + let time_overdue = *t + dt - wait_t; + *counter += 1; + *t = -dt; + (Success, time_overdue) + } else { + *t += dt; + RUNNING } - }, - ); + } + }); acc } @@ -56,7 +52,7 @@ fn test_alter_wait_time() { Box::new(Wait(50.0)), vec![Action(DynamicWait(vec![1.0, 2.0, 3.0])), Action(Inc)], ); - let mut state = State::new(rep); + let mut state = BT::new(rep, ()); // time passed=1.0 let a = tick(a, 1.0, &mut timer, &mut counter, &mut state);