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..f0fdabce4af640da2a406412e67020761ded3ac1 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/BlockPosition.java @@ -0,0 +1,98 @@ +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.jetbrains.annotations.NotNull; + +/** + * A position represented with integers. + *

+ * May see breaking changes until Experimental annotation is removed. + * @see FinePosition + */ +@ApiStatus.Experimental +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 @NotNull BlockPosition toBlock() { + return this; + } + + @Override + default @NotNull BlockPosition offset(int x, int y, int z) { + return x == 0 && y == 0 && z == 0 ? this : new BlockPositionImpl(this.blockX() + x, this.blockY() + y, this.blockZ() + z); + } + + @Override + default @NotNull FinePosition offset(double x, double y, 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 @NotNull BlockPosition offset(@NotNull 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 @NotNull BlockPosition offset(@NotNull BlockFace blockFace, 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 @NotNull BlockPosition offset(@NotNull Axis axis, 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..d8df70d731573cf2446044925f218876d62fd7cf --- /dev/null +++ b/src/main/java/io/papermc/paper/math/FinePosition.java @@ -0,0 +1,56 @@ +package io.papermc.paper.math; + +import org.bukkit.util.NumberConversions; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +/** + * A position represented with doubles. + *

+ * May see breaking changes until Experimental annotation is removed. + * @see BlockPosition + */ +@ApiStatus.Experimental +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 @NotNull BlockPosition toBlock() { + return new BlockPositionImpl(this.blockX(), this.blockY(), this.blockZ()); + } + + @Override + default @NotNull FinePosition offset(int x, int y, int z) { + return this.offset((double) x, y, z); + } + + @Override + default @NotNull FinePosition offset(double x, double y, 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..26bc5a0fa67855af87c8fd4cd8229b4d9f242740 --- /dev/null +++ b/src/main/java/io/papermc/paper/math/Position.java @@ -0,0 +1,191 @@ +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.jetbrains.annotations.NotNull; + +/** + * Common interface for {@link FinePosition} and {@link BlockPosition}. + *

+ * May see breaking changes until Experimental annotation is removed. + */ +@ApiStatus.Experimental +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 + */ + @NotNull 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 + */ + @NotNull 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 @NotNull 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) + @NotNull BlockPosition toBlock(); + + /** + * Converts this position to a vector + * + * @return a new vector + */ + @Contract(value = "-> new", pure = true) + default @NotNull 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 @NotNull Location toLocation(@NotNull 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 @NotNull BlockPosition block(int x, int y, 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 @NotNull BlockPosition block(@NotNull 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 @NotNull FinePosition fine(double x, double y, 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 @NotNull FinePosition fine(@NotNull 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 }