Skip to main content

steel_registry/structure_processor/
data.rs

1//! Typed structure processor-list codec data.
2
3use serde::{Deserialize, Deserializer, de::Error as _};
4use steel_utils::{Identifier, value_providers::IntProvider};
5
6use crate::shared_structs::{
7    BlockStateData, deserialize_optional_tag_identifier, deserialize_tag_identifier,
8};
9
10/// Codec payload for a structure processor list.
11#[derive(Debug, Clone, Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct StructureProcessorListData {
14    /// Ordered processors.
15    pub processors: Vec<StructureProcessorKind>,
16}
17
18/// A typed vanilla structure processor.
19#[derive(Debug, Clone, Deserialize)]
20#[serde(tag = "processor_type")]
21pub enum StructureProcessorKind {
22    /// Randomly drops input blocks.
23    #[serde(rename = "minecraft:block_rot")]
24    BlockRot {
25        /// Optional tag restricting which blocks may be dropped.
26        #[serde(default, deserialize_with = "deserialize_optional_tag_identifier")]
27        rottable_blocks: Option<Identifier>,
28        /// Keep probability.
29        integrity: f32,
30    },
31    /// Prevents replacement of protected world blocks.
32    #[serde(rename = "minecraft:protected_blocks")]
33    ProtectedBlocks {
34        /// Vanilla field name is `value`; it stores the cannot-replace tag.
35        #[serde(rename = "value", deserialize_with = "deserialize_tag_identifier")]
36        cannot_replace: Identifier,
37    },
38    /// Applies the first matching rule.
39    #[serde(rename = "minecraft:rule")]
40    Rule { rules: Vec<ProcessorRuleData> },
41    /// Ages stone/obsidian structure blocks, used by ruined portals.
42    #[serde(rename = "minecraft:block_age")]
43    BlockAge { mossiness: f32 },
44    /// Keeps non-full structure blocks submerged in existing lava.
45    #[serde(rename = "minecraft:lava_submerged_block")]
46    LavaSubmergedBlock,
47    /// Replaces stone ruin blocks with blackstone variants.
48    #[serde(rename = "minecraft:blackstone_replace")]
49    BlackstoneReplace,
50    /// Delegates to another processor but caps successful modifications.
51    #[serde(rename = "minecraft:capped")]
52    Capped {
53        delegate: Box<StructureProcessorKind>,
54        limit: IntProvider,
55    },
56}
57
58/// One rule inside vanilla's `RuleProcessor`.
59#[derive(Debug, Clone, Deserialize)]
60#[serde(deny_unknown_fields)]
61pub struct ProcessorRuleData {
62    pub input_predicate: StructureRuleTestData,
63    pub location_predicate: StructureRuleTestData,
64    #[serde(default)]
65    pub position_predicate: PosRuleTestData,
66    pub output_state: BlockStateData,
67    #[serde(default)]
68    pub block_entity_modifier: RuleBlockEntityModifierData,
69}
70
71/// Block-state rule tests used by `RuleProcessor`.
72#[derive(Debug, Clone, Deserialize)]
73#[serde(tag = "predicate_type")]
74pub enum StructureRuleTestData {
75    #[serde(rename = "minecraft:always_true")]
76    AlwaysTrue,
77    #[serde(rename = "minecraft:block_match")]
78    BlockMatch { block: Identifier },
79    #[serde(rename = "minecraft:random_block_match")]
80    RandomBlockMatch { block: Identifier, probability: f32 },
81    #[serde(rename = "minecraft:tag_match")]
82    TagMatch { tag: Identifier },
83    #[serde(rename = "minecraft:blockstate_match")]
84    BlockStateMatch { block_state: BlockStateData },
85}
86
87/// Position rule tests used by `RuleProcessor`.
88#[derive(Debug, Clone, Deserialize, Default)]
89#[serde(tag = "predicate_type")]
90pub enum PosRuleTestData {
91    #[default]
92    #[serde(rename = "minecraft:always_true")]
93    AlwaysTrue,
94    #[serde(rename = "minecraft:axis_aligned_linear_pos")]
95    AxisAlignedLinearPos {
96        #[serde(deserialize_with = "deserialize_processor_axis")]
97        axis: StructureProcessorAxis,
98        min_chance: f32,
99        max_chance: f32,
100        min_dist: i32,
101        max_dist: i32,
102    },
103}
104
105/// Axis enum for position predicates.
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum StructureProcessorAxis {
108    X,
109    Y,
110    Z,
111}
112
113fn deserialize_processor_axis<'de, D: Deserializer<'de>>(
114    deserializer: D,
115) -> Result<StructureProcessorAxis, D::Error> {
116    let value = String::deserialize(deserializer)?;
117    match value.as_str() {
118        "x" => Ok(StructureProcessorAxis::X),
119        "y" => Ok(StructureProcessorAxis::Y),
120        "z" => Ok(StructureProcessorAxis::Z),
121        _ => Err(D::Error::custom("invalid structure processor axis")),
122    }
123}
124
125/// Rule block-entity NBT modifiers.
126#[derive(Debug, Clone, Deserialize, Default)]
127#[serde(tag = "type")]
128pub enum RuleBlockEntityModifierData {
129    /// Vanilla passthrough when the field is absent.
130    #[default]
131    Passthrough,
132    /// Appends loot table metadata to the output block entity.
133    #[serde(rename = "minecraft:append_loot")]
134    AppendLoot { loot_table: Identifier },
135}