mecha10_behavior_runtime/
behavior.rs1use crate::NodeStatus;
6use async_trait::async_trait;
7use mecha10_core::Context;
8use std::fmt::Debug;
9
10#[async_trait]
11pub trait BehaviorNode: Send + Sync + Debug {
12 async fn tick(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus>;
15
16 fn name(&self) -> &str {
20 std::any::type_name::<Self>()
21 }
22
23 fn children_mut(&mut self) -> Vec<&mut dyn BehaviorNode> {
27 Vec::new()
28 }
29
30 fn active_capability(&self) -> Option<&str> {
34 None
35 }
36
37 fn reset_self(&mut self) {}
41
42 async fn reset(&mut self) -> anyhow::Result<()> {
46 self.reset_self();
47 for child in self.children_mut() {
48 child.reset().await?;
49 }
50 Ok(())
51 }
52
53 async fn on_init(&mut self, ctx: &Context) -> anyhow::Result<()> {
57 for child in self.children_mut() {
58 child.on_init(ctx).await?;
59 }
60 Ok(())
61 }
62
63 async fn on_terminate(&mut self, ctx: &Context) -> anyhow::Result<()> {
67 for child in self.children_mut() {
68 child.on_terminate(ctx).await?;
69 }
70 Ok(())
71 }
72}
73
74pub type BoxedBehavior = Box<dyn BehaviorNode>;
75
76pub fn boxed_children_mut<'a>(children: impl Iterator<Item = &'a mut BoxedBehavior>) -> Vec<&'a mut dyn BehaviorNode> {
79 children.map(|c| c.as_mut() as &mut dyn BehaviorNode).collect()
80}
81
82#[macro_export]
83macro_rules! children_mut_via_wrapped_behavior {
84 ($field:ident, $wrapper:ident) => {
85 fn children_mut(&mut self) -> Vec<&mut dyn $crate::BehaviorNode> {
86 $crate::boxed_children_mut(self.$field.iter_mut().map(|$wrapper| &mut $wrapper.behavior))
87 }
88 };
89}
90
91#[macro_export]
92macro_rules! reset_child_statuses_field {
93 ($field:ident) => {
94 fn reset_self(&mut self) {
95 self.$field
96 .iter_mut()
97 .for_each(|s| *s = $crate::NodeStatus::Running);
98 }
99 };
100}
101
102#[macro_export]
103macro_rules! reset_index_field {
104 ($field:ident) => {
105 fn reset_self(&mut self) {
106 self.$field = 0;
107 }
108 };
109}
110
111#[async_trait]
112pub trait BehaviorNodeExt: BehaviorNode {
113 async fn run_until_complete(&mut self, ctx: &Context) -> anyhow::Result<NodeStatus> {
117 loop {
118 match self.tick(ctx).await? {
119 NodeStatus::Success => return Ok(NodeStatus::Success),
120 NodeStatus::Failure => return Ok(NodeStatus::Failure),
121 NodeStatus::Running => continue,
122 }
123 }
124 }
125
126 async fn run_with_limit(&mut self, ctx: &Context, max_ticks: usize) -> anyhow::Result<NodeStatus> {
130 for _tick_count in 0..max_ticks {
131 match self.tick(ctx).await? {
132 NodeStatus::Success => return Ok(NodeStatus::Success),
133 NodeStatus::Failure => return Ok(NodeStatus::Failure),
134 NodeStatus::Running => continue,
135 }
136 }
137 anyhow::bail!("Behavior exceeded maximum ticks ({})", max_ticks)
138 }
139}
140
141impl<T: BehaviorNode + ?Sized> BehaviorNodeExt for T {}