From 6eed4611624efb0927baafe5d9299f8d6f227fa5 Mon Sep 17 00:00:00 2001 From: Ceikry Date: Thu, 25 May 2023 04:33:27 +0000 Subject: [PATCH] Added some bot debugging support via the "Request Assist" option on bots Found and fixed the issue causing bots to get stuck or only interact with one thing Added some additional safety checks in the script processor --- .../main/content/global/bots/Adventurer.kt | 2 +- .../global/handlers/player/RequestOption.kt | 5 ++- .../src/main/core/game/bots/AIRepository.kt | 16 ++++++++++ .../core/game/interaction/MovementPulse.java | 31 +++++++++++++++++-- .../core/game/interaction/ScriptProcessor.kt | 26 +++++++++------- 5 files changed, 63 insertions(+), 17 deletions(-) diff --git a/Server/src/main/content/global/bots/Adventurer.kt b/Server/src/main/content/global/bots/Adventurer.kt index d47e23145..543046192 100644 --- a/Server/src/main/content/global/bots/Adventurer.kt +++ b/Server/src/main/content/global/bots/Adventurer.kt @@ -77,7 +77,7 @@ class Adventurer(val style: CombatStyle): Script() { return "${bot.name} is an Adventurer bot at ${bot.location}! State: $state - City: $city" } - private var state = State.START + var state = State.START fun getRandomCity(): Location{ return cities.random() diff --git a/Server/src/main/content/global/handlers/player/RequestOption.kt b/Server/src/main/content/global/handlers/player/RequestOption.kt index aecf7515b..33707b358 100644 --- a/Server/src/main/content/global/handlers/player/RequestOption.kt +++ b/Server/src/main/content/global/handlers/player/RequestOption.kt @@ -7,6 +7,7 @@ import core.game.node.entity.player.link.request.RequestType import core.plugin.Initializable import core.game.interaction.IntType import core.game.interaction.InteractionListener +import core.game.bots.* /** * Represents the plugin used to handle the player option interacting. @@ -22,8 +23,10 @@ class RequestOption : InteractionListener { return@on true } on(_P_ASSIST.name, IntType.PLAYER) { player, node -> + if (node is AIPlayer) + AIRepository.sendBotInfo(player, node) player.requestManager.request((node as Player), RequestType.ASSIST) return@on true } } -} \ No newline at end of file +} diff --git a/Server/src/main/core/game/bots/AIRepository.kt b/Server/src/main/core/game/bots/AIRepository.kt index 113a565f7..83f5e4ae2 100644 --- a/Server/src/main/core/game/bots/AIRepository.kt +++ b/Server/src/main/core/game/bots/AIRepository.kt @@ -3,6 +3,7 @@ package core.game.bots import core.game.node.entity.player.Player import core.game.node.item.GroundItem import core.game.ge.GrandExchangeOffer +import content.global.bots.* /** * A repository for bots to make use of that can contain any info that might be useful to them. @@ -49,5 +50,20 @@ class AIRepository { AIPlayer.deregister((it.botScript.bot as AIPlayer).uid) } } + + @JvmStatic fun sendBotInfo (player: Player, bot: AIPlayer) { + val pulse = PulseRepository[bot.username.lowercase()] ?: return + bot.setAttribute("tracked", true) + player.debug("[Bot: ${bot.username}][${pulse.botScript::class.simpleName}]=================") + player.debug("PM Pulse Running? ${if(bot.pulseManager.hasPulseRunning()) bot.pulseManager.getCurrent()::class.java.name else "No"}") + player.debug("Interaction Running? ${bot.scripts.getActiveScript() != null} ${bot.scripts.getActiveScript()?.let { " : " + it.execution!!::class.java.name } ?: ""}") + player.debug("Botscript Running? ${pulse.botScript.running}") + player.debug("Random Delay? ${pulse.randomDelay}") + player.debug("Delayed? ${bot.scripts.delay}") + if (pulse.botScript is Adventurer) { + player.debug("State: ${pulse.botScript.state.name}") + } + player.debug("==========================================") + } } } diff --git a/Server/src/main/core/game/interaction/MovementPulse.java b/Server/src/main/core/game/interaction/MovementPulse.java index 11f727dd9..67caf8676 100644 --- a/Server/src/main/core/game/interaction/MovementPulse.java +++ b/Server/src/main/core/game/interaction/MovementPulse.java @@ -17,6 +17,10 @@ import core.net.packet.out.ClearMinimapFlag; import kotlin.jvm.functions.Function2; import core.tools.SystemLogger; +import static core.api.ContentAPIKt.getWorldTicks; +import static core.api.ContentAPIKt.log; +import core.tools.Log; + import java.util.Deque; /** @@ -80,6 +84,9 @@ public abstract class MovementPulse extends Pulse { private Location previousLoc; + private Location previousMoverLoc; + private int previousMoveTime; + /** * Constructs a new {@code MovementPulse} {@code Object}. * @@ -182,7 +189,8 @@ public abstract class MovementPulse extends Pulse { public boolean update() { mover.face(null); if (mover == null || destination == null || mover.getViewport().getRegion() == null) { - return false; + stop(); + return true; } if (hasInactiveNode() || !mover.getViewport().getRegion().isActive()) { @@ -194,6 +202,23 @@ public abstract class MovementPulse extends Pulse { } findPath(); Location ml = mover.getLocation(); + + if (previousMoverLoc == null || !previousMoverLoc.equals(ml)) { + previousMoverLoc = Location.create(ml); + previousMoveTime = getWorldTicks(); + } + else if (getWorldTicks() - previousMoveTime >= 25) { + if (mover instanceof Player) { + ((Player) mover).getPacketDispatch().sendMessage("I can't reach that."); + PacketRepository.send(ClearMinimapFlag.class, new PlayerContext((Player) mover)); + } + log(this.getClass(), Log.FINE, mover.getName() + " was trying to move to " + interactLocation + " from " + ml + " but hasn't changed location in 25 ticks. More info follows:"); + log(this.getClass(), Log.FINE, " -> Locked? " + mover.getLocks().isMovementLocked()); + log(this.getClass(), Log.FINE, " -> Has path? " + mover.getWalkingQueue().hasPath()); + stop(); + return true; + } + // Allow being within 1 square of moving entities to interact with them. int radius = destination instanceof Entity && ((Entity)destination).getWalkingQueue().hasPath() ? 1 : 0; if (interactLocation == null) @@ -265,7 +290,7 @@ public abstract class MovementPulse extends Pulse { else if (inside) { loc = findBorderLocation(); } - } else if (loc == previousLoc) return; + } else if (loc == previousLoc && interactLocation != null && mover.getWalkingQueue().hasPath()) return; if (destination == null) { return; @@ -332,8 +357,8 @@ public abstract class MovementPulse extends Pulse { mover.face(null); } } + previousLoc = loc; } - previousLoc = loc; } last = destination.getLocation(); } diff --git a/Server/src/main/core/game/interaction/ScriptProcessor.kt b/Server/src/main/core/game/interaction/ScriptProcessor.kt index dd8e4792c..5ccd0e446 100644 --- a/Server/src/main/core/game/interaction/ScriptProcessor.kt +++ b/Server/src/main/core/game/interaction/ScriptProcessor.kt @@ -10,6 +10,7 @@ import core.game.node.scenery.Scenery import core.game.world.GameWorld import core.game.world.map.Location import core.game.world.map.path.Pathfinder +import core.game.bots.AIPlayer import core.tools.Log import core.tools.SystemLogger import java.lang.Integer.max @@ -39,18 +40,18 @@ class ScriptProcessor(val entity: Entity) { if (entity.delayed()) return var canProcess = !entity.delayed() - if (entity is Player) + if (entity is Player && entity !is AIPlayer) canProcess = canProcess && !entity.hasModalOpen() if (entity !is Player) return if (!entity.delayed() && canProcess && interactTarget != null) { if (opScript != null && inOperableDistance()) { - face(entity, interactTarget?.getFaceLocation(entity.location) ?: return) - processInteractScript(opScript ?: return) + face(entity, interactTarget?.getFaceLocation(entity.location) ?: return reset()) + processInteractScript(opScript ?: return reset()) } - else if (apScript != null && inApproachDistance(apScript ?: return)) { - face(entity, interactTarget?.getFaceLocation(entity.location) ?: return) - processInteractScript(apScript ?: return) + else if (apScript != null && inApproachDistance(apScript ?: return reset())) { + face(entity, interactTarget?.getFaceLocation(entity.location) ?: return reset()) + processInteractScript(apScript ?: return reset()) } else if (apScript == null && opScript == null && inOperableDistance()) { sendMessage(entity, "Nothing interesting happens.") @@ -62,18 +63,18 @@ class ScriptProcessor(val entity: Entity) { if (didMove) entity.clocks[Clocks.MOVEMENT] = GameWorld.ticks + if (entity.walkingQueue.isRunning) 0 else 1 var canProcess = !entity.delayed() - if (entity is Player) + if (entity is Player && entity !is AIPlayer) canProcess = canProcess && !entity.interfaceManager.isOpened && !entity.interfaceManager.hasChatbox() if (entity !is Player) return if (!entity.delayed() && canProcess && interactTarget != null && !interacted) { if (opScript != null && inOperableDistance()) { - face(entity, interactTarget?.centerLocation ?: return) - processInteractScript(opScript ?: return) + face(entity, interactTarget?.centerLocation ?: return reset()) + processInteractScript(opScript ?: return reset()) } - else if (apScript != null && inApproachDistance(apScript ?: return)) { - face(entity, interactTarget?.centerLocation ?: return) - processInteractScript(apScript ?: return) + else if (apScript != null && inApproachDistance(apScript ?: return reset())) { + face(entity, interactTarget?.centerLocation ?: return reset()) + processInteractScript(apScript ?: return reset()) } else if (apScript == null && opScript == null && inOperableDistance()) { sendMessage(entity, "Nothing interesting happens.") @@ -246,6 +247,7 @@ class ScriptProcessor(val entity: Entity) { fun reset() { apScript = null opScript = null + currentScript = null apRangeCalled = false interacted = false apRange = 10