From 4b73ca431c82587c95586ea51adc164c713c3aca Mon Sep 17 00:00:00 2001 From: Max Weber Date: Mon, 21 Oct 2019 01:15:23 -0600 Subject: [PATCH 01/43] runelite-client: use privateLookupIn for invokespecialing defaults The private ctor we used for MethodHandles$Lookup is gone in jdk-14. --- .../config/ConfigInvocationHandler.java | 9 +-- .../runelite/client/eventbus/EventBus.java | 28 +------- .../net/runelite/client/util/ReflectUtil.java | 72 +++++++++++++++++++ 3 files changed, 76 insertions(+), 33 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java diff --git a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java index ae0126cc89..b78117b8ce 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java +++ b/runelite-client/src/main/java/net/runelite/client/config/ConfigInvocationHandler.java @@ -26,12 +26,11 @@ package net.runelite.client.config; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Constructor; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.util.Objects; import lombok.extern.slf4j.Slf4j; +import net.runelite.client.util.ReflectUtil; @Slf4j class ConfigInvocationHandler implements InvocationHandler @@ -165,12 +164,8 @@ class ConfigInvocationHandler implements InvocationHandler static Object callDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable { - // Call the default method implementation - https://rmannibucau.wordpress.com/2014/03/27/java-8-default-interface-methods-and-jdk-dynamic-proxies/ - Constructor constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class); - constructor.setAccessible(true); - Class declaringClass = method.getDeclaringClass(); - return constructor.newInstance(declaringClass, MethodHandles.Lookup.PUBLIC | MethodHandles.Lookup.PRIVATE) + return ReflectUtil.privateLookupIn(declaringClass) .unreflectSpecial(method, declaringClass) .bindTo(proxy) .invokeWithArguments(args); diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java index a28f2f4371..588752fd46 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java @@ -34,8 +34,6 @@ import java.lang.invoke.LambdaMetafactory; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.function.Consumer; @@ -45,6 +43,7 @@ import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; import lombok.Value; import lombok.extern.slf4j.Slf4j; +import net.runelite.client.util.ReflectUtil; @Slf4j @RequiredArgsConstructor @@ -141,7 +140,7 @@ public class EventBus try { - final MethodHandles.Lookup caller = privateLookupIn(clazz); + final MethodHandles.Lookup caller = ReflectUtil.privateLookupIn(clazz); final MethodType subscription = MethodType.methodType(void.class, parameterClazz); final MethodHandle target = caller.findVirtual(clazz, method.getName(), subscription); final CallSite site = LambdaMetafactory.metafactory( @@ -223,27 +222,4 @@ public class EventBus } } } - - private static MethodHandles.Lookup privateLookupIn(Class clazz) throws IllegalAccessException, NoSuchFieldException, InvocationTargetException - { - try - { - // Java 9+ has privateLookupIn method on MethodHandles, but since we are shipping and using Java 8 - // we need to access it via reflection. This is preferred way because it's Java 9+ public api and is - // likely to not change - final Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); - return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, MethodHandles.lookup()); - } - catch (NoSuchMethodException e) - { - // In Java 8 we first do standard lookupIn class - final MethodHandles.Lookup lookupIn = MethodHandles.lookup().in(clazz); - - // and then we mark it as trusted for private lookup via reflection on private field - final Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); - modes.setAccessible(true); - modes.setInt(lookupIn, -1); // -1 == TRUSTED - return lookupIn; - } - } } diff --git a/runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java b/runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java new file mode 100644 index 0000000000..76530b6ab6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * Copyright (c) 2018, Abex + * 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.util; + +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ReflectUtil +{ + private ReflectUtil() + { + } + + public static MethodHandles.Lookup privateLookupIn(Class clazz) + { + try + { + // Java 9+ has privateLookupIn method on MethodHandles, but since we are shipping and using Java 8 + // we need to access it via reflection. This is preferred way because it's Java 9+ public api and is + // likely to not change + final Method privateLookupIn = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class); + return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, MethodHandles.lookup()); + } + catch (InvocationTargetException | IllegalAccessException e) + { + throw new RuntimeException(e); + } + catch (NoSuchMethodException e) + { + try + { + // In Java 8 we first do standard lookupIn class + final MethodHandles.Lookup lookupIn = MethodHandles.lookup().in(clazz); + + // and then we mark it as trusted for private lookup via reflection on private field + final Field modes = MethodHandles.Lookup.class.getDeclaredField("allowedModes"); + modes.setAccessible(true); + modes.setInt(lookupIn, -1); // -1 == TRUSTED + return lookupIn; + } + catch (ReflectiveOperationException ex) + { + throw new RuntimeException(ex); + } + } + } +} From 87af40bec758976d3597bf06bc14e8a2d88bd50e Mon Sep 17 00:00:00 2001 From: dekvall Date: Wed, 13 Nov 2019 01:55:14 +0100 Subject: [PATCH 02/43] emojis: add facepalm emoji --- .../net/runelite/client/plugins/emojis/Emoji.java | 4 +++- .../runelite/client/plugins/emojis/facepalm.png | Bin 0 -> 382 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/emojis/facepalm.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/emojis/Emoji.java b/runelite-client/src/main/java/net/runelite/client/plugins/emojis/Emoji.java index 8d6006856e..16e27b1519 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/emojis/Emoji.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/emojis/Emoji.java @@ -84,7 +84,9 @@ enum Emoji ALIEN("(@.@)"), EGGPLANT("8=D"), WAVE("(^_^)/"), - HEART_EYES("(*.*)"); + HEART_EYES("(*.*)"), + FACEPALM("M-)"), + ; private static final Map emojiMap; diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/emojis/facepalm.png b/runelite-client/src/main/resources/net/runelite/client/plugins/emojis/facepalm.png new file mode 100644 index 0000000000000000000000000000000000000000..00c3ddb5255c8a7b9f2fde4c12633b8d61d03290 GIT binary patch literal 382 zcmV-^0fGLBP)%9KL4#X|F1Ux)>!@1S^2_L_`Op3uSEaS zRsY;w|Jz*s)LQ+~S^2t7|Hex5&uRVIU(1?9#F0S$&{d{=wwiIm#GID)wov`qT>sHj z)tYsZXv(W;mi*6H|HDW0r9qr-yv%c7__kF4&QbraG?r_{rgN?P%vbitTj`!ryoZa( zp_Gke#EoRbrF^%OX~~Ub#gb^riekZrUcFvvUcmqW00neXPE!B?0002OYX-3Z003@D zL_t&t9RsV+m__3QCvdzdr;)pAxS?e^P6>>kH>i`IL_;GLK$!J c`EfV#4`|vDw7RQ?v;Y7A07*qoM6N<$g0=R!T>t<8 literal 0 HcmV?d00001 From b319012cbb1ba08ade40059bec609e0fe022f84f Mon Sep 17 00:00:00 2001 From: al3x-huang Date: Mon, 18 Nov 2019 05:41:27 -0500 Subject: [PATCH 03/43] fpsplugin: Add multiple FPS targets for multiple modes (#10239) Players can now set a global FPS target as well as one for when the window is unfocused --- .../client/plugins/fps/FpsConfig.java | 39 +++++++++++++++---- .../client/plugins/fps/FpsDrawListener.java | 16 +++++--- .../client/plugins/fps/FpsLimitMode.java | 32 --------------- .../client/plugins/fps/FpsOverlay.java | 4 +- 4 files changed, 44 insertions(+), 47 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsLimitMode.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java index 73e7f3f8c5..e47449ee71 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsConfig.java @@ -32,20 +32,21 @@ import net.runelite.client.config.ConfigItem; public interface FpsConfig extends Config { @ConfigItem( - keyName = "limitMode", - name = "Limit Mode", - description = "Stay at or under the target frames per second even when in this mode", + keyName = "limitFps", + name = "Limit Global FPS", + description = "Global FPS limit in effect regardless of
" + + "whether window is in focus or not", position = 1 ) - default FpsLimitMode limitMode() + default boolean limitFps() { - return FpsLimitMode.NEVER; + return false; } @ConfigItem( keyName = "maxFps", - name = "FPS target", - description = "Desired max frames per second", + name = "Global FPS target", + description = "Desired max global frames per second", position = 2 ) default int maxFps() @@ -53,11 +54,33 @@ public interface FpsConfig extends Config return 50; } + @ConfigItem( + keyName = "limitFpsUnfocused", + name = "Limit FPS unfocused", + description = "FPS limit while window is out of focus", + position = 3 + ) + default boolean limitFpsUnfocused() + { + return false; + } + + @ConfigItem( + keyName = "maxFpsUnfocused", + name = "Unfocused FPS target", + description = "Desired max frames per second for unfocused", + position = 4 + ) + default int maxFpsUnfocused() + { + return 50; + } + @ConfigItem( keyName = "drawFps", name = "Draw FPS indicator", description = "Show a number in the corner for the current FPS", - position = 3 + position = 5 ) default boolean drawFps() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java index 3be17f5577..ca521b6b1c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsDrawListener.java @@ -36,7 +36,7 @@ import net.runelite.api.events.FocusChanged; * For low powered computers, the RS client is often throttled by the hardware or OS and draws at 25-30 fps. * The nano timer is not used in this scenario. * Instead to catch up the RS client runs several cycles before drawing, thus maintaining 50 cycles / second. - * + *

* Enforcing FPS in the draw code does not impact the client engine's ability to run including its audio, * even when forced to 1 FPS with this plugin. */ @@ -67,7 +67,13 @@ public class FpsDrawListener implements Runnable void reloadConfig() { lastMillis = System.currentTimeMillis(); - targetDelay = 1000 / Math.max(1, config.maxFps()); + + int fps = config.limitFpsUnfocused() && !isFocused + ? config.maxFpsUnfocused() + : config.maxFps(); + + targetDelay = 1000 / Math.max(1, fps); + sleepDelay = targetDelay; for (int i = 0; i < SAMPLE_SIZE; i++) @@ -79,18 +85,18 @@ public class FpsDrawListener implements Runnable void onFocusChanged(FocusChanged event) { this.isFocused = event.isFocused(); + reloadConfig(); // load new delay } private boolean isEnforced() { - return FpsLimitMode.ALWAYS == config.limitMode() - || (FpsLimitMode.UNFOCUSED == config.limitMode() && !isFocused); + return config.limitFps() + || (config.limitFpsUnfocused() && !isFocused); } @Override public void run() { - if (!isEnforced()) { return; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsLimitMode.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsLimitMode.java deleted file mode 100644 index 25f855f1c5..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsLimitMode.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2017, Levi - * 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.fps; - -public enum FpsLimitMode -{ - NEVER, - UNFOCUSED, - ALWAYS -} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsOverlay.java index 22bf76373b..76b8d18908 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fps/FpsOverlay.java @@ -77,8 +77,8 @@ public class FpsOverlay extends Overlay private boolean isEnforced() { - return FpsLimitMode.ALWAYS == config.limitMode() - || (FpsLimitMode.UNFOCUSED == config.limitMode() && !isFocused); + return config.limitFps() + || (config.limitFpsUnfocused() && !isFocused); } private Color getFpsValueColor() From 3fd8fb79aa171c924af5f3cb577ec9dce404e4da Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 18 Nov 2019 08:40:53 -0500 Subject: [PATCH 04/43] woodcutting plugin: add respawn timer Co-authored-by: David --- .../client/plugins/woodcutting/Tree.java | 40 +++++++++++++-- .../plugins/woodcutting/TreeRespawn.java | 46 +++++++++++++++++ .../woodcutting/WoodcuttingConfig.java | 11 +++++ .../woodcutting/WoodcuttingPlugin.java | 49 +++++++++++++++++-- .../woodcutting/WoodcuttingTreesOverlay.java | 48 ++++++++++++++++-- 5 files changed, 183 insertions(+), 11 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/Tree.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/Tree.java index befc78df8c..e041108602 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/Tree.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/Tree.java @@ -25,20 +25,54 @@ package net.runelite.client.plugins.woodcutting; import com.google.common.collect.ImmutableMap; +import java.time.Duration; import java.util.Map; +import javax.annotation.Nullable; import lombok.Getter; -import static net.runelite.api.ObjectID.REDWOOD; +import net.runelite.api.ObjectID; +import static net.runelite.api.ObjectID.MAGIC_TREE_10834; +import static net.runelite.api.NullObjectID.NULL_10835; +import static net.runelite.api.ObjectID.MAHOGANY; +import static net.runelite.api.ObjectID.MAHOGANY_36688; +import static net.runelite.api.ObjectID.MAPLE_TREE_10832; +import static net.runelite.api.ObjectID.MAPLE_TREE_36681; +import static net.runelite.api.ObjectID.OAK_10820; +import static net.runelite.api.ObjectID.OAK_TREE_4540; import static net.runelite.api.ObjectID.REDWOOD_29670; +import static net.runelite.api.ObjectID.TEAK; +import static net.runelite.api.ObjectID.TEAK_36686; +import static net.runelite.api.ObjectID.TREE; +import static net.runelite.api.ObjectID.TREE_1277; +import static net.runelite.api.ObjectID.TREE_1278; +import static net.runelite.api.ObjectID.TREE_1279; +import static net.runelite.api.ObjectID.TREE_1280; +import static net.runelite.api.ObjectID.WILLOW; +import static net.runelite.api.ObjectID.WILLOW_10831; +import static net.runelite.api.ObjectID.WILLOW_10833; +import static net.runelite.api.ObjectID.YEW; +import static net.runelite.api.NullObjectID.NULL_10823; +import static net.runelite.api.ObjectID.YEW_36683; @Getter enum Tree { - REDWOOD_TREE_SPAWN(REDWOOD, REDWOOD_29670); + REGULAR_TREE(null, TREE, TREE_1277, TREE_1278, TREE_1279, TREE_1280), + OAK_TREE(Duration.ofMillis(8500), ObjectID.OAK_TREE, OAK_TREE_4540, OAK_10820), + WILLOW_TREE(Duration.ofMillis(8500), WILLOW, WILLOW_10833, WILLOW_10831), + MAPLE_TREE(Duration.ofSeconds(35), ObjectID.MAPLE_TREE, MAPLE_TREE_10832, MAPLE_TREE_36681), + TEAK_TREE(Duration.ofMillis(8500), TEAK, TEAK_36686), + MAHOGANY_TREE(Duration.ofMillis(8500), MAHOGANY, MAHOGANY_36688), + YEW_TREE(Duration.ofMinutes(1), YEW, NULL_10823, YEW_36683), + MAGIC_TREE(Duration.ofMinutes(2), MAGIC_TREE_10834, NULL_10835), + REDWOOD(Duration.ofMinutes(2), ObjectID.REDWOOD, REDWOOD_29670); + @Nullable + private final Duration respawnTime; private final int[] treeIds; - Tree(int... treeIds) + Tree(Duration respawnTime, int... treeIds) { + this.respawnTime = respawnTime; this.treeIds = treeIds; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java new file mode 100644 index 0000000000..a3022ca8f3 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/TreeRespawn.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019, Adam + * Copyright (c) 2019, David + * 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.woodcutting; + +import java.time.Instant; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.runelite.api.coords.LocalPoint; + +@AllArgsConstructor +@Getter +class TreeRespawn +{ + private final Tree tree; + private final LocalPoint location; + private final Instant startTime; + private final int respawnTime; + + boolean isExpired() + { + return Instant.now().isAfter(startTime.plusMillis(respawnTime)); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java index 55cb5e3637..7f992744c6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java @@ -74,4 +74,15 @@ public interface WoodcuttingConfig extends Config { return true; } + + @ConfigItem( + position = 5, + keyName = "showRespawnTimers", + name = "Show respawn timers", + description = "Configures whether to display the respawn timer overlay" + ) + default boolean showRespawnTimers() + { + return true; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java index 01ced70693..b269bc1e99 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -27,15 +27,18 @@ package net.runelite.client.plugins.woodcutting; import com.google.inject.Provides; import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.regex.Pattern; import javax.inject.Inject; +import lombok.AccessLevel; import lombok.Getter; +import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameObject; -import net.runelite.api.GameState; import net.runelite.api.MenuAction; import net.runelite.api.Player; import net.runelite.api.events.AnimationChanged; @@ -62,6 +65,7 @@ import net.runelite.client.ui.overlay.OverlayMenuEntry; tags = {"birds", "nest", "notifications", "overlay", "skilling", "wc"} ) @PluginDependency(XpTrackerPlugin.class) +@Slf4j public class WoodcuttingPlugin extends Plugin { private static final Pattern WOOD_CUT_PATTERN = Pattern.compile("You get (?:some|an)[\\w ]+(?:logs?|mushrooms)\\."); @@ -93,6 +97,10 @@ public class WoodcuttingPlugin extends Plugin @Getter private final Set treeObjects = new HashSet<>(); + @Getter(AccessLevel.PACKAGE) + private final List respawns = new ArrayList<>(); + private boolean recentlyLoggedIn; + @Provides WoodcuttingConfig getConfig(ConfigManager configManager) { @@ -111,6 +119,7 @@ public class WoodcuttingPlugin extends Plugin { overlayManager.remove(overlay); overlayManager.remove(treesOverlay); + respawns.clear(); treeObjects.clear(); session = null; axe = null; @@ -131,6 +140,10 @@ public class WoodcuttingPlugin extends Plugin @Subscribe public void onGameTick(GameTick gameTick) { + recentlyLoggedIn = false; + + respawns.removeIf(TreeRespawn::isExpired); + if (session == null || session.getLastLogCut() == null) { return; @@ -174,7 +187,7 @@ public class WoodcuttingPlugin extends Plugin GameObject gameObject = event.getGameObject(); Tree tree = Tree.findTree(gameObject.getId()); - if (tree != null) + if (tree == Tree.REDWOOD) { treeObjects.add(gameObject); } @@ -183,7 +196,23 @@ public class WoodcuttingPlugin extends Plugin @Subscribe public void onGameObjectDespawned(final GameObjectDespawned event) { - treeObjects.remove(event.getGameObject()); + final GameObject object = event.getGameObject(); + + Tree tree = Tree.findTree(object.getId()); + if (tree != null) + { + if (tree.getRespawnTime() != null && !recentlyLoggedIn) + { + log.debug("Adding respawn timer for {} tree at {}", tree, object.getLocalLocation()); + TreeRespawn treeRespawn = new TreeRespawn(tree, object.getLocalLocation(), Instant.now(), (int) tree.getRespawnTime().toMillis()); + respawns.add(treeRespawn); + } + + if (tree == Tree.REDWOOD) + { + treeObjects.remove(event.getGameObject()); + } + } } @Subscribe @@ -195,9 +224,19 @@ public class WoodcuttingPlugin extends Plugin @Subscribe public void onGameStateChanged(final GameStateChanged event) { - if (event.getGameState() != GameState.LOGGED_IN) + switch (event.getGameState()) { - treeObjects.clear(); + case LOADING: + case HOPPING: + respawns.clear(); + treeObjects.clear(); + break; + case LOGGED_IN: + // After login trees that are depleted will be changed, + // wait for the next game tick before watching for + // trees to despawn + recentlyLoggedIn = true; + break; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java index 2415d17f7a..b070861e08 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingTreesOverlay.java @@ -1,6 +1,7 @@ /* * Copyright (c) 2018, Tomas Slusny * Copyright (c) 2018, Adam + * Copyright (c) 2019, David * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,16 +26,23 @@ */ package net.runelite.client.plugins.woodcutting; +import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.time.Instant; +import java.util.List; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.GameObject; +import net.runelite.api.Perspective; +import net.runelite.api.Point; +import net.runelite.api.coords.LocalPoint; import net.runelite.client.game.ItemManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.ProgressPieComponent; class WoodcuttingTreesOverlay extends Overlay { @@ -56,16 +64,23 @@ class WoodcuttingTreesOverlay extends Overlay @Override public Dimension render(Graphics2D graphics) + { + renderAxes(graphics); + renderTimers(graphics); + return null; + } + + private void renderAxes(Graphics2D graphics) { if (plugin.getSession() == null || !config.showRedwoodTrees()) { - return null; + return; } Axe axe = plugin.getAxe(); if (axe == null) { - return null; + return; } for (GameObject treeObject : plugin.getTreeObjects()) @@ -75,7 +90,34 @@ class WoodcuttingTreesOverlay extends Overlay OverlayUtil.renderImageLocation(client, graphics, treeObject.getLocalLocation(), itemManager.getImage(axe.getItemId()), 120); } } + } - return null; + private void renderTimers(Graphics2D graphics) + { + List respawns = plugin.getRespawns(); + if (respawns.isEmpty() || !config.showRespawnTimers()) + { + return; + } + + Instant now = Instant.now(); + for (TreeRespawn treeRespawn : respawns) + { + LocalPoint loc = treeRespawn.getLocation(); + + float percent = (now.toEpochMilli() - treeRespawn.getStartTime().toEpochMilli()) / (float) treeRespawn.getRespawnTime(); + Point point = Perspective.localToCanvas(client, loc, client.getPlane()); + if (point == null || percent > 1.0f) + { + continue; + } + + ProgressPieComponent ppc = new ProgressPieComponent(); + ppc.setBorderColor(Color.ORANGE); + ppc.setFill(Color.YELLOW); + ppc.setPosition(point); + ppc.setProgress(percent); + ppc.render(graphics); + } } } From 408d567fcf45cbbc12c96be2c56c1dae7ca7c3e1 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Tue, 19 Nov 2019 21:33:30 +0000 Subject: [PATCH 05/43] inventory grid: use correct item quantities for drag previews --- .../inventorygrid/InventoryGridOverlay.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java index a179c3f5f2..9eaced470d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventorygrid/InventoryGridOverlay.java @@ -85,7 +85,6 @@ class InventoryGridOverlay extends Overlay final Point mousePoint = new Point(mouse.getX(), mouse.getY()); final int if1DraggedItemIndex = client.getIf1DraggedItemIndex(); final WidgetItem draggedItem = inventoryWidget.getWidgetItem(if1DraggedItemIndex); - final int itemId = draggedItem.getId(); final Rectangle initialBounds = draggedItem.getCanvasBounds(); if (initialMousePoint == null) @@ -93,7 +92,7 @@ class InventoryGridOverlay extends Overlay initialMousePoint = mousePoint; } - if (itemId == -1 || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER) + if (draggedItem.getId() == -1 || !hoverActive && initialMousePoint.distance(mousePoint) < DISTANCE_TO_ACTIVATE_HOVER) { return null; } @@ -102,16 +101,15 @@ class InventoryGridOverlay extends Overlay for (int i = 0; i < INVENTORY_SIZE; ++i) { - WidgetItem widgetItem = inventoryWidget.getWidgetItem(i); - final int targetItemId = widgetItem.getId(); + WidgetItem targetWidgetItem = inventoryWidget.getWidgetItem(i); - final Rectangle bounds = widgetItem.getCanvasBounds(); + final Rectangle bounds = targetWidgetItem.getCanvasBounds(); boolean inBounds = bounds.contains(mousePoint); if (config.showItem() && inBounds) { - drawItem(graphics, bounds, itemId); - drawItem(graphics, initialBounds, targetItemId); + drawItem(graphics, bounds, draggedItem); + drawItem(graphics, initialBounds, targetWidgetItem); } if (config.showHighlight() && inBounds) @@ -129,14 +127,14 @@ class InventoryGridOverlay extends Overlay return null; } - private void drawItem(Graphics2D graphics, Rectangle bounds, int itemId) + private void drawItem(Graphics2D graphics, Rectangle bounds, WidgetItem item) { - if (itemId == -1) + if (item.getId() == -1) { return; } - final BufferedImage draggedItemImage = itemManager.getImage(itemId); + final BufferedImage draggedItemImage = itemManager.getImage(item.getId(), item.getQuantity(), false); final int x = (int) bounds.getX(); final int y = (int) bounds.getY(); From b565f29049f39b334b3459f16e25789ad6865884 Mon Sep 17 00:00:00 2001 From: HSJ-OSRS Date: Mon, 11 Nov 2019 19:41:44 +0000 Subject: [PATCH 06/43] screenshot plugin: add friend/clan member death screenshotting --- .../plugins/screenshot/ScreenshotConfig.java | 21 ++++++++++++++----- .../plugins/screenshot/ScreenshotPlugin.java | 7 ++++++- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java index 164fe7dbdd..2158de75e3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotConfig.java @@ -153,11 +153,22 @@ public interface ScreenshotConfig extends Config return false; } + @ConfigItem( + keyName = "friendDeath", + name = "Screenshot Friend Deaths", + description = "Configures whether or not screenshots are automatically taken when friends or clan members die.", + position = 11 + ) + default boolean screenshotFriendDeath() + { + return false; + } + @ConfigItem( keyName = "duels", name = "Screenshot Duels", description = "Configures whether or not screenshots are automatically taken of the duel end screen.", - position = 11 + position = 12 ) default boolean screenshotDuels() { @@ -168,7 +179,7 @@ public interface ScreenshotConfig extends Config keyName = "valuableDrop", name = "Screenshot Valuable drops", description = "Configures whether or not screenshots are automatically taken when you receive a valuable drop.", - position = 12 + position = 13 ) default boolean screenshotValuableDrop() { @@ -179,7 +190,7 @@ public interface ScreenshotConfig extends Config keyName = "untradeableDrop", name = "Screenshot Untradeable drops", description = "Configures whether or not screenshots are automatically taken when you receive an untradeable drop.", - position = 13 + position = 14 ) default boolean screenshotUntradeableDrop() { @@ -190,10 +201,10 @@ public interface ScreenshotConfig extends Config keyName = "hotkey", name = "Screenshot hotkey", description = "When you press this key a screenshot will be taken", - position = 14 + position = 15 ) default Keybind hotkey() { return Keybind.NOT_SET; } -} \ No newline at end of file +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 5510a09635..2867e4d9f6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -281,10 +281,15 @@ public class ScreenshotPlugin extends Plugin @Subscribe public void onPlayerDeath(PlayerDeath playerDeath) { - if (playerDeath.getPlayer() == client.getLocalPlayer() && config.screenshotPlayerDeath()) + Player player = playerDeath.getPlayer(); + if (player == client.getLocalPlayer() && config.screenshotPlayerDeath()) { takeScreenshot("Death " + format(new Date())); } + else if ((player.isClanMember() || player.isFriend()) && config.screenshotFriendDeath() && player.getCanvasTilePoly() != null) + { + takeScreenshot("Death " + player.getName() + " " + format(new Date())); + } } @Subscribe From 5057e48d10350d49c05635ff908374b01f4ed31e Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 20 Nov 2019 12:04:25 -0500 Subject: [PATCH 07/43] api: add welcome chat message type Update chat history plugin to check the message type of the welcome message. --- .../src/main/java/net/runelite/api/ChatMessageType.java | 4 ++++ .../client/plugins/chathistory/ChatHistoryPlugin.java | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java b/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java index b4659dfa18..abed95406c 100644 --- a/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java +++ b/runelite-api/src/main/java/net/runelite/api/ChatMessageType.java @@ -148,6 +148,10 @@ public enum ChatMessageType * A message that times out after 10 seconds. */ TENSECTIMEOUT(107), + /** + * The "Welcome to RuneScape" message + */ + WELCOME(108), /** * An unknown message type. */ diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java index 03aa7c2110..63215c772b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java @@ -111,7 +111,8 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener { // Start sending old messages right after the welcome message, as that is most reliable source // of information that chat history was reset - if (chatMessage.getMessage().equals(WELCOME_MESSAGE)) + ChatMessageType chatMessageType = chatMessage.getType(); + if (chatMessageType == ChatMessageType.WELCOME && chatMessage.getMessage().equals(WELCOME_MESSAGE)) { if (!config.retainChatHistory()) { @@ -128,7 +129,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener return; } - switch (chatMessage.getType()) + switch (chatMessageType) { case PRIVATECHATOUT: case PRIVATECHAT: @@ -150,7 +151,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener case FRIENDSCHAT: case CONSOLE: final QueuedMessage queuedMessage = QueuedMessage.builder() - .type(chatMessage.getType()) + .type(chatMessageType) .name(chatMessage.getName()) .sender(chatMessage.getSender()) .value(nbsp(chatMessage.getMessage())) From ebdd3c7fce33020555a71cd590b5e6b5244903fc Mon Sep 17 00:00:00 2001 From: seth Date: Tue, 19 Nov 2019 19:39:59 -0600 Subject: [PATCH 08/43] chathistory: update welcome message matching to include leagues --- .../client/plugins/chathistory/ChatHistoryPlugin.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java index 63215c772b..77fbdd957f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/chathistory/ChatHistoryPlugin.java @@ -50,6 +50,7 @@ import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.Text; +import org.apache.commons.lang3.StringUtils; @PluginDescriptor( name = "Chat History", @@ -58,7 +59,7 @@ import net.runelite.client.util.Text; ) public class ChatHistoryPlugin extends Plugin implements KeyListener { - private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape."; + private static final String WELCOME_MESSAGE = "Welcome to Old School RuneScape"; private static final String CLEAR_HISTORY = "Clear history"; private static final String CLEAR_PRIVATE = "Private:"; private static final int CYCLE_HOTKEY = KeyEvent.VK_TAB; @@ -112,7 +113,7 @@ public class ChatHistoryPlugin extends Plugin implements KeyListener // Start sending old messages right after the welcome message, as that is most reliable source // of information that chat history was reset ChatMessageType chatMessageType = chatMessage.getType(); - if (chatMessageType == ChatMessageType.WELCOME && chatMessage.getMessage().equals(WELCOME_MESSAGE)) + if (chatMessageType == ChatMessageType.WELCOME && StringUtils.startsWithIgnoreCase(chatMessage.getMessage(), WELCOME_MESSAGE)) { if (!config.retainChatHistory()) { From 0e920bdd98f4b8141fea652deaa7bb7b1f726a6a Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 20 Nov 2019 15:43:59 -0500 Subject: [PATCH 09/43] raids plugin: fix matching rotation whitelist Spaces were not being removed from the config values causing the whitelist contains check to fail. Additionally, change the format of the raids whitelist to be newline separated CSV which is not interpreted by GSON as valid JSON, fixing the config service from serializing the whitelist rotation which is adding erroneous quotes around the room names. This also refactors the rotation whitelist display to be a simple yes/no instead of this unused match count logic. Co-authored-by: Alexsuperfly --- .../runelite/client/plugins/raids/Raid.java | 4 +- .../client/plugins/raids/RaidsConfig.java | 2 +- .../client/plugins/raids/RaidsOverlay.java | 11 +- .../client/plugins/raids/RaidsPlugin.java | 55 ++++---- .../client/plugins/raids/RaidsPluginTest.java | 122 ++++++++++++++++++ 5 files changed, 150 insertions(+), 44 deletions(-) create mode 100644 runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/Raid.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/Raid.java index 574dcebb2a..66f303a8ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/Raid.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/Raid.java @@ -30,7 +30,7 @@ import lombok.Getter; import net.runelite.client.plugins.raids.solver.Layout; import net.runelite.client.plugins.raids.solver.Room; -public class Raid +class Raid { @Getter private final RaidRoom[] rooms = new RaidRoom[16]; @@ -38,7 +38,7 @@ public class Raid @Getter private Layout layout; - public void updateLayout(Layout layout) + void updateLayout(Layout layout) { if (layout == null) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java index f92e483eae..10612e483d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsConfig.java @@ -123,7 +123,7 @@ public interface RaidsConfig extends Config position = 8, keyName = "whitelistedRotations", name = "Whitelisted rotations", - description = "Warn when boss rotation doesn't match a whitelisted one. Add rotations like [tekton, muttadile, guardians]" + description = "Warn when boss rotation doesn't match a whitelisted one. Add rotations like: tekton, muttadiles, guardians - each rotation on its own line" ) default String whitelistedRotations() { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java index 3f572adf2a..d9fd379f5c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsOverlay.java @@ -101,14 +101,6 @@ public class RaidsOverlay extends Overlay .color(color) .build()); - int bossMatches = 0; - int bossCount = 0; - - if (config.enableRotationWhitelist()) - { - bossMatches = plugin.getRotationMatches(); - } - for (Room layoutRoom : plugin.getRaid().getLayout().getRooms()) { int position = layoutRoom.getPosition(); @@ -124,13 +116,12 @@ public class RaidsOverlay extends Overlay switch (room.getType()) { case COMBAT: - bossCount++; if (plugin.getRoomWhitelist().contains(room.getName().toLowerCase())) { color = Color.GREEN; } else if (plugin.getRoomBlacklist().contains(room.getName().toLowerCase()) - || config.enableRotationWhitelist() && bossCount > bossMatches) + || config.enableRotationWhitelist() && !plugin.getRotationMatches()) { color = Color.RED; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index f96f9c0a9d..12ded3525a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -24,21 +24,24 @@ */ package net.runelite.client.plugins.raids; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Joiner; import com.google.inject.Binder; import com.google.inject.Provides; import java.io.IOException; import java.text.DecimalFormat; import java.time.Instant; -import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.ScheduledExecutorService; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.inject.Inject; +import lombok.AccessLevel; import lombok.Getter; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.Client; @@ -96,7 +99,6 @@ public class RaidsPlugin extends Plugin private static final String RAID_COMPLETE_MESSAGE = "Congratulations - your raid is complete!"; private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##"); private static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###"); - private static final Pattern ROTATION_REGEX = Pattern.compile("\\[(.*?)]"); private static final String LAYOUT_COMMAND = "!layout"; @Inject @@ -142,17 +144,18 @@ public class RaidsPlugin extends Plugin private ScheduledExecutorService scheduledExecutorService; @Getter - private final ArrayList roomWhitelist = new ArrayList<>(); + private final Set roomWhitelist = new HashSet(); @Getter - private final ArrayList roomBlacklist = new ArrayList<>(); + private final Set roomBlacklist = new HashSet(); @Getter - private final ArrayList rotationWhitelist = new ArrayList<>(); + private final Set rotationWhitelist = new HashSet(); @Getter - private final ArrayList layoutWhitelist = new ArrayList<>(); + private final Set layoutWhitelist = new HashSet(); + @Setter(AccessLevel.PACKAGE) // for the test @Getter private Raid raid; @@ -399,38 +402,28 @@ public class RaidsPlugin extends Plugin } } - private void updateLists() + @VisibleForTesting + void updateLists() { updateList(roomWhitelist, config.whitelistedRooms()); updateList(roomBlacklist, config.blacklistedRooms()); - updateList(rotationWhitelist, config.whitelistedRotations()); updateList(layoutWhitelist, config.whitelistedLayouts()); + + // Update rotation whitelist + rotationWhitelist.clear(); + for (String line : config.whitelistedRotations().split("\\n")) + { + rotationWhitelist.add(line.toLowerCase().replace(" ", "")); + } } - private void updateList(ArrayList list, String input) + private void updateList(Collection list, String input) { list.clear(); - - if (list == rotationWhitelist) - { - Matcher m = ROTATION_REGEX.matcher(input); - while (m.find()) - { - String rotation = m.group(1).toLowerCase(); - - if (!list.contains(rotation)) - { - list.add(rotation); - } - } - } - else - { - list.addAll(Text.fromCSV(input.toLowerCase())); - } + list.addAll(Text.fromCSV(input.toLowerCase())); } - int getRotationMatches() + boolean getRotationMatches() { RaidRoom[] combatRooms = raid.getCombatRooms(); String rotation = Arrays.stream(combatRooms) @@ -438,7 +431,7 @@ public class RaidsPlugin extends Plugin .map(String::toLowerCase) .collect(Collectors.joining(",")); - return rotationWhitelist.contains(rotation) ? combatRooms.length : 0; + return rotationWhitelist.contains(rotation); } private Point findLobbyBase() diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java new file mode 100644 index 0000000000..09c432f7bd --- /dev/null +++ b/runelite-client/src/test/java/net/runelite/client/plugins/raids/RaidsPluginTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2019, Alexsuperfly + * 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.raids; + +import com.google.inject.Guice; +import com.google.inject.Inject; +import com.google.inject.testing.fieldbinder.Bind; +import com.google.inject.testing.fieldbinder.BoundFieldModule; +import java.util.concurrent.ScheduledExecutorService; +import net.runelite.api.Client; +import net.runelite.client.config.ChatColorConfig; +import net.runelite.client.config.RuneLiteConfig; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import org.mockito.junit.MockitoJUnitRunner; + +@RunWith(MockitoJUnitRunner.class) +public class RaidsPluginTest +{ + @Mock + @Bind + Client client; + + @Mock + @Bind + ScheduledExecutorService executor; + + @Mock + @Bind + ChatColorConfig chatColorConfig; + + @Mock + @Bind + RuneLiteConfig runeliteConfig; + + @Mock + @Bind + RaidsConfig raidsConfig; + + @Inject + RaidsPlugin raidsPlugin; + + @Before + public void before() + { + Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this); + when(raidsConfig.whitelistedRooms()).thenReturn(""); + when(raidsConfig.blacklistedRooms()).thenReturn(""); + when(raidsConfig.whitelistedRotations()).thenReturn(""); + when(raidsConfig.whitelistedLayouts()).thenReturn(""); + } + + @Test + public void testRotationWhitelist() + { + when(raidsConfig.whitelistedRotations()).thenReturn("Muttadiles, Tekton, Mystics"); + raidsPlugin.updateLists(); + + final RaidRoom[] raidRooms = new RaidRoom[]{RaidRoom.MUTTADILES, RaidRoom.TEKTON, RaidRoom.MYSTICS}; + Raid raid = mock(Raid.class); + when(raid.getCombatRooms()).thenReturn(raidRooms); + raidsPlugin.setRaid(raid); + + assertTrue(raidsPlugin.getRotationMatches()); + } + + @Test + public void testRotationWhitelistMultiple() + { + when(raidsConfig.whitelistedRotations()).thenReturn("Vanguards, Vespula, Vasa \nMuttadiles, Tekton, Mystics"); + raidsPlugin.updateLists(); + + final RaidRoom[] raidRooms = new RaidRoom[]{RaidRoom.MUTTADILES, RaidRoom.TEKTON, RaidRoom.MYSTICS}; + Raid raid = mock(Raid.class); + when(raid.getCombatRooms()).thenReturn(raidRooms); + raidsPlugin.setRaid(raid); + + assertTrue(raidsPlugin.getRotationMatches()); + } + + @Test + public void testRotationWhitelistBackwards() + { + when(raidsConfig.whitelistedRotations()).thenReturn("muttadiles, tekton, mystics"); + raidsPlugin.updateLists(); + + final RaidRoom[] raidRooms = new RaidRoom[]{RaidRoom.MYSTICS, RaidRoom.TEKTON, RaidRoom.MUTTADILES}; + Raid raid = mock(Raid.class); + when(raid.getCombatRooms()).thenReturn(raidRooms); + raidsPlugin.setRaid(raid); + + assertFalse(raidsPlugin.getRotationMatches()); + } +} From 1078fab4db7064d1ad40f77e0f7fa9e3615aab7f Mon Sep 17 00:00:00 2001 From: seth Date: Sat, 16 Nov 2019 20:11:33 -0600 Subject: [PATCH 10/43] Add kourend home teleport to timers plugin --- .../src/main/java/net/runelite/api/widgets/WidgetID.java | 1 + .../src/main/java/net/runelite/api/widgets/WidgetInfo.java | 1 + .../net/runelite/client/plugins/timers/TeleportWidget.java | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) 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 7c27c4fd9e..d671304d99 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 @@ -732,6 +732,7 @@ public class WidgetID static class StandardSpellBook { static final int LUMBRIDGE_HOME_TELEPORT = 5; + static final int KOUREND_HOME_TELEPORT = 4; } static class AncientSpellBook 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 aa1260990b..3acbdb48cb 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 @@ -468,6 +468,7 @@ public enum WidgetInfo 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_KOUREND_HOME_TELEPORT(WidgetID.SPELLBOOK_GROUP_ID, WidgetID.StandardSpellBook.KOUREND_HOME_TELEPORT), PVP_SKULL_CONTAINER(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SKULL_CONTAINER), PVP_WORLD_SAFE_ZONE(WidgetID.PVP_GROUP_ID, WidgetID.Pvp.SAFE_ZONE), diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java index a5e3c44a2e..24fe28fa25 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timers/TeleportWidget.java @@ -38,7 +38,8 @@ enum TeleportWidget WidgetInfo.SPELL_LUMBRIDGE_HOME_TELEPORT.getId(), WidgetInfo.SPELL_EDGEVILLE_HOME_TELEPORT.getId(), WidgetInfo.SPELL_LUNAR_HOME_TELEPORT.getId(), - WidgetInfo.SPELL_ARCEUUS_HOME_TELEPORT.getId() + WidgetInfo.SPELL_ARCEUUS_HOME_TELEPORT.getId(), + WidgetInfo.SPELL_KOUREND_HOME_TELEPORT.getId() ); private static final Collection MINIGAME_TELEPORT_IDS = ImmutableList.of( WidgetInfo.MINIGAME_TELEPORT_BUTTON.getId() From 546e6abce8e2c6fcaa0a5915e7eccdb93bdedb58 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Thu, 21 Nov 2019 11:32:49 +0000 Subject: [PATCH 11/43] Update Item IDs to 2019-11-21-rev182 --- runelite-api/src/main/java/net/runelite/api/ItemID.java | 1 + runelite-api/src/main/java/net/runelite/api/NullItemID.java | 1 + 2 files changed, 2 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/ItemID.java b/runelite-api/src/main/java/net/runelite/api/ItemID.java index 8b955ca420..c5960611c1 100644 --- a/runelite-api/src/main/java/net/runelite/api/ItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java @@ -11354,5 +11354,6 @@ public final class ItemID public static final int TWISTED_TROUSERS_T1 = 24409; public static final int TWISTED_BOOTS_T1 = 24411; public static final int TWISTED_LEAGUE_BANNER = 24413; + public static final int RUNE_POUCH_L = 24416; /* This file is automatically generated. Do not edit. */ } diff --git a/runelite-api/src/main/java/net/runelite/api/NullItemID.java b/runelite-api/src/main/java/net/runelite/api/NullItemID.java index 91f4b15a8d..47ecf9083f 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullItemID.java @@ -12850,5 +12850,6 @@ public final class NullItemID public static final int NULL_24410 = 24410; public static final int NULL_24412 = 24412; public static final int NULL_24414 = 24414; + public static final int NULL_24415 = 24415; /* This file is automatically generated. Do not edit. */ } From 6ddab7029bc3e554198c6da0caa9e2b728020c7c Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Thu, 21 Nov 2019 11:32:50 +0000 Subject: [PATCH 12/43] Update Item variations to 2019-11-21-rev182 --- runelite-client/src/main/resources/item_variations.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/resources/item_variations.json b/runelite-client/src/main/resources/item_variations.json index 66ef2d3c50..57626614b9 100644 --- a/runelite-client/src/main/resources/item_variations.json +++ b/runelite-client/src/main/resources/item_variations.json @@ -8025,7 +8025,8 @@ ], "rune pouch": [ 12791, - 23650 + 23650, + 24416 ], "nest box": [ 12792, From 5a1883d9d7e6a0052ffda2ff91396cf0a3fdecbd Mon Sep 17 00:00:00 2001 From: 15987632 Date: Tue, 12 Nov 2019 00:21:42 -0500 Subject: [PATCH 13/43] entity hider plugin: add support for hiding pets --- .../src/main/java/net/runelite/api/Client.java | 7 +++++++ .../plugins/entityhider/EntityHiderConfig.java | 13 ++++++++++++- .../plugins/entityhider/EntityHiderPlugin.java | 4 ++++ 3 files changed, 23 insertions(+), 1 deletion(-) 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 88480c9c5b..8ab313e0f1 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1493,6 +1493,13 @@ public interface Client extends GameEngine */ void setNPCsHidden2D(boolean state); + /** + * Sets whether Pets from other players are hidden. + * + * @param state new pet hidden state + */ + void setPetsHidden(boolean state); + /** * Sets whether attacking players or NPCs are hidden. * diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderConfig.java index caca619791..4fdc717182 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderConfig.java @@ -122,6 +122,17 @@ public interface EntityHiderConfig extends Config @ConfigItem( position = 9, + keyName = "hidePets", + name = "Hide Pets", + description = "Configures whether or not other player pets are hidden" + ) + default boolean hidePets() + { + return false; + } + + @ConfigItem( + position = 10, keyName = "hideAttackers", name = "Hide Attackers", description = "Configures whether or not NPCs/players attacking you are hidden" @@ -132,7 +143,7 @@ public interface EntityHiderConfig extends Config } @ConfigItem( - position = 10, + position = 11, keyName = "hideProjectiles", name = "Hide Projectiles", description = "Configures whether or not projectiles are hidden" diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java index 40416c366a..25d6625e49 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/entityhider/EntityHiderPlugin.java @@ -95,6 +95,8 @@ public class EntityHiderPlugin extends Plugin client.setNPCsHidden(config.hideNPCs()); client.setNPCsHidden2D(config.hideNPCs2D()); + client.setPetsHidden(config.hidePets()); + client.setAttackersHidden(config.hideAttackers()); client.setProjectilesHidden(config.hideProjectiles()); @@ -117,6 +119,8 @@ public class EntityHiderPlugin extends Plugin client.setNPCsHidden(false); client.setNPCsHidden2D(false); + client.setPetsHidden(false); + client.setAttackersHidden(false); client.setProjectilesHidden(false); From ff6658f0e970c09c4404e23868bda7c1939d2976 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 21 Nov 2019 17:21:26 -0500 Subject: [PATCH 14/43] api: use region size constant in getRegionOffset --- .../src/main/java/net/runelite/api/coords/WorldPoint.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java index bbacd1914a..e2b57bdbc5 100644 --- a/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java +++ b/runelite-api/src/main/java/net/runelite/api/coords/WorldPoint.java @@ -32,6 +32,7 @@ import java.util.List; import lombok.Value; import net.runelite.api.Client; import static net.runelite.api.Constants.CHUNK_SIZE; +import static net.runelite.api.Constants.REGION_SIZE; import net.runelite.api.Perspective; /** @@ -356,6 +357,6 @@ public class WorldPoint private static int getRegionOffset(final int position) { - return position & 0x3f; + return position & (REGION_SIZE - 1); } } From 8528ba72c6349858b87bc25b150e77307491cd60 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 21 Nov 2019 17:22:41 -0500 Subject: [PATCH 15/43] object indicators: use WorldPoint getRegionX/Y --- .../plugins/objectindicators/ObjectIndicatorsPlugin.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java index 34386b52c4..2e28d778b2 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java @@ -43,7 +43,6 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; -import static net.runelite.api.Constants.REGION_SIZE; import net.runelite.api.DecorativeObject; import net.runelite.api.GameObject; import net.runelite.api.GameState; @@ -325,8 +324,8 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener for (ObjectPoint objectPoint : objectPoints) { - if ((worldPoint.getX() & (REGION_SIZE - 1)) == objectPoint.getRegionX() - && (worldPoint.getY() & (REGION_SIZE - 1)) == objectPoint.getRegionY()) + if (worldPoint.getRegionX() == objectPoint.getRegionX() + && worldPoint.getRegionY() == objectPoint.getRegionY()) { // Transform object to get the name which matches against what we've stored if (objectPoint.getName().equals(getObjectComposition(object.getId()).getName())) @@ -419,8 +418,8 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener final ObjectPoint point = new ObjectPoint( name, regionId, - worldPoint.getX() & (REGION_SIZE - 1), - worldPoint.getY() & (REGION_SIZE - 1), + worldPoint.getRegionX(), + worldPoint.getRegionY(), client.getPlane()); Set objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>()); From 2c5f52e57c15a57db4f91901042955a3640597ac Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 20 Nov 2019 21:31:54 -0500 Subject: [PATCH 16/43] object markers: fix removing markers from multilocs multilocs whose name changed would not be matched if unmarked after the name change due to the name mismatch, use object id instead. --- .../objectindicators/ObjectIndicatorsPlugin.java | 15 ++++++++++++--- .../plugins/objectindicators/ObjectPoint.java | 9 +++++++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java index 2e28d778b2..dad5bd5c52 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectIndicatorsPlugin.java @@ -416,6 +416,7 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener final WorldPoint worldPoint = WorldPoint.fromLocalInstance(client, object.getLocalLocation()); final int regionId = worldPoint.getRegionID(); final ObjectPoint point = new ObjectPoint( + object.getId(), name, regionId, worldPoint.getRegionX(), @@ -424,10 +425,18 @@ public class ObjectIndicatorsPlugin extends Plugin implements KeyListener Set objectPoints = points.computeIfAbsent(regionId, k -> new HashSet<>()); - if (objectPoints.contains(point)) + if (objects.remove(object)) { - objectPoints.remove(point); - objects.remove(object); + // Use object id instead of name to match the object point with this object due to the object name being + // able to change because of multilocs. + if (!objectPoints.removeIf(op -> (op.getId() == -1 || op.getId() == object.getId()) + && op.getRegionX() == worldPoint.getRegionX() + && op.getRegionY() == worldPoint.getRegionY() + && op.getZ() == worldPoint.getPlane())) + { + log.warn("unable to find object point for unmarked object {}", object.getId()); + } + log.debug("Unmarking object: {}", point); } else diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java index 576f0e7c72..ca8786faa3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/objectindicators/ObjectPoint.java @@ -25,11 +25,16 @@ package net.runelite.client.plugins.objectindicators; -import lombok.Value; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; -@Value +@Data +@NoArgsConstructor +@AllArgsConstructor class ObjectPoint { + private int id = -1; private String name; private int regionId; private int regionX; From 6a209b860ca6422e144afd2c0bb06828cadd2000 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 21 Nov 2019 20:00:55 -0500 Subject: [PATCH 17/43] api: refactor to use NameableContainer This uses a nameable container for the friends and ignore lists, and provides the clan manager which inherits from it --- .../java/net/runelite/api/ClanMember.java | 7 --- ...endManager.java => ClanMemberManager.java} | 18 ++++-- .../main/java/net/runelite/api/Client.java | 56 +++---------------- .../main/java/net/runelite/api/Friend.java | 13 ----- .../main/java/net/runelite/api/Ignore.java | 13 ----- .../main/java/net/runelite/api/Nameable.java | 13 +++++ .../net/runelite/api/NameableContainer.java | 50 +++++++++++++++++ 7 files changed, 84 insertions(+), 86 deletions(-) rename runelite-api/src/main/java/net/runelite/api/{FriendManager.java => ClanMemberManager.java} (82%) create mode 100644 runelite-api/src/main/java/net/runelite/api/NameableContainer.java diff --git a/runelite-api/src/main/java/net/runelite/api/ClanMember.java b/runelite-api/src/main/java/net/runelite/api/ClanMember.java index b8082af3d9..3afb7d85d9 100644 --- a/runelite-api/src/main/java/net/runelite/api/ClanMember.java +++ b/runelite-api/src/main/java/net/runelite/api/ClanMember.java @@ -29,13 +29,6 @@ package net.runelite.api; */ public interface ClanMember extends ChatPlayer { - /** - * Gets the username of the member. - * - * @return the username - */ - String getUsername(); - /** * Gets the world the member is in. * diff --git a/runelite-api/src/main/java/net/runelite/api/FriendManager.java b/runelite-api/src/main/java/net/runelite/api/ClanMemberManager.java similarity index 82% rename from runelite-api/src/main/java/net/runelite/api/FriendManager.java rename to runelite-api/src/main/java/net/runelite/api/ClanMemberManager.java index 4bdd5a496f..e618525084 100644 --- a/runelite-api/src/main/java/net/runelite/api/FriendManager.java +++ b/runelite-api/src/main/java/net/runelite/api/ClanMemberManager.java @@ -24,9 +24,19 @@ */ package net.runelite.api; -/** - * Represents the friend and ignore list manager. - */ -public interface FriendManager +public interface ClanMemberManager extends NameableContainer { + /** + * Gets the clan owner of the currently joined clan chat + * + * @return + */ + String getClanOwner(); + + /** + * Gets the clan chat name of the currently joined clan chat + * + * @return + */ + String getClanChatName(); } 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 8ab313e0f1..ea20abdccf 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1111,68 +1111,26 @@ public interface Client extends GameEngine boolean isFriended(String name, boolean mustBeLoggedIn); /** - * Gets the number of players in the clan chat. - * - * @return the number of clan chat members - */ - int getClanChatCount(); - - /** - * Gets an array of players in the clan chat. - * - * @return the clan chat members, null if not in a clan - */ - ClanMember[] getClanMembers(); - - /** - * Gets the clan owner of the currently joined clan chat + * Retrieve the clan member manager * * @return */ - String getClanOwner(); + @Nullable + ClanMemberManager getClanMemberManager(); /** - * Gets the clan chat name of the currently joined clan chat + * Retrieve the nameable container containing friends * * @return */ - String getClanChatName(); + NameableContainer getFriendContainer(); /** - * Gets an array of players in the friends list. - * - * @return the friends list - */ - Friend[] getFriends(); - - /** - * Gets the number of friends on the friends list. + * Retrieve the nameable container containing ignores * * @return */ - int getFriendsCount(); - - /** - * Gets an array of players on the ignore list. - * - * @return - */ - Ignore[] getIgnores(); - - /** - * Gets the number of ignored players on the ignore list. - * - * @return - */ - int getIgnoreCount(); - - /** - * Checks whether a player is in the same clan chat. - * - * @param name the name of the player - * @return true if the player is in clan chat - */ - boolean isClanMember(String name); + NameableContainer getIgnoreContainer(); /** * Gets the clients saved preferences. diff --git a/runelite-api/src/main/java/net/runelite/api/Friend.java b/runelite-api/src/main/java/net/runelite/api/Friend.java index 7b28e18a67..d585767e2f 100644 --- a/runelite-api/src/main/java/net/runelite/api/Friend.java +++ b/runelite-api/src/main/java/net/runelite/api/Friend.java @@ -29,17 +29,4 @@ package net.runelite.api; */ public interface Friend extends ChatPlayer { - /** - * The name of the player. - * - * @return the name - */ - String getName(); - - /** - * The previous name the player had. - * - * @return the previous name - */ - String getPrevName(); } diff --git a/runelite-api/src/main/java/net/runelite/api/Ignore.java b/runelite-api/src/main/java/net/runelite/api/Ignore.java index 52f42e0aaa..e2506ca183 100644 --- a/runelite-api/src/main/java/net/runelite/api/Ignore.java +++ b/runelite-api/src/main/java/net/runelite/api/Ignore.java @@ -29,17 +29,4 @@ package net.runelite.api; */ public interface Ignore extends Nameable { - /** - * The name of the player. - * - * @return the name - */ - String getName(); - - /** - * The previous name the player had. - * - * @return the previous name - */ - String getPrevName(); } diff --git a/runelite-api/src/main/java/net/runelite/api/Nameable.java b/runelite-api/src/main/java/net/runelite/api/Nameable.java index 081074594e..f627d98901 100644 --- a/runelite-api/src/main/java/net/runelite/api/Nameable.java +++ b/runelite-api/src/main/java/net/runelite/api/Nameable.java @@ -29,4 +29,17 @@ package net.runelite.api; */ public interface Nameable extends Comparable { + /** + * The name of the player. + * + * @return the name + */ + String getName(); + + /** + * The previous name the player had. + * + * @return the previous name + */ + String getPrevName(); } diff --git a/runelite-api/src/main/java/net/runelite/api/NameableContainer.java b/runelite-api/src/main/java/net/runelite/api/NameableContainer.java new file mode 100644 index 0000000000..a76bb78891 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/NameableContainer.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019, Adam + * 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.api; + +public interface NameableContainer +{ + /** + * Get the number of members in this container + * + * @return + */ + int getCount(); + + /** + * Get the members in this container + * + * @return + */ + T[] getMembers(); + + /** + * Find a nameable by name + * + * @param name the name + * @return + */ + T findByName(String name); +} From 0b90fcde2293ec82b971bc998e877353b0797df7 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 21 Nov 2019 20:01:17 -0500 Subject: [PATCH 18/43] client: refactor for nameable api changes --- .../net/runelite/client/game/ClanManager.java | 17 ++++--- .../plugins/chatfilter/ChatFilterPlugin.java | 6 ++- .../plugins/clanchat/ClanChatPlugin.java | 44 ++++++++++++------- .../plugins/friendlist/FriendListPlugin.java | 9 +++- .../plugins/hiscore/NameAutocompleter.java | 22 +++++----- .../worldhopper/WorldHopperPlugin.java | 30 +++++-------- .../chatfilter/ChatFilterPluginTest.java | 11 +++-- 7 files changed, 81 insertions(+), 58 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java index 2a88aab050..c71c4a205d 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java @@ -38,6 +38,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberManager; import net.runelite.api.ClanMemberRank; import net.runelite.api.Client; import net.runelite.api.GameState; @@ -79,16 +80,16 @@ public class ClanManager @Override public ClanMemberRank load(@Nonnull String key) { - final ClanMember[] clanMembersArr = client.getClanMembers(); - - if (clanMembersArr == null || clanMembersArr.length == 0) + final ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager == null) { return ClanMemberRank.UNRANKED; } - return Arrays.stream(clanMembersArr) + final ClanMember[] clanMembers = clanMemberManager.getMembers(); + return Arrays.stream(clanMembers) .filter(Objects::nonNull) - .filter(clanMember -> sanitize(clanMember.getUsername()).equals(sanitize(key))) + .filter(clanMember -> sanitize(clanMember.getName()).equals(sanitize(key))) .map(ClanMember::getRank) .findAny() .orElse(ClanMemberRank.UNRANKED); @@ -104,6 +105,12 @@ public class ClanManager this.spriteManager = spriteManager; } + public boolean isClanMember(String name) + { + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + return clanMemberManager != null && clanMemberManager.findByName(name) != null; + } + public ClanMemberRank getRank(String playerName) { return clanRanksCache.getUnchecked(playerName); 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 1e7666ba00..fe8fdb18f4 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 @@ -44,6 +44,7 @@ import net.runelite.api.events.OverheadTextChanged; import net.runelite.api.events.ScriptCallbackEvent; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.ClanManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.Text; @@ -72,6 +73,9 @@ public class ChatFilterPlugin extends Plugin @Inject private ChatFilterConfig config; + @Inject + private ClanManager clanManager; + @Provides ChatFilterConfig provideConfig(ConfigManager configManager) { @@ -176,7 +180,7 @@ public class ChatFilterPlugin extends Plugin boolean isMessageFromSelf = playerName.equals(client.getLocalPlayer().getName()); return !isMessageFromSelf && (config.filterFriends() || !client.isFriended(playerName, false)) && - (config.filterClan() || !client.isClanMember(playerName)); + (config.filterClan() || !clanManager.isClanMember(playerName)); } String censorMessage(final String message) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java index 095295d819..00779cb51c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/clanchat/ClanChatPlugin.java @@ -42,6 +42,7 @@ import javax.inject.Inject; import net.runelite.api.ChatLineBuffer; import net.runelite.api.ChatMessageType; import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberManager; import net.runelite.api.ClanMemberRank; import net.runelite.api.Client; import net.runelite.api.GameState; @@ -55,7 +56,6 @@ import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ClanChanged; import net.runelite.api.events.ClanMemberJoined; import net.runelite.api.events.ClanMemberLeft; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.PlayerDespawned; @@ -69,6 +69,7 @@ import net.runelite.client.callback.ClientThread; import net.runelite.client.chat.ChatMessageBuilder; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.game.ClanManager; import net.runelite.client.game.SpriteManager; import net.runelite.client.plugins.Plugin; @@ -170,7 +171,7 @@ public class ClanChatPlugin extends Plugin if (member.getWorld() == client.getWorld()) { final Player local = client.getLocalPlayer(); - final String memberName = Text.toJagexName(member.getUsername()); + final String memberName = Text.toJagexName(member.getName()); for (final Player player : client.getPlayers()) { @@ -196,15 +197,15 @@ public class ClanChatPlugin extends Plugin } // attempt to filter out world hopping joins - if (!activityBuffer.containsKey(member.getUsername())) + if (!activityBuffer.containsKey(member.getName())) { ClanMemberActivity joinActivity = new ClanMemberActivity(ClanActivityType.JOINED, member, client.getTickCount()); - activityBuffer.put(member.getUsername(), joinActivity); + activityBuffer.put(member.getName(), joinActivity); } else { - activityBuffer.remove(member.getUsername()); + activityBuffer.remove(member.getName()); } } @@ -215,7 +216,7 @@ public class ClanChatPlugin extends Plugin if (member.getWorld() == client.getWorld()) { - final String memberName = Text.toJagexName(member.getUsername()); + final String memberName = Text.toJagexName(member.getName()); final Iterator each = clanMembers.iterator(); while (each.hasNext()) @@ -240,15 +241,15 @@ public class ClanChatPlugin extends Plugin return; } - if (!activityBuffer.containsKey(member.getUsername())) + if (!activityBuffer.containsKey(member.getName())) { ClanMemberActivity leaveActivity = new ClanMemberActivity(ClanActivityType.LEFT, member, client.getTickCount()); - activityBuffer.put(member.getUsername(), leaveActivity); + activityBuffer.put(member.getName(), leaveActivity); } else { - activityBuffer.remove(member.getUsername()); + activityBuffer.remove(member.getName()); } } @@ -265,9 +266,10 @@ public class ClanChatPlugin extends Plugin { Widget clanChatList = client.getWidget(WidgetInfo.CLAN_CHAT_LIST); Widget owner = client.getWidget(WidgetInfo.CLAN_CHAT_OWNER); - if (client.getClanChatCount() > 0) + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager != null && clanMemberManager.getCount() > 0) { - clanChatTitleWidget.setText(CLAN_CHAT_TITLE + " (" + client.getClanChatCount() + "/100)"); + clanChatTitleWidget.setText(CLAN_CHAT_TITLE + " (" + clanMemberManager.getCount() + "/100)"); } else if (config.recentChats() && clanChatList.getChildren() == null && !Strings.isNullOrEmpty(owner.getText())) { @@ -332,6 +334,12 @@ public class ClanChatPlugin extends Plugin private void addClanActivityMessages() { + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager == null || activityBuffer.isEmpty()) + { + return; + } + Iterator activityIt = activityBuffer.values().iterator(); while (activityIt.hasNext()) @@ -341,12 +349,12 @@ public class ClanChatPlugin extends Plugin if (activity.getTick() < client.getTickCount() - MESSAGE_DELAY) { activityIt.remove(); - addActivityMessage(activity.getMember(), activity.getActivityType()); + addActivityMessage(clanMemberManager, activity.getMember(), activity.getActivityType()); } } } - private void addActivityMessage(ClanMember member, ClanActivityType activityType) + private void addActivityMessage(ClanMemberManager clanMemberManager, ClanMember member, ClanActivityType activityType) { final String activityMessage = activityType == ClanActivityType.JOINED ? " has joined." : " has left."; final ClanMemberRank rank = member.getRank(); @@ -367,7 +375,7 @@ public class ClanChatPlugin extends Plugin ChatMessageBuilder message = new ChatMessageBuilder() .append("[") - .append(channelColor, client.getClanChatName()); + .append(channelColor, clanMemberManager.getClanChatName()); if (rankIcon > -1) { message @@ -376,7 +384,7 @@ public class ClanChatPlugin extends Plugin } message .append("] ") - .append(textColor, member.getUsername() + activityMessage); + .append(textColor, member.getName() + activityMessage); final String messageString = message.build(); client.addChatMessage(ChatMessageType.FRIENDSCHATNOTIFICATION, "", messageString, ""); @@ -406,7 +414,8 @@ public class ClanChatPlugin extends Plugin return; } - if (client.getClanChatCount() <= 0) + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager == null || clanMemberManager.getCount() == 0) { return; } @@ -542,7 +551,8 @@ public class ClanChatPlugin extends Plugin return; } - if (client.getClanChatCount() == 0) + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager == null || clanMemberManager.getCount() == 0) { clanChatList.setChildren(null); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/friendlist/FriendListPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/friendlist/FriendListPlugin.java index 355d9db46a..cbe43c0aea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/friendlist/FriendListPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/friendlist/FriendListPlugin.java @@ -27,6 +27,9 @@ package net.runelite.client.plugins.friendlist; import javax.inject.Inject; import net.runelite.api.Client; +import net.runelite.api.Friend; +import net.runelite.api.Ignore; +import net.runelite.api.NameableContainer; import net.runelite.api.VarPlayer; import net.runelite.api.events.GameTick; import net.runelite.api.widgets.Widget; @@ -64,7 +67,8 @@ public class FriendListPlugin extends Plugin final int world = client.getWorld(); final boolean isMember = client.getVar(VarPlayer.MEMBERSHIP_DAYS) > 0; - final int friendCount = client.getFriendsCount(); + final NameableContainer friendContainer = client.getFriendContainer(); + final int friendCount = friendContainer.getCount(); if (friendCount >= 0) { final int limit = isMember ? MAX_FRIENDS_P2P : MAX_FRIENDS_F2P; @@ -80,7 +84,8 @@ public class FriendListPlugin extends Plugin setFriendsListTitle(title); } - final int ignoreCount = client.getIgnoreCount(); + final NameableContainer ignoreContainer = client.getIgnoreContainer(); + final int ignoreCount = ignoreContainer.getCount(); if (ignoreCount >= 0) { final int limit = isMember ? MAX_IGNORES_P2P : MAX_IGNORES_F2P; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java index 6dcaaecf83..e89cbb2a8d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/hiscore/NameAutocompleter.java @@ -37,9 +37,11 @@ import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import lombok.extern.slf4j.Slf4j; -import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; import net.runelite.api.Friend; +import net.runelite.api.Nameable; +import net.runelite.api.NameableContainer; import net.runelite.api.Player; @Slf4j @@ -191,12 +193,11 @@ class NameAutocompleter implements KeyListener // TODO: Search lookup history - Friend[] friends = client.getFriends(); - if (friends != null) + NameableContainer friendContainer = client.getFriendContainer(); + if (friendContainer != null) { - autocompleteName = Arrays.stream(friends) - .filter(Objects::nonNull) - .map(Friend::getName) + autocompleteName = Arrays.stream(friendContainer.getMembers()) + .map(Nameable::getName) .filter(n -> pattern.matcher(n).matches()) .findFirst(); } @@ -204,12 +205,11 @@ class NameAutocompleter implements KeyListener // Search clan if a friend wasn't found if (!autocompleteName.isPresent()) { - final ClanMember[] clannies = client.getClanMembers(); - if (clannies != null) + final ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager != null) { - autocompleteName = Arrays.stream(clannies) - .filter(Objects::nonNull) - .map(ClanMember::getUsername) + autocompleteName = Arrays.stream(clanMemberManager.getMembers()) + .map(Nameable::getName) .filter(n -> pattern.matcher(n).matches()) .findFirst(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index 22d063c537..5e397a23f8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -52,14 +52,15 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.api.ChatMessageType; import net.runelite.api.ChatPlayer; import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberManager; import net.runelite.api.Client; import net.runelite.api.Friend; import net.runelite.api.GameState; import net.runelite.api.MenuAction; import net.runelite.api.MenuEntry; +import net.runelite.api.NameableContainer; import net.runelite.api.Varbits; import net.runelite.api.events.ChatMessage; -import net.runelite.client.events.ConfigChanged; import net.runelite.api.events.GameStateChanged; import net.runelite.api.events.GameTick; import net.runelite.api.events.MenuEntryAdded; @@ -74,6 +75,7 @@ import net.runelite.client.chat.ChatMessageManager; import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -756,30 +758,20 @@ public class WorldHopperPlugin extends Plugin // Search clan members first, because if a friend is in the clan chat but their private // chat is 'off', then the hop-to option will not get shown in the menu (issue #5679). - ClanMember[] clanMembers = client.getClanMembers(); - - if (clanMembers != null) + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager != null) { - for (ClanMember clanMember : clanMembers) + ClanMember clanMember = clanMemberManager.findByName(cleanName); + if (clanMember != null) { - if (clanMember != null && clanMember.getUsername().equals(cleanName)) - { - return clanMember; - } + return clanMember; } } - Friend[] friends = client.getFriends(); - - if (friends != null) + NameableContainer friendContainer = client.getFriendContainer(); + if (friendContainer != null) { - for (Friend friend : friends) - { - if (friend != null && friend.getName().equals(cleanName)) - { - return friend; - } - } + return friendContainer.findByName(cleanName); } return null; 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 9af09b1d63..949bac892d 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 @@ -31,6 +31,7 @@ import com.google.inject.testing.fieldbinder.BoundFieldModule; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.Player; +import net.runelite.client.game.ClanManager; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -53,6 +54,10 @@ public class ChatFilterPluginTest @Bind private ChatFilterConfig chatFilterConfig; + @Mock + @Bind + private ClanManager clanManager; + @Mock private Player localPlayer; @@ -132,7 +137,7 @@ public class ChatFilterPluginTest @Test public void testMessageFromFriendIsFiltered() { - when(client.isClanMember("Iron Mammal")).thenReturn(false); + when(clanManager.isClanMember("Iron Mammal")).thenReturn(false); when(chatFilterConfig.filterFriends()).thenReturn(true); assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Iron Mammal")); } @@ -156,7 +161,7 @@ public class ChatFilterPluginTest @Test public void testMessageFromClanIsNotFiltered() { - when(client.isClanMember("B0aty")).thenReturn(true); + when(clanManager.isClanMember("B0aty")).thenReturn(true); when(chatFilterConfig.filterClan()).thenReturn(false); assertFalse(chatFilterPlugin.shouldFilterPlayerMessage("B0aty")); } @@ -172,7 +177,7 @@ public class ChatFilterPluginTest public void testMessageFromNonFriendNonClanIsFiltered() { when(client.isFriended("Woox", false)).thenReturn(false); - when(client.isClanMember("Woox")).thenReturn(false); + when(clanManager.isClanMember("Woox")).thenReturn(false); assertTrue(chatFilterPlugin.shouldFilterPlayerMessage("Woox")); } } \ No newline at end of file From 9e6eb370b4c9fad11768abc8646e92d24971dd37 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 21 Nov 2019 20:31:05 -0500 Subject: [PATCH 19/43] clan manager: use clanmember manager find to lookup rank --- .../java/net/runelite/client/game/ClanManager.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java index c71c4a205d..7ac318243e 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ClanManager.java @@ -31,7 +31,6 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.util.Arrays; -import java.util.Objects; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -86,13 +85,8 @@ public class ClanManager return ClanMemberRank.UNRANKED; } - final ClanMember[] clanMembers = clanMemberManager.getMembers(); - return Arrays.stream(clanMembers) - .filter(Objects::nonNull) - .filter(clanMember -> sanitize(clanMember.getName()).equals(sanitize(key))) - .map(ClanMember::getRank) - .findAny() - .orElse(ClanMemberRank.UNRANKED); + ClanMember clanMember = clanMemberManager.findByName(sanitize(key)); + return clanMember != null ? clanMember.getRank() : ClanMemberRank.UNRANKED; } }); From 37bf35087d6bc1e4dcdb4e6955e38e5d3e351e34 Mon Sep 17 00:00:00 2001 From: Jay <35314154+GiantFrog@users.noreply.github.com> Date: Fri, 22 Nov 2019 08:07:22 -0700 Subject: [PATCH 20/43] music plugin: reclassify teleport sfx as other players' area effects instead of environmental area effects --- .../runelite/client/plugins/music/MusicPlugin.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java index 3aca086669..812eb86959 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/music/MusicPlugin.java @@ -25,10 +25,12 @@ */ package net.runelite.client.plugins.music; +import com.google.common.collect.ImmutableSet; import com.google.inject.Provides; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.Set; import java.util.function.BiConsumer; import java.util.function.ToIntFunction; import java.util.stream.Collectors; @@ -76,6 +78,10 @@ import net.runelite.client.plugins.PluginDescriptor; ) public class MusicPlugin extends Plugin { + private static final Set SOURCELESS_PLAYER_SOUNDS = ImmutableSet.of( + SoundEffectID.TELEPORT_VWOOP + ); + @Inject private Client client; @@ -558,13 +564,14 @@ public class MusicPlugin extends Plugin public void onAreaSoundEffectPlayed(AreaSoundEffectPlayed areaSoundEffectPlayed) { Actor source = areaSoundEffectPlayed.getSource(); + int soundId = areaSoundEffectPlayed.getSoundId(); if (source == client.getLocalPlayer() && musicConfig.muteOwnAreaSounds()) { areaSoundEffectPlayed.consume(); } else if (source != client.getLocalPlayer() - && source instanceof Player + && (source instanceof Player || (source == null && SOURCELESS_PLAYER_SOUNDS.contains(soundId))) && musicConfig.muteOtherAreaSounds()) { areaSoundEffectPlayed.consume(); @@ -575,9 +582,10 @@ public class MusicPlugin extends Plugin areaSoundEffectPlayed.consume(); } else if (source == null + && !SOURCELESS_PLAYER_SOUNDS.contains(soundId) && musicConfig.muteEnvironmentAreaSounds()) { areaSoundEffectPlayed.consume(); } } -} \ No newline at end of file +} From e724f9a41996106bc82567d02e2788535566136e Mon Sep 17 00:00:00 2001 From: Austin Lee Date: Sat, 23 Nov 2019 03:02:42 -0800 Subject: [PATCH 21/43] Add Bird Houses to crafting skill calculator (#10306) --- .../skillcalculator/skill_crafting.json | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_crafting.json b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_crafting.json index 963c56f382..655703639f 100644 --- a/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_crafting.json +++ b/runelite-client/src/main/resources/net/runelite/client/plugins/skillcalculator/skill_crafting.json @@ -48,6 +48,12 @@ "name": "Gold Ring", "xp": 15 }, + { + "level": 5, + "icon": 21512, + "name": "Bird House", + "xp": 15 + }, { "level": 6, "icon": 1654, @@ -120,6 +126,12 @@ "name": "Leather Body", "xp": 25 }, + { + "level": 15, + "icon": 21515, + "name": "Oak Bird House", + "xp": 20 + }, { "level": 16, "icon": 1613, @@ -217,6 +229,12 @@ "name": "Jade Necklace", "xp": 54 }, + { + "level": 25, + "icon": 21518, + "name": "Willow Bird House", + "xp": 25 + }, { "level": 26, "icon": 6209, @@ -319,6 +337,12 @@ "name": "Broodoo shield", "xp": 100 }, + { + "level": 35, + "icon": 21521, + "name": "Teak Bird House", + "xp": 30 + }, { "level": 36, "icon": 5376, @@ -385,6 +409,12 @@ "name": "Snakeskin boots", "xp": 30 }, + { + "level": 45, + "icon": 22192, + "name": "Maple Bird House", + "xp": 35 + }, { "level": 46, "icon": 567, @@ -415,6 +445,12 @@ "name": "Ruby Amulet (U)", "xp": 85 }, + { + "level": 50, + "icon": 22195, + "name": "Mahogany Bird House", + "xp": 40 + }, { "level": 51, "icon": 6324, @@ -481,6 +517,12 @@ "name": "Green D'hide Chaps", "xp": 124 }, + { + "level": 60, + "icon": 22198, + "name": "Yew Bird House", + "xp": 45 + }, { "level": 62, "icon": 1393, @@ -571,6 +613,12 @@ "name": "Red D'hide Chaps", "xp": 156 }, + { + "level": 75, + "icon": 22201, + "name": "Magic Bird House", + "xp": 50 + }, { "level": 76, "icon": 22281, @@ -667,6 +715,12 @@ "name": "Onyx Amulet (U)", "xp": 165 }, + { + "level": 90, + "icon": 22204, + "name": "Redwood Bird House", + "xp": 55 + }, { "level": 92, "icon": 19535, @@ -686,4 +740,4 @@ "xp": 200 } ] -} +} \ No newline at end of file From 643a77ad26202f487eff4fcd2004e73f1cc68d02 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 23 Nov 2019 16:24:02 -0500 Subject: [PATCH 22/43] client: add backup jav_config support --- .../runelite/client/RuneLiteProperties.java | 12 ++++ .../client/rs/ClientConfigLoader.java | 10 +-- .../net/runelite/client/rs/ClientLoader.java | 64 ++++++++++++++----- .../java/net/runelite/client/rs/RSConfig.java | 10 +++ .../net/runelite/client/runelite.properties | 2 + 5 files changed, 73 insertions(+), 25 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java index a1ff15e2eb..60355dee62 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteProperties.java @@ -43,6 +43,8 @@ public class RuneLiteProperties private static final String TROUBLESHOOTING_LINK = "runelite.wiki.troubleshooting.link"; private static final String BUILDING_LINK = "runelite.wiki.building.link"; private static final String DNS_CHANGE_LINK = "runelite.dnschange.link"; + private static final String JAV_CONFIG = "runelite.jav_config"; + private static final String JAV_CONFIG_BACKUP = "runelite.jav_config_backup"; private static final Properties properties = new Properties(); @@ -118,4 +120,14 @@ public class RuneLiteProperties { return properties.getProperty(DNS_CHANGE_LINK); } + + public static String getJavConfig() + { + return properties.getProperty(JAV_CONFIG); + } + + public static String getJavConfigBackup() + { + return properties.getProperty(JAV_CONFIG_BACKUP); + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java index ed105ec830..19c612bd0e 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientConfigLoader.java @@ -39,16 +39,8 @@ class ClientConfigLoader { } - private static final String CONFIG_URL = "http://oldschool.runescape.com/jav_config.ws"; - - static RSConfig fetch(String host) throws IOException + static RSConfig fetch(HttpUrl url) throws IOException { - HttpUrl url = HttpUrl.parse(CONFIG_URL); - if (host != null) - { - url = url.newBuilder().host(host).build(); - } - final Request request = new Request.Builder() .url(url) .build(); diff --git a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java index 6a5067561c..1dd110dc68 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/ClientLoader.java @@ -57,6 +57,7 @@ import javax.swing.SwingUtilities; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.client.RuneLite; +import net.runelite.client.RuneLiteProperties; import static net.runelite.client.rs.ClientUpdateCheckMode.AUTO; import static net.runelite.client.rs.ClientUpdateCheckMode.NONE; import static net.runelite.client.rs.ClientUpdateCheckMode.VANILLA; @@ -154,32 +155,55 @@ public class ClientLoader implements Supplier private void downloadConfig() throws IOException { - String host = null; - for (int attempt = 0; ; attempt++) + HttpUrl url = HttpUrl.parse(RuneLiteProperties.getJavConfig()); + IOException err = null; + for (int attempt = 0; attempt < NUM_ATTEMPTS; attempt++) { try { - config = ClientConfigLoader.fetch(host); + config = ClientConfigLoader.fetch(url); if (Strings.isNullOrEmpty(config.getCodeBase()) || Strings.isNullOrEmpty(config.getInitialJar()) || Strings.isNullOrEmpty(config.getInitialClass())) { throw new IOException("Invalid or missing jav_config"); } - break; + return; } catch (IOException e) { - log.info("Failed to get jav_config from host \"{}\" ({})", host, e.getMessage()); - - if (attempt >= NUM_ATTEMPTS) - { - throw e; - } - - host = hostSupplier.get(); + log.info("Failed to get jav_config from host \"{}\" ({})", url.host(), e.getMessage()); + String host = hostSupplier.get(); + url = url.newBuilder().host(host).build(); + err = e; } } + + log.info("Falling back to backup client config"); + + try + { + RSConfig backupConfig = ClientConfigLoader.fetch(HttpUrl.parse(RuneLiteProperties.getJavConfigBackup())); + + if (Strings.isNullOrEmpty(backupConfig.getCodeBase()) || Strings.isNullOrEmpty(backupConfig.getInitialJar()) || Strings.isNullOrEmpty(backupConfig.getInitialClass())) + { + throw new IOException("Invalid or missing jav_config"); + } + + if (Strings.isNullOrEmpty(backupConfig.getRuneLiteGamepack())) + { + throw new IOException("Backup config does not have RuneLite gamepack url"); + } + + // Randomize the codebase + String codebase = hostSupplier.get(); + backupConfig.setCodebase("http://" + codebase + "/"); + config = backupConfig; + } + catch (IOException ex) + { + throw err; // use error from Jagex's servers + } } private void updateVanilla() throws IOException, VerificationException @@ -217,10 +241,18 @@ public class ClientLoader implements Supplier vanilla.position(0); // Start downloading the vanilla client - - String codebase = config.getCodeBase(); - String initialJar = config.getInitialJar(); - HttpUrl url = HttpUrl.parse(codebase + initialJar); + HttpUrl url; + if (config.getRuneLiteGamepack() != null) + { + // If we are using the backup config, use our own gamepack and ignore the codebase + url = HttpUrl.parse(config.getRuneLiteGamepack()); + } + else + { + String codebase = config.getCodeBase(); + String initialJar = config.getInitialJar(); + url = HttpUrl.parse(codebase + initialJar); + } for (int attempt = 0; ; attempt++) { diff --git a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java index e0c5539323..a9841755b9 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/RSConfig.java @@ -40,6 +40,11 @@ class RSConfig return classLoaderProperties.get("codebase"); } + void setCodebase(String codebase) + { + classLoaderProperties.put("codebase", codebase); + } + String getInitialJar() { return classLoaderProperties.get("initial_jar"); @@ -49,4 +54,9 @@ class RSConfig { return classLoaderProperties.get("initial_class").replace(".class", ""); } + + String getRuneLiteGamepack() + { + return classLoaderProperties.get("runelite.gamepack"); + } } diff --git a/runelite-client/src/main/resources/net/runelite/client/runelite.properties b/runelite-client/src/main/resources/net/runelite/client/runelite.properties index c29c1e8e39..b9ea63fae9 100644 --- a/runelite-client/src/main/resources/net/runelite/client/runelite.properties +++ b/runelite-client/src/main/resources/net/runelite/client/runelite.properties @@ -9,3 +9,5 @@ runelite.patreon.link=https://www.patreon.com/runelite runelite.wiki.troubleshooting.link=https://github.com/runelite/runelite/wiki/Troubleshooting-problems-with-the-client runelite.wiki.building.link=https://github.com/runelite/runelite/wiki/Building-with-IntelliJ-IDEA#client-failing-to-start runelite.dnschange.link=https://1.1.1.1/dns/ +runelite.jav_config=http://oldschool.runescape.com/jav_config.ws +runelite.jav_config_backup=http://static.runelite.net/jav_config.ws From 6f5a719cfb59243bd6268cf0d164911e2f219892 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 23 Nov 2019 16:52:09 -0500 Subject: [PATCH 23/43] world client: always return non null or throw an error --- .../net/runelite/http/api/worlds/WorldClient.java | 2 +- .../plugins/defaultworld/DefaultWorldPlugin.java | 7 ------- .../plugins/worldhopper/WorldHopperPlugin.java | 12 ++++-------- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java b/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java index 8e08d0c9b1..b9d84eefd9 100644 --- a/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java +++ b/http-api/src/main/java/net/runelite/http/api/worlds/WorldClient.java @@ -67,7 +67,7 @@ public class WorldClient if (!response.isSuccessful()) { logger.debug("Error looking up worlds: {}", response); - return null; + throw new IOException("unsuccessful response looking up worlds"); } InputStream in = response.body().byteStream(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java index 1f97074772..eed2830ae1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java @@ -119,13 +119,6 @@ public class DefaultWorldPlugin extends Plugin try { final WorldResult worldResult = worldClient.lookupWorlds(); - - if (worldResult == null) - { - log.warn("Failed to lookup worlds."); - return; - } - final World world = worldResult.findWorld(correctedWorld); if (world != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index 5e397a23f8..98c8e39a27 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -514,14 +514,10 @@ public class WorldHopperPlugin extends Plugin try { WorldResult worldResult = worldClient.lookupWorlds(); - - if (worldResult != null) - { - worldResult.getWorlds().sort(Comparator.comparingInt(World::getId)); - this.worldResult = worldResult; - this.lastFetch = Instant.now(); - updateList(); - } + worldResult.getWorlds().sort(Comparator.comparingInt(World::getId)); + this.worldResult = worldResult; + this.lastFetch = Instant.now(); + updateList(); } catch (IOException ex) { From b273e9f46486c198e08cdeb2feaa641ddf0dbb1a Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 23 Nov 2019 18:55:45 -0500 Subject: [PATCH 24/43] client: use mock webserver for client config loader test --- runelite-client/pom.xml | 6 ++ .../client/rs/ClientConfigLoaderTest.java | 49 +++++++++----- .../net/runelite/client/rs/jav_config.ws | 65 +++++++++++++++++++ 3 files changed, 103 insertions(+), 17 deletions(-) create mode 100644 runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index a07335788e..2c162879a0 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -232,6 +232,12 @@ ${guice.version} test + + com.squareup.okhttp3 + mockwebserver + 3.7.0 + test + diff --git a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java index 436c2c2bea..c2c3d3a87e 100644 --- a/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java +++ b/runelite-client/src/test/java/net/runelite/client/rs/ClientConfigLoaderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2017, Adam + * Copyright (c) 2016-2019, Adam * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,34 +22,49 @@ * (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.rs; +import com.google.common.base.Charsets; +import com.google.common.io.CharStreams; import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import org.junit.After; +import static org.junit.Assert.assertEquals; +import org.junit.Before; import org.junit.Test; -/** - * - * @author Adam - */ public class ClientConfigLoaderTest { - @Test - public void test() throws IOException + private final MockWebServer server = new MockWebServer(); + + @Before + public void before() throws IOException { - final RSConfig config = ClientConfigLoader.fetch(null); - - for (String key : config.getClassLoaderProperties().keySet()) + String response; + try (InputStream in = getClass().getResourceAsStream("jav_config.ws")) { - System.out.println(key + ": " + config.getClassLoaderProperties().get(key)); + response = CharStreams.toString(new InputStreamReader( + in, Charsets.UTF_8)); } + server.enqueue(new MockResponse().setBody(response)); - System.out.println("Applet properties:"); + server.start(); + } - for (String key : config.getAppletProperties().keySet()) - { - System.out.println(key + ": " + config.getAppletProperties().get(key)); - } + @After + public void after() throws IOException + { + server.shutdown(); + } + + @Test + public void testFetch() throws IOException + { + final RSConfig config = ClientConfigLoader.fetch(server.url("/")); + assertEquals("http://oldschool1.runescape.com/", config.getCodeBase()); } } diff --git a/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws b/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws new file mode 100644 index 0000000000..c85ff07cb3 --- /dev/null +++ b/runelite-client/src/test/resources/net/runelite/client/rs/jav_config.ws @@ -0,0 +1,65 @@ +title=Old School RuneScape +adverturl=http://www.runescape.com/g=oldscape/bare_advert.ws +codebase=http://oldschool1.runescape.com/ +cachedir=oldschool +storebase=0 +initial_jar=gamepack_6140455.jar +initial_class=client.class +termsurl=http://www.jagex.com/g=oldscape/terms/terms.ws +privacyurl=http://www.jagex.com/g=oldscape/privacy/privacy.ws +viewerversion=124 +win_sub_version=1 +mac_sub_version=2 +other_sub_version=2 +browsercontrol_win_x86_jar=browsercontrol_0_-1928975093.jar +browsercontrol_win_amd64_jar=browsercontrol_1_1674545273.jar +download=1276414 +window_preferredwidth=800 +window_preferredheight=600 +advert_height=96 +applet_minwidth=765 +applet_minheight=503 +applet_maxwidth=5760 +applet_maxheight=2160 +msg=lang0=English +msg=tandc=This game is copyright © 1999 - 2019 Jagex Ltd.\Use of this game is subject to our ["http://www.runescape.com/terms/terms.ws"Terms and Conditions] and ["http://www.runescape.com/privacy/privacy.ws"Privacy Policy]. +msg=options=Options +msg=language=Language +msg=changes_on_restart=Your changes will take effect when you next start this program. +msg=loading_app_resources=Loading application resources +msg=err_verify_bc64=Unable to verify browsercontrol64 +msg=err_verify_bc=Unable to verify browsercontrol +msg=err_load_bc=Unable to load browsercontrol +msg=loading_app=Loading application +msg=err_create_target=Unable to create target applet +msg=err_create_advertising=Unable to create advertising +msg=err_save_file=Error saving file +msg=err_downloading=Error downloading +msg=ok=OK +msg=cancel=Cancel +msg=message=Message +msg=copy_paste_url=Please copy and paste the following URL into your web browser +msg=information=Information +msg=err_get_file=Error getting file +msg=new_version=Update available! You can now launch the client directly from the OldSchool website.\nGet the new version from the link on the OldSchool homepage: http://oldschool.runescape.com/ +msg=new_version_linktext=Open OldSchool Homepage +msg=new_version_link=http://oldschool.runescape.com/ +param=14=0 +param=12=301 +param=11=https://auth.jagex.com/ +param=13=.runescape.com +param=3=false +param=6=0 +param=7=0 +param=9=ElZAIrq5NpKN6D3mDdihco3oPeYN2KFy2DCquj7JMmECPmLrDP3Bnw +param=15=0 +param=10=5 +param=8=true +param=17=http://www.runescape.com/g=oldscape/slr.ws?order=LPWM +param=2=https://payments.jagex.com/operator/v1/ +param=18= +param=4=45569 +param=1=1 +param=19=196515767263-1oo20deqm6edn7ujlihl6rpadk9drhva.apps.googleusercontent.com +param=16=false +param=5=0 From 2884e379272c564acf46f10eb8cf9e123e3eac77 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 23 Nov 2019 23:10:42 -0500 Subject: [PATCH 25/43] hostsupplier: only supply regular f2p or p2p worlds --- .../src/main/java/net/runelite/client/rs/HostSupplier.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java b/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java index cd75157ac1..d9fb0f8509 100644 --- a/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java +++ b/runelite-client/src/main/java/net/runelite/client/rs/HostSupplier.java @@ -27,6 +27,7 @@ package net.runelite.client.rs; import java.io.IOException; import java.util.ArrayDeque; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Queue; import java.util.Random; @@ -36,6 +37,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.worlds.World; import net.runelite.http.api.worlds.WorldClient; +import net.runelite.http.api.worlds.WorldType; @Slf4j class HostSupplier implements Supplier @@ -57,6 +59,7 @@ class HostSupplier implements Supplier .lookupWorlds() .getWorlds() .stream() + .filter(w -> w.getTypes().isEmpty() || EnumSet.of(WorldType.MEMBERS).equals(w.getTypes())) .map(World::getAddress) .collect(Collectors.toList()); From c117bc9bd52c537a5191c96eb5244207c97ca6fc Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 13:07:22 -0500 Subject: [PATCH 26/43] chat controller: limit layouts to 16 rooms --- .../java/net/runelite/http/service/chat/ChatController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java index 15381845b5..ccba9db430 100644 --- a/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java +++ b/http-service/src/main/java/net/runelite/http/service/chat/ChatController.java @@ -47,6 +47,7 @@ public class ChatController { private static final Pattern STRING_VALIDATION = Pattern.compile("[^a-zA-Z0-9' -]"); private static final int STRING_MAX_LENGTH = 50; + private static final int MAX_LAYOUT_ROOMS = 16; private final Cache killCountCache = CacheBuilder.newBuilder() .expireAfterWrite(2, TimeUnit.MINUTES) @@ -214,6 +215,11 @@ public class ChatController @PostMapping("/layout") public void submitLayout(@RequestParam String name, @RequestBody LayoutRoom[] rooms) { + if (rooms.length > MAX_LAYOUT_ROOMS) + { + return; + } + chatService.setLayout(name, rooms); } From 6d6647a43f94f3cab2f47d6ba3bec9737596a5b6 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 13:11:09 -0500 Subject: [PATCH 27/43] raids plugin: limit layout message to 300 characters --- .../net/runelite/client/plugins/raids/RaidsPlugin.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java index 12ded3525a..cdeabce0a9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/raids/RaidsPlugin.java @@ -100,6 +100,7 @@ public class RaidsPlugin extends Plugin private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("###.##"); private static final DecimalFormat POINTS_FORMAT = new DecimalFormat("#,###"); private static final String LAYOUT_COMMAND = "!layout"; + private static final int MAX_LAYOUT_LEN = 300; @Inject private ChatMessageManager chatMessageManager; @@ -637,6 +638,12 @@ public class RaidsPlugin extends Plugin .map(RaidRoom::getName) .toArray()); + if (layoutMessage.length() > MAX_LAYOUT_LEN) + { + log.debug("layout message too long! {}", layoutMessage.length()); + return; + } + String response = new ChatMessageBuilder() .append(ChatColorType.HIGHLIGHT) .append("Layout: ") From 3ad56130e5867086f5eaf0f0e60544191f12c77b Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 14:17:01 -0500 Subject: [PATCH 28/43] api: add npc composition isInteractible --- .../src/main/java/net/runelite/api/NPCComposition.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/NPCComposition.java b/runelite-api/src/main/java/net/runelite/api/NPCComposition.java index c058ca57cd..d61ef4b670 100644 --- a/runelite-api/src/main/java/net/runelite/api/NPCComposition.java +++ b/runelite-api/src/main/java/net/runelite/api/NPCComposition.java @@ -48,6 +48,12 @@ public interface NPCComposition boolean isClickable(); + /** + * NPC can be interacting with via menu options + * @return + */ + boolean isInteractible(); + /** * Gets whether the NPC is visible on the mini-map. */ From 5f18b32976ee888733c6358cfcc798d84313e144 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 14:17:11 -0500 Subject: [PATCH 29/43] npc highlight: skip noninteractiable npcs --- .../plugins/npchighlight/NpcSceneOverlay.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java index 66b4a97224..d6bb1268ea 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java @@ -145,17 +145,17 @@ public class NpcSceneOverlay extends Overlay private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color) { + NPCComposition npcComposition = actor.getTransformedComposition(); + if (npcComposition == null || !npcComposition.isVisible()) + { + return; + } + switch (config.renderStyle()) { case SOUTH_WEST_TILE: { - int size = 1; - NPCComposition composition = actor.getTransformedComposition(); - if (composition != null) - { - size = composition.getSize(); - } - + int size = npcComposition.getSize(); LocalPoint localPoint = actor.getLocalLocation(); int x = localPoint.getX() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); @@ -167,12 +167,7 @@ public class NpcSceneOverlay extends Overlay break; } case TILE: - int size = 1; - NPCComposition composition = actor.getTransformedComposition(); - if (composition != null) - { - size = composition.getSize(); - } + int size = npcComposition.getSize(); LocalPoint lp = actor.getLocalLocation(); Polygon tilePoly = Perspective.getCanvasTileAreaPoly(client, lp, size); From 6dc9d9dc8876b49d0c34438e85169715e301c5e8 Mon Sep 17 00:00:00 2001 From: chestnut1693 Date: Tue, 26 Nov 2019 13:48:16 +0100 Subject: [PATCH 30/43] loottracker plugin: fix typo --- .../runelite/client/plugins/loottracker/LootTrackerConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java index 55fee8a6c4..77c31694e8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loottracker/LootTrackerConfig.java @@ -82,7 +82,7 @@ public interface LootTrackerConfig extends Config @ConfigItem( keyName = "syncPanel", name = "Synchronize panel contents", - description = "Synchronize you local loot tracker with your online (requires being logged in). This means" + + description = "Synchronize your local loot tracker with your online (requires being logged in). This means" + " that panel is filled with portion of your remote data on startup and deleting data in panel deletes them" + " also on server." ) From 1d344df411d41c42e7ad179bd1c5859c9578923b Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 26 Nov 2019 10:13:09 -0500 Subject: [PATCH 31/43] npc highlight: fix npc interactible check isVisible is actually the draw priority and is not what we want here --- .../runelite/client/plugins/npchighlight/NpcSceneOverlay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java index d6bb1268ea..b1a5ed8ada 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java @@ -146,7 +146,7 @@ public class NpcSceneOverlay extends Overlay private void renderNpcOverlay(Graphics2D graphics, NPC actor, Color color) { NPCComposition npcComposition = actor.getTransformedComposition(); - if (npcComposition == null || !npcComposition.isVisible()) + if (npcComposition == null || !npcComposition.isInteractible()) { return; } From d936a23894da46ad89513664d891970ea721165d Mon Sep 17 00:00:00 2001 From: Austin Lee Date: Tue, 26 Nov 2019 23:58:10 -0800 Subject: [PATCH 32/43] Add support for rune pouch (l) to rune pouch overlay (#10331) --- .../net/runelite/client/plugins/runepouch/RunepouchOverlay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 91b4e9c6fa..8b8131cb7d 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 @@ -76,7 +76,7 @@ public class RunepouchOverlay extends WidgetItemOverlay @Override public void renderItemOverlay(Graphics2D graphics, int itemId, WidgetItem itemWidget) { - if (itemId != ItemID.RUNE_POUCH) + if (itemId != ItemID.RUNE_POUCH && itemId != ItemID.RUNE_POUCH_L) { return; } From 93b042a5d0cc090f3a607a1a6de4f68bbc9fd086 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 09:41:11 -0500 Subject: [PATCH 33/43] keyremapping: only update chatbox input and not player name --- .../keyremapping/KeyRemappingPlugin.java | 30 +++++++------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/keyremapping/KeyRemappingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/keyremapping/KeyRemappingPlugin.java index b1edacd3da..c2b2ee146f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/keyremapping/KeyRemappingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/keyremapping/KeyRemappingPlugin.java @@ -1,4 +1,4 @@ -/*' +/* * Copyright (c) 2018, Adam * Copyright (c) 2018, Abexlry * All rights reserved. @@ -33,7 +33,6 @@ import lombok.Getter; import lombok.Setter; import net.runelite.api.Client; import net.runelite.api.GameState; -import net.runelite.api.IconID; import net.runelite.api.VarClientInt; import net.runelite.api.VarClientStr; import net.runelite.api.Varbits; @@ -159,7 +158,7 @@ public class KeyRemappingPlugin extends Plugin { if (chatboxFocused() && !typing) { - chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); + setChatboxWidgetInput(chatboxInput, PRESS_ENTER_TO_CHAT); } } break; @@ -179,7 +178,7 @@ public class KeyRemappingPlugin extends Plugin Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); if (chatboxInput != null) { - chatboxInput.setText(getPlayerNameWithIcon() + ": " + PRESS_ENTER_TO_CHAT); + setChatboxWidgetInput(chatboxInput, PRESS_ENTER_TO_CHAT); } } @@ -192,28 +191,19 @@ public class KeyRemappingPlugin extends Plugin { final boolean isChatboxTransparent = client.isResized() && client.getVar(Varbits.TRANSPARENT_CHATBOX) == 1; final Color textColor = isChatboxTransparent ? JagexColors.CHAT_TYPED_TEXT_TRANSPARENT_BACKGROUND : JagexColors.CHAT_TYPED_TEXT_OPAQUE_BACKGROUND; - chatboxInput.setText(getPlayerNameWithIcon() + ": " + ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor)); + setChatboxWidgetInput(chatboxInput, ColorUtil.wrapWithColorTag(client.getVar(VarClientStr.CHATBOX_TYPED_TEXT) + "*", textColor)); } } } - private String getPlayerNameWithIcon() + private void setChatboxWidgetInput(Widget widget, String input) { - IconID icon; - switch (client.getAccountType()) + String text = widget.getText(); + int idx = text.indexOf(':'); + if (idx != -1) { - case IRONMAN: - icon = IconID.IRONMAN; - break; - case ULTIMATE_IRONMAN: - icon = IconID.ULTIMATE_IRONMAN; - break; - case HARDCORE_IRONMAN: - icon = IconID.HARDCORE_IRONMAN; - break; - default: - return client.getLocalPlayer().getName(); + String newText = text.substring(0, idx) + ": " + input; + widget.setText(newText); } - return icon + client.getLocalPlayer().getName(); } } From 5407e162a3d31bea20fee55f2c30c0d1af796140 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 09:39:56 -0500 Subject: [PATCH 34/43] client: add world service to manage world fetching --- .../runelite/client/game/WorldService.java | 121 ++++++++++++++++++ .../defaultworld/DefaultWorldPlugin.java | 51 ++++---- .../worldhopper/WorldHopperPlugin.java | 77 +++-------- 3 files changed, 164 insertions(+), 85 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/game/WorldService.java diff --git a/runelite-client/src/main/java/net/runelite/client/game/WorldService.java b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java new file mode 100644 index 0000000000..0740c59c07 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2019, Adam + * 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.game; + +import java.io.IOException; +import java.util.Comparator; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Client; +import net.runelite.api.GameState; +import net.runelite.client.util.RunnableExceptionLogger; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldClient; +import net.runelite.http.api.worlds.WorldResult; + +@Singleton +@Slf4j +public class WorldService +{ + private static final int WORLD_FETCH_TIMER = 10; // minutes + + private final Client client; + private final ScheduledExecutorService scheduledExecutorService; + private final WorldClient worldClient; + private final CompletableFuture firstRunFuture = new CompletableFuture<>(); + + private WorldResult worlds; + + @Inject + private WorldService(Client client, ScheduledExecutorService scheduledExecutorService, WorldClient worldClient) + { + this.client = client; + this.scheduledExecutorService = scheduledExecutorService; + this.worldClient = worldClient; + + scheduledExecutorService.scheduleWithFixedDelay(RunnableExceptionLogger.wrap(this::tick), 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES); + } + + private void tick() + { + try + { + if (worlds == null || client.getGameState() == GameState.LOGGED_IN) + { + fetch(); + } + } + finally + { + firstRunFuture.complete(worlds); + } + } + + private void fetch() + { + log.debug("Fetching worlds"); + + try + { + WorldResult worldResult = worldClient.lookupWorlds(); + worldResult.getWorlds().sort(Comparator.comparingInt(World::getId)); + worlds = worldResult; + } + catch (IOException ex) + { + log.warn("Error looking up worlds", ex); + } + } + + public void refresh() + { + scheduledExecutorService.execute(this::fetch); + } + + @Nullable + public WorldResult getWorlds() + { + if (!firstRunFuture.isDone()) + { + try + { + return firstRunFuture.get(10, TimeUnit.SECONDS); + } + catch (InterruptedException | ExecutionException | TimeoutException e) + { + log.warn("Failed to retrieve worlds on first run", e); + } + } + + return worlds; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java index eed2830ae1..9010f9a8d0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/defaultworld/DefaultWorldPlugin.java @@ -25,7 +25,6 @@ package net.runelite.client.plugins.defaultworld; import com.google.inject.Provides; -import java.io.IOException; import javax.inject.Inject; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; @@ -34,11 +33,11 @@ import net.runelite.api.events.GameStateChanged; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.SessionOpen; +import net.runelite.client.game.WorldService; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.util.WorldUtil; import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldClient; import net.runelite.http.api.worlds.WorldResult; @PluginDescriptor( @@ -56,7 +55,7 @@ public class DefaultWorldPlugin extends Plugin private DefaultWorldConfig config; @Inject - private WorldClient worldClient; + private WorldService worldService; private int worldCache; private boolean worldChangeRequired; @@ -116,32 +115,32 @@ public class DefaultWorldPlugin extends Plugin return; } - try + final WorldResult worldResult = worldService.getWorlds(); + + if (worldResult == null) { - final WorldResult worldResult = worldClient.lookupWorlds(); - final World world = worldResult.findWorld(correctedWorld); - - if (world != null) - { - final net.runelite.api.World rsWorld = client.createWorld(); - rsWorld.setActivity(world.getActivity()); - rsWorld.setAddress(world.getAddress()); - rsWorld.setId(world.getId()); - rsWorld.setPlayerCount(world.getPlayers()); - rsWorld.setLocation(world.getLocation()); - rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes())); - - client.changeWorld(rsWorld); - log.debug("Applied new world {}", correctedWorld); - } - else - { - log.warn("World {} not found.", correctedWorld); - } + log.warn("Failed to lookup worlds."); + return; } - catch (IOException e) + + final World world = worldResult.findWorld(correctedWorld); + + if (world != null) { - log.warn("Error looking up world {}. Error: {}", correctedWorld, e); + final net.runelite.api.World rsWorld = client.createWorld(); + rsWorld.setActivity(world.getActivity()); + rsWorld.setAddress(world.getAddress()); + rsWorld.setId(world.getId()); + rsWorld.setPlayerCount(world.getPlayers()); + rsWorld.setLocation(world.getLocation()); + rsWorld.setTypes(WorldUtil.toWorldTypes(world.getTypes())); + + client.changeWorld(rsWorld); + log.debug("Applied new world {}", correctedWorld); + } + else + { + log.warn("World {} not found.", correctedWorld); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index 98c8e39a27..fa3b61fd33 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -31,10 +31,8 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ObjectArrays; import com.google.inject.Provides; import java.awt.image.BufferedImage; -import java.io.IOException; import java.time.Duration; import java.time.Instant; -import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -76,6 +74,7 @@ import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.game.WorldService; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; @@ -88,7 +87,6 @@ import net.runelite.client.util.HotkeyListener; import net.runelite.client.util.Text; import net.runelite.client.util.WorldUtil; import net.runelite.http.api.worlds.World; -import net.runelite.http.api.worlds.WorldClient; import net.runelite.http.api.worlds.WorldResult; import net.runelite.http.api.worlds.WorldType; import org.apache.commons.lang3.ArrayUtils; @@ -101,7 +99,6 @@ import org.apache.commons.lang3.ArrayUtils; @Slf4j public class WorldHopperPlugin extends Plugin { - private static final int WORLD_FETCH_TIMER = 10; private static final int REFRESH_THROTTLE = 60_000; // ms private static final int TICK_THROTTLE = (int) Duration.ofMinutes(10).toMillis(); @@ -130,9 +127,6 @@ public class WorldHopperPlugin extends Plugin @Inject private ChatMessageManager chatMessageManager; - @Inject - private ScheduledExecutorService executorService; - @Inject private WorldHopperConfig config; @@ -143,7 +137,7 @@ public class WorldHopperPlugin extends Plugin private WorldHopperPingOverlay worldHopperOverlay; @Inject - private WorldClient worldClient; + private WorldService worldService; private ScheduledExecutorService hopperExecutorService; @@ -158,11 +152,9 @@ public class WorldHopperPlugin extends Plugin private int favoriteWorld1, favoriteWorld2; - private ScheduledFuture worldResultFuture, pingFuture, currPingFuture; - private WorldResult worldResult; + private ScheduledFuture pingFuture, currPingFuture; private int currentWorld; private Instant lastFetch; - private boolean firstRun; @Getter(AccessLevel.PACKAGE) private int currentPing; @@ -193,7 +185,6 @@ public class WorldHopperPlugin extends Plugin @Override protected void startUp() throws Exception { - firstRun = true; currentPing = -1; keyManager.registerKeyListener(previousKeyListener); @@ -225,8 +216,8 @@ public class WorldHopperPlugin extends Plugin // The plugin has its own executor for pings, as it blocks for a long time hopperExecutorService = new ExecutorServiceExceptionLogger(Executors.newSingleThreadScheduledExecutor()); - // On first run this schedules an initial ping on hopperExecutorService - worldResultFuture = executorService.scheduleAtFixedRate(this::tick, 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES); + // Run the first-run ping + hopperExecutorService.execute(this::pingInitialWorlds); // Give some initial delay - this won't run until after pingInitialWorlds finishes from tick() anyway pingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingNextWorld, 15, 3, TimeUnit.SECONDS); @@ -247,11 +238,6 @@ public class WorldHopperPlugin extends Plugin keyManager.unregisterKeyListener(previousKeyListener); keyManager.unregisterKeyListener(nextKeyListener); - worldResultFuture.cancel(true); - worldResultFuture = null; - worldResult = null; - lastFetch = null; - clientToolbar.removeNavigation(navButton); hopperExecutorService.shutdown(); @@ -385,6 +371,7 @@ public class WorldHopperPlugin extends Plugin // Don't add entry if user is offline ChatPlayer player = getChatPlayerFromName(event.getTarget()); + WorldResult worldResult = worldService.getWorlds(); if (player == null || player.getWorld() == 0 || player.getWorld() == client.getWorld() || worldResult == null) @@ -475,26 +462,6 @@ public class WorldHopperPlugin extends Plugin this.lastFetch = Instant.now(); // This counts as a fetch as it updates populations } - private void tick() - { - Instant now = Instant.now(); - if (lastFetch != null && now.toEpochMilli() - lastFetch.toEpochMilli() < TICK_THROTTLE) - { - log.debug("Throttling world refresh tick"); - return; - } - - fetchWorlds(); - - // Ping worlds once at startup - if (firstRun) - { - firstRun = false; - // On first run we ping all of the worlds at once to initialize the ping values - hopperExecutorService.execute(this::pingInitialWorlds); - } - } - void refresh() { Instant now = Instant.now(); @@ -504,25 +471,8 @@ public class WorldHopperPlugin extends Plugin return; } - fetchWorlds(); - } - - private void fetchWorlds() - { - log.debug("Fetching worlds"); - - try - { - WorldResult worldResult = worldClient.lookupWorlds(); - worldResult.getWorlds().sort(Comparator.comparingInt(World::getId)); - this.worldResult = worldResult; - this.lastFetch = Instant.now(); - updateList(); - } - catch (IOException ex) - { - log.warn("Error looking up worlds", ex); - } + lastFetch = now; + worldService.refresh(); } /** @@ -530,11 +480,16 @@ public class WorldHopperPlugin extends Plugin */ private void updateList() { - SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds())); + WorldResult worldResult = worldService.getWorlds(); + if (worldResult != null) + { + SwingUtilities.invokeLater(() -> panel.populate(worldResult.getWorlds())); + } } private void hop(boolean previous) { + WorldResult worldResult = worldService.getWorlds(); if (worldResult == null || client.getGameState() != GameState.LOGGED_IN) { return; @@ -645,6 +600,7 @@ public class WorldHopperPlugin extends Plugin private void hop(int worldId) { + WorldResult worldResult = worldService.getWorlds(); // Don't try to hop if the world doesn't exist World world = worldResult.findWorld(worldId); if (world == null) @@ -778,6 +734,7 @@ public class WorldHopperPlugin extends Plugin */ private void pingInitialWorlds() { + WorldResult worldResult = worldService.getWorlds(); if (worldResult == null || !config.showSidebar() || !config.ping()) { return; @@ -801,6 +758,7 @@ public class WorldHopperPlugin extends Plugin */ private void pingNextWorld() { + WorldResult worldResult = worldService.getWorlds(); if (worldResult == null || !config.showSidebar() || !config.ping()) { return; @@ -837,6 +795,7 @@ public class WorldHopperPlugin extends Plugin */ private void pingCurrentWorld() { + WorldResult worldResult = worldService.getWorlds(); // There is no reason to ping the current world if not logged in, as the overlay doesn't draw if (worldResult == null || !config.displayPing() || client.getGameState() != GameState.LOGGED_IN) { From b9de8aeb7dd15dd207803d83781839571687d987 Mon Sep 17 00:00:00 2001 From: Adam Date: Mon, 25 Nov 2019 09:41:54 -0500 Subject: [PATCH 35/43] add leagues chat icon plugin Co-authored-by: hsamoht <6449361+hsamoht@users.noreply.github.com> --- .../LeagueChatIconsPlugin.java | 350 ++++++++++++++++++ .../plugins/leaguechaticons/league_icon.png | Bin 0 -> 356 bytes 2 files changed, 350 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/leaguechaticons/league_icon.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java new file mode 100644 index 0000000000..55a30bbeef --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/leaguechaticons/LeagueChatIconsPlugin.java @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2019, hsamoht + * Copyright (c) 2019, Adam + * 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.leaguechaticons; + +import java.awt.image.BufferedImage; +import java.util.Arrays; +import javax.inject.Inject; +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.ChatPlayer; +import net.runelite.api.ClanMember; +import net.runelite.api.ClanMemberManager; +import net.runelite.api.Client; +import net.runelite.api.Friend; +import net.runelite.api.GameState; +import net.runelite.api.IconID; +import net.runelite.api.IndexedSprite; +import net.runelite.api.MessageNode; +import net.runelite.api.NameableContainer; +import net.runelite.api.Player; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.chat.ChatMessageManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.game.WorldService; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.util.ImageUtil; +import net.runelite.client.util.Text; +import net.runelite.http.api.worlds.World; +import net.runelite.http.api.worlds.WorldResult; +import net.runelite.http.api.worlds.WorldType; + +@PluginDescriptor( + name = "Chat League Icons", + description = "Changes the chat icon for players on league worlds", + enabledByDefault = false +) +@Slf4j +public class LeagueChatIconsPlugin extends Plugin +{ + private static final String SCRIPT_EVENT_SET_CHATBOX_INPUT = "setChatboxInput"; + private static final String IRONMAN_PREFIX = ""; + + @Inject + private Client client; + + @Inject + private ChatMessageManager chatMessageManager; + + @Inject + private WorldService worldService; + + @Inject + private ClientThread clientThread; + + private int leagueIconOffset = -1; // offset for league icon + private boolean onLeagueWorld; + + @Override + protected void startUp() + { + onLeagueWorld = false; + + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN) + { + loadLeagueIcon(); + onLeagueWorld = isLeagueWorld(client.getWorld()); + if (onLeagueWorld) + { + setChatboxName(getNameChatbox()); + } + } + }); + } + + @Override + protected void shutDown() + { + clientThread.invoke(() -> + { + if (client.getGameState() == GameState.LOGGED_IN && onLeagueWorld) + { + setChatboxName(getNameDefault()); + } + }); + } + + @Subscribe + public void onGameStateChanged(GameStateChanged gameStateChanged) + { + if (gameStateChanged.getGameState() == GameState.LOGGED_IN) + { + loadLeagueIcon(); + onLeagueWorld = isLeagueWorld(client.getWorld()); + } + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent scriptCallbackEvent) + { + if (scriptCallbackEvent.getEventName().equals(SCRIPT_EVENT_SET_CHATBOX_INPUT) && onLeagueWorld) + { + setChatboxName(getNameChatbox()); + } + } + + @Subscribe + public void onChatMessage(ChatMessage chatMessage) + { + if (client.getGameState() != GameState.LOADING && client.getGameState() != GameState.LOGGED_IN) + { + return; + } + + switch (chatMessage.getType()) + { + case PRIVATECHAT: + case MODPRIVATECHAT: + // Note this is unable to change icon on PMs if they are not a friend or in clan chat + case FRIENDSCHAT: + String name = Text.removeTags(chatMessage.getName()); + if (isChatPlayerOnLeague(name)) + { + addLeagueIconToMessage(chatMessage); + } + break; + case PUBLICCHAT: + case MODCHAT: + if (onLeagueWorld) + { + addLeagueIconToMessage(chatMessage); + } + break; + } + } + + /** + * Adds the League Icon in front of player names chatting from a league world. + * + * @param chatMessage chat message to edit sender name on + */ + private void addLeagueIconToMessage(ChatMessage chatMessage) + { + String name = chatMessage.getName(); + if (!name.startsWith(IRONMAN_PREFIX)) + { + // don't replace non-ironman icons, like mods + return; + } + + name = Text.removeTags(name); + + final MessageNode messageNode = chatMessage.getMessageNode(); + messageNode.setName(getNameWithIcon(leagueIconOffset, name)); + + chatMessageManager.update(messageNode); + client.refreshChat(); + } + + /** + * Update the player name in the chatbox input + */ + private void setChatboxName(String name) + { + Widget chatboxInput = client.getWidget(WidgetInfo.CHATBOX_INPUT); + if (chatboxInput != null) + { + String text = chatboxInput.getText(); + int idx = text.indexOf(':'); + if (idx != -1) + { + String newText = name + text.substring(idx); + chatboxInput.setText(newText); + } + } + } + + /** + * Gets the league name, including possible icon, of the local player. + * + * @return String of icon + name + */ + private String getNameChatbox() + { + Player player = client.getLocalPlayer(); + if (player != null) + { + return getNameWithIcon(leagueIconOffset, player.getName()); + } + return null; + } + + /** + * Gets the default name, including possible icon, of the local player. + * + * @return String of icon + name + */ + private String getNameDefault() + { + Player player = client.getLocalPlayer(); + if (player == null) + { + return null; + } + + int iconIndex; + switch (client.getAccountType()) + { + case IRONMAN: + iconIndex = IconID.IRONMAN.getIndex(); + break; + case HARDCORE_IRONMAN: + iconIndex = IconID.HARDCORE_IRONMAN.getIndex(); + break; + case ULTIMATE_IRONMAN: + iconIndex = IconID.ULTIMATE_IRONMAN.getIndex(); + break; + default: + return player.getName(); + } + + return getNameWithIcon(iconIndex, player.getName()); + } + + /** + * Get a name formatted with icon + * + * @param iconIndex index of the icon + * @param name name of the player + * @return String of icon + name + */ + private static String getNameWithIcon(int iconIndex, String name) + { + String icon = ""; + return icon + name; + } + + /** + * Checks if a player name is a friend or clan member on a league world. + * + * @param name name of player to check. + * @return boolean true/false. + */ + private boolean isChatPlayerOnLeague(String name) + { + ChatPlayer player = getChatPlayerFromName(name); + + if (player == null) + { + return false; + } + + int world = player.getWorld(); + return isLeagueWorld(world); + } + + /** + * Checks if the world is a League world. + * + * @param worldNumber number of the world to check. + * @return boolean true/false if it is a league world or not. + */ + private boolean isLeagueWorld(int worldNumber) + { + WorldResult worlds = worldService.getWorlds(); + if (worlds == null) + { + return false; + } + + World world = worlds.findWorld(worldNumber); + return world != null && world.getTypes().contains(WorldType.LEAGUE); + } + + /** + * Loads the league icon into the client. + */ + private void loadLeagueIcon() + { + final IndexedSprite[] modIcons = client.getModIcons(); + + if (leagueIconOffset != -1 || modIcons == null) + { + return; + } + + BufferedImage image = ImageUtil.getResourceStreamFromClass(getClass(), "league_icon.png"); + IndexedSprite indexedSprite = ImageUtil.getImageIndexedSprite(image, client); + + leagueIconOffset = modIcons.length; + + final IndexedSprite[] newModIcons = Arrays.copyOf(modIcons, modIcons.length + 1); + newModIcons[newModIcons.length - 1] = indexedSprite; + + client.setModIcons(newModIcons); + } + + /** + * Gets a ChatPlayer object from a clean name by searching clan and friends list. + * + * @param name name of player to find. + * @return ChatPlayer if found, else null. + */ + private ChatPlayer getChatPlayerFromName(String name) + { + // Search clan members first, because if a friend is in the clan chat but their private + // chat is 'off', then we won't know the world + ClanMemberManager clanMemberManager = client.getClanMemberManager(); + if (clanMemberManager != null) + { + ClanMember clanMember = clanMemberManager.findByName(name); + if (clanMember != null) + { + return clanMember; + } + } + + NameableContainer friendContainer = client.getFriendContainer(); + return friendContainer.findByName(name); + } +} diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/leaguechaticons/league_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/leaguechaticons/league_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..41e448712029e7e3d32474f97db1253d4f58ceb1 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2@q#X;^)4C~IxyaaMs(j9#r85lP9 zbN@+X1@buyJR*x382Ao@Fyrz36)8Z$pPnv`AsWG@LE3zW90ca-K4h@)(G^{=gQJ1+GQpwU^x4Yr_5diM?UTnuH^#O?x@N)ZMFG=GFFmVd^}#1zc0> zWz3%Esjgti^(qsv6=4uqz|@eCb?g1ZWEIQa83`SoJq5oXekt&ud4^qjiST^!;*VjM w_w^{NC~tcBEYYc{KkI8Z#~HDb{kDtb{TzFXfBoQz0|o+vr>mdKI;Vst0M_t`t^fc4 literal 0 HcmV?d00001 From 0087fb743bfff57011cb5011b1097aa0e64c4b43 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Thu, 28 Nov 2019 11:33:27 +0000 Subject: [PATCH 36/43] Update Item IDs to 2019-11-28-rev182 --- runelite-api/src/main/java/net/runelite/api/ItemID.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/ItemID.java b/runelite-api/src/main/java/net/runelite/api/ItemID.java index c5960611c1..3c6fa9cf83 100644 --- a/runelite-api/src/main/java/net/runelite/api/ItemID.java +++ b/runelite-api/src/main/java/net/runelite/api/ItemID.java @@ -11355,5 +11355,14 @@ public final class ItemID public static final int TWISTED_BOOTS_T1 = 24411; public static final int TWISTED_LEAGUE_BANNER = 24413; public static final int RUNE_POUCH_L = 24416; + public static final int INQUISITORS_MACE = 24417; + public static final int SIRENS_TOME = 24418; + public static final int INQUISITORS_GREAT_HELM = 24419; + public static final int INQUISITORS_HAUBERK = 24420; + public static final int INQUISITORS_PLATESKIRT = 24421; + public static final int NIGHTMARE_STAFF = 24422; + public static final int HARMONISED_NIGHTMARE_STAFF = 24423; + public static final int VOLATILE_NIGHTMARE_STAFF = 24424; + public static final int ELDRITCH_NIGHTMARE_STAFF = 24425; /* This file is automatically generated. Do not edit. */ } From 34c825cba46e5346ea53c52160a0ca4994471ff3 Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Thu, 28 Nov 2019 11:33:28 +0000 Subject: [PATCH 37/43] Update Object IDs to 2019-11-28-rev182 --- runelite-api/src/main/java/net/runelite/api/NullObjectID.java | 1 + 1 file changed, 1 insertion(+) diff --git a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java index 86b6e4a5bd..623326fd6a 100644 --- a/runelite-api/src/main/java/net/runelite/api/NullObjectID.java +++ b/runelite-api/src/main/java/net/runelite/api/NullObjectID.java @@ -18070,5 +18070,6 @@ public final class NullObjectID public static final int NULL_37480 = 37480; public static final int NULL_37481 = 37481; public static final int NULL_37490 = 37490; + public static final int NULL_37491 = 37491; /* This file is automatically generated. Do not edit. */ } From 141d93ea5b7779a5dcfe02d23d918b57021d90bc Mon Sep 17 00:00:00 2001 From: RuneLite Cache-Code Autoupdater Date: Thu, 28 Nov 2019 11:33:35 +0000 Subject: [PATCH 38/43] Update Scripts to 2019-11-28-rev182 --- .../src/main/scripts/FakeXpDrop.hash | 2 +- .../src/main/scripts/FakeXpDrop.rs2asm | 102 ++++++++++-------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/runelite-client/src/main/scripts/FakeXpDrop.hash b/runelite-client/src/main/scripts/FakeXpDrop.hash index cf5e37e931..9eba813f20 100644 --- a/runelite-client/src/main/scripts/FakeXpDrop.hash +++ b/runelite-client/src/main/scripts/FakeXpDrop.hash @@ -1 +1 @@ -32FBC48F8C6D8E62E02BCF09F444BA036F76133B6596396F0AB9E474687D9F3F \ No newline at end of file +C85469C2529D794C523505679F14AA20E988513E8FBAF249E41F4760382B4BBB \ No newline at end of file diff --git a/runelite-client/src/main/scripts/FakeXpDrop.rs2asm b/runelite-client/src/main/scripts/FakeXpDrop.rs2asm index 93ac905034..0f5b817d85 100644 --- a/runelite-client/src/main/scripts/FakeXpDrop.rs2asm +++ b/runelite-client/src/main/scripts/FakeXpDrop.rs2asm @@ -6,9 +6,9 @@ iload 0 ; stat iload 1 ; xp sconst "fakeXpDrop" - runelite_callback - pop_int - pop_int + runelite_callback + pop_int + pop_int iconst 105 iconst 83 iconst 681 @@ -25,7 +25,7 @@ LABEL9: iload 1 movecoord set_varc_int 207 - jump LABEL216 + jump LABEL227 LABEL16: iconst 105 iconst 83 @@ -43,7 +43,7 @@ LABEL25: iload 1 movecoord set_varc_int 208 - jump LABEL216 + jump LABEL227 LABEL32: iconst 105 iconst 83 @@ -61,7 +61,7 @@ LABEL41: iload 1 movecoord set_varc_int 209 - jump LABEL216 + jump LABEL227 LABEL48: iconst 105 iconst 83 @@ -79,7 +79,7 @@ LABEL57: iload 1 movecoord set_varc_int 210 - jump LABEL216 + jump LABEL227 LABEL64: iconst 105 iconst 83 @@ -97,7 +97,7 @@ LABEL73: iload 1 movecoord set_varc_int 211 - jump LABEL216 + jump LABEL227 LABEL80: iconst 105 iconst 83 @@ -115,7 +115,7 @@ LABEL89: iload 1 movecoord set_varc_int 212 - jump LABEL216 + jump LABEL227 LABEL96: iconst 105 iconst 83 @@ -133,13 +133,27 @@ LABEL105: iload 1 movecoord set_varc_int 213 - jump LABEL216 + jump LABEL227 LABEL112: + iload 0 + iconst 3 + if_icmpeq LABEL116 + jump LABEL123 +LABEL116: + iload 1 + iconst 20000001 + if_icmpeq LABEL120 + jump LABEL123 +LABEL120: + iconst 269500481 + set_varc_int 207 + jump LABEL227 +LABEL123: get_varc_int 207 iconst -1 - if_icmpeq LABEL116 - jump LABEL127 -LABEL116: + if_icmpeq LABEL127 + jump LABEL138 +LABEL127: iconst 0 iconst 83 iconst 105 @@ -150,13 +164,13 @@ LABEL116: iload 1 movecoord set_varc_int 207 - jump LABEL216 -LABEL127: + jump LABEL227 +LABEL138: get_varc_int 208 iconst -1 - if_icmpeq LABEL131 - jump LABEL142 -LABEL131: + if_icmpeq LABEL142 + jump LABEL153 +LABEL142: iconst 0 iconst 83 iconst 105 @@ -167,13 +181,13 @@ LABEL131: iload 1 movecoord set_varc_int 208 - jump LABEL216 -LABEL142: + jump LABEL227 +LABEL153: get_varc_int 209 iconst -1 - if_icmpeq LABEL146 - jump LABEL157 -LABEL146: + if_icmpeq LABEL157 + jump LABEL168 +LABEL157: iconst 0 iconst 83 iconst 105 @@ -184,13 +198,13 @@ LABEL146: iload 1 movecoord set_varc_int 209 - jump LABEL216 -LABEL157: + jump LABEL227 +LABEL168: get_varc_int 210 iconst -1 - if_icmpeq LABEL161 - jump LABEL172 -LABEL161: + if_icmpeq LABEL172 + jump LABEL183 +LABEL172: iconst 0 iconst 83 iconst 105 @@ -201,13 +215,13 @@ LABEL161: iload 1 movecoord set_varc_int 210 - jump LABEL216 -LABEL172: + jump LABEL227 +LABEL183: get_varc_int 211 iconst -1 - if_icmpeq LABEL176 - jump LABEL187 -LABEL176: + if_icmpeq LABEL187 + jump LABEL198 +LABEL187: iconst 0 iconst 83 iconst 105 @@ -218,13 +232,13 @@ LABEL176: iload 1 movecoord set_varc_int 211 - jump LABEL216 -LABEL187: + jump LABEL227 +LABEL198: get_varc_int 212 iconst -1 - if_icmpeq LABEL191 - jump LABEL202 -LABEL191: + if_icmpeq LABEL202 + jump LABEL213 +LABEL202: iconst 0 iconst 83 iconst 105 @@ -235,13 +249,13 @@ LABEL191: iload 1 movecoord set_varc_int 212 - jump LABEL216 -LABEL202: + jump LABEL227 +LABEL213: get_varc_int 213 iconst -1 - if_icmpeq LABEL206 - jump LABEL216 -LABEL206: + if_icmpeq LABEL217 + jump LABEL227 +LABEL217: iconst 0 iconst 83 iconst 105 @@ -252,5 +266,5 @@ LABEL206: iload 1 movecoord set_varc_int 213 -LABEL216: +LABEL227: return From f0439e1da5e7aa07c0f8ab21f5e0d1b82a9bfd49 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Thu, 28 Nov 2019 12:44:51 +0000 Subject: [PATCH 39/43] Update 186 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3e6a1f9d82..853a6c967b 100644 --- a/pom.xml +++ b/pom.xml @@ -43,7 +43,7 @@ true true - 185 + 186 From 56465edd1f7785c523d5d4681faf66d00b8a5811 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Thu, 28 Nov 2019 13:01:37 +0000 Subject: [PATCH 40/43] Release 1.5.42 --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- http-api/pom.xml | 2 +- http-service/pom.xml | 2 +- pom.xml | 4 ++-- protocol-api/pom.xml | 2 +- protocol/pom.xml | 2 +- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index cb5f3a015b..ad986c56a3 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index d8847b485a..ce07ec66f1 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index 58c8e79116..e9062498b8 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 cache diff --git a/http-api/pom.xml b/http-api/pom.xml index b7f4e98234..8d9423ebf4 100644 --- a/http-api/pom.xml +++ b/http-api/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 Web API diff --git a/http-service/pom.xml b/http-service/pom.xml index 98f258123e..f918e6d040 100644 --- a/http-service/pom.xml +++ b/http-service/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 Web Service diff --git a/pom.xml b/pom.xml index 853a6c967b..65e0ccb649 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 pom RuneLite @@ -59,7 +59,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - HEAD + runelite-parent-1.5.42 diff --git a/protocol-api/pom.xml b/protocol-api/pom.xml index 42c621b83c..e467c358b6 100644 --- a/protocol-api/pom.xml +++ b/protocol-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 protocol-api diff --git a/protocol/pom.xml b/protocol/pom.xml index 2491a3c6cc..ff0eeb4754 100644 --- a/protocol/pom.xml +++ b/protocol/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 protocol diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 6019461c26..937505309a 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 2c162879a0..1a6145c75f 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 client diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 8e2b4fb336..641c646e41 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42-SNAPSHOT + 1.5.42 script-assembler-plugin From f6cbfeb8ceba79e8c47e248374a72238f2a9afa9 Mon Sep 17 00:00:00 2001 From: Runelite auto updater Date: Thu, 28 Nov 2019 13:01:43 +0000 Subject: [PATCH 41/43] Bump for 1.5.43-SNAPSHOT --- cache-client/pom.xml | 2 +- cache-updater/pom.xml | 2 +- cache/pom.xml | 2 +- http-api/pom.xml | 2 +- http-service/pom.xml | 2 +- pom.xml | 4 ++-- protocol-api/pom.xml | 2 +- protocol/pom.xml | 2 +- runelite-api/pom.xml | 2 +- runelite-client/pom.xml | 2 +- runelite-script-assembler-plugin/pom.xml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/cache-client/pom.xml b/cache-client/pom.xml index ad986c56a3..901c55da08 100644 --- a/cache-client/pom.xml +++ b/cache-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT cache-client diff --git a/cache-updater/pom.xml b/cache-updater/pom.xml index ce07ec66f1..77446dd24e 100644 --- a/cache-updater/pom.xml +++ b/cache-updater/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT Cache Updater diff --git a/cache/pom.xml b/cache/pom.xml index e9062498b8..dc876a07d6 100644 --- a/cache/pom.xml +++ b/cache/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT cache diff --git a/http-api/pom.xml b/http-api/pom.xml index 8d9423ebf4..f205515ac4 100644 --- a/http-api/pom.xml +++ b/http-api/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT Web API diff --git a/http-service/pom.xml b/http-service/pom.xml index f918e6d040..201a0caad5 100644 --- a/http-service/pom.xml +++ b/http-service/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT Web Service diff --git a/pom.xml b/pom.xml index 65e0ccb649..96d6ccede9 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT pom RuneLite @@ -59,7 +59,7 @@ https://github.com/runelite/runelite scm:git:git://github.com/runelite/runelite scm:git:git@github.com:runelite/runelite - runelite-parent-1.5.42 + HEAD diff --git a/protocol-api/pom.xml b/protocol-api/pom.xml index e467c358b6..bc4761d0e6 100644 --- a/protocol-api/pom.xml +++ b/protocol-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT protocol-api diff --git a/protocol/pom.xml b/protocol/pom.xml index ff0eeb4754..fe55362ae6 100644 --- a/protocol/pom.xml +++ b/protocol/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT protocol diff --git a/runelite-api/pom.xml b/runelite-api/pom.xml index 937505309a..e1bab701fa 100644 --- a/runelite-api/pom.xml +++ b/runelite-api/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT runelite-api diff --git a/runelite-client/pom.xml b/runelite-client/pom.xml index 1a6145c75f..dd45150342 100644 --- a/runelite-client/pom.xml +++ b/runelite-client/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT client diff --git a/runelite-script-assembler-plugin/pom.xml b/runelite-script-assembler-plugin/pom.xml index 641c646e41..01084c7971 100644 --- a/runelite-script-assembler-plugin/pom.xml +++ b/runelite-script-assembler-plugin/pom.xml @@ -29,7 +29,7 @@ net.runelite runelite-parent - 1.5.42 + 1.5.43-SNAPSHOT script-assembler-plugin From 665b021c858eccc4459d76b7769845d1cd7b76c1 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 28 Nov 2019 09:00:56 -0500 Subject: [PATCH 42/43] client: fix world hopper not populating worlds on startup and when refreshed --- .../runelite/client/events/WorldsFetch.java | 37 +++++++++++++++++++ .../runelite/client/game/WorldService.java | 8 +++- .../worldhopper/WorldHopperPlugin.java | 10 +++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/events/WorldsFetch.java diff --git a/runelite-client/src/main/java/net/runelite/client/events/WorldsFetch.java b/runelite-client/src/main/java/net/runelite/client/events/WorldsFetch.java new file mode 100644 index 0000000000..cc07aa5a23 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/events/WorldsFetch.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, Adam + * 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.events; + +import lombok.Value; +import net.runelite.http.api.worlds.WorldResult; + +/** + * Fired when the @{link net.runelite.client.game.WorldService} refreshes the world list + */ +@Value +public class WorldsFetch +{ + private final WorldResult worldResult; +} diff --git a/runelite-client/src/main/java/net/runelite/client/game/WorldService.java b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java index 0740c59c07..263f712a25 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/WorldService.java +++ b/runelite-client/src/main/java/net/runelite/client/game/WorldService.java @@ -37,6 +37,8 @@ import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Client; import net.runelite.api.GameState; +import net.runelite.client.eventbus.EventBus; +import net.runelite.client.events.WorldsFetch; import net.runelite.client.util.RunnableExceptionLogger; import net.runelite.http.api.worlds.World; import net.runelite.http.api.worlds.WorldClient; @@ -51,16 +53,19 @@ public class WorldService private final Client client; private final ScheduledExecutorService scheduledExecutorService; private final WorldClient worldClient; + private final EventBus eventBus; private final CompletableFuture firstRunFuture = new CompletableFuture<>(); private WorldResult worlds; @Inject - private WorldService(Client client, ScheduledExecutorService scheduledExecutorService, WorldClient worldClient) + private WorldService(Client client, ScheduledExecutorService scheduledExecutorService, WorldClient worldClient, + EventBus eventBus) { this.client = client; this.scheduledExecutorService = scheduledExecutorService; this.worldClient = worldClient; + this.eventBus = eventBus; scheduledExecutorService.scheduleWithFixedDelay(RunnableExceptionLogger.wrap(this::tick), 0, WORLD_FETCH_TIMER, TimeUnit.MINUTES); } @@ -89,6 +94,7 @@ public class WorldService WorldResult worldResult = worldClient.lookupWorlds(); worldResult.getWorlds().sort(Comparator.comparingInt(World::getId)); worlds = worldResult; + eventBus.post(new WorldsFetch(worldResult)); } catch (IOException ex) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java index fa3b61fd33..e46ab2ec4c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/worldhopper/WorldHopperPlugin.java @@ -74,6 +74,7 @@ import net.runelite.client.chat.QueuedMessage; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; import net.runelite.client.events.ConfigChanged; +import net.runelite.client.events.WorldsFetch; import net.runelite.client.game.WorldService; import net.runelite.client.input.KeyManager; import net.runelite.client.plugins.Plugin; @@ -222,6 +223,9 @@ public class WorldHopperPlugin extends Plugin // Give some initial delay - this won't run until after pingInitialWorlds finishes from tick() anyway pingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingNextWorld, 15, 3, TimeUnit.SECONDS); currPingFuture = hopperExecutorService.scheduleWithFixedDelay(this::pingCurrentWorld, 15, 1, TimeUnit.SECONDS); + + // populate initial world list + updateList(); } @Override @@ -475,6 +479,12 @@ public class WorldHopperPlugin extends Plugin worldService.refresh(); } + @Subscribe + public void onWorldsFetch(WorldsFetch worldsFetch) + { + updateList(); + } + /** * This method ONLY updates the list's UI, not the actual world list and data it displays. */ From 0d27667720267e131a3172c43f05d99795f38406 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 28 Nov 2019 09:11:06 -0500 Subject: [PATCH 43/43] woodcutting plugin: disable by default --- .../runelite/client/plugins/woodcutting/WoodcuttingPlugin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java index b269bc1e99..a8a38d852e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -62,7 +62,8 @@ import net.runelite.client.ui.overlay.OverlayMenuEntry; @PluginDescriptor( name = "Woodcutting", description = "Show woodcutting statistics and/or bird nest notifications", - tags = {"birds", "nest", "notifications", "overlay", "skilling", "wc"} + tags = {"birds", "nest", "notifications", "overlay", "skilling", "wc"}, + enabledByDefault = false ) @PluginDependency(XpTrackerPlugin.class) @Slf4j