steel_registry/
decorated_pot_pattern.rs1use std::io::{Cursor, Result as IoResult, Write};
4
5use rustc_hash::FxHashMap;
6use simdnbt::owned::{NbtCompound, NbtTag};
7use simdnbt::{FromNbtTag, ToNbtTag};
8use steel_utils::Identifier;
9use steel_utils::hash::{ComponentHasher, HashComponent, HashEntry};
10use steel_utils::serial::{ReadFrom, WriteTo};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct DecoratedPotPatternValue {
17 asset_id: Identifier,
18}
19
20impl DecoratedPotPatternValue {
21 #[must_use]
22 pub const fn new(asset_id: Identifier) -> Self {
23 Self { asset_id }
24 }
25
26 #[must_use]
27 pub const fn asset_id(&self) -> &Identifier {
28 &self.asset_id
29 }
30
31 fn to_nbt_tag_ref(&self) -> NbtTag {
32 let mut compound = NbtCompound::new();
33 compound.insert("asset_id", self.asset_id.clone());
34 NbtTag::Compound(compound)
35 }
36}
37
38impl WriteTo for DecoratedPotPatternValue {
39 fn write(&self, writer: &mut impl Write) -> IoResult<()> {
40 self.asset_id.write(writer)
41 }
42}
43
44impl ReadFrom for DecoratedPotPatternValue {
45 fn read(data: &mut Cursor<&[u8]>) -> IoResult<Self> {
46 Ok(Self::new(Identifier::read(data)?))
47 }
48}
49
50impl ToNbtTag for DecoratedPotPatternValue {
51 fn to_nbt_tag(self) -> NbtTag {
52 self.to_nbt_tag_ref()
53 }
54}
55
56impl FromNbtTag for DecoratedPotPatternValue {
57 fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
58 let compound = tag.compound()?;
59 let asset_id = Identifier::from_nbt_tag(compound.get("asset_id")?)?;
60 Some(Self::new(asset_id))
61 }
62}
63
64impl HashComponent for DecoratedPotPatternValue {
65 fn hash_component(&self, hasher: &mut ComponentHasher) {
66 let mut key_hasher = ComponentHasher::new();
67 key_hasher.put_string("asset_id");
68 let mut value_hasher = ComponentHasher::new();
69 self.asset_id.hash_component(&mut value_hasher);
70 let entry = HashEntry::new(key_hasher, value_hasher);
71
72 hasher.start_map();
73 hasher.put_raw_bytes(&entry.key_bytes);
74 hasher.put_raw_bytes(&entry.value_bytes);
75 hasher.end_map();
76 }
77}
78
79#[derive(Debug)]
81pub struct DecoratedPotPattern {
82 pub key: Identifier,
83 value: DecoratedPotPatternValue,
84}
85
86impl DecoratedPotPattern {
87 #[must_use]
88 pub const fn new(key: Identifier, value: DecoratedPotPatternValue) -> Self {
89 Self { key, value }
90 }
91
92 #[must_use]
93 pub const fn value(&self) -> &DecoratedPotPatternValue {
94 &self.value
95 }
96}
97
98impl ToNbtTag for &DecoratedPotPattern {
99 fn to_nbt_tag(self) -> NbtTag {
100 self.value.to_nbt_tag_ref()
101 }
102}
103
104pub type DecoratedPotPatternRef = &'static DecoratedPotPattern;
105
106pub struct DecoratedPotPatternRegistry {
107 patterns_by_id: Vec<DecoratedPotPatternRef>,
108 patterns_by_key: FxHashMap<Identifier, usize>,
109 allows_registering: bool,
110}
111
112impl DecoratedPotPatternRegistry {
113 #[must_use]
114 pub fn new() -> Self {
115 Self {
116 patterns_by_id: Vec::new(),
117 patterns_by_key: FxHashMap::default(),
118 allows_registering: true,
119 }
120 }
121}
122
123crate::impl_standard_methods!(
124 DecoratedPotPatternRegistry,
125 DecoratedPotPatternRef,
126 patterns_by_id,
127 patterns_by_key,
128 allows_registering
129);
130
131crate::impl_registry!(
132 DecoratedPotPatternRegistry,
133 DecoratedPotPattern,
134 patterns_by_id,
135 patterns_by_key,
136 decorated_pot_patterns
137);
138
139#[cfg(test)]
140mod tests {
141 use std::io::Cursor;
142
143 use simdnbt::borrow::read_tag;
144 use simdnbt::{FromNbtTag as _, ToNbtTag as _};
145 use steel_utils::hash::HashComponent as _;
146 use steel_utils::serial::{ReadFrom as _, WriteTo as _};
147
148 use super::DecoratedPotPatternValue;
149 use crate::init_vanilla_registry;
150 use crate::{REGISTRY, vanilla_decorated_pot_patterns};
151
152 fn parse(tag: simdnbt::owned::NbtTag) -> Option<DecoratedPotPatternValue> {
153 let mut bytes = Vec::new();
154 tag.write(&mut bytes);
155 let borrowed = read_tag(&mut Cursor::new(bytes.as_slice())).ok()?;
156 DecoratedPotPatternValue::from_nbt_tag(borrowed.as_tag())
157 }
158
159 #[test]
160 fn generated_patterns_are_registered() {
161 init_vanilla_registry();
162 assert!(
163 REGISTRY
164 .decorated_pot_patterns
165 .iter()
166 .any(|(_, pattern)| pattern.key.path.as_ref() == "angler")
167 );
168 }
169
170 #[test]
171 fn direct_codecs_and_hash_match_vanilla_shape() {
172 init_vanilla_registry();
173 let pattern = vanilla_decorated_pot_patterns::ANGLER.value().clone();
174 let mut network = Vec::new();
175 pattern.write(&mut network).expect("pattern should encode");
176 assert_eq!(
177 DecoratedPotPatternValue::read(&mut Cursor::new(network.as_slice()))
178 .expect("pattern should decode"),
179 pattern
180 );
181
182 let nbt = pattern.clone().to_nbt_tag();
183 assert_eq!(parse(nbt.clone()), Some(pattern.clone()));
184 assert_eq!(pattern.compute_hash(), nbt.compute_hash());
185 }
186}