use crate::{
self as behaviortree, BehaviorDescription, BehaviorKind, BehaviorTreeFactory, Control,
behavior::{Behavior, BehaviorCreationFn, BehaviorData, BehaviorError, BehaviorResult, BehaviorState},
tree::BehaviorTreeElementList,
};
use alloc::boxed::Box;
use tinyscript::SharedRuntime;
#[derive(Control, Debug, Default)]
#[behavior(groot2, no_create, no_register, no_register_with)]
pub struct Sequence {
child_idx: usize,
skipped: usize,
#[behavior(parameter)]
asynch: bool,
}
#[async_trait::async_trait]
impl Behavior for Sequence {
#[inline]
fn on_halt(&mut self) -> Result<(), BehaviorError> {
self.child_idx = 0;
self.skipped = 0;
Ok(())
}
async fn tick(
&mut self,
behavior: &mut BehaviorData,
children: &mut BehaviorTreeElementList,
runtime: &SharedRuntime,
) -> BehaviorResult {
if !behavior.is_active() {
self.skipped = 0;
}
behavior.set_state(BehaviorState::Running);
let children_count = children.len();
while self.child_idx < children_count {
let child = &mut children[self.child_idx];
let prev_state = child.state();
let child_state = child.tick(runtime).await?;
match child_state {
BehaviorState::Failure => {
children.reset(runtime)?;
self.child_idx = 0;
return Ok(child_state);
}
BehaviorState::Idle => {
return Err(BehaviorError::State {
behavior: "Sequence".into(),
state: child_state,
});
}
BehaviorState::Running => return Ok(child_state),
BehaviorState::Skipped => {
self.child_idx += 1;
self.skipped += 1;
}
BehaviorState::Success => {
self.child_idx += 1;
if self.asynch && (prev_state == BehaviorState::Idle) && (self.child_idx < children_count) {
return Ok(BehaviorState::Running);
}
}
}
}
let all_skipped = self.skipped == children_count;
if self.child_idx >= children_count {
children.reset(runtime)?;
self.child_idx = 0;
self.skipped = 0;
}
if all_skipped {
Ok(BehaviorState::Skipped)
} else {
Ok(BehaviorState::Success)
}
}
}
impl Sequence {
#[must_use]
pub const fn new(asynch: bool) -> Self {
Self {
child_idx: 0,
skipped: 0,
asynch,
}
}
#[must_use]
pub fn create_fn(asynch: bool) -> Box<BehaviorCreationFn> {
Box::new(move || {
Box::new(Self {
child_idx: 0,
skipped: 0,
asynch,
})
})
}
pub fn register_with(
factory: &mut BehaviorTreeFactory,
name: &str,
asynch: bool,
) -> Result<(), crate::factory::error::Error> {
let bhvr_desc = BehaviorDescription::new(name, name, BehaviorKind::Control, true, Self::provided_ports());
let bhvr_creation_fn = Self::create_fn(asynch);
factory
.registry_mut()
.add_behavior(bhvr_desc, bhvr_creation_fn)
}
}