Skip to main content

steel_core/worldgen/structure/piece_placer/
template_processors.rs

1use std::collections::BTreeMap;
2
3use steel_registry::shared_structs::BlockStateData;
4use steel_registry::structure::{OceanRuinBiomeTempData, RuinedPortalPlacementData};
5use steel_registry::structure_processor::{
6    PosRuleTestData, ProcessorRuleData, RuleBlockEntityModifierData, StructureProcessorKind,
7    StructureRuleTestData,
8};
9use steel_registry::vanilla_block_tags::BlockTag;
10use steel_registry::{Registry, RegistryExt};
11use steel_utils::Identifier;
12use steel_utils::value_providers::IntProvider;
13
14use steel_worldgen::structure::{RuinedPortalProperties, TemplateProcessorList};
15
16use super::StructurePiecePlacer;
17
18impl StructurePiecePlacer {
19    pub(super) fn template_processors<'a>(
20        registry: &'a Registry,
21        processors: &'a TemplateProcessorList,
22        hardcoded_processors: &'a mut Vec<StructureProcessorKind>,
23    ) -> &'a [StructureProcessorKind] {
24        match processors {
25            TemplateProcessorList::Empty => &[],
26            TemplateProcessorList::Registry(key) => {
27                let Some(processor_list) = registry.structure_processors.by_key(key) else {
28                    panic!("template piece references unknown processor list {key}");
29                };
30                &processor_list.data.processors
31            }
32            TemplateProcessorList::OceanRuin {
33                biome_temp,
34                integrity,
35            } => {
36                hardcoded_processors.extend(Self::ocean_ruin_processors(*biome_temp, *integrity));
37                hardcoded_processors.as_slice()
38            }
39            TemplateProcessorList::RuinedPortal {
40                vertical_placement,
41                properties,
42            } => {
43                hardcoded_processors.extend(Self::ruined_portal_processors(
44                    *vertical_placement,
45                    *properties,
46                ));
47                hardcoded_processors.as_slice()
48            }
49        }
50    }
51
52    fn ocean_ruin_processors(
53        biome_temp: OceanRuinBiomeTempData,
54        integrity: f32,
55    ) -> Vec<StructureProcessorKind> {
56        let (source, target, loot_table) = match biome_temp {
57            OceanRuinBiomeTempData::Warm => (
58                "sand",
59                "suspicious_sand",
60                Identifier::vanilla_static("archaeology/ocean_ruin_warm"),
61            ),
62            OceanRuinBiomeTempData::Cold => (
63                "gravel",
64                "suspicious_gravel",
65                Identifier::vanilla_static("archaeology/ocean_ruin_cold"),
66            ),
67        };
68
69        vec![
70            StructureProcessorKind::BlockRot {
71                rottable_blocks: None,
72                integrity,
73            },
74            StructureProcessorKind::Capped {
75                delegate: Box::new(StructureProcessorKind::Rule {
76                    rules: vec![Self::append_loot_replace_rule(source, target, loot_table)],
77                }),
78                limit: IntProvider::Constant(5),
79            },
80        ]
81    }
82
83    fn ruined_portal_processors(
84        vertical_placement: RuinedPortalPlacementData,
85        properties: RuinedPortalProperties,
86    ) -> Vec<StructureProcessorKind> {
87        let mut rules = vec![
88            Self::random_block_replace_rule("gold_block", 0.3, "air"),
89            Self::ruined_portal_lava_rule(vertical_placement, properties),
90        ];
91        if !properties.cold {
92            rules.push(Self::random_block_replace_rule(
93                "netherrack",
94                0.07,
95                "magma_block",
96            ));
97        }
98
99        let mut processors = vec![
100            StructureProcessorKind::Rule { rules },
101            StructureProcessorKind::BlockAge {
102                mossiness: properties.mossiness,
103            },
104            StructureProcessorKind::ProtectedBlocks {
105                cannot_replace: BlockTag::FEATURES_CANNOT_REPLACE,
106            },
107            StructureProcessorKind::LavaSubmergedBlock,
108        ];
109        if properties.replace_with_blackstone {
110            processors.push(StructureProcessorKind::BlackstoneReplace);
111        }
112        processors
113    }
114
115    fn ruined_portal_lava_rule(
116        vertical_placement: RuinedPortalPlacementData,
117        properties: RuinedPortalProperties,
118    ) -> ProcessorRuleData {
119        if vertical_placement == RuinedPortalPlacementData::OnOceanFloor {
120            Self::block_replace_rule("lava", "magma_block")
121        } else if properties.cold {
122            Self::block_replace_rule("lava", "netherrack")
123        } else {
124            Self::random_block_replace_rule("lava", 0.2, "magma_block")
125        }
126    }
127
128    const fn block_replace_rule(source: &'static str, target: &'static str) -> ProcessorRuleData {
129        ProcessorRuleData {
130            input_predicate: StructureRuleTestData::BlockMatch {
131                block: Identifier::vanilla_static(source),
132            },
133            location_predicate: StructureRuleTestData::AlwaysTrue,
134            position_predicate: PosRuleTestData::AlwaysTrue,
135            output_state: Self::block_state_data(target),
136            block_entity_modifier: RuleBlockEntityModifierData::Passthrough,
137        }
138    }
139
140    const fn random_block_replace_rule(
141        source: &'static str,
142        probability: f32,
143        target: &'static str,
144    ) -> ProcessorRuleData {
145        ProcessorRuleData {
146            input_predicate: StructureRuleTestData::RandomBlockMatch {
147                block: Identifier::vanilla_static(source),
148                probability,
149            },
150            location_predicate: StructureRuleTestData::AlwaysTrue,
151            position_predicate: PosRuleTestData::AlwaysTrue,
152            output_state: Self::block_state_data(target),
153            block_entity_modifier: RuleBlockEntityModifierData::Passthrough,
154        }
155    }
156
157    const fn append_loot_replace_rule(
158        source: &'static str,
159        target: &'static str,
160        loot_table: Identifier,
161    ) -> ProcessorRuleData {
162        ProcessorRuleData {
163            input_predicate: StructureRuleTestData::BlockMatch {
164                block: Identifier::vanilla_static(source),
165            },
166            location_predicate: StructureRuleTestData::AlwaysTrue,
167            position_predicate: PosRuleTestData::AlwaysTrue,
168            output_state: Self::block_state_data(target),
169            block_entity_modifier: RuleBlockEntityModifierData::AppendLoot { loot_table },
170        }
171    }
172
173    const fn block_state_data(block: &'static str) -> BlockStateData {
174        BlockStateData {
175            name: Identifier::vanilla_static(block),
176            properties: BTreeMap::new(),
177        }
178    }
179}