Add BlockVec as a Point implementation (#2144)

* Add the BlockVec class

* Use BlockVec in BlockEvent

* Add usage notes
This commit is contained in:
Samuel 2024-05-23 16:52:16 -04:00 committed by GitHub
parent 1f07d38f2b
commit 776ad02d63
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 228 additions and 25 deletions

View File

@ -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);
}
}

View File

@ -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.

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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) {

View File

@ -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()) {

View File

@ -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);