Correct bed placement (#797)

* Added bed

* Changed can_place_at params to match on_place

* Bed placement restrictions

* Removed replacing from can_place_at, as it is handled by can_update_at

* Made fire work with the on_place changes
This commit is contained in:
Laurent Stéphenne
2025-05-06 12:21:47 -04:00
committed by GitHub
parent 1b78299193
commit 5645eb4f6f
41 changed files with 622 additions and 414 deletions

View File

@@ -0,0 +1,140 @@
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::BlockState;
use pumpkin_data::block_properties::BedPart;
use pumpkin_data::block_properties::BlockProperties;
use pumpkin_data::tag::RegistryKey;
use pumpkin_data::tag::get_tag_values;
use pumpkin_util::GameMode;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use std::sync::Arc;
use crate::block::BlockIsReplacing;
use crate::block::pumpkin_block::{BlockMetadata, PumpkinBlock};
use crate::entity::player::Player;
use crate::world::BlockFlags;
use pumpkin_protocol::server::play::SUseItemOn;
use crate::server::Server;
use crate::world::World;
type BedProperties = pumpkin_data::block_properties::WhiteBedLikeProperties;
pub struct BedBlock;
impl BlockMetadata for BedBlock {
fn namespace(&self) -> &'static str {
"minecraft"
}
fn ids(&self) -> &'static [&'static str] {
get_tag_values(RegistryKey::Block, "minecraft:beds").unwrap()
}
}
#[async_trait]
impl PumpkinBlock for BedBlock {
async fn can_place_at(
&self,
_server: &Server,
world: &World,
player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
let facing = player.living_entity.entity.get_horizontal_facing();
world
.get_block_state(block_pos)
.await
.is_ok_and(|state| state.replaceable())
&& world
.get_block_state(&block_pos.offset(facing.to_offset()))
.await
.is_ok_and(|state| state.replaceable())
}
async fn on_place(
&self,
_server: &Server,
_world: &World,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut bed_props = BedProperties::default(block);
bed_props.facing = player.living_entity.entity.get_horizontal_facing();
bed_props.part = BedPart::Foot;
bed_props.to_state_id(block)
}
async fn placed(
&self,
world: &Arc<World>,
block: &Block,
state_id: BlockStateId,
block_pos: &BlockPos,
_old_state_id: BlockStateId,
_notify: bool,
) {
let mut head_props = BedProperties::default(block);
head_props.facing = BedProperties::from_state_id(state_id, block).facing;
head_props.part = BedPart::Head;
world
.set_block_state(
&block_pos.offset(head_props.facing.to_offset()),
head_props.to_state_id(block),
BlockFlags::NOTIFY_ALL | BlockFlags::SKIP_BLOCK_ADDED_CALLBACK,
)
.await;
}
async fn broken(
&self,
block: &Block,
player: &Arc<Player>,
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
) {
let bed_props = BedProperties::from_state_id(state.id, block);
let other_half_pos = if bed_props.part == BedPart::Head {
block_pos.offset(bed_props.facing.opposite().to_offset())
} else {
block_pos.offset(bed_props.facing.to_offset())
};
world
.break_block(
&other_half_pos,
Some(player.clone()),
if player.gamemode.load() == GameMode::Creative {
BlockFlags::SKIP_DROPS | BlockFlags::NOTIFY_NEIGHBORS
} else {
BlockFlags::NOTIFY_NEIGHBORS
},
)
.await;
}
async fn normal_use(
&self,
_block: &Block,
_player: &Player,
_location: BlockPos,
_server: &Server,
_world: &Arc<World>,
) {
// Sleep
}
}

View File

