diff --git a/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java b/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java index a149f1175..2f79a4f1c 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java @@ -1,17 +1,27 @@ package net.minestom.server.event.player; import net.minestom.server.event.CancellableEvent; +import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.utils.BlockPosition; public class PlayerBlockBreakEvent extends CancellableEvent { private BlockPosition blockPosition; + private short blockId; + private CustomBlock customBlock; + private short resultBlockId; private short resultCustomBlockId; - public PlayerBlockBreakEvent(BlockPosition blockPosition, short resultBlockId, short resultCustomBlockId) { + public PlayerBlockBreakEvent(BlockPosition blockPosition, + short blockId, CustomBlock customBlock, + short resultBlockId, short resultCustomBlockId) { this.blockPosition = blockPosition; + + this.blockId = blockId; + this.customBlock = customBlock; + this.resultBlockId = resultBlockId; this.resultCustomBlockId = resultCustomBlockId; } @@ -20,23 +30,51 @@ public class PlayerBlockBreakEvent extends CancellableEvent { return blockPosition; } + /** + * @return the block id of the block that has been broken + */ + public short getBlockId() { + return blockId; + } + + /** + * @return the custom block of the block that has been broken, + * null if not any + */ + public CustomBlock getCustomBlock() { + return customBlock; + } + + /** + * @return the block id that will be set at {@link #getBlockPosition()} + * set to 0 to remove + */ public short getResultBlockId() { return resultBlockId; } + /** + * @param resultBlockId the result block id + */ public void setResultBlockId(short resultBlockId) { this.resultBlockId = resultBlockId; } + /** + * @return the custom block id that will be set at {@link #getBlockPosition()} + * set to 0 to remove + *

+ * Warning: the visual block will not be changed, be sure to call {@link #setResultBlockId(short)} + * if you want the visual to be the same as {@link CustomBlock#getBlockId()} + */ public short getResultCustomBlockId() { return resultCustomBlockId; } + /** + * @param resultCustomBlockId the result custom block id + */ public void setResultCustomBlockId(short resultCustomBlockId) { this.resultCustomBlockId = resultCustomBlockId; } - - public boolean isResultCustomBlock() { - return resultCustomBlockId != 0; - } } diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 773d5f517..eb2a6c841 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -212,7 +212,7 @@ public class InstanceContainer extends Instance { int y = blockPosition.getY(); int z = blockPosition.getZ(); - short blockId = chunk.getBlockId(x, y, z); + short blockId = getBlockId(x, y, z); // The player probably have a wrong version of this chunk section, send it if (blockId == 0) { @@ -220,7 +220,9 @@ public class InstanceContainer extends Instance { return false; } - PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(blockPosition, (short) 0, (short) 0); + CustomBlock customBlock = getCustomBlock(x, y, z); + + PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(blockPosition, blockId, customBlock, (short) 0, (short) 0); player.callEvent(PlayerBlockBreakEvent.class, blockBreakEvent); boolean result = !blockBreakEvent.isCancelled(); if (result) { @@ -235,7 +237,13 @@ public class InstanceContainer extends Instance { writer.writeVarInt(blockId); }); - chunk.sendPacketToViewers(particlePacket); + chunk.getViewers().forEach(p -> { + // The player who breaks the block already get particles client-side + if (!(p.equals(player) && player.isCreative())) { + p.getPlayerConnection().sendPacket(particlePacket); + } + }); + } else { // Cancelled so we need to refresh player chunk section sendChunkSectionUpdate(chunk, ChunkUtils.getSectionAt(blockPosition.getY()), player); diff --git a/src/main/java/net/minestom/server/instance/block/BlockManager.java b/src/main/java/net/minestom/server/instance/block/BlockManager.java index b2bdf43a6..2fe7ea339 100644 --- a/src/main/java/net/minestom/server/instance/block/BlockManager.java +++ b/src/main/java/net/minestom/server/instance/block/BlockManager.java @@ -14,6 +14,9 @@ public class BlockManager { private Short2ObjectOpenHashMap placementRules = new Short2ObjectOpenHashMap<>(); + /** + * @param customBlock the custom block to register + */ public void registerCustomBlock(CustomBlock customBlock) { String identifier = customBlock.getIdentifier(); short id = customBlock.getCustomBlockId(); @@ -21,24 +24,43 @@ public class BlockManager { this.customBlocksId.put(identifier, customBlock); } + /** + * @param blockPlacementRule the block placement rule to register + */ public void registerBlockPlacementRule(BlockPlacementRule blockPlacementRule) { this.placementRules.put(blockPlacementRule.getBlockId(), blockPlacementRule); } + /** + * @param blockId the block id to check + * @return the block placement rule associated with the id, null if not any + */ public BlockPlacementRule getBlockPlacementRule(short blockId) { Block block = Block.fromId(blockId); // Convert block alternative blockId = block.getBlockId(); return this.placementRules.get(blockId); } + /** + * @param block the block to check + * @return the block placement rule associated with the block, null if not any + */ public BlockPlacementRule getBlockPlacementRule(Block block) { return getBlockPlacementRule(block.getBlockId()); } + /** + * @param identifier the custom block identifier + * @return the {@link CustomBlock} associated with the identifier, null if not any + */ public CustomBlock getCustomBlock(String identifier) { return customBlocksId.get(identifier); } + /** + * @param id the custom block id + * @return the {@link CustomBlock} associated with the id, null if not any + */ public CustomBlock getCustomBlock(short id) { return customBlocksInternalId.get(id); } diff --git a/src/main/java/net/minestom/server/instance/block/CustomBlock.java b/src/main/java/net/minestom/server/instance/block/CustomBlock.java index 2a8777458..002078fdf 100644 --- a/src/main/java/net/minestom/server/instance/block/CustomBlock.java +++ b/src/main/java/net/minestom/server/instance/block/CustomBlock.java @@ -19,6 +19,10 @@ public abstract class CustomBlock { private short blockId; private String identifier; + /** + * @param blockId the visual block id + * @param identifier the custom block identifier + */ public CustomBlock(short blockId, String identifier) { this.blockId = blockId; this.identifier = identifier; @@ -28,16 +32,48 @@ public abstract class CustomBlock { this(block.getBlockId(), identifier); } + /** + * Calling delay depends on {@link #getUpdateOption()} which should be overridden + * + * @param instance the instance of the block + * @param blockPosition the position of the block + * @param data the data associated with the block + * @throws UnsupportedOperationException if {@link #getUpdateOption()} + * is not null but the update method is not overridden + */ public void update(Instance instance, BlockPosition blockPosition, Data data) { throw new UnsupportedOperationException("Update method not overridden"); } + /** + * The update option is used to define the delay between two + * {@link #update(Instance, BlockPosition, Data)} execution. + *

+ * If this is not null, {@link #update(Instance, BlockPosition, Data)} + * should be overridden or errors with occurs + * + * @return the update option of the block + */ public UpdateOption getUpdateOption() { return null; } + /** + * Called when a custom block has been placed + * + * @param instance the instance of the block + * @param blockPosition the position of the block + * @param data the data associated with the block + */ public abstract void onPlace(Instance instance, BlockPosition blockPosition, Data data); + /** + * Called when a custom block has been destroyed or replaced + * + * @param instance the instance of the block + * @param blockPosition the position of the block + * @param data the data associated with the block + */ public abstract void onDestroy(Instance instance, BlockPosition blockPosition, Data data); /** @@ -70,6 +106,9 @@ public abstract class CustomBlock { */ public abstract int getBreakDelay(Player player, BlockPosition position); + /** + * @return true if {@link #getUpdateOption()} is not null, false otherwise + */ public boolean hasUpdate() { UpdateOption updateOption = getUpdateOption(); if (updateOption == null) @@ -89,10 +128,25 @@ public abstract class CustomBlock { public void handleContact(Instance instance, BlockPosition position, Entity touching) { } + /** + * This is the default visual for the block when the custom block is set, + * it is possible to change this value per block using + * {@link net.minestom.server.instance.BlockModifier#setSeparateBlocks(int, int, int, short, short)} + *

+ * Meaning that you should not believe that your custom blocks id will always be this one. + * + * @return the default visual block id + */ public short getBlockId() { return blockId; } + /** + * The custom block identifier, used to retrieve the custom block object with + * {@link BlockManager#getCustomBlock(String)} and to set custom block in the instance + * + * @return the custom block identifier + */ public String getIdentifier() { return identifier; } @@ -144,6 +198,7 @@ public abstract class CustomBlock { /** * Called when an explosion wants to destroy this block. + * * @param instance * @param lootTableArguments arguments used in the loot table loot generation * @return 'true' if the explosion should happen on this block, 'false' to cancel the destruction. @@ -155,6 +210,7 @@ public abstract class CustomBlock { /** * Return the loot table associated to this block. Return null to use vanilla behavior + * * @param tableManager * @return */