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