1use std::{collections::HashMap, io::Cursor};
9
10use indexmap::IndexMap;
11use simdnbt::{
12 Deserialize, FromNbtTag, Serialize, ToNbtTag,
13 owned::{NbtCompound, NbtTag},
14};
15use tracing::error;
16
17use crate::resource_location::ResourceLocation;
18
19#[derive(Default, Debug, Clone)]
28pub struct RegistryHolder {
29 pub map: HashMap<ResourceLocation, IndexMap<ResourceLocation, NbtCompound>>,
30}
31
32impl RegistryHolder {
33 pub fn append(
34 &mut self,
35 id: ResourceLocation,
36 entries: Vec<(ResourceLocation, Option<NbtCompound>)>,
37 ) {
38 let map = self.map.entry(id).or_default();
39 for (key, value) in entries {
40 if let Some(value) = value {
41 map.insert(key, value);
42 } else {
43 map.shift_remove(&key);
44 }
45 }
46 }
47
48 pub fn dimension_type(&self) -> Option<RegistryType<DimensionTypeElement>> {
52 let name = ResourceLocation::new("minecraft:dimension_type");
53 match self.get(&name) {
54 Some(Ok(registry)) => Some(registry),
55 Some(Err(err)) => {
56 error!(
57 "Error deserializing dimension type registry: {err:?}\n{:?}",
58 self.map.get(&name)
59 );
60 None
61 }
62 None => None,
63 }
64 }
65
66 fn get<T: Deserialize>(
67 &self,
68 name: &ResourceLocation,
69 ) -> Option<Result<RegistryType<T>, simdnbt::DeserializeError>> {
70 let mut map = HashMap::new();
74
75 for (key, value) in self.map.get(name)? {
76 let mut nbt_bytes = Vec::new();
78 value.write(&mut nbt_bytes);
79 let nbt_borrow_compound =
80 simdnbt::borrow::read_compound(&mut Cursor::new(&nbt_bytes)).ok()?;
81 let value = match T::from_compound((&nbt_borrow_compound).into()) {
82 Ok(value) => value,
83 Err(err) => {
84 return Some(Err(err));
85 }
86 };
87
88 map.insert(key.clone(), value);
89 }
90
91 Some(Ok(RegistryType { map }))
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct RegistryType<T> {
98 pub map: HashMap<ResourceLocation, T>,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
102#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
103pub struct TrimMaterialElement {
104 pub asset_name: String,
105 pub ingredient: ResourceLocation,
106 pub item_model_index: f32,
107 pub override_armor_materials: HashMap<String, String>,
108 pub description: Option<String>,
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
114pub struct ChatTypeElement {
115 pub chat: ChatTypeData,
116 pub narration: ChatTypeData,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
122pub struct ChatTypeData {
123 pub translation_key: String,
124 pub parameters: Vec<String>,
125 pub style: Option<ChatTypeStyle>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
131pub struct ChatTypeStyle {
132 pub color: Option<String>,
133 pub bold: Option<bool>,
134 pub italic: Option<bool>,
135 pub underlined: Option<bool>,
136 pub strikethrough: Option<bool>,
137 pub obfuscated: Option<bool>,
138}
139
140#[cfg(feature = "strict_registry")]
142#[derive(Debug, Clone, Serialize, Deserialize)]
143#[simdnbt(deny_unknown_fields)]
144pub struct DimensionTypeElement {
145 pub ambient_light: f32,
146 pub bed_works: bool,
147 pub coordinate_scale: f32,
148 pub effects: ResourceLocation,
149 pub fixed_time: Option<u32>,
150 pub has_ceiling: bool,
151 pub has_raids: bool,
152 pub has_skylight: bool,
153 pub height: u32,
154 pub infiniburn: ResourceLocation,
155 pub logical_height: u32,
156 pub min_y: i32,
157 pub monster_spawn_block_light_limit: u32,
158 pub monster_spawn_light_level: MonsterSpawnLightLevel,
159 pub natural: bool,
160 pub piglin_safe: bool,
161 pub respawn_anchor_works: bool,
162 pub ultrawarm: Option<bool>,
163}
164
165#[cfg(not(feature = "strict_registry"))]
167#[derive(Debug, Clone, Serialize, Deserialize)]
168pub struct DimensionTypeElement {
169 pub height: u32,
170 pub min_y: i32,
171 pub ultrawarm: Option<bool>,
172 #[simdnbt(flatten)]
173 pub _extra: HashMap<String, NbtTag>,
174}
175
176#[derive(Debug, Clone)]
181pub enum MonsterSpawnLightLevel {
183 Simple(u32),
185 Complex {
188 kind: ResourceLocation,
189 value: MonsterSpawnLightLevelValues,
190 },
191}
192
193impl FromNbtTag for MonsterSpawnLightLevel {
194 fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
195 if let Some(value) = tag.int() {
196 Some(Self::Simple(value as u32))
197 } else if let Some(value) = tag.compound() {
198 let kind = ResourceLocation::from_nbt_tag(value.get("type")?)?;
199 let value = MonsterSpawnLightLevelValues::from_nbt_tag(value.get("value")?)?;
200 Some(Self::Complex { kind, value })
201 } else {
202 None
203 }
204 }
205}
206
207impl ToNbtTag for MonsterSpawnLightLevel {
208 fn to_nbt_tag(self) -> simdnbt::owned::NbtTag {
209 match self {
210 Self::Simple(value) => value.to_nbt_tag(),
211 Self::Complex { kind, value } => {
212 let mut compound = NbtCompound::new();
213 compound.insert("type", kind.to_nbt_tag());
214 compound.insert("value", value.to_nbt_tag());
215 simdnbt::owned::NbtTag::Compound(compound)
216 }
217 }
218 }
219}
220
221#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
225#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
226pub struct MonsterSpawnLightLevelValues {
227 #[simdnbt(rename = "min_inclusive")]
228 pub min: u32,
229 #[simdnbt(rename = "max_inclusive")]
230 pub max: u32,
231}
232
233#[derive(Debug, Clone, Serialize, Deserialize)]
235#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
236pub struct WorldTypeElement {
237 pub has_precipitation: bool,
238 pub temperature: f32,
239 pub temperature_modifier: Option<String>,
240 pub downfall: f32,
241 pub effects: BiomeEffects,
242}
243
244#[derive(Debug, PartialEq, Eq, Copy, Clone)]
246pub enum BiomePrecipitation {
247 None,
248 Rain,
249 Snow,
250}
251impl FromNbtTag for BiomePrecipitation {
252 fn from_nbt_tag(tag: simdnbt::borrow::NbtTag) -> Option<Self> {
253 match tag.string()?.to_str().as_ref() {
254 "none" => Some(Self::None),
255 "rain" => Some(Self::Rain),
256 "snow" => Some(Self::Snow),
257 _ => None,
258 }
259 }
260}
261impl ToNbtTag for BiomePrecipitation {
262 fn to_nbt_tag(self) -> NbtTag {
263 match self {
264 Self::None => NbtTag::String("none".into()),
265 Self::Rain => NbtTag::String("rain".into()),
266 Self::Snow => NbtTag::String("snow".into()),
267 }
268 }
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
276#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
277pub struct BiomeEffects {
278 pub sky_color: u32,
279 pub fog_color: u32,
280 pub water_color: u32,
281 pub water_fog_color: u32,
282 pub foliage_color: Option<u32>,
283 pub grass_color: Option<u32>,
284 pub grass_color_modifier: Option<String>,
285 pub music: Option<BiomeMusic>,
286 pub mood_sound: BiomeMoodSound,
287 pub additions_sound: Option<AdditionsSound>,
288 pub ambient_sound: Option<ResourceLocation>,
289 pub particle: Option<BiomeParticle>,
290}
291
292#[derive(Debug, Clone, Serialize, Deserialize)]
296#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
297pub struct BiomeMusic {
298 pub replace_current_music: bool,
299 pub max_delay: u32,
300 pub min_delay: u32,
301 pub sound: azalea_registry::SoundEvent,
302}
303
304#[derive(Debug, Clone, Serialize, Deserialize)]
305#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
306pub struct BiomeMoodSound {
307 pub tick_delay: u32,
308 pub block_search_extent: u32,
309 pub offset: f32,
310 pub sound: azalea_registry::SoundEvent,
311}
312
313#[derive(Debug, Clone, Serialize, Deserialize)]
314#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
315pub struct AdditionsSound {
316 pub tick_chance: f32,
317 pub sound: azalea_registry::SoundEvent,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
324#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
325pub struct BiomeParticle {
326 pub probability: f32,
327 pub options: HashMap<String, String>,
328}
329
330#[derive(Debug, Clone, Serialize, Deserialize)]
331#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
332pub struct TrimPatternElement {
333 #[simdnbt(flatten)]
334 pub pattern: HashMap<String, String>,
335}
336
337#[derive(Debug, Clone, Serialize, Deserialize)]
338#[cfg_attr(feature = "strict_registry", simdnbt(deny_unknown_fields))]
339pub struct DamageTypeElement {
340 pub message_id: String,
341 pub scaling: String,
342 pub exhaustion: f32,
343 pub effects: Option<String>,
344 pub death_message_type: Option<String>,
345}