Skip to main content

steel_core/behavior/blocks/vegetation/
mod.rs

1//! Block behavior implementations for crops and feature-placed vegetation.
2
3use std::sync::Arc;
4
5mod attached_stem_block;
6mod azalea_block;
7mod bamboo;
8mod bamboo_sapling;
9mod base_coral_fan_block;
10mod base_coral_plant_block;
11mod base_coral_wall_fan_block;
12mod beetroots;
13mod big_dripleaf_block;
14mod big_dripleaf_stem_block;
15pub mod bonemealable;
16mod bush_block;
17mod cactus_block;
18mod cactus_flower_block;
19mod carpet_block;
20mod carrot;
21mod carved_pumpkin_block;
22mod cave_vines_block;
23mod cave_vines_plant_block;
24mod chorus_flower_block;
25mod chorus_plant_block;
26mod cocoa_block;
27mod coral_block;
28mod coral_fan_block;
29mod coral_plant_block;
30mod coral_wall_fan_block;
31mod crop_block;
32mod dirt_path_block;
33mod double_plant_block;
34mod dry_vegetation_block;
35mod eyeblossom_block;
36mod farmland_block;
37mod firefly_bush_block;
38mod flower_bed_block;
39mod flower_block;
40mod glow_lichen_block;
41mod grass_block;
42mod growing_plant_block;
43mod growing_plant_body_block;
44mod growing_plant_head_block;
45mod hanging_moss_block;
46mod hanging_roots_block;
47mod huge_mushroom_block;
48mod kelp_block;
49mod kelp_plant_block;
50mod leaf_litter_block;
51mod leaves_block;
52mod lily_pad_block;
53mod mangrove_propagule_block;
54mod mangrove_roots_block;
55mod mossy_carpet_block;
56pub(crate) mod multiface_block;
57mod mushroom_block;
58mod mycelium_block;
59mod nether_fungus_block;
60mod nether_roots_block;
61mod nether_sprouts;
62mod nether_vines;
63mod nether_wart;
64mod pitcher_crop;
65mod pointed_dripstone_block;
66mod potato;
67mod pumpkin_block;
68mod rooted_dirt_block;
69mod sapling_block;
70mod sculk_vein_block;
71mod sea_pickle_block;
72mod seagrass_block;
73mod segmentable_block;
74mod shelf_mushroom_block;
75mod short_dry_grass_block;
76mod small_dripleaf_block;
77mod snowy_block;
78mod spore_blossom_block;
79mod spreading_grass_block;
80mod stem_block;
81mod sugar_cane;
82mod sweet_berry_bush;
83mod tall_dry_grass_block;
84mod tall_flower_block;
85mod tall_grass_block;
86mod tall_seagrass_block;
87mod torchflower;
88mod turtle_egg_block;
89mod twisting_vines_block;
90mod twisting_vines_plant_block;
91mod vegetation_block;
92mod vine_block;
93mod weeping_vines_block;
94mod weeping_vines_plant_block;
95mod wither_rose_block;
96
97pub use attached_stem_block::*;
98pub use azalea_block::*;
99pub use bamboo::*;
100pub use bamboo_sapling::*;
101pub use base_coral_fan_block::*;
102pub use base_coral_plant_block::*;
103pub use base_coral_wall_fan_block::*;
104pub use beetroots::*;
105pub use big_dripleaf_block::*;
106pub use big_dripleaf_stem_block::*;
107pub use bush_block::*;
108pub use cactus_block::*;
109pub use cactus_flower_block::*;
110pub use carpet_block::*;
111pub use carrot::*;
112pub use carved_pumpkin_block::*;
113pub use cave_vines_block::*;
114pub use cave_vines_plant_block::*;
115pub use chorus_flower_block::*;
116pub use chorus_plant_block::*;
117pub use cocoa_block::*;
118pub use coral_block::*;
119pub use coral_fan_block::*;
120pub use coral_plant_block::*;
121pub use coral_wall_fan_block::*;
122pub use crop_block::*;
123pub use dirt_path_block::*;
124pub use double_plant_block::*;
125pub use dry_vegetation_block::*;
126pub use eyeblossom_block::*;
127pub use farmland_block::*;
128pub use firefly_bush_block::*;
129pub use flower_bed_block::*;
130pub use flower_block::*;
131pub use glow_lichen_block::*;
132pub use grass_block::*;
133pub use growing_plant_head_block::*;
134pub use hanging_moss_block::*;
135pub use hanging_roots_block::*;
136pub use huge_mushroom_block::*;
137pub use kelp_block::*;
138pub use kelp_plant_block::*;
139pub use leaf_litter_block::*;
140pub use leaves_block::*;
141pub use lily_pad_block::*;
142pub use mangrove_propagule_block::*;
143pub use mangrove_roots_block::*;
144pub use mossy_carpet_block::*;
145pub use multiface_block::*;
146pub use mushroom_block::*;
147pub use mycelium_block::*;
148pub use nether_fungus_block::*;
149pub use nether_roots_block::*;
150pub use nether_sprouts::*;
151pub use nether_wart::*;
152pub use pitcher_crop::*;
153pub use pointed_dripstone_block::*;
154pub use potato::*;
155pub use pumpkin_block::*;
156pub use rooted_dirt_block::*;
157pub use sapling_block::*;
158pub use sculk_vein_block::*;
159pub use sea_pickle_block::*;
160pub use seagrass_block::*;
161pub use shelf_mushroom_block::*;
162pub use short_dry_grass_block::*;
163pub use small_dripleaf_block::*;
164pub use snowy_block::*;
165pub use spore_blossom_block::*;
166pub use spreading_grass_block::*;
167pub use stem_block::*;
168pub use sugar_cane::*;
169pub use sweet_berry_bush::*;
170pub use tall_dry_grass_block::*;
171pub use tall_flower_block::*;
172pub use tall_grass_block::*;
173pub use tall_seagrass_block::*;
174pub use torchflower::*;
175pub use turtle_egg_block::*;
176pub use twisting_vines_block::*;
177pub use twisting_vines_plant_block::*;
178pub use vegetation_block::*;
179pub use vine_block::*;
180pub use weeping_vines_block::*;
181pub use weeping_vines_plant_block::*;
182pub use wither_rose_block::*;
183
184use steel_registry::blocks::properties::Direction;
185use steel_registry::blocks::{BlockRef, block_state_ext::BlockStateExt};
186use steel_registry::fluid::FluidState;
187use steel_registry::vanilla_fluids;
188use steel_registry::{vanilla_blocks, vanilla_game_events};
189use steel_utils::{BlockPos, BlockStateId, types::UpdateFlags};
190
191use crate::behavior::block::BlockBehavior;
192use crate::behavior::block::push_entities_up;
193use crate::behavior::context::BlockPlaceContext;
194use crate::entity::Entity;
195use crate::world::game_event::GameEventContext;
196use crate::world::{LevelReader, World};
197
198pub(super) type BlockTagRef<'a> = &'a steel_utils::Identifier;
199
200/// Turns farmland or a dirt path into dirt.
201pub(crate) fn turn_to_dirt(
202    state: BlockStateId,
203    world: &Arc<World>,
204    pos: BlockPos,
205    source_entity: Option<&dyn Entity>,
206) {
207    let dirt_state = push_entities_up(state, vanilla_blocks::DIRT.default_state(), world, pos);
208    if world.set_block(pos, dirt_state, UpdateFlags::UPDATE_ALL) {
209        world.game_event(
210            &vanilla_game_events::BLOCK_CHANGE,
211            pos,
212            &GameEventContext::new(source_entity, Some(dirt_state)),
213        );
214    }
215}
216
217pub(super) fn survives_on_tag(
218    world: &dyn LevelReader,
219    pos: BlockPos,
220    tag: BlockTagRef<'_>,
221) -> bool {
222    let below = world.get_block_state(pos.below());
223    below.get_block().has_tag(tag)
224}
225
226pub(super) fn default_surviving_state(
227    block: BlockRef,
228    behavior: &dyn BlockBehavior,
229    context: &BlockPlaceContext<'_>,
230) -> Option<BlockStateId> {
231    let state = block.default_state();
232    behavior
233        .can_survive(state, context.world, context.place_pos())
234        .then_some(state)
235}
236
237pub(super) fn water_source_fluid_state() -> FluidState {
238    FluidState::source(&vanilla_fluids::WATER)
239}
240
241/// Vanilla equal `getTopConnectedBlock()`
242pub fn get_top_connected_block(
243    world: &dyn LevelReader,
244    pos: BlockPos,
245    body_block: BlockRef,
246    growth_direction: Direction,
247    head_block: BlockRef,
248) -> Option<BlockPos> {
249    let mut forward_pos = pos;
250    let mut forward_state;
251
252    loop {
253        forward_pos = forward_pos.relative(growth_direction);
254        forward_state = world.get_block_state(forward_pos);
255
256        if forward_state.get_block() != body_block {
257            break;
258        }
259    }
260
261    if forward_state.get_block() == head_block {
262        Some(forward_pos)
263    } else {
264        None
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty};
271    use steel_registry::init_vanilla_registry;
272
273    use super::*;
274    use crate::behavior::init_behaviors;
275    use crate::test_support::TestLevel;
276
277    const NORTH: &BoolProperty = &BlockStateProperties::NORTH;
278    const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
279
280    #[test]
281    fn multiface_update_uses_supplied_neighbor_state_and_schedules_water_first() {
282        init_vanilla_registry();
283        init_behaviors();
284        let pos = BlockPos::new(0, 64, 0);
285        let state = vanilla_blocks::GLOW_LICHEN
286            .default_state()
287            .set_value(NORTH, true)
288            .set_value(WATERLOGGED, true);
289        let level =
290            TestLevel::default().with_block(pos.north(), vanilla_blocks::STONE.default_state());
291
292        let updated = MultifaceBlock::update_shape(
293            &MultifaceBlock::new(&vanilla_blocks::GLOW_LICHEN),
294            state,
295            &level,
296            pos,
297            Direction::North,
298            pos.north(),
299            vanilla_blocks::AIR.default_state(),
300        );
301
302        assert!(updated.is_air());
303        assert!(level.scheduled_water_tick());
304    }
305}