use crate::prelude::*;
pub trait StatefulAction<T> {
fn tick(&mut self, data: &mut T) -> Status;
fn reset(&mut self);
}
pub struct BehaviorTree<T> {
pub tree: Node<T>,
pub debug: TreeRepr,
}
pub enum Behavior<T> {
Wait {
curr: f64,
max: f64,
},
Cond(
String,
fn(&T) -> bool,
Box<Node<T>>,
Box<Node<T>>,
),
Sequence(usize, Vec<Node<T>>),
Select(usize, Vec<Node<T>>),
Action(String, fn(&mut T) -> Status),
ActionSuccess(String, fn(&mut T) -> ()),
StatefulAction(String, Box<dyn StatefulAction<T>>),
While(fn(&T) -> bool, Box<Node<T>>),
}
fn sequence<T>(
delta: f64,
context: &mut T,
is_sequence: bool,
current: &mut usize,
xs: &mut Vec<Node<T>>,
) -> (Status, DebugRepr) {
let (status_positive, status_negative) = if is_sequence {
(Status::Success, Status::Failure)
} else {
(Status::Failure, Status::Success)
};
let mut repr_string = String::new();
let mut status = status_positive;
let mut child_repr = None;
let len = xs.len();
if *current == len {
*current = 0;
}
while *current < len {
let x = &mut xs[*current];
if x.status == Status::Success || x.status == Status::Failure {
x.behavior.reset();
}
let (res, repr) = x.tick(delta, context);
if res == status_positive {
*current += 1;
repr_string += "+";
child_repr = Some(repr);
} else if res == status_negative {
status = status_negative;
repr_string += "-";
child_repr = Some(repr);
break;
} else {
status = Status::Running;
repr_string += ".";
child_repr = Some(repr);
break;
}
}
let mut repr = DebugRepr::new(
"Sequence",
Cursor::Index(
*current,
Box::new(child_repr.expect("Sequence must have a child repr since it's non-empty")),
),
status,
);
repr.params = Some(repr_string);
(status, repr)
}
impl<T> Behavior<T> {
pub fn tick(&mut self, delta: f64, context: &mut T) -> (Status, DebugRepr) {
let _status = match self {
Behavior::Wait {
ref mut curr,
max: _,
} => {
*curr -= delta;
let status = if *curr <= 0.0 {
trace!("timer reset");
Status::Success
} else {
Status::Running
};
return (status, DebugRepr::new("Wait", Cursor::Leaf, status));
}
Behavior::Cond(s, cond, a, b) => {
let c = cond(context);
let (status, child_repr) = if c {
a.tick(delta, context)
} else {
b.tick(delta, context)
};
let mut repr = DebugRepr::new(
"If",
Cursor::Index(if c { 0 } else { 1 }, Box::new(child_repr)),
status,
)
.with_override(c);
repr.params = Some(format!("true? = {:?} ... str = {:?}", c, s));
return (status, repr);
}
Behavior::Sequence(ref mut current, xs) => {
return sequence(delta, context, true, current, xs)
}
Behavior::Select(ref mut current, xs) => {
return sequence(delta, context, false, current, xs)
}
Behavior::Action(name, action) => {
let status = action(context);
return (status, DebugRepr::new(name, Cursor::Leaf, status));
}
Behavior::ActionSuccess(name, action) => {
let _ = action(context);
return (
Status::Success,
DebugRepr::new(name, Cursor::Leaf, Status::Success),
);
}
Behavior::StatefulAction(name, action) => {
let status = action.tick(context);
return (status, DebugRepr::new(name, Cursor::Leaf, status));
}
Behavior::While(cond, behavior) => {
if cond(context) {
return behavior.tick(delta, context);
} else {
let status = Status::Failure;
return (status, DebugRepr::new("while", Cursor::Leaf, status));
}
}
};
}
pub fn reset(&mut self) {
match self {
Behavior::Wait { ref mut curr, max } => {
*curr = *max;
}
Behavior::Sequence(ref mut idx, _) => {
*idx = 0;
}
Behavior::StatefulAction(_name, ref mut state) => {
state.reset();
}
_ => {}
}
}
}
impl<T> core::fmt::Debug for Behavior<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Behavior::Wait{curr, max} => {
f.debug_struct("Wait").field("current", curr).field("max", max);
}
Behavior::Action(name, _fn) => {
f.debug_struct("Action").field("name", name);
}
_ => {}
};
Ok(())
}
}