steel_registry/data_components/components/
provides_pottery_pattern.rs1use 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#[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}