diff --git a/src/main/java/xyz/nucleoid/plasmid/api/util/BlockTraversal.java b/src/main/java/xyz/nucleoid/plasmid/api/util/BlockTraversal.java index c91ac2eb..c016f435 100644 --- a/src/main/java/xyz/nucleoid/plasmid/api/util/BlockTraversal.java +++ b/src/main/java/xyz/nucleoid/plasmid/api/util/BlockTraversal.java @@ -141,9 +141,17 @@ boolean isComplete() { * @see 3-dimensional pixel connectivity */ public static final class Connectivity { - public static final Connectivity SIX = create(Connectivity::six); - public static final Connectivity EIGHTEEN = create(Connectivity::eighteen); - public static final Connectivity TWENTY_SIX = create(Connectivity::twentySix); + public static final Connectivity SIX = create(Connectivity::generateSix); + public static final Connectivity EIGHTEEN = create(Connectivity::generateEighteen); + public static final Connectivity TWENTY_SIX = create(Connectivity::generateTwentySix); + + private static final Connectivity FOUR_X = create(consumer -> generateFour(Direction.Axis.X, consumer)); + private static final Connectivity FOUR_Y = create(consumer -> generateFour(Direction.Axis.Y, consumer)); + private static final Connectivity FOUR_Z = create(consumer -> generateFour(Direction.Axis.Z, consumer)); + + private static final Connectivity EIGHT_X = create(consumer -> generateEight(Direction.Axis.X, consumer)); + private static final Connectivity EIGHT_Y = create(consumer -> generateEight(Direction.Axis.Y, consumer)); + private static final Connectivity EIGHT_Z = create(consumer -> generateEight(Direction.Axis.Z, consumer)); final Vec3i[] offsets; @@ -151,20 +159,36 @@ public static final class Connectivity { this.offsets = offsets; } + public static Connectivity four(Direction.Axis orthogonalAxis) { + return switch (orthogonalAxis) { + case X -> FOUR_X; + case Y -> FOUR_Y; + case Z -> FOUR_Z; + }; + } + + public static Connectivity eight(Direction.Axis orthogonalAxis) { + return switch (orthogonalAxis) { + case X -> EIGHT_X; + case Y -> EIGHT_Y; + case Z -> EIGHT_Z; + }; + } + static Connectivity create(Consumer> generator) { var offsets = new ArrayList(); generator.accept(offsets::add); return new Connectivity(offsets.toArray(new Vec3i[0])); } - private static void six(Consumer consumer) { + private static void generateSix(Consumer consumer) { for (var direction : Direction.values()) { consumer.accept(direction.getVector()); } } - private static void eighteen(Consumer consumer) { - six(consumer); + private static void generateEighteen(Consumer consumer) { + generateSix(consumer); for (int x = -1; x <= 1; x += 2) { for (int y = -1; y <= 1; y += 2) { @@ -175,8 +199,8 @@ private static void eighteen(Consumer consumer) { } } - private static void twentySix(Consumer consumer) { - eighteen(consumer); + private static void generateTwentySix(Consumer consumer) { + generateEighteen(consumer); for (int z = -1; z <= 1; z += 2) { for (int x = -1; x <= 1; x += 2) { @@ -186,6 +210,28 @@ private static void twentySix(Consumer consumer) { } } } + + private static void generateFour(Direction.Axis orthogonalAxis, Consumer consumer) { + for (var direction : Direction.values()) { + if (direction.getAxis() != orthogonalAxis) { + consumer.accept(direction.getVector()); + } + } + } + + private static void generateEight(Direction.Axis orthogonalAxis, Consumer consumer) { + generateFour(orthogonalAxis, consumer); + + for (int x = -1; x <= 1; x += 2) { + for (int y = -1; y <= 1; y += 2) { + consumer.accept(switch (orthogonalAxis) { + case X -> new BlockPos(0, x, y); + case Y -> new BlockPos(y, 0, x); + case Z -> new BlockPos(x, y, 0); + }); + } + } + } } /** diff --git a/src/test/java/xyz/nucleoid/plasmid/test/BlockTraversalTests.java b/src/test/java/xyz/nucleoid/plasmid/test/BlockTraversalTests.java new file mode 100644 index 00000000..436d4e6d --- /dev/null +++ b/src/test/java/xyz/nucleoid/plasmid/test/BlockTraversalTests.java @@ -0,0 +1,201 @@ +package xyz.nucleoid.plasmid.test; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import xyz.nucleoid.plasmid.api.util.BlockTraversal; +import org.junit.jupiter.api.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +public class BlockTraversalTests { + @Test + public void testSixConnectivity() { + var expected = Set.of( + new BlockPos(-1, 0, 0), + new BlockPos(0, -1, 0), + new BlockPos(0, 0, -1), + new BlockPos(1, 0, 0), + new BlockPos(0, 1, 0), + new BlockPos(0, 0, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.SIX); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testEighteenConnectivity() { + var expected = Set.of( + new BlockPos(-1, 0, 0), + new BlockPos(0, -1, 0), + new BlockPos(0, 0, -1), + new BlockPos(1, 0, 0), + new BlockPos(0, 1, 0), + new BlockPos(0, 0, 1), + + new BlockPos(-1, -1, 0), + new BlockPos(-1, 0, -1), + new BlockPos(0, -1, -1), + new BlockPos(1, -1, 0), + new BlockPos(1, 0, -1), + new BlockPos(0, 1, -1), + new BlockPos(-1, 1, 0), + new BlockPos(-1, 0, 1), + new BlockPos(0, -1, 1), + new BlockPos(1, 1, 0), + new BlockPos(1, 0, 1), + new BlockPos(0, 1, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.EIGHTEEN); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testTwentySixConnectivity() { + var expected = Set.of( + new BlockPos(-1, 0, 0), + new BlockPos(0, -1, 0), + new BlockPos(0, 0, -1), + new BlockPos(1, 0, 0), + new BlockPos(0, 1, 0), + new BlockPos(0, 0, 1), + + new BlockPos(-1, -1, 0), + new BlockPos(-1, 0, -1), + new BlockPos(0, -1, -1), + new BlockPos(1, -1, 0), + new BlockPos(1, 0, -1), + new BlockPos(0, 1, -1), + new BlockPos(-1, 1, 0), + new BlockPos(-1, 0, 1), + new BlockPos(0, -1, 1), + new BlockPos(1, 1, 0), + new BlockPos(1, 0, 1), + new BlockPos(0, 1, 1), + + new BlockPos(-1, -1, -1), + new BlockPos(-1, -1, 1), + new BlockPos(-1, 1, -1), + new BlockPos(-1, 1, 1), + new BlockPos(1, -1, -1), + new BlockPos(1, -1, 1), + new BlockPos(1, 1, -1), + new BlockPos(1, 1, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.TWENTY_SIX); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testFourConnectivityAxisX() { + var expected = Set.of( + new BlockPos(0, -1, 0), + new BlockPos(0, 1, 0), + new BlockPos(0, 0, -1), + new BlockPos(0, 0, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.X)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testFourConnectivityAxisY() { + var expected = Set.of( + new BlockPos(0, 0, -1), + new BlockPos(0, 0, 1), + new BlockPos(-1, 0, 0), + new BlockPos(1, 0, 0) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.Y)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testFourConnectivityAxisZ() { + var expected = Set.of( + new BlockPos(-1, 0, 0), + new BlockPos(1, 0, 0), + new BlockPos(0, -1, 0), + new BlockPos(0, 1, 0) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.four(Direction.Axis.Z)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testEightConnectivityAxisX() { + var expected = Set.of( + new BlockPos(0, -1, 0), + new BlockPos(0, 1, 0), + new BlockPos(0, 0, -1), + new BlockPos(0, 0, 1), + + new BlockPos(0, -1, -1), + new BlockPos(0, -1, 1), + new BlockPos(0, 1, -1), + new BlockPos(0, 1, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.X)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testEightConnectivityAxisY() { + var expected = Set.of( + new BlockPos(0, 0, -1), + new BlockPos(0, 0, 1), + new BlockPos(-1, 0, 0), + new BlockPos(1, 0, 0), + + new BlockPos(-1, 0, -1), + new BlockPos(-1, 0, 1), + new BlockPos(1, 0, -1), + new BlockPos(1, 0, 1) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.Y)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + @Test + public void testEightConnectivityAxisZ() { + var expected = Set.of( + new BlockPos(-1, 0, 0), + new BlockPos(1, 0, 0), + new BlockPos(0, -1, 0), + new BlockPos(0, 1, 0), + + new BlockPos(-1, -1, 0), + new BlockPos(-1, 1, 0), + new BlockPos(1, -1, 0), + new BlockPos(1, 1, 0) + ); + + var traversal = BlockTraversal.create().connectivity(BlockTraversal.Connectivity.eight(Direction.Axis.Z)); + assertSingleTraversalVisits(expected, BlockPos.ORIGIN, traversal); + } + + private void assertSingleTraversalVisits(Set expected, BlockPos origin, BlockTraversal traversal) { + Set actual = new HashSet<>(); + + traversal.accept(origin, (pos, fromPos, depth) -> { + if (depth >= 1) { + actual.add(pos.toImmutable()); + return BlockTraversal.Result.TERMINATE; + } + + return BlockTraversal.Result.CONTINUE; + }); + + assertEquals(expected, actual); + } +}