Skip to main content

mecha10_behavior_runtime/actions/
timing.rs

1//! Action nodes that gate on elapsed time, or do nothing.
2
3use super::elapsed_timer::{reset_timer_field, ElapsedTimer};
4use crate::{BehaviorNode, Context, NodeStatus};
5use async_trait::async_trait;
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::time::Duration;
9
10macro_rules! from_json_with_duration {
11    ($config:ident) => {
12        /// Create a new node from JSON configuration
13        pub fn from_json(config: Value) -> anyhow::Result<Self> {
14            let cfg: $config = serde_json::from_value(config)?;
15            Ok(Self {
16                duration: Duration::from_secs_f64(cfg.duration_secs),
17                timer: ElapsedTimer::default(),
18            })
19        }
20    };
21}
22
23#[derive(Debug, Default)]
24pub struct TimerNode {
25    duration: Duration,
26    timer: ElapsedTimer,
27}
28
29#[derive(Debug, Serialize, Deserialize)]
30struct TimerConfig {
31    duration_secs: f64,
32}
33
34impl TimerNode {
35    from_json_with_duration!(TimerConfig);
36}
37
38#[async_trait]
39impl BehaviorNode for TimerNode {
40    async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
41        if self.timer.elapsed_since_start(self.duration) {
42            Ok(NodeStatus::Success)
43        } else {
44            Ok(NodeStatus::Running)
45        }
46    }
47
48    reset_timer_field!(timer);
49
50    fn name(&self) -> &str {
51        "TimerNode"
52    }
53}
54
55#[derive(Debug)]
56pub struct IdleNode;
57
58impl IdleNode {
59    /// Create a new IdleNode from JSON configuration
60    pub fn from_json(_config: Value) -> anyhow::Result<Self> {
61        Ok(Self)
62    }
63}
64
65#[async_trait]
66impl BehaviorNode for IdleNode {
67    async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
68        Ok(NodeStatus::Success)
69    }
70
71    fn name(&self) -> &str {
72        "IdleNode"
73    }
74}
75
76#[derive(Debug, Default)]
77pub struct PauseNode {
78    duration: Duration,
79    timer: ElapsedTimer,
80}
81
82#[derive(Debug, Serialize, Deserialize)]
83struct PauseConfig {
84    duration_secs: f64,
85}
86
87impl PauseNode {
88    from_json_with_duration!(PauseConfig);
89}
90
91#[async_trait]
92impl BehaviorNode for PauseNode {
93    async fn tick(&mut self, _ctx: &Context) -> anyhow::Result<NodeStatus> {
94        if !self.timer.is_running() {
95            tracing::debug!("PauseNode: starting pause for {:?}", self.duration);
96        }
97
98        if self.timer.elapsed_since_start(self.duration) {
99            tracing::debug!("PauseNode: pause complete");
100            Ok(NodeStatus::Success)
101        } else {
102            Ok(NodeStatus::Running)
103        }
104    }
105
106    reset_timer_field!(timer);
107
108    fn name(&self) -> &str {
109        "PauseNode"
110    }
111}