azalea_core/registry_holder/
mod.rs1pub mod block_predicate;
9pub mod block_state_provider;
10pub mod components;
11pub mod dimension_type;
12pub mod enchantment;
13pub mod entity_effect;
14pub mod float_provider;
15pub mod value;
16
17use std::{collections::HashMap, io::Cursor};
18
19use azalea_registry::identifier::Identifier;
20use indexmap::IndexMap;
21use simdnbt::{DeserializeError, FromNbtTag, borrow, owned::NbtCompound};
22use thiserror::Error;
23use tracing::error;
24
25#[derive(Default, Debug, Clone)]
34pub struct RegistryHolder {
35 #[rustfmt::skip] pub dimension_type: RegistryType<dimension_type::DimensionKindElement>,
42
43 pub enchantment: RegistryType<enchantment::EnchantmentData>,
44
45 pub extra: HashMap<Identifier, RegistryType<NbtCompound>>,
50}
51
52macro_rules! registry_holder {
53 ($($registry:ident),* $(,)?) => {
54 impl RegistryHolder {
55 pub fn append(
56 &mut self,
57 id: Identifier,
58 entries: Vec<(Identifier, Option<NbtCompound>)>,
59 ) {
60
61 if id.namespace() == "minecraft" {
62 match id.path() {
63 $(
64 stringify!($registry) => {
65 return self.$registry.append_nbt(id, entries);
66 }
67 )*
68 _ => {}
69 }
70 }
71
72 self.extra
73 .entry(id.clone())
74 .or_default()
75 .append_nbt(id, entries);
76 }
77
78 pub fn extend(&mut self, other: RegistryHolder) {
79 $(
80 self.$registry = other.$registry;
81 )*
82 self.extra.extend(other.extra);
83 }
84
85 pub fn protocol_id_to_identifier(
89 &self,
90 registry: Identifier,
91 protocol_id: u32,
92 ) -> Option<&Identifier> {
93 let index = protocol_id as usize;
94
95 if registry.namespace() == "minecraft" {
96 match registry.path() {
97 $(
98 stringify!($registry) => {
99 return self.$registry.map.get_index(index).map(|(k, _)| k);
100 }
101 )*
102 _ => {}
103 }
104 }
105
106 self.extra
107 .get(®istry)
108 .and_then(|r| r.map.get_index(index))
109 .map(|(k, _)| k)
110 }
111 }
112 };
113}
114
115registry_holder!(dimension_type, enchantment);
116
117fn nbt_to_serializable_type<T: simdnbt::Deserialize>(
118 value: &NbtCompound,
119) -> Result<T, NbtToSerializableTypeError> {
120 let mut nbt_bytes = Vec::new();
122 value.write(&mut nbt_bytes);
123 let nbt_borrow_compound = simdnbt::borrow::read_compound(&mut Cursor::new(&nbt_bytes))?;
124 T::from_compound((&nbt_borrow_compound).into()).map_err(Into::into)
125}
126
127#[derive(Error, Debug)]
128enum NbtToSerializableTypeError {
129 #[error(transparent)]
130 NbtError(#[from] simdnbt::Error),
131 #[error(transparent)]
132 DeserializeError(#[from] simdnbt::DeserializeError),
133}
134
135#[derive(Debug, Clone)]
137pub struct RegistryType<T: simdnbt::Deserialize> {
138 pub map: IndexMap<Identifier, T>,
139}
140
141impl<T: simdnbt::Deserialize> Default for RegistryType<T> {
142 fn default() -> Self {
143 Self {
144 map: IndexMap::new(),
145 }
146 }
147}
148
149impl<T: simdnbt::Deserialize> RegistryType<T> {
150 fn append_nbt(&mut self, id: Identifier, entries: Vec<(Identifier, Option<NbtCompound>)>) {
151 let map = &mut self.map;
152 for (key, value) in entries {
153 if let Some(value) = value {
154 match nbt_to_serializable_type(&value) {
155 Ok(value) => {
156 map.insert(key, value);
157 }
158 Err(err) => {
159 error!("Error deserializing {id} entry {key}: {err:?}\n{value:?}");
160 }
161 }
162 } else {
163 map.shift_remove(&key);
164 }
165 }
166 }
167}
168
169pub trait RegistryDeserializesTo: simdnbt::Deserialize {
170 fn get_for_registry<'a>(
171 registries: &'a RegistryHolder,
172 registry_name: &'static str,
173 protocol_id: u32,
174 ) -> Option<(&'a Identifier, &'a Self)>;
175}
176
177impl RegistryDeserializesTo for NbtCompound {
178 fn get_for_registry<'a>(
179 registries: &'a RegistryHolder,
180 registry_name: &'static str,
181 protocol_id: u32,
182 ) -> Option<(&'a Identifier, &'a Self)> {
183 registries
184 .extra
185 .get(&Identifier::new(registry_name))?
186 .map
187 .get_index(protocol_id as usize)
188 }
189}
190impl RegistryDeserializesTo for dimension_type::DimensionKindElement {
191 fn get_for_registry<'a>(
192 registries: &'a RegistryHolder,
193 registry_name: &'static str,
194 protocol_id: u32,
195 ) -> Option<(&'a Identifier, &'a Self)> {
196 if registry_name != "dimension_type" {
197 error!(
198 "called RegistryDeserializesTo::get_for_registry with the wrong registry: {registry_name}"
199 );
200 }
201 registries
202 .dimension_type
203 .map
204 .get_index(protocol_id as usize)
205 }
206}
207impl RegistryDeserializesTo for enchantment::EnchantmentData {
208 fn get_for_registry<'a>(
209 registries: &'a RegistryHolder,
210 registry_name: &'static str,
211 protocol_id: u32,
212 ) -> Option<(&'a Identifier, &'a Self)> {
213 if registry_name != "enchantment" {
214 error!(
215 "called RegistryDeserializesTo::get_for_registry with the wrong registry: {registry_name}"
216 );
217 }
218 registries.enchantment.map.get_index(protocol_id as usize)
219 }
220}
221
222pub fn get_in_compound<T: FromNbtTag>(
223 compound: &borrow::NbtCompound,
224 key: &str,
225) -> Result<T, DeserializeError> {
226 let value = compound.get(key).ok_or(DeserializeError::MissingField)?;
227 T::from_nbt_tag(value).ok_or(DeserializeError::MissingField)
228}