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. * Represents a 3D point.
*/ */
public sealed interface Point permits Vec, Pos { public sealed interface Point permits Vec, Pos, BlockVec {
/** /**
* Gets the X coordinate. * Gets the X coordinate.

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -14,13 +15,13 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C
private final Player player; private final Player player;
private final Block block; private final Block block;
private Block resultBlock; private Block resultBlock;
private final Point blockPosition; private final BlockVec blockPosition;
private final BlockFace blockFace; private final BlockFace blockFace;
private boolean cancelled; private boolean cancelled;
public PlayerBlockBreakEvent(@NotNull Player player, 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) { @NotNull BlockFace blockFace) {
this.player = player; this.player = player;
@ -72,7 +73,8 @@ public class PlayerBlockBreakEvent implements PlayerInstanceEvent, BlockEvent, C
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -18,7 +19,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent
private final Player player; private final Player player;
private final Player.Hand hand; private final Player.Hand hand;
private final Block block; private final Block block;
private final Point blockPosition; private final BlockVec blockPosition;
private final Point cursorPosition; private final Point cursorPosition;
private final BlockFace blockFace; private final BlockFace blockFace;
@ -31,7 +32,7 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent
private boolean cancelled; private boolean cancelled;
public PlayerBlockInteractEvent(@NotNull Player player, @NotNull Player.Hand hand, 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) { @NotNull BlockFace blockFace) {
this.player = player; this.player = player;
this.hand = hand; this.hand = hand;
@ -69,7 +70,8 @@ public class PlayerBlockInteractEvent implements PlayerInstanceEvent, BlockEvent
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -17,7 +18,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
private final Player player; private final Player player;
private Block block; private Block block;
private final BlockFace blockFace; private final BlockFace blockFace;
private final Point blockPosition; private final BlockVec blockPosition;
private final Player.Hand hand; private final Player.Hand hand;
private boolean consumeBlock; private boolean consumeBlock;
@ -27,7 +28,7 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block, public PlayerBlockPlaceEvent(@NotNull Player player, @NotNull Block block,
@NotNull BlockFace blockFace, @NotNull BlockFace blockFace,
@NotNull Point blockPosition, @NotNull Player.Hand hand) { @NotNull BlockVec blockPosition, @NotNull Player.Hand hand) {
this.player = player; this.player = player;
this.block = block; this.block = block;
this.blockFace = blockFace; this.blockFace = blockFace;
@ -65,7 +66,8 @@ public class PlayerBlockPlaceEvent implements PlayerInstanceEvent, BlockEvent, C
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -13,9 +14,9 @@ import org.jetbrains.annotations.NotNull;
public class PlayerCancelDiggingEvent implements PlayerInstanceEvent, BlockEvent { public class PlayerCancelDiggingEvent implements PlayerInstanceEvent, BlockEvent {
private final Player player; private final Player player;
private final Block block; 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.player = player;
this.block = block; this.block = block;
this.blockPosition = blockPosition; this.blockPosition = blockPosition;
@ -36,9 +37,11 @@ public class PlayerCancelDiggingEvent implements PlayerInstanceEvent, BlockEvent
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }
@Override @Override
public @NotNull Player getPlayer() { public @NotNull Player getPlayer() {
return player; return player;

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -13,9 +14,9 @@ import org.jetbrains.annotations.NotNull;
public class PlayerFinishDiggingEvent implements PlayerInstanceEvent, BlockEvent { public class PlayerFinishDiggingEvent implements PlayerInstanceEvent, BlockEvent {
private final Player player; private final Player player;
private @NotNull Block block; 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.player = player;
this.block = block; this.block = block;
this.blockPosition = blockPosition; this.blockPosition = blockPosition;
@ -51,9 +52,11 @@ public class PlayerFinishDiggingEvent implements PlayerInstanceEvent, BlockEvent
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }
@Override @Override
public @NotNull Player getPlayer() { public @NotNull Player getPlayer() {
return player; return player;

View File

@ -1,5 +1,6 @@
package net.minestom.server.event.player; package net.minestom.server.event.player;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.trait.BlockEvent; import net.minestom.server.event.trait.BlockEvent;
@ -21,12 +22,12 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent,
private final Player player; private final Player player;
private final Block block; private final Block block;
private final Point blockPosition; private final BlockVec blockPosition;
private final BlockFace blockFace; private final BlockFace blockFace;
private boolean cancelled; 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) { @NotNull BlockFace blockFace) {
this.player = player; this.player = player;
this.block = block; this.block = block;
@ -49,7 +50,8 @@ public class PlayerStartDiggingEvent implements PlayerInstanceEvent, BlockEvent,
* *
* @return the block position * @return the block position
*/ */
public @NotNull Point getBlockPosition() { @Override
public @NotNull BlockVec getBlockPosition() {
return blockPosition; return blockPosition;
} }

View File

@ -1,9 +1,12 @@
package net.minestom.server.event.trait; package net.minestom.server.event.trait;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.event.Event; import net.minestom.server.event.Event;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public interface BlockEvent extends Event { public interface BlockEvent extends Event {
@NotNull Block getBlock(); @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 it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
@ -219,7 +220,7 @@ public class InstanceContainer extends Instance {
chunk.sendChunk(player); chunk.sendChunk(player);
return false; 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); EventDispatcher.call(blockBreakEvent);
final boolean allowed = !blockBreakEvent.isCancelled(); final boolean allowed = !blockBreakEvent.isCancelled();
if (allowed) { if (allowed) {

View File

@ -2,6 +2,7 @@ package net.minestom.server.listener;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.collision.CollisionUtils; import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.Entity; import net.minestom.server.entity.Entity;
@ -56,7 +57,7 @@ public class BlockPlacementListener {
// Interact at block // Interact at block
// FIXME: onUseOnBlock // 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); EventDispatcher.call(playerBlockInteractEvent);
boolean blockUse = playerBlockInteractEvent.isBlockingItemUse(); boolean blockUse = playerBlockInteractEvent.isBlockingItemUse();
if (!playerBlockInteractEvent.isCancelled()) { if (!playerBlockInteractEvent.isCancelled()) {
@ -153,7 +154,7 @@ public class BlockPlacementListener {
} }
// BlockPlaceEvent check // 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); playerBlockPlaceEvent.consumeBlock(player.getGameMode() != GameMode.CREATIVE);
EventDispatcher.call(playerBlockPlaceEvent); EventDispatcher.call(playerBlockPlaceEvent);
if (playerBlockPlaceEvent.isCancelled()) { if (playerBlockPlaceEvent.isCancelled()) {

View File

@ -1,5 +1,6 @@
package net.minestom.server.listener; package net.minestom.server.listener;
import net.minestom.server.coordinate.BlockVec;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
@ -82,7 +83,7 @@ public final class PlayerDiggingListener {
// FIXME: verify mineable tag and enchantment // FIXME: verify mineable tag and enchantment
final boolean instantBreak = player.isInstantBreak() || block.registry().hardness() == 0; final boolean instantBreak = player.isInstantBreak() || block.registry().hardness() == 0;
if (!instantBreak) { if (!instantBreak) {
PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, blockPosition, blockFace); PlayerStartDiggingEvent playerStartDiggingEvent = new PlayerStartDiggingEvent(player, block, new BlockVec(blockPosition), blockFace);
EventDispatcher.call(playerStartDiggingEvent); EventDispatcher.call(playerStartDiggingEvent);
return new DiggingResult(block, !playerStartDiggingEvent.isCancelled()); return new DiggingResult(block, !playerStartDiggingEvent.isCancelled());
} }
@ -92,7 +93,7 @@ public final class PlayerDiggingListener {
private static DiggingResult cancelDigging(Player player, Instance instance, Point blockPosition) { private static DiggingResult cancelDigging(Player player, Instance instance, Point blockPosition) {
final Block block = instance.getBlock(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); EventDispatcher.call(playerCancelDiggingEvent);
return new DiggingResult(block, true); return new DiggingResult(block, true);
} }
@ -104,7 +105,7 @@ public final class PlayerDiggingListener {
return new DiggingResult(block, false); return new DiggingResult(block, false);
} }
PlayerFinishDiggingEvent playerFinishDiggingEvent = new PlayerFinishDiggingEvent(player, block, blockPosition); PlayerFinishDiggingEvent playerFinishDiggingEvent = new PlayerFinishDiggingEvent(player, block, new BlockVec(blockPosition));
EventDispatcher.call(playerFinishDiggingEvent); EventDispatcher.call(playerFinishDiggingEvent);
return breakBlock(instance, player, blockPosition, playerFinishDiggingEvent.getBlock(), blockFace); return breakBlock(instance, player, blockPosition, playerFinishDiggingEvent.getBlock(), blockFace);