Skip to main content

steel_registry/
pig_variant.rs

1use steel_utils::random::Random;
2
3use crate::biome::BiomeRef;
4use crate::shared_structs::{
5    SpawnConditionEntry, insert_spawn_conditions, pick_spawn_conditioned_entry,
6};
7use rustc_hash::FxHashMap;
8use simdnbt::ToNbtTag;
9use simdnbt::owned::NbtTag;
10use steel_utils::Identifier;
11
12/// Represents a full pig variant definition from a data pack JSON file.
13#[derive(Debug)]
14pub struct PigVariant {
15    pub key: Identifier,
16    pub asset_id: Identifier,
17    pub baby_asset_id: Identifier,
18    pub model: PigModelType,
19    pub spawn_conditions: &'static [SpawnConditionEntry],
20}
21
22/// The model type for the pig, which can affect its shape.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
24pub enum PigModelType {
25    #[default]
26    Normal,
27    Cold,
28}
29
30impl ToNbtTag for &PigVariant {
31    fn to_nbt_tag(self) -> NbtTag {
32        use simdnbt::owned::{NbtCompound, NbtTag};
33        let mut compound = NbtCompound::new();
34        compound.insert("asset_id", self.asset_id.clone());
35        compound.insert("baby_asset_id", self.baby_asset_id.clone());
36        compound.insert(
37            "model",
38            match self.model {
39                PigModelType::Normal => "normal",
40                PigModelType::Cold => "cold",
41            },
42        );
43        insert_spawn_conditions(&mut compound, self.spawn_conditions);
44        NbtTag::Compound(compound)
45    }
46}
47
48pub type PigVariantRef = &'static PigVariant;
49
50pub struct PigVariantRegistry {
51    pig_variants_by_id: Vec<PigVariantRef>,
52    pig_variants_by_key: FxHashMap<Identifier, usize>,
53    allows_registering: bool,
54}
55
56impl PigVariantRegistry {
57    #[must_use]
58    pub fn new() -> Self {
59        Self {
60            pig_variants_by_id: Vec::new(),
61            pig_variants_by_key: FxHashMap::default(),
62            allows_registering: true,
63        }
64    }
65
66    #[must_use]
67    pub fn select_spawn_variant(
68        &self,
69        biome: BiomeRef,
70        random: &mut impl Random,
71    ) -> Option<PigVariantRef> {
72        pick_spawn_conditioned_entry(
73            self.iter().map(|(_, variant)| variant),
74            |variant| variant.spawn_conditions,
75            biome,
76            random,
77        )
78    }
79}
80
81crate::impl_standard_methods!(
82    PigVariantRegistry,
83    PigVariantRef,
84    pig_variants_by_id,
85    pig_variants_by_key,
86    allows_registering
87);
88
89crate::impl_registry!(
90    PigVariantRegistry,
91    PigVariant,
92    pig_variants_by_id,
93    pig_variants_by_key,
94    pig_variants
95);
96
97#[cfg(test)]
98mod tests {
99    use steel_utils::random::legacy_random::LegacyRandom;
100
101    use crate::{REGISTRY, init_vanilla_registry, vanilla_biomes, vanilla_pig_variants};
102
103    #[test]
104    fn select_spawn_variant_uses_highest_matching_biome_priority() {
105        init_vanilla_registry();
106
107        let mut random = LegacyRandom::from_seed(0);
108        assert_eq!(
109            REGISTRY
110                .pig_variants
111                .select_spawn_variant(&vanilla_biomes::DESERT, &mut random)
112                .map(|variant| &variant.key),
113            Some(&vanilla_pig_variants::WARM.key)
114        );
115
116        let mut random = LegacyRandom::from_seed(0);
117        assert_eq!(
118            REGISTRY
119                .pig_variants
120                .select_spawn_variant(&vanilla_biomes::SNOWY_PLAINS, &mut random)
121                .map(|variant| &variant.key),
122            Some(&vanilla_pig_variants::COLD.key)
123        );
124
125        let mut random = LegacyRandom::from_seed(0);
126        assert_eq!(
127            REGISTRY
128                .pig_variants
129                .select_spawn_variant(&vanilla_biomes::PLAINS, &mut random)
130                .map(|variant| &variant.key),
131            Some(&vanilla_pig_variants::TEMPERATE.key)
132        );
133    }
134}