behavior_tree_lite/
nodes.rs

1use crate::{
2    BehaviorCallback, BehaviorNode, BehaviorNodeContainer, BehaviorResult, Blackboard, Context,
3    Lazy, NumChildren, PortSpec, PortType, Symbol,
4};
5
6pub fn tick_child_node<T>(
7    arg: BehaviorCallback,
8    ctx: &mut Context,
9    node: &mut BehaviorNodeContainer,
10) -> BehaviorResult {
11    std::mem::swap(&mut ctx.blackboard_map, &mut node.blackboard_map);
12    let res = node.node.tick(arg, ctx);
13    std::mem::swap(&mut ctx.blackboard_map, &mut node.blackboard_map);
14    res
15}
16
17/// SubtreeNode is a container for a subtree, introducing a local namescope of blackboard variables.
18pub struct SubtreeNode {
19    /// Blackboard variables needs to be a part of the node payload
20    blackboard: Blackboard,
21    params: Vec<PortSpec>,
22}
23
24impl SubtreeNode {
25    pub fn new(blackboard: Blackboard, params: Vec<PortSpec>) -> Self {
26        Self { blackboard, params }
27    }
28}
29
30impl BehaviorNode for SubtreeNode {
31    fn provided_ports(&self) -> Vec<PortSpec> {
32        self.params.clone()
33    }
34
35    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
36        for param in self
37            .params
38            .iter()
39            .filter(|param| matches!(param.ty, PortType::Input | PortType::InOut))
40        {
41            if let Some(value) = ctx.get_any(param.key) {
42                self.blackboard.insert(param.key, value.clone());
43            }
44        }
45
46        std::mem::swap(&mut self.blackboard, &mut ctx.blackboard);
47        let res = ctx.tick_child(0, arg);
48        std::mem::swap(&mut ctx.blackboard, &mut self.blackboard);
49
50        // It is debatable if we should assign the output value back to the parent blackboard
51        // when the result was Fail or Running. We chose to assign them, which seems less counterintuitive.
52        for param in self
53            .params
54            .iter()
55            .filter(|param| matches!(param.ty, PortType::Output | PortType::InOut))
56        {
57            if let Some(value) = self.blackboard.get(&param.key) {
58                ctx.set_any(param.key, value.clone());
59            }
60        }
61
62        res.unwrap_or(BehaviorResult::Fail)
63    }
64
65    fn max_children(&self) -> NumChildren {
66        NumChildren::Finite(1)
67    }
68}
69
70#[derive(Default)]
71pub struct SequenceNode {
72    current_child: Option<usize>,
73}
74
75impl BehaviorNode for SequenceNode {
76    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
77        let from = self.current_child.unwrap_or(0);
78        for i in from..ctx.num_children() {
79            match ctx.tick_child(i, arg) {
80                Some(BehaviorResult::Fail) => {
81                    self.current_child = None;
82                    return BehaviorResult::Fail;
83                }
84                Some(BehaviorResult::Running) => {
85                    self.current_child = Some(i);
86                    return BehaviorResult::Running;
87                }
88                _ => (),
89            }
90        }
91        self.current_child = None;
92        BehaviorResult::Success
93    }
94
95    fn max_children(&self) -> NumChildren {
96        NumChildren::Infinite
97    }
98}
99
100#[derive(Default)]
101pub struct ReactiveSequenceNode;
102
103impl BehaviorNode for ReactiveSequenceNode {
104    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
105        for i in 0..ctx.num_children() {
106            match ctx.tick_child(i, arg) {
107                Some(BehaviorResult::Fail) => {
108                    return BehaviorResult::Fail;
109                }
110                Some(BehaviorResult::Running) => {
111                    return BehaviorResult::Running;
112                }
113                _ => (),
114            }
115        }
116        BehaviorResult::Success
117    }
118
119    fn max_children(&self) -> NumChildren {
120        NumChildren::Infinite
121    }
122}
123
124#[derive(Default)]
125pub struct FallbackNode {
126    current_child: Option<usize>,
127}
128
129impl BehaviorNode for FallbackNode {
130    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
131        let from = self.current_child.unwrap_or(0);
132        for i in from..ctx.num_children() {
133            match ctx.tick_child(i, arg) {
134                Some(BehaviorResult::Success) => {
135                    self.current_child = None;
136                    return BehaviorResult::Success;
137                }
138                Some(BehaviorResult::Running) => {
139                    self.current_child = Some(i);
140                    return BehaviorResult::Running;
141                }
142                _ => (),
143            }
144        }
145        self.current_child = None;
146        BehaviorResult::Fail
147    }
148
149    fn max_children(&self) -> NumChildren {
150        NumChildren::Infinite
151    }
152}
153
154#[derive(Default)]
155pub struct ReactiveFallbackNode;
156
157impl BehaviorNode for ReactiveFallbackNode {
158    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
159        for i in 0..ctx.num_children() {
160            match ctx.tick_child(i, arg) {
161                Some(BehaviorResult::Success) => {
162                    return BehaviorResult::Success;
163                }
164                Some(BehaviorResult::Running) => {
165                    return BehaviorResult::Running;
166                }
167                _ => (),
168            }
169        }
170        BehaviorResult::Fail
171    }
172
173    fn max_children(&self) -> NumChildren {
174        NumChildren::Infinite
175    }
176}
177
178#[derive(Default)]
179pub struct ForceSuccessNode;
180
181impl BehaviorNode for ForceSuccessNode {
182    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
183        match ctx.tick_child(0, arg) {
184            Some(BehaviorResult::Running) => BehaviorResult::Running,
185            Some(_) => BehaviorResult::Success,
186            _ => BehaviorResult::Fail,
187        }
188    }
189
190    fn max_children(&self) -> NumChildren {
191        NumChildren::Finite(1)
192    }
193}
194
195#[derive(Default)]
196pub struct ForceFailureNode(Option<BehaviorNodeContainer>);
197
198impl BehaviorNode for ForceFailureNode {
199    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
200        if let Some(ref mut node) = self.0 {
201            std::mem::swap(&mut ctx.blackboard_map, &mut node.blackboard_map);
202            if let BehaviorResult::Running = node.node.tick(arg, ctx) {
203                std::mem::swap(&mut ctx.blackboard_map, &mut node.blackboard_map);
204                return BehaviorResult::Running;
205            }
206            std::mem::swap(&mut ctx.blackboard_map, &mut node.blackboard_map);
207            BehaviorResult::Fail
208        } else {
209            BehaviorResult::Fail
210        }
211    }
212
213    fn max_children(&self) -> NumChildren {
214        NumChildren::Finite(1)
215    }
216}
217
218#[derive(Default)]
219pub struct InverterNode;
220
221impl BehaviorNode for InverterNode {
222    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
223        match ctx.tick_child(0, arg) {
224            Some(BehaviorResult::Running) => BehaviorResult::Running,
225            Some(BehaviorResult::Success) => BehaviorResult::Fail,
226            Some(BehaviorResult::Fail) => BehaviorResult::Success,
227            None => BehaviorResult::Fail,
228        }
229    }
230
231    fn max_children(&self) -> NumChildren {
232        NumChildren::Finite(1)
233    }
234}
235
236static N: Lazy<Symbol> = Lazy::new(|| "n".into());
237
238#[derive(Default)]
239pub(super) struct RepeatNode {
240    n: Option<usize>,
241}
242
243impl BehaviorNode for RepeatNode {
244    fn provided_ports(&self) -> Vec<PortSpec> {
245        vec![PortSpec::new_in(*N)]
246    }
247
248    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
249        if let Some(current) = self.n.or_else(|| ctx.get_parse::<usize>("n")) {
250            if current == 0 {
251                self.n = None;
252                return BehaviorResult::Success;
253            }
254            match ctx.tick_child(0, arg) {
255                Some(BehaviorResult::Success) => {
256                    self.n = Some(current - 1);
257                    return BehaviorResult::Running;
258                }
259                Some(BehaviorResult::Running) => return BehaviorResult::Running,
260                Some(res) => {
261                    self.n = None;
262                    return res;
263                }
264                _ => return BehaviorResult::Fail,
265            }
266        }
267        BehaviorResult::Fail
268    }
269
270    fn max_children(&self) -> NumChildren {
271        NumChildren::Finite(1)
272    }
273}
274
275#[derive(Default)]
276pub(super) struct RetryNode {
277    n: Option<usize>,
278}
279
280impl BehaviorNode for RetryNode {
281    fn provided_ports(&self) -> Vec<PortSpec> {
282        vec![PortSpec::new_in(*N)]
283    }
284
285    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
286        if let Some(current) = self.n.or_else(|| ctx.get_parse::<usize>("n")) {
287            if current == 0 {
288                self.n = None;
289                return BehaviorResult::Success;
290            }
291            match ctx.tick_child(0, arg) {
292                Some(BehaviorResult::Fail) => {
293                    self.n = Some(current - 1);
294                    return BehaviorResult::Running;
295                }
296                Some(BehaviorResult::Running) => return BehaviorResult::Running,
297                Some(res) => {
298                    self.n = None;
299                    return res;
300                }
301                _ => return BehaviorResult::Fail,
302            }
303        }
304        BehaviorResult::Fail
305    }
306
307    fn max_children(&self) -> NumChildren {
308        NumChildren::Finite(1)
309    }
310}
311
312pub(crate) static VALUE: Lazy<Symbol> = Lazy::new(|| "value".into());
313pub(crate) static OUTPUT: Lazy<Symbol> = Lazy::new(|| "output".into());
314
315pub(crate) struct SetBoolNode;
316
317impl BehaviorNode for SetBoolNode {
318    fn provided_ports(&self) -> Vec<PortSpec> {
319        vec![PortSpec::new_in(*VALUE), PortSpec::new_out(*OUTPUT)]
320    }
321
322    fn tick(&mut self, _arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
323        let result = ctx.get_parse::<bool>(*VALUE);
324        if let Some(value) = result {
325            ctx.set(*OUTPUT, value);
326            BehaviorResult::Success
327        } else {
328            BehaviorResult::Fail
329        }
330    }
331}
332
333pub(crate) static INPUT: Lazy<Symbol> = Lazy::new(|| "input".into());
334
335pub struct IsTrueNode;
336
337impl BehaviorNode for IsTrueNode {
338    fn provided_ports(&self) -> Vec<PortSpec> {
339        vec![PortSpec::new_in(*INPUT)]
340    }
341
342    fn tick(&mut self, _arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
343        if let Some(input) = ctx.get_parse::<bool>(*INPUT) {
344            if input {
345                BehaviorResult::Success
346            } else {
347                BehaviorResult::Fail
348            }
349        } else {
350            BehaviorResult::Fail
351        }
352    }
353}
354
355#[derive(Default)]
356pub struct IfNode {
357    condition_result: Option<BehaviorResult>,
358}
359
360impl BehaviorNode for IfNode {
361    fn tick(&mut self, arg: BehaviorCallback, ctx: &mut Context) -> BehaviorResult {
362        let condition_result = match self.condition_result {
363            Some(BehaviorResult::Running) => ctx.tick_child(0, arg).unwrap_or(BehaviorResult::Fail),
364            Some(res) => res,
365            None => ctx.tick_child(0, arg).unwrap_or(BehaviorResult::Fail),
366        };
367
368        // Remember the last conditional result in case the child node returns Running
369        self.condition_result = Some(condition_result);
370
371        if matches!(condition_result, BehaviorResult::Running) {
372            return BehaviorResult::Running;
373        }
374
375        let branch_result = match condition_result {
376            BehaviorResult::Success => ctx.tick_child(1, arg).unwrap_or(BehaviorResult::Fail),
377            BehaviorResult::Fail => {
378                // Be aware that lack of else clause is not an error, so the result is Success.
379                ctx.tick_child(2, arg).unwrap_or(BehaviorResult::Success)
380            }
381            BehaviorResult::Running => BehaviorResult::Running,
382        };
383
384        // Clear the last state if either true or false branch has succeeded. This node should
385        // evaluate condition again if it's ticked later.
386        if !matches!(branch_result, BehaviorResult::Running) {
387            self.condition_result = None;
388        }
389
390        branch_result
391    }
392
393    fn max_children(&self) -> NumChildren {
394        NumChildren::Finite(3)
395    }
396}
397
398#[cfg(test)]
399mod test;