Skip to main content

steel_registry/data_components/components/
rarity.rs

1//! Vanilla `minecraft:rarity` item component.
2
3use std::io::{Cursor, Result, Write};
4
5use simdnbt::owned::NbtTag;
6use simdnbt::{FromNbtTag, ToNbtTag};
7use steel_utils::codec::VarInt;
8use steel_utils::hash::{ComponentHasher, HashComponent};
9use steel_utils::serial::{ReadFrom, WriteTo};
10use text_components::format::Color;
11
12/// Vanilla item rarity, including its serialized and network IDs.
13#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
14pub enum Rarity {
15    #[default]
16    Common,
17    Uncommon,
18    Rare,
19    Epic,
20}
21
22impl Rarity {
23    #[must_use]
24    pub const fn serialized_name(self) -> &'static str {
25        match self {
26            Self::Common => "common",
27            Self::Uncommon => "uncommon",
28            Self::Rare => "rare",
29            Self::Epic => "epic",
30        }
31    }
32
33    #[must_use]
34    pub const fn color(self) -> Color {
35        match self {
36            Self::Common => Color::White,
37            Self::Uncommon => Color::Yellow,
38            Self::Rare => Color::Aqua,
39            Self::Epic => Color::LightPurple,
40        }
41    }
42
43    const fn network_id(self) -> i32 {
44        match self {
45            Self::Common => 0,
46            Self::Uncommon => 1,
47            Self::Rare => 2,
48            Self::Epic => 3,
49        }
50    }
51
52    const fn from_network_id(id: i32) -> Self {
53        match id {
54            1 => Self::Uncommon,
55            2 => Self::Rare,
56            3 => Self::Epic,
57            _ => Self::Common,
58        }
59    }
60
61    const fn from_serialized_name(name: &str) -> Option<Self> {
62        match name {
63            "common" => Some(Self::Common),
64            "uncommon" => Some(Self::Uncommon),
65            "rare" => Some(Self::Rare),
66            "epic" => Some(Self::Epic),
67            _ => None,
68        }
69    }
70}
71
72impl WriteTo for Rarity {
73    fn write(&self, writer: &mut impl Write) -> Result<()> {
74        VarInt(self.network_id()).write(writer)
75    }
76}
77
78impl ReadFrom for Rarity {
79    fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
80        Ok(Self::from_network_id(VarInt::read(data)?.0))
81    }
82}
83
84impl ToNbtTag for Rarity {
85    fn to_nbt_tag(self) -> NbtTag {
86        self.serialized_name().to_nbt_tag()
87    }
88}
89
90impl FromNbtTag for Rarity {
91    fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
92        Self::from_serialized_name(&tag.string()?.to_str())
93    }
94}
95
96impl HashComponent for Rarity {
97    fn hash_component(&self, hasher: &mut ComponentHasher) {
98        hasher.put_string(self.serialized_name());
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use std::io::Cursor;
105
106    use steel_utils::codec::VarInt;
107    use steel_utils::serial::{ReadFrom as _, WriteTo as _};
108
109    use super::Rarity;
110
111    #[test]
112    fn network_ids_match_vanilla_and_fall_back_to_common() {
113        for (rarity, expected_id) in [
114            (Rarity::Common, 0),
115            (Rarity::Uncommon, 1),
116            (Rarity::Rare, 2),
117            (Rarity::Epic, 3),
118        ] {
119            let mut encoded = Vec::new();
120            rarity.write(&mut encoded).expect("rarity should encode");
121            let mut cursor = Cursor::new(encoded.as_slice());
122            assert_eq!(
123                VarInt::read(&mut cursor).expect("id should decode").0,
124                expected_id
125            );
126        }
127
128        for id in [-1, 4, i32::MAX] {
129            let mut encoded = Vec::new();
130            VarInt(id).write(&mut encoded).expect("id should encode");
131            assert_eq!(
132                Rarity::read(&mut Cursor::new(encoded.as_slice())).expect("rarity should decode"),
133                Rarity::Common
134            );
135        }
136    }
137}