diff --git a/src/main/java/net/minestom/server/coordinate/BlockVec.java b/src/main/java/net/minestom/server/coordinate/BlockVec.java new file mode 100644 index 000000000..c168bacb6 --- /dev/null +++ b/src/main/java/net/minestom/server/coordinate/BlockVec.java @@ -0,0 +1,183 @@ +package net.minestom.server.coordinate; + +import net.minestom.server.instance.block.BlockFace; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.function.DoubleUnaryOperator; + +/** + * Represents an immutable block position. + * + * Usage note: If you accept a block position as an argument to a method, + * it's usually better to accept a Point rather than a BlockVec to avoid + * callers continually having to convert. + */ +public record BlockVec(double x, double y, double z) implements Point { + public BlockVec { + x = Math.floor(x); + y = Math.floor(y); + z = Math.floor(z); + } + + public BlockVec(int x, int y, int z) { + this((double) x, (double) y, (double) z); + } + + public BlockVec(@NotNull Point point) { + this(point.x(), point.y(), point.z()); + } + + @Override + public @NotNull Point withX(@NotNull DoubleUnaryOperator operator) { + return new Vec(operator.applyAsDouble(x), y, z); + } + + @Override + public @NotNull Point withX(double x) { + return new Vec(x, y, z); + } + + @Contract(pure = true) + public @NotNull BlockVec withBlockX(int x) { + return new BlockVec(x, y, z); + } + + @Override + public @NotNull Point withY(@NotNull DoubleUnaryOperator operator) { + return new Vec(x, operator.applyAsDouble(y), z); + } + + @Override + public @NotNull Point withY(double y) { + return new Vec(x, y, z); + } + + @Contract(pure = true) + public @NotNull BlockVec withBlockY(int y) { + return new BlockVec(x, y, z); + } + + @Override + public @NotNull Point withZ(@NotNull DoubleUnaryOperator operator) { + return new Vec(x, y, operator.applyAsDouble(z)); + } + + @Override + public @NotNull Point withZ(double z) { + return new Vec(x, y, z); + } + + @Contract(pure = true) + public @NotNull BlockVec withBlockZ(int z) { + return new BlockVec(x, y, z); + } + + @Override + public @NotNull Point add(double x, double y, double z) { + return new Vec(this.x + x, this.y + y, this.z + z); + } + + @Contract(pure = true) + public @NotNull BlockVec add(int x, int y, int z) { + return new BlockVec(this.x + x, this.y + y, this.z + z); + } + + @Override + public @NotNull Point add(@NotNull Point point) { + return new Vec(this.x + point.x(), this.y + point.y(), this.z + point.z()); + } + + @Contract(pure = true) + public @NotNull BlockVec add(@NotNull BlockVec blockVec) { + return new BlockVec(this.x + blockVec.x(), this.y + blockVec.y(), this.z + blockVec.z()); + } + + @Override + public @NotNull Point add(double value) { + return add(value, value, value); + } + + @Contract(pure = true) + public @NotNull BlockVec add(int value) { + return new BlockVec(x + value, y + value, z + value); + } + + @Override + public @NotNull Point sub(double x, double y, double z) { + return new Vec(this.x - x, this.y - y, this.z - z); + } + + @Contract(pure = true) + public @NotNull BlockVec sub(int x, int y, int z) { + return new BlockVec(this.x - x, this.y - y, this.z - z); + } + + @Override + public @NotNull Point sub(@NotNull Point point) { + return sub(point.x(), point.y(), point.z()); + } + + @Contract(pure = true) + public @NotNull BlockVec sub(@NotNull BlockVec blockVec) { + return new BlockVec(this.x - blockVec.x(), this.y - blockVec.y(), this.z - blockVec.z()); + } + + @Override + public @NotNull Point sub(double value) { + return sub(value, value, value); + } + + @Contract(pure = true) + public @NotNull BlockVec sub(int value) { + return new BlockVec(x - value, y - value, z - value); + } + + @Override + public @NotNull Point mul(double x, double y, double z) { + return new Vec(this.x * x, this.y * y, this.z * z); + } + + @Override + public @NotNull Point mul(@NotNull Point point) { + return mul(point.x(), point.y(), point.z()); + } + + @Override + public @NotNull Point mul(double value) { + return mul(value, value, value); + } + + @Override + public @NotNull Point div(double x, double y, double z) { + return div(this.x / x, this.y / y, this.z / z); + } + + @Override + public @NotNull Point div(@NotNull Point point) { + return div(point.x(), point.y(), point.z()); + } + + @Override + public @NotNull Point div(double value) { + return div(value, value, value); + } + + @Override + @Contract(pure = true) + public @NotNull BlockVec relative(@NotNull BlockFace face) { + return switch (face) { + case BOTTOM -> sub(0, 1, 0); + case TOP -> add(0, 1, 0); + case NORTH -> sub(0, 0, 1); + case SOUTH -> add(0, 0, 1); + case WEST -> sub(1, 0, 0); + case EAST -> add(1, 0, 0); + }; + } + + @Contract(pure = true) + public @NotNull Vec asVec() { + return new Vec(x, y, z); + } +} diff --git a/src/main/java/net/minestom/server/coordinate/Point.java b/src/main/java/net/minestom/server/coordinate/Point.java index 1914243d6..0d792c9b1 100644 --- a/src/main/java/net/minestom/server/coordinate/Point.java +++ b/src/main/java/net/minestom/server/coordinate/Point.java @@ -12,7 +12,7 @@ import java.util.function.DoubleUnaryOperator; /** * Represents a 3D point. */ -public sealed interface Point permits Vec, Pos { +public sealed interface Point permits Vec, Pos, BlockVec { /** * Gets the X coordinate. 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 04edaf1be..7fc447641 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockBreakEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -14,13 +15,13 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C private final Player player; private final Block block; private Block resultBlock; - private final Point blockPosition; + private final BlockVec 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 BlockVec blockPosition, @NotNull BlockFace blockFace) { this.player = player; @@ -72,7 +73,8 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java b/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java index 2ee16cf92..f43a96137 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockInteractEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -18,7 +19,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent private final Player player; private final Player.Hand hand; private final Block block; - private final Point blockPosition; + private final BlockVec blockPosition; private final Point cursorPosition; private final BlockFace blockFace; @@ -31,7 +32,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 Point cursorPosition, + @NotNull Block block, @NotNull BlockVec blockPosition, @NotNull Point cursorPosition, @NotNull BlockFace blockFace) { this.player = player; this.hand = hand; @@ -69,7 +70,8 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } 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 5613ee00c..7454103ba 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerBlockPlaceEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -17,7 +18,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C private final Player player; private Block block; private final BlockFace blockFace; - private final Point blockPosition; + private final BlockVec blockPosition; private final Player.Hand hand; private boolean consumeBlock; @@ -27,7 +28,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block, @NotNull BlockFace blockFace, - @NotNull Point blockPosition, @NotNull Player.Hand hand) { + @NotNull BlockVec blockPosition, @NotNull Player.Hand hand) { this.player = player; this.block = block; this.blockFace = blockFace; @@ -65,7 +66,8 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } diff --git a/src/main/java/net/minestom/server/event/player/PlayerCancelDiggingEvent.java b/src/main/java/net/minestom/server/event/player/PlayerCancelDiggingEvent.java index 0adf6a0f4..ab866527f 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerCancelDiggingEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerCancelDiggingEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -13,9 +14,9 @@ import org.jetbrains.annotations.NotNull; public class PlayerCancelDiggingEvent implements PlayerInstanceEvent, BlockEvent { private final Player player; private final Block block; - private final Point blockPosition; + private final BlockVec blockPosition; - public PlayerCancelDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull Point blockPosition) { + public PlayerCancelDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull BlockVec blockPosition) { this.player = player; this.block = block; this.blockPosition = blockPosition; @@ -36,9 +37,11 @@ public class PlayerCancelDiggingEvent implements PlayerInstanceEvent, BlockEvent * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } + @Override public @NotNull Player getPlayer() { return player; diff --git a/src/main/java/net/minestom/server/event/player/PlayerFinishDiggingEvent.java b/src/main/java/net/minestom/server/event/player/PlayerFinishDiggingEvent.java index 2ded2723a..6e486b1a0 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerFinishDiggingEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerFinishDiggingEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -13,9 +14,9 @@ import org.jetbrains.annotations.NotNull; public class PlayerFinishDiggingEvent implements PlayerInstanceEvent, BlockEvent { private final Player player; private @NotNull Block block; - private final Point blockPosition; + private final BlockVec blockPosition; - public PlayerFinishDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull Point blockPosition) { + public PlayerFinishDiggingEvent(@NotNull Player player, @NotNull Block block, @NotNull BlockVec blockPosition) { this.player = player; this.block = block; this.blockPosition = blockPosition; @@ -51,9 +52,11 @@ public class PlayerFinishDiggingEvent implements PlayerInstanceEvent, BlockEvent * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } + @Override public @NotNull Player getPlayer() { return player; diff --git a/src/main/java/net/minestom/server/event/player/PlayerStartDiggingEvent.java b/src/main/java/net/minestom/server/event/player/PlayerStartDiggingEvent.java index f5c457602..fd0b3bf45 100644 --- a/src/main/java/net/minestom/server/event/player/PlayerStartDiggingEvent.java +++ b/src/main/java/net/minestom/server/event/player/PlayerStartDiggingEvent.java @@ -1,5 +1,6 @@ package net.minestom.server.event.player; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.entity.Player; import net.minestom.server.event.trait.BlockEvent; @@ -21,12 +22,12 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent, private final Player player; private final Block block; - private final Point blockPosition; + private final BlockVec 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 BlockVec blockPosition, @NotNull BlockFace blockFace) { this.player = player; this.block = block; @@ -49,7 +50,8 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent, * * @return the block position */ - public @NotNull Point getBlockPosition() { + @Override + public @NotNull BlockVec getBlockPosition() { return blockPosition; } diff --git a/src/main/java/net/minestom/server/event/trait/BlockEvent.java b/src/main/java/net/minestom/server/event/trait/BlockEvent.java index 6185ee3cb..b1bce005a 100644 --- a/src/main/java/net/minestom/server/event/trait/BlockEvent.java +++ b/src/main/java/net/minestom/server/event/trait/BlockEvent.java @@ -1,9 +1,12 @@ package net.minestom.server.event.trait; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.event.Event; import net.minestom.server.instance.block.Block; import org.jetbrains.annotations.NotNull; public interface BlockEvent extends Event { @NotNull Block getBlock(); + + @NotNull BlockVec getBlockPosition(); } diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index f9fed417a..31459fcb6 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -2,6 +2,7 @@ package net.minestom.server.instance; import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import net.minestom.server.MinecraftServer; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; @@ -219,7 +220,7 @@ public class InstanceContainer extends Instance { chunk.sendChunk(player); return false; } - PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(player, block, Block.AIR, blockPosition, blockFace); + PlayerBlockBreakEvent blockBreakEvent = new PlayerBlockBreakEvent(player, block, Block.AIR, new BlockVec(blockPosition), blockFace); EventDispatcher.call(blockBreakEvent); final boolean allowed = !blockBreakEvent.isCancelled(); if (allowed) { diff --git a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java index 46980b6ac..38526303d 100644 --- a/src/main/java/net/minestom/server/listener/BlockPlacementListener.java +++ b/src/main/java/net/minestom/server/listener/BlockPlacementListener.java @@ -2,6 +2,7 @@ package net.minestom.server.listener; import net.minestom.server.MinecraftServer; import net.minestom.server.collision.CollisionUtils; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Vec; import net.minestom.server.entity.Entity; @@ -56,7 +57,7 @@ public class BlockPlacementListener { // Interact at block // FIXME: onUseOnBlock - PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, hand, interactedBlock, blockPosition, cursorPosition, blockFace); + PlayerBlockInteractEvent playerBlockInteractEvent = new PlayerBlockInteractEvent(player, hand, interactedBlock, new BlockVec(blockPosition), cursorPosition, blockFace); EventDispatcher.call(playerBlockInteractEvent); boolean blockUse = playerBlockInteractEvent.isBlockingItemUse(); if (!playerBlockInteractEvent.isCancelled()) { @@ -153,7 +154,7 @@ public class BlockPlacementListener { } // BlockPlaceEvent check - PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, placedBlock, blockFace, placementPosition, packet.hand()); + PlayerBlockPlaceEvent playerBlockPlaceEvent = new PlayerBlockPlaceEvent(player, placedBlock, blockFace, new BlockVec(placementPosition), packet.hand()); playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE); EventDispatcher.call(playerBlockPlaceEvent); if (playerBlockPlaceEvent.isCancelled()) { diff --git a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java index 9c3beec2c..c95e5de25 100644 --- a/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java +++ b/src/main/java/net/minestom/server/listener/PlayerDiggingListener.java @@ -1,5 +1,6 @@ package net.minestom.server.listener; +import net.minestom.server.coordinate.BlockVec; import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Pos; import net.minestom.server.entity.GameMode; @@ -82,7 +83,7 @@ public final class PlayerDiggingListener { // FIXME: verify mineable tag and enchantment final boolean instantBreak = player.isInstantBreak() || block.registry().hardness() == 0; if (!instantBreak) { - PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, blockPosition, blockFace); + PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, new BlockVec(blockPosition), blockFace); EventDispatcher.call(playerStartDiggingEvent); return new DiggingResult(block, !playerStartDiggingEvent.isCancelled()); } @@ -92,7 +93,7 @@ public final class PlayerDiggingListener { private static DiggingResult cancelDigging(Player player, Instance instance, Point blockPosition) { final Block block = instance.getBlock(blockPosition); - PlayerCancelDiggingEvent playerCancelDiggingEvent = new PlayerCancelDiggingEvent(player, block, blockPosition); + PlayerCancelDiggingEvent playerCancelDiggingEvent = new PlayerCancelDiggingEvent(player, block, new BlockVec(blockPosition)); EventDispatcher.call(playerCancelDiggingEvent); return new DiggingResult(block, true); } @@ -104,7 +105,7 @@ public final class PlayerDiggingListener { return new DiggingResult(block, false); } - PlayerFinishDiggingEvent playerFinishDiggingEvent = new PlayerFinishDiggingEvent(player, block, blockPosition); + PlayerFinishDiggingEvent playerFinishDiggingEvent = new PlayerFinishDiggingEvent(player, block, new BlockVec(blockPosition)); EventDispatcher.call(playerFinishDiggingEvent); return breakBlock(instance, player, blockPosition, playerFinishDiggingEvent.getBlock(), blockFace);