pub mod composite;
use std::sync::Arc;
#[derive(Debug)]
pub enum NodeResult<B> {
Running(BehaviorArc<B>),
Success,
Failure,
}
pub type BehaviorArc<B> = Arc<dyn BehaviorNode<B>>;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ReportStatus {
#[default]
Unexecuted,
Running,
Success,
Failure,
}
impl ReportStatus {
pub fn unexecuted_or(self, other: ReportStatus) -> ReportStatus {
if self == ReportStatus::Unexecuted {
ReportStatus::Unexecuted
} else {
other
}
}
pub fn unexecuted_or_else(self, other: impl FnOnce() -> ReportStatus) -> ReportStatus {
if self == ReportStatus::Unexecuted {
ReportStatus::Unexecuted
} else {
(other)()
}
}
}
#[derive(Debug)]
pub struct BehaviorStatus {
pub name: Box<str>,
pub status: ReportStatus,
pub children: Vec<BehaviorStatus>,
pub current: Option<usize>,
}
pub trait BehaviorNode<B>: std::fmt::Debug + Send + Sync {
fn tick(self: Arc<Self>, context: &mut B) -> NodeResult<B>;
fn arc(self) -> BehaviorArc<B>
where
Self: Sized + Send + Sync + 'static,
{
Arc::new(self)
}
fn status(&self, parent: ReportStatus, context: &B) -> BehaviorStatus {
let _ = context;
BehaviorStatus {
name: std::any::type_name_of_val(self).into(),
status: parent,
children: vec![],
current: None,
}
}
}
#[derive(Debug)]
pub struct BehaviorRunner<B> {
tree: BehaviorArc<B>,
current_tick: Option<BehaviorArc<B>>,
}
impl<B> BehaviorRunner<B> {
pub fn new(tree: BehaviorArc<B>) -> Self {
Self {
tree,
current_tick: None,
}
}
pub fn from_node<N>(node: N) -> Self
where
N: BehaviorNode<B> + 'static,
{
Self {
tree: Arc::new(node),
current_tick: None,
}
}
pub fn into_inner(self) -> BehaviorArc<B> {
self.current_tick.unwrap_or(self.tree)
}
pub fn is_running(&self) -> bool {
self.current_tick.is_some()
}
pub fn reset(&mut self) {
self.current_tick.take();
}
pub fn status(&self, context: &B) -> BehaviorStatus {
if let Some(bp) = self.current_tick.as_ref() {
bp.status(ReportStatus::Running, context)
} else {
self.tree.status(ReportStatus::Unexecuted, context)
}
}
fn tick_node(&mut self, node: Arc<dyn BehaviorNode<B>>, context: &mut B) -> Option<bool> {
match node.tick(context) {
NodeResult::Running(nbp) => {
self.current_tick = Some(nbp);
None
}
NodeResult::Success => Some(true),
NodeResult::Failure => Some(false),
}
}
pub fn proceed(&mut self, context: &mut B) -> Option<bool> {
if let Some(bp) = self.current_tick.take() {
self.tick_node(bp, context)
} else {
let node = self.tree.clone();
self.tick_node(node, context)
}
}
}