animgraph/processors/
timed_event.rs

1use serde_derive::{Deserialize, Serialize};
2
3use crate::{
4    io::{Event, EventEmit, NumberRef, Timer},
5    FlowState, GraphBoolean, GraphNodeConstructor, Seconds,
6};
7
8use super::{GraphNode, GraphVisitor};
9
10#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
11pub struct TimedEventNode {
12    pub timer: Timer,
13    pub event: Event,
14    pub condition: GraphBoolean,
15    pub duration: NumberRef<Seconds>,
16    pub emit: EventEmit,
17    pub elapsed: bool,
18}
19
20impl GraphNodeConstructor for TimedEventNode {
21    fn identity() -> &'static str {
22        "timed_event"
23    }
24
25    fn construct_entry(
26        self,
27        metrics: &crate::GraphMetrics,
28    ) -> anyhow::Result<crate::GraphNodeEntry> {
29        metrics.validate_timer(&self.timer, Self::identity())?;
30        metrics.validate_event(&self.event, Self::identity())?;
31        metrics.validate_bool(self.condition, Self::identity())?;
32        metrics.validate_number_ref(&self.duration, Self::identity())?;
33        Ok(crate::GraphNodeEntry::Process(Box::new(self)))
34    }
35}
36
37impl GraphNode for TimedEventNode {
38    fn visit(&self, visitor: &mut GraphVisitor) {
39        let emit = if visitor.graph.get_bool(self.condition) {
40            self.emit
41        } else {
42            EventEmit::Never
43        };
44
45        let duration = self.duration.get(visitor.graph);
46
47        let in_event = if self.elapsed {
48            self.timer.elapsed(visitor.graph).0 >= duration.0
49        } else {
50            self.timer.remaining(visitor.graph).0 <= duration.0
51        };
52
53        let state = if in_event {
54            visitor.graph.get_state(visitor.context.state)
55        } else {
56            FlowState::Exited
57        };
58
59        self.event.emit(visitor, state, emit);
60    }
61}
62
63#[cfg(feature = "compiler")]
64pub mod compile {
65    use serde_derive::{Deserialize, Serialize};
66    use serde_json::Value;
67
68    use crate::{
69        compiler::prelude::{
70            Extras, IOSlot, IOType, Node, NodeCompilationError, NodeCompiler,
71            NodeSerializationContext, NodeSettings,
72        },
73        io::{Event, EventEmit, Timer},
74        GraphNodeConstructor, Seconds,
75    };
76
77    pub use super::TimedEventNode;
78
79    #[derive(Debug, Clone, Serialize, Deserialize, Default)]
80    pub struct TimedEventSettings {
81        pub emit: EventEmit,
82        pub elapsed: bool,
83    }
84
85    impl NodeSettings for TimedEventSettings {
86        fn name() -> &'static str {
87            TimedEventNode::identity()
88        }
89
90        fn input() -> &'static [(&'static str, IOType)] {
91            use IOType::*;
92            &[
93                ("timer", Timer),
94                ("event", Event),
95                ("condition", Bool),
96                ("duration", Number),
97            ]
98        }
99
100        fn output() -> &'static [(&'static str, IOType)] {
101            &[]
102        }
103
104        fn build(self) -> anyhow::Result<Extras> {
105            Ok(serde_json::to_value(self)?)
106        }
107    }
108
109    impl NodeCompiler for TimedEventNode {
110        type Settings = TimedEventSettings;
111        fn build<'a>(
112            context: &NodeSerializationContext<'a>,
113        ) -> Result<Value, NodeCompilationError> {
114            let timer = context.input_timer(0)?;
115            let event = context.input_event(1)?;
116            let condition = context.input_bool(2)?;
117            let duration = context.input_number::<Seconds>(3)?;
118            let settings = context.settings::<TimedEventSettings>()?;
119
120            context.serialize_node(TimedEventNode {
121                timer,
122                event,
123                condition,
124                duration,
125                emit: settings.emit,
126                elapsed: settings.elapsed,
127            })
128        }
129    }
130
131    pub fn remaining_event(
132        timer: impl IOSlot<Timer>,
133        event: impl IOSlot<Event>,
134        condition: impl IOSlot<bool>,
135        duration: impl IOSlot<Seconds>,
136        emit: EventEmit,
137    ) -> Node {
138        let settings = TimedEventSettings {
139            emit,
140            elapsed: false,
141        };
142        let input = vec![
143            timer.into_slot("timer"),
144            event.into_slot("event"),
145            condition.into_slot("condition"),
146            duration.into_slot("duration"),
147        ];
148        Node::new(input, vec![], settings).expect("Valid")
149    }
150}