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