Minestom/src/main/java/net/minestom/server/listener/BlockPlacementListener.java

146 lines
6.7 KiB
Java
Raw Normal View History

2020-04-24 03:25:58 +02:00
package net.minestom.server.listener;
2020-04-24 03:25:58 +02:00
import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerBlockInteractEvent;
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
2020-04-24 03:25:58 +02:00
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
2020-04-24 03:25:58 +02:00
import net.minestom.server.instance.block.BlockManager;
import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.client.play.ClientPlayerBlockPlacementPacket;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Direction;
import net.minestom.server.utils.chunk.ChunkUtils;
2020-04-21 15:31:41 +02:00
import java.util.Set;
public class BlockPlacementListener {
public static void listener(ClientPlayerBlockPlacementPacket packet, Player player) {
2020-07-23 05:36:15 +02:00
final PlayerInventory playerInventory = player.getInventory();
final Player.Hand hand = packet.hand;
final BlockFace blockFace = packet.blockFace;
final BlockPosition blockPosition = packet.blockPosition;
final Direction direction = blockFace.toDirection();
2020-07-23 05:36:15 +02:00
final Instance instance = player.getInstance();
if (instance == null)
return;
final ItemStack usedItem = player.getItemInHand(hand);
2020-04-21 15:31:41 +02:00
// Interact at block
final boolean cancel = usedItem.onUseOnBlock(player, hand, blockPosition, direction);
2020-07-24 16:11:48 +02:00
PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, blockPosition, hand, blockFace);
playerBlockInteractEvent.setCancelled(cancel);
playerBlockInteractEvent.setBlockingItemUse(cancel);
2020-03-30 19:48:25 +02:00
player.callCancellableEvent(PlayerBlockInteractEvent.class, playerBlockInteractEvent, () -> {
2020-07-23 05:36:15 +02:00
final CustomBlock customBlock = instance.getCustomBlock(blockPosition);
2020-03-30 19:48:25 +02:00
if (customBlock != null) {
2020-07-23 05:36:15 +02:00
final Data data = instance.getBlockData(blockPosition);
final boolean blocksItem = customBlock.onInteract(player, hand, blockPosition, data);
if (blocksItem) {
playerBlockInteractEvent.setBlockingItemUse(true);
}
2020-03-30 19:48:25 +02:00
}
});
2020-07-21 18:48:15 +02:00
if (playerBlockInteractEvent.isBlockingItemUse()) {
return;
}
2020-04-21 15:31:41 +02:00
// Check if item at hand is a block
2020-07-23 05:36:15 +02:00
final Material material = usedItem.getMaterial();
2020-07-21 18:48:15 +02:00
if (material == Material.AIR) {
2019-08-29 02:15:52 +02:00
return;
2019-09-01 06:18:41 +02:00
}
2019-08-29 02:15:52 +02:00
2020-04-21 15:31:41 +02:00
// Get the newly placed block position
2020-07-21 18:48:15 +02:00
final int offsetX = blockFace == BlockFace.WEST ? -1 : blockFace == BlockFace.EAST ? 1 : 0;
final int offsetY = blockFace == BlockFace.BOTTOM ? -1 : blockFace == BlockFace.TOP ? 1 : 0;
final int offsetZ = blockFace == BlockFace.NORTH ? -1 : blockFace == BlockFace.SOUTH ? 1 : 0;
2019-08-22 14:52:32 +02:00
blockPosition.add(offsetX, offsetY, offsetZ);
2020-04-21 15:31:41 +02:00
2020-07-21 18:48:15 +02:00
final Chunk chunk = instance.getChunkAt(blockPosition);
2020-07-24 18:23:15 +02:00
// 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
2020-04-21 15:31:41 +02:00
boolean refreshChunk = false;
if (material.isBlock()) {
2020-07-21 18:48:15 +02:00
final Block block = material.getBlock();
final Set<Entity> entities = instance.getChunkEntities(chunk);
2020-07-24 18:23:15 +02:00
// Check if the player is trying to place a block in an entity
boolean intersect = false;
if (block.isSolid()) {
for (Entity entity : entities) {
intersect = entity.getBoundingBox().intersect(blockPosition);
if (intersect)
break;
}
2020-04-17 15:58:07 +02:00
}
if (!intersect) {
// BlockPlacementRule check
2020-07-21 18:48:15 +02:00
final BlockManager blockManager = MinecraftServer.getBlockManager();
final BlockPlacementRule blockPlacementRule = blockManager.getBlockPlacementRule(block);
2020-08-09 09:55:30 +02:00
final short blockStateId = blockPlacementRule == null ? block.getBlockId() :
2020-07-24 18:23:15 +02:00
blockPlacementRule.blockPlace(instance, block, blockFace, player);
2020-08-09 09:55:30 +02:00
PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, blockStateId, (short) 0, blockPosition, packet.hand);
playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
// BlockPlacementRule check
2020-07-24 18:23:15 +02:00
final boolean canPlace = blockPlacementRule == null || blockPlacementRule.canPlace(instance, blockPosition);
player.callEvent(PlayerBlockPlaceEvent.class, playerBlockPlaceEvent);
if (!playerBlockPlaceEvent.isCancelled() && canPlace) {
2020-07-24 18:23:15 +02:00
final short customBlockId = playerBlockPlaceEvent.getCustomBlockId();
2020-07-23 05:36:15 +02:00
if (customBlockId != 0) {
2020-08-09 09:55:30 +02:00
instance.setSeparateBlocks(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), playerBlockPlaceEvent.getBlockStateId(), playerBlockPlaceEvent.getCustomBlockId());
} else {
2020-08-09 09:55:30 +02:00
instance.setBlockStateId(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), playerBlockPlaceEvent.getBlockStateId());
}
if (playerBlockPlaceEvent.doesConsumeBlock()) {
2020-07-24 18:23:15 +02:00
// Consume the block in the player's hand
final ItemStack newUsedItem = usedItem.consume(1);
2020-02-17 17:33:53 +01:00
2020-07-24 18:23:15 +02:00
if (newUsedItem != null) {
playerInventory.setItemInHand(hand, newUsedItem);
}
2019-08-31 07:54:53 +02:00
}
} else {
refreshChunk = true;
2019-08-29 02:15:52 +02:00
}
2019-08-31 07:54:53 +02:00
} else {
2020-04-21 15:31:41 +02:00
refreshChunk = true;
2019-08-29 02:15:52 +02:00
}
2020-04-20 18:46:39 +02:00
} else {
2020-07-24 18:23:15 +02:00
// Player didn't try to place a block but interacted with one
PlayerUseItemOnBlockEvent event = new PlayerUseItemOnBlockEvent(player, hand, usedItem, blockPosition, direction);
player.callEvent(PlayerUseItemOnBlockEvent.class, event);
2020-04-21 15:31:41 +02:00
refreshChunk = true;
}
// Refresh chunk section if needed
if (refreshChunk) {
2020-04-20 18:46:39 +02:00
instance.sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player);
}
2020-04-21 15:31:41 +02:00
player.getInventory().refreshSlot(player.getHeldSlot());
}
}