fix: add Kelp block placement/break rules (#1805)

* fix: wrong piston break check

* feat: kelp placement rules and break/place behaviour

* chore: make clippy happy

* fix: breaking kelp now places water instead of air

* chore: make clippy happy

* fix: vanilla parity
This commit is contained in:
Greened
2026-03-15 17:19:25 +04:00
committed by GitHub
parent 554b3daad9
commit a54728f2be
2 changed files with 111 additions and 15 deletions

View File

@@ -1,7 +1,13 @@
use crate::block::blocks::plant::PlantBlockBase;
use crate::block::{BlockBehaviour, BlockFuture, BlockMetadata, CanPlaceAtArgs};
use crate::block::{
BlockBehaviour, BlockFuture, BlockMetadata, BrokenArgs, CanPlaceAtArgs,
GetStateForNeighborUpdateArgs, PlacedArgs,
};
use pumpkin_data::Block;
use pumpkin_data::block_properties::{BlockProperties, WaterLikeProperties};
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::world::{BlockAccessor, BlockFlags};
pub struct KelpBlock;
impl BlockMetadata for KelpBlock {
@@ -13,22 +19,111 @@ impl BlockMetadata for KelpBlock {
impl BlockBehaviour for KelpBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
Box::pin(async move {
// Determine support block
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
}
fn get_state_for_neighbor_update<'a>(
&'a self,
args: GetStateForNeighborUpdateArgs<'a>,
) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
<Self as PlantBlockBase>::get_state_for_neighbor_update(
self,
args.world,
args.position,
args.state_id,
)
.await
})
}
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let support_pos = args.position.down();
let support_block = args.block_accessor.get_block(&support_pos).await;
// If placing the base kelp block, allow placement on water or on other kelp segments.
if args.block.id == Block::KELP.id {
support_block == &Block::WATER
|| support_block == &Block::KELP
|| support_block == &Block::KELP_PLANT
} else {
support_block == &Block::KELP || support_block == &Block::KELP_PLANT
let support_block = args.world.get_block(&support_pos).await;
if support_block == &Block::KELP {
args.world
.set_block_state(
&support_pos,
Block::KELP_PLANT.default_state.id,
BlockFlags::empty(),
)
.await;
}
})
}
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let support_pos = args.position.down();
let support_block = args.world.get_block(&support_pos).await;
if support_block == &Block::KELP_PLANT {
args.world
.set_block_state(
&support_pos,
Block::KELP.default_state.id,
BlockFlags::empty(),
)
.await;
args.world
.set_block_state(
args.position,
Block::WATER.default_state.id,
BlockFlags::empty(),
)
.await;
}
})
}
// TODO: proper kelp placement (fix `can_place_at`) and break behavior (including supporting blocks)
}
impl PlantBlockBase for KelpBlock {}
impl PlantBlockBase for KelpBlock {
async fn can_plant_on_top(
&self,
block_accessor: &dyn pumpkin_world::world::BlockAccessor,
pos: &pumpkin_util::math::position::BlockPos,
) -> bool {
// Determine support block
let support_pos = pos;
let (replacing_block, replacing_block_state) =
block_accessor.get_block_and_state(&pos.up()).await;
let (support_block, support_block_state) =
block_accessor.get_block_and_state(support_pos).await;
if replacing_block == &Block::WATER {
let water_props =
WaterLikeProperties::from_state_id(replacing_block_state.id, replacing_block);
//Only allow placing kelp on either full water or downward flowing water
if water_props.level as u8 != 0 && water_props.level as u8 != 8 {
return false;
}
} else {
//Replacing block can also be a kelp_plant or kelp in case this is an neighbour update check
if replacing_block != &Block::KELP_PLANT && replacing_block != &Block::KELP {
return false;
}
}
// If placing the base kelp block, allow placement on water or on other kelp segments.
if support_block == &Block::KELP || support_block == &Block::KELP_PLANT {
return true;
}
if support_block == &Block::MAGMA_BLOCK {
return false;
}
if support_block_state.is_side_solid(pumpkin_data::BlockDirection::Up)
&& support_block.is_solid()
{
return true;
}
false
}
async fn get_state_for_neighbor_update(
&self,
block_accessor: &dyn BlockAccessor,
block_pos: &BlockPos,
block_state: BlockStateId,
) -> BlockStateId {
if !<Self as PlantBlockBase>::can_place_at(self, block_accessor, block_pos).await {
return Block::WATER.default_state.id;
}
block_state
}
}

View File

@@ -40,6 +40,7 @@ pub fn can_be_replaced(block_state: &BlockState, block: &Block, fluid: &Fluid) -
|| id == Block::CAMPFIRE.id
|| id == Block::DRAGON_EGG.id
|| id == Block::KELP.id
|| id == Block::KELP_PLANT.id
|| id == Block::LADDER.id
|| id == Block::POINTED_DRIPSTONE.id
|| id == Block::SCAFFOLDING.id