mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
feat: Sweet Berry Bushes (#1248)
* switch to btreemap to comply with lint * amplifier i32 -> u8 * switch allow to expect lint * remove many many unnecessary clippy lints * dont use expect inside quotes * beetroot chance 1/3 * prevent sugar cane from growing more than 3 high * add sweet berry bush * check for block above * start nether warts * nether warts with random ticks * cargo fmt * bamboo! * pass when using bone meal on sweet berry bush with age < 3 * fix first two bamboo not being wide * use early returns to flatten nesting * switch damage and damage context to take references instead of arcs * entity collision damage with sweet berry bush and campfire * prevent panic and instead just reject placement if y < 0 * fix cactus growing and add cactus flowers * cargo fmt
This commit is contained in:
@@ -336,7 +336,9 @@ impl ChunkSections {
|
||||
block_state_id: BlockStateId,
|
||||
) -> BlockStateId {
|
||||
let y = y - self.min_y;
|
||||
debug_assert!(y >= 0);
|
||||
if y < 0 {
|
||||
return Block::AIR.default_state.id;
|
||||
}
|
||||
let relative_y = y as usize;
|
||||
|
||||
self.set_relative_block(relative_x, relative_y, relative_z, block_state_id)
|
||||
|
||||
@@ -529,19 +529,19 @@ impl Level {
|
||||
chunk_z_base + z_offset,
|
||||
);
|
||||
|
||||
let block_id = chunk
|
||||
let block_state_id = chunk
|
||||
.section
|
||||
.get_block_absolute_y(x_offset as usize, random_pos.0.y, z_offset as usize)
|
||||
.unwrap_or(Block::AIR.default_state.id);
|
||||
|
||||
section_block_data.push((random_pos, block_id));
|
||||
section_block_data.push((random_pos, block_state_id));
|
||||
}
|
||||
section_blocks.push(section_block_data);
|
||||
}
|
||||
|
||||
for section_data in section_blocks {
|
||||
for (random_pos, block_id) in section_data {
|
||||
if has_random_ticks(block_id) {
|
||||
for (random_pos, block_state_id) in section_data {
|
||||
if has_random_ticks(block_state_id) {
|
||||
ticks.random_ticks.push(ScheduledTick {
|
||||
position: random_pos,
|
||||
delay: 0,
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
use pumpkin_data::tag;
|
||||
use pumpkin_data::tag::Taggable;
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
|
||||
use crate::block::{BlockBehaviour, BlockFuture, CanPlaceAtArgs};
|
||||
|
||||
#[pumpkin_block("minecraft:bamboo")]
|
||||
pub struct BambooBlock;
|
||||
|
||||
impl BlockBehaviour for BambooBlock {
|
||||
fn can_place_at<'a>(&'a self, args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
|
||||
Box::pin(async move {
|
||||
let block_below = args.block_accessor.get_block(&args.position.down()).await;
|
||||
block_below.has_tag(&tag::Block::MINECRAFT_BAMBOO_PLANTABLE_ON)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use pumpkin_data::{
|
||||
Block, BlockDirection,
|
||||
block_properties::{BlockProperties, CampfireLikeProperties},
|
||||
damage::DamageType,
|
||||
fluid::Fluid,
|
||||
};
|
||||
use pumpkin_world::{BlockStateId, tick::TickPriority};
|
||||
@@ -32,8 +33,10 @@ impl BlockBehaviour for CampfireBlock {
|
||||
if CampfireLikeProperties::from_state_id(args.state.id, args.block).lit
|
||||
&& args.entity.get_living_entity().is_some()
|
||||
{
|
||||
// TODO
|
||||
//args.entity.damage(args.entity, 1.0, DamageType::CAMPFIRE).await;
|
||||
// FIXME: entity collision code is wrong
|
||||
args.entity
|
||||
.damage(args.entity, 1.0, DamageType::CAMPFIRE)
|
||||
.await;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
pub mod anvil;
|
||||
pub mod bamboo;
|
||||
pub mod barrel;
|
||||
pub mod barrier;
|
||||
pub mod bed;
|
||||
pub mod cactus;
|
||||
pub mod cake;
|
||||
pub mod campfire;
|
||||
pub mod candle_cakes;
|
||||
@@ -48,7 +46,6 @@ pub mod skull_block;
|
||||
pub mod slabs;
|
||||
pub mod spawner;
|
||||
pub mod stairs;
|
||||
pub mod sugar_cane;
|
||||
pub mod tnt;
|
||||
pub mod torches;
|
||||
pub mod trapdoor;
|
||||
|
||||
286
pumpkin/src/block/blocks/plant/bamboo.rs
Normal file
286
pumpkin/src/block/blocks/plant/bamboo.rs
Normal file
@@ -0,0 +1,286 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_data::block_properties::{
|
||||
BambooLeaves, BambooLikeProperties, BlockProperties, EnumVariants, Integer0To1,
|
||||
};
|
||||
use pumpkin_data::item::Item;
|
||||
use pumpkin_data::tag::Block::MINECRAFT_BAMBOO_PLANTABLE_ON;
|
||||
use pumpkin_data::tag::Taggable;
|
||||
use pumpkin_data::tag::{self};
|
||||
use pumpkin_data::{Block, BlockDirection};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::tick::TickPriority;
|
||||
use pumpkin_world::world::{BlockAccessor, BlockFlags};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::block::registry::BlockActionResult;
|
||||
use crate::block::{BlockBehaviour, BlockFuture, CanPlaceAtArgs, blocks::plant::PlantBlockBase};
|
||||
use crate::block::{
|
||||
GetStateForNeighborUpdateArgs, OnPlaceArgs, OnScheduledTickArgs, RandomTickArgs,
|
||||
UseWithItemArgs,
|
||||
};
|
||||
use crate::world::World;
|
||||
|
||||
#[pumpkin_block("minecraft:bamboo")]
|
||||
pub struct BambooBlock;
|
||||
|
||||
impl BlockBehaviour for BambooBlock {
|
||||
fn on_place<'a>(&'a self, args: OnPlaceArgs<'a>) -> BlockFuture<'a, BlockStateId> {
|
||||
Box::pin(async move {
|
||||
let (block_below, state_id_below) = args
|
||||
.world
|
||||
.get_block_and_state_id(&args.position.down())
|
||||
.await;
|
||||
|
||||
if block_below.has_tag(&MINECRAFT_BAMBOO_PLANTABLE_ON) {
|
||||
let mut props = BambooLikeProperties::from_state_id(
|
||||
Block::BAMBOO.default_state.id,
|
||||
&Block::BAMBOO,
|
||||
);
|
||||
if block_below == &Block::BAMBOO_SAPLING {
|
||||
return Block::BAMBOO.default_state.id;
|
||||
} else if block_below == &Block::BAMBOO {
|
||||
let props_below =
|
||||
BambooLikeProperties::from_state_id(state_id_below, block_below);
|
||||
if props_below.age.to_index() > 0 {
|
||||
props.age = Integer0To1::L1;
|
||||
}
|
||||
} else {
|
||||
let (block_above, state_id_above) =
|
||||
args.world.get_block_and_state_id(&args.position.up()).await;
|
||||
if block_above == &Block::BAMBOO {
|
||||
let props_above =
|
||||
BambooLikeProperties::from_state_id(state_id_above, block_above);
|
||||
props.age = props_above.age;
|
||||
} else {
|
||||
return Block::BAMBOO_SAPLING.default_state.id;
|
||||
}
|
||||
}
|
||||
return props.to_state_id(&Block::BAMBOO);
|
||||
}
|
||||
Block::AIR.default_state.id
|
||||
})
|
||||
}
|
||||
|
||||
fn use_with_item<'a>(
|
||||
&'a self,
|
||||
args: UseWithItemArgs<'a>,
|
||||
) -> BlockFuture<'a, BlockActionResult> {
|
||||
Box::pin(async move {
|
||||
let lock = args.item_stack.lock().await;
|
||||
if lock.get_item() == &Item::BONE_MEAL {
|
||||
bone_meal(Arc::clone(args.world), args.position).await;
|
||||
return BlockActionResult::Success;
|
||||
}
|
||||
BlockActionResult::Pass
|
||||
})
|
||||
}
|
||||
|
||||
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_scheduled_tick<'a>(&'a self, args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if !<Self as PlantBlockBase>::can_place_at(self, args.world.as_ref(), args.position)
|
||||
.await
|
||||
{
|
||||
args.world
|
||||
.break_block(args.position, None, BlockFlags::empty())
|
||||
.await;
|
||||
} else if args.world.get_block(&args.position.down()).await == &Block::BAMBOO_SAPLING {
|
||||
args.world
|
||||
.set_block_state(
|
||||
&args.position.down(),
|
||||
Block::BAMBOO.default_state.id,
|
||||
BlockFlags::empty(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_state_for_neighbor_update<'a>(
|
||||
&'a self,
|
||||
args: GetStateForNeighborUpdateArgs<'a>,
|
||||
) -> BlockFuture<'a, BlockStateId> {
|
||||
Box::pin(async move {
|
||||
if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position).await {
|
||||
args.world
|
||||
.schedule_block_tick(args.block, *args.position, 1, TickPriority::Normal)
|
||||
.await;
|
||||
}
|
||||
let neighbor_block = args.world.get_block(args.neighbor_position).await;
|
||||
if args.direction == BlockDirection::Up && neighbor_block == &Block::BAMBOO {
|
||||
let neighbor_props =
|
||||
BambooLikeProperties::from_state_id(args.neighbor_state_id, neighbor_block);
|
||||
let mut props = BambooLikeProperties::from_state_id(args.state_id, args.block);
|
||||
if neighbor_props.age.to_index() > props.age.to_index() {
|
||||
props.age = match props.age {
|
||||
Integer0To1::L0 => Integer0To1::L1,
|
||||
Integer0To1::L1 => Integer0To1::L0,
|
||||
};
|
||||
return props.to_state_id(args.block);
|
||||
}
|
||||
}
|
||||
args.state_id
|
||||
})
|
||||
}
|
||||
|
||||
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if rand::rng().random_range(0..=3) == 0 {
|
||||
update_leaves_and_grow(args.world.clone(), args.position).await;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_leaves_and_grow(world: Arc<World>, position: &BlockPos) {
|
||||
let above_pos = position.up();
|
||||
let below_pos = position.down();
|
||||
let two_below_pos = position.down_height(2);
|
||||
|
||||
let (block, state_id) = world.get_block_and_state_id(position).await;
|
||||
let state_above = world.get_block_state(&above_pos).await;
|
||||
|
||||
if !state_above.is_air() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut props = BambooLikeProperties::from_state_id(state_id, block);
|
||||
if props.stage != Integer0To1::L0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let bamboo_count = count_bamboo_below(world.clone(), position).await;
|
||||
if bamboo_count >= 16 {
|
||||
return;
|
||||
}
|
||||
let (block_below, state_id_below) = world.get_block_and_state_id(&below_pos).await;
|
||||
let (block_two_below, state_id_two_below) = world.get_block_and_state_id(&two_below_pos).await;
|
||||
|
||||
let mut props_below = BambooLikeProperties::from_state_id(state_id_below, block_below);
|
||||
|
||||
if bamboo_count >= 1 {
|
||||
let below_is_bamboo = block_below == &Block::BAMBOO;
|
||||
let below_has_leaves = props_below.leaves != BambooLeaves::None;
|
||||
|
||||
props.leaves = if !below_is_bamboo || !below_has_leaves {
|
||||
BambooLeaves::Small
|
||||
} else {
|
||||
BambooLeaves::Large
|
||||
};
|
||||
|
||||
if props.leaves == BambooLeaves::Large && block_two_below == &Block::BAMBOO {
|
||||
props_below.leaves = BambooLeaves::Small;
|
||||
|
||||
let mut props_two_below =
|
||||
BambooLikeProperties::from_state_id(state_id_two_below, block_two_below);
|
||||
props_two_below.leaves = BambooLeaves::None;
|
||||
|
||||
world
|
||||
.set_block_state(
|
||||
&below_pos,
|
||||
props_below.to_state_id(block_below),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
world
|
||||
.set_block_state(
|
||||
&two_below_pos,
|
||||
props_two_below.to_state_id(block_two_below),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
||||
props.age = if props.age != Integer0To1::L1 && block_two_below == &Block::BAMBOO {
|
||||
Integer0To1::L0
|
||||
} else {
|
||||
Integer0To1::L1
|
||||
};
|
||||
|
||||
props.stage =
|
||||
if (bamboo_count < 11 || rand::rng().random::<f32>() >= 0.25) && bamboo_count != 15 {
|
||||
Integer0To1::L0
|
||||
} else {
|
||||
Integer0To1::L1
|
||||
};
|
||||
|
||||
world
|
||||
.set_block_state(&above_pos, props.to_state_id(block), BlockFlags::NOTIFY_ALL)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn count_bamboo_below(world: Arc<World>, pos: &BlockPos) -> usize {
|
||||
let mut bamboo_count = 0;
|
||||
let mut found_bamboo_below = true;
|
||||
let mut current_position = pos.down();
|
||||
while found_bamboo_below && bamboo_count < 16 {
|
||||
found_bamboo_below = false;
|
||||
if world.get_block(¤t_position).await == &Block::BAMBOO {
|
||||
current_position = current_position.down();
|
||||
bamboo_count += 1;
|
||||
found_bamboo_below = true;
|
||||
}
|
||||
}
|
||||
bamboo_count
|
||||
}
|
||||
|
||||
async fn count_bamboo_above(world: Arc<World>, pos: &BlockPos) -> usize {
|
||||
let mut bamboo_count = 0;
|
||||
let mut found_bamboo_below = true;
|
||||
let mut current_position = pos.up();
|
||||
while found_bamboo_below && bamboo_count < 16 {
|
||||
found_bamboo_below = false;
|
||||
if world.get_block(¤t_position).await == &Block::BAMBOO {
|
||||
current_position = current_position.up();
|
||||
bamboo_count += 1;
|
||||
found_bamboo_below = true;
|
||||
}
|
||||
}
|
||||
bamboo_count
|
||||
}
|
||||
|
||||
async fn bone_meal(world: Arc<World>, position: &BlockPos) {
|
||||
let mut bamboo_above = count_bamboo_above(Arc::clone(&world), position).await;
|
||||
let bamboo_below = count_bamboo_below(Arc::clone(&world), position).await;
|
||||
let mut new_height = bamboo_above + bamboo_below + 1;
|
||||
let l = rand::rng().random_range(0..=2) + 1; // what is this?
|
||||
for _ in 0..l {
|
||||
let next_pos = position.up_height(bamboo_above as i32);
|
||||
let next_state = world.get_block_state(&next_pos).await;
|
||||
if !next_state.is_air() || new_height >= 16 {
|
||||
return;
|
||||
}
|
||||
let next_props = BambooLikeProperties::from_state_id(next_state.id, &Block::BAMBOO);
|
||||
|
||||
if next_props.stage == Integer0To1::L1 {
|
||||
return;
|
||||
}
|
||||
update_leaves_and_grow(Arc::clone(&world), position).await;
|
||||
new_height += 1;
|
||||
bamboo_above += 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl PlantBlockBase for BambooBlock {
|
||||
async fn can_plant_on_top(
|
||||
&self,
|
||||
block_accessor: &dyn pumpkin_world::world::BlockAccessor,
|
||||
pos: &pumpkin_util::math::position::BlockPos,
|
||||
) -> bool {
|
||||
let block = block_accessor.get_block(pos).await;
|
||||
block.has_tag(&tag::Block::MINECRAFT_BAMBOO_PLANTABLE_ON)
|
||||
}
|
||||
|
||||
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await
|
||||
}
|
||||
}
|
||||
119
pumpkin/src/block/blocks/plant/bamboo_sapling.rs
Normal file
119
pumpkin/src/block/blocks/plant/bamboo_sapling.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
use pumpkin_data::{
|
||||
Block, BlockDirection,
|
||||
block_properties::{BambooLeaves, BambooLikeProperties, BlockProperties},
|
||||
item::Item,
|
||||
tag::Taggable,
|
||||
};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{
|
||||
BlockStateId,
|
||||
world::{BlockAccessor, BlockFlags},
|
||||
};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::block::{
|
||||
BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
|
||||
OnNeighborUpdateArgs, UseWithItemArgs, blocks::plant::PlantBlockBase,
|
||||
registry::BlockActionResult,
|
||||
};
|
||||
|
||||
#[pumpkin_block("minecraft:bamboo_sapling")]
|
||||
pub struct BambooSaplingBlock;
|
||||
|
||||
impl BlockBehaviour for BambooSaplingBlock {
|
||||
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.down())
|
||||
.await
|
||||
})
|
||||
}
|
||||
|
||||
fn use_with_item<'a>(
|
||||
&'a self,
|
||||
args: UseWithItemArgs<'a>,
|
||||
) -> BlockFuture<'a, BlockActionResult> {
|
||||
Box::pin(async move {
|
||||
let lock = args.item_stack.lock().await;
|
||||
if lock.get_item() == &Item::BONE_MEAL {
|
||||
let mut props_new = BambooLikeProperties::from_state_id(
|
||||
Block::BAMBOO.default_state.id,
|
||||
&Block::BAMBOO,
|
||||
);
|
||||
props_new.leaves = BambooLeaves::Small;
|
||||
args.world
|
||||
.set_block_state(
|
||||
&args.position.up(),
|
||||
props_new.to_state_id(&Block::BAMBOO),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
return BlockActionResult::Success;
|
||||
}
|
||||
BlockActionResult::Pass
|
||||
})
|
||||
}
|
||||
|
||||
fn on_neighbor_update<'a>(&'a self, args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if args.block == &Block::BAMBOO_SAPLING
|
||||
&& args.world.get_block(&args.position.up()).await == &Block::BAMBOO
|
||||
{
|
||||
args.world
|
||||
.set_block_state(
|
||||
args.position,
|
||||
Block::BAMBOO.default_state.id,
|
||||
BlockFlags::NOTIFY_NEIGHBORS,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_state_for_neighbor_update<'a>(
|
||||
&'a self,
|
||||
args: GetStateForNeighborUpdateArgs<'a>,
|
||||
) -> BlockFuture<'a, BlockStateId> {
|
||||
Box::pin(async move {
|
||||
if !<Self as PlantBlockBase>::can_place_at(self, args.world, args.position).await {
|
||||
return Block::AIR.default_state.id;
|
||||
}
|
||||
if args.direction == BlockDirection::Up
|
||||
&& args.world.get_block(args.neighbor_position).await == &Block::BAMBOO
|
||||
{
|
||||
return Block::BAMBOO.default_state.id;
|
||||
}
|
||||
args.state_id
|
||||
})
|
||||
}
|
||||
|
||||
fn random_tick<'a>(&'a self, args: crate::block::RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
let state_above = args.world.get_block_state(&args.position.up()).await;
|
||||
if !state_above.is_air() || rand::rng().random_range(0..3) > 0 {
|
||||
return;
|
||||
}
|
||||
let mut props_new =
|
||||
BambooLikeProperties::from_state_id(Block::BAMBOO.default_state.id, &Block::BAMBOO);
|
||||
props_new.leaves = BambooLeaves::Small;
|
||||
args.world
|
||||
.set_block_state(
|
||||
&args.position.up(),
|
||||
props_new.to_state_id(&Block::BAMBOO),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlantBlockBase for BambooSaplingBlock {
|
||||
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await
|
||||
}
|
||||
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
let block = block_accessor.get_block(pos).await;
|
||||
block.has_tag(&pumpkin_data::tag::Block::MINECRAFT_BAMBOO_PLANTABLE_ON)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
use pumpkin_data::block_properties::{
|
||||
BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15,
|
||||
};
|
||||
use pumpkin_data::damage::DamageType;
|
||||
use pumpkin_data::tag::Taggable;
|
||||
use pumpkin_data::{Block, BlockDirection, tag};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
@@ -8,10 +9,11 @@ use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::tick::TickPriority;
|
||||
use pumpkin_world::world::{BlockAccessor, BlockFlags};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::block::{
|
||||
BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
|
||||
OnScheduledTickArgs, RandomTickArgs,
|
||||
OnEntityCollisionArgs, OnScheduledTickArgs, RandomTickArgs,
|
||||
};
|
||||
|
||||
#[pumpkin_block("minecraft:cactus")]
|
||||
@@ -30,38 +32,58 @@ impl BlockBehaviour for CactusBlock {
|
||||
|
||||
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if args
|
||||
.world
|
||||
.get_block_state(&args.position.up())
|
||||
.await
|
||||
.is_air()
|
||||
{
|
||||
let state_id = args.world.get_block_state(args.position).await.id;
|
||||
let age = CactusLikeProperties::from_state_id(state_id, args.block).age;
|
||||
if age == Integer0To15::L15 {
|
||||
let block_up = args.position.up();
|
||||
if args.world.get_block_state(&block_up).await.is_air() {
|
||||
let state = args.world.get_block_state(args.position).await;
|
||||
let mut props = CactusLikeProperties::from_state_id(state.id, args.block);
|
||||
let age = props.age;
|
||||
let mut i = 1;
|
||||
while args.world.get_block(&args.position.down_height(i)).await == &Block::CACTUS {
|
||||
i += 1;
|
||||
if 1 == 3 && age == Integer0To15::L15 {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if age == Integer0To15::L8 && can_place_at(args.world.as_ref(), &block_up).await {
|
||||
let d = if i >= 3 { 0.25 } else { 0.1 };
|
||||
if rand::rng().random_range(0.0..1.0) <= d {
|
||||
args.world
|
||||
.set_block_state(
|
||||
&block_up,
|
||||
Block::CACTUS_FLOWER.default_state.id,
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
} else if age == Integer0To15::L15 && i < 3 {
|
||||
args.world
|
||||
.set_block_state(
|
||||
&args.position.up(),
|
||||
&block_up,
|
||||
Block::CACTUS.default_state.id,
|
||||
BlockFlags::empty(),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
let mut new_props = CactusLikeProperties::default(&Block::CACTUS);
|
||||
new_props.age = Integer0To15::L0;
|
||||
args.world
|
||||
.set_block_state(
|
||||
args.position,
|
||||
Block::CACTUS.default_state.id,
|
||||
BlockFlags::empty(),
|
||||
new_props.to_state_id(&Block::CACTUS),
|
||||
BlockFlags::SKIP_BLOCK_ENTITY_REPLACED_CALLBACK,
|
||||
)
|
||||
.await;
|
||||
} else {
|
||||
let props = CactusLikeProperties {
|
||||
age: Integer0To15::from_index(age.to_index() + 1),
|
||||
};
|
||||
args.world
|
||||
.update_neighbor(args.position, &Block::CACTUS)
|
||||
.await;
|
||||
}
|
||||
if age.to_index() < 15 {
|
||||
props.age = Integer0To15::from_index(age.to_index() + 1);
|
||||
args.world
|
||||
.set_block_state(
|
||||
args.position,
|
||||
props.to_state_id(args.block),
|
||||
BlockFlags::empty(),
|
||||
props.to_state_id(&Block::CACTUS),
|
||||
BlockFlags::SKIP_BLOCK_ENTITY_REPLACED_CALLBACK,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
@@ -69,10 +91,14 @@ impl BlockBehaviour for CactusBlock {
|
||||
})
|
||||
}
|
||||
|
||||
// async fn on_entity_collision(&self, _args: OnEntityCollisionArgs<'_>) {
|
||||
// // TODO
|
||||
// //args.entity.damage(1.0, DamageType::CACTUS).await;
|
||||
// }
|
||||
fn on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
log::warn!("CactusBlock::on_entity_collision");
|
||||
Box::pin(async move {
|
||||
args.entity
|
||||
.damage(args.entity, 1.0, DamageType::CACTUS)
|
||||
.await;
|
||||
})
|
||||
}
|
||||
|
||||
fn get_state_for_neighbor_update<'a>(
|
||||
&'a self,
|
||||
@@ -95,8 +121,6 @@ impl BlockBehaviour for CactusBlock {
|
||||
}
|
||||
|
||||
async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
// TODO: use tags
|
||||
// Disallow to place any blocks nearby a cactus
|
||||
for direction in BlockDirection::horizontal() {
|
||||
let (block, state) = world
|
||||
.get_block_and_state(&block_pos.offset(direction.to_offset()))
|
||||
@@ -106,7 +130,6 @@ async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
}
|
||||
}
|
||||
let block = world.get_block(&block_pos.down()).await;
|
||||
// TODO: use tags
|
||||
(block == &Block::CACTUS || block.has_tag(&tag::Block::MINECRAFT_SAND))
|
||||
&& !world.get_block_state(&block_pos.up()).await.is_liquid()
|
||||
}
|
||||
@@ -46,7 +46,7 @@ impl BlockBehaviour for BeetrootBlock {
|
||||
|
||||
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if rand::rng().random_range(0..2) != 0 {
|
||||
if rand::rng().random_range(0..3) == 0 {
|
||||
<Self as CropBlockBase>::random_tick(self, args.world, args.position).await;
|
||||
}
|
||||
})
|
||||
|
||||
@@ -22,7 +22,9 @@ type FarmlandProperties = FarmlandLikeProperties;
|
||||
pub mod beetroot;
|
||||
pub mod carrot;
|
||||
pub mod gourds;
|
||||
pub mod nether_wart;
|
||||
pub mod potatoes;
|
||||
pub mod sweet_berry_bush;
|
||||
pub mod torch_flower;
|
||||
pub mod wheat;
|
||||
|
||||
|
||||
99
pumpkin/src/block/blocks/plant/crop/nether_wart.rs
Normal file
99
pumpkin/src/block/blocks/plant/crop/nether_wart.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, EnumVariants, Integer0To3, NetherWartLikeProperties},
|
||||
};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{
|
||||
BlockStateId,
|
||||
world::{BlockAccessor, BlockFlags},
|
||||
};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{
|
||||
block::{
|
||||
BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, RandomTickArgs,
|
||||
blocks::plant::{PlantBlockBase, crop::CropBlockBase},
|
||||
},
|
||||
world::World,
|
||||
};
|
||||
|
||||
#[pumpkin_block("minecraft:nether_wart")]
|
||||
pub struct NetherWartBlock;
|
||||
|
||||
impl BlockBehaviour for NetherWartBlock {
|
||||
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 random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
<Self as CropBlockBase>::random_tick(self, args.world, args.position).await;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlantBlockBase for NetherWartBlock {
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
let block = block_accessor.get_block(pos).await;
|
||||
block == &Block::SOUL_SAND
|
||||
}
|
||||
|
||||
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl CropBlockBase for NetherWartBlock {
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos).await
|
||||
}
|
||||
|
||||
fn max_age(&self) -> i32 {
|
||||
3
|
||||
}
|
||||
|
||||
fn get_age(&self, state: u16, block: &Block) -> i32 {
|
||||
let props = NetherWartLikeProperties::from_state_id(state, block);
|
||||
i32::from(props.age.to_index())
|
||||
}
|
||||
|
||||
fn state_with_age(&self, block: &Block, state: u16, age: i32) -> BlockStateId {
|
||||
let mut props = NetherWartLikeProperties::from_state_id(state, block);
|
||||
props.age = Integer0To3::from_index(age as u16);
|
||||
props.to_state_id(block)
|
||||
}
|
||||
|
||||
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
|
||||
let (block, state) = world.get_block_and_state_id(pos).await;
|
||||
let age = self.get_age(state, block);
|
||||
if age < self.max_age() && rand::rng().random_range(0..=10) == 0 {
|
||||
world
|
||||
.set_block_state(
|
||||
pos,
|
||||
self.state_with_age(block, state, age + 1),
|
||||
BlockFlags::NOTIFY_NEIGHBORS,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
203
pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs
Normal file
203
pumpkin/src/block/blocks/plant/crop/sweet_berry_bush.rs
Normal file
@@ -0,0 +1,203 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use pumpkin_data::{
|
||||
Block,
|
||||
block_properties::{BlockProperties, EnumVariants, Integer0To3, NetherWartLikeProperties},
|
||||
damage::DamageType,
|
||||
entity::EntityType,
|
||||
item::Item,
|
||||
tag::{self, Taggable},
|
||||
};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{
|
||||
BlockStateId,
|
||||
item::ItemStack,
|
||||
world::{BlockAccessor, BlockFlags},
|
||||
};
|
||||
use rand::Rng;
|
||||
|
||||
use crate::{
|
||||
block::{
|
||||
BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, NormalUseArgs,
|
||||
OnEntityCollisionArgs, RandomTickArgs, UseWithItemArgs,
|
||||
blocks::plant::{PlantBlockBase, crop::CropBlockBase},
|
||||
registry::BlockActionResult,
|
||||
},
|
||||
world::World,
|
||||
};
|
||||
|
||||
#[pumpkin_block("minecraft:sweet_berry_bush")]
|
||||
pub struct SweetBerryBushBlock;
|
||||
|
||||
impl BlockBehaviour for SweetBerryBushBlock {
|
||||
fn normal_use<'a>(&'a self, args: NormalUseArgs<'a>) -> BlockFuture<'a, BlockActionResult> {
|
||||
Box::pin(async move {
|
||||
let state_id = args.world.get_block_state_id(args.position).await;
|
||||
let mut props = NetherWartLikeProperties::from_state_id(state_id, args.block);
|
||||
match props.age {
|
||||
Integer0To3::L2 | Integer0To3::L3 => {
|
||||
let index = props.age.to_index() as u8;
|
||||
props.age = Integer0To3::L1;
|
||||
let count: u8 = rand::rng().random_range((index - 1)..=(index));
|
||||
for _ in 0..count {
|
||||
args.world
|
||||
.drop_stack(
|
||||
args.position,
|
||||
ItemStack::new(1, &Item::SWEET_BERRIES), //
|
||||
)
|
||||
.await;
|
||||
}
|
||||
args.world
|
||||
.set_block_state(
|
||||
args.position,
|
||||
props.to_state_id(&Block::SWEET_BERRY_BUSH),
|
||||
BlockFlags::NOTIFY_ALL,
|
||||
)
|
||||
.await;
|
||||
BlockActionResult::SuccessServer
|
||||
}
|
||||
_ => BlockActionResult::Pass,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn use_with_item<'a>(
|
||||
&'a self,
|
||||
args: UseWithItemArgs<'a>,
|
||||
) -> BlockFuture<'a, BlockActionResult> {
|
||||
Box::pin(async move {
|
||||
let state_id = args.world.get_block_state_id(args.position).await;
|
||||
let props = NetherWartLikeProperties::from_state_id(state_id, &Block::SWEET_BERRY_BUSH);
|
||||
if props.age != Integer0To3::L3
|
||||
&& args.item_stack.lock().await.get_item() == &Item::BONE_MEAL
|
||||
{
|
||||
BlockActionResult::Pass
|
||||
} else {
|
||||
BlockActionResult::PassToDefaultBlockAction
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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 on_entity_collision<'a>(&'a self, args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
let entity = args.entity.get_entity();
|
||||
|
||||
if entity.entity_type == &EntityType::FOX || entity.entity_type == &EntityType::BEE {
|
||||
return;
|
||||
}
|
||||
|
||||
let state_id = args.world.get_block_state_id(args.position).await;
|
||||
let props = NetherWartLikeProperties::from_state_id(state_id, args.block);
|
||||
if props.age == Integer0To3::L0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let velocity = entity.velocity.load(); // FIXME: velocity != momentum/movement
|
||||
|
||||
if velocity.horizontal_length_squared() <= 0.0
|
||||
|| (velocity.x.abs() < 0.003 && velocity.z.abs() < 0.003)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
args.entity
|
||||
.damage(args.entity, 1.0, DamageType::SWEET_BERRY_BUSH)
|
||||
.await;
|
||||
})
|
||||
}
|
||||
|
||||
fn random_tick<'a>(&'a self, args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if rand::rng().random_range(0..5) == 0 {
|
||||
<Self as CropBlockBase>::random_tick(self, args.world, args.position).await;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlantBlockBase for SweetBerryBushBlock {
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
let block = block_accessor.get_block(pos).await;
|
||||
block.has_tag(&tag::Block::MINECRAFT_DIRT)
|
||||
}
|
||||
|
||||
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::AIR.default_state.id;
|
||||
}
|
||||
block_state
|
||||
}
|
||||
|
||||
async fn can_place_at(&self, block_accessor: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, &block_pos.down()).await
|
||||
}
|
||||
}
|
||||
|
||||
impl CropBlockBase for SweetBerryBushBlock {
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
<Self as PlantBlockBase>::can_plant_on_top(self, block_accessor, pos).await
|
||||
}
|
||||
|
||||
fn max_age(&self) -> i32 {
|
||||
3
|
||||
}
|
||||
|
||||
fn get_age(&self, state: u16, block: &Block) -> i32 {
|
||||
let props = NetherWartLikeProperties::from_state_id(state, block);
|
||||
i32::from(props.age.to_index())
|
||||
}
|
||||
|
||||
fn state_with_age(&self, block: &Block, state: u16, age: i32) -> BlockStateId {
|
||||
let mut props = NetherWartLikeProperties::from_state_id(state, block);
|
||||
props.age = Integer0To3::from_index(age as u16);
|
||||
props.to_state_id(block)
|
||||
}
|
||||
|
||||
async fn random_tick(&self, world: &Arc<World>, pos: &BlockPos) {
|
||||
let (block, state) = world.get_block_and_state_id(pos).await;
|
||||
let age = self.get_age(state, block);
|
||||
if age < self.max_age() {
|
||||
let state_above = world.get_block_state(&pos.up()).await;
|
||||
|
||||
if state_above.is_full_cube() || state_above.is_solid() {
|
||||
return;
|
||||
}
|
||||
if rand::rng().random_range(0..=25) == 0 {
|
||||
world
|
||||
.set_block_state(
|
||||
pos,
|
||||
self.state_with_age(block, state, age + 1),
|
||||
BlockFlags::NOTIFY_NEIGHBORS,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,10 @@ use pumpkin_data::{Block, tag, tag::Taggable};
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::{BlockStateId, world::BlockAccessor};
|
||||
|
||||
pub mod bamboo;
|
||||
pub mod bamboo_sapling;
|
||||
pub mod bush;
|
||||
pub mod cactus;
|
||||
pub mod crop;
|
||||
pub mod dry_vegetation;
|
||||
pub mod flower;
|
||||
@@ -10,13 +13,13 @@ pub mod flowerbed;
|
||||
pub mod leaf_litter;
|
||||
pub mod lily_pad;
|
||||
pub mod mushroom_plant;
|
||||
pub mod nether_wart;
|
||||
pub mod roots;
|
||||
pub mod sapling;
|
||||
pub mod sea_grass;
|
||||
pub mod sea_pickles;
|
||||
pub mod segmented;
|
||||
pub mod short_plant;
|
||||
pub mod sugar_cane;
|
||||
pub mod tall_plant;
|
||||
|
||||
trait PlantBlockBase {
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
use pumpkin_data::Block;
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_world::BlockStateId;
|
||||
use pumpkin_world::world::BlockAccessor;
|
||||
|
||||
use crate::block::blocks::plant::PlantBlockBase;
|
||||
use crate::block::{BlockBehaviour, BlockFuture, CanPlaceAtArgs, GetStateForNeighborUpdateArgs};
|
||||
|
||||
#[pumpkin_block("minecraft:nether_wart")]
|
||||
pub struct NetherWartBlock;
|
||||
|
||||
impl BlockBehaviour for NetherWartBlock {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PlantBlockBase for NetherWartBlock {
|
||||
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
|
||||
let block = block_accessor.get_block(pos).await;
|
||||
block == &Block::SOUL_SAND
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,9 @@ impl BlockBehaviour for SugarCaneBlock {
|
||||
.get_block_state(&args.position.up())
|
||||
.await
|
||||
.is_air()
|
||||
&& !(args.world.get_block(&args.position.down()).await == &Block::SUGAR_CANE
|
||||
&& args.world.get_block(&args.position.down().down()).await
|
||||
== &Block::SUGAR_CANE)
|
||||
{
|
||||
let state_id = args.world.get_block_state(args.position).await.id;
|
||||
let age = CactusLikeProperties::from_state_id(state_id, args.block).age;
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::block::blocks::anvil::AnvilBlock;
|
||||
use crate::block::blocks::bamboo::BambooBlock;
|
||||
|
||||
use crate::block::blocks::barrel::BarrelBlock;
|
||||
use crate::block::blocks::barrier::BarrierBlock;
|
||||
use crate::block::blocks::bed::BedBlock;
|
||||
use crate::block::blocks::cactus::CactusBlock;
|
||||
use crate::block::blocks::carpet::{CarpetBlock, MossCarpetBlock, PaleMossCarpetBlock};
|
||||
use crate::block::blocks::carved_pumpkin::CarvedPumpkinBlock;
|
||||
use crate::block::blocks::chests::ChestBlock;
|
||||
@@ -30,7 +29,12 @@ use crate::block::blocks::note::NoteBlock;
|
||||
use crate::block::blocks::piston::piston::PistonBlock;
|
||||
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::bush::BushBlock;
|
||||
use crate::block::blocks::plant::cactus::CactusBlock;
|
||||
use crate::block::blocks::plant::crop::nether_wart::NetherWartBlock;
|
||||
use crate::block::blocks::plant::crop::sweet_berry_bush::SweetBerryBushBlock;
|
||||
use crate::block::blocks::plant::dry_vegetation::DryVegetationBlock;
|
||||
use crate::block::blocks::plant::flower::FlowerBlock;
|
||||
use crate::block::blocks::plant::flowerbed::FlowerbedBlock;
|
||||
@@ -39,6 +43,7 @@ use crate::block::blocks::plant::lily_pad::LilyPadBlock;
|
||||
use crate::block::blocks::plant::mushroom_plant::MushroomPlantBlock;
|
||||
use crate::block::blocks::plant::sapling::SaplingBlock;
|
||||
use crate::block::blocks::plant::short_plant::ShortPlantBlock;
|
||||
use crate::block::blocks::plant::sugar_cane::SugarCaneBlock;
|
||||
use crate::block::blocks::plant::tall_plant::TallPlantBlock;
|
||||
use crate::block::blocks::pumpkin::PumpkinBlock;
|
||||
use crate::block::blocks::redstone::buttons::ButtonBlock;
|
||||
@@ -64,7 +69,6 @@ use crate::block::blocks::signs::SignBlock;
|
||||
use crate::block::blocks::slabs::SlabBlock;
|
||||
use crate::block::blocks::spawner::SpawnerBlock;
|
||||
use crate::block::blocks::stairs::StairBlock;
|
||||
use crate::block::blocks::sugar_cane::SugarCaneBlock;
|
||||
use crate::block::blocks::tnt::TNTBlock;
|
||||
use crate::block::blocks::torches::TorchBlock;
|
||||
use crate::block::blocks::trapdoor::TrapDoorBlock;
|
||||
@@ -103,7 +107,6 @@ use crate::block::blocks::plant::crop::carrot::CarrotBlock;
|
||||
use crate::block::blocks::plant::crop::potatoes::PotatoBlock;
|
||||
use crate::block::blocks::plant::crop::torch_flower::TorchFlowerBlock;
|
||||
use crate::block::blocks::plant::crop::wheat::WheatBlock;
|
||||
use crate::block::blocks::plant::nether_wart::NetherWartBlock;
|
||||
use crate::block::blocks::plant::roots::RootsBlock;
|
||||
use crate::block::blocks::plant::sea_grass::SeaGrassBlock;
|
||||
use crate::block::blocks::plant::sea_pickles::SeaPickleBlock;
|
||||
@@ -168,6 +171,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
manager.register(JukeboxBlock);
|
||||
manager.register(LogBlock);
|
||||
manager.register(BambooBlock);
|
||||
manager.register(BambooSaplingBlock);
|
||||
manager.register(BannerBlock);
|
||||
manager.register(SignBlock);
|
||||
manager.register(SlabBlock);
|
||||
@@ -184,6 +188,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
manager.register(BeetrootBlock);
|
||||
manager.register(TorchFlowerBlock);
|
||||
manager.register(CarrotBlock);
|
||||
manager.register(SweetBerryBushBlock);
|
||||
manager.register(SeaGrassBlock);
|
||||
manager.register(NetherWartBlock);
|
||||
manager.register(WheatBlock);
|
||||
|
||||
@@ -89,14 +89,7 @@ impl CommandExecutor for LocationExecutor {
|
||||
let location = Position3DArgumentConsumer::find_arg(args, ARG_LOCATION)?;
|
||||
|
||||
let success = target
|
||||
.damage_with_context(
|
||||
target.clone(),
|
||||
amount,
|
||||
damage_type,
|
||||
Some(location),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.damage_with_context(&*target, amount, damage_type, Some(location), None, None)
|
||||
.await;
|
||||
|
||||
send_damage_result(sender, success, amount, target.get_display_name().await).await;
|
||||
@@ -143,7 +136,7 @@ impl CommandExecutor for EntityExecutor {
|
||||
|
||||
let success = target
|
||||
.damage_with_context(
|
||||
target.clone(),
|
||||
&*target,
|
||||
amount,
|
||||
damage_type,
|
||||
None,
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::command::tree::CommandTree;
|
||||
use crate::command::tree::builder::{argument, require};
|
||||
use crate::command::{CommandError, CommandExecutor, CommandResult, CommandSender};
|
||||
use crate::entity::EntityBase;
|
||||
use crate::server::Server;
|
||||
use CommandError::InvalidConsumption;
|
||||
|
||||
const NAMES: [&str; 1] = ["kill"];
|
||||
@@ -19,7 +20,7 @@ impl CommandExecutor for Executor {
|
||||
fn execute<'a>(
|
||||
&'a self,
|
||||
sender: &'a CommandSender,
|
||||
_server: &'a crate::server::Server,
|
||||
_server: &'a Server,
|
||||
args: &'a ConsumedArgs<'a>,
|
||||
) -> CommandResult<'a> {
|
||||
Box::pin(async move {
|
||||
@@ -29,7 +30,7 @@ impl CommandExecutor for Executor {
|
||||
|
||||
let target_count = targets.len();
|
||||
for target in targets {
|
||||
target.kill(target.clone()).await;
|
||||
target.kill(&**target).await;
|
||||
}
|
||||
|
||||
let msg = if target_count == 1 {
|
||||
@@ -57,12 +58,12 @@ impl CommandExecutor for SelfExecutor {
|
||||
fn execute<'a>(
|
||||
&'a self,
|
||||
sender: &'a CommandSender,
|
||||
_server: &'a crate::server::Server,
|
||||
_server: &'a Server,
|
||||
_args: &'a ConsumedArgs<'a>,
|
||||
) -> CommandResult<'a> {
|
||||
Box::pin(async move {
|
||||
let target = sender.as_player().ok_or(CommandError::InvalidRequirement)?;
|
||||
target.kill(target.clone()).await;
|
||||
target.kill(&*target).await;
|
||||
|
||||
sender
|
||||
.send_message(TextComponent::translate(
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicI32, AtomicI64, AtomicU8, Ordering},
|
||||
};
|
||||
use std::sync::atomic::{AtomicI32, AtomicI64, AtomicU8, Ordering};
|
||||
|
||||
use crate::entity::{
|
||||
Entity, EntityBase, EntityBaseFuture, NBTStorage, NbtFuture, living::LivingEntity,
|
||||
@@ -300,7 +297,7 @@ impl EntityBase for ArmorStandEntity {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
caller: Arc<dyn EntityBase>,
|
||||
caller: &'a dyn EntityBase,
|
||||
_amount: f32,
|
||||
damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use core::f32;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::entity::{Entity, EntityBase, EntityBaseFuture, NBTStorage, living::LivingEntity};
|
||||
use pumpkin_data::damage::DamageType;
|
||||
@@ -37,7 +36,7 @@ impl EntityBase for EndCrystalEntity {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
_caller: Arc<dyn EntityBase>,
|
||||
_caller: &'a dyn EntityBase,
|
||||
_amount: f32,
|
||||
damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use core::f32;
|
||||
use std::sync::{Arc, atomic::Ordering};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
use crate::entity::{
|
||||
Entity, EntityBase, EntityBaseFuture, NBTStorage, NbtFuture, living::LivingEntity,
|
||||
@@ -44,7 +44,7 @@ impl EntityBase for PaintingEntity {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
_caller: Arc<dyn EntityBase>,
|
||||
_caller: &'a dyn EntityBase,
|
||||
_amount: f32,
|
||||
_damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
|
||||
@@ -71,7 +71,7 @@ impl HungerManager {
|
||||
|| (difficulty == Difficulty::Hard)
|
||||
|| (health > 1.0 && difficulty == Difficulty::Normal)
|
||||
{
|
||||
player.damage(player.clone(), 1.0, DamageType::STARVE).await;
|
||||
player.damage(&**player, 1.0, DamageType::STARVE).await;
|
||||
}
|
||||
self.tick_timer.store(0);
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ impl EntityBase for ItemEntity {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
_caller: Arc<dyn EntityBase>,
|
||||
_caller: &'a dyn EntityBase,
|
||||
amount: f32,
|
||||
_damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
@@ -376,12 +376,12 @@ impl EntityBase for ItemEntity {
|
||||
})
|
||||
}
|
||||
|
||||
fn damage(
|
||||
&self,
|
||||
_caller: Arc<dyn EntityBase>,
|
||||
fn damage<'a>(
|
||||
&'a self,
|
||||
_caller: &'a dyn EntityBase,
|
||||
_amount: f32,
|
||||
_damage_type: DamageType,
|
||||
) -> EntityBaseFuture<'_, bool> {
|
||||
) -> EntityBaseFuture<'a, bool> {
|
||||
Box::pin(async { false })
|
||||
}
|
||||
|
||||
|
||||
@@ -332,7 +332,7 @@ impl LivingEntity {
|
||||
let suffocating = self.entity.tick_block_collisions(&caller, server).await;
|
||||
|
||||
if suffocating {
|
||||
self.damage(caller, 1.0, DamageType::IN_WALL).await;
|
||||
self.damage(&*caller, 1.0, DamageType::IN_WALL).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +697,7 @@ impl LivingEntity {
|
||||
|
||||
// TODO: Play block fall sound
|
||||
if damage > 0.0 {
|
||||
let check_damage = self.damage(caller, damage, DamageType::FALL).await; // Fall
|
||||
let check_damage = self.damage(&*caller, damage, DamageType::FALL).await; // Fall
|
||||
if check_damage {
|
||||
self.entity
|
||||
.play_sound(Self::get_fall_sound(fall_distance as i32))
|
||||
@@ -840,7 +840,7 @@ impl LivingEntity {
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_use_death_protector(&self, caller: &Arc<dyn EntityBase>) -> bool {
|
||||
async fn try_use_death_protector(&self, caller: &dyn EntityBase) -> bool {
|
||||
for hand in Hand::all() {
|
||||
let stack = self.get_stack_in_hand(caller, hand).await;
|
||||
let mut stack = stack.lock().await;
|
||||
@@ -859,7 +859,7 @@ impl LivingEntity {
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn held_item(&self, caller: &Arc<dyn EntityBase>) -> Arc<Mutex<ItemStack>> {
|
||||
pub async fn held_item(&self, caller: &dyn EntityBase) -> Arc<Mutex<ItemStack>> {
|
||||
if let Some(player) = caller.get_player() {
|
||||
return player.inventory.held_item();
|
||||
}
|
||||
@@ -873,7 +873,7 @@ impl LivingEntity {
|
||||
|
||||
pub async fn get_stack_in_hand(
|
||||
&self,
|
||||
caller: &Arc<dyn EntityBase>,
|
||||
caller: &dyn EntityBase,
|
||||
hand: Hand,
|
||||
) -> Arc<Mutex<ItemStack>> {
|
||||
match hand {
|
||||
@@ -962,7 +962,7 @@ impl NBTStorage for LivingEntity {
|
||||
impl EntityBase for LivingEntity {
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
caller: Arc<dyn EntityBase>,
|
||||
caller: &'a dyn EntityBase,
|
||||
amount: f32,
|
||||
damage_type: DamageType,
|
||||
position: Option<Vector3<f64>>,
|
||||
@@ -1046,7 +1046,7 @@ impl EntityBase for LivingEntity {
|
||||
self.set_health(new_health).await;
|
||||
}
|
||||
|
||||
if new_health <= 0.0 && !self.try_use_death_protector(&caller).await {
|
||||
if new_health <= 0.0 && !self.try_use_death_protector(caller).await {
|
||||
self.on_death(damage_type, source, cause).await;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ impl<T: Mob + Send + 'static> EntityBase for T {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
caller: Arc<dyn EntityBase>,
|
||||
caller: &'a dyn EntityBase,
|
||||
amount: f32,
|
||||
damage_type: DamageType,
|
||||
position: Option<Vector3<f64>>,
|
||||
|
||||
@@ -126,12 +126,12 @@ pub trait EntityBase: Send + Sync + NBTStorage {
|
||||
}
|
||||
|
||||
/// Returns if damage was successful or not
|
||||
fn damage(
|
||||
&self,
|
||||
caller: Arc<dyn EntityBase>,
|
||||
fn damage<'a>(
|
||||
&'a self,
|
||||
caller: &'a dyn EntityBase,
|
||||
amount: f32,
|
||||
damage_type: DamageType,
|
||||
) -> EntityBaseFuture<'_, bool> {
|
||||
) -> EntityBaseFuture<'a, bool> {
|
||||
Box::pin(async move {
|
||||
self.damage_with_context(caller, amount, damage_type, None, None, None)
|
||||
.await
|
||||
@@ -156,7 +156,7 @@ pub trait EntityBase: Send + Sync + NBTStorage {
|
||||
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
_caller: Arc<dyn EntityBase>,
|
||||
_caller: &'a dyn EntityBase,
|
||||
_amount: f32,
|
||||
_damage_type: DamageType,
|
||||
_position: Option<Vector3<f64>>,
|
||||
@@ -220,7 +220,7 @@ pub trait EntityBase: Send + Sync + NBTStorage {
|
||||
}
|
||||
|
||||
/// Kills the Entity.
|
||||
fn kill(&self, caller: Arc<dyn EntityBase>) -> EntityBaseFuture<'_, ()> {
|
||||
fn kill<'a>(&'a self, caller: &'a dyn EntityBase) -> EntityBaseFuture<'a, ()> {
|
||||
Box::pin(async move {
|
||||
if let Some(living) = self.get_living_entity() {
|
||||
living
|
||||
@@ -1761,11 +1761,11 @@ impl Entity {
|
||||
vehicle.is_some()
|
||||
}
|
||||
|
||||
pub async fn check_out_of_world(&self, dyn_self: Arc<dyn EntityBase>) {
|
||||
pub async fn check_out_of_world(&self, dyn_self: &dyn EntityBase) {
|
||||
if self.pos.load().y < f64::from(self.world.generation_settings().shape.min_y) - 64.0 {
|
||||
// Tick out of world damage
|
||||
dyn_self
|
||||
.damage(dyn_self.clone(), 4.0, DamageType::OUT_OF_WORLD)
|
||||
.damage(dyn_self, 4.0, DamageType::OUT_OF_WORLD)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
@@ -1871,7 +1871,7 @@ impl EntityBase for Entity {
|
||||
Box::pin(async move {
|
||||
self.tick_portal(&caller).await;
|
||||
self.update_fluid_state(&caller).await;
|
||||
self.check_out_of_world(caller.clone()).await;
|
||||
self.check_out_of_world(&*caller).await;
|
||||
let fire_ticks = self.fire_ticks.load(Ordering::Relaxed);
|
||||
if fire_ticks > 0 {
|
||||
if self.entity_type.fire_immune {
|
||||
@@ -1881,9 +1881,7 @@ impl EntityBase for Entity {
|
||||
}
|
||||
} else {
|
||||
if fire_ticks % 20 == 0 {
|
||||
caller
|
||||
.damage(caller.clone(), 1.0, DamageType::ON_FIRE)
|
||||
.await;
|
||||
caller.damage(&*caller, 1.0, DamageType::ON_FIRE).await;
|
||||
}
|
||||
|
||||
self.fire_ticks.store(fire_ticks - 1, Ordering::Relaxed);
|
||||
|
||||
@@ -621,7 +621,7 @@ impl Player {
|
||||
|
||||
if !victim
|
||||
.damage_with_context(
|
||||
victim.clone(),
|
||||
&*victim,
|
||||
damage as f32,
|
||||
DamageType::PLAYER_ATTACK,
|
||||
None,
|
||||
@@ -2313,7 +2313,7 @@ impl NBTStorageInit for EnderChestInventory {}
|
||||
impl EntityBase for Player {
|
||||
fn damage_with_context<'a>(
|
||||
&'a self,
|
||||
caller: Arc<dyn EntityBase>,
|
||||
caller: &'a dyn EntityBase,
|
||||
amount: f32,
|
||||
damage_type: DamageType,
|
||||
position: Option<Vector3<f64>>,
|
||||
|
||||
@@ -14,6 +14,7 @@ pub mod loot;
|
||||
pub mod portal;
|
||||
pub mod time;
|
||||
|
||||
use crate::block::RandomTickArgs;
|
||||
use crate::world::loot::LootContextParameters;
|
||||
use crate::{
|
||||
PLUGIN_MANAGER,
|
||||
@@ -712,7 +713,8 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Fix this deadlock
|
||||
// TODO: Fix this deadlock
|
||||
// TODO: ^ find this deadlock ^
|
||||
for scheduled_tick in tick_data.random_ticks {
|
||||
let block = self.get_block(&scheduled_tick.position).await;
|
||||
if let Some(pumpkin_block) = self.block_registry.get_pumpkin_block(block) {
|
||||
@@ -724,7 +726,7 @@ impl World {
|
||||
})
|
||||
.await;
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
let spawn_entity_clock_start = tokio::time::Instant::now();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user