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 short_dry_grass_block;
75mod small_dripleaf_block;
76mod snowy_block;
77mod spore_blossom_block;
78mod spreading_grass_block;
79mod stem_block;
80mod sugar_cane;
81mod sweet_berry_bush;
82mod tall_dry_grass_block;
83mod tall_flower_block;
84mod tall_grass_block;
85mod tall_seagrass_block;
86mod torchflower;
87mod turtle_egg_block;
88mod twisting_vines_block;
89mod twisting_vines_plant_block;
90mod vegetation_block;
91mod vine_block;
92mod weeping_vines_block;
93mod weeping_vines_plant_block;
94mod wither_rose_block;
95
96pub use attached_stem_block::AttachedStemBlock;
97pub use azalea_block::AzaleaBlock;
98pub use bamboo::BambooStalkBlock;
99pub use bamboo_sapling::BambooSaplingBlock;
100pub use base_coral_fan_block::BaseCoralFanBlock;
101pub use base_coral_plant_block::BaseCoralPlantBlock;
102pub use base_coral_wall_fan_block::BaseCoralWallFanBlock;
103pub use beetroots::BeetrootBlock;
104pub use big_dripleaf_block::BigDripleafBlock;
105pub use big_dripleaf_stem_block::BigDripleafStemBlock;
106pub use bush_block::BushBlock;
107pub use cactus_block::CactusBlock;
108pub use cactus_flower_block::CactusFlowerBlock;
109pub use carpet_block::{CarpetBlock, WoolCarpetBlock};
110pub use carrot::CarrotBlock;
111pub use carved_pumpkin_block::CarvedPumpkinBlock;
112pub use cave_vines_block::CaveVinesBlock;
113pub use cave_vines_plant_block::CaveVinesPlantBlock;
114pub use chorus_flower_block::ChorusFlowerBlock;
115pub use chorus_plant_block::ChorusPlantBlock;
116pub use cocoa_block::CocoaBlock;
117pub use coral_block::CoralBlock;
118pub use coral_fan_block::CoralFanBlock;
119pub use coral_plant_block::CoralPlantBlock;
120pub use coral_wall_fan_block::CoralWallFanBlock;
121pub use crop_block::CropBlock;
122pub use dirt_path_block::DirtPathBlock;
123pub use double_plant_block::DoublePlantBlock;
124pub use dry_vegetation_block::DryVegetationBlock;
125pub use eyeblossom_block::{EyeblossomBlock, EyeblossomType};
126pub use farmland_block::FarmlandBlock;
127pub use firefly_bush_block::FireflyBushBlock;
128pub use flower_bed_block::FlowerBedBlock;
129pub use flower_block::FlowerBlock;
130pub use glow_lichen_block::GlowLichenBlock;
131pub use grass_block::GrassBlock;
132pub use growing_plant_head_block::{GrowingPlantHeadBehavior, MAX_AGE};
133pub use hanging_moss_block::HangingMossBlock;
134pub use hanging_roots_block::HangingRootsBlock;
135pub use huge_mushroom_block::HugeMushroomBlock;
136pub use kelp_block::KelpBlock;
137pub use kelp_plant_block::KelpPlantBlock;
138pub use leaf_litter_block::LeafLitterBlock;
139pub use leaves_block::{
140    MangroveLeavesBlock, TintedParticleLeavesBlock, UntintedParticleLeavesBlock,
141};
142pub use lily_pad_block::LilyPadBlock;
143pub use mangrove_propagule_block::MangrovePropaguleBlock;
144pub use mangrove_roots_block::MangroveRootsBlock;
145pub use mossy_carpet_block::MossyCarpetBlock;
146pub use multiface_block::MultifaceBlock;
147pub(crate) use multiface_block::{MultifaceSpreadPos, MultifaceSpreadType, multiface_spread_pos};
148pub use mushroom_block::MushroomBlock;
149pub use mycelium_block::MyceliumBlock;
150pub use nether_fungus_block::NetherFungusBlock;
151pub use nether_roots_block::NetherRootsBlock;
152pub use nether_sprouts::NetherSproutsBlock;
153pub use nether_wart::NetherWartBlock;
154pub use pitcher_crop::PitcherCropBlock;
155pub use pointed_dripstone_block::{
156    PointedDripstoneBlock, SulfurSpikeBlock, find_stalactite_tip_above_cauldron,
157    get_cauldron_fill_fluid_type,
158};
159pub use potato::PotatoBlock;
160pub use pumpkin_block::PumpkinBlock;
161pub use rooted_dirt_block::RootedDirtBlock;
162pub use sapling_block::SaplingBlock;
163pub use sculk_vein_block::SculkVeinBlock;
164pub use sea_pickle_block::SeaPickleBlock;
165pub use seagrass_block::SeagrassBlock;
166pub use short_dry_grass_block::ShortDryGrassBlock;
167pub use small_dripleaf_block::SmallDripleafBlock;
168pub use snowy_block::SnowyBlock;
169pub use spore_blossom_block::SporeBlossomBlock;
170pub use spreading_grass_block::SpreadingGrassBlock;
171pub use stem_block::StemBlock;
172pub use sugar_cane::SugarCaneBlock;
173pub use sweet_berry_bush::SweetBerryBushBlock;
174pub use tall_dry_grass_block::TallDryGrassBlock;
175pub use tall_flower_block::TallFlowerBlock;
176pub use tall_grass_block::TallGrassBlock;
177pub use tall_seagrass_block::TallSeagrassBlock;
178pub use torchflower::TorchflowerCropBlock;
179pub use turtle_egg_block::TurtleEggBlock;
180pub use twisting_vines_block::TwistingVinesBlock;
181pub use twisting_vines_plant_block::TwistingVinesPlantBlock;
182pub use vegetation_block::Vegetation;
183pub use vine_block::VineBlock;
184pub use weeping_vines_block::WeepingVinesBlock;
185pub use weeping_vines_plant_block::WeepingVinesPlantBlock;
186pub use wither_rose_block::WitherRoseBlock;
187
188use steel_registry::blocks::properties::Direction;
189use steel_registry::blocks::{BlockRef, block_state_ext::BlockStateExt};
190use steel_registry::fluid::FluidState;
191use steel_registry::vanilla_fluids;
192use steel_registry::{vanilla_blocks, vanilla_game_events};
193use steel_utils::{BlockPos, BlockStateId, types::UpdateFlags};
194
195use crate::behavior::block::BlockBehavior;
196use crate::behavior::block::push_entities_up;
197use crate::behavior::context::BlockPlaceContext;
198use crate::entity::Entity;
199use crate::world::game_event::GameEventContext;
200use crate::world::{LevelReader, World};
201
202pub(super) type BlockTagRef<'a> = &'a steel_utils::Identifier;
203
204/// Turns farmland or a dirt path into dirt.
205pub(crate) fn turn_to_dirt(
206    state: BlockStateId,
207    world: &Arc<World>,
208    pos: BlockPos,
209    source_entity: Option<&dyn Entity>,
210) {
211    let dirt_state = push_entities_up(state, vanilla_blocks::DIRT.default_state(), world, pos);
212    if world.set_block(pos, dirt_state, UpdateFlags::UPDATE_ALL) {
213        world.game_event(
214            &vanilla_game_events::BLOCK_CHANGE,
215            pos,
216            &GameEventContext::new(source_entity, Some(dirt_state)),
217        );
218    }
219}
220
221pub(super) fn survives_on_tag(
222    world: &dyn LevelReader,
223    pos: BlockPos,
224    tag: BlockTagRef<'_>,
225) -> bool {
226    let below = world.get_block_state(pos.below());
227    below.get_block().has_tag(tag)
228}
229
230pub(super) fn default_surviving_state(
231    block: BlockRef,
232    behavior: &dyn BlockBehavior,
233    context: &BlockPlaceContext<'_>,
234) -> Option<BlockStateId> {
235    let state = block.default_state();
236    behavior
237        .can_survive(state, context.world, context.place_pos())
238        .then_some(state)
239}
240
241pub(super) fn water_source_fluid_state() -> FluidState {
242    FluidState::source(&vanilla_fluids::WATER)
243}
244
245/// Vanilla equal `getTopConnectedBlock()`
246pub fn get_top_connected_block(
247    world: &dyn LevelReader,
248    pos: BlockPos,
249    body_block: BlockRef,
250    growth_direction: Direction,
251    head_block: BlockRef,
252) -> Option<BlockPos> {
253    let mut forward_pos = pos;
254    let mut forward_state;
255
256    loop {
257        forward_pos = forward_pos.relative(growth_direction);
258        forward_state = world.get_block_state(forward_pos);
259
260        if forward_state.get_block() != body_block {
261            break;
262        }
263    }
264
265    if forward_state.get_block() == head_block {
266        Some(forward_pos)
267    } else {
268        None
269    }
270}
271
272#[cfg(test)]
273mod tests {
274    use steel_registry::blocks::properties::{BlockStateProperties, BoolProperty};
275    use steel_registry::init_vanilla_registry;
276
277    use super::*;
278    use crate::behavior::init_behaviors;
279    use crate::test_support::TestLevel;
280
281    const NORTH: &BoolProperty = &BlockStateProperties::NORTH;
282    const WATERLOGGED: &BoolProperty = &BlockStateProperties::WATERLOGGED;
283
284    #[test]
285    fn multiface_update_uses_supplied_neighbor_state_and_schedules_water_first() {
286        init_vanilla_registry();
287        init_behaviors();
288        let pos = BlockPos::new(0, 64, 0);
289        let state = vanilla_blocks::GLOW_LICHEN
290            .default_state()
291            .set_value(NORTH, true)
292            .set_value(WATERLOGGED, true);
293        let level =
294            TestLevel::default().with_block(pos.north(), vanilla_blocks::STONE.default_state());
295
296        let updated = MultifaceBlock::update_shape(
297            &MultifaceBlock::new(&vanilla_blocks::GLOW_LICHEN),
298            state,
299            &level,
300            pos,
301            Direction::North,
302            pos.north(),
303            vanilla_blocks::AIR.default_state(),
304        );
305
306        assert!(updated.is_air());
307        assert!(level.scheduled_water_tick());
308    }
309}