Skip to main content

behaviortree_rs/nodes/control/
fallback.rs

1use behaviortree_rs_derive::bt_node;
2
3use crate::{
4    basic_types::NodeStatus,
5    nodes::{NodeError, NodeResult},
6};
7
8/// The FallbackNode is used to try different strategies,
9/// until one succeeds.
10/// If any child returns RUNNING, previous children will NOT be ticked again.
11///
12/// - If all the children return FAILURE, this node returns FAILURE.
13///
14/// - If a child returns RUNNING, this node returns RUNNING.
15///
16/// - If a child returns SUCCESS, stop the loop and return SUCCESS.
17// #[derive(TreeNodeDefaults, ControlNode, Debug, Clone)]
18#[bt_node(ControlNode)]
19pub struct FallbackNode {
20    #[bt(default = "0")]
21    child_idx: usize,
22    #[bt(default = "true")]
23    all_skipped: bool,
24}
25
26#[bt_node(ControlNode)]
27impl FallbackNode {
28    async fn tick(&mut self) -> NodeResult {
29        if node_.status == NodeStatus::Idle {
30            self.all_skipped = true;
31        }
32
33        node_.status = NodeStatus::Running;
34
35        while self.child_idx < node_.children.len() {
36            let cur_child = &mut node_.children[self.child_idx];
37
38            let _prev_status = cur_child.status();
39            let child_status = cur_child.execute_tick().await?;
40
41            self.all_skipped &= child_status == NodeStatus::Skipped;
42
43            match &child_status {
44                NodeStatus::Running => {
45                    return Ok(NodeStatus::Running);
46                }
47                NodeStatus::Failure => {
48                    self.child_idx += 1;
49                }
50                NodeStatus::Success => {
51                    node_.reset_children().await;
52                    self.child_idx = 0;
53                    return Ok(NodeStatus::Success);
54                }
55                NodeStatus::Skipped => {
56                    self.child_idx += 1;
57                }
58                NodeStatus::Idle => {
59                    return Err(NodeError::StatusError(
60                        "Name here".to_string(),
61                        "Idle".to_string(),
62                    ));
63                }
64            };
65        }
66
67        if self.child_idx == node_.children.len() {
68            node_.reset_children().await;
69            self.child_idx = 0;
70        }
71
72        match self.all_skipped {
73            true => Ok(NodeStatus::Skipped),
74            false => Ok(NodeStatus::Failure),
75        }
76    }
77
78    async fn halt(&mut self) {
79        self.child_idx = 0;
80        node_.reset_children().await;
81    }
82}