From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 20 Mar 2022 10:42:28 -0700 Subject: [PATCH] Add Position diff --git a/src/main/java/io/papermc/paper/math/BlockPosition.java b/src/main/java/io/papermc/paper/math/BlockPosition.java new file mode 100644 index 0000000000000000000000000000000000000000..c358bfdefc9bc7598dbd0d89a6b0b8a9408b5bb3 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/BlockPosition.java @@ -0,0 +1,100 @@ +package io.papermc.paper.math; + +import org.bukkit.Axis; +import org.bukkit.block.BlockFace; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * A position represented with integers. + *

+ * May see breaking changes until Experimental annotation is removed. + * + * @see FinePosition + */ +@ApiStatus.Experimental +@NullMarked +public interface BlockPosition extends Position { + + @Override + default double x() { + return this.blockX(); + } + + @Override + default double y() { + return this.blockY(); + } + + @Override + default double z() { + return this.blockZ(); + } + + @Override + default boolean isBlock() { + return true; + } + + @Override + default boolean isFine() { + return false; + } + + @Override + default BlockPosition toBlock() { + return this; + } + + @Override + default BlockPosition offset(final int x, final int y, final int z) { + return x == 0 && y == 0 && z == 0 ? this : new BlockPositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z); + } + + @Override + default FinePosition offset(final double x, final double y, final double z) { + return new FinePositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z); + } + + /** + * Returns a block position offset by 1 in the direction specified. + * + * @param blockFace the block face to offset towards + * @return the offset block position + */ + @Contract(value = "_ -> new", pure = true) + default BlockPosition offset(final BlockFace blockFace) { + return this.offset(blockFace, 1); + } + + /** + * Returns a block position offset in the direction specified + * multiplied by the amount. + * + * @param blockFace the block face to offset towards + * @param amount the number of times to move in that direction + * @return the offset block position + */ + @Contract(pure = true) + default BlockPosition offset(final BlockFace blockFace, final int amount) { + return amount == 0 ? this : new BlockPositionImpl(this.blockX() + (blockFace.getModX() * amount), this.blockY() + (blockFace.getModY() * amount), this.blockZ() + (blockFace.getModZ() * amount)); + } + + /** + * Returns a block position offset by the amount along + * the specified axis. + * + * @param axis the axis to offset along + * @param amount the amount to offset along that axis + * @return the offset block position + */ + @Contract(pure = true) + default BlockPosition offset(final Axis axis, final int amount) { + return amount == 0 ? this : switch (axis) { + case X -> new BlockPositionImpl(this.blockX() + amount, this.blockY(), this.blockZ()); + case Y -> new BlockPositionImpl(this.blockX(), this.blockY() + amount, this.blockZ()); + case Z -> new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ() + amount); + }; + } +} diff --git a/src/main/java/io/papermc/paper/math/BlockPositionImpl.java b/src/main/java/io/papermc/paper/math/BlockPositionImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..eb5a3f26c7ba56c6715827f52c0013a860ec7d9a --- /dev/null +++ b/src/main/java/io/papermc/paper/math/BlockPositionImpl.java @@ -0,0 +1,4 @@ +package io.papermc.paper.math; + +record BlockPositionImpl(int blockX, int blockY, int blockZ) implements BlockPosition { +} diff --git a/src/main/java/io/papermc/paper/math/FinePosition.java b/src/main/java/io/papermc/paper/math/FinePosition.java new file mode 100644 index 0000000000000000000000000000000000000000..b9c0065d8a9dedc3bd1a2d8bfbedfbc7f952ff93 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/FinePosition.java @@ -0,0 +1,57 @@ +package io.papermc.paper.math; + +import org.bukkit.util.NumberConversions; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +/** + * A position represented with doubles. + *

+ * May see breaking changes until Experimental annotation is removed. + * + * @see BlockPosition + */ +@ApiStatus.Experimental +@NullMarked +public interface FinePosition extends Position { + + @Override + default int blockX() { + return NumberConversions.floor(this.x()); + } + + @Override + default int blockY() { + return NumberConversions.floor(this.y()); + } + + @Override + default int blockZ() { + return NumberConversions.floor(this.z()); + } + + @Override + default boolean isBlock() { + return false; + } + + @Override + default boolean isFine() { + return true; + } + + @Override + default BlockPosition toBlock() { + return new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ()); + } + + @Override + default FinePosition offset(final int x, final int y, final int z) { + return this.offset((double) x, y, z); + } + + @Override + default FinePosition offset(final double x, final double y, final double z) { + return x == 0.0 && y == 0.0 && z == 0.0 ? this : new FinePositionImpl(this.x() + x, this.y() + y, this.z() + z); + } +} diff --git a/src/main/java/io/papermc/paper/math/FinePositionImpl.java b/src/main/java/io/papermc/paper/math/FinePositionImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..93476aaf8d21efb5a30b6d2cc2eeda8100fb72d0 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/FinePositionImpl.java @@ -0,0 +1,4 @@ +package io.papermc.paper.math; + +record FinePositionImpl(double x, double y, double z) implements FinePosition { +} diff --git a/src/main/java/io/papermc/paper/math/Position.java b/src/main/java/io/papermc/paper/math/Position.java new file mode 100644 index 0000000000000000000000000000000000000000..0e6a6a6738353b118e0ed093994dda06750700c4 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/Position.java @@ -0,0 +1,192 @@ +package io.papermc.paper.math; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +/** + * Common interface for {@link FinePosition} and {@link BlockPosition}. + *

+ * May see breaking changes until Experimental annotation is removed. + */ +@ApiStatus.Experimental +@NullMarked +public interface Position { + + FinePosition FINE_ZERO = new FinePositionImpl(0, 0, 0); + BlockPosition BLOCK_ZERO = new BlockPositionImpl(0, 0, 0); + + /** + * Gets the block x value for this position + * + * @return the block x value + */ + int blockX(); + + /** + * Gets the block x value for this position + * + * @return the block x value + */ + int blockY(); + + /** + * Gets the block x value for this position + * + * @return the block x value + */ + int blockZ(); + + /** + * Gets the x value for this position + * + * @return the x value + */ + double x(); + + /** + * Gets the y value for this position + * + * @return the y value + */ + double y(); + + /** + * Gets the z value for this position + * + * @return the z value + */ + double z(); + + /** + * Checks of this position represents a {@link BlockPosition} + * + * @return true if block + */ + boolean isBlock(); + + /** + * Checks if this position represents a {@link FinePosition} + * + * @return true if fine + */ + boolean isFine(); + + /** + * Checks if each component of this position is finite. + */ + default boolean isFinite() { + return Double.isFinite(this.x()) && Double.isFinite(this.y()) && Double.isFinite(this.z()); + } + + /** + * Returns a position offset by the specified amounts. + * + * @param x x value to offset + * @param y y value to offset + * @param z z value to offset + * @return the offset position + */ + Position offset(int x, int y, int z); + + /** + * Returns a position offset by the specified amounts. + * + * @param x x value to offset + * @param y y value to offset + * @param z z value to offset + * @return the offset position + */ + FinePosition offset(double x, double y, double z); + + /** + * Returns a new position at the center of the block position this represents + * + * @return a new center position + */ + @Contract(value = "-> new", pure = true) + default FinePosition toCenter() { + return new FinePositionImpl(this.blockX() + 0.5, this.blockY() + 0.5, this.blockZ() + 0.5); + } + + /** + * Returns the block position of this position + * or itself if it already is a block position + * + * @return the block position + */ + @Contract(pure = true) + BlockPosition toBlock(); + + /** + * Converts this position to a vector + * + * @return a new vector + */ + @Contract(value = "-> new", pure = true) + default Vector toVector() { + return new Vector(this.x(), this.y(), this.z()); + } + + /** + * Creates a new location object at this position with the specified world + * + * @param world the world for the location object + * @return a new location + */ + @Contract(value = "_ -> new", pure = true) + default Location toLocation(final World world) { + return new Location(world, this.x(), this.y(), this.z()); + } + + /** + * Creates a position at the coordinates + * + * @param x x coord + * @param y y coord + * @param z z coord + * @return a position with those coords + */ + @Contract(value = "_, _, _ -> new", pure = true) + static BlockPosition block(final int x, final int y, final int z) { + return new BlockPositionImpl(x, y, z); + } + + /** + * Creates a position from the location. + * + * @param location the location to copy the position of + * @return a new position at that location + */ + @Contract(value = "_ -> new", pure = true) + static BlockPosition block(final Location location) { + return new BlockPositionImpl(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Creates a position at the coordinates + * + * @param x x coord + * @param y y coord + * @param z z coord + * @return a position with those coords + */ + @Contract(value = "_, _, _ -> new", pure = true) + static FinePosition fine(final double x, final double y, final double z) { + return new FinePositionImpl(x, y, z); + } + + /** + * Creates a position from the location. + * + * @param location the location to copy the position of + * @return a new position at that location + */ + @Contract(value = "_ -> new", pure = true) + static FinePosition fine(final Location location) { + return new FinePositionImpl(location.getX(), location.getY(), location.getZ()); + } +} diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java index 7c4db051472fb6a6c6d24092dc6f75487356690a..85c342fc50f2fe0ce9a1b3980df9e088c3dea92d 100644 --- a/src/main/java/org/bukkit/Location.java +++ b/src/main/java/org/bukkit/Location.java @@ -20,7 +20,7 @@ import org.jetbrains.annotations.Nullable; * magnitude than 360 are valid, but may be normalized to any other equivalent * representation by the implementation. */ -public class Location implements Cloneable, ConfigurationSerializable { +public class Location implements Cloneable, ConfigurationSerializable, io.papermc.paper.math.FinePosition { // Paper private Reference world; private double x; private double y; @@ -706,4 +706,31 @@ public class Location implements Cloneable, ConfigurationSerializable { } return pitch; } + + // Paper - add Position + @Override + public double x() { + return this.getX(); + } + + @Override + public double y() { + return this.getY(); + } + + @Override + public double z() { + return this.getZ(); + } + + @Override + public boolean isFinite() { + return io.papermc.paper.math.FinePosition.super.isFinite() && Float.isFinite(this.getYaw()) && Float.isFinite(this.getPitch()); + } + + @Override + public @NotNull Location toLocation(@NotNull World world) { + return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch()); + } + // Paper end }