diff --git a/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java new file mode 100644 index 000000000..0c269ae4b --- /dev/null +++ b/core/src/main/java/com/seibel/distanthorizons/core/pos/DhSectionPos.java @@ -0,0 +1,411 @@ +/* + * This file is part of the Distant Horizons mod + * licensed under the GNU LGPL v3 License. + * + * Copyright (C) 2020-2023 James Seibel + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package com.seibel.distanthorizons.core.pos; + +import com.seibel.distanthorizons.core.enums.EDhDirection; +import com.seibel.distanthorizons.core.util.LodUtil; +import com.seibel.distanthorizons.coreapi.util.BitShiftUtil; + +/** + * The position object used to define LOD objects in the quad trees.

+ * + * A section contains 64 x 64 LOD columns at a given quality. + * The Section detail level is different from the LOD detail level. + * For the specifics of how they compare can be viewed in the constants {@link #SECTION_BLOCK_DETAIL_LEVEL}, + * {@link #SECTION_CHUNK_DETAIL_LEVEL}, and {@link #SECTION_REGION_DETAIL_LEVEL}).

+ * + * Why does the smallest render section represent 2x2 MC chunks (section detail level 6)?
+ * A section defines what unit the quad tree works in, because of that we don't want that unit to be too big or too small.
+ * Too small, and we'll have 1,000s of sections running around, all needing individual files and render buffers.
+ * Too big, and the LOD dropoff will be very noticeable.
+ * With those thoughts in mind we decided on a smallest section size of 32 data points square (IE 2x2 chunks). + * + * @author Leetom + */ +public class DhSectionPos +{ + /** + * The lowest detail level a Section position can hold. + * This section DetailLevel holds 64 x 64 Block level (detail level 0) LODs. + */ + public static final byte SECTION_MINIMUM_DETAIL_LEVEL = 6; + + public static final byte SECTION_BLOCK_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.BLOCK_DETAIL_LEVEL; + public static final byte SECTION_CHUNK_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.CHUNK_DETAIL_LEVEL; + public static final byte SECTION_REGION_DETAIL_LEVEL = SECTION_MINIMUM_DETAIL_LEVEL + LodUtil.REGION_DETAIL_LEVEL; + + + + public static final int DETAIL_LEVEL_WIDTH = 8; + public static final int X_POS_WIDTH = 28; + public static final int Z_POS_WIDTH = 28; + public static final int X_POS_MISSING_WIDTH = 32 - 28; + public static final int Z_POS_MISSING_WIDTH = 32 - 28; + + + public static final int DETAIL_LEVEL_OFFSET = 0; + public static final int POS_X_OFFSET = DETAIL_LEVEL_OFFSET + DETAIL_LEVEL_WIDTH; + /** indicates the Y position where the LOD starts relative to the level's minimum height */ + public static final int POS_Z_OFFSET = POS_X_OFFSET + X_POS_WIDTH; + + public static final long DETAIL_LEVEL_MASK = Byte.MAX_VALUE; + public static final int POS_X_MASK = (int) Math.pow(2, X_POS_WIDTH) - 1; + public static final int POS_Z_MASK = (int) Math.pow(2, Z_POS_WIDTH) - 1; + + + + //==============// + // constructors // + //==============// + + /** + * This class just holds utility methods for handling a packed + * {@link DhSectionPos} and shouldn't be constructed.

+ * + * Use one of the {@link DhSectionPos#encode(byte, int, int)} methods instead + */ + private DhSectionPos() { } + + + + /** + * Note: + * no validation is done for whether the detail level is positive + * or if the X/Z positions can be represented by available bits. + */ + public static long encode(byte detailLevel, int x, int z) + { + long data = 0; + data |= detailLevel & DETAIL_LEVEL_MASK; + data |= (long) (x & POS_X_MASK) << POS_X_OFFSET; + data |= (long) (z & POS_Z_MASK) << POS_Z_OFFSET; + return data; + } + + public static long encode(DhBlockPos pos) { return encodeBlockPos(pos.x, pos.z); } + public static long encode(DhBlockPos2D pos) { return encodeBlockPos(pos.x, pos.z); } + public static long encodeBlockPos(int blockX, int blockZ) + { + long pos = encode(LodUtil.BLOCK_DETAIL_LEVEL, blockX, blockZ); + pos = convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, pos); + return pos; + } + + public static long encode(DhChunkPos pos) { return encodeChunkPos(pos.x, pos.z); } + public static long encodeChunkPos(int chunkX, int chunkZ) + { + long pos = encode(LodUtil.CHUNK_DETAIL_LEVEL, chunkX, chunkZ); + pos = convertToDetailLevel(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, pos); + return pos; + } + + + + //============// + // converters // + //============// + + /** uses the absolute detail level aka detail levels like {@link LodUtil#CHUNK_DETAIL_LEVEL} instead of the dhSectionPos detailLevels. */ + public static long convertToDetailLevel(byte newDetailLevel, long pos) + { + byte detailLevel = getDetailLevel(pos); + int x = getX(pos); + int z = getZ(pos); + + // logic originally taken from DhLodPos + if (newDetailLevel >= detailLevel) + { + x = Math.floorDiv(x, BitShiftUtil.powerOfTwo(newDetailLevel - detailLevel)); + z = Math.floorDiv(z, BitShiftUtil.powerOfTwo(newDetailLevel - detailLevel)); + } + else + { + x = x * BitShiftUtil.powerOfTwo(detailLevel - newDetailLevel); + z = z * BitShiftUtil.powerOfTwo(detailLevel - newDetailLevel); + } + + return encode(newDetailLevel, x, z); + } + + + + //==================// + // property getters // + //==================// + + public static byte getDetailLevel(long pos) { return (byte) ((pos >> DETAIL_LEVEL_OFFSET) & DETAIL_LEVEL_MASK); } + public static int getX(long pos) + { + // unpack the position + int x = (int) ((pos >> POS_X_OFFSET) & POS_X_MASK); + // add the missing 2's compliment most-significant bits (if not done negative numbers will parse incorrectly) + x = (x << X_POS_MISSING_WIDTH) >> X_POS_MISSING_WIDTH; + return x; + } + public static int getZ(long pos) + { + int Z = (int) ((pos >> POS_Z_OFFSET) & POS_Z_MASK); + Z = (Z << Z_POS_MISSING_WIDTH) >> Z_POS_MISSING_WIDTH; + return Z; + } + + + + //=========// + // getters // + //=========// + + /** @return the block X pos that represents the smallest X coordinate of this section */ + public static int getMinCornerBlockX(long pos) + { + int halfBlockWidth = DhSectionPos.getBlockWidth(pos) / 2; + return DhSectionPos.getCenterBlockPosX(pos) - halfBlockWidth; + } + /** @return the block Z pos that represents the smallest Z coordinate of this section */ + public static int getMinCornerBlockZ(long pos) + { + int halfBlockWidth = DhSectionPos.getBlockWidth(pos) / 2; + return DhSectionPos.getCenterBlockPosZ(pos) - halfBlockWidth; + } + + /** + * A detail level of X lower than this section's detail level will return:
+ * 0 -> 1
+ * 1 -> 2
+ * 2 -> 4
+ * 3 -> 8
+ * etc. + * + * @return how many {@link DhSectionPos}'s at the given detail level it would take to span the width of this section. + */ + public static int getWidthCountForLowerDetailedSection(byte returnDetailLevel, long pos) + { + byte detailLevel = getDetailLevel(pos); + + LodUtil.assertTrue(returnDetailLevel <= detailLevel, "returnDetailLevel must be less than sectionDetail"); + byte offset = (byte) (detailLevel - returnDetailLevel); + return BitShiftUtil.powerOfTwo(offset); + } + + /** @return how wide this section is in blocks */ + public static int getBlockWidth(long pos) { return BitShiftUtil.powerOfTwo(getDetailLevel(pos)); } + + + public static DhBlockPos2D getCenterBlockPos(long pos) { return new DhBlockPos2D(getCenterBlockPosX(pos), getCenterBlockPosZ(pos)); } + + public static int getCenterBlockPosX(long pos) { return getCenterBlockPosXOrZ(true, pos); } + public static int getCenterBlockPosZ(long pos) { return getCenterBlockPosXOrZ(false, pos); } + private static int getCenterBlockPosXOrZ(boolean returnX, long pos) + { + byte detailLevel = getDetailLevel(pos); + int x = getX(pos); + int z = getZ(pos); + + + int centerBlockPos = returnX ? x : z; + + if (detailLevel == 0) + { + // already at block detail level, no conversion necessary + return centerBlockPos; + } + + // we can't get the center of the position at block level, only attempt to get the position offset for detail levels above 0 + int positionOffset = 0; + if (detailLevel != 1) + { + positionOffset = BitShiftUtil.powerOfTwo(detailLevel - 1); + } + + return (centerBlockPos * BitShiftUtil.powerOfTwo(detailLevel)) + positionOffset; + } + + public static int getManhattanBlockDistance(DhBlockPos2D blockPos, long pos) + { + return Math.abs(getCenterBlockPosX(pos) - blockPos.x) + + Math.abs(getCenterBlockPosZ(pos) - blockPos.z); + } + + + + //==================// + // parent child pos // + //==================// + + /** + * Returns a position 1 detail level lower.

+ * + * Relative child positions returned for each index:
+ * 0 = (0,0) - North West
+ * 1 = (1,0) - South West
+ * 2 = (0,1) - North East
+ * 3 = (1,1) - South East
+ * + * @param child0to3 must be an int between 0 and 3 + */ + public static long getChildByIndex(int child0to3, long pos) throws IllegalArgumentException, IllegalStateException + { + byte detailLevel = getDetailLevel(pos); + int x = getX(pos); + int z = getZ(pos); + + if (child0to3 < 0 || child0to3 > 3) + { + throw new IllegalArgumentException("child0to3 must be between 0 and 3"); + } + if (detailLevel <= 0) + { + throw new IllegalStateException("section detail must be greater than 0"); + } + + return DhSectionPos.encode((byte) (detailLevel - 1), + x * 2 + (child0to3 & 1), + z * 2 + BitShiftUtil.half(child0to3 & 2)); + } + /** Returns this position's child index in its parent */ + public static int getChildIndexOfParent(long pos) { return (getX(pos) & 1) + BitShiftUtil.square(getZ(pos) & 1); } + + public static long getParentPos(long pos) { return DhSectionPos.encode((byte) (getDetailLevel(pos) + 1), BitShiftUtil.half(getX(pos)), BitShiftUtil.half(getZ(pos))); } + + + + public static long getAdjacentPos(EDhDirection dir, long pos) throws IllegalArgumentException + { + if (dir == EDhDirection.UP || dir == EDhDirection.DOWN) + { + throw new IllegalArgumentException("getAdjacentPos can't be UP or DOWN, direction given: ["+dir.name()+"]."); + } + + return DhSectionPos.encode(getDetailLevel(pos), + getX(pos) + dir.getNormal().x, + getZ(pos) + dir.getNormal().z); + } + + //public DhLodPos getSectionBBoxPos() { return new DhLodPos(this.detailLevel, this.x, this.z); } + + + + //=============// + // comparisons // + //=============// + + public static boolean contains(long aPos, long bPos) + { + int aMinX = getMinCornerBlockX(aPos); + int aMinZ = getMinCornerBlockZ(aPos); + + int bMinX = getMinCornerBlockX(bPos); + int bMinZ = getMinCornerBlockZ(bPos); + + int aBlockWidth = getBlockWidth(aPos) - 1; // minus 1 to account for zero based positional indexing + int aMaxX = aMinX + aBlockWidth; + int aMaxZ = aMinZ + aBlockWidth; + + return aMinX <= bMinX && bMinX <= aMaxX && + aMinZ <= bMinZ && bMinZ <= aMaxZ; + } + + + + //===========// + // iterators // + //===========// + + /** Applies the given consumer to all 4 of this position's children. */ + public static void forEachChild(IPrimitiveLongConsumer callback, long pos) throws IllegalArgumentException, IllegalStateException + { + for (int i = 0; i < 4; i++) + { + callback.accept(getChildByIndex(i, pos)); + } + } + + /** Applies the given consumer to all children of the position at the given section detail level. */ + public static void forEachChildDownToDetailLevel(byte minSectionDetailLevel, ICancelablePrimitiveLongConsumer callback, long pos) throws IllegalArgumentException, IllegalStateException + { + boolean stop = callback.accept(pos); + if (stop || minSectionDetailLevel == getDetailLevel(pos)) + { + return; + } + + for (int i = 0; i < 4; i++) + { + forEachChildDownToDetailLevel(minSectionDetailLevel, callback, getChildByIndex(i, pos)); + } + } + + /** Applies the given consumer to all children of the position at the given section detail level. */ + public static void forEachChildAtDetailLevel(byte sectionDetailLevel, IPrimitiveLongConsumer callback, long pos) throws IllegalArgumentException, IllegalStateException + { + if (sectionDetailLevel == getDetailLevel(pos)) + { + callback.accept(pos); + return; + } + + for (int i = 0; i < 4; i++) + { + forEachChildAtDetailLevel(sectionDetailLevel, callback, getChildByIndex(i, pos)); + } + } + + /** Applies the given consumer to all children of the position at the given section detail level. */ + public static void forEachPosUpToDetailLevel(byte maxSectionDetailLevel, IPrimitiveLongConsumer callback, long pos) + { + callback.accept(pos); + if (maxSectionDetailLevel == getDetailLevel(pos)) + { + return; + } + + forEachPosUpToDetailLevel(maxSectionDetailLevel, callback, getParentPos(pos)); + } + + + + //==============// + // Base methods // + //==============// + + public static String toString(long pos) { return getDetailLevel(pos) + "*" + getX(pos) + "," + getZ(pos); } + + + + //================// + // helper methods // + //================// + + /** Used instead of {@link java.util.function.Consumer} to prevent unnecessary (un)wrapping. */ + @FunctionalInterface + public interface IPrimitiveLongConsumer + { + void accept(long value); + } + + /** Used instead of {@link java.util.function.Function} to prevent unnecessary (un)wrapping. */ + @FunctionalInterface + public interface ICancelablePrimitiveLongConsumer + { + /** @return true if this method should cancel further consumers. */ + boolean accept(long value); + } + +} diff --git a/core/src/test/java/tests/DhSectionPosTest.java b/core/src/test/java/tests/DhSectionPosTest.java index 23bd48819..89f459b7b 100644 --- a/core/src/test/java/tests/DhSectionPosTest.java +++ b/core/src/test/java/tests/DhSectionPosTest.java @@ -19,99 +19,134 @@ package tests; -import com.seibel.distanthorizons.core.pos.*; +import com.seibel.distanthorizons.core.enums.EDhDirection; +import com.seibel.distanthorizons.core.pos.DhSectionPos; +import com.seibel.distanthorizons.core.pos.DhChunkPos; +import com.seibel.distanthorizons.core.pos.DhBlockPos; +import com.seibel.distanthorizons.core.pos.DhBlockPos2D; import org.junit.Assert; import org.junit.Test; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicInteger; + public class DhSectionPosTest { + @Test - public void ContainsPosTest() + public void basicEncodeDecodeTest() { - OldDhSectionPos root = new OldDhSectionPos((byte) 10, 0, 0); - OldDhSectionPos child = new OldDhSectionPos((byte) 9, 1, 1); + long pos; - Assert.assertTrue("section pos contains fail", root.contains(child)); - Assert.assertFalse("section pos contains fail", child.contains(root)); + // zero pos + pos = DhSectionPos.encode((byte) 0, 0, 0); + assertSectionPosEqual(0, DhSectionPos.getDetailLevel(pos)); + assertSectionPosEqual(0, DhSectionPos.getX(pos)); + assertSectionPosEqual(0, DhSectionPos.getZ(pos)); + + // positive values + pos = DhSectionPos.encode((byte) 10, 4, 1); + assertSectionPosEqual(10, DhSectionPos.getDetailLevel(pos)); + assertSectionPosEqual(4, DhSectionPos.getX(pos)); + assertSectionPosEqual(1, DhSectionPos.getZ(pos)); + + // negative position, positive detail level + pos = DhSectionPos.encode((byte) 2, -1, -4); + assertSectionPosEqual(2, DhSectionPos.getDetailLevel(pos)); + assertSectionPosEqual(-1, DhSectionPos.getX(pos)); + assertSectionPosEqual(-4, DhSectionPos.getZ(pos)); + + } + + + + @Test + public void containsPosTest() + { + long root = DhSectionPos.encode((byte) 10, 0, 0); + long child = DhSectionPos.encode((byte) 9, 1, 1); + + Assert.assertTrue("section pos contains fail", DhSectionPos.contains(root, child)); + Assert.assertFalse("section pos contains fail", DhSectionPos.contains(child, root)); - root = new OldDhSectionPos((byte) 10, 1, 0); + root = DhSectionPos.encode((byte) 10, 1, 0); // out of bounds - child = new OldDhSectionPos((byte) 9, 0, 0); - Assert.assertFalse("position should be out of bounds", root.contains(child)); - child = new OldDhSectionPos((byte) 9, 1, 1); - Assert.assertFalse("position should be out of bounds", root.contains(child)); + child = DhSectionPos.encode((byte) 9, 0, 0); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); + child = DhSectionPos.encode((byte) 9, 1, 1); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); // in bounds - child = new OldDhSectionPos((byte) 9, 2, 0); - Assert.assertTrue("position should be in bounds", root.contains(child)); - child = new OldDhSectionPos((byte) 9, 3, 1); - Assert.assertTrue("position should be in bounds", root.contains(child)); + child = DhSectionPos.encode((byte) 9, 2, 0); + Assert.assertTrue("position should be in bounds", DhSectionPos.contains(root, child)); + child = DhSectionPos.encode((byte) 9, 3, 1); + Assert.assertTrue("position should be in bounds", DhSectionPos.contains(root, child)); // out of bounds - child = new OldDhSectionPos((byte) 9, 2, 2); - Assert.assertFalse("position should be out of bounds", root.contains(child)); - child = new OldDhSectionPos((byte) 9, 3, 3); - Assert.assertFalse("position should be out of bounds", root.contains(child)); + child = DhSectionPos.encode((byte) 9, 2, 2); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); + child = DhSectionPos.encode((byte) 9, 3, 3); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); - child = new OldDhSectionPos((byte) 9, 4, 4); - Assert.assertFalse("position should be out of bounds", root.contains(child)); - child = new OldDhSectionPos((byte) 9, 5, 5); - Assert.assertFalse("position should be out of bounds", root.contains(child)); + child = DhSectionPos.encode((byte) 9, 4, 4); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); + child = DhSectionPos.encode((byte) 9, 5, 5); + Assert.assertFalse("position should be out of bounds", DhSectionPos.contains(root, child)); } @Test - public void ContainsAdjacentPosTest() + public void containsAdjacentPosTest() { // neither should contain the other, they are single blocks that are next to each other - OldDhSectionPos left = new OldDhSectionPos((byte) 0, 4606, 0); - OldDhSectionPos right = new OldDhSectionPos((byte) 0, 4607, 0); - Assert.assertFalse(left.contains(right)); - Assert.assertFalse(right.contains(left)); - - + long left = DhSectionPos.encode((byte) 0, 4606, 0); + long right = DhSectionPos.encode((byte) 0, 4607, 0); + Assert.assertFalse(DhSectionPos.contains(left, right)); + Assert.assertFalse(DhSectionPos.contains(right, left)); + + // 512 block wide sections that are adjacent, but not overlapping - left = new OldDhSectionPos((byte) 9, 0, 0); - right = new OldDhSectionPos((byte) 9, 1, 0); - Assert.assertFalse(left.contains(right)); - Assert.assertFalse(right.contains(left)); - + left = DhSectionPos.encode((byte) 9, 0, 0); + right = DhSectionPos.encode((byte) 9, 1, 0); + Assert.assertFalse(DhSectionPos.contains(left, right)); + Assert.assertFalse(DhSectionPos.contains(right, left)); + } @Test - public void ParentPosTest() + public void parentPosTest() { - OldDhSectionPos leaf = new OldDhSectionPos((byte) 0, 0, 0); - OldDhSectionPos convert = leaf.convertNewToDetailLevel((byte) 1); - OldDhSectionPos parent = leaf.getParentPos(); - Assert.assertEquals("get parent at 0,0 fail", convert, parent); - - - leaf = new OldDhSectionPos((byte) 0, 1, 1); - convert = leaf.convertNewToDetailLevel((byte) 1); - parent = leaf.getParentPos(); - Assert.assertEquals("get parent at 1,1 fail", convert, parent); - - - leaf = new OldDhSectionPos((byte) 1, 2, 2); - convert = leaf.convertNewToDetailLevel((byte) 2); - parent = leaf.getParentPos(); - Assert.assertEquals("parent upscale fail", convert, parent); - convert = leaf.convertNewToDetailLevel((byte) 0); - OldDhSectionPos childIndex = leaf.getChildByIndex(0); - Assert.assertEquals("child detail fail", convert, childIndex); - + long leaf = DhSectionPos.encode((byte) 0, 0, 0); + long convert = DhSectionPos.convertToDetailLevel((byte) 1, leaf); + long parent = DhSectionPos.getParentPos(leaf); + assertSectionPosEqual("get parent at 0,0 fail", convert, parent); + + + leaf = DhSectionPos.encode((byte) 0, 1, 1); + convert = DhSectionPos.convertToDetailLevel((byte) 1, leaf); + parent = DhSectionPos.getParentPos(leaf); + assertSectionPosEqual("get parent at 1,1 fail", convert, parent); + + + leaf = DhSectionPos.encode((byte) 1, 2, 2); + convert = DhSectionPos.convertToDetailLevel((byte) 2, leaf); + parent = DhSectionPos.getParentPos(leaf); + assertSectionPosEqual("parent upscale fail", convert, parent); + convert = DhSectionPos.convertToDetailLevel((byte) 0, leaf); + long childIndex = DhSectionPos.getChildByIndex(0, leaf); + assertSectionPosEqual("child detail fail", convert, childIndex); + } @Test - public void ChildPosTest() + public void childPosTest() { - OldDhSectionPos node = new OldDhSectionPos((byte) 1, 2302, 0); - OldDhSectionPos nw = node.getChildByIndex(0); - OldDhSectionPos sw = node.getChildByIndex(1); - OldDhSectionPos ne = node.getChildByIndex(2); - OldDhSectionPos se = node.getChildByIndex(3); + long node = DhSectionPos.encode((byte) 1, 2302, 0); + long nw = DhSectionPos.getChildByIndex(0, node); + long sw = DhSectionPos.getChildByIndex(1, node); + long ne = DhSectionPos.getChildByIndex(2, node); + long se = DhSectionPos.getChildByIndex(3, node); // confirm no children have the same values Assert.assertNotEquals(nw, sw); @@ -119,244 +154,340 @@ public class DhSectionPosTest Assert.assertNotEquals(ne, se); // confirm each child has the correct value - Assert.assertEquals(nw, new OldDhSectionPos((byte) 0, 4604, 0)); - Assert.assertEquals(sw, new OldDhSectionPos((byte) 0, 4605, 0)); - Assert.assertEquals(ne, new OldDhSectionPos((byte) 0, 4604, 1)); - Assert.assertEquals(se, new OldDhSectionPos((byte) 0, 4605, 1)); + assertSectionPosEqual(nw, DhSectionPos.encode((byte) 0, 4604, 0)); + assertSectionPosEqual(sw, DhSectionPos.encode((byte) 0, 4605, 0)); + assertSectionPosEqual(ne, DhSectionPos.encode((byte) 0, 4604, 1)); + assertSectionPosEqual(se, DhSectionPos.encode((byte) 0, 4605, 1)); } @Test - public void GetCenterTest() + public void getCenterBlockTest() { - OldDhSectionPos node = new OldDhSectionPos((byte) 1, 2303, 0); - DhBlockPos2D centerBlockPos = node.getCenterBlockPos(); + long node = DhSectionPos.encode((byte) 1, 2303, 0); + DhBlockPos2D centerBlockPos = DhSectionPos.getCenterBlockPos(node); DhBlockPos2D expectedCenterNode = new DhBlockPos2D(4606, 0); - Assert.assertEquals("", expectedCenterNode, centerBlockPos); - - - - node = new OldDhSectionPos((byte) 10, 0, 0); // 1024 blocks wide - centerBlockPos = node.getCenterBlockPos(); + Assert.assertEquals(expectedCenterNode, centerBlockPos); + + + + node = DhSectionPos.encode((byte) 10, 0, 0); // 1024 blocks wide + centerBlockPos = DhSectionPos.getCenterBlockPos(node); expectedCenterNode = new DhBlockPos2D(1024 / 2, 1024 / 2); - Assert.assertEquals("", expectedCenterNode, centerBlockPos); + Assert.assertEquals(expectedCenterNode, centerBlockPos); } @Test - public void GetCenter2Test() + public void getCenterBlock2DTest() { - OldDhSectionPos parentNode = new OldDhSectionPos((byte) 2, 1151, 0); // width 4 blocks - OldDhSectionPos inputPos = new OldDhSectionPos((byte) 0, 4606, 0); // width 1 block - Assert.assertTrue(parentNode.contains(inputPos)); - - DhBlockPos2D parentCenter = parentNode.getCenterBlockPos(); - DhBlockPos2D inputCenter = inputPos.getCenterBlockPos(); + long parentNode = DhSectionPos.encode((byte) 2, 1151, 0); // width 4 blocks + long inputPos = DhSectionPos.encode((byte) 0, 4606, 0); // width 1 block + Assert.assertTrue(DhSectionPos.contains(parentNode, inputPos)); + + DhBlockPos2D parentCenter = DhSectionPos.getCenterBlockPos(parentNode); + DhBlockPos2D inputCenter = DhSectionPos.getCenterBlockPos(inputPos); Assert.assertEquals(new DhBlockPos2D(4606, 2), parentCenter); Assert.assertEquals(new DhBlockPos2D(4606, 0), inputCenter); - + } @Test - public void CreateFromBlockPos() + public void createFromBlockPos() { // origin pos // DhBlockPos originBlockPos = new DhBlockPos(0, 0, 0); - OldDhSectionPos originSectionPos = new OldDhSectionPos(originBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + long originsectionPos = DhSectionPos.encode(originBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originsectionPos); // offset pos // + long offsetSectionPos; DhBlockPos offsetBlockPos = new DhBlockPos(1000, 0, 42000); - OldDhSectionPos offsetSectionPos = new OldDhSectionPos(offsetBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + offsetSectionPos = DhSectionPos.encode(offsetBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); offsetBlockPos = new DhBlockPos(-987654, 0, 46); - offsetSectionPos = new OldDhSectionPos(offsetBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + offsetSectionPos = DhSectionPos.encode(offsetBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); } @Test - public void CreateFromBlockPos2D() + public void createFromBlockPos2D() { // origin pos // DhBlockPos2D originBlockPos = new DhBlockPos2D(0, 0); - OldDhSectionPos originSectionPos = new OldDhSectionPos(originBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + long originSectionPos = DhSectionPos.encode(originBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); // offset pos // DhBlockPos2D offsetBlockPos = new DhBlockPos2D(1000, 42000); - OldDhSectionPos offsetSectionPos = new OldDhSectionPos(offsetBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + long offsetSectionPos = DhSectionPos.encode(offsetBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 15, 656), offsetSectionPos); offsetBlockPos = new DhBlockPos2D(-987654, 46); - offsetSectionPos = new OldDhSectionPos(offsetBlockPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + offsetSectionPos = DhSectionPos.encode(offsetBlockPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); } @Test - public void CreateFromChunkPos() + public void createFromChunkPos() { // origin pos // DhChunkPos originChunkPos = new DhChunkPos(0,0); - OldDhSectionPos originSectionPos = new OldDhSectionPos(originChunkPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 0, 0), originSectionPos); + long originSectionPos = DhSectionPos.encode(originChunkPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 0, 0), originSectionPos); // offset pos // DhChunkPos offsetChunkPos = new DhChunkPos(1000, 42000); - OldDhSectionPos offsetSectionPos = new OldDhSectionPos(offsetChunkPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 15, 656), offsetSectionPos); + long offsetSectionPos = DhSectionPos.encode(offsetChunkPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, 15, 656), offsetSectionPos); offsetChunkPos = new DhChunkPos(-987654, 46); - offsetSectionPos = new OldDhSectionPos(offsetChunkPos); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); + offsetSectionPos = DhSectionPos.encode(offsetChunkPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL, -15433, 0), offsetSectionPos); } @Test - public void ConvertToDetailLevel() + public void convertToDetailLevel() { // origin pos // - OldDhSectionPos originSectionPos = new OldDhSectionPos((byte) 0,0,0); + long originSectionPos = DhSectionPos.encode((byte) 0,0,0); - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(new OldDhSectionPos((byte) 1, 0, 0), originSectionPos); + originSectionPos = DhSectionPos.convertToDetailLevel((byte) 1, originSectionPos); + assertSectionPosEqual(DhSectionPos.encode((byte) 1, 0, 0), originSectionPos); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, 0, 0), originSectionPos); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL, 0, 0), originSectionPos); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, 0, 0), originSectionPos); // offset pos // - OldDhSectionPos sectionPos = new OldDhSectionPos((byte) 0,-10000,5000); + long offsetSectionPos = DhSectionPos.encode((byte) 0,-10000,5000); - sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(new OldDhSectionPos((byte) 1, -5000, 2500), sectionPos); + offsetSectionPos = DhSectionPos.convertToDetailLevel((byte) 1, offsetSectionPos); + assertSectionPosEqual(DhSectionPos.encode((byte) 1, -5000, 2500), offsetSectionPos); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -157, 78), sectionPos); + offsetSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, offsetSectionPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, -157, 78), offsetSectionPos); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(new OldDhSectionPos(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL, -1, 0), sectionPos); + offsetSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, offsetSectionPos); + assertSectionPosEqual(DhSectionPos.encode(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, -1, 0), offsetSectionPos); } @Test - public void GetOffsetWidth() + public void getOffsetWidth() { - OldDhSectionPos originSectionPos = new OldDhSectionPos((byte) 0,0,0); - OldDhSectionPos sectionPos = new OldDhSectionPos((byte) 0,-10000,5000); + long originSectionPos = DhSectionPos.encode((byte) 0,0,0); + long sectionPos = DhSectionPos.encode((byte) 0,-10000,5000); // 1 -> 0 byte returnDetailLevel = 0; - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + originSectionPos = DhSectionPos.convertToDetailLevel((byte) 1, originSectionPos); + assertSectionPosEqual(2, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, originSectionPos)); - sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + sectionPos = DhSectionPos.convertToDetailLevel((byte) 1, sectionPos); + assertSectionPosEqual(2, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, sectionPos)); // 2 -> 1 returnDetailLevel = 1; - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 2); - Assert.assertEquals(2, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + originSectionPos = DhSectionPos.convertToDetailLevel((byte) 2, originSectionPos); + assertSectionPosEqual(2, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, originSectionPos)); - sectionPos = sectionPos.convertNewToDetailLevel((byte) 2); - Assert.assertEquals(2, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + sectionPos = DhSectionPos.convertToDetailLevel((byte) 2, sectionPos); + assertSectionPosEqual(2, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, sectionPos)); // Block -> 0 returnDetailLevel = 0; - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(64, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, originSectionPos)); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, sectionPos); + assertSectionPosEqual(64, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, sectionPos)); // Region -> 3 returnDetailLevel = 3; - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, originSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(4096, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, originSectionPos)); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(4096, sectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, sectionPos); + assertSectionPosEqual(4096, DhSectionPos.getWidthCountForLowerDetailedSection(returnDetailLevel, sectionPos)); } @Test - public void GetBlockWidth() + public void getBlockWidth() { - OldDhSectionPos originSectionPos = new OldDhSectionPos((byte) 0,0,0); - OldDhSectionPos sectionPos = new OldDhSectionPos((byte) 0,-10000,5000); + long originSectionPos = DhSectionPos.encode((byte) 0,0,0); + long sectionPos = DhSectionPos.encode((byte) 0,-10000,5000); - Assert.assertEquals(1, originSectionPos.getBlockWidth()); - Assert.assertEquals(1, sectionPos.getBlockWidth()); + assertSectionPosEqual(1, DhSectionPos.getBlockWidth(originSectionPos)); + assertSectionPosEqual(1, DhSectionPos.getBlockWidth(sectionPos)); - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, originSectionPos.getBlockWidth()); - sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(2, sectionPos.getBlockWidth()); + originSectionPos = DhSectionPos.convertToDetailLevel((byte) 1, originSectionPos); + assertSectionPosEqual(2, DhSectionPos.getBlockWidth(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel((byte) 1, sectionPos); + assertSectionPosEqual(2, DhSectionPos.getBlockWidth(sectionPos)); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, originSectionPos.getBlockWidth()); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(64, sectionPos.getBlockWidth()); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(64, DhSectionPos.getBlockWidth(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, sectionPos); + assertSectionPosEqual(64, DhSectionPos.getBlockWidth(sectionPos)); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(32768, originSectionPos.getBlockWidth()); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(32768, sectionPos.getBlockWidth()); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, originSectionPos); + assertSectionPosEqual(32768, DhSectionPos.getBlockWidth(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, sectionPos); + assertSectionPosEqual(32768, DhSectionPos.getBlockWidth(sectionPos)); } @Test - public void GetCenterBlockPos() + public void getCenterBlockPos() { - OldDhSectionPos originSectionPos = new OldDhSectionPos((byte) 0,0,0); - OldDhSectionPos sectionPos = new OldDhSectionPos((byte) 0,-10000,5000); + long originSectionPos = DhSectionPos.encode((byte) 0,0,0); + long sectionPos = DhSectionPos.encode((byte) 0,-10000,5000); - Assert.assertEquals(new DhBlockPos2D(0, 0), originSectionPos.getCenterBlockPos()); - Assert.assertEquals(new DhBlockPos2D(-10000, 5000), sectionPos.getCenterBlockPos()); + Assert.assertEquals(new DhBlockPos2D(0, 0), DhSectionPos.getCenterBlockPos(originSectionPos)); + Assert.assertEquals(new DhBlockPos2D(-10000, 5000), DhSectionPos.getCenterBlockPos(sectionPos)); - originSectionPos = originSectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(new DhBlockPos2D(0, 0), originSectionPos.getCenterBlockPos()); - sectionPos = sectionPos.convertNewToDetailLevel((byte) 1); - Assert.assertEquals(new DhBlockPos2D(-10000, 5000), sectionPos.getCenterBlockPos()); + originSectionPos = DhSectionPos.convertToDetailLevel((byte) 1, originSectionPos); + Assert.assertEquals(new DhBlockPos2D(0, 0), DhSectionPos.getCenterBlockPos(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel((byte) 1, sectionPos); + Assert.assertEquals(new DhBlockPos2D(-10000, 5000), DhSectionPos.getCenterBlockPos(sectionPos)); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(new DhBlockPos2D(32, 32), originSectionPos.getCenterBlockPos()); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_BLOCK_DETAIL_LEVEL); - Assert.assertEquals(new DhBlockPos2D(-10016, 5024), sectionPos.getCenterBlockPos()); + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, originSectionPos); + Assert.assertEquals(new DhBlockPos2D(32, 32), DhSectionPos.getCenterBlockPos(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_BLOCK_DETAIL_LEVEL, sectionPos); + Assert.assertEquals(new DhBlockPos2D(-10016, 5024), DhSectionPos.getCenterBlockPos(sectionPos)); + + + originSectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, originSectionPos); + Assert.assertEquals(new DhBlockPos2D(16384, 16384), DhSectionPos.getCenterBlockPos(originSectionPos)); + sectionPos = DhSectionPos.convertToDetailLevel(DhSectionPos.SECTION_REGION_DETAIL_LEVEL, sectionPos); + Assert.assertEquals(new DhBlockPos2D(-16384, 16384), DhSectionPos.getCenterBlockPos(sectionPos)); + + } + + @Test + public void getMinCornerBlockPos() + { + long pos; + + // origin block detail + pos = DhSectionPos.encode((byte) 0,0,0); + Assert.assertEquals(0, DhSectionPos.getMinCornerBlockX(pos)); + Assert.assertEquals(0, DhSectionPos.getMinCornerBlockZ(pos)); + + // offset block detail + pos = DhSectionPos.encode((byte) 0,2,3); + Assert.assertEquals(2 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockX(pos)); + Assert.assertEquals(3 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockZ(pos)); + + // negative offset block detail + pos = DhSectionPos.encode((byte) 0,-1,-2); + Assert.assertEquals(-1 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockX(pos)); + Assert.assertEquals(-2 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockZ(pos)); - originSectionPos = originSectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(new DhBlockPos2D(16384, 16384), originSectionPos.getCenterBlockPos()); - sectionPos = sectionPos.convertNewToDetailLevel(OldDhSectionPos.SECTION_REGION_DETAIL_LEVEL); - Assert.assertEquals(new DhBlockPos2D(-16384, 16384), sectionPos.getCenterBlockPos()); + // origin chunk detail + pos = DhSectionPos.encode(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL,0,0); + Assert.assertEquals(0, DhSectionPos.getMinCornerBlockX(pos)); + Assert.assertEquals(0, DhSectionPos.getMinCornerBlockZ(pos)); + + // offset chunk detail + pos = DhSectionPos.encode(DhSectionPos.SECTION_CHUNK_DETAIL_LEVEL,2,3); + Assert.assertEquals(2 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockX(pos)); + Assert.assertEquals(3 * DhSectionPos.getBlockWidth(pos), DhSectionPos.getMinCornerBlockZ(pos)); + } + @Test + public void getAdjacentPos() + { + long pos = DhSectionPos.encode((byte) 0, 0, 0); + + assertSectionPosEqual(DhSectionPos.encode((byte) 0, 0, -1), DhSectionPos.getAdjacentPos(EDhDirection.NORTH, pos)); + assertSectionPosEqual(DhSectionPos.encode((byte) 0, 0, 1), DhSectionPos.getAdjacentPos(EDhDirection.SOUTH, pos)); + + assertSectionPosEqual(DhSectionPos.encode((byte) 0, 1, 0), DhSectionPos.getAdjacentPos(EDhDirection.EAST, pos)); + assertSectionPosEqual(DhSectionPos.encode((byte) 0, -1, 0), DhSectionPos.getAdjacentPos(EDhDirection.WEST, pos)); + + // getting the adjacent position in the up and down position don't make sense + Assert.assertThrows(IllegalArgumentException.class, () -> { DhSectionPos.getAdjacentPos(EDhDirection.UP, pos); }); + Assert.assertThrows(IllegalArgumentException.class, () -> { DhSectionPos.getAdjacentPos(EDhDirection.DOWN, pos); }); + } + + @Test + public void forEachChildIterator() + { + long pos = DhSectionPos.encode((byte) 1, 0, 0); + + ArrayList childPosList = new ArrayList<>(); + AtomicInteger childCount = new AtomicInteger(0); + DhSectionPos.forEachChild((childPos) -> + { + childCount.incrementAndGet(); + childPosList.add(childPos); + }, pos); + + Assert.assertTrue(childPosList.contains(DhSectionPos.encode((byte) 0, 0, 0))); + Assert.assertTrue(childPosList.contains(DhSectionPos.encode((byte) 0, 1, 0))); + Assert.assertTrue(childPosList.contains(DhSectionPos.encode((byte) 0, 0, 1))); + Assert.assertTrue(childPosList.contains(DhSectionPos.encode((byte) 0, 1, 1))); + + } + + + + + //================// + // helper methods // + //================// + + public static void assertSectionPosEqual(long expected, long actual) { assertSectionPosEqual("", expected, actual); } + public static void assertSectionPosEqual(String messagePrefix, long expected, long actual) + { + if (!messagePrefix.endsWith(" ")) + { + messagePrefix += " "; + } + + String expectedString = DhSectionPos.toString(expected); + String actualString = DhSectionPos.toString(actual); + String mismatchSuffix = "expected: ["+expectedString+"] actual: ["+actualString+"]."; + + Assert.assertEquals(messagePrefix+"Detail level mismatch, "+mismatchSuffix, DhSectionPos.getDetailLevel(expected), DhSectionPos.getDetailLevel(actual)); + Assert.assertEquals(messagePrefix+"X Pos mismatch, "+mismatchSuffix, DhSectionPos.getX(expected), DhSectionPos.getX(actual)); + Assert.assertEquals(messagePrefix+"Z Pos mismatch, "+mismatchSuffix, DhSectionPos.getZ(expected), DhSectionPos.getZ(actual)); + } + + }