diff --git a/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java b/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java index 49594df1c..4d266aa51 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java @@ -4,6 +4,7 @@ import net.minestom.server.MinecraftServer; import net.minestom.server.entity.Player; import net.minestom.server.event.CancellableEvent; import net.minestom.server.event.PlayerEvent; +import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; @@ -25,11 +26,10 @@ public class PlayerBlockPlaceEvent extends PlayerEvent implements CancellableEve private boolean cancelled; - public PlayerBlockPlaceEvent(@NotNull Player player, short blockStateId, short customBlockId, + public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block, @NotNull BlockPosition blockPosition, @NotNull Player.Hand hand) { super(player); - this.blockStateId = blockStateId; - this.customBlockId = customBlockId; + this.blockStateId = block.getBlockId(); this.blockPosition = blockPosition; this.hand = hand; this.consumeBlock = true; diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 53ebb0f02..652f79d9f 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -300,7 +300,7 @@ public class InstanceContainer extends Instance { private short executeBlockPlacementRule(short blockStateId, @NotNull BlockPosition blockPosition) { final BlockPlacementRule blockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(blockStateId); if (blockPlacementRule != null) { - return blockPlacementRule.blockRefresh(this, blockPosition, blockStateId); + return blockPlacementRule.blockUpdate(this, blockPosition, blockStateId); } return blockStateId; } @@ -331,7 +331,7 @@ public class InstanceContainer extends Instance { final BlockPlacementRule neighborBlockPlacementRule = BLOCK_MANAGER.getBlockPlacementRule(neighborStateId); if (neighborBlockPlacementRule != null) { final BlockPosition neighborPosition = new BlockPosition(neighborX, neighborY, neighborZ); - final short newNeighborId = neighborBlockPlacementRule.blockRefresh(this, + final short newNeighborId = neighborBlockPlacementRule.blockUpdate(this, neighborPosition, neighborStateId); if (neighborStateId != newNeighborId) { refreshBlockStateId(neighborPosition, newNeighborId); diff --git a/src/main/java/net/minestom/server/instance/block/rule/BlockPlacementRule.java b/src/main/java/net/minestom/server/instance/block/rule/BlockPlacementRule.java index 39e0d95b4..59677350d 100644 --- a/src/main/java/net/minestom/server/instance/block/rule/BlockPlacementRule.java +++ b/src/main/java/net/minestom/server/instance/block/rule/BlockPlacementRule.java @@ -9,6 +9,8 @@ import org.jetbrains.annotations.NotNull; public abstract class BlockPlacementRule { + public static final int CANCEL_CODE = -1; + private final short blockId; public BlockPlacementRule(short blockId) { @@ -19,16 +21,6 @@ public abstract class BlockPlacementRule { this(block.getBlockId()); } - /** - * Gets if the block can be placed in {@code blockPosition}. - * Can for example, be used for blocks which have to be placed on a solid block. - * - * @param instance the instance of the block - * @param blockPosition the position where the block is trying to get place - * @return true if the block placement position is valid - */ - public abstract boolean canPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition); - /** * Called when the block state id can be updated (for instance if a neighbour block changed). * @@ -37,19 +29,21 @@ public abstract class BlockPlacementRule { * @param currentStateID the current block state id of the block * @return the updated block state id */ - public abstract short blockRefresh(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentStateID); + public abstract short blockUpdate(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentStateID); /** * Called when the block is placed. * - * @param instance the instance of the block - * @param block the block placed - * @param blockFace the block face - * @param pl the player who placed the block - * @return the block state id of the placed block + * @param instance the instance of the block + * @param block the block placed + * @param blockFace the block face + * @param blockPosition the block position + * @param pl the player who placed the block + * @return the block state id of the placed block, + * {@link #CANCEL_CODE} to prevent the placement */ public abstract short blockPlace(@NotNull Instance instance, - @NotNull Block block, @NotNull BlockFace blockFace, + @NotNull Block block, @NotNull BlockFace blockFace, @NotNull BlockPosition blockPosition, @NotNull Player pl); public short getBlockId() { diff --git a/src/main/java/net/minestom/server/instance/block/rule/vanilla/AxisPlacementRule.java b/src/main/java/net/minestom/server/instance/block/rule/vanilla/AxisPlacementRule.java index cacb38910..e8e20dc28 100644 --- a/src/main/java/net/minestom/server/instance/block/rule/vanilla/AxisPlacementRule.java +++ b/src/main/java/net/minestom/server/instance/block/rule/vanilla/AxisPlacementRule.java @@ -18,17 +18,14 @@ public class AxisPlacementRule extends BlockPlacementRule { } @Override - public boolean canPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { - return true; - } - - @Override - public short blockRefresh(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { + public short blockUpdate(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { return currentId; } @Override - public short blockPlace(@NotNull Instance instance, @NotNull Block block, @NotNull BlockFace blockFace, @NotNull Player pl) { + public short blockPlace(@NotNull Instance instance, + @NotNull Block block, @NotNull BlockFace blockFace, @NotNull BlockPosition blockPosition, + @NotNull Player pl) { String axis = "y"; if (blockFace == BlockFace.WEST || blockFace == BlockFace.EAST) { axis = "x"; diff --git a/src/main/java/net/minestom/server/instance/block/rule/vanilla/RedstonePlacementRule.java b/src/main/java/net/minestom/server/instance/block/rule/vanilla/RedstonePlacementRule.java index 697b01f75..458b6d64b 100644 --- a/src/main/java/net/minestom/server/instance/block/rule/vanilla/RedstonePlacementRule.java +++ b/src/main/java/net/minestom/server/instance/block/rule/vanilla/RedstonePlacementRule.java @@ -16,13 +16,7 @@ public class RedstonePlacementRule extends BlockPlacementRule { } @Override - public boolean canPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { - BlockUtils block = new BlockUtils(instance, blockPosition); - return block.below().getBlock().isSolid(); - } - - @Override - public short blockRefresh(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { + public short blockUpdate(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { BlockUtils block = new BlockUtils(instance, blockPosition); String east = "none"; @@ -104,7 +98,14 @@ public class RedstonePlacementRule extends BlockPlacementRule { } @Override - public short blockPlace(@NotNull Instance instance, @NotNull Block block, @NotNull BlockFace blockFace, @NotNull Player pl) { + public short blockPlace(@NotNull Instance instance, + @NotNull Block block, @NotNull BlockFace blockFace, @NotNull BlockPosition blockPosition, + @NotNull Player pl) { + final short belowBlockId = instance.getBlockStateId(blockPosition.getX(), blockPosition.getY() - 1, blockPosition.getZ()); + if (!Block.fromStateId(belowBlockId).isSolid()) { + return CANCEL_CODE; + } + return getBlockId(); } diff --git a/src/main/java/net/minestom/server/instance/block/rule/vanilla/WallPlacementRule.java b/src/main/java/net/minestom/server/instance/block/rule/vanilla/WallPlacementRule.java index 0d9ba924e..b9824df5a 100644 --- a/src/main/java/net/minestom/server/instance/block/rule/vanilla/WallPlacementRule.java +++ b/src/main/java/net/minestom/server/instance/block/rule/vanilla/WallPlacementRule.java @@ -18,15 +18,10 @@ public class WallPlacementRule extends BlockPlacementRule { } @Override - public boolean canPlace(@NotNull Instance instance, @NotNull BlockPosition blockPosition) { - return true; - } - - @Override - public short blockRefresh(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { - int x = blockPosition.getX(); - int y = blockPosition.getY(); - int z = blockPosition.getZ(); + public short blockUpdate(@NotNull Instance instance, @NotNull BlockPosition blockPosition, short currentId) { + final int x = blockPosition.getX(); + final int y = blockPosition.getY(); + final int z = blockPosition.getZ(); String east = "none"; String north = "none"; @@ -57,7 +52,9 @@ public class WallPlacementRule extends BlockPlacementRule { } @Override - public short blockPlace(@NotNull Instance instance, @NotNull Block block, @NotNull BlockFace blockFace, @NotNull Player pl) { + public short blockPlace(@NotNull Instance instance, + @NotNull Block block, @NotNull BlockFace blockFace, @NotNull BlockPosition blockPosition, + @NotNull Player pl) { return getBlockId(); } diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index d4e5716a2..46888a85e 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -82,6 +82,8 @@ public class BlockPlacementListener { final Chunk chunk = instance.getChunkAt(blockPosition); + + // The concerned chunk will be send to the player if an error occur // This will ensure that the player has the correct version of the chunk boolean refreshChunk = false; @@ -101,33 +103,43 @@ public class BlockPlacementListener { } if (!intersect) { - // BlockPlacementRule check - final BlockManager blockManager = MinecraftServer.getBlockManager(); - final BlockPlacementRule blockPlacementRule = blockManager.getBlockPlacementRule(block); - final short blockStateId = blockPlacementRule == null ? block.getBlockId() : - blockPlacementRule.blockPlace(instance, block, blockFace, player); - PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, blockStateId, (short) 0, blockPosition, packet.hand); + // BlockPlaceEvent check + PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, block, blockPosition, packet.hand); playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE); - // BlockPlacementRule check - final boolean canPlace = blockPlacementRule == null || blockPlacementRule.canPlace(instance, blockPosition); - player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent); - if (!playerBlockPlaceEvent.isCancelled() && canPlace) { - final short customBlockId = playerBlockPlaceEvent.getCustomBlockId(); - if (customBlockId != 0) { - instance.setSeparateBlocks(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), playerBlockPlaceEvent.getBlockStateId(), playerBlockPlaceEvent.getCustomBlockId()); - } else { - instance.setBlockStateId(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), playerBlockPlaceEvent.getBlockStateId()); - } - if (playerBlockPlaceEvent.doesConsumeBlock()) { - // Consume the block in the player's hand - final ItemStack newUsedItem = usedItem.consume(1); + if (!playerBlockPlaceEvent.isCancelled()) { - if (newUsedItem != null) { - playerInventory.setItemInHand(hand, newUsedItem); + // BlockPlacementRule check + final Block resultBlock = Block.fromStateId(playerBlockPlaceEvent.getBlockStateId()); + final BlockManager blockManager = MinecraftServer.getBlockManager(); + final BlockPlacementRule blockPlacementRule = blockManager.getBlockPlacementRule(resultBlock); + final short blockStateId = blockPlacementRule == null ? resultBlock.getBlockId() : + blockPlacementRule.blockPlace(instance, resultBlock, blockFace, blockPosition, player); + final boolean placementRuleCheck = blockStateId != BlockPlacementRule.CANCEL_CODE; + + if (placementRuleCheck) { + + // Place the block + final short customBlockId = playerBlockPlaceEvent.getCustomBlockId(); + if (customBlockId != 0) { + instance.setSeparateBlocks(blockPosition, playerBlockPlaceEvent.getBlockStateId(), customBlockId); + } else { + instance.setBlockStateId(blockPosition, playerBlockPlaceEvent.getBlockStateId()); } + + // Block consuming + if (playerBlockPlaceEvent.doesConsumeBlock()) { + // Consume the block in the player's hand + final ItemStack newUsedItem = usedItem.consume(1); + + if (newUsedItem != null) { + playerInventory.setItemInHand(hand, newUsedItem); + } + } + } else { + refreshChunk = true; } } else { refreshChunk = true;