From daa0d84447dcf1df6a811abcdce11be96711c3ea Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Sat, 16 Jun 2018 11:31:00 -0700 Subject: [PATCH 1/4] Add IN_WILDERNESS Varbit --- runelite-api/src/main/java/net/runelite/api/Varbits.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/Varbits.java b/runelite-api/src/main/java/net/runelite/api/Varbits.java index 1115ad29f6..a9f1b92f8d 100644 --- a/runelite-api/src/main/java/net/runelite/api/Varbits.java +++ b/runelite-api/src/main/java/net/runelite/api/Varbits.java @@ -211,6 +211,12 @@ public enum Varbits */ IN_GAME_BA(3923), + /** + * 0 = Outside wilderness + * 1 = In wilderness + */ + IN_WILDERNESS(5963), + /** * Fishing Trawler * FISHING_TRAWLER_ACTIVITY Expected values: 0-255 From 2c4c7c566c7586c78a24eb778293a82cf4468d0a Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Mon, 18 Jun 2018 11:08:23 -0700 Subject: [PATCH 2/4] Add PVP and Deadman widget info --- .../java/net/runelite/api/widgets/WidgetID.java | 14 +++++++++++++- .../java/net/runelite/api/widgets/WidgetInfo.java | 13 ++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index 662ba2c1ce..ec42b12839 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -116,6 +116,7 @@ public class WidgetID public static final int FOSSIL_ISLAND_OXYGENBAR_ID = 609; public static final int MINIGAME_TAB_ID = 76; public static final int SPELLBOOK_GROUP_ID = 218; + public static final int PVP_GROUP_ID = 90; static class WorldMap { @@ -677,4 +678,15 @@ public class WidgetID { static final int ARCEUUS_HOME_TELEPORT = 145; } -} \ No newline at end of file + + static class Pvp + { + static final int PVP_WIDGET_CONTAINER = 50; + static final int SKULL_CONTAINER = 51; + static final int SKULL = 52; + static final int SAFE_ZONE = 53; + static final int ATTACK_RANGE = 55; + static final int WILDERNESS_LEVEL = 56; // this can also be the Deadman Mode "Protection" text + static final int DEADMAN_PROTECTION_TIME = 57; + } +} diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index dbcaec49c0..bc1c45d3e6 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -412,7 +412,18 @@ public enum WidgetInfo SPELL_LUMBRIDGE_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.StandardSpellBook.LUMBRIDGE_HOME_TELEPORT), SPELL_EDGEVILLE_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.AncientSpellBook.EDGEVILLE_HOME_TELEPORT), SPELL_LUNAR_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.LunarSpellBook.LUNAR_HOME_TELEPORT), - SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT); + SPELL_ARCEUUS_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.ArceuusSpellBook.ARCEUUS_HOME_TELEPORT), + + PVP_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.PVP_WIDGET_CONTAINER), + PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER), + PVP_SKULL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL), + PVP_WILDERNESS_LEVEL(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE), + + PVP_WORLD_SAFE_ZONE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SAFE_ZONE), + PVP_WORLD_ATTACK_RANGE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.ATTACK_RANGE), + + DEADMAN_PROTECTION_TEXT(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.WILDERNESS_LEVEL), + DEADMAN_PROTECTION_TIME(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.DEADMAN_PROTECTION_TIME); private final int groupId; private final int childId; From facf7d69c902fbb67aff6a59f06d4dc042f37d9c Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 20 Sep 2018 17:24:51 -0700 Subject: [PATCH 3/4] worldtype: Add PVP_WORLD_TYPES and isPvpWorld --- .../main/java/net/runelite/api/WorldType.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/WorldType.java b/runelite-api/src/main/java/net/runelite/api/WorldType.java index 88741753b3..81f2ae1d2d 100644 --- a/runelite-api/src/main/java/net/runelite/api/WorldType.java +++ b/runelite-api/src/main/java/net/runelite/api/WorldType.java @@ -24,6 +24,7 @@ */ package net.runelite.api; +import java.util.Collection; import java.util.EnumSet; /** @@ -75,6 +76,13 @@ public enum WorldType this.mask = mask; } + private static EnumSet PVP_WORLD_TYPES = EnumSet.of( + DEADMAN, + PVP, + PVP_HIGH_RISK, + SEASONAL_DEADMAN + ); + /** * Create enum set of world types from mask. * @@ -113,4 +121,16 @@ public enum WorldType return mask; } -} \ No newline at end of file + + /** + * Checks whether a world having a {@link Collection} of {@link WorldType}s is a PVP world. + * + * @param worldTypes A {@link Collection} of {@link WorldType}s describing the given world. + * @return True if the given worldtypes of the world are a PVP world, false otherwise. + * @see Client#getWorldType() + */ + public static boolean isPvpWorld(final Collection worldTypes) + { + return worldTypes.stream().anyMatch(PVP_WORLD_TYPES::contains); + } +} From 5ef3597486e8078798ae2a545572a0a4b65b1a28 Mon Sep 17 00:00:00 2001 From: Jordan Atwood Date: Thu, 20 Sep 2018 17:25:30 -0700 Subject: [PATCH 4/4] timers plugin: Reset Teleblock on entering safe zone The effects of the Tele Block spell expire on three possible conditions: 1. When a player leaves the wilderness on a non-PVP/DMM world 2. When a player enters a PVP/DMM world safe zone 3. When a player logs out Leaving the wilderness can be detected via Varbits changes, entering safe zones in PVP/DMM worlds can be detected via WidgetHiddenChanged events, and logging out is already detected via GameStateChanged events. With that said, addressing the first two cases is not a trvial effort as there are certain race conditions that must be handled. The WidgetHiddenChanged event triggers upon login to PVP worlds regardless of where you log in, and the PVP widgets all initially load in a state which would be reflective of being in a safe zone, and are later set to the proper state before the first display frame is rendered. Similarly, during world hops, GameStateChanged and VarbitChanged events trigger in a pattern which causes the client to think that a player is always outside the wilderness upon reaching a `LOGGED_IN` game state; that is, the following events occur on world hopping: 1. Game state changes to `HOPPING` 2. Varbits are all reset to default values. In the case of the wilderness varbit, it is set to 0--the value representing being outside the wilderness. 3. Game state changes to `LOGGED_IN` 4. Varbits are set based on player information. Only at this point is the IN_WILDERNESS varbit set to its proper value. To handle these race conditions, the event subscribers for game state change and widget hidden events only set a flag which is checked once per game tick to handle PVP safe zone (and wilderness varbit) checks. Fixes runelite/runelite#2384 --- .../client/plugins/timers/TimersPlugin.java | 97 +++++++++++++++---- 1 file changed, 79 insertions(+), 18 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java index a56186ca88..6156d382a6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TimersPlugin.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Seth + * Copyright (c) 2018, Jordan Atwood * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,6 +29,7 @@ import com.google.common.eventbus.Subscribe; import com.google.inject.Provides; import java.awt.image.BufferedImage; import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; import net.runelite.api.AnimationID; import net.runelite.api.ChatMessageType; @@ -48,13 +50,17 @@ import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; -import net.runelite.api.events.GameTick; import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.GameTick; import net.runelite.api.events.GraphicChanged; import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.events.NpcDespawned; import net.runelite.api.events.VarbitChanged; +import net.runelite.api.events.WidgetHiddenChanged; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import static net.runelite.api.widgets.WidgetInfo.PVP_WORLD_SAFE_ZONE; import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.game.SpriteManager; @@ -68,6 +74,7 @@ import net.runelite.client.ui.overlay.infobox.InfoBoxManager; description = "Show various timers in an infobox", tags = {"combat", "items", "magic", "potions", "prayer", "overlay", "abyssal", "sire"} ) +@Slf4j public class TimersPlugin extends Plugin { private static final String ANTIFIRE_DRINK_MESSAGE = "You drink some of your antifire potion."; @@ -101,9 +108,12 @@ public class TimersPlugin extends Plugin private int freezeTime = -1; // time frozen, in game ticks private int lastRaidVarb; + private int lastWildernessVarb; private WorldPoint lastPoint; private TeleportWidget lastTeleportClicked; private int lastAnimation; + private boolean loggedInRace; + private boolean widgetHiddenChangedOnPvpWorld; @Inject private ItemManager itemManager; @@ -134,6 +144,8 @@ public class TimersPlugin extends Plugin lastPoint = null; lastTeleportClicked = null; lastAnimation = -1; + loggedInRace = false; + widgetHiddenChangedOnPvpWorld = false; } @Subscribe @@ -146,6 +158,33 @@ public class TimersPlugin extends Plugin removeGameTimer(PRAYER_ENHANCE); lastRaidVarb = raidVarb; } + + int inWilderness = client.getVar(Varbits.IN_WILDERNESS); + + if (lastWildernessVarb != inWilderness + && client.getGameState() == GameState.LOGGED_IN + && !loggedInRace) + { + if (!WorldType.isPvpWorld(client.getWorldType()) + && inWilderness == 0) + { + log.debug("Left wilderness in non-PVP world, clearing Teleblock timer."); + removeTbTimers(); + } + + lastWildernessVarb = inWilderness; + } + } + + @Subscribe + public void onWidgetHiddenChanged(WidgetHiddenChanged event) + { + Widget widget = event.getWidget(); + if (WorldType.isPvpWorld(client.getWorldType()) + && WidgetInfo.TO_GROUP(widget.getId()) == WidgetInfo.PVP_CONTAINER.getGroupId()) + { + widgetHiddenChangedOnPvpWorld = true; + } } @Subscribe @@ -250,10 +289,7 @@ public class TimersPlugin extends Plugin if (!config.showTeleblock()) { - removeGameTimer(FULLTB); - removeGameTimer(HALFTB); - removeGameTimer(DMM_FULLTB); - removeGameTimer(DMM_HALFTB); + removeTbTimers(); } if (!config.showFreezes()) @@ -503,34 +539,51 @@ public class TimersPlugin extends Plugin @Subscribe public void onGameTick(GameTick event) { + loggedInRace = false; + Player player = client.getLocalPlayer(); WorldPoint currentWorldPoint = player.getWorldLocation(); - if (freezeTimer == null) + if (freezeTimer != null) + { + // assume movement means unfrozen + if (!currentWorldPoint.equals(lastPoint)) + { + removeGameTimer(freezeTimer.getTimer()); + freezeTimer = null; + } + } + + lastPoint = currentWorldPoint; + + if (!widgetHiddenChangedOnPvpWorld) { - lastPoint = currentWorldPoint; return; } - // assume movement means unfrozen - if (!currentWorldPoint.equals(lastPoint)) + widgetHiddenChangedOnPvpWorld = false; + + Widget widget = client.getWidget(PVP_WORLD_SAFE_ZONE); + if (widget != null + && !widget.isSelfHidden()) { - removeGameTimer(freezeTimer.getTimer()); - freezeTimer = null; - lastPoint = currentWorldPoint; + log.debug("Entered safe zone in PVP world, clearing Teleblock timer."); + removeTbTimers(); } } @Subscribe public void onGameStateChanged(GameStateChanged gameStateChanged) { - // Check for game state changes which removes a teleblock (Hopping or Login screen) - if (gameStateChanged.getGameState() == GameState.HOPPING || gameStateChanged.getGameState() == GameState.LOGIN_SCREEN) + switch (gameStateChanged.getGameState()) { - removeGameTimer(HALFTB); - removeGameTimer(DMM_HALFTB); - removeGameTimer(FULLTB); - removeGameTimer(DMM_FULLTB); + case HOPPING: + case LOGIN_SCREEN: + removeTbTimers(); + break; + case LOGGED_IN: + loggedInRace = true; + break; } } @@ -755,4 +808,12 @@ public class TimersPlugin extends Plugin { infoBoxManager.removeIf(t -> t instanceof TimerTimer && ((TimerTimer) t).getTimer() == timer); } + + private void removeTbTimers() + { + removeGameTimer(FULLTB); + removeGameTimer(HALFTB); + removeGameTimer(DMM_FULLTB); + removeGameTimer(DMM_HALFTB); + } }