steel_core/worldgen/structure/piece_placer/
template_processors.rs1use 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}