diff --git a/Server/src/main/core/game/world/map/path/Pathfinder.java b/Server/src/main/core/game/world/map/path/Pathfinder.java index 50dca754f..633f47073 100644 --- a/Server/src/main/core/game/world/map/path/Pathfinder.java +++ b/Server/src/main/core/game/world/map/path/Pathfinder.java @@ -121,13 +121,13 @@ public abstract class Pathfinder { */ public static Path find(Location start, int moverSize, Node destination, boolean near, Pathfinder finder, ClipMaskSupplier clipMaskSupplier) { if (destination instanceof Scenery) { - Scenery object = (Scenery) destination; + Scenery object = getRouteScenery((Scenery) destination); int type = object.getType(); int rotation = object.getRotation(); if (type == 10 || type == 11 || type == 22) { - return finder.find(start, moverSize, destination.getLocation(), object.getDefinition().sizeX, object.getDefinition().sizeY, rotation, type, object.getDefinition().getWalkingFlag(), near, clipMaskSupplier); + return finder.find(start, moverSize, object.getLocation(), object.getDefinition().sizeX, object.getDefinition().sizeY, rotation, type, object.getDefinition().getWalkingFlag(), near, clipMaskSupplier); } - return finder.find(start, moverSize, destination.getLocation(), 0, 0, rotation, type, 0, near, clipMaskSupplier); + return finder.find(start, moverSize, object.getLocation(), 0, 0, rotation, type, 0, near, clipMaskSupplier); } int size = 0; if (destination instanceof Entity) { @@ -138,6 +138,21 @@ public abstract class Pathfinder { return finder.find(start, moverSize, destination.getLocation(), size, size, 0, -1, 0, near, clipMaskSupplier); } + private static Scenery getRouteScenery(Scenery object) { + Scenery wrapper = object.getWrapper(); + if (wrapper == object) { + return object; + } + if (getFootprintArea(wrapper) <= getFootprintArea(object)) { + return object; + } + return wrapper; + } + + private static int getFootprintArea(Scenery object) { + return object.getDefinition().sizeX * object.getDefinition().sizeY; + } + /** * Checks if interaction with decoration is possible. * @param curX The current x-coordinate in viewport. diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index 20fa3c249..6c4d147ca 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -172,6 +172,26 @@ class PathfinderTests { } } + @Test fun pathfinderShouldUseWrapperFootprintWhenSceneryChildIsSmallerThanWrapper() { + TestUtils.getMockPlayer("taverleyPatchChildPath").use { p -> + val wrapper = RegionManager.getObject(0, 2935, 3437, 8388) + ?: throw AssertionError("Expected Taverley tree patch wrapper.") + val child = wrapper.getChild(p) + val start = Location.create(2936, 3440, 0) + + Assertions.assertEquals(8395, child.id) + Assertions.assertTrue(wrapper.definition.sizeX * wrapper.definition.sizeY > child.definition.sizeX * child.definition.sizeY) + + val path = Pathfinder.find(start, child) + val last = path.points.lastOrNull() ?: throw AssertionError("Expected a path point.") + val approach = Location.create(last.x, last.y, start.z) + + Assertions.assertTrue(path.isSuccessful) + Assertions.assertFalse(path.isMoveNear) + Assertions.assertEquals(start, approach) + } + } + @Test fun entityMovementPulseShouldTriggerWhenDestinationOverrideIsAlreadyReached() { TestUtils.getMockPlayer("bankerOverrideApproach").use { p -> val npc = NPC.create(0, NPC_TEST_LOC)