From 5c8ed9f11ab4673f13b0cd7af3676313d41f4125 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 10 Nov 2021 11:53:33 -0800 Subject: [PATCH 01/14] ground items: Fix despawn timer in clan hall (#14358) --- .../client/plugins/grounditems/GroundItemsOverlay.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index 9fb512c688..8fb08840af 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -78,6 +78,7 @@ public class GroundItemsOverlay extends Overlay private static final Duration DESPAWN_TIME_DROP = Duration.ofMinutes(3); private static final Duration DESPAWN_TIME_TABLE = Duration.ofMinutes(10); private static final int KRAKEN_REGION = 9116; + private static final int CLAN_HALL_REGION = 6997; private static final int KBD_NMZ_REGION = 9033; private static final int ZILYANA_REGION = 11602; private static final int GRAARDOR_REGION = 11347; @@ -456,7 +457,8 @@ public class GroundItemsOverlay extends Overlay } else if (playerRegionID == ZILYANA_REGION || playerRegionID == GRAARDOR_REGION || playerRegionID == KRIL_TSUTSAROTH_REGION || playerRegionID == KREEARRA_REGION || - playerRegionID == NIGHTMARE_REGION || playerRegionID == TEMPOROSS_REGION) + playerRegionID == NIGHTMARE_REGION || playerRegionID == TEMPOROSS_REGION || + playerRegionID == CLAN_HALL_REGION) { // GWD, Nightmare, and Tempoross instances use the normal despawn timers despawnTime = spawnTime.plus(groundItem.getLootType() == LootType.DROPPED From f71397f3f1608512eab04cf46753edc8985e98b2 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 10 Nov 2021 15:50:04 -0500 Subject: [PATCH 02/14] banktags: remove extra space in chatbox prompt --- .../net/runelite/client/plugins/banktags/tabs/TabInterface.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java index 7d8736a41e..0716ef747c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java @@ -316,7 +316,7 @@ public class TabInterface return; } - chatboxPanelManager.openTextInput((inventory ? "Inventory " : "Equipment ") + " tags:") + chatboxPanelManager.openTextInput((inventory ? "Inventory" : "Equipment") + " tags:") .addCharValidator(FILTERED_CHARS) .onDone((Consumer) (newTags) -> clientThread.invoke(() -> From c8ec004b7af874ab670b6494b9ba61a37db77502 Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 10 Nov 2021 15:50:27 -0500 Subject: [PATCH 03/14] banktags: improve bank scrollbar updates With tag tab tab or "Remove tab separators", the scrollbar height needs to be adjusted to account for either many tag tabs (which requires scrolling to see) or the hiding of the tab separators. This is because we artifically filter the bank results without keeping the bank in searching mode, causing the vanilla code which usually computes the scroll height to be incorrect. The existing code does this by manually invoking [proc,update_scrollbar] later with the recomputed scroll height. Now that invokeLater runs next tick and not next frame, this leaves several frames with the scrollbar the incorrect size. The desired scroll height is passed to [proc,bankmain_finishbuilding] in argument int12, so instead we recompute the scroll height and overwrite the script argument prior to execution. --- .../plugins/banktags/BankTagsPlugin.java | 59 +++++++++---------- .../src/main/scripts/BankSearchFilter.rs2asm | 2 +- .../src/main/scripts/BankSearchLayout.rs2asm | 4 +- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java index 052270570e..c4158abd6a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/BankTagsPlugin.java @@ -477,6 +477,32 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener Widget bankTitle = client.getWidget(WidgetInfo.BANK_TITLE_BAR); bankTitle.setText("Tag tab " + activeTab.getTag() + ""); } + + // Recompute scroll size. Only required for tag tab tab and with remove separators, to remove the + // space that the separators took. + if (tabInterface.isTagTabActive() || (tabInterface.isActive() && config.removeSeparators())) + { + Widget itemContainer = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER); + Widget[] children = itemContainer.getChildren(); + int items = 0; + for (Widget child : children) + { + if (child != null && child.getItemId() != -1 && !child.isHidden()) + { + ++items; + } + } + + // New scroll height for if_setscrollsize + final int adjustedScrollHeight = (Math.max(0, items - 1) / ITEMS_PER_ROW) * ITEM_VERTICAL_SPACING + + ITEM_VERTICAL_SPACING + ITEM_CONTAINER_BOTTOM_PADDING; + + // This is prior to bankmain_finishbuilding running, so the arguments are still on the stack. Overwrite + // argument int12 (7 from the end) which is the height passed to if_setscrollsize + final int[] intStack = client.getIntStack(); + final int intStackSize = client.getIntStackSize(); + intStack[intStackSize - 7] = adjustedScrollHeight; + } } else if (scriptId == ScriptID.BANKMAIN_SEARCH_TOGGLE) { @@ -510,15 +536,6 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener return; } - if (tabInterface.isTagTabActive()) - { - int numTabs = (int) Arrays.stream(itemContainer.getDynamicChildren()) - .filter(child -> child.getItemId() != -1 && !child.isHidden()) - .count(); - updateBankContainerScrollHeight(numTabs); - return; - } - if (!tabInterface.isActive() || !config.removeSeparators()) { return; @@ -540,14 +557,9 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener int adjYOffset = (items / ITEMS_PER_ROW) * ITEM_VERTICAL_SPACING; int adjXOffset = (items % ITEMS_PER_ROW) * ITEM_HORIZONTAL_SPACING + ITEM_ROW_START; - if (child.getOriginalY() != adjYOffset) + if (child.getOriginalY() != adjYOffset || child.getOriginalX() != adjXOffset) { child.setOriginalY(adjYOffset); - child.revalidate(); - } - - if (child.getOriginalX() != adjXOffset) - { child.setOriginalX(adjXOffset); child.revalidate(); } @@ -562,23 +574,6 @@ public class BankTagsPlugin extends Plugin implements MouseWheelListener child.setHidden(true); } } - - updateBankContainerScrollHeight(items); - } - - private void updateBankContainerScrollHeight(int items) - { - Widget bankItemContainer = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER); - int itemContainerHeight = bankItemContainer.getHeight(); - final int adjustedScrollHeight = (Math.max(0, items - 1) / ITEMS_PER_ROW) * ITEM_VERTICAL_SPACING + ITEM_VERTICAL_SPACING + ITEM_CONTAINER_BOTTOM_PADDING; - bankItemContainer.setScrollHeight(Math.max(adjustedScrollHeight, itemContainerHeight)); - - final int itemContainerScroll = bankItemContainer.getScrollY(); - clientThread.invokeLater(() -> - client.runScript(ScriptID.UPDATE_SCROLLBAR, - WidgetInfo.BANK_SCROLLBAR.getId(), - WidgetInfo.BANK_ITEM_CONTAINER.getId(), - itemContainerScroll)); } @Subscribe diff --git a/runelite-client/src/main/scripts/BankSearchFilter.rs2asm b/runelite-client/src/main/scripts/BankSearchFilter.rs2asm index 0555737bdb..0c809b35e3 100644 --- a/runelite-client/src/main/scripts/BankSearchFilter.rs2asm +++ b/runelite-client/src/main/scripts/BankSearchFilter.rs2asm @@ -1,4 +1,4 @@ -.id 279 +.id 279 ; [proc,bankmain_filteritem] .int_stack_count 1 .string_stack_count 0 .int_var_count 2 ; +1 for storage of search filter result diff --git a/runelite-client/src/main/scripts/BankSearchLayout.rs2asm b/runelite-client/src/main/scripts/BankSearchLayout.rs2asm index f67c6a9bfe..4550aba6d1 100644 --- a/runelite-client/src/main/scripts/BankSearchLayout.rs2asm +++ b/runelite-client/src/main/scripts/BankSearchLayout.rs2asm @@ -1,4 +1,4 @@ -.id 277 +.id 277 ; [proc,bankmain_build] .int_stack_count 17 .string_stack_count 0 .int_var_count 36 @@ -842,7 +842,7 @@ LABEL729: iload 14 iload 15 iload 16 - invoke 505 + invoke 505 ; [proc,bankmain_finishbuilding] return LABEL750: invoke 514 From 70d916af520a13b82bd5c10ce88e906f2707d95d Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 10 Nov 2021 17:37:56 -0500 Subject: [PATCH 04/14] banktags: remove setBankScroll event This hasn't worked in awhile since it was assining the scroll value to the wrong variable. Now we are computing the scroll in onScriptPreFixed for [proc,bankmain_finishbuilding], so it is no longer necessary here. --- .../client/plugins/banktags/tabs/TabInterface.java | 7 ++----- runelite-client/src/main/scripts/BankSearchLayout.rs2asm | 8 +++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java index 0716ef747c..04c41c9d1b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/banktags/tabs/TabInterface.java @@ -573,7 +573,7 @@ public class TabInterface switch (eventName) { - case "setBankScroll": + case "skipBankLayout": if (!isTabMenuActive()) { setTabMenuVisible(false); @@ -582,11 +582,8 @@ public class TabInterface setTabMenuVisible(true); - // scroll height - intStack[intStackSize - 3] = (((tabManager.getTabs().size() - 1) / BANK_ITEMS_PER_ROW) + 1) * (BANK_ITEM_HEIGHT + BANK_ITEM_Y_PADDING); - // skip normal bank layout - intStack[intStackSize - 2] = 1; + intStack[intStackSize - 1] = 1; break; case "beforeBankLayout": setTabMenuVisible(false); diff --git a/runelite-client/src/main/scripts/BankSearchLayout.rs2asm b/runelite-client/src/main/scripts/BankSearchLayout.rs2asm index 4550aba6d1..ea13a99a47 100644 --- a/runelite-client/src/main/scripts/BankSearchLayout.rs2asm +++ b/runelite-client/src/main/scripts/BankSearchLayout.rs2asm @@ -7,8 +7,8 @@ ; Fired before the bank starts its layout ; Used by the TabInterface to hide fake bank items for tag tabs ; -; callback "setBankScroll" -; Fired before bank is calculated +; callback "skipBankLayout" +; Fired before bank is built ; Used by the TabInterface to show fake bank items for tag tabs sconst "beforeBankLayout" runelite_callback @@ -403,13 +403,11 @@ LABEL348: sub istore 30 LABEL352: - iconst 0 ; Scroll height variable iconst 0 ; Compare variable iconst 0 ; - sconst "setBankScroll" ; Show fake bank items for tag tabs + sconst "skipBankLayout" ; Show fake bank items for tag tabs runelite_callback ; If tag tab menu search isn't active if_icmpeq CONTINUE_SEARCH ; continue to normal bank search - istore 27 ; Load scroll height into variable jump GetTabRange ; Skip normal bank layout CONTINUE_SEARCH: iload 31 From 685ec4524e3e1509c73cbc8b750279106442dbfe Mon Sep 17 00:00:00 2001 From: andmcadams Date: Thu, 11 Nov 2021 02:20:25 -0500 Subject: [PATCH 05/14] crowdsourcing: Add varbit crowdsourcing (#13212) --- .../crowdsourcing/CrowdsourcingPlugin.java | 8 + .../varbits/CrowdsourcingVarbits.java | 190 ++++++++++++++++++ .../crowdsourcing/varbits/VarData.java | 42 ++++ 3 files changed, 240 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java index 84fa9bb01f..20f04726e2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java @@ -35,6 +35,7 @@ import net.runelite.client.plugins.crowdsourcing.dialogue.CrowdsourcingDialogue; import net.runelite.client.plugins.crowdsourcing.movement.CrowdsourcingMovement; import net.runelite.client.plugins.crowdsourcing.music.CrowdsourcingMusic; import net.runelite.client.plugins.crowdsourcing.thieving.CrowdsourcingThieving; +import net.runelite.client.plugins.crowdsourcing.varbits.CrowdsourcingVarbits; import net.runelite.client.plugins.crowdsourcing.woodcutting.CrowdsourcingWoodcutting; import net.runelite.client.plugins.crowdsourcing.zmi.CrowdsourcingZMI; import net.runelite.client.task.Schedule; @@ -69,6 +70,9 @@ public class CrowdsourcingPlugin extends Plugin @Inject private CrowdsourcingThieving thieving; + @Inject + private CrowdsourcingVarbits varbits; + @Inject private CrowdsourcingWoodcutting woodcutting; @@ -83,8 +87,10 @@ public class CrowdsourcingPlugin extends Plugin eventBus.register(movement); eventBus.register(music); eventBus.register(thieving); + eventBus.register(varbits); eventBus.register(woodcutting); eventBus.register(zmi); + varbits.startUp(); } @Override @@ -95,8 +101,10 @@ public class CrowdsourcingPlugin extends Plugin eventBus.unregister(movement); eventBus.unregister(music); eventBus.unregister(thieving); + eventBus.unregister(varbits); eventBus.unregister(woodcutting); eventBus.unregister(zmi); + varbits.shutDown(); } @Schedule( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java new file mode 100644 index 0000000000..aad4f46685 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2021 andmcadams + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.crowdsourcing.varbits; + +import com.google.common.collect.ImmutableSet; +import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.api.IndexDataBase; +import net.runelite.api.VarbitComposition; +import net.runelite.api.coords.LocalPoint; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.VarbitChanged; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.eventbus.Subscribe; + +@Slf4j +public class CrowdsourcingVarbits +{ + + @Inject + private Client client; + + @Inject + private CrowdsourcingManager crowdsourcingManager; + + @Inject + private ClientThread clientThread; + + private static final int VARBITS_ARCHIVE_ID = 14; + private static final int VARBIT = 0; + private static final int VARPLAYER = 1; + + private int[] oldVarps = null; + private int[] oldVarps2 = null; + private Multimap varbits; + + private int initializingTick = 0; + + /* Blacklist certain common varbs that give us little useful data. + * 357 - Equipped weapon type + * 5983 - Dialogue option appear/disappear + */ + private static final ImmutableSet BLACKLIST = ImmutableSet.of(357, 5983); + + public void startUp() + { + + varbits = HashMultimap.create(); + + if (oldVarps == null) + { + oldVarps = new int[client.getVarps().length]; + oldVarps2 = new int[client.getVarps().length]; + } + + // Set oldVarps to be the current varps + System.arraycopy(client.getVarps(), 0, oldVarps, 0, oldVarps.length); + System.arraycopy(client.getVarps(), 0, oldVarps2, 0, oldVarps2.length); + + // For all varbits, add their ids to the multimap with the varp index as their key + clientThread.invoke(() -> + { + if (client.getIndexConfig() == null) + { + return false; + } + if (client.getGameState() == GameState.STARTING || client.getGameState() == GameState.UNKNOWN) + { + return false; + } + IndexDataBase indexVarbits = client.getIndexConfig(); + final int[] varbitIds = indexVarbits.getFileIds(VARBITS_ARCHIVE_ID); + for (int id : varbitIds) + { + VarbitComposition varbit = client.getVarbit(id); + if (varbit != null) + { + varbits.put(varbit.getIndex(), id); + } + } + return true; + }); + } + + public void shutDown() + { + varbits = null; + oldVarps = null; + oldVarps2 = null; + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState().equals(GameState.HOPPING) + || gameStateChanged.getGameState().equals(GameState.LOGGING_IN)) + { + initializingTick = client.getTickCount(); + shutDown(); + startUp(); + } + } + + private void pushVarChange(int varType, int varIndex, int oldValue, int newValue, int tick) + { + /* Queues up varbit or varplayer changes to be pushed out to the crowdsourcing manager during the next client + * tick. + */ + clientThread.invokeLater(() -> + { + LocalPoint local = LocalPoint.fromWorld(client, client.getLocalPlayer().getWorldLocation()); + WorldPoint location = WorldPoint.fromLocalInstance(client, local); + boolean isInInstance = client.isInInstancedRegion(); + + log.debug(String.format("Storing VarData (tick %d): %d, %d, %d->%d", tick, varType, varIndex, oldValue, newValue)); + VarData varbitData = new VarData(varType, varIndex, oldValue, newValue, tick, isInInstance, location); + crowdsourcingManager.storeEvent(varbitData); + }); + } + + @Subscribe + public void onVarbitChanged(VarbitChanged varbitChanged) + { + int tick = client.getTickCount(); + + // Whenever a varbit is changed, record it and pass the info off to be submitted. + int index = varbitChanged.getIndex(); + int[] varps = client.getVarps(); + + for (int i : varbits.get(index)) + { + int oldValue = client.getVarbitValue(oldVarps, i); + int newValue = client.getVarbitValue(varps, i); + + if (oldValue != newValue) + { + // Set oldVarps2 so it doesn't pick up varbit changes + client.setVarbitValue(oldVarps2, i, newValue); + + // If the varbit is being changed on an initializing tick (when logging in), don't push out a change + if (tick != initializingTick && !BLACKLIST.contains(i)) + { + pushVarChange(VARBIT, i, oldValue, newValue, tick); + } + } + } + + int oldValue = oldVarps2[index]; + int newValue = varps[index]; + + // Push out varp changes + if (oldValue != newValue && tick != initializingTick) + { + pushVarChange(VARPLAYER, index, oldValue, newValue, tick); + } + + oldVarps[index] = varps[index]; + oldVarps2[index] = varps[index]; + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java new file mode 100644 index 0000000000..2799f2eb81 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 andmcadams + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.crowdsourcing.varbits; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.runelite.api.coords.WorldPoint; + +@Data +@AllArgsConstructor +public class VarData +{ + private final int varType; + private final int varbitNumber; + private final int oldValue; + private final int newValue; + private final int tick; + private final boolean isInInstance; + private final WorldPoint location; +} From 020d26ce7fae174b1249f267c20ad2a34698da12 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 11 Nov 2021 10:00:59 -0500 Subject: [PATCH 06/14] Revert "crowdsourcing: Add varbit crowdsourcing (#13212)" This reverts commit 685ec4524e3e1509c73cbc8b750279106442dbfe. --- .../crowdsourcing/CrowdsourcingPlugin.java | 8 - .../varbits/CrowdsourcingVarbits.java | 190 ------------------ .../crowdsourcing/varbits/VarData.java | 42 ---- 3 files changed, 240 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java index 20f04726e2..84fa9bb01f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingPlugin.java @@ -35,7 +35,6 @@ import net.runelite.client.plugins.crowdsourcing.dialogue.CrowdsourcingDialogue; import net.runelite.client.plugins.crowdsourcing.movement.CrowdsourcingMovement; import net.runelite.client.plugins.crowdsourcing.music.CrowdsourcingMusic; import net.runelite.client.plugins.crowdsourcing.thieving.CrowdsourcingThieving; -import net.runelite.client.plugins.crowdsourcing.varbits.CrowdsourcingVarbits; import net.runelite.client.plugins.crowdsourcing.woodcutting.CrowdsourcingWoodcutting; import net.runelite.client.plugins.crowdsourcing.zmi.CrowdsourcingZMI; import net.runelite.client.task.Schedule; @@ -70,9 +69,6 @@ public class CrowdsourcingPlugin extends Plugin @Inject private CrowdsourcingThieving thieving; - @Inject - private CrowdsourcingVarbits varbits; - @Inject private CrowdsourcingWoodcutting woodcutting; @@ -87,10 +83,8 @@ public class CrowdsourcingPlugin extends Plugin eventBus.register(movement); eventBus.register(music); eventBus.register(thieving); - eventBus.register(varbits); eventBus.register(woodcutting); eventBus.register(zmi); - varbits.startUp(); } @Override @@ -101,10 +95,8 @@ public class CrowdsourcingPlugin extends Plugin eventBus.unregister(movement); eventBus.unregister(music); eventBus.unregister(thieving); - eventBus.unregister(varbits); eventBus.unregister(woodcutting); eventBus.unregister(zmi); - varbits.shutDown(); } @Schedule( diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java deleted file mode 100644 index aad4f46685..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/CrowdsourcingVarbits.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright (c) 2018 Abex - * Copyright (c) 2021 andmcadams - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.crowdsourcing.varbits; - -import com.google.common.collect.ImmutableSet; -import net.runelite.client.plugins.crowdsourcing.CrowdsourcingManager; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.Multimap; -import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.IndexDataBase; -import net.runelite.api.VarbitComposition; -import net.runelite.api.coords.LocalPoint; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.VarbitChanged; -import net.runelite.client.callback.ClientThread; -import net.runelite.client.eventbus.Subscribe; - -@Slf4j -public class CrowdsourcingVarbits -{ - - @Inject - private Client client; - - @Inject - private CrowdsourcingManager crowdsourcingManager; - - @Inject - private ClientThread clientThread; - - private static final int VARBITS_ARCHIVE_ID = 14; - private static final int VARBIT = 0; - private static final int VARPLAYER = 1; - - private int[] oldVarps = null; - private int[] oldVarps2 = null; - private Multimap varbits; - - private int initializingTick = 0; - - /* Blacklist certain common varbs that give us little useful data. - * 357 - Equipped weapon type - * 5983 - Dialogue option appear/disappear - */ - private static final ImmutableSet BLACKLIST = ImmutableSet.of(357, 5983); - - public void startUp() - { - - varbits = HashMultimap.create(); - - if (oldVarps == null) - { - oldVarps = new int[client.getVarps().length]; - oldVarps2 = new int[client.getVarps().length]; - } - - // Set oldVarps to be the current varps - System.arraycopy(client.getVarps(), 0, oldVarps, 0, oldVarps.length); - System.arraycopy(client.getVarps(), 0, oldVarps2, 0, oldVarps2.length); - - // For all varbits, add their ids to the multimap with the varp index as their key - clientThread.invoke(() -> - { - if (client.getIndexConfig() == null) - { - return false; - } - if (client.getGameState() == GameState.STARTING || client.getGameState() == GameState.UNKNOWN) - { - return false; - } - IndexDataBase indexVarbits = client.getIndexConfig(); - final int[] varbitIds = indexVarbits.getFileIds(VARBITS_ARCHIVE_ID); - for (int id : varbitIds) - { - VarbitComposition varbit = client.getVarbit(id); - if (varbit != null) - { - varbits.put(varbit.getIndex(), id); - } - } - return true; - }); - } - - public void shutDown() - { - varbits = null; - oldVarps = null; - oldVarps2 = null; - } - - @Subscribe - public void onGameStateChanged(GameStateChanged gameStateChanged) - { - if (gameStateChanged.getGameState().equals(GameState.HOPPING) - || gameStateChanged.getGameState().equals(GameState.LOGGING_IN)) - { - initializingTick = client.getTickCount(); - shutDown(); - startUp(); - } - } - - private void pushVarChange(int varType, int varIndex, int oldValue, int newValue, int tick) - { - /* Queues up varbit or varplayer changes to be pushed out to the crowdsourcing manager during the next client - * tick. - */ - clientThread.invokeLater(() -> - { - LocalPoint local = LocalPoint.fromWorld(client, client.getLocalPlayer().getWorldLocation()); - WorldPoint location = WorldPoint.fromLocalInstance(client, local); - boolean isInInstance = client.isInInstancedRegion(); - - log.debug(String.format("Storing VarData (tick %d): %d, %d, %d->%d", tick, varType, varIndex, oldValue, newValue)); - VarData varbitData = new VarData(varType, varIndex, oldValue, newValue, tick, isInInstance, location); - crowdsourcingManager.storeEvent(varbitData); - }); - } - - @Subscribe - public void onVarbitChanged(VarbitChanged varbitChanged) - { - int tick = client.getTickCount(); - - // Whenever a varbit is changed, record it and pass the info off to be submitted. - int index = varbitChanged.getIndex(); - int[] varps = client.getVarps(); - - for (int i : varbits.get(index)) - { - int oldValue = client.getVarbitValue(oldVarps, i); - int newValue = client.getVarbitValue(varps, i); - - if (oldValue != newValue) - { - // Set oldVarps2 so it doesn't pick up varbit changes - client.setVarbitValue(oldVarps2, i, newValue); - - // If the varbit is being changed on an initializing tick (when logging in), don't push out a change - if (tick != initializingTick && !BLACKLIST.contains(i)) - { - pushVarChange(VARBIT, i, oldValue, newValue, tick); - } - } - } - - int oldValue = oldVarps2[index]; - int newValue = varps[index]; - - // Push out varp changes - if (oldValue != newValue && tick != initializingTick) - { - pushVarChange(VARPLAYER, index, oldValue, newValue, tick); - } - - oldVarps[index] = varps[index]; - oldVarps2[index] = varps[index]; - } - -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java deleted file mode 100644 index 2799f2eb81..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/varbits/VarData.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2020 andmcadams - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.client.plugins.crowdsourcing.varbits; - -import lombok.AllArgsConstructor; -import lombok.Data; -import net.runelite.api.coords.WorldPoint; - -@Data -@AllArgsConstructor -public class VarData -{ - private final int varType; - private final int varbitNumber; - private final int oldValue; - private final int newValue; - private final int tick; - private final boolean isInInstance; - private final WorldPoint location; -} From b6ce64d31533c44f5bd2f0b23d1ee3993d8acd37 Mon Sep 17 00:00:00 2001 From: simeonlg Date: Thu, 11 Nov 2021 19:41:43 +0100 Subject: [PATCH 07/14] clues: Accept Tome of water when requiring water runes (#14361) --- .../client/plugins/cluescrolls/clues/SkillChallengeClue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java index 7ff2f150ba..1b7925b380 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java @@ -143,7 +143,7 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, Nam new SkillChallengeClue("Equip a Dragon Scimitar.", true, any("Any Dragon Scimitar", item(ItemID.DRAGON_SCIMITAR), item(ItemID.DRAGON_SCIMITAR_OR))), new SkillChallengeClue("Enchant some Dragonstone Jewellery.", "enchant a piece of dragonstone jewellery.", xOfItem(ItemID.COSMIC_RUNE, 1), - any("Water Rune x15", xOfItem(ItemID.WATER_RUNE, 15), xOfItem(ItemID.MIST_RUNE, 15), xOfItem(ItemID.MUD_RUNE, 15), xOfItem(ItemID.STEAM_RUNE, 15), item(ItemID.STAFF_OF_WATER), item(ItemID.WATER_BATTLESTAFF), item(ItemID.MYSTIC_WATER_STAFF), item(ItemID.MUD_BATTLESTAFF), item(ItemID.MYSTIC_MUD_STAFF), item(ItemID.MIST_BATTLESTAFF), item(ItemID.MYSTIC_MIST_STAFF), item(ItemID.STEAM_BATTLESTAFF), item(ItemID.MYSTIC_STEAM_STAFF), item(ItemID.STEAM_BATTLESTAFF_12795), item(ItemID.MYSTIC_STEAM_STAFF_12796), item(ItemID.KODAI_WAND)), + any("Water Rune x15", xOfItem(ItemID.WATER_RUNE, 15), xOfItem(ItemID.MIST_RUNE, 15), xOfItem(ItemID.MUD_RUNE, 15), xOfItem(ItemID.STEAM_RUNE, 15), item(ItemID.STAFF_OF_WATER), item(ItemID.WATER_BATTLESTAFF), item(ItemID.MYSTIC_WATER_STAFF), item(ItemID.MUD_BATTLESTAFF), item(ItemID.MYSTIC_MUD_STAFF), item(ItemID.MIST_BATTLESTAFF), item(ItemID.MYSTIC_MIST_STAFF), item(ItemID.STEAM_BATTLESTAFF), item(ItemID.MYSTIC_STEAM_STAFF), item(ItemID.STEAM_BATTLESTAFF_12795), item(ItemID.MYSTIC_STEAM_STAFF_12796), item(ItemID.KODAI_WAND), item(ItemID.TOME_OF_WATER)), any("Earth Rune x15", xOfItem(ItemID.EARTH_RUNE, 15), xOfItem(ItemID.DUST_RUNE, 15), xOfItem(ItemID.MUD_RUNE, 15), xOfItem(ItemID.LAVA_RUNE, 15), item(ItemID.STAFF_OF_EARTH), item(ItemID.EARTH_BATTLESTAFF), item(ItemID.MYSTIC_EARTH_STAFF), item(ItemID.MUD_BATTLESTAFF), item(ItemID.MYSTIC_MUD_STAFF), item(ItemID.DUST_BATTLESTAFF), item(ItemID.MYSTIC_DUST_STAFF), item(ItemID.LAVA_BATTLESTAFF), item(ItemID.MYSTIC_LAVA_STAFF), item(ItemID.LAVA_BATTLESTAFF_21198), item(ItemID.MYSTIC_LAVA_STAFF_21200)), any("Unenchanted Dragonstone Jewellery", item(ItemID.DRAGONSTONE_RING), item(ItemID.DRAGON_NECKLACE), item(ItemID.DRAGONSTONE_BRACELET), item(ItemID.DRAGONSTONE_AMULET))), new SkillChallengeClue("Craft a nature rune.", item(ItemID.PURE_ESSENCE)), From e9a1326fd40e388f01a9dc5bba6bbe59a15be3eb Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sun, 19 Apr 2020 13:42:31 +0100 Subject: [PATCH 08/14] move runepouch rune enum to client/game --- .../Runes.java => game/RunepouchRune.java} | 14 +++++++------- .../client/plugins/runepouch/RunepouchOverlay.java | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) rename runelite-client/src/main/java/net/runelite/client/{plugins/runepouch/Runes.java => game/RunepouchRune.java} (91%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java b/runelite-client/src/main/java/net/runelite/client/game/RunepouchRune.java similarity index 91% rename from runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java rename to runelite-client/src/main/java/net/runelite/client/game/RunepouchRune.java index 3031aa7b97..f9a863124f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/Runes.java +++ b/runelite-client/src/main/java/net/runelite/client/game/RunepouchRune.java @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.runepouch; +package net.runelite.client.game; import com.google.common.collect.ImmutableMap; @@ -52,7 +52,7 @@ import static net.runelite.api.ItemID.STEAM_RUNE; import static net.runelite.api.ItemID.WATER_RUNE; import static net.runelite.api.ItemID.WRATH_RUNE; -public enum Runes +public enum RunepouchRune { AIR(1, AIR_RUNE), WATER(2, WATER_RUNE), @@ -85,25 +85,25 @@ public enum Runes @Setter private BufferedImage image; - private static final Map runes; + private static final Map runes; static { - ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); - for (Runes rune : values()) + ImmutableMap.Builder builder = new ImmutableMap.Builder<>(); + for (RunepouchRune rune : values()) { builder.put(rune.getId(), rune); } runes = builder.build(); } - Runes(int id, int itemId) + RunepouchRune(int id, int itemId) { this.id = id; this.itemId = itemId; } - public static Runes getRune(int varbit) + public static RunepouchRune getRune(int varbit) { return runes.get(varbit); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java index 255f3f9ac1..962e47d413 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java @@ -35,6 +35,7 @@ import net.runelite.api.Point; import net.runelite.api.Varbits; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.game.ItemManager; +import net.runelite.client.game.RunepouchRune; import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.BOTH; import static net.runelite.client.plugins.runepouch.config.RunePouchOverlayMode.MOUSE_HOVER; import net.runelite.client.ui.FontManager; @@ -100,7 +101,7 @@ public class RunepouchOverlay extends WidgetItemOverlay Varbits runeVarbit = RUNE_VARBITS[i]; int runeId = client.getVar(runeVarbit); - Runes rune = Runes.getRune(runeId); + RunepouchRune rune = RunepouchRune.getRune(runeId); if (rune == null) { continue; @@ -149,7 +150,7 @@ public class RunepouchOverlay extends WidgetItemOverlay } } - private BufferedImage getRuneImage(Runes rune) + private BufferedImage getRuneImage(RunepouchRune rune) { BufferedImage runeImg = rune.getImage(); if (runeImg != null) From 32ff64b30cfaa1536e2a9319087564d5a4005f81 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Sun, 19 Apr 2020 13:43:19 +0100 Subject: [PATCH 09/14] clues: make item requirements work with the runepouch --- .../plugins/cluescrolls/ClueScrollPlugin.java | 63 ++++++++++++++++++- .../cluescrolls/ClueScrollPluginTest.java | 48 ++++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index bcc207325b..3136d3b954 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -64,6 +64,7 @@ import net.runelite.api.Scene; import net.runelite.api.ScriptID; import net.runelite.api.Tile; import net.runelite.api.TileObject; +import net.runelite.api.Varbits; import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; @@ -95,6 +96,7 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; import net.runelite.client.events.OverlayMenuClicked; import net.runelite.client.game.ItemManager; +import net.runelite.client.game.RunepouchRune; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; @@ -143,6 +145,12 @@ public class ClueScrollPlugin extends Plugin private static final Color HIGHLIGHT_HOVER_BORDER_COLOR = HIGHLIGHT_BORDER_COLOR.darker(); private static final Color HIGHLIGHT_FILL_COLOR = new Color(0, 255, 0, 20); private static final String CLUE_TAG_NAME = "clue"; + private static final Varbits[] RUNEPOUCH_AMOUNT_VARBITS = { + Varbits.RUNE_POUCH_AMOUNT1, Varbits.RUNE_POUCH_AMOUNT2, Varbits.RUNE_POUCH_AMOUNT3 + }; + private static final Varbits[] RUNEPOUCH_RUNE_VARBITS = { + Varbits.RUNE_POUCH_RUNE1, Varbits.RUNE_POUCH_RUNE2, Varbits.RUNE_POUCH_RUNE3 + }; @Getter private ClueScroll clue; @@ -361,7 +369,36 @@ public class ClueScrollPlugin extends Plugin return; } - inventoryItems = event.getItemContainer().getItems(); + if (event.getItemContainer().contains(ItemID.RUNE_POUCH) || event.getItemContainer().contains(ItemID.RUNE_POUCH_L)) + { + // Clone the array so changes aren't passed back to the event. + inventoryItems = event.getItemContainer().getItems().clone(); + + List runePouchContents = getRunepouchContents(); + + if (!runePouchContents.isEmpty()) + { + for (int i = 0; i < inventoryItems.length; i++) + { + Item invItem = inventoryItems[i]; + for (Item rune : runePouchContents) + { + if (invItem.getId() == rune.getId()) + { + inventoryItems[i] = new Item(invItem.getId(), rune.getQuantity() + invItem.getQuantity()); + runePouchContents.remove(rune); + break; + } + } + } + + inventoryItems = ArrayUtils.addAll(inventoryItems, runePouchContents.toArray(new Item[0])); + } + } + else + { + inventoryItems = event.getItemContainer().getItems(); + } // Check if item was removed from inventory if (clue != null && clueItemId != null) @@ -393,6 +430,30 @@ public class ClueScrollPlugin extends Plugin } } + private List getRunepouchContents() + { + List items = new ArrayList<>(); + for (int i = 0; i < RUNEPOUCH_AMOUNT_VARBITS.length; i++) + { + int amount = client.getVar(RUNEPOUCH_AMOUNT_VARBITS[i]); + if (amount <= 0) + { + continue; + } + + int varbId = client.getVar(RUNEPOUCH_RUNE_VARBITS[i]); + RunepouchRune rune = RunepouchRune.getRune(varbId); + if (rune == null) + { + continue; + } + + Item item = new Item(rune.getItemId(), amount); + items.add(item); + } + return items; + } + @Subscribe public void onNpcSpawned(final NpcSpawned event) { diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java index 668e7fe837..14c6d1a585 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java @@ -30,14 +30,22 @@ import com.google.inject.Inject; import com.google.inject.name.Named; import com.google.inject.testing.fieldbinder.Bind; import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.Arrays; +import java.util.List; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; +import net.runelite.api.InventoryID; +import net.runelite.api.Item; +import net.runelite.api.ItemContainer; +import net.runelite.api.ItemID; import net.runelite.api.NPC; import net.runelite.api.NullObjectID; import net.runelite.api.Player; +import net.runelite.api.Varbits; import net.runelite.api.coords.WorldPoint; import net.runelite.api.events.ChatMessage; import net.runelite.api.events.GameTick; +import net.runelite.api.events.ItemContainerChanged; import net.runelite.api.events.MenuOptionClicked; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; @@ -45,8 +53,11 @@ import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.banktags.TagManager; import net.runelite.client.plugins.cluescrolls.clues.hotcold.HotColdLocation; import net.runelite.client.ui.overlay.OverlayManager; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -183,4 +194,41 @@ public class ClueScrollPluginTest plugin.onChatMessage(withdrawMessage); assertNull(plugin.getActiveSTASHClue()); } + + @Test + public void testThatRunepouchIsAddedToInventory() + { + ItemContainer container = mock(ItemContainer.class); + ItemContainerChanged event = new ItemContainerChanged(InventoryID.INVENTORY.getId(), container); + + final Item[] inventory = { + new Item(ItemID.COINS_995, 100), + new Item(ItemID.MITHRIL_BAR, 1), + new Item(ItemID.MITHRIL_BAR, 1), + new Item(ItemID.MITHRIL_BAR, 1), + new Item(ItemID.SOUL_RUNE, 30), + new Item(ItemID.COSMIC_RUNE, 100), + new Item(ItemID.RUNE_POUCH, 1), + new Item(ItemID.SPADE, 1), + new Item(ItemID.CLUE_SCROLL_MASTER, 1) + }; + + when(container.getItems()).thenReturn(inventory); + when(container.contains(ItemID.RUNE_POUCH)).thenReturn(true); + when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(container); + + when(client.getVar(Varbits.RUNE_POUCH_RUNE1)).thenReturn(9); // Cosmic Rune + when(client.getVar(Varbits.RUNE_POUCH_AMOUNT1)).thenReturn(20); + when(client.getVar(Varbits.RUNE_POUCH_RUNE3)).thenReturn(4); // Fire Rune + when(client.getVar(Varbits.RUNE_POUCH_AMOUNT3)).thenReturn(4000); + + plugin.onItemContainerChanged(event); + + assertFalse(Arrays.equals(inventory, plugin.getInventoryItems())); + + List inventoryList = Arrays.asList(plugin.getInventoryItems()); + + assertThat(inventoryList, hasItem(new Item(ItemID.COSMIC_RUNE, 120))); + assertThat(inventoryList, hasItem(new Item(ItemID.FIRE_RUNE, 4000))); + } } From 706b9bdba097ca7bc1967d50f1fd7142efe54a7a Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 12 Nov 2021 09:17:13 -0500 Subject: [PATCH 10/14] clues: remove unnecessary item array copy The array returned by getItems() is always a new array and so does not require copying --- .../plugins/cluescrolls/ClueScrollPlugin.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 3136d3b954..ac333a0e6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -358,22 +358,22 @@ public class ClueScrollPlugin extends Plugin @Subscribe public void onItemContainerChanged(final ItemContainerChanged event) { - if (event.getItemContainer() == client.getItemContainer(InventoryID.EQUIPMENT)) + if (event.getContainerId() == InventoryID.EQUIPMENT.getId()) { equippedItems = event.getItemContainer().getItems(); return; } - if (event.getItemContainer() != client.getItemContainer(InventoryID.INVENTORY)) + if (event.getContainerId() != InventoryID.INVENTORY.getId()) { return; } + inventoryItems = event.getItemContainer().getItems(); + + // Add runes from rune pouch to inventoryItems if (event.getItemContainer().contains(ItemID.RUNE_POUCH) || event.getItemContainer().contains(ItemID.RUNE_POUCH_L)) { - // Clone the array so changes aren't passed back to the event. - inventoryItems = event.getItemContainer().getItems().clone(); - List runePouchContents = getRunepouchContents(); if (!runePouchContents.isEmpty()) @@ -395,10 +395,6 @@ public class ClueScrollPlugin extends Plugin inventoryItems = ArrayUtils.addAll(inventoryItems, runePouchContents.toArray(new Item[0])); } } - else - { - inventoryItems = event.getItemContainer().getItems(); - } // Check if item was removed from inventory if (clue != null && clueItemId != null) @@ -432,7 +428,7 @@ public class ClueScrollPlugin extends Plugin private List getRunepouchContents() { - List items = new ArrayList<>(); + List items = new ArrayList<>(RUNEPOUCH_AMOUNT_VARBITS.length); for (int i = 0; i < RUNEPOUCH_AMOUNT_VARBITS.length; i++) { int amount = client.getVar(RUNEPOUCH_AMOUNT_VARBITS[i]); From 67f7e7f48811e9ce34ff60373c92ad2ed165fc53 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 12 Nov 2021 20:02:42 -0500 Subject: [PATCH 11/14] clues test: remove unnecessary stubbing --- .../client/plugins/cluescrolls/ClueScrollPluginTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java index 14c6d1a585..7db5ce3f6e 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/cluescrolls/ClueScrollPluginTest.java @@ -215,7 +215,6 @@ public class ClueScrollPluginTest when(container.getItems()).thenReturn(inventory); when(container.contains(ItemID.RUNE_POUCH)).thenReturn(true); - when(client.getItemContainer(InventoryID.INVENTORY)).thenReturn(container); when(client.getVar(Varbits.RUNE_POUCH_RUNE1)).thenReturn(9); // Cosmic Rune when(client.getVar(Varbits.RUNE_POUCH_AMOUNT1)).thenReturn(20); From 1362af414a1a7c4e6ec3fc678f00a9aecb233b6f Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 13 Nov 2021 09:50:23 -0500 Subject: [PATCH 12/14] chat filter: Ignore character accents for matching This lets plain latin-character filters to match messages with accents and diacritics which are not easily typed on all keyboard layouts. Co-authored-by: Jordan Atwood --- .../plugins/chatfilter/ChatFilterPlugin.java | 20 ++++++++++--- .../chatfilter/ChatFilterPluginTest.java | 30 +++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java index b5d111035a..ab0e0e7149 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chatfilter/ChatFilterPlugin.java @@ -36,6 +36,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.regex.MatchResult; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; @@ -316,6 +317,9 @@ public class ChatFilterPlugin extends Plugin { String strippedMessage = jagexPrintableCharMatcher.retainFrom(message) .replace('\u00A0', ' '); + String strippedAccents = StringUtils.stripAccents(strippedMessage); + assert strippedMessage.length() == strippedAccents.length(); + if (username != null && shouldFilterByName(username)) { switch (config.filterType()) @@ -332,16 +336,20 @@ public class ChatFilterPlugin extends Plugin boolean filtered = false; for (Pattern pattern : filteredPatterns) { - Matcher m = pattern.matcher(strippedMessage); + Matcher m = pattern.matcher(strippedAccents); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); + int idx = 0; while (m.find()) { switch (config.filterType()) { case CENSOR_WORDS: - m.appendReplacement(sb, StringUtils.repeat('*', m.group(0).length())); + MatchResult matchResult = m.toMatchResult(); + sb.append(strippedMessage, idx, matchResult.start()) + .append(StringUtils.repeat('*', matchResult.group().length())); + idx = m.end(); filtered = true; break; case CENSOR_MESSAGE: @@ -350,9 +358,10 @@ public class ChatFilterPlugin extends Plugin return null; } } - m.appendTail(sb); + sb.append(strippedMessage.substring(idx)); strippedMessage = sb.toString(); + assert strippedMessage.length() == strippedAccents.length(); } return filtered ? strippedMessage : message; @@ -364,15 +373,18 @@ public class ChatFilterPlugin extends Plugin filteredNamePatterns.clear(); Text.fromCSV(config.filteredWords()).stream() + .map(StringUtils::stripAccents) .map(s -> Pattern.compile(Pattern.quote(s), Pattern.CASE_INSENSITIVE)) .forEach(filteredPatterns::add); NEWLINE_SPLITTER.splitToList(config.filteredRegex()).stream() + .map(StringUtils::stripAccents) .map(ChatFilterPlugin::compilePattern) .filter(Objects::nonNull) .forEach(filteredPatterns::add); NEWLINE_SPLITTER.splitToList(config.filteredNames()).stream() + .map(StringUtils::stripAccents) .map(ChatFilterPlugin::compilePattern) .filter(Objects::nonNull) .forEach(filteredNamePatterns::add); diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java index 501787576a..b93f3b1078 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/chatfilter/ChatFilterPluginTest.java @@ -186,6 +186,36 @@ public class ChatFilterPluginTest assertNull(chatFilterPlugin.censorMessage("Blue", "hello\u00A0osrs")); } + @Test + public void testFilterUnicode() + { + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); + when(chatFilterConfig.filteredWords()).thenReturn("filterme"); + + chatFilterPlugin.updateFilteredPatterns(); + assertEquals("plëäsë ******** plügïn", chatFilterPlugin.censorMessage("Blue", "plëäsë fïltërmë plügïn")); + } + + @Test + public void testUnicodeFiltersUnicode() + { + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); + when(chatFilterConfig.filteredWords()).thenReturn("plëäsë"); + + chatFilterPlugin.updateFilteredPatterns(); + assertEquals("****** fïltërmë plügïn", chatFilterPlugin.censorMessage("Blue", "plëäsë fïltërmë plügïn")); + } + + @Test + public void testMixedUnicodeFiltersUnicode() + { + when(chatFilterConfig.filterType()).thenReturn(ChatFilterType.CENSOR_WORDS); + when(chatFilterConfig.filteredWords()).thenReturn("plëäsë, filterme"); + + chatFilterPlugin.updateFilteredPatterns(); + assertEquals("****** ******** plügïn", chatFilterPlugin.censorMessage("Blue", "plëäsë fïltërmë plügïn")); + } + @Test public void testMessageFromFriendIsFiltered() { From b6e0e01f7d232a6251a84643afae3f5ef2435dbd Mon Sep 17 00:00:00 2001 From: LlemonDuck Date: Sat, 13 Nov 2021 19:41:44 -0800 Subject: [PATCH 13/14] special counter: ignore vet'ion hellhounds Prevents spec counter resetting when attacking a skeleton hellhound spawned by Vet'ion. The hellhounds are spawned at 50% HP, and are required to kill to continue the fight, so the player will continue fighting Vet'ion after they are killed. It's possible that a player may want to use a spec against the hellhounds, but I'm not aware of any reason for it. --- .../client/plugins/specialcounter/SpecialCounterPlugin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java index 6c612efff9..b2b78e9a52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specialcounter/SpecialCounterPlugin.java @@ -72,7 +72,8 @@ public class SpecialCounterPlugin extends Plugin { private static final Set IGNORED_NPCS = ImmutableSet.of( NpcID.DARK_ENERGY_CORE, NpcID.ZOMBIFIED_SPAWN, NpcID.ZOMBIFIED_SPAWN_8063, - NpcID.COMBAT_DUMMY, NpcID.UNDEAD_COMBAT_DUMMY + NpcID.COMBAT_DUMMY, NpcID.UNDEAD_COMBAT_DUMMY, + NpcID.SKELETON_HELLHOUND_6613, NpcID.GREATER_SKELETON_HELLHOUND ); private static final Set RESET_ON_LEAVE_INSTANCED_REGIONS = ImmutableSet.of( From 13ecfc0a9eaf3161b979f6e9f1b6f66fa075fb51 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 14 Nov 2021 13:41:07 -0500 Subject: [PATCH 14/14] gpu: add sync mode config This allows the additional OFF mode which has the client manage its own frame rate target without the use of vsync. On lower end systems which have a hard time delivering a frame in the vsync interval this can give a noticible performance improvement since it doesn't stall the cpu waiting for the next vblank when a frame is skipped --- .../main/java/net/runelite/api/Client.java | 1 + .../client/plugins/gpu/GpuPlugin.java | 43 ++++++++++++++----- .../client/plugins/gpu/GpuPluginConfig.java | 33 ++++++++++++++ 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 4f38b13c0c..5f1175fcdd 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1953,6 +1953,7 @@ public interface Client extends GameEngine ClanSettings getClanSettings(int clanId); void setUnlockedFps(boolean unlock); + void setUnlockedFpsTarget(int fps); /** * Gets the ambient sound effects diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java index b9900a988e..b275fd7d4e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPlugin.java @@ -394,9 +394,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks this.gl = glContext.getGL().getGL4(); - final boolean unlockFps = this.config.unlockFps(); - client.setUnlockedFps(unlockFps); - gl.setSwapInterval(unlockFps ? -1 : 0); + setupSyncMode(); if (log.isDebugEnabled()) { @@ -556,18 +554,43 @@ public class GpuPlugin extends Plugin implements DrawCallbacks { if (configChanged.getGroup().equals(GpuPluginConfig.GROUP)) { - if (configChanged.getKey().equals("unlockFps")) + if (configChanged.getKey().equals("unlockFps") + || configChanged.getKey().equals("vsyncMode") + || configChanged.getKey().equals("fpsTarget")) { - boolean unlockFps = Boolean.parseBoolean(configChanged.getNewValue()); - clientThread.invokeLater(() -> - { - client.setUnlockedFps(unlockFps); - invokeOnMainThread(() -> gl.setSwapInterval(unlockFps ? -1 : 0)); - }); + log.debug("Rebuilding sync mode"); + clientThread.invokeLater(() -> invokeOnMainThread(this::setupSyncMode)); } } } + private void setupSyncMode() + { + final boolean unlockFps = config.unlockFps(); + client.setUnlockedFps(unlockFps); + + // Without unlocked fps, the client manages sync on its 20ms timer + GpuPluginConfig.SyncMode syncMode = unlockFps + ? this.config.syncMode() + : GpuPluginConfig.SyncMode.OFF; + + switch (syncMode) + { + case ON: + gl.setSwapInterval(1); + client.setUnlockedFpsTarget(0); + break; + case OFF: + gl.setSwapInterval(0); + client.setUnlockedFpsTarget(config.fpsTarget()); // has no effect with unlockFps=false + break; + case ADAPTIVE: + gl.setSwapInterval(-1); + client.setUnlockedFpsTarget(0); + break; + } + } + private void initProgram() throws ShaderException { String versionHeader = OSType.getOSType() == OSType.Linux ? LINUX_VERSION_HEADER : WINDOWS_VERSION_HEADER; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java index ff69cd80e8..3d5f1095ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/gpu/GpuPluginConfig.java @@ -159,4 +159,37 @@ public interface GpuPluginConfig extends Config { return false; } + + enum SyncMode + { + OFF, + ON, + ADAPTIVE + } + + @ConfigItem( + keyName = "vsyncMode", + name = "Vsync Mode", + description = "Method to synchronize frame rate with refresh rate", + position = 11 + ) + default SyncMode syncMode() + { + return SyncMode.ADAPTIVE; + } + + @ConfigItem( + keyName = "fpsTarget", + name = "FPS Target", + description = "Target FPS when unlock FPS is enabled and Vsync mode is OFF", + position = 12 + ) + @Range( + min = 1, + max = 999 + ) + default int fpsTarget() + { + return 60; + } }