Skip to main content

steel_registry/
potion.rs

1//! Potion registry values extracted from Vanilla.
2
3use rustc_hash::FxHashMap;
4use steel_utils::Identifier;
5
6use crate::RegistryTags;
7use crate::mob_effect::MobEffectRef;
8
9/// One base effect supplied by a registered potion.
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct PotionEffect {
12    pub effect: MobEffectRef,
13    pub duration: i32,
14    pub amplifier: i32,
15}
16
17/// Registered potion definition.
18#[derive(Debug)]
19pub struct Potion {
20    pub key: Identifier,
21    /// Translation-key suffix used for item names.
22    pub name: &'static str,
23    pub effects: &'static [PotionEffect],
24}
25
26impl Potion {
27    #[must_use]
28    pub const fn new(
29        key: Identifier,
30        name: &'static str,
31        effects: &'static [PotionEffect],
32    ) -> Self {
33        Self { key, name, effects }
34    }
35}
36
37pub type PotionRef = &'static Potion;
38
39pub struct PotionRegistry {
40    potions_by_id: Vec<PotionRef>,
41    potions_by_key: FxHashMap<Identifier, usize>,
42    tags: RegistryTags,
43    allows_registering: bool,
44}
45
46impl PotionRegistry {
47    #[must_use]
48    pub fn new() -> Self {
49        Self {
50            potions_by_id: Vec::new(),
51            potions_by_key: FxHashMap::default(),
52            tags: RegistryTags::default(),
53            allows_registering: true,
54        }
55    }
56}
57
58crate::impl_standard_methods!(
59    PotionRegistry,
60    PotionRef,
61    potions_by_id,
62    potions_by_key,
63    allows_registering
64);
65
66crate::impl_registry!(
67    PotionRegistry,
68    Potion,
69    potions_by_id,
70    potions_by_key,
71    potions
72);
73crate::impl_tagged_registry!(PotionRegistry, potions_by_key, "potion");
74
75#[cfg(test)]
76mod tests {
77    use steel_utils::Identifier;
78
79    use crate::init_vanilla_registry;
80    use crate::{REGISTRY, RegistryExt, TaggedRegistryExt, potion::Potion};
81
82    static FIRST_DUPLICATE: Potion =
83        Potion::new(Identifier::vanilla_static("duplicate"), "duplicate", &[]);
84    static SECOND_DUPLICATE: Potion =
85        Potion::new(Identifier::vanilla_static("duplicate"), "duplicate", &[]);
86
87    #[test]
88    fn extracted_potions_follow_vanilla_ids_and_effects() {
89        init_vanilla_registry();
90        assert_eq!(REGISTRY.potions.len(), 46);
91        assert_eq!(
92            REGISTRY.potions.by_id(0).map(|potion| &potion.key),
93            Some(&Identifier::vanilla_static("water"))
94        );
95        let long_swiftness = REGISTRY
96            .potions
97            .by_key(&Identifier::vanilla_static("long_swiftness"))
98            .expect("long swiftness should be registered");
99        assert_eq!(long_swiftness.name, "swiftness");
100        let turtle_master = REGISTRY
101            .potions
102            .by_key(&Identifier::vanilla_static("turtle_master"))
103            .expect("turtle master should be registered");
104        assert_eq!(turtle_master.effects.len(), 2);
105        assert_eq!(
106            turtle_master.effects[0].effect.key.path.as_ref(),
107            "slowness"
108        );
109        assert_eq!(
110            turtle_master.effects[1].effect.key.path.as_ref(),
111            "resistance"
112        );
113    }
114
115    #[test]
116    fn vanilla_potion_tags_are_generated_from_builtin_data() {
117        init_vanilla_registry();
118        let tradeable = Identifier::vanilla_static("tradeable");
119        assert!(REGISTRY.potions.get_tag(&tradeable).is_some());
120    }
121
122    #[test]
123    fn tag_membership_and_iteration_follow_duplicate_key_replacement() {
124        let mut registry = super::PotionRegistry::new();
125        let tag = Identifier::vanilla_static("test_tag");
126        registry.register(&FIRST_DUPLICATE);
127        registry.register_tag(tag.clone(), &["duplicate"]);
128        registry.register(&SECOND_DUPLICATE);
129
130        assert!(registry.is_in_tag(&FIRST_DUPLICATE, &tag));
131        assert!(registry.is_in_tag(&SECOND_DUPLICATE, &tag));
132        assert!(
133            registry
134                .iter_tag(&tag)
135                .next()
136                .is_some_and(|entry| std::ptr::eq(entry, &raw const SECOND_DUPLICATE))
137        );
138    }
139}