Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
263 changes: 263 additions & 0 deletions pumpkin/src/block/blocks/plant/big_dripleaf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
use std::sync::Arc;
use std::sync::atomic::Ordering;

use crate::block::blocks::plant::PlantBlockBase;
use crate::block::blocks::plant::big_dripleaf_stem::{
BigDripleafStemLikeProperties, handle_big_dripleaf_breaking,
};
use crate::block::blocks::redstone::block_receives_redstone_power;
use crate::block::{
BlockBehaviour, BlockFuture, BrokenArgs, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
OnEntityStepArgs, OnNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs, PlacedArgs,
};
use crate::entity::EntityBase;
use crate::entity::ai::pathfinder::node::Coordinate;
use crate::world::World;
use pumpkin_data::block_properties::{
BigDripleafLikeProperties, BlockProperties, HorizontalFacing, Tilt,
};
use pumpkin_data::sound::{Sound, SoundCategory};
use pumpkin_data::tag::Taggable;
use pumpkin_data::{Block, tag};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector3::Vector3;
use pumpkin_world::BlockStateId;
use pumpkin_world::world::{BlockAccessor, BlockFlags};
use rand::RngExt;

#[pumpkin_block("minecraft:big_dripleaf")]
pub struct BigDripleafBlock;

impl BlockBehaviour for BigDripleafBlock {
fn on_entity_step<'a>(&'a self, args: OnEntityStepArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let props = BigDripleafLikeProperties::from_state_id(args.state.id, args.block);
if props.tilt == Tilt::None
&& can_entity_tilt(args.position, args.entity)
&& !block_receives_redstone_power(args.world, args.position).await
{
set_tilt_and_schedule_tick(
args.state.id,
args.world,
args.position,
Tilt::Unstable,
None,
)
.await;
}
})
}
fn on_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let state = args.world.get_block_state(args.position).await;
if block_receives_redstone_power(args.world, args.position).await {
reset_tilt(state.id, args.world, args.position).await;
} else {
let props =
BigDripleafLikeProperties::from_state_id(state.id, &Block::BIG_DRIPLEAF);

if props.tilt == Tilt::Unstable {
set_tilt_and_schedule_tick(
state.id,
args.world,
args.position,
Tilt::Partial,
Some(Sound::BlockBigDripleafTiltDown),
)
.await;
} else if props.tilt == Tilt::Partial {
set_tilt_and_schedule_tick(
state.id,
args.world,
args.position,
Tilt::Full,
Some(Sound::BlockBigDripleafTiltDown),
)
.await;
} else if props.tilt == Tilt::Full {
reset_tilt(state.id, args.world, args.position).await;
}
}
})
}
//TODO: onProjectileHit
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
Box::pin(async move {
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
})
}
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
Box::pin(async move {
let (support_block, support_block_state_id) = args
.world
.get_block_and_state_id(&args.position.down())
.await;
let facing = if support_block == &Block::BIG_DRIPLEAF {
get_dripleaf_facing_dir(support_block_state_id)
} else {
args.player
.living_entity
.entity
.get_horizontal_facing()
.opposite()
};
let mut dripleaf_props = BigDripleafLikeProperties::default(args.block);

dripleaf_props.facing = facing;
dripleaf_props.waterlogged = args.replacing.water_source();

dripleaf_props.to_state_id(args.block)
})
}

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 on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
if block_receives_redstone_power(args.world, args.position).await {
let state_id = args.world.get_block_state_id(args.position).await;
reset_tilt(state_id, args.world, args.position).await;
}
})
}

/// if leaf is placed on top of another leaf, turn the lower one into a stem.
fn placed<'a>(&'a self, args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {
let support_pos = args.position.down();
let (support_block, support_state_id) =
args.world.get_block_and_state_id(&support_pos).await;
if support_block == &Block::BIG_DRIPLEAF {
let old_dripleaf_props = BigDripleafLikeProperties::from_state_id(
support_state_id,
&Block::BIG_DRIPLEAF,
);
let mut dripleaf_stem_props =
BigDripleafStemLikeProperties::default(&Block::BIG_DRIPLEAF_STEM);

dripleaf_stem_props.facing = old_dripleaf_props.facing;
dripleaf_stem_props.waterlogged = old_dripleaf_props.waterlogged;
args.world
.set_block_state(
&support_pos,
dripleaf_stem_props.to_state_id(&Block::BIG_DRIPLEAF_STEM),
BlockFlags::empty(),
)
.await;
}
})
}

/// if the leaf is broken, turn the stem below into a leaf.
fn broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { handle_big_dripleaf_breaking(args.world, args.position).await })
}
}
async fn set_tilt_and_schedule_tick(
state_id: BlockStateId,
world: &Arc<World>,
pos: &BlockPos,
tilt: Tilt,
sound_wrapper: Option<Sound>,
) {
set_tilt(state_id, world, pos, tilt).await;
if let Some(tilt_sound) = sound_wrapper {
play_tilt_sound(world, pos, tilt_sound).await;
}
let tick_delay = match tilt {
Tilt::None => -1,
Tilt::Unstable | Tilt::Partial => 10,
Tilt::Full => 100,
};
if tick_delay != -1 {
world
.schedule_block_tick(
&Block::BIG_DRIPLEAF,
*pos,
tick_delay as u8,
pumpkin_world::tick::TickPriority::Normal,
)
.await;
}
}
async fn play_tilt_sound(world: &Arc<World>, pos: &BlockPos, tilt_sound: Sound) {
let pitch = rand::rng().random_range(0.8f32..1.2f32);
let v = pos.as_vector3();
let position = Vector3::new(v.x as f64, v.y as f64, v.z as f64);
world
.play_sound_fine(tilt_sound, SoundCategory::Blocks, &position, 1f32, pitch)
.await;
}
async fn reset_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos) {
set_tilt(state_id, world, pos, Tilt::None).await;
let props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF);
if props.tilt != Tilt::None {
play_tilt_sound(world, pos, Sound::BlockBigDripleafTiltUp).await;
}
}
async fn set_tilt(state_id: BlockStateId, world: &Arc<World>, pos: &BlockPos, new_tilt: Tilt) {
let mut props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF);
props.tilt = new_tilt;
world
.set_block_state(
pos,
props.to_state_id(&Block::BIG_DRIPLEAF),
BlockFlags::NOTIFY_ALL,
)
.await;
//todo GameEvents?
}
fn can_entity_tilt<T: EntityBase + ?Sized>(pos: &BlockPos, entity: &T) -> bool {
entity.get_entity().on_ground.load(Ordering::Relaxed)
&& entity.get_entity().pos.load().y > pos.as_vector3().y as f64 + 0.6875f64
}
fn get_dripleaf_facing_dir(state_id: BlockStateId) -> HorizontalFacing {
let dripleaf_props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF);
dripleaf_props.facing
}

fn is_dripleaf_waterlogged(state_id: BlockStateId) -> bool {
let dripleaf_props = BigDripleafLikeProperties::from_state_id(state_id, &Block::BIG_DRIPLEAF);
dripleaf_props.waterlogged
}
impl PlantBlockBase for BigDripleafBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let support_block = block_accessor.get_block(pos).await;
can_plant_dripleaf_on_top(support_block)
}
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 {
if is_dripleaf_waterlogged(block_state) {
return Block::WATER.default_state.id;
}
return Block::AIR.default_state.id;
}
block_state
}
}
#[must_use]
pub fn can_plant_dripleaf_on_top(support_block: &Block) -> bool {
if support_block == &Block::BIG_DRIPLEAF || support_block == &Block::BIG_DRIPLEAF_STEM {
return true;
}

support_block.has_tag(&tag::Block::MINECRAFT_SUPPORTS_BIG_DRIPLEAF)
}
91 changes: 91 additions & 0 deletions pumpkin/src/block/blocks/plant/big_dripleaf_stem.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use std::sync::Arc;

use crate::block::blocks::plant::PlantBlockBase;
use crate::block::blocks::plant::big_dripleaf::can_plant_dripleaf_on_top;
use crate::block::{
BlockBehaviour, BlockFuture, BrokenArgs, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
};
use crate::world::World;
use pumpkin_data::Block;
use pumpkin_data::block_properties::{
BigDripleafLikeProperties, BlockProperties, LadderLikeProperties,
};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::world::{BlockAccessor, BlockFlags};

#[pumpkin_block("minecraft:big_dripleaf_stem")]
pub struct BigDripleafStemBlock;

pub type BigDripleafStemLikeProperties = LadderLikeProperties;

impl BlockBehaviour for BigDripleafStemBlock {
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
Box::pin(async move {
<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 broken<'a>(&'a self, args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move { handle_big_dripleaf_breaking(args.world, args.position).await })
}
}
impl PlantBlockBase for BigDripleafStemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let support_block = block_accessor.get_block(pos).await;
can_plant_dripleaf_on_top(support_block)
}

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 {
let block = block_accessor.get_block(block_pos).await;

let dripleaf_stem_props =
BigDripleafStemLikeProperties::from_state_id(block_state, block);
if dripleaf_stem_props.waterlogged {
return Block::WATER.default_state.id;
}
return Block::AIR.default_state.id;
}
block_state
}
}
pub async fn handle_big_dripleaf_breaking(world: &Arc<World>, position: &BlockPos) {
let support_pos = position.down();
let (support_block, support_state_id) = world.get_block_and_state_id(&support_pos).await;
if support_block == &Block::BIG_DRIPLEAF_STEM {
let dripleaf_stem_props =
BigDripleafStemLikeProperties::from_state_id(support_state_id, support_block);

let mut dripleaf_props = BigDripleafLikeProperties::default(&Block::BIG_DRIPLEAF);
dripleaf_props.facing = dripleaf_stem_props.facing;
dripleaf_props.waterlogged = dripleaf_stem_props.waterlogged;
world
.set_block_state(
&support_pos,
dripleaf_props.to_state_id(&Block::BIG_DRIPLEAF),
BlockFlags::empty(),
)
.await;
}
}
2 changes: 2 additions & 0 deletions pumpkin/src/block/blocks/plant/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use pumpkin_world::{BlockStateId, world::BlockAccessor};

pub mod bamboo;
pub mod bamboo_sapling;
pub mod big_dripleaf;
pub mod big_dripleaf_stem;
pub mod bush;
pub mod cactus;
pub mod cactus_flower;
Expand Down
4 changes: 4 additions & 0 deletions pumpkin/src/block/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ use crate::block::blocks::piston::piston_extension::PistonExtensionBlock;
use crate::block::blocks::piston::piston_head::PistonHeadBlock;
use crate::block::blocks::plant::bamboo::BambooBlock;
use crate::block::blocks::plant::bamboo_sapling::BambooSaplingBlock;
use crate::block::blocks::plant::big_dripleaf::BigDripleafBlock;
use crate::block::blocks::plant::big_dripleaf_stem::BigDripleafStemBlock;
use crate::block::blocks::plant::bush::BushBlock;
use crate::block::blocks::plant::cactus::CactusBlock;
use crate::block::blocks::plant::cactus_flower::CactusFlowerBlock;
Expand Down Expand Up @@ -276,6 +278,8 @@ pub fn default_registry() -> Arc<BlockRegistry> {
manager.register(TwistingVinesBlock);
manager.register(WeepingVinesBlock);
manager.register(CactusFlowerBlock);
manager.register(BigDripleafStemBlock);
manager.register(BigDripleafBlock);

manager.register(FallingBlock);

Expand Down