Skip to main content

steel_registry/
shared_structs.rs

1use std::{collections::BTreeMap, str::FromStr};
2
3use serde::{Deserialize, Deserializer, de::Error as _};
4use simdnbt::ToNbtTag;
5use simdnbt::owned::{NbtCompound, NbtList, NbtTag};
6use steel_utils::Identifier;
7
8/// Block state data as encoded by vanilla registry JSON.
9#[derive(Debug, Clone, Deserialize)]
10#[serde(deny_unknown_fields)]
11pub struct BlockStateData {
12    /// Block identifier.
13    #[serde(rename = "Name")]
14    pub name: Identifier,
15    /// String-valued block-state properties.
16    #[serde(rename = "Properties", default)]
17    pub properties: BTreeMap<String, String>,
18}
19
20/// Fluid state data as encoded by vanilla registry JSON.
21#[derive(Debug, Clone, Deserialize)]
22#[serde(deny_unknown_fields)]
23pub struct FluidStateData {
24    /// Fluid identifier.
25    #[serde(rename = "Name")]
26    pub name: Identifier,
27    /// String-valued fluid-state properties.
28    #[serde(rename = "Properties", default)]
29    pub properties: BTreeMap<String, String>,
30}
31
32pub fn deserialize_tag_identifier<'de, D: Deserializer<'de>>(
33    deserializer: D,
34) -> Result<Identifier, D::Error> {
35    let value = String::deserialize(deserializer)?;
36    let tag = value.strip_prefix('#').unwrap_or(&value);
37    Identifier::from_str(tag).map_err(D::Error::custom)
38}
39
40pub fn deserialize_optional_tag_identifier<'de, D: Deserializer<'de>>(
41    deserializer: D,
42) -> Result<Option<Identifier>, D::Error> {
43    let Some(value) = Option::<String>::deserialize(deserializer)? else {
44        return Ok(None);
45    };
46    let tag = value.strip_prefix('#').unwrap_or(&value);
47    Identifier::from_str(tag)
48        .map(Some)
49        .map_err(D::Error::custom)
50}
51
52/// A single entry in the list of spawn conditions.
53#[derive(Debug)]
54pub struct SpawnConditionEntry {
55    pub priority: i32,
56    pub condition: Option<BiomeCondition>,
57}
58
59impl ToNbtTag for &SpawnConditionEntry {
60    fn to_nbt_tag(self) -> NbtTag {
61        let mut e = NbtCompound::new();
62        e.insert("priority", self.priority);
63        if let Some(cond) = &self.condition {
64            e.insert("condition", cond.to_nbt_tag());
65        }
66        NbtTag::Compound(e)
67    }
68}
69
70/// Defines a condition based on a biome or list of biomes.
71#[derive(Debug)]
72pub struct BiomeCondition {
73    pub condition_type: &'static str,
74    pub biomes: &'static str,
75}
76
77impl ToNbtTag for &BiomeCondition {
78    fn to_nbt_tag(self) -> NbtTag {
79        let mut c = NbtCompound::new();
80        c.insert("type", self.condition_type);
81        c.insert("biomes", self.biomes);
82        NbtTag::Compound(c)
83    }
84}
85
86/// Serialize a `spawn_conditions` list into the enclosing compound.
87/// Matches vanilla's `[{priority, condition?}, …]` shape exactly.
88pub fn insert_spawn_conditions(compound: &mut NbtCompound, entries: &[SpawnConditionEntry]) {
89    let list: Vec<NbtCompound> = entries
90        .iter()
91        .map(|entry| {
92            let mut e = NbtCompound::new();
93            e.insert("priority", entry.priority);
94            if let Some(cond) = &entry.condition {
95                e.insert("condition", cond.to_nbt_tag());
96            }
97            e
98        })
99        .collect();
100    compound.insert("spawn_conditions", NbtTag::List(NbtList::Compound(list)));
101}