Pumpkin/pumpkin/src/block/blocks/plant/tall_plant.rs
2026-05-14 12:28:43 +02:00

132 lines
5.0 KiB
Rust

use crate::block::{BrokenArgs, PlacedArgs};
use pumpkin_data::Block;
use pumpkin_data::BlockDirection;
use pumpkin_data::block_properties::{
BlockProperties, DoubleBlockHalf, TallSeagrassLikeProperties,
};
use pumpkin_world::BlockStateId;
use pumpkin_world::world::BlockFlags;
use crate::block::BlockFuture;
use crate::block::{
BlockBehaviour, BlockMetadata, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
blocks::plant::PlantBlockBase,
};
pub struct TallPlantBlock;
impl BlockMetadata for TallPlantBlock {
fn ids() -> Box<[u16]> {
[
Block::TALL_GRASS.id,
Block::LARGE_FERN.id,
Block::PITCHER_PLANT.id,
// TallFlowerBlocks
Block::SUNFLOWER.id,
Block::LILAC.id,
Block::PEONY.id,
Block::ROSE_BUSH.id,
]
.into()
}
}
impl BlockBehaviour for TallPlantBlock {
fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
let up_pos = args.position.up();
let upper_state = args.block_accessor.get_block_state(&up_pos);
let Some(world) = args.world else {
return <Self as PlantBlockBase>::can_place_at(
self,
args.block_accessor,
args.position,
) && upper_state.is_air();
};
if up_pos.0.y > world.get_top_y() {
return false;
}
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position)
&& upper_state.is_air()
}
fn get_state_for_neighbor_update<'a>(
&'a self,
args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let tall_plant_props =
TallSeagrassLikeProperties::from_state_id(args.state_id, args.block);
let (support_block_pos, other_block_pos) = match tall_plant_props.half {
DoubleBlockHalf::Upper => (args.position.down_height(2), args.position.down()),
DoubleBlockHalf::Lower => (args.position.down(), args.position.up()),
};
if !<Self as PlantBlockBase>::can_place_at(self, args.world, &support_block_pos.up()) {
return Block::AIR.default_state.id;
}
let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_block_pos);
if Self::ids().contains(&other_block.id) {
let other_props =
TallSeagrassLikeProperties::from_state_id(other_state_id, other_block);
let opposite_half = match tall_plant_props.half {
DoubleBlockHalf::Upper => DoubleBlockHalf::Lower,
DoubleBlockHalf::Lower => DoubleBlockHalf::Upper,
};
if other_props.half == opposite_half {
return args.state_id;
}
}
Block::AIR.default_state.id
})
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let mut tall_plant_props =
TallSeagrassLikeProperties::from_state_id(args.state_id, args.block);
tall_plant_props.half = DoubleBlockHalf::Upper;
args.world
.set_block_state(
&args.position.offset(BlockDirection::Up.to_offset()),
tall_plant_props.to_state_id(args.block),
BlockFlags::NOTIFY_ALL | BlockFlags::SKIP_BLOCK_ADDED_CALLBACK,
)
.await;
})
}
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
// When one half of a tall plant is broken, break the other half too
let tall_plant_props =
TallSeagrassLikeProperties::from_state_id(args.state.id, args.block);
let other_block_pos = match tall_plant_props.half {
DoubleBlockHalf::Upper => args.position.down(),
DoubleBlockHalf::Lower => args.position.up(),
};
let (other_block, other_state_id) = args.world.get_block_and_state_id(&other_block_pos);
if Self::ids().contains(&other_block.id) {
let other_props =
TallSeagrassLikeProperties::from_state_id(other_state_id, other_block);
let opposite_half = match tall_plant_props.half {
DoubleBlockHalf::Upper => DoubleBlockHalf::Lower,
DoubleBlockHalf::Lower => DoubleBlockHalf::Upper,
};
if other_props.half == opposite_half {
// Break the other half, using SKIP_DROPS to prevent double drops
args.world
.break_block(
&other_block_pos,
None,
BlockFlags::SKIP_DROPS | BlockFlags::SKIP_BLOCK_ADDED_CALLBACK,
)
.await;
}
}
})
}
}
impl PlantBlockBase for TallPlantBlock {}