use anyhow::Result;
use async_trait::async_trait;
use mecha10_behavior_runtime::prelude::*;
use std::time::Duration;
#[derive(Debug)]
struct PrintMessage {
message: String,
}
impl PrintMessage {
fn from_config(config: serde_json::Value) -> Result<Self> {
let message = config
.get("message")
.and_then(|v| v.as_str())
.unwrap_or("Hello, world!")
.to_string();
Ok(Self { message })
}
}
#[async_trait]
impl BehaviorNode for PrintMessage {
async fn tick(&mut self, _ctx: &Context) -> Result<NodeStatus> {
println!(">>> {}", self.message);
Ok(NodeStatus::Success)
}
fn name(&self) -> &str {
"print_message"
}
}
#[derive(Debug)]
struct WaitBehavior {
duration: Duration,
started: Option<std::time::Instant>,
}
impl WaitBehavior {
fn from_config(config: serde_json::Value) -> Result<Self> {
let duration_seconds = config.get("duration_seconds").and_then(|v| v.as_f64()).unwrap_or(1.0);
Ok(Self {
duration: Duration::from_secs_f64(duration_seconds),
started: None,
})
}
}
#[async_trait]
impl BehaviorNode for WaitBehavior {
async fn tick(&mut self, _ctx: &Context) -> Result<NodeStatus> {
if self.started.is_none() {
println!(">>> Waiting for {:?}...", self.duration);
self.started = Some(std::time::Instant::now());
}
if self.started.unwrap().elapsed() >= self.duration {
println!(">>> Wait complete!");
Ok(NodeStatus::Success)
} else {
Ok(NodeStatus::Running)
}
}
async fn reset(&mut self) -> Result<()> {
self.started = None;
Ok(())
}
fn name(&self) -> &str {
"wait"
}
}
#[derive(Debug)]
struct CounterBehavior {
target: usize,
current: usize,
}
impl CounterBehavior {
fn from_config(config: serde_json::Value) -> Result<Self> {
let target = config.get("target").and_then(|v| v.as_u64()).unwrap_or(5) as usize;
Ok(Self { target, current: 0 })
}
}
#[async_trait]
impl BehaviorNode for CounterBehavior {
async fn tick(&mut self, _ctx: &Context) -> Result<NodeStatus> {
self.current += 1;
println!(">>> Count: {} / {}", self.current, self.target);
if self.current >= self.target {
Ok(NodeStatus::Success)
} else {
Ok(NodeStatus::Running)
}
}
async fn reset(&mut self) -> Result<()> {
self.current = 0;
Ok(())
}
fn name(&self) -> &str {
"counter"
}
}
#[tokio::main]
async fn main() -> Result<()> {
tracing_subscriber::fmt().with_max_level(tracing::Level::INFO).init();
println!("\n=== Behavior Tree Loading and Execution Example ===\n");
println!("Step 1: Creating NodeRegistry...");
let mut registry = NodeRegistry::new();
println!("Step 2: Registering custom nodes...");
registry.register("print_message", |config| {
Ok(Box::new(PrintMessage::from_config(config)?))
});
registry.register("wait", |config| Ok(Box::new(WaitBehavior::from_config(config)?)));
registry.register("counter", |config| Ok(Box::new(CounterBehavior::from_config(config)?)));
println!(
" Registered {} node types: {:?}",
registry.len(),
registry.registered_types()
);
println!("\nStep 3: Creating BehaviorLoader...");
let loader = BehaviorLoader::new(registry);
println!("\nStep 4: Loading behavior tree from JSON...");
let json = r#"{
"name": "demo_sequence",
"description": "Demonstrates loading and executing a behavior tree",
"root": {
"type": "sequence",
"children": [
{
"type": "node",
"node": "print_message",
"config": {
"message": "Starting demo sequence..."
}
},
{
"type": "node",
"node": "counter",
"config": {
"target": 3
}
},
{
"type": "node",
"node": "wait",
"config": {
"duration_seconds": 0.5
}
},
{
"type": "node",
"node": "print_message",
"config": {
"message": "Demo complete!"
}
}
]
}
}"#;
let behavior = loader.load_from_json(json)?;
println!(" Successfully loaded behavior tree!");
println!("\nStep 5: Creating execution context...");
let ctx = Context::new("demo_robot").await?;
println!("\nStep 6: Creating BehaviorExecutor...");
let mut executor = BehaviorExecutor::new(behavior, 30.0) .with_max_ticks(1000);
println!("\nStep 7: Initializing behavior...");
executor.init(&ctx).await?;
println!("\nStep 8: Executing behavior tree...\n");
println!("--- Execution Output ---");
let (status, stats) = executor.run_until_complete(&ctx).await?;
println!("--- Execution Complete ---\n");
println!("\nStep 9: Execution Statistics:");
println!(" Final Status: {}", status);
println!(" Total Ticks: {}", stats.tick_count);
println!(" Total Duration: {:?}", stats.total_duration);
println!(" Average Tick: {:?}", stats.avg_tick_duration);
println!(
" Min/Max Tick: {:?} / {:?}",
stats.min_tick_duration, stats.max_tick_duration
);
println!("\nStep 10: Cleaning up...");
executor.terminate(&ctx).await?;
println!("\n=== Demo Complete! ===\n");
demonstrate_different_compositions(&loader, &ctx).await?;
Ok(())
}
async fn demonstrate_different_compositions(loader: &BehaviorLoader, ctx: &Context) -> Result<()> {
println!("\n=== Additional Examples ===\n");
println!("Example 1: Selector Node (fallback behavior)");
let selector_json = r#"{
"name": "selector_demo",
"root": {
"type": "selector",
"children": [
{
"type": "node",
"node": "print_message",
"config": {
"message": "First option succeeded!"
}
},
{
"type": "node",
"node": "print_message",
"config": {
"message": "This won't execute"
}
}
]
}
}"#;
let behavior = loader.load_from_json(selector_json)?;
let mut executor = BehaviorExecutor::new(behavior, 30.0);
let (status, _) = executor.run_until_complete(ctx).await?;
println!(" Result: {}\n", status);
println!("Example 2: Parallel Node (concurrent execution)");
let parallel_json = r#"{
"name": "parallel_demo",
"root": {
"type": "parallel",
"policy": "require_all",
"children": [
{
"type": "node",
"node": "print_message",
"config": {
"message": "Parallel task 1"
}
},
{
"type": "node",
"node": "print_message",
"config": {
"message": "Parallel task 2"
}
}
]
}
}"#;
let behavior = loader.load_from_json(parallel_json)?;
let mut executor = BehaviorExecutor::new(behavior, 30.0);
let (status, _) = executor.run_until_complete(ctx).await?;
println!(" Result: {}\n", status);
println!("Example 3: Nested Composition");
let nested_json = r#"{
"name": "nested_demo",
"root": {
"type": "sequence",
"children": [
{
"type": "node",
"node": "print_message",
"config": {
"message": "Outer sequence started"
}
},
{
"type": "selector",
"children": [
{
"type": "node",
"node": "print_message",
"config": {
"message": "Inner selector option"
}
}
]
},
{
"type": "node",
"node": "print_message",
"config": {
"message": "Outer sequence complete"
}
}
]
}
}"#;
let behavior = loader.load_from_json(nested_json)?;
let mut executor = BehaviorExecutor::new(behavior, 30.0);
let (status, _) = executor.run_until_complete(ctx).await?;
println!(" Result: {}\n", status);
println!("=== All Examples Complete! ===\n");
Ok(())
}