diff --git a/core/src/main/java/mc/core/world/block/BlockLocation.java b/core/src/main/java/mc/core/world/block/BlockLocation.java index cabccaa..7c9ca85 100644 --- a/core/src/main/java/mc/core/world/block/BlockLocation.java +++ b/core/src/main/java/mc/core/world/block/BlockLocation.java @@ -8,6 +8,10 @@ import lombok.*; public class BlockLocation implements Cloneable { private int x, y, z; + public static BlockLocation ZERO() { + return new BlockLocation(0,0,0); + } + public void setXYZ(int x, int y, int z) { this.x = x; this.y = y; diff --git a/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/BlockLocationSerializer.java b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/BlockLocationSerializer.java new file mode 100644 index 0000000..9aea2f5 --- /dev/null +++ b/proto_1.12.2/src/main/java/mc/core/network/proto_1_12_2/serializers/BlockLocationSerializer.java @@ -0,0 +1,63 @@ +package mc.core.network.proto_1_12_2.serializers; + +import mc.core.world.block.BlockLocation; + +import static com.google.common.math.IntMath.isPowerOfTwo; + +public class BlockLocationSerializer { + private static final int[] MULTIPLY_DE_BRUIJN_BIT_POSITION = new int[] {0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9}; + private static final int NUM_X_BITS = 1 + log2(smallestEncompassingPowerOfTwo(30000000)); + private static final int NUM_Z_BITS = NUM_X_BITS; + private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS; + private static final int Y_SHIFT = NUM_Z_BITS; + private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS; + private static final long X_MASK = (1L << NUM_X_BITS) - 1L; + private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L; + private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L; + + /* + * net.minecraft.util.math.MathHelper#log2(int) + */ + private static int log2(int value) { + return log2DeBruijn(value) - (isPowerOfTwo(value) ? 0 : 1); + } + + /* + * net.minecraft.util.math.MathHelper#log2DeBruijn(int) + */ + private static int log2DeBruijn(int value) { + value = isPowerOfTwo(value) ? value : smallestEncompassingPowerOfTwo(value); + return MULTIPLY_DE_BRUIJN_BIT_POSITION[(int)((long)value * 125613361L >> 27) & 31]; + } + + /* + * net.minecraft.util.math.MathHelper#smallestEncompassingPowerOfTwo(int) + */ + private static int smallestEncompassingPowerOfTwo(int value) { + int i = value - 1; + i = i | i >> 1; + i = i | i >> 2; + i = i | i >> 4; + i = i | i >> 8; + i = i | i >> 16; + return i + 1; + } + + public static long toLong(BlockLocation location) { + return ((long)location.getX() & X_MASK) << X_SHIFT | + ((long)location.getY() & Y_MASK) << Y_SHIFT | + ((long)location.getZ() & Z_MASK); + } + + public static BlockLocation fromLong(long value) { + BlockLocation location = BlockLocation.ZERO(); + fromLong(value, location); + return location; + } + + public static void fromLong(long value, BlockLocation location) { + location.setX((int)(value << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS)); + location.setY((int)(value << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS)); + location.setZ((int)(value << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS)); + } +} diff --git a/proto_1.12.2/src/test/java/mc/core/network/proto_1_12_2/serializers/TestBlockLocationSerializer.java b/proto_1.12.2/src/test/java/mc/core/network/proto_1_12_2/serializers/TestBlockLocationSerializer.java new file mode 100644 index 0000000..28db9ea --- /dev/null +++ b/proto_1.12.2/src/test/java/mc/core/network/proto_1_12_2/serializers/TestBlockLocationSerializer.java @@ -0,0 +1,32 @@ +package mc.core.network.proto_1_12_2.serializers; + +import mc.core.world.block.BlockLocation; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.ThreadLocalRandom; + +import static org.junit.Assert.*; + +public class TestBlockLocationSerializer { + private static final ThreadLocalRandom rnd = ThreadLocalRandom.current(); + private static final int minI = 0, maxI = 10; + private int x, y, z; + + @Before + public void before() { + x = rnd.nextInt(minI, maxI); + y = rnd.nextInt(minI, maxI); + z = rnd.nextInt(minI, maxI); + } + + @Test + public void test() { + BlockLocation location = new BlockLocation(x, y, z); + final long serializedCoords = BlockLocationSerializer.toLong(location); + + BlockLocation deserLoc = BlockLocationSerializer.fromLong(serializedCoords); + + assertEquals(location, deserLoc); + } +} \ No newline at end of file