diff --git a/Server/src/main/core/game/node/entity/npc/NPC.java b/Server/src/main/core/game/node/entity/npc/NPC.java index 71071cf64..b80bfd187 100644 --- a/Server/src/main/core/game/node/entity/npc/NPC.java +++ b/Server/src/main/core/game/node/entity/npc/NPC.java @@ -528,6 +528,10 @@ public class NPC extends Entity { getWalkingQueue().reset(); getPulseManager().clear(); getUpdateMasks().reset(); + if (getAttribute("return-to-spawn", false)) { + this.location = getProperties().getSpawnLocation(); + removeAttribute("return-to-spawn"); + } Repository.removeRenderableNPC(this); if (getViewport().getRegion() instanceof DynamicRegion) { clear(); diff --git a/Server/src/test/kotlin/core/PathfinderTests.kt b/Server/src/test/kotlin/core/PathfinderTests.kt index aa5b1b0f1..993cb6ece 100644 --- a/Server/src/test/kotlin/core/PathfinderTests.kt +++ b/Server/src/test/kotlin/core/PathfinderTests.kt @@ -16,6 +16,7 @@ import core.game.node.entity.impl.PulseType import core.game.node.entity.npc.NPC import core.game.node.entity.player.Player import core.game.world.GameWorld +import core.game.world.map.Region import core.net.packet.PacketProcessor import core.plugin.ClassScanner import core.plugin.Plugin @@ -221,4 +222,39 @@ class PathfinderTests { Assertions.assertEquals(1.0, p.location.getDistance(npc.location)) } } + + @Test fun npcShouldReliablyReturnToSpawnLocationIfTooFar() { + //spawn a player into the area just to make sure it ticks... + TestUtils.getMockPlayer("areatest").use { p -> + val npc = NPC(1, Location.create(3240, 3226, 0)) + npc.isWalks = true + npc.isNeverWalks = false + npc.walkRadius = 5 + npc.init() + npc.properties.spawnLocation = ServerConstants.HOME_LOCATION + TestUtils.advanceTicks(5, false) + Assertions.assertEquals(true, npc.getAttribute("return-to-spawn", false)) + TestUtils.advanceTicks(50, false) + Assertions.assertEquals(true, npc.location.getDistance(ServerConstants.HOME_LOCATION) <= 9) + } + } + + @Test fun npcShouldReliablyReturnToSpawnEvenIfRegionUnloaded() { + //spawn a player into the area just to make sure it ticks... + TestUtils.getMockPlayer("areatest").use { p -> + val npc = NPC(1, Location.create(3240, 3226, 0)) + npc.isWalks = true + npc.isNeverWalks = false + npc.walkRadius = 5 + npc.init() + npc.properties.spawnLocation = ServerConstants.HOME_LOCATION + TestUtils.advanceTicks(3, false) + Assertions.assertEquals(true, npc.getAttribute("return-to-spawn", false)) + p.clear() + RegionManager.forId(npc.location.regionId).flagInactive(true) + TestUtils.advanceTicks(50, false) + Assertions.assertEquals(false, npc.getAttribute("return-to-spawn", false)) + Assertions.assertEquals(true, npc.location.getDistance(ServerConstants.HOME_LOCATION) <= 5) + } + } } \ No newline at end of file