Skip to main content

issun/plugin/entropy/
hook_ecs.rs

1//! Hook trait for game-specific entropy behavior (ECS version)
2//!
3//! Uses hecs::Entity for entity identification.
4
5use super::state_ecs::EntropyStateECS;
6use async_trait::async_trait;
7
8/// Hook for customizing entropy behavior (ECS version)
9#[async_trait]
10pub trait EntropyHookECS: Send + Sync {
11    /// Called when entity durability status changes
12    ///
13    /// # Arguments
14    /// * `entity` - Entity that changed status
15    /// * `new_durability` - New durability value
16    async fn on_durability_status_changed(&self, entity: hecs::Entity, new_durability: f32) {
17        let _ = (entity, new_durability);
18        // Default: no-op
19    }
20
21    /// Called when entity is destroyed (durability reaches 0)
22    ///
23    /// # Arguments
24    /// * `entity` - Entity that was destroyed
25    /// * `state` - Current ECS state (for querying components)
26    async fn on_entity_destroyed(&self, entity: hecs::Entity, state: &EntropyStateECS) {
27        let _ = (entity, state);
28        // Default: no-op
29    }
30
31    /// Calculate repair cost for entity
32    ///
33    /// # Arguments
34    /// * `entity` - Entity being repaired
35    /// * `repair_amount` - Amount of durability being restored
36    ///
37    /// # Returns
38    /// Cost of the repair operation
39    async fn calculate_repair_cost(&self, entity: hecs::Entity, repair_amount: f32) -> f32 {
40        let _ = entity;
41        // Default: cost equals repair amount
42        repair_amount
43    }
44
45    /// Called before decay update (can modify decay rate)
46    ///
47    /// # Arguments
48    /// * `entity` - Entity about to decay
49    /// * `base_decay` - Calculated base decay amount
50    ///
51    /// # Returns
52    /// Modified decay amount
53    async fn modify_decay(&self, entity: hecs::Entity, base_decay: f32) -> f32 {
54        let _ = entity;
55        base_decay
56    }
57}
58
59/// Default implementation (no-op)
60pub struct DefaultEntropyHookECS;
61
62#[async_trait]
63impl EntropyHookECS for DefaultEntropyHookECS {}
64
65#[cfg(test)]
66mod tests {
67
68    use super::*;
69
70    struct TestHook {
71        on_destroyed_called: std::sync::Arc<std::sync::atomic::AtomicBool>,
72    }
73
74    #[async_trait]
75    impl EntropyHookECS for TestHook {
76        async fn on_entity_destroyed(&self, _entity: hecs::Entity, _state: &EntropyStateECS) {
77            self.on_destroyed_called
78                .store(true, std::sync::atomic::Ordering::SeqCst);
79        }
80
81        async fn calculate_repair_cost(&self, _entity: hecs::Entity, repair_amount: f32) -> f32 {
82            repair_amount * 2.0 // Double cost
83        }
84    }
85
86    #[tokio::test]
87    async fn test_default_hook() {
88        let hook = DefaultEntropyHookECS;
89        let state = EntropyStateECS::new();
90        let entity = hecs::Entity::DANGLING;
91
92        // Should not panic
93        hook.on_durability_status_changed(entity, 50.0).await;
94        hook.on_entity_destroyed(entity, &state).await;
95
96        let cost = hook.calculate_repair_cost(entity, 10.0).await;
97        assert_eq!(cost, 10.0);
98
99        let decay = hook.modify_decay(entity, 5.0).await;
100        assert_eq!(decay, 5.0);
101    }
102
103    #[tokio::test]
104    async fn test_custom_hook() {
105        let called = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));
106        let hook = TestHook {
107            on_destroyed_called: called.clone(),
108        };
109
110        let state = EntropyStateECS::new();
111        let entity = hecs::Entity::DANGLING;
112
113        hook.on_entity_destroyed(entity, &state).await;
114
115        assert!(called.load(std::sync::atomic::Ordering::SeqCst));
116
117        let cost = hook.calculate_repair_cost(entity, 10.0).await;
118        assert_eq!(cost, 20.0); // Doubled
119    }
120}