@@ -1,20 +1,23 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::tag::Tagable;
use pumpkin_data::{
Block,
block_properties::{BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15},
use pumpkin_data::Block;
use pumpkin_data::block_properties::{
BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15,
};
use pumpkin_data::tag::Tagable;
use pumpkin_macros::pumpkin_block;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use pumpkin_world::chunk::TickPriority;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::BlockFlags;
use crate::world::World;
use pumpkin_util::math::position::BlockPos;
#[pumpkin_block("minecraft:cactus")]
pub struct CactusBlock;
@@ -22,7 +25,7 @@ pub struct CactusBlock;
#[async_trait]
impl PumpkinBlock for CactusBlock {
async fn on_scheduled_tick(&self, world: &Arc<World>, _block: &Block, pos: &BlockPos) {
if !self.can_place_at(world, pos, BlockDirection::Down).await {
if !can_place_at(world, pos).await {
world.break_block(pos, None, BlockFlags::empty()).await;
}
}
@@ -66,29 +69,47 @@ impl PumpkinBlock for CactusBlock {
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if !self.can_place_at(world, pos, BlockDirection::Down).await {
if !can_place_at(world, pos).await {
world
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
.await;
}
state
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
// TODO: use tags
// Disallow to place any blocks nearby a cactus
for direction in BlockDirection::horizontal() {
let (block, state) = world
.get_block_and_block_state(&pos.offset(direction.to_offset()))
.await
.unwrap();
if state.is_solid() || block == Block::LAVA {
return false;
}
}
let block = world.get_block(&pos.down()).await.unwrap();
// TODO: use tags
(block == Block::CACTUS || block.is_tagged_with("minecraft:sand").unwrap())
&& !world.get_block_state(&pos.up()).await.unwrap().is_liquid()
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_at(world, block_pos).await
}
}
async fn can_place_at(world: &World, 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_block_state(&block_pos.offset(direction.to_offset()))
.await
.unwrap();
if state.is_solid() || block == Block::LAVA {
return false;
}
}
let block = world.get_block(&block_pos.down()).await.unwrap();
// TODO: use tags
(block == Block::CACTUS || block.is_tagged_with("minecraft:sand").unwrap())
&& !world
.get_block_state(&block_pos.up())
.await
.unwrap()
.is_liquid()
}

View File

@@ -44,12 +44,12 @@ impl PumpkinBlock for ChestBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut chest_props = ChestLikeProperties::default(block);
@@ -131,7 +131,7 @@ impl PumpkinBlock for ChestBlock {
async fn broken(
&self,
block: &Block,
player: &Player,
player: &Arc<Player>,
block_pos: BlockPos,
server: &Server,
world: Arc<World>,

View File

@@ -46,7 +46,7 @@ impl PumpkinBlock for CraftingTableBlock {
async fn broken(
&self,
block: &Block,
player: &Player,
player: &Arc<Player>,
location: BlockPos,
server: &Server,
_world: Arc<World>,

View File

@@ -31,16 +31,17 @@ impl PumpkinBlock for DirtPathBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
if !self.can_place_at(world, pos, BlockDirection::Down).await {
if !can_place_at(world, block_pos).await {
return Block::DIRT.default_state_id;
}
block.default_state_id
}
@@ -54,9 +55,7 @@ impl PumpkinBlock for DirtPathBlock {
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if direction == BlockDirection::Up
&& !self.can_place_at(world, pos, BlockDirection::Down).await
{
if direction == BlockDirection::Up && !can_place_at(world, pos).await {
world
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
.await;
@@ -64,8 +63,21 @@ impl PumpkinBlock for DirtPathBlock {
state
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
let state = world.get_block_state(&pos.up()).await.unwrap();
!state.is_solid() // TODO: add fence gata block
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_at(world, block_pos).await
}
}
async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
let state = world.get_block_state(&block_pos.up()).await.unwrap();
!state.is_solid() // TODO: add fence gate block
}

View File

@@ -167,12 +167,12 @@ impl PumpkinBlock for DoorBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
use_item_on: &SUseItemOn,
) -> BlockStateId {
let powered = block_receives_redstone_power(world, block_pos).await
|| block_receives_redstone_power(world, &block_pos.up()).await;
@@ -192,18 +192,15 @@ impl PumpkinBlock for DoorBlock {
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
world
.get_block_state(&block_pos.offset(BlockDirection::Up.to_offset()))
.await
.is_ok_and(|state| state.replaceable())
&& world
.get_block_state(&block_pos.offset(BlockDirection::Down.to_offset()))
.await
.is_ok_and(|state| state.is_solid() && state.is_full_cube())
can_place_at(world, block_pos).await
}
async fn placed(
@@ -328,7 +325,7 @@ impl PumpkinBlock for DoorBlock {
{
if lv == DoubleBlockHalf::Lower
&& direction == BlockDirection::Down
&& !self.can_place_at(world, block_pos, direction).await
&& !can_place_at(world, block_pos).await
{
return 0;
}
@@ -344,3 +341,14 @@ impl PumpkinBlock for DoorBlock {
state
}
}
async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
world
.get_block_state(&block_pos.up())
.await
.is_ok_and(|state| state.replaceable())
&& world
.get_block_state(&block_pos.down())
.await
.is_ok_and(|state| state.is_solid() && state.is_full_cube())
}

View File

@@ -31,14 +31,14 @@ impl PumpkinBlock for FarmLandBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
face: BlockDirection,
pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player_direction: &Player,
block: &Block,
pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
if !self.can_place_at(world, pos, face).await {
if !can_place_at(world, pos).await {
return Block::DIRT.default_state_id;
}
block.default_state_id
@@ -54,9 +54,7 @@ impl PumpkinBlock for FarmLandBlock {
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if direction == BlockDirection::Up
&& !self.can_place_at(world, pos, BlockDirection::Down).await
{
if direction == BlockDirection::Up && !can_place_at(world, pos).await {
world
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
.await;
@@ -64,8 +62,21 @@ impl PumpkinBlock for FarmLandBlock {
state
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
let state = world.get_block_state(&pos.up()).await.unwrap();
!state.is_solid() // TODO: add fence gata block
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_at(world, block_pos).await
}
}
async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
let state = world.get_block_state(&block_pos.up()).await.unwrap();
!state.is_solid() // TODO: add fence gate block
}

View File

@@ -54,12 +54,12 @@ impl PumpkinBlock for FenceGateBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
_face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut fence_gate_props = FenceGateProperties::default(block);
fence_gate_props.facing = player.living_entity.entity.get_horizontal_facing();

View File

@@ -36,12 +36,12 @@ impl PumpkinBlock for FenceBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> u16 {
let mut fence_props = FenceProperties::default(block);
fence_props.waterlogged = replacing.water_source();

View File

@@ -1,18 +1,22 @@
use pumpkin_data::block_properties::HorizontalAxis;
use pumpkin_registry::DimensionType;
use rand::Rng;
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use pumpkin_world::chunk::TickPriority;
use rand::Rng;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use async_trait::async_trait;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use crate::world::portal::NetherPortal;
use super::FireBlockBase;
@@ -34,18 +38,23 @@ impl PumpkinBlock for FireBlock {
state_id: BlockStateId,
pos: &BlockPos,
old_state_id: BlockStateId,
notify: bool,
_notify: bool,
) {
FireBlockBase::placed(
&FireBlockBase,
world,
block,
state_id,
pos,
old_state_id,
notify,
)
.await;
if old_state_id == state_id {
// Already a fire
return;
}
let dimension = world.dimension_type;
// First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla
if dimension == DimensionType::Overworld || dimension == DimensionType::TheNether {
if let Some(portal) = NetherPortal::get_new_portal(world, pos, HorizontalAxis::X).await
{
portal.create(world).await;
return;
}
}
world
.schedule_block_tick(
block,
@@ -60,37 +69,41 @@ impl PumpkinBlock for FireBlock {
&self,
world: &World,
_block: &Block,
state: BlockStateId,
state_id: BlockStateId,
block_pos: &BlockPos,
direction: BlockDirection,
_direction: BlockDirection,
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
// TODO: add can_place_at
if self.can_place_at(world, block_pos, direction).await {
return state;
if !FireBlockBase::can_place_on(&world.get_block(&block_pos.down()).await.unwrap()) {
return Block::AIR.default_state_id;
}
Block::AIR.default_state_id
state_id
}
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
FireBlockBase::can_place_at(world, block_pos).await
}
async fn broken(
&self,
block: &Block,
player: &Player,
position: BlockPos,
server: &Server,
_block: &Block,
_player: &Arc<Player>,
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
_state: BlockState,
) {
FireBlockBase::broken(
&FireBlockBase,
block,
player,
position,
server,
world,
state,
)
.await;
FireBlockBase::broken(world, block_pos).await;
}
}

View File

@@ -1,20 +1,12 @@
use std::sync::Arc;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use crate::world::portal::NetherPortal;
use async_trait::async_trait;
use pumpkin_data::block_properties::HorizontalAxis;
use pumpkin_data::Block;
use pumpkin_data::world::WorldEvent;
use pumpkin_data::{Block, BlockState};
use pumpkin_registry::DimensionType;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use soul_fire::SoulFireBlock;
use crate::world::World;
#[expect(clippy::module_inception)]
pub mod fire;
pub mod soul_fire;
@@ -22,7 +14,7 @@ pub mod soul_fire;
pub struct FireBlockBase;
impl FireBlockBase {
pub async fn get_state(world: &World, pos: &BlockPos) -> Block {
pub async fn get_fire_type(world: &World, pos: &BlockPos) -> Block {
let (block, _block_state) = world.get_block_and_block_state(&pos.down()).await.unwrap();
if SoulFireBlock::is_soul_base(&block) {
return Block::SOUL_FIRE;
@@ -30,62 +22,24 @@ impl FireBlockBase {
// TODO
Block::FIRE
}
}
#[async_trait]
impl PumpkinBlock for FireBlockBase {
async fn placed(
&self,
world: &Arc<World>,
_block: &Block,
state_id: BlockStateId,
pos: &BlockPos,
old_state_id: BlockStateId,
_notify: bool,
) {
if old_state_id == state_id {
return;
}
let dimension = world.dimension_type;
// First lets check if we are in OverWorld or Nether, its not possible to place an Nether portal in other dimensions in Vanilla
if dimension == DimensionType::Overworld || dimension == DimensionType::TheNether {
if let Some(portal) = NetherPortal::get_new_portal(world, pos, HorizontalAxis::X).await
{
portal.create(world).await;
}
}
pub fn can_place_on(_block: &Block) -> bool {
// TODO: make sure the block can be lit
// block
// .is_tagged_with("minecraft:soul_fire_base_blocks")
// .unwrap()
true
}
async fn can_place_at(
&self,
world: &World,
block_pos: &BlockPos,
face: BlockDirection,
) -> bool {
pub async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
let block_state = world.get_block_state(block_pos).await.unwrap();
if !block_state.is_air() {
return false;
}
let block = Self::get_state(world, block_pos).await;
if let Some(block) = world.block_registry.get_pumpkin_block(&block) {
return block.can_place_at(world, block_pos, face).await;
}
return false;
block_state.is_air()
&& Self::can_place_on(&world.get_block(&block_pos.down()).await.unwrap())
}
async fn broken(
&self,
_block: &Block,
_player: &Player,
position: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
) {
async fn broken(world: Arc<World>, block_pos: BlockPos) {
world
.sync_world_event(WorldEvent::FireExtinguished, position, 0)
.sync_world_event(WorldEvent::FireExtinguished, block_pos, 0)
.await;
}
}

View File

@@ -1,17 +1,18 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::tag::Tagable;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::World;
use async_trait::async_trait;
use pumpkin_data::{Block, BlockState};
use pumpkin_macros::pumpkin_block;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use super::FireBlockBase;
@@ -28,70 +29,46 @@ impl SoulFireBlock {
#[async_trait]
impl PumpkinBlock for SoulFireBlock {
async fn placed(
&self,
world: &Arc<World>,
block: &Block,
state_id: BlockStateId,
pos: &BlockPos,
old_state_id: BlockStateId,
notify: bool,
) {
FireBlockBase::placed(
&FireBlockBase,
world,
block,
state_id,
pos,
old_state_id,
notify,
)
.await;
}
async fn get_state_for_neighbor_update(
&self,
world: &World,
_block: &Block,
state: BlockStateId,
state_id: BlockStateId,
block_pos: &BlockPos,
direction: BlockDirection,
_direction: BlockDirection,
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if self.can_place_at(world, block_pos, direction).await {
return state;
if !Self::is_soul_base(&world.get_block(&block_pos.down()).await.unwrap()) {
return Block::AIR.default_state_id;
}
Block::AIR.default_state_id
state_id
}
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
Self::is_soul_base(&world.get_block(&block_pos.down()).await.unwrap())
FireBlockBase::can_place_at(world, block_pos).await
&& Self::is_soul_base(&world.get_block(&block_pos.down()).await.unwrap())
}
async fn broken(
&self,
block: &Block,
player: &Player,
position: BlockPos,
server: &Server,
_block: &Block,
_player: &Arc<Player>,
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
_state: BlockState,
) {
FireBlockBase::broken(
&FireBlockBase,
block,
player,
position,
server,
world,
state,
)
.await;
FireBlockBase::broken(world, block_pos).await;
}
}

View File

@@ -46,7 +46,7 @@ impl PumpkinBlock for FurnaceBlock {
async fn broken(
&self,
block: &Block,
player: &Player,
player: &Arc<Player>,
location: BlockPos,
server: &Server,
_world: Arc<World>,

View File

@@ -34,12 +34,12 @@ impl PumpkinBlock for GlassPaneBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> u16 {
let mut pane_props = GlassPaneProperties::default(block);
pane_props.waterlogged = replacing.water_source();

View File

@@ -25,12 +25,12 @@ impl PumpkinBlock for IronBarsBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> u16 {
let mut bars_props = IronBarsProperties::default(block);
bars_props.waterlogged = replacing.water_source();

View File

@@ -112,7 +112,7 @@ impl PumpkinBlock for JukeboxBlock {
async fn broken(
&self,
_block: &Block,
_player: &Player,
_player: &Arc<Player>,
position: BlockPos,
_server: &Server,
world: Arc<World>,

View File

@@ -32,12 +32,12 @@ impl PumpkinBlock for LogBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut log_props = LogProperties::default(block);
log_props.axis = face.to_axis();

View File

@@ -5,6 +5,7 @@ use pumpkin_util::math::position::BlockPos;
use crate::{entity::player::Player, server::Server};
pub mod bed;
pub mod cactus;
pub mod chest;
pub mod crafting_table;

View File

@@ -64,12 +64,12 @@ impl PumpkinBlock for ButtonBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = ButtonLikeProperties::default(block);

View File

@@ -45,12 +45,12 @@ impl PumpkinBlock for LeverBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut lever_props = LeverLikeProperties::from_state_id(block.default_state_id, block);

View File

@@ -30,12 +30,12 @@ impl PumpkinBlock for ObserverBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
_face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = ObserverLikeProperties::default(block);
props.facing = player.living_entity.entity.get_facing();

View File

@@ -35,12 +35,12 @@ impl PumpkinBlock for PistonBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
_face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = PistonProps::default(block);
props.extended = false;

View File

@@ -29,12 +29,12 @@ impl PumpkinBlock for ActivatorRailBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut rail_props = RailProperties::default(block);
let player_facing = player.living_entity.entity.get_horizontal_facing();
@@ -74,7 +74,16 @@ impl PumpkinBlock for ActivatorRailBlock {
}
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
can_place_rail_at(world, pos).await
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_rail_at(world, block_pos).await
}
}

View File

@@ -29,12 +29,12 @@ impl PumpkinBlock for DetectorRailBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut rail_props = RailProperties::default(block);
let player_facing = player.living_entity.entity.get_horizontal_facing();
@@ -74,7 +74,16 @@ impl PumpkinBlock for DetectorRailBlock {
}
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
can_place_rail_at(world, pos).await
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_rail_at(world, block_pos).await
}
}

View File

@@ -29,12 +29,12 @@ impl PumpkinBlock for PoweredRailBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut rail_props = RailProperties::default(block);
let player_facing = player.living_entity.entity.get_horizontal_facing();
@@ -74,7 +74,16 @@ impl PumpkinBlock for PoweredRailBlock {
}
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
can_place_rail_at(world, pos).await
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_rail_at(world, block_pos).await
}
}

View File

@@ -29,12 +29,12 @@ impl PumpkinBlock for RailBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut rail_props = RailProperties::default(block);
rail_props.set_waterlogged(replacing.water_source());
@@ -146,7 +146,16 @@ impl PumpkinBlock for RailBlock {
}
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
can_place_rail_at(world, pos).await
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_rail_at(world, block_pos).await
}
}

View File

@@ -27,12 +27,12 @@ impl PumpkinBlock for RedstoneLamp {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = RedstoneLampProperties::default(block);
props.lit = block_receives_redstone_power(world, block_pos).await;

View File

@@ -41,12 +41,12 @@ impl PumpkinBlock for RedstoneTorchBlock {
&self,
_server: &Server,
world: &World,
_block: &Block,
face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
if face.is_horizontal() {
let mut torch_props = RWallTorchProps::default(&Block::REDSTONE_WALL_TORCH);

View File

@@ -30,29 +30,29 @@ pub struct RedstoneWireBlock;
#[async_trait]
impl PumpkinBlock for RedstoneWireBlock {
// Start of placement
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
let floor = world.get_block_state(&block_pos.down()).await.unwrap();
// TODO: Only check face instead of block
return floor.is_full_cube();
can_place_at(world, block_pos).await
}
async fn on_place(
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut wire = RedstoneWireProperties::default(block);
wire.power = Integer0To15::from_index(calculate_power(world, block_pos).await.into());
@@ -201,7 +201,7 @@ impl PumpkinBlock for RedstoneWireBlock {
_source_block: &Block,
_notify: bool,
) {
if self.can_place_at(world, pos, BlockDirection::Down).await {
if can_place_at(world, pos).await {
let state = world.get_block_state(pos).await.unwrap();
let mut wire = RedstoneWireProperties::from_state_id(state.id, block);
let new_power = calculate_power(world, pos).await;
@@ -268,7 +268,7 @@ impl PumpkinBlock for RedstoneWireBlock {
async fn broken(
&self,
_block: &Block,
_player: &Player,
_player: &Arc<Player>,
location: BlockPos,
_server: &Server,
world: Arc<World>,
@@ -278,6 +278,12 @@ impl PumpkinBlock for RedstoneWireBlock {
}
}
async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
let floor = world.get_block_state(&block_pos.down()).await.unwrap();
// TODO: Only check face instead of block
floor.is_full_cube()
}
async fn on_use(wire: RedstoneWireProperties, world: &Arc<World>, block_pos: &BlockPos) -> bool {
if is_cross(wire) || is_dot(wire) {
let mut new_wire = if is_cross(wire) {

View File

@@ -32,12 +32,12 @@ impl PumpkinBlock for RepeaterBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut props = RepeaterProperties::default(block);
let dir = player

View File

@@ -36,12 +36,12 @@ impl PumpkinBlock for SignBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
_face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> u16 {
let mut sign_props = SignProperties::default(block);
sign_props.waterlogged = replacing.water_source();

View File

@@ -34,12 +34,12 @@ impl PumpkinBlock for SlabBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
face: BlockDirection,
_block_pos: &BlockPos,
use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
replacing: BlockIsReplacing,
use_item_on: &SUseItemOn,
) -> BlockStateId {
if let BlockIsReplacing::Itself(state_id) = replacing {
let mut slab_props = SlabProperties::from_state_id(state_id, block);

View File

@@ -39,12 +39,12 @@ impl PumpkinBlock for StairBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
face: BlockDirection,
block_pos: &BlockPos,
use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
replacing: BlockIsReplacing,
use_item_on: &SUseItemOn,
) -> BlockStateId {
let mut stair_props = StairsProperties::default(block);
stair_props.waterlogged = replacing.water_source();

View File

@@ -1,20 +1,24 @@
use std::sync::Arc;
use async_trait::async_trait;
use pumpkin_data::block_properties::HorizontalFacing;
use pumpkin_data::tag::Tagable;
use pumpkin_data::{
Block,
block_properties::{BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15},
};
use pumpkin_macros::pumpkin_block;
use pumpkin_protocol::server::play::SUseItemOn;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::BlockStateId;
use pumpkin_world::block::BlockDirection;
use pumpkin_world::chunk::TickPriority;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::server::Server;
use crate::world::BlockFlags;
use crate::world::World;
use pumpkin_util::math::position::BlockPos;
#[pumpkin_block("minecraft:sugar_cane")]
pub struct SugarCaneBlock;
@@ -22,7 +26,7 @@ pub struct SugarCaneBlock;
#[async_trait]
impl PumpkinBlock for SugarCaneBlock {
async fn on_scheduled_tick(&self, world: &Arc<World>, _block: &Block, pos: &BlockPos) {
if !self.can_place_at(world, pos, BlockDirection::Down).await {
if !can_place_at(world, pos).await {
world.break_block(pos, None, BlockFlags::empty()).await;
}
}
@@ -66,7 +70,7 @@ impl PumpkinBlock for SugarCaneBlock {
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if !self.can_place_at(world, pos, BlockDirection::Down).await {
if !can_place_at(world, pos).await {
world
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
.await;
@@ -74,27 +78,41 @@ impl PumpkinBlock for SugarCaneBlock {
state
}
async fn can_place_at(&self, world: &World, pos: &BlockPos, _face: BlockDirection) -> bool {
let block = world.get_block(&pos.down()).await.unwrap();
if block == Block::SUGAR_CANE {
return true;
}
if block.is_tagged_with("minecraft:dirt").unwrap()
|| block.is_tagged_with("minecraft:sand").unwrap()
{
for direction in BlockDirection::horizontal() {
let block = world
.get_block(&pos.down().offset(direction.to_offset()))
.await
.unwrap();
if block == Block::WATER || block == Block::FROSTED_ICE {
return true;
}
}
}
false
async fn can_place_at(
&self,
_server: &Server,
world: &World,
_player: &Player,
_block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
can_place_at(world, block_pos).await
}
}
async fn can_place_at(world: &World, block_pos: &BlockPos) -> bool {
let block_below = world.get_block(&block_pos.down()).await.unwrap();
if block_below == Block::SUGAR_CANE {
return true;
}
if block_below.is_tagged_with("minecraft:dirt").unwrap()
|| block_below.is_tagged_with("minecraft:sand").unwrap()
{
for direction in HorizontalFacing::all() {
let block = world
.get_block(&block_pos.down().offset(direction.to_offset()))
.await
.unwrap();
if block == Block::WATER || block == Block::FROSTED_ICE {
return true;
}
}
}
false
}

View File

@@ -33,12 +33,12 @@ impl PumpkinBlock for TorchBlock {
&self,
_server: &Server,
_world: &World,
block: &Block,
face: BlockDirection,
_block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
_block_pos: &BlockPos,
face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
if face.is_horizontal() {
let wall_block = match block.name {

View File

@@ -41,12 +41,12 @@ impl PumpkinBlock for WallBlock {
&self,
_server: &Server,
world: &World,
block: &Block,
_face: BlockDirection,
block_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
block_pos: &BlockPos,
_face: BlockDirection,
replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> u16 {
let mut wall_props = WallProperties::default(block);
wall_props.waterlogged = replacing.water_source();

View File

@@ -1,3 +1,4 @@
use blocks::bed::BedBlock;
use blocks::cactus::CactusBlock;
use blocks::dirt_path::DirtPathBlock;
use blocks::doors::DoorBlock;
@@ -64,6 +65,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
let mut manager = BlockRegistry::default();
// Blocks
manager.register(BedBlock);
manager.register(CactusBlock);
manager.register(ChestBlock);
manager.register(CraftingTableBlock);

View File

@@ -61,23 +61,28 @@ pub trait PumpkinBlock: Send + Sync {
&self,
_server: &Server,
_world: &World,
block: &Block,
_face: BlockDirection,
_pos: &BlockPos,
_use_item_on: &SUseItemOn,
_player: &Player,
block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_replacing: BlockIsReplacing,
_use_item_on: &SUseItemOn,
) -> BlockStateId {
block.default_state_id
}
async fn random_tick(&self, _block: &Block, _world: &Arc<World>, _pos: &BlockPos) {}
#[allow(clippy::too_many_arguments)]
async fn can_place_at(
&self,
_server: &Server,
_world: &World,
_player: &Player,
_block: &Block,
_block_pos: &BlockPos,
_face: BlockDirection,
_use_item_on: &SUseItemOn,
) -> bool {
true
}
@@ -120,7 +125,7 @@ pub trait PumpkinBlock: Send + Sync {
async fn broken(
&self,
_block: &Block,
_player: &Player,
_player: &Arc<Player>,
_location: BlockPos,
_server: &Server,
_world: Arc<World>,

View File

@@ -97,17 +97,55 @@ impl BlockRegistry {
BlockActionResult::Continue
}
#[allow(clippy::too_many_arguments)]
pub async fn can_place_at(
&self,
server: &Server,
world: &World,
player: &Player,
block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
use_item_on: &SUseItemOn,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.can_place_at(server, world, player, block, block_pos, face, use_item_on)
.await;
}
true
}
pub async fn can_update_at(
&self,
world: &World,
block: &Block,
state_id: BlockStateId,
block_pos: &BlockPos,
face: BlockDirection,
use_item_on: &SUseItemOn,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.can_update_at(world, block, state_id, block_pos, face, use_item_on)
.await;
}
false
}
#[allow(clippy::too_many_arguments)]
pub async fn on_place(
&self,
server: &Server,
world: &World,
block: &Block,
face: BlockDirection,
block_pos: &BlockPos,
use_item_on: &SUseItemOn,
player: &Player,
block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
replacing: BlockIsReplacing,
use_item_on: &SUseItemOn,
) -> BlockStateId {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
@@ -115,12 +153,12 @@ impl BlockRegistry {
.on_place(
server,
world,
block,
face,
block_pos,
use_item_on,
player,
block,
block_pos,
face,
replacing,
use_item_on,
)
.await;
}
@@ -144,38 +182,6 @@ impl BlockRegistry {
}
}
pub async fn can_place_at(
&self,
world: &World,
block: &Block,
block_pos: &BlockPos,
face: BlockDirection,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block.can_place_at(world, block_pos, face).await;
}
true
}
pub async fn can_update_at(
&self,
world: &World,
block: &Block,
state_id: BlockStateId,
block_pos: &BlockPos,
face: BlockDirection,
use_item_on: &SUseItemOn,
) -> bool {
let pumpkin_block = self.get_pumpkin_block(block);
if let Some(pumpkin_block) = pumpkin_block {
return pumpkin_block
.can_update_at(world, block, state_id, block_pos, face, use_item_on)
.await;
}
false
}
pub async fn on_placed(
&self,
world: &Arc<World>,
@@ -214,7 +220,7 @@ impl BlockRegistry {
&self,
world: Arc<World>,
block: &Block,
player: &Player,
player: &Arc<Player>,
location: BlockPos,
server: &Server,
state: BlockState,

View File

@@ -1,14 +1,14 @@
use crate::block::blocks::fire::FireBlockBase;
use crate::block::pumpkin_block::PumpkinBlock;
use crate::entity::player::Player;
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
use crate::server::Server;
use crate::world::BlockFlags;
use async_trait::async_trait;
use pumpkin_data::Block;
use pumpkin_data::item::Item;
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::block::{BlockDirection, HorizontalFacingExt};
use pumpkin_world::block::BlockDirection;
use crate::block::blocks::fire::FireBlockBase;
use crate::entity::player::Player;
use crate::item::pumpkin_item::{ItemMetadata, PumpkinItem};
use crate::server::Server;
use crate::world::BlockFlags;
pub struct FlintAndSteelItem;
@@ -32,21 +32,11 @@ impl PumpkinItem for FlintAndSteelItem {
// TODO: check CampfireBlock, CandleBlock and CandleCakeBlock
let world = player.world().await;
let pos = location.offset(face.to_offset());
if FireBlockBase::can_place_at(
&FireBlockBase,
&world,
&pos,
player
.living_entity
.entity
.get_horizontal_facing()
.to_block_direction(),
)
.await
{
let state = FireBlockBase::get_state(&world, &pos).await;
if FireBlockBase::can_place_at(&world, &pos).await {
let fire_block = FireBlockBase::get_fire_type(&world, &pos).await;
world
.set_block_state(&pos, state.default_state_id, BlockFlags::NOTIFY_ALL)
.set_block_state(&pos, fire_block.default_state_id, BlockFlags::NOTIFY_ALL)
.await;
// TODO
}

View File

@@ -1766,7 +1766,15 @@ impl Player {
if !server
.block_registry
.can_place_at(world, &block, &final_block_pos, face)
.can_place_at(
server,
world,
self,
&block,
&final_block_pos,
final_face,
&use_item_on,
)
.await
{
return Ok(false);
@@ -1777,12 +1785,12 @@ impl Player {
.on_place(
server,
world,
&block,
final_face,
&final_block_pos,
&use_item_on,
self,
&block,
&final_block_pos,
final_face,
replacing,
&use_item_on,
)
.await;