diff --git a/gradle.properties b/gradle.properties index f8b4737..c4911d6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -34,7 +34,7 @@ mod_name=Area Control # The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default. mod_license=BSD-3-Clause # The mod version. See https://semver.org/ -mod_version=0.8.6 +mod_version=0.8.7 # The group ID for the mod. It is only important when publishing as an artifact to a Maven repository. # This should match the base package used for the mod sources. # See https://maven.apache.org/guides/mini/guide-naming-conventions.html diff --git a/src/main/java/org/teacon/areacontrol/impl/AreaEntitySelectorChecker.java b/src/main/java/org/teacon/areacontrol/impl/AreaEntitySelectorChecker.java index 6c1fb81..916cbfa 100644 --- a/src/main/java/org/teacon/areacontrol/impl/AreaEntitySelectorChecker.java +++ b/src/main/java/org/teacon/areacontrol/impl/AreaEntitySelectorChecker.java @@ -57,17 +57,17 @@ private static boolean check0(CommandSourceStack sourceStack, Entity e, String selectFromChild, String selectFromParent, Supplier<@NotNull Boolean> selectFromChildFallBack, Supplier<@NotNull Boolean> selectFromParentFallBack) { - var area = AreaManager.INSTANCE.findBy(sourceStack.getLevel(), sourceStack.getPosition()); + var startArea = AreaManager.INSTANCE.findBy(sourceStack.getLevel(), sourceStack.getPosition()); // Get the area in which the target entity locates. // Do note that, EntitySelector can select entities from a different dimension, // so we must use the level from the target entity. final var targetArea = AreaManager.INSTANCE.findBy(e.level(), new Vec3(e.xo, e.yo, e.zo)); // If the entity is in the same area as the selector initiator, then it may be selected - if (area == targetArea) { + if (startArea == targetArea) { return true; } // Otherwise, we follow this procedure to determine. - var currentlyChecking = area; + var currentlyChecking = startArea; // 1. Walk up from the area hierarchy tree, checking if all the parent areas // allow "selecting entities from child area". // The walking stops at the area that is common ancestor to both the @@ -77,16 +77,18 @@ private static boolean check0(CommandSourceStack sourceStack, Entity e, // Otherwise, we'd have NPE. This is specifically the case for vanilla // /tp command. if (currentlyChecking != null) { - do { + while (!AreaMath.isEnclosing(currentlyChecking, targetArea)) { currentlyChecking = currentlyChecking.resolveParent(); var result = AreaProperties.getBoolOptional(currentlyChecking, selectFromChild); if (!result.orElseGet(selectFromChildFallBack)) { return false; } - } while (!AreaMath.isEnclosing(currentlyChecking, targetArea)); + } } // 2. If we are at the target area, then we are done, we can select this entity. // Else, we have to walk down along the hierarchy tree, to the target area. + // For performance reason, we walk down the hierarchy by "walking up" from the + // target area (which is the smallest) to the common ancestor we found above. if (currentlyChecking != targetArea) { var reverseChecking = targetArea; // 3. For each area that we encounter, we check if it allows "selecting entities diff --git a/src/test/java/org/teacon/areacontrol/test/impl/AreaEntitySelectorCheckerTest.java b/src/test/java/org/teacon/areacontrol/test/impl/AreaEntitySelectorCheckerTest.java index 107ce59..f0d36bd 100644 --- a/src/test/java/org/teacon/areacontrol/test/impl/AreaEntitySelectorCheckerTest.java +++ b/src/test/java/org/teacon/areacontrol/test/impl/AreaEntitySelectorCheckerTest.java @@ -70,6 +70,20 @@ public static void setup() { initAreaManager(); } + /* + * Area overview: + * + * - Area A + * - Child area B + * - Child area C + * - Child area D + * - Child area E + * - Child area F + * - Child area G + * - Child area H + * - Area I + * - Child area J + */ public static void initAreaManager() { Area a, b, c, d, e, f, g, h, i, j; var allAreas = new ArrayList(); @@ -104,6 +118,9 @@ public static void initAreaManager() { d.properties.put(AreaProperties.ALLOW_ENTITY_USE_SELECTOR_FROM_PARENT, true); d.properties.put(AreaProperties.ALLOW_CB_USE_SELECTOR_FROM_PARENT, true); + i.properties.put(AreaProperties.ALLOW_ENTITY_USE_SELECTOR_FROM_PARENT, false); + j.properties.put(AreaProperties.ALLOW_ENTITY_USE_SELECTOR_FROM_PARENT, true); + var areaRepo = new InMemoryAreaRepository(allAreas); try { AreaManager.INSTANCE.init(areaRepo); @@ -200,6 +217,29 @@ public void testSelectingByCommandBlockFromMultiLayerNestedAreas() { Assertions.assertTrue(AreaEntitySelectorChecker.check(commandSrc, this.mockEntity)); } + /** + * Test that a player, who is standing in an area A, can use entity selector to select entities inside area B, where + *
false
+ * true
+ *