# behaviortree
'behaviortree' implements a behavior tree library similar to [BehaviorTree.CPP](https://www.behaviortree.dev/) but in `Rust`.
Examples implementing the BehaviorTree.CPP [tutorials](https://www.behaviortree.dev/docs/intro)
can be found [here](https://codeberg.org/dibbots/behaviortree/src/branch/main/examples).
For __embedded__ devices similar examples are available [here](https://codeberg.org/dibbots/behaviortree/src/branch/main/embedded)
⚠️ INFO ⚠️
This crate is still in development.
## Usage
Below is a very simple example using functions as `Actions`.
For more examples see:
- [Linux/Mac-OS/Windows](https://codeberg.org/dibbots/behaviortree/src/branch/main/examples),
- [embedded](https://codeberg.org/dibbots/behaviortree/src/branch/main/embedded)
```rust
use behaviortree::prelude::*;
const XML: &str = r#"
<root BTCPP_format="4">
<BehaviorTree ID="MyBehavior">
<Sequence>
<MyAction1/>
<MyAction2/>
</Sequence>
</BehaviorTree>
</root>
"#;
fn action_1() -> BehaviorResult {
// your activity
// ...
// In case of Failure
//return Ok(BehaviorState::Failure);
// In case of Success
Ok(BehaviorState::Success)
}
fn action_2() -> BehaviorResult {
// your activity
// ...
Ok(BehaviorState::Success)
}
#[tokio::main]
async fn main() {
// create a behavior factory
let mut factory = BehaviorTreeFactory::new().unwrap();
// register your behaviors
register_simple_behavior!(factory, action_1, "MyAction1", BehaviorKind::Action).unwrap();
register_simple_behavior!(factory, action_2, "MyAction2", BehaviorKind::Action).unwrap();
// create the tree
let mut tree = factory.create_from_text(XML).unwrap();
// run the tree until Success or Failure
tree.tick_while_running().await.unwrap();
}
```
For implementation of your own behaviors, there is a set of
derive macros: `Action`, `Condition`, `Control` and `Decorator`.
```rust
use behaviortree::prelude::*;
const XML: &str = r#"
<root BTCPP_format="4">
<BehaviorTree ID="MyBehavior">
<MyAction message = "hello world!"/>
</BehaviorTree>
</root>
"#;
#[derive(Action, Debug)]
pub struct SaySomething {
/// The ports
#[behavior(portlist)]
portlist: PortArray<1>,
}
#[async_trait::async_trait]
impl Behavior for SaySomething {
async fn tick(
&mut self,
_behavior: &mut BehaviorData,
_children: &mut BehaviorTreeElementList,
_runtime: &SharedRuntime,
) -> BehaviorResult {
let msg = self.portlist.get::<String>("message")?;
println!("Robot says: {msg}");
Ok(BehaviorState::Success)
}
}
impl SaySomething {
port_array_init! {1,
create_inbound_entry_parseable!("message", String)
}
}
#[tokio::main]
async fn main() {
// create a behavior factory
let mut factory = BehaviorTreeFactory::new().unwrap();
// register the behavior
SaySomething::register(&mut factory, "MyAction").unwrap();
// create the tree
let mut tree = factory.create_from_text(XML).unwrap();
// run the tree until Success or Failure
tree.tick_while_running().await.unwrap();
}
```
## Capabilities
✅: Supported<br>
☑️: Supported with some caveats<br>
🚦: Needs testing but basically works<br>
🔴: Not yet supported<br>
??: Unclear if it can be supported<br>
❌: Will not be supported
### General capabilities
| XML | | | |
| - parsing | ✅ | ☑️ | embedded tree depth limited |
| - generation | ✅ | ✅ | |
| | | | |
| Ports | | | |
| - remapping | ✅ | ✅ | |
| - access by ref | ✅ | ✅ | |
| | | | |
| Subtrees | | | |
| - structure | ✅ | ✅ | |
| - remapping | ✅ | ✅ | |
| - 'include' from file | ✅ | ❌ | |
| | | | |
| Blackboard | | | |
| - hierarchy | ✅ | ✅ | |
| - remapping | ✅ | ✅ | |
| - access by ref | ✅ | ✅ | |
| - backup | 🔴 | ?? | |
| | | | |
| Pre-/post-conditions | ✅ | ✅ | |
| Scripting | ✅ | ✅ | |
| | | | |
| Loggers/Observers | ✅ | ✅ | embedded basically works, no time info |
| Substitution rules | 🚦 | 🚦 | no delay in embedded, currently no functions possible |
| | | | |
| Using Groot2 for: | | | |
| - XML Create/Edit | ☑️ | ☑️ | different type systems |
| - Live Monitoring | ☑️ | ☑️ | different type systems, Ethernet over USB |
| - Pro Features | 🔴 | ?? | |
### Built-in behaviors
| __Actions__ | | |
| `AlwaysFailure`, `AlwaysSuccess` | ✅ | ✅ |
| `Script` | ✅ | ✅ |
| `SetBlackboard`, `UnsetBlackboard` | ✅ | ✅ |
| `PopFromQueue<T>` | ✅ | ✅ |
| `Sleep` | ✅ | 🔴 |
| | | |
| __Conditions__ | | |
| `ScriptCondition` | ✅ | ✅ |
| `WasEntryUpdated` | ✅ | ✅ |
| | | |
| __Controls__ | | |
| `Fallback` | ✅ | ✅ |
| `AsyncFallback`, `ReactiveFallback` | ✅ | ✅ |
| `Sequence`, `SequenceWithMemory` | ✅ | ✅ |
| `AsyncSequence`, `ReactiveSequence` | ✅ | ✅ |
| `Parallel`, `ParallelAll` | ✅ | ✅ |
| `IfThenElse`, `WhileDoElse` | ✅ | ✅ |
| `Switch<u8>` | ✅ | ✅ |
| `ManualSelector` | 🔴 | ?? |
| | | |
| __Decorators__ | | |
| `ForceFailure`, `ForceSuccess` | ✅ | ✅ |
| `Inverter` | ✅ | ✅ |
| `KeepRunningUntilFailure` | ✅ | ✅ |
| `Repeat` | ✅ | ✅ |
| `RetryUntilSuccessful` | ✅ | ✅ |
| `EntryUpdated` | ✅ | ✅ |
| `LoopQueue<T>` | ✅ | ✅ |
| `RunOnce` | ✅ | ✅ |
| `Precondition` | ✅ | ✅ |
| `Delay` | ✅ | 🔴 |
| `Timeout` | ✅ | 🔴 |
## License
Licensed with the fair use "NGMC" license, see [license file](https://codeberg.org/dibbots/behaviortree/src/branch/main/LICENSE)
## Contribution
Any contribution intentionally submitted for inclusion in the work by you,
shall be licensed with the same "NGMC" license, without any additional terms or conditions.