Skip to main content

dreamwell_engine/physics/
events.rs

1use super::promotion::PromotionTarget;
2use serde::{Deserialize, Serialize};
3
4pub type EntityId = u64;
5pub type EventId = u64;
6
7/// Physics event — reducer-emitted canonical events that trigger GPU simulation.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub enum PhysicsEvent {
10    Impact {
11        event_id: EventId,
12        source: EntityId,
13        target: EntityId,
14        position: [f32; 3],
15        normal: [f32; 3],
16        force: f32,
17        seed: u64,
18    },
19    Fracture {
20        event_id: EventId,
21        entity: EntityId,
22        fracture_class: String,
23        position: [f32; 3],
24        impulse: [f32; 3],
25        seed: u64,
26    },
27    Ignite {
28        event_id: EventId,
29        entity: EntityId,
30        heat: f32,
31        seed: u64,
32    },
33    Explode {
34        event_id: EventId,
35        position: [f32; 3],
36        radius: f32,
37        force: f32,
38        seed: u64,
39    },
40    PromoteParticle {
41        event_id: EventId,
42        emitter_id: u64,
43        particle_index: u32,
44        target: PromotionTarget,
45    },
46    SpawnEmitter {
47        event_id: EventId,
48        preset_id: String,
49        position: [f32; 3],
50        seed: u64,
51    },
52    StopEmitter {
53        event_id: EventId,
54        emitter_id: u64,
55    },
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn physics_event_serde() {
64        let e = PhysicsEvent::Impact {
65            event_id: 1,
66            source: 100,
67            target: 200,
68            position: [1.0, 2.0, 3.0],
69            normal: [0.0, 1.0, 0.0],
70            force: 150.0,
71            seed: 42,
72        };
73        let json = serde_json::to_string(&e).unwrap();
74        let restored: PhysicsEvent = serde_json::from_str(&json).unwrap();
75        if let PhysicsEvent::Impact { force, .. } = restored {
76            assert_eq!(force, 150.0);
77        } else {
78            panic!("wrong variant");
79        }
80    }
81
82    #[test]
83    fn physics_event_all_variants() {
84        let events = vec![
85            PhysicsEvent::Impact {
86                event_id: 1,
87                source: 0,
88                target: 0,
89                position: [0.0; 3],
90                normal: [0.0, 1.0, 0.0],
91                force: 1.0,
92                seed: 0,
93            },
94            PhysicsEvent::Fracture {
95                event_id: 2,
96                entity: 0,
97                fracture_class: "stone".into(),
98                position: [0.0; 3],
99                impulse: [0.0; 3],
100                seed: 0,
101            },
102            PhysicsEvent::Ignite {
103                event_id: 3,
104                entity: 0,
105                heat: 100.0,
106                seed: 0,
107            },
108            PhysicsEvent::Explode {
109                event_id: 4,
110                position: [0.0; 3],
111                radius: 5.0,
112                force: 100.0,
113                seed: 0,
114            },
115            PhysicsEvent::PromoteParticle {
116                event_id: 5,
117                emitter_id: 0,
118                particle_index: 0,
119                target: PromotionTarget::Pickup,
120            },
121            PhysicsEvent::SpawnEmitter {
122                event_id: 6,
123                preset_id: "fire".into(),
124                position: [0.0; 3],
125                seed: 0,
126            },
127            PhysicsEvent::StopEmitter {
128                event_id: 7,
129                emitter_id: 0,
130            },
131        ];
132        for e in events {
133            let json = serde_json::to_string(&e).unwrap();
134            let _: PhysicsEvent = serde_json::from_str(&json).unwrap();
135        }
136    }
137}