diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index cef606aba..dc1862a3c 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -236,7 +236,7 @@ public abstract class MovementPulse extends Pulse { private boolean tryInteract() { Location ml = mover.getLocation(); - if (interactLocation == null) return false; + if (ml == null || interactLocation == null) return false; boolean atInteractLocation = ml.equals(interactLocation); if (destination instanceof Entity) { boolean canInteractFromCurrentPosition = canInteractWithEntityFromCurrentPosition((Entity) destination); @@ -282,7 +282,13 @@ public abstract class MovementPulse extends Pulse { } private boolean canInteractWithEntityFrom(Location source, Entity target) { + if (source == null || target == null) { + return false; + } Location dl = target.getLocation(); + if (dl == null) { + return false; + } if (source.getZ() != dl.getZ()) { return false; } @@ -354,7 +360,7 @@ public abstract class MovementPulse extends Pulse { if (mover instanceof NPC && mover.asNpc().isNeverWalks()) { return; } - if (destination == null || destination.getLocation() == null) { + if (mover.getLocation() == null || destination == null || destination.getLocation() == null) { return; } @@ -520,7 +526,13 @@ public abstract class MovementPulse extends Pulse { } private boolean overlapsEntityFootprint(Location source, Entity target) { + if (source == null || target == null) { + return false; + } Location targetLocation = target.getLocation(); + if (targetLocation == null) { + return false; + } return Pathfinder.isStandingIn(source.getX(), source.getY(), mover.size(), @@ -643,6 +655,9 @@ public abstract class MovementPulse extends Pulse { * @return {@code True} if so. */ private boolean isInsideEntity(Location l) { + if (l == null) { + return false; + } if (!(destination instanceof Entity)) { return false; } @@ -650,6 +665,9 @@ public abstract class MovementPulse extends Pulse { return false; } Location loc = destination.getLocation(); + if (loc == null) { + return false; + } int size = destination.size(); return Pathfinder.isStandingIn(l.getX(), l.getY(), mover.size(), mover.size(), loc.getX(), loc.getY(), size, size); } diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index ecf5fecc5..418f62933 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -378,6 +378,58 @@ class PathfinderTests { } } + @Test + fun entityMovementPulseShouldIgnoreMissingTargetLocation() { + TestUtils.getMockPlayer("missingTargetLocationGuard").use { p -> + val npc = NPC.create(0, NPC_TEST_LOC) + npc.init() + val originalNpcLocation = npc.location + var pulsed = false + try { + npc.location = null + val pulse = object : MovementPulse(p, npc) { + override fun pulse(): Boolean { + pulsed = true + return true + } + } + + Assertions.assertFalse(pulse.update()) + Assertions.assertFalse(pulsed) + } finally { + npc.location = originalNpcLocation + npc.clear() + } + } + } + + @Test + fun entityMovementPulseShouldIgnoreMissingMoverLocation() { + TestUtils.getMockPlayer("missingMoverLocationGuard").use { p -> + val npc = NPC.create(0, NPC_TEST_LOC) + npc.init() + val locationField = Node::class.java.getDeclaredField("location") + locationField.isAccessible = true + val originalPlayerLocation = p.location + var pulsed = false + try { + locationField.set(p, null) + val pulse = object : MovementPulse(p, npc) { + override fun pulse(): Boolean { + pulsed = true + return true + } + } + + Assertions.assertFalse(pulse.update()) + Assertions.assertFalse(pulsed) + } finally { + locationField.set(p, originalPlayerLocation) + npc.clear() + } + } + } + @Test fun runEnabledEntityMovementPulseShouldCatchWalkingNpcMovingDirectlyAway() { TestUtils.getMockPlayer("runNpcInteractionChaser").use { p ->