Block event changes (#1675)

* Add cursor position to interact events

* Add block face to digging events

* Expose interact position in interact event
This commit is contained in:
emortaldev 2023-01-16 23:57:18 +00:00 committed by GitHub
parent 8eb089bf3e
commit c995f9c3a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 87 additions and 29 deletions

View File

@ -6,6 +6,7 @@ import net.minestom.server.event.trait.BlockEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerInstanceEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import org.jetbrains.annotations.NotNull;
public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, CancellableEvent {
@ -14,16 +15,19 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C
private final Block block;
private Block resultBlock;
private final Point blockPosition;
private final BlockFace blockFace;
private boolean cancelled;
public PlayerBlockBreakEvent(@NotNull Player player,
@NotNull Block block, @NotNull Block resultBlock, @NotNull Point blockPosition) {
@NotNull Block block, @NotNull Block resultBlock, @NotNull Point blockPosition,
@NotNull BlockFace blockFace) {
this.player = player;
this.block = block;
this.resultBlock = resultBlock;
this.blockPosition = blockPosition;
this.blockFace = blockFace;
}
/**
@ -45,6 +49,15 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C
return resultBlock;
}
/**
* Gets the face at which the block was broken
*
* @return the block face
*/
public @NotNull BlockFace getBlockFace() {
return blockFace;
}
/**
* Changes the result of the event.
*

View File

@ -30,7 +30,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent
private boolean cancelled;
public PlayerBlockInteractEvent(@NotNull Player player, @NotNull Player.Hand hand,
@NotNull Block block, @NotNull Point blockPosition,
@NotNull Block block, @NotNull Point blockPosition, @NotNull Point cursorPosition,
@NotNull BlockFace blockFace) {
this.player = player;
this.hand = hand;

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player;
import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.PlayerInstanceEvent;
@ -13,11 +14,19 @@ public class PlayerEntityInteractEvent implements PlayerInstanceEvent {
private final Player player;
private final Entity entityTarget;
private final Player.Hand hand;
private final Point interactPosition;
public PlayerEntityInteractEvent(@NotNull Player player, @NotNull Entity entityTarget, @NotNull Player.Hand hand) {
public PlayerEntityInteractEvent(@NotNull Player player, @NotNull Entity entityTarget, @NotNull Player.Hand hand,
@NotNull Point interactPosition) {
this.player = player;
this.entityTarget = entityTarget;
this.hand = hand;
this.interactPosition = interactPosition;
}
@Override
public @NotNull Player getPlayer() {
return player;
}
/**
@ -40,8 +49,14 @@ public class PlayerEntityInteractEvent implements PlayerInstanceEvent {
return hand;
}
@Override
public @NotNull Player getPlayer() {
return player;
/**
* Gets the position at which the entity was interacted
*
* @see net.minestom.server.network.packet.client.play.ClientInteractEntityPacket.InteractAt
* @return the interaction position
*/
@NotNull
public Point getInteractPosition() {
return interactPosition;
}
}

View File

@ -6,6 +6,7 @@ import net.minestom.server.event.trait.BlockEvent;
import net.minestom.server.event.trait.CancellableEvent;
import net.minestom.server.event.trait.PlayerInstanceEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import org.jetbrains.annotations.NotNull;
/**
@ -21,13 +22,16 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent,
private final Player player;
private final Block block;
private final Point blockPosition;
private final BlockFace blockFace;
private boolean cancelled;
public PlayerStartDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull Point blockPosition) {
public PlayerStartDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull Point blockPosition,
@NotNull BlockFace blockFace) {
this.player = player;
this.block = block;
this.blockPosition = blockPosition;
this.blockFace = blockFace;
}
/**
@ -49,6 +53,15 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent,
return blockPosition;
}
/**
* Gets the face you are digging
*
* @return the block face
*/
public @NotNull BlockFace getBlockFace() {
return blockFace;
}
@Override
public boolean isCancelled() {
return cancelled;

View File

@ -21,7 +21,8 @@ public class PlayerUseItemOnBlockEvent implements PlayerInstanceEvent, ItemEvent
public PlayerUseItemOnBlockEvent(@NotNull Player player, @NotNull Player.Hand hand,
@NotNull ItemStack itemStack,
@NotNull Point position, @NotNull BlockFace blockFace) {
@NotNull Point position, @NotNull Point cursorPosition,
@NotNull BlockFace blockFace) {
this.player = player;
this.hand = hand;
this.itemStack = itemStack;

View File

@ -20,6 +20,7 @@ import net.minestom.server.event.EventNode;
import net.minestom.server.event.instance.InstanceTickEvent;
import net.minestom.server.event.trait.InstanceEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.generator.Generator;
import net.minestom.server.network.packet.server.play.BlockActionPacket;
@ -150,7 +151,7 @@ public abstract class Instance implements Block.Getter, Block.Setter,
* @return true if the block has been broken, false if it has been cancelled
*/
@ApiStatus.Internal
public abstract boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition);
public abstract boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace);
/**
* Forces the generation of a {@link Chunk}, even if no file and {@link ChunkGenerator} are defined.

View File

@ -11,6 +11,7 @@ import net.minestom.server.event.instance.InstanceChunkLoadEvent;
import net.minestom.server.event.instance.InstanceChunkUnloadEvent;
import net.minestom.server.event.player.PlayerBlockBreakEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.block.rule.BlockPlacementRule;
import net.minestom.server.instance.generator.Generator;
@ -175,7 +176,7 @@ public class InstanceContainer extends Instance {
}
@Override
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition) {
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace) {
final Chunk chunk = getChunkAt(blockPosition);
Check.notNull(chunk, "You cannot break blocks in a null chunk!");
if (chunk.isReadOnly()) return false;
@ -190,7 +191,7 @@ public class InstanceContainer extends Instance {
chunk.sendChunk(player);
return false;
}
PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(player, block, Block.AIR, blockPosition);
PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(player, block, Block.AIR, blockPosition, blockFace);
EventDispatcher.call(blockBreakEvent);
final boolean allowed = !blockBreakEvent.isCancelled();
if (allowed) {

View File

@ -3,6 +3,7 @@ package net.minestom.server.instance;
import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.instance.generator.Generator;
import org.jetbrains.annotations.NotNull;
@ -35,8 +36,8 @@ public class SharedInstance extends Instance {
}
@Override
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition) {
return instanceContainer.breakBlock(player, blockPosition);
public boolean breakBlock(@NotNull Player player, @NotNull Point blockPosition, @NotNull BlockFace blockFace) {
return instanceContainer.breakBlock(player, blockPosition, blockFace);
}
@Override

View File

@ -194,14 +194,16 @@ public interface BlockHandler {
private final Block block;
private final Instance instance;
private final Point blockPosition;
private final Point cursorPosition;
private final Player player;
private final Player.Hand hand;
@ApiStatus.Internal
public Interaction(Block block, Instance instance, Point blockPosition, Player player, Player.Hand hand) {
public Interaction(Block block, Instance instance, Point blockPosition, Point cursorPosition, Player player, Player.Hand hand) {
this.block = block;
this.instance = instance;
this.blockPosition = blockPosition;
this.cursorPosition = cursorPosition;
this.player = player;
this.hand = hand;
}
@ -218,6 +220,10 @@ public interface BlockHandler {
return blockPosition;
}
public @NotNull Point getCursorPosition() {
return cursorPosition;
}
public @NotNull Player getPlayer() {
return player;
}

View File

@ -3,6 +3,7 @@ package net.minestom.server.listener;
import net.minestom.server.MinecraftServer;
import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
@ -49,15 +50,17 @@ public class BlockPlacementListener {
final ItemStack usedItem = player.getItemInHand(hand);
final Block interactedBlock = instance.getBlock(blockPosition);
final Point cursorPosition = new Vec(packet.cursorPositionX(), packet.cursorPositionY(), packet.cursorPositionZ());
// Interact at block
// FIXME: onUseOnBlock
PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, hand, interactedBlock, blockPosition, blockFace);
PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, hand, interactedBlock, blockPosition, cursorPosition, blockFace);
EventDispatcher.call(playerBlockInteractEvent);
boolean blockUse = playerBlockInteractEvent.isBlockingItemUse();
if (!playerBlockInteractEvent.isCancelled()) {
final var handler = interactedBlock.handler();
if (handler != null) {
blockUse |= !handler.onInteract(new BlockHandler.Interaction(interactedBlock, instance, blockPosition, player, hand));
blockUse |= !handler.onInteract(new BlockHandler.Interaction(interactedBlock, instance, blockPosition, cursorPosition, player, hand));
}
}
if (blockUse) {
@ -68,7 +71,7 @@ public class BlockPlacementListener {
final Material useMaterial = usedItem.material();
if (!useMaterial.isBlock()) {
// Player didn't try to place a block but interacted with one
PlayerUseItemOnBlockEvent event = new PlayerUseItemOnBlockEvent(player, hand, usedItem, blockPosition, blockFace);
PlayerUseItemOnBlockEvent event = new PlayerUseItemOnBlockEvent(player, hand, usedItem, blockPosition, cursorPosition, blockFace);
EventDispatcher.call(event);
return;
}

View File

@ -11,6 +11,7 @@ import net.minestom.server.event.player.PlayerStartDiggingEvent;
import net.minestom.server.event.player.PlayerSwapItemEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.block.BlockFace;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.StackingRule;
@ -29,13 +30,13 @@ public final class PlayerDiggingListener {
DiggingResult diggingResult = null;
if (status == ClientPlayerDiggingPacket.Status.STARTED_DIGGING) {
if (!instance.isChunkLoaded(blockPosition)) return;
diggingResult = startDigging(player, instance, blockPosition);
diggingResult = startDigging(player, instance, blockPosition, packet.blockFace());
} else if (status == ClientPlayerDiggingPacket.Status.CANCELLED_DIGGING) {
if (!instance.isChunkLoaded(blockPosition)) return;
diggingResult = cancelDigging(instance, blockPosition);
} else if (status == ClientPlayerDiggingPacket.Status.FINISHED_DIGGING) {
if (!instance.isChunkLoaded(blockPosition)) return;
diggingResult = finishDigging(player, instance, blockPosition);
diggingResult = finishDigging(player, instance, blockPosition, packet.blockFace());
} else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM_STACK) {
dropStack(player);
} else if (status == ClientPlayerDiggingPacket.Status.DROP_ITEM) {
@ -51,7 +52,7 @@ public final class PlayerDiggingListener {
}
}
private static DiggingResult startDigging(Player player, Instance instance, Point blockPosition) {
private static DiggingResult startDigging(Player player, Instance instance, Point blockPosition, BlockFace blockFace) {
final Block block = instance.getBlock(blockPosition);
final GameMode gameMode = player.getGameMode();
@ -61,19 +62,19 @@ public final class PlayerDiggingListener {
}
if (gameMode == GameMode.CREATIVE) {
return breakBlock(instance, player, blockPosition, block);
return breakBlock(instance, player, blockPosition, block, blockFace);
}
// Survival digging
// FIXME: verify mineable tag and enchantment
final boolean instantBreak = player.isInstantBreak() || block.registry().hardness() == 0;
if (!instantBreak) {
PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, blockPosition);
PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, blockPosition, blockFace);
EventDispatcher.call(playerStartDiggingEvent);
return new DiggingResult(block, !playerStartDiggingEvent.isCancelled());
}
// Client only send a single STARTED_DIGGING when insta-break is enabled
return breakBlock(instance, player, blockPosition, block);
return breakBlock(instance, player, blockPosition, block, blockFace);
}
private static DiggingResult cancelDigging(Instance instance, Point blockPosition) {
@ -81,14 +82,14 @@ public final class PlayerDiggingListener {
return new DiggingResult(block, true);
}
private static DiggingResult finishDigging(Player player, Instance instance, Point blockPosition) {
private static DiggingResult finishDigging(Player player, Instance instance, Point blockPosition, BlockFace blockFace) {
final Block block = instance.getBlock(blockPosition);
if (shouldPreventBreaking(player, block)) {
return new DiggingResult(block, false);
}
return breakBlock(instance, player, blockPosition, block);
return breakBlock(instance, player, blockPosition, block, blockFace);
}
private static boolean shouldPreventBreaking(@NotNull Player player, Block block) {
@ -155,9 +156,9 @@ public final class PlayerDiggingListener {
private static DiggingResult breakBlock(Instance instance,
Player player,
Point blockPosition, Block previousBlock) {
Point blockPosition, Block previousBlock, BlockFace blockFace) {
// Unverified block break, client is fully responsible
final boolean success = instance.breakBlock(player, blockPosition);
final boolean success = instance.breakBlock(player, blockPosition, blockFace);
final Block updatedBlock = instance.getBlock(blockPosition);
if (!success) {
if (previousBlock.isSolid()) {

View File

@ -1,5 +1,7 @@
package net.minestom.server.listener;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.LivingEntity;
import net.minestom.server.entity.Player;
@ -12,7 +14,7 @@ public class UseEntityListener {
public static void useEntityListener(ClientInteractEntityPacket packet, Player player) {
final Entity entity = Entity.getEntity(packet.targetId());
if (entity == null || !entity.isViewer(player) || player.getDistance(entity) > 6)
if (entity == null || !entity.isViewer(player) || player.getDistanceSquared(entity) > 6 * 6)
return;
ClientInteractEntityPacket.Type type = packet.type();
@ -21,7 +23,8 @@ public class UseEntityListener {
return;
EventDispatcher.call(new EntityAttackEvent(player, entity));
} else if (type instanceof ClientInteractEntityPacket.InteractAt interactAt) {
EventDispatcher.call(new PlayerEntityInteractEvent(player, entity, interactAt.hand()));
Point interactPosition = new Vec(interactAt.targetX(), interactAt.targetY(), interactAt.targetZ());
EventDispatcher.call(new PlayerEntityInteractEvent(player, entity, interactAt.hand(), interactPosition));
}
}
}