diff --git a/pumpkin/src/block/blocks/plant/kelp.rs b/pumpkin/src/block/blocks/plant/kelp.rs index f841378c6..d6b089223 100644 --- a/pumpkin/src/block/blocks/plant/kelp.rs +++ b/pumpkin/src/block/blocks/plant/kelp.rs @@ -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 + ::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 { + ::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 !::can_place_at(self, block_accessor, block_pos).await { + return Block::WATER.default_state.id; + } + block_state + } +} diff --git a/pumpkin/src/block/fluid/physics.rs b/pumpkin/src/block/fluid/physics.rs index 5fe258f7f..7b879a8ea 100644 --- a/pumpkin/src/block/fluid/physics.rs +++ b/pumpkin/src/block/fluid/physics.rs @@ -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