Skip to main content

steel_core/behavior/
consume_effect.rs

1//! Consume-effect behavior registry.
2
3use std::ops::Deref;
4use std::sync::{Arc, OnceLock};
5
6use steel_registry::consume_effect::{ConsumeEffectData, ConsumeEffectTypeRef};
7use steel_registry::{REGISTRY, RegistryEntry, RegistryExt};
8
9use crate::entity::LivingEntity;
10use crate::entity::consume_effect::ConsumeEffectBehavior;
11use crate::world::World;
12
13/// No-op behavior for a consume-effect type without a registered behavior
14/// (e.g. a mod-added type Steel doesn't implement yet).
15struct NoopConsumeEffect;
16
17impl ConsumeEffectBehavior for NoopConsumeEffect {
18    fn apply(&self, _effect: &ConsumeEffectData, _world: &Arc<World>, _user: &dyn LivingEntity) {}
19}
20
21/// Wrapper for the global consume-effect behavior registry that implements `Deref`.
22pub struct ConsumeEffectBehaviorLock(pub OnceLock<ConsumeEffectBehaviorRegistry>);
23
24impl Deref for ConsumeEffectBehaviorLock {
25    type Target = ConsumeEffectBehaviorRegistry;
26
27    fn deref(&self) -> &Self::Target {
28        self.0
29            .get()
30            .expect("Consume effect behaviors not initialized")
31    }
32}
33
34/// Global consume-effect behavior registry.
35///
36/// Access behaviors directly via deref:
37/// `CONSUME_EFFECT_BEHAVIORS.get_behavior(effect_type)`
38pub static CONSUME_EFFECT_BEHAVIORS: ConsumeEffectBehaviorLock =
39    ConsumeEffectBehaviorLock(OnceLock::new());
40
41/// Registry for consume-effect behaviors.
42///
43/// Created after the main registry is frozen. All consume-effect types are
44/// initialized with a default no-op behavior, then custom behaviors are
45/// registered.
46pub struct ConsumeEffectBehaviorRegistry {
47    behaviors: Vec<Box<dyn ConsumeEffectBehavior>>,
48}
49
50impl ConsumeEffectBehaviorRegistry {
51    /// Creates a new behavior registry with default behaviors for all consume-effect types.
52    #[must_use]
53    pub fn new() -> Self {
54        let count = REGISTRY.consume_effect_types.len();
55        let mut behaviors: Vec<Box<dyn ConsumeEffectBehavior>> = Vec::with_capacity(count);
56
57        for _ in 0..count {
58            behaviors.push(Box::new(NoopConsumeEffect));
59        }
60
61        Self { behaviors }
62    }
63
64    /// Sets a custom behavior for a consume-effect type.
65    ///
66    /// # Panics
67    /// Panics if `effect_type` is not registered in the global registry.
68    pub fn set_behavior(
69        &mut self,
70        effect_type: ConsumeEffectTypeRef,
71        behavior: Box<dyn ConsumeEffectBehavior>,
72    ) {
73        self.behaviors[effect_type.id()] = behavior;
74    }
75
76    /// Gets the behavior for a consume-effect type.
77    ///
78    /// # Panics
79    /// Panics if `effect_type` is not registered in the global registry.
80    #[must_use]
81    pub fn get_behavior(&self, effect_type: ConsumeEffectTypeRef) -> &dyn ConsumeEffectBehavior {
82        self.behaviors[effect_type.id()].as_ref()
83    }
84}
85
86impl Default for ConsumeEffectBehaviorRegistry {
87    fn default() -> Self {
88        Self::new()
89    }
90}