diff --git a/src/main/java/com/botdetector/BotDetectorPlugin.java b/src/main/java/com/botdetector/BotDetectorPlugin.java index c41c245..fe14c81 100644 --- a/src/main/java/com/botdetector/BotDetectorPlugin.java +++ b/src/main/java/com/botdetector/BotDetectorPlugin.java @@ -61,8 +61,10 @@ import java.util.Collection; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; @@ -81,6 +83,7 @@ import net.runelite.api.MenuEntry; import net.runelite.api.MessageNode; import net.runelite.api.Player; +import net.runelite.api.WorldEntity; import net.runelite.api.WorldType; import net.runelite.api.WorldView; import net.runelite.api.coords.WorldPoint; @@ -661,10 +664,10 @@ private void onGameStateChanged(GameStateChanged event) && previousTwoGameStates.contains(GameState.LOGGED_IN) && previousTwoGameStates.contains(GameState.LOADING)) { - WorldView wv = client.getTopLevelWorldView(); - if (wv != null) + Set allPlayers = getAllPlayers(); + if (allPlayers != null) { - wv.players().forEach(this::processPlayer); + allPlayers.forEach(this::processPlayer); } } break; @@ -727,19 +730,20 @@ private void processPlayer(Player player) // IDK man I can't ever seem to be able to repro this... clientThread.invoke(() -> { - WorldView wv = client.getTopLevelWorldView(); + WorldView wv = player.getWorldView(); boolean instanced = wv != null && wv.isInstance(); + boolean isBoat = wv != null && wv.getId() != WorldView.TOPLEVEL && client != null && client.getTopLevelWorldView() != null; - WorldPoint wp = !instanced ? player.getWorldLocation() - : WorldPoint.fromLocalInstance(client, player.getLocalLocation()); - - if (wp.getRegionID() > MAX_ALLOWED_REGION_ID) + WorldPoint wp = player.getWorldLocation(); + if (isBoat) { - WorldView wv2 = client.getTopLevelWorldView(); - log.warn(String.format("Player sighting with invalid region ID. (name:'%s' x:%d y:%d z:%d r:%d s:%d)", - playerName, wp.getX(), wp.getY(), wp.getPlane(), wp.getRegionID(), - (instanced ? 1 : 0) + (wv2 != null && wv2.isInstance() ? 2 : 0))); // Sanity check - return; + // Appears to give us the center of the boat, good enough for now + WorldEntity we = client.getTopLevelWorldView().worldEntities().byIndex(wv.getId()); + wp = WorldPoint.fromLocalInstance(client, we.getLocalLocation()); + } + else if (instanced) + { + wp = WorldPoint.fromLocalInstance(client, player.getLocalLocation()); } // Get player's equipment item ids (botanicvelious/Equipment-Inspector) @@ -761,7 +765,9 @@ private void processPlayer(Player player) .regionID(wp.getRegionID()) .worldX(wp.getX()) .worldY(wp.getY()) - .plane(wp.getPlane()) + // If coordinate comes from a boat, add 64 to the plane (z) coordinate + // We'll handle it on the server later + .plane(wp.getPlane() + (isBoat ? 64 : 0)) .equipment(equipment) .equipmentGEValue(geValue) .timestamp(Instant.now()) @@ -1214,6 +1220,33 @@ private String getMenuOption(String playerName, String option) return prepend != null ? ColorUtil.prependColorTag(option, prepend) : option; } + private Set getAllPlayers() + { + WorldView top = client.getTopLevelWorldView(); + if (top == null) + { + return null; + } + + HashSet pSet = new HashSet<>(); + getAllPlayersRecurse(top, pSet); + + return pSet; + } + + private void getAllPlayersRecurse(WorldView wv, HashSet pSet) + { + if (wv == null) + { + return; + } + wv.players().stream().forEach(pSet::add); + for (WorldView sub : wv.worldViews()) + { + getAllPlayersRecurse(sub, pSet); + } + } + /** * Normalizes the given {@code playerName} by sanitizing the player name string, * removing any Jagex tags and replacing any {@code _} or {@code -} with spaces. @@ -1281,10 +1314,10 @@ else if (client.getGameState() != GameState.LOGGED_IN) } else { - WorldView wv = client.getTopLevelWorldView(); - if (wv != null) + Set allPlayers = getAllPlayers(); + if (allPlayers != null) { - wv.players().forEach(this::processPlayer); + allPlayers.forEach(this::processPlayer); sendChatStatusMessage("Player sightings refreshed.", true); } else