From 0b4a4f92e25b73e899b9726a21f56710ee91236b Mon Sep 17 00:00:00 2001 From: Jason Mitchell Date: Sun, 7 Jul 2024 15:38:54 -0700 Subject: [PATCH] Add CoordinatePacker * Currently used in Angelica & GT5u --- addon.gradle | 7 +++ dependencies.gradle | 4 -- .../gtnhlib/util/CoordinatePacker.java | 62 +++++++++++++++++++ .../test/util/CoordinatePackerTest.java | 58 +++++++++++++++++ 4 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 addon.gradle create mode 100644 src/main/java/com/gtnewhorizon/gtnhlib/util/CoordinatePacker.java create mode 100644 src/test/java/com/gtnewhorizon/gtnhlib/test/util/CoordinatePackerTest.java diff --git a/addon.gradle b/addon.gradle new file mode 100644 index 0000000..29106b4 --- /dev/null +++ b/addon.gradle @@ -0,0 +1,7 @@ + +test { + useJUnitPlatform() + testLogging { + events "passed", "skipped", "failed" + } +} diff --git a/dependencies.gradle b/dependencies.gradle index fe15674..3897703 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -18,7 +18,3 @@ dependencies { compileOnly("org.projectlombok:lombok:1.18.22") {transitive = false } annotationProcessor("org.projectlombok:lombok:1.18.22") } - -test { - useJUnitPlatform() -} diff --git a/src/main/java/com/gtnewhorizon/gtnhlib/util/CoordinatePacker.java b/src/main/java/com/gtnewhorizon/gtnhlib/util/CoordinatePacker.java new file mode 100644 index 0000000..11debfd --- /dev/null +++ b/src/main/java/com/gtnewhorizon/gtnhlib/util/CoordinatePacker.java @@ -0,0 +1,62 @@ +package com.gtnewhorizon.gtnhlib.util; + +import net.minecraft.util.ChunkCoordinates; + +import org.joml.Vector3i; + +public final class CoordinatePacker { + + private static final int SIZE_BITS_X = 26; // range in MC: -30,000,000 to 30,000,000; Range here - [-33554432, + // 33554431] + private static final int SIZE_BITS_Z = SIZE_BITS_X; // Same as X + private static final int SIZE_BITS_Y = 64 - SIZE_BITS_X - SIZE_BITS_Z; // range in MC: [0, 255]; Range here - + // [-2048, 2047] + + private static final long BITS_X = (1L << SIZE_BITS_X) - 1L; + private static final long BITS_Y = (1L << SIZE_BITS_Y) - 1L; + private static final long BITS_Z = (1L << SIZE_BITS_Z) - 1L; + + private static final int BIT_SHIFT_X = SIZE_BITS_Y + SIZE_BITS_Z; + private static final int BIT_SHIFT_Z = SIZE_BITS_Y; + private static final int BIT_SHIFT_Y = 0; + + public static long pack(int x, int y, int z) { + long l = 0L; + l |= ((long) x & BITS_X) << BIT_SHIFT_X; + l |= ((long) y & BITS_Y) << BIT_SHIFT_Y; + l |= ((long) z & BITS_Z) << BIT_SHIFT_Z; + return l; + } + + public static long pack(ChunkCoordinates coords) { + return pack(coords.posX, coords.posY, coords.posZ); + } + + public static long pack(Vector3i coords) { + return pack(coords.x, coords.y, coords.z); + } + + public static int unpackX(long packed) { + return (int) (packed << 64 - BIT_SHIFT_X - SIZE_BITS_X >> 64 - SIZE_BITS_X); + } + + public static int unpackY(long packed) { + return (int) (packed << 64 - SIZE_BITS_Y >> 64 - SIZE_BITS_Y); + } + + public static int unpackZ(long packed) { + return (int) (packed << 64 - BIT_SHIFT_Z - SIZE_BITS_Z >> 64 - SIZE_BITS_Z); + } + + public static void unpack(long packed, ChunkCoordinates coords) { + coords.posX = unpackX(packed); + coords.posY = unpackY(packed); + coords.posZ = unpackZ(packed); + } + + public static void unpack(long packed, Vector3i coords) { + coords.x = unpackX(packed); + coords.y = unpackY(packed); + coords.z = unpackZ(packed); + } +} diff --git a/src/test/java/com/gtnewhorizon/gtnhlib/test/util/CoordinatePackerTest.java b/src/test/java/com/gtnewhorizon/gtnhlib/test/util/CoordinatePackerTest.java new file mode 100644 index 0000000..3980657 --- /dev/null +++ b/src/test/java/com/gtnewhorizon/gtnhlib/test/util/CoordinatePackerTest.java @@ -0,0 +1,58 @@ +package com.gtnewhorizon.gtnhlib.test.util; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import net.minecraft.util.ChunkCoordinates; + +import org.junit.jupiter.api.Test; + +import com.gtnewhorizon.gtnhlib.util.CoordinatePacker; + +public class CoordinatePackerTest { + + @Test + void testPackUnpack() { + int[][] coordinates = { + // 0 + { 0, 0, 0 }, + // MC min, [0, 255], MC min + { -30_000_000, 0, -30_000_000 }, { -30_000_000, 255, -30_000_000 }, + // MC max, [0, 255], MC max + { 30_000_000, 0, 30_000_000 }, { 30_000_000, 255, 30_000_000 }, + // MC min, [0, 255], MC max + { -30_000_000, 0, 30_000_000 }, { -30_000_000, 255, 30_000_000 }, + // MC max, [0, 255], MC min + { 30_000_000, 0, -30_000_000 }, { 30_000_000, 255, -30_000_000 }, + // Java Min/Max based on bits + { -33_554_432, -2048, -33_554_432 }, { 33_554_431, 2047, 33_554_431 }, + // bunch of 255's + { 255, 255, 255 }, { 255, 255, 0 }, { 255, 0, 255 }, { 0, 255, 255 }, { 0, 0, 255 }, { 0, 255, 0 }, + { 255, 0, 0 }, { 0, 255, 0 }, { 0, 0, 255 }, + // 0, min/max, 0 + { 0, -2048, 0 }, { 0, 2047, 0 }, }; + final ChunkCoordinates chunkCoordinates = new ChunkCoordinates(); + final ChunkCoordinates unpackedCoordinates = new ChunkCoordinates(); + for (int[] coordinate : coordinates) { + chunkCoordinates.set(coordinate[0], coordinate[1], coordinate[2]); + long packed = CoordinatePacker.pack(chunkCoordinates); + CoordinatePacker.unpack(packed, unpackedCoordinates); + assertTrue( + coordinate[0] == unpackedCoordinates.posX && coordinate[1] == unpackedCoordinates.posY + && coordinate[2] == unpackedCoordinates.posZ, + "Failed for " + coordinate[0] + + ", " + + coordinate[1] + + ", " + + coordinate[2] + + " -> " + + packed + + " -> " + + unpackedCoordinates.posX + + ", " + + unpackedCoordinates.posY + + ", " + + unpackedCoordinates.posZ); + } + } + +}