1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! # Shrubbery
//!
//! <img src="../../../bt/crates/shrubbery/doc/shrub-dark.gif" alt="sample bt" />
//!
//! <img src="../../../bt/crates/shrubbery/doc/shrubbery.jpg" alt="it is a good shrubbery" />
//!
//! ## Motivation
//!
//! Fundamentally behavior trees are _simple_, leaf nodes perform some action and return one of
//! three states: Success, Failure, or Running. All other nodes nodes determine how tree traversal
//! is done -- effectively controlling which execution nodes get executed and in what order.
//!
//! ## BT vs FSM
//!
//! FSMs are more explicit in their state transitions, but can be more difficult to manage as the
//! number of states grows, especially when it comes to modification of behavior. In contrast,
//! BTs are more flexible and can be more easily modified, since behavior is localized strictly
//! to the sub-tree where the behavior is defined, changes to a sub-tree do not impact the program
//! outside of that sub-tree.
//!
//! The trade offs are:
//!
//! - Reactivity: FSMs are more reactive, since state transitions are explicit, in a BT the
//! execution flow is essentially compiled into the shape of the tree.
//!
//! ## Motivation for Shrubbery (why not keep using `bonsai_bt`)
//!
//! IMO bonsai has a few insurmountable issues that make it unsuitable:
//!
//! - API: The way the BT gets defined is by constructing a single, ultra-nested enum of
//! `Behavior<T>` upfront that cannot be changed once the `BT` is instantiated. This is both
//! cumbersome to and error prone to write (a problem I tried to mitigate in `bt_functional`), and
//! more importantly, very difficult to compose subtrees with different `T` into a greater
//! behavior tree and there is no mechanism for helping with this
//!
//! **Node seperation**
//!
//! Control (internal) nodes and Executor (leaf) nodes are not delineated (they are all `Behavior<T>`).
//!
//! - To `&mut` or not to `&mut`: typically execution nodes have two flavors:
//! - Read a value from the blackboard and return `Success` if it's present, `Failure` if
//! it's not, or `Running` to indicate a loop should continue executing.
//! - Execute a task & update the blackboard with the outcome, return `Success`, `Failure`,
//! or `Running` to reflect the outcome of the task.
//! - In bonsai, you always have an `&mut Blackboard` when handling an action in a tick and
//! the read vs. execute and write distinction doesn't exist, this makes it tempting to do
//! work in places that it's not appropriate.
//!
//! - If Control is independent of Execution, `T` (the executable behavior type) is independent
//! of Control, thus by building the `BT` out of indices into a `Vec<ControlNode>` and a
//! `Vec<ExecutorNode>` (which can be done implicitly since nodes are executors iff they are
//! a leaf, and nodes are control iff they are not executors). Seperating these in this way
//! makes sub-tree composition trivially easy.
//!
//! **Graphviz**
//!
//! This feels like a nit, but I don't think it is. A lot of the debugging behavior trees is made a
//! lot easier with the ability to look at the tree itself.
//!
//! A nicely formatted graphviz tree goes a long way to make it easy to parse what is going on &
//! there are a standard set of symbols typically used to do so:
//!
//! <img src="../../../bt/crates/shrubbery/doc/sample_bt.png" alt="sample bt" />
//!
//! Petgraphs' `Dot` implementation isn't great since you can't style nodes differently and it relies
//! purely on the implementation of [`std::fmt::Debug`] (something very useless if your nodes are ids),
//! but at least you can use [`grahviz-rust`] & tree traveral to DIY it.
//!
//! Bonsai uses petgraph, but doens't expose the actual graph in the public API, they just wrap the
//! [`petgraph::Dot`] implementation and return a string. We could vendor `bonsai` or try and land a
//! PR to get around this, but the other issues I have mean I really don't care.
//!
//!
use Debug;
use CTreeNodeID;
use Error;
pub type ShrubberyResult<T> = ;