dreamwell-engine 1.0.0

Dreamwell pure-logic engine library — transforms, hierarchy, canon pipeline, spatial math, hashing, tile rules, validation, waymark schema, material/lighting descriptors. No SpacetimeDB dependency.
Documentation
use super::promotion::PromotionTarget;
use serde::{Deserialize, Serialize};

pub type EntityId = u64;
pub type EventId = u64;

/// Physics event — reducer-emitted canonical events that trigger GPU simulation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PhysicsEvent {
    Impact {
        event_id: EventId,
        source: EntityId,
        target: EntityId,
        position: [f32; 3],
        normal: [f32; 3],
        force: f32,
        seed: u64,
    },
    Fracture {
        event_id: EventId,
        entity: EntityId,
        fracture_class: String,
        position: [f32; 3],
        impulse: [f32; 3],
        seed: u64,
    },
    Ignite {
        event_id: EventId,
        entity: EntityId,
        heat: f32,
        seed: u64,
    },
    Explode {
        event_id: EventId,
        position: [f32; 3],
        radius: f32,
        force: f32,
        seed: u64,
    },
    PromoteParticle {
        event_id: EventId,
        emitter_id: u64,
        particle_index: u32,
        target: PromotionTarget,
    },
    SpawnEmitter {
        event_id: EventId,
        preset_id: String,
        position: [f32; 3],
        seed: u64,
    },
    StopEmitter {
        event_id: EventId,
        emitter_id: u64,
    },
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn physics_event_serde() {
        let e = PhysicsEvent::Impact {
            event_id: 1,
            source: 100,
            target: 200,
            position: [1.0, 2.0, 3.0],
            normal: [0.0, 1.0, 0.0],
            force: 150.0,
            seed: 42,
        };
        let json = serde_json::to_string(&e).unwrap();
        let restored: PhysicsEvent = serde_json::from_str(&json).unwrap();
        if let PhysicsEvent::Impact { force, .. } = restored {
            assert_eq!(force, 150.0);
        } else {
            panic!("wrong variant");
        }
    }

    #[test]
    fn physics_event_all_variants() {
        let events = vec![
            PhysicsEvent::Impact {
                event_id: 1,
                source: 0,
                target: 0,
                position: [0.0; 3],
                normal: [0.0, 1.0, 0.0],
                force: 1.0,
                seed: 0,
            },
            PhysicsEvent::Fracture {
                event_id: 2,
                entity: 0,
                fracture_class: "stone".into(),
                position: [0.0; 3],
                impulse: [0.0; 3],
                seed: 0,
            },
            PhysicsEvent::Ignite {
                event_id: 3,
                entity: 0,
                heat: 100.0,
                seed: 0,
            },
            PhysicsEvent::Explode {
                event_id: 4,
                position: [0.0; 3],
                radius: 5.0,
                force: 100.0,
                seed: 0,
            },
            PhysicsEvent::PromoteParticle {
                event_id: 5,
                emitter_id: 0,
                particle_index: 0,
                target: PromotionTarget::Pickup,
            },
            PhysicsEvent::SpawnEmitter {
                event_id: 6,
                preset_id: "fire".into(),
                position: [0.0; 3],
                seed: 0,
            },
            PhysicsEvent::StopEmitter {
                event_id: 7,
                emitter_id: 0,
            },
        ];
        for e in events {
            let json = serde_json::to_string(&e).unwrap();
            let _: PhysicsEvent = serde_json::from_str(&json).unwrap();
        }
    }
}