Skip to main content

steel_registry/data_components/components/
provides_pottery_pattern.rs

1//! Vanilla `minecraft:provides_pottery_pattern` item component.
2
3use std::io::{Cursor, Error, Result, Write};
4use std::str::FromStr;
5
6use simdnbt::{FromNbtTag, ToNbtTag};
7use steel_utils::Identifier;
8use steel_utils::codec::VarInt;
9use steel_utils::hash::{ComponentHasher, HashComponent};
10use steel_utils::serial::{ReadFrom, WriteTo};
11
12use crate::decorated_pot_pattern::DecoratedPotPatternRef;
13use crate::{REGISTRY, RegistryEntry, RegistryExt};
14
15/// Decorated pot pattern supplied by a pottery sherd item.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct ProvidesPotteryPattern {
18    pub pattern: DecoratedPotPatternRef,
19}
20
21impl WriteTo for ProvidesPotteryPattern {
22    fn write(&self, writer: &mut impl Write) -> Result<()> {
23        let id = self.pattern.try_id().ok_or_else(|| {
24            Error::other(format!(
25                "Unknown decorated pot pattern: {}",
26                self.pattern.key
27            ))
28        })?;
29        let id = i32::try_from(id)
30            .map_err(|_| Error::other(format!("Decorated pot pattern id out of range: {id}")))?;
31        VarInt(id).write(writer)
32    }
33}
34
35impl ReadFrom for ProvidesPotteryPattern {
36    fn read(data: &mut Cursor<&[u8]>) -> Result<Self> {
37        let id = VarInt::read(data)?.0;
38        let id = usize::try_from(id)
39            .map_err(|_| Error::other(format!("Negative decorated pot pattern id: {id}")))?;
40        let pattern = REGISTRY
41            .decorated_pot_patterns
42            .by_id(id)
43            .ok_or_else(|| Error::other(format!("Unknown decorated pot pattern id: {id}")))?;
44        Ok(Self { pattern })
45    }
46}
47
48impl ToNbtTag for ProvidesPotteryPattern {
49    fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
50        self.pattern.key.to_string().to_nbt_tag()
51    }
52}
53
54impl FromNbtTag for ProvidesPotteryPattern {
55    fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
56        let key = Identifier::from_str(&tag.string()?.to_str()).ok()?;
57        REGISTRY
58            .decorated_pot_patterns
59            .by_key(&key)
60            .map(|pattern| Self { pattern })
61    }
62}
63
64impl HashComponent for ProvidesPotteryPattern {
65    fn hash_component(&self, hasher: &mut ComponentHasher) {
66        hasher.put_string(&self.pattern.key.to_string());
67    }
68}
69
70#[cfg(test)]
71mod tests {
72    use std::io::Cursor;
73
74    use simdnbt::borrow::read_tag;
75    use simdnbt::{FromNbtTag as _, ToNbtTag as _};
76    use steel_utils::serial::{ReadFrom as _, WriteTo as _};
77
78    use super::ProvidesPotteryPattern;
79    use crate::data_components::vanilla_components::PROVIDES_POTTERY_PATTERN;
80    use crate::init_vanilla_registry;
81    use crate::item_stack::ItemStack;
82    use crate::{REGISTRY, vanilla_decorated_pot_patterns, vanilla_items};
83
84    fn parse(tag: simdnbt::owned::NbtTag) -> Option<ProvidesPotteryPattern> {
85        let mut bytes = Vec::new();
86        tag.write(&mut bytes);
87        let borrowed = read_tag(&mut Cursor::new(bytes.as_slice())).ok()?;
88        ProvidesPotteryPattern::from_nbt_tag(borrowed.as_tag())
89    }
90
91    #[test]
92    fn round_trips_both_codecs_and_hashes_by_key() {
93        init_vanilla_registry();
94        let component = ProvidesPotteryPattern {
95            pattern: &vanilla_decorated_pot_patterns::ANGLER,
96        };
97
98        let mut network = Vec::new();
99        component
100            .write(&mut network)
101            .expect("pottery pattern should encode");
102        assert_eq!(
103            ProvidesPotteryPattern::read(&mut Cursor::new(network.as_slice()))
104                .expect("pottery pattern should decode"),
105            component
106        );
107
108        let nbt = component.clone().to_nbt_tag();
109        assert_eq!(
110            nbt,
111            simdnbt::owned::NbtTag::String("minecraft:angler".into())
112        );
113        assert_eq!(parse(nbt), Some(component));
114    }
115
116    #[test]
117    fn extracted_sherd_item_provides_its_pattern() {
118        init_vanilla_registry();
119        let sherd = ItemStack::new(&vanilla_items::ANGLER_POTTERY_SHERD);
120        let component = sherd
121            .get(PROVIDES_POTTERY_PATTERN)
122            .expect("angler pottery sherd should provide a pattern");
123        assert_eq!(
124            component.pattern.key,
125            vanilla_decorated_pot_patterns::ANGLER.key
126        );
127        assert_eq!(
128            REGISTRY
129                .items
130                .iter()
131                .filter(|(_, item)| item.components.has(PROVIDES_POTTERY_PATTERN))
132                .count(),
133            23
134        );
135    }
136}