From 61f732d3301a80d8aea8a56522726398d87b2a9d Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 30 Jan 2021 11:10:05 -0500 Subject: [PATCH 1/7] tile: add setter for ground object --- runelite-api/src/main/java/net/runelite/api/Tile.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/runelite-api/src/main/java/net/runelite/api/Tile.java b/runelite-api/src/main/java/net/runelite/api/Tile.java index be35c8c3d2..9c0565ea31 100644 --- a/runelite-api/src/main/java/net/runelite/api/Tile.java +++ b/runelite-api/src/main/java/net/runelite/api/Tile.java @@ -61,6 +61,13 @@ public interface Tile */ GroundObject getGroundObject(); + /** + * Sets the object on the ground layer of the tile. + * + * @param groundObject the ground object + */ + void setGroundObject(GroundObject groundObject); + /** * Gets the wall of the tile. * From 2b3ce15516c65703885c0ea5c74ae53971cd1bce Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 22 Dec 2020 12:00:31 -0700 Subject: [PATCH 2/7] don't use gson's reflection serialization on non RuneLite classes java >=16 disallows access to most private fields which makes these fail with the reflection type adapter --- .../net/runelite/http/api/RuneLiteAPI.java | 25 +++++- .../http/api/gson/ColorTypeAdapter.java | 80 ++++++++++++++++++ .../api/gson/IllegalReflectionExclusion.java | 58 +++++++++++++ .../http/api/gson/InstantTypeAdapter.java | 82 +++++++++++++++++++ .../http/api/ws/WebsocketGsonFactory.java | 4 +- .../http/api/gson/ColorTypeAdapterTest.java | 51 ++++++++++++ .../http/api/gson/InstantTypeAdapterTest.java | 49 +++++++++++ .../net/runelite/client/RuneLiteModule.java | 4 + .../client/account/SessionManager.java | 9 +- .../externalplugins/ExternalPluginClient.java | 11 ++- .../crowdsourcing/CrowdsourcingManager.java | 7 +- .../grandexchange/GrandExchangePlugin.java | 8 +- .../groundmarkers/GroundMarkerPlugin.java | 9 +- .../GroundMarkerSharingManager.java | 12 +-- .../ObjectIndicatorsPlugin.java | 8 +- .../screenmarkers/ScreenMarkerPlugin.java | 5 +- .../timetracking/clocks/ClockManager.java | 7 +- .../wiki/WikiSearchChatboxTextInput.java | 3 +- .../runelite/client/util/ImageCapture.java | 11 ++- 19 files changed, 402 insertions(+), 41 deletions(-) create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java create mode 100644 http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java create mode 100644 http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java create mode 100644 http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java diff --git a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java index 0b017518c8..dc483f35db 100644 --- a/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java +++ b/http-api/src/main/java/net/runelite/http/api/RuneLiteAPI.java @@ -25,10 +25,16 @@ package net.runelite.http.api; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.awt.Color; import java.io.IOException; import java.io.InputStream; +import java.time.Instant; import java.util.Properties; import java.util.concurrent.TimeUnit; +import net.runelite.http.api.gson.ColorTypeAdapter; +import net.runelite.http.api.gson.InstantTypeAdapter; +import net.runelite.http.api.gson.IllegalReflectionExclusion; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.MediaType; @@ -46,7 +52,7 @@ public class RuneLiteAPI public static final String RUNELITE_MACHINEID = "RUNELITE-MACHINEID"; public static final OkHttpClient CLIENT; - public static final Gson GSON = new Gson(); + public static final Gson GSON; public static final MediaType JSON = MediaType.parse("application/json"); public static String userAgent; @@ -96,6 +102,23 @@ public class RuneLiteAPI } }) .build(); + + GsonBuilder gsonBuilder = new GsonBuilder(); + + gsonBuilder + .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) + .registerTypeAdapter(Color.class, new ColorTypeAdapter()); + + boolean assertionsEnabled = false; + assert assertionsEnabled = true; + if (assertionsEnabled) + { + IllegalReflectionExclusion jbe = new IllegalReflectionExclusion(); + gsonBuilder.addSerializationExclusionStrategy(jbe); + gsonBuilder.addDeserializationExclusionStrategy(jbe); + } + + GSON = gsonBuilder.create(); } public static HttpUrl getSessionBase() diff --git a/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java new file mode 100644 index 0000000000..6f4b003df0 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/ColorTypeAdapter.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 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.http.api.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.awt.Color; +import java.io.IOException; + +public class ColorTypeAdapter extends TypeAdapter +{ + @Override + public void write(JsonWriter out, Color value) throws IOException + { + if (value == null) + { + out.nullValue(); + return; + } + + int rgba = value.getRGB(); + out.beginObject() + .name("value") + .value(rgba) + .endObject(); + } + + @Override + public Color read(JsonReader in) throws IOException + { + switch (in.peek()) + { + case NULL: + in.nextNull(); + return null; + case BEGIN_OBJECT: + in.beginObject(); + double value = 0; + while (in.peek() != JsonToken.END_OBJECT) + { + switch (in.nextName()) + { + case "value": + value = in.nextDouble(); + break; + default: + in.skipValue(); + break; + } + } + in.endObject(); + return new Color((int) value, true); + } + return null; // throws + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java b/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java new file mode 100644 index 0000000000..d7611cf83f --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/IllegalReflectionExclusion.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 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.http.api.gson; + +import com.google.gson.ExclusionStrategy; +import com.google.gson.FieldAttributes; +import java.lang.reflect.Modifier; + +public class IllegalReflectionExclusion implements ExclusionStrategy +{ + @Override + public boolean shouldSkipField(FieldAttributes f) + { + if (f.getDeclaringClass().getName().startsWith("net.runelite")) + { + return false; + } + + assert !Modifier.isPrivate(f.getDeclaringClass().getModifiers()) : "gsoning private class " + f.getDeclaringClass().getName(); + try + { + f.getDeclaringClass().getField(f.getName()); + } + catch (NoSuchFieldException e) + { + throw new AssertionError("gsoning private field " + f.getDeclaringClass() + "." + f.getName()); + } + return false; + } + + @Override + public boolean shouldSkipClass(Class clazz) + { + return false; + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java b/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java new file mode 100644 index 0000000000..bf92af94b8 --- /dev/null +++ b/http-api/src/main/java/net/runelite/http/api/gson/InstantTypeAdapter.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 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.http.api.gson; + +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.time.Instant; + +// Just add water! +public class InstantTypeAdapter extends TypeAdapter +{ + @Override + public void write(JsonWriter out, Instant value) throws IOException + { + if (value == null) + { + out.nullValue(); + return; + } + + out.beginObject() + .name("seconds") + .value(value.getEpochSecond()) + .name("nanos") + .value(value.getNano()) + .endObject(); + } + + @Override + public Instant read(JsonReader in) throws IOException + { + if (in.peek() == JsonToken.NULL) + { + in.nextNull(); + return null; + } + + long seconds = 0; + int nanos = 0; + in.beginObject(); + while (in.peek() != JsonToken.END_OBJECT) + { + switch (in.nextName()) + { + case "nanos": + nanos = in.nextInt(); + break; + case "seconds": + seconds = in.nextLong(); + break; + } + } + in.endObject(); + + return Instant.ofEpochSecond(seconds, nanos); + } +} diff --git a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java index 9d4e46e6ea..328d0aa1a7 100644 --- a/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java +++ b/http-api/src/main/java/net/runelite/http/api/ws/WebsocketGsonFactory.java @@ -25,11 +25,11 @@ package net.runelite.http.api.ws; import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.ws.messages.Handshake; import net.runelite.http.api.ws.messages.LoginResponse; import net.runelite.http.api.ws.messages.party.Join; @@ -76,7 +76,7 @@ public class WebsocketGsonFactory public static Gson build(final RuntimeTypeAdapterFactory factory) { - return new GsonBuilder() + return RuneLiteAPI.GSON.newBuilder() .registerTypeAdapterFactory(factory) .create(); } diff --git a/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java new file mode 100644 index 0000000000..d7f5e6fd4c --- /dev/null +++ b/http-api/src/test/java/net/runelite/http/api/gson/ColorTypeAdapterTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 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.http.api.gson; + +import java.awt.Color; +import net.runelite.http.api.RuneLiteAPI; +import org.junit.Assert; +import org.junit.Test; + +public class ColorTypeAdapterTest +{ + @Test + public void test() + { + test("null", null); + test("{\"value\":-13347208,\"falpha\":0.0}", new Color(0x12345678, false)); + test("{\"value\":305419896,\"falpha\":0.0}", new Color(0x12345678, true)); + test("{\"value\":-1.4221317E7,\"falpha\":0.0}", new Color(0xFF26FFFB, true)); + } + + private void test(String json, Color object) + { + Color parsed = RuneLiteAPI.GSON.fromJson(json, Color.class); + Assert.assertEquals(object, parsed); + String serialized = RuneLiteAPI.GSON.toJson(object); + Color roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Color.class); + Assert.assertEquals(object, roundTripped); + } +} \ No newline at end of file diff --git a/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java b/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java new file mode 100644 index 0000000000..dab70a4f96 --- /dev/null +++ b/http-api/src/test/java/net/runelite/http/api/gson/InstantTypeAdapterTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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.http.api.gson; + +import java.time.Instant; +import net.runelite.http.api.RuneLiteAPI; +import org.junit.Assert; +import org.junit.Test; + +public class InstantTypeAdapterTest +{ + @Test + public void test() + { + test("null", null); + test("{\"seconds\":1609538310,\"nanos\":291698903}", Instant.ofEpochSecond(1609538310, 291698903)); + } + + private void test(String json, Instant object) + { + Instant parsed = RuneLiteAPI.GSON.fromJson(json, Instant.class); + Assert.assertEquals(object, parsed); + String serialized = RuneLiteAPI.GSON.toJson(object); + Instant roundTripped = RuneLiteAPI.GSON.fromJson(serialized, Instant.class); + Assert.assertEquals(object, roundTripped); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java index 3376c62f77..8c80c67a37 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLiteModule.java @@ -24,6 +24,7 @@ */ package net.runelite.client; +import com.google.gson.Gson; import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.name.Names; @@ -51,6 +52,7 @@ import net.runelite.client.plugins.PluginManager; import net.runelite.client.task.Scheduler; import net.runelite.client.util.DeferredEventBus; import net.runelite.client.util.ExecutorServiceExceptionLogger; +import net.runelite.http.api.RuneLiteAPI; import net.runelite.http.api.chat.ChatClient; import okhttp3.OkHttpClient; @@ -86,6 +88,8 @@ public class RuneLiteModule extends AbstractModule bind(PluginManager.class); bind(SessionManager.class); + bind(Gson.class).toInstance(RuneLiteAPI.GSON); + bind(Callbacks.class).to(Hooks.class); bind(EventBus.class) diff --git a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java index cadf0b4562..4b6bf1674e 100644 --- a/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java +++ b/runelite-client/src/main/java/net/runelite/client/account/SessionManager.java @@ -64,6 +64,7 @@ public class SessionManager private final WSClient wsClient; private final File sessionFile; private final AccountClient accountClient; + private final Gson gson; @Inject private SessionManager( @@ -71,13 +72,15 @@ public class SessionManager ConfigManager configManager, EventBus eventBus, WSClient wsClient, - OkHttpClient okHttpClient) + OkHttpClient okHttpClient, + Gson gson) { this.configManager = configManager; this.eventBus = eventBus; this.wsClient = wsClient; this.sessionFile = sessionfile; this.accountClient = new AccountClient(okHttpClient); + this.gson = gson; eventBus.register(this); } @@ -94,7 +97,7 @@ public class SessionManager try (FileInputStream in = new FileInputStream(sessionFile)) { - session = new Gson().fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), AccountSession.class); + session = gson.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), AccountSession.class); log.debug("Loaded session for {}", session.getUsername()); } @@ -124,7 +127,7 @@ public class SessionManager try (Writer fw = new OutputStreamWriter(new FileOutputStream(sessionFile), StandardCharsets.UTF_8)) { - new Gson().toJson(accountSession, fw); + gson.toJson(accountSession, fw); log.debug("Saved session to {}", sessionFile); } diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java index e6bda75032..ccf4b9fad3 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClient.java @@ -25,6 +25,7 @@ package net.runelite.client.externalplugins; import com.google.common.reflect.TypeToken; +import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; @@ -59,11 +60,13 @@ import okio.BufferedSource; public class ExternalPluginClient { private final OkHttpClient okHttpClient; + private final Gson gson; @Inject - private ExternalPluginClient(OkHttpClient okHttpClient) + private ExternalPluginClient(OkHttpClient okHttpClient, Gson gson) { this.okHttpClient = okHttpClient; + this.gson = gson; } public List downloadManifest() throws IOException, VerificationException @@ -94,7 +97,7 @@ public class ExternalPluginClient throw new VerificationException("Unable to verify external plugin manifest"); } - return RuneLiteAPI.GSON.fromJson(new String(data, StandardCharsets.UTF_8), + return gson.fromJson(new String(data, StandardCharsets.UTF_8), new TypeToken>() { }.getType()); @@ -156,7 +159,7 @@ public class ExternalPluginClient Request request = new Request.Builder() .url(url) - .post(RequestBody.create(RuneLiteAPI.JSON, RuneLiteAPI.GSON.toJson(plugins))) + .post(RequestBody.create(RuneLiteAPI.JSON, gson.toJson(plugins))) .build(); okHttpClient.newCall(request).enqueue(new Callback() @@ -190,7 +193,7 @@ public class ExternalPluginClient } // CHECKSTYLE:OFF - return RuneLiteAPI.GSON.fromJson(new InputStreamReader(res.body().byteStream()), new TypeToken>(){}.getType()); + return gson.fromJson(new InputStreamReader(res.body().byteStream()), new TypeToken>(){}.getType()); // CHECKSTYLE:ON } catch (JsonSyntaxException ex) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java index 661071a786..09d737c10f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/crowdsourcing/CrowdsourcingManager.java @@ -32,7 +32,6 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; import okhttp3.Callback; import okhttp3.MediaType; @@ -47,11 +46,13 @@ public class CrowdsourcingManager { private static final String CROWDSOURCING_BASE = "https://crowdsource.runescape.wiki/runelite"; private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); - private static final Gson GSON = RuneLiteAPI.GSON; @Inject private OkHttpClient okHttpClient; + @Inject + private Gson gson; + private List data = new ArrayList<>(); public void storeEvent(Object event) @@ -77,7 +78,7 @@ public class CrowdsourcingManager Request r = new Request.Builder() .url(CROWDSOURCING_BASE) - .post(RequestBody.create(JSON, GSON.toJson(temp))) + .post(RequestBody.create(JSON, gson.toJson(temp))) .build(); okHttpClient.newCall(r).enqueue(new Callback() diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java index d28f4b0323..f3d9b513b3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grandexchange/GrandExchangePlugin.java @@ -128,7 +128,6 @@ public class GrandExchangePlugin extends Plugin private static final String BUY_LIMIT_GE_TEXT = "
Buy limit: "; private static final String BUY_LIMIT_KEY = "buylimit"; - private static final Gson GSON = new Gson(); private static final Duration BUY_LIMIT_RESET = Duration.ofHours(4); static final String SEARCH_GRAND_EXCHANGE = "Search Grand Exchange"; @@ -183,6 +182,9 @@ public class GrandExchangePlugin extends Plugin @Inject private ConfigManager configManager; + @Inject + private Gson gson; + private Widget grandExchangeText; private Widget grandExchangeItem; private String grandExchangeExamine; @@ -253,12 +255,12 @@ public class GrandExchangePlugin extends Plugin { return null; } - return GSON.fromJson(offer, SavedOffer.class); + return gson.fromJson(offer, SavedOffer.class); } private void setOffer(int slot, SavedOffer offer) { - configManager.setRSProfileConfiguration("geoffer", Integer.toString(slot), GSON.toJson(offer)); + configManager.setRSProfileConfiguration("geoffer", Integer.toString(slot), gson.toJson(offer)); } private void deleteOffer(int slot) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java index c1e1774931..cfb6171941 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerPlugin.java @@ -73,8 +73,6 @@ public class GroundMarkerPlugin extends Plugin private static final String WALK_HERE = "Walk here"; private static final String REGION_PREFIX = "region_"; - private static final Gson GSON = new Gson(); - @Getter(AccessLevel.PACKAGE) private final List points = new ArrayList<>(); @@ -105,6 +103,9 @@ public class GroundMarkerPlugin extends Plugin @Inject private GroundMarkerSharingManager sharingManager; + @Inject + private Gson gson; + void savePoints(int regionId, Collection points) { if (points == null || points.isEmpty()) @@ -113,7 +114,7 @@ public class GroundMarkerPlugin extends Plugin return; } - String json = GSON.toJson(points); + String json = gson.toJson(points); configManager.setConfiguration(CONFIG_GROUP, REGION_PREFIX + regionId, json); } @@ -126,7 +127,7 @@ public class GroundMarkerPlugin extends Plugin } // CHECKSTYLE:OFF - return GSON.fromJson(json, new TypeToken>(){}.getType()); + return gson.fromJson(json, new TypeToken>(){}.getType()); // CHECKSTYLE:ON } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerSharingManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerSharingManager.java index 8899a81f0d..91c0e800ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerSharingManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/groundmarkers/GroundMarkerSharingManager.java @@ -53,7 +53,6 @@ import net.runelite.client.eventbus.Subscribe; import net.runelite.client.game.chatbox.ChatboxPanelManager; import net.runelite.client.menus.MenuManager; import net.runelite.client.menus.WidgetMenuOption; -import net.runelite.http.api.RuneLiteAPI; @Slf4j class GroundMarkerSharingManager @@ -61,22 +60,23 @@ class GroundMarkerSharingManager private static final WidgetMenuOption EXPORT_MARKERS_OPTION = new WidgetMenuOption("Export", "Ground Markers", WORLD_MAP_OPTION); private static final WidgetMenuOption IMPORT_MARKERS_OPTION = new WidgetMenuOption("Import", "Ground Markers", WORLD_MAP_OPTION); - private static final Gson GSON = RuneLiteAPI.GSON; - private final GroundMarkerPlugin plugin; private final Client client; private final MenuManager menuManager; private final ChatMessageManager chatMessageManager; private final ChatboxPanelManager chatboxPanelManager; + private final Gson gson; @Inject - private GroundMarkerSharingManager(GroundMarkerPlugin plugin, Client client, MenuManager menuManager, ChatMessageManager chatMessageManager, ChatboxPanelManager chatboxPanelManager) + private GroundMarkerSharingManager(GroundMarkerPlugin plugin, Client client, MenuManager menuManager, + ChatMessageManager chatMessageManager, ChatboxPanelManager chatboxPanelManager, Gson gson) { this.plugin = plugin; this.client = client; this.menuManager = menuManager; this.chatMessageManager = chatMessageManager; this.chatboxPanelManager = chatboxPanelManager; + this.gson = gson; } void addMenuOptions() @@ -135,7 +135,7 @@ class GroundMarkerSharingManager return; } - final String exportDump = GSON.toJson(activePoints); + final String exportDump = gson.toJson(activePoints); log.debug("Exported ground markers: {}", exportDump); @@ -173,7 +173,7 @@ class GroundMarkerSharingManager try { // CHECKSTYLE:OFF - importPoints = GSON.fromJson(clipboardText, new TypeToken>(){}.getType()); + importPoints = gson.fromJson(clipboardText, new TypeToken>(){}.getType()); // CHECKSTYLE:ON } catch (JsonSyntaxException e) 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 46a4a0924d..cfa99092a8 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 @@ -88,7 +88,6 @@ public class ObjectIndicatorsPlugin extends Plugin private static final String MARK = "Mark object"; private static final String UNMARK = "Unmark object"; - private final Gson GSON = new Gson(); @Getter(AccessLevel.PACKAGE) private final List objects = new ArrayList<>(); private final Map> points = new HashMap<>(); @@ -108,6 +107,9 @@ public class ObjectIndicatorsPlugin extends Plugin @Inject private ObjectIndicatorsConfig config; + @Inject + private Gson gson; + @Provides ObjectIndicatorsConfig provideConfig(ConfigManager configManager) { @@ -428,7 +430,7 @@ public class ObjectIndicatorsPlugin extends Plugin } else { - final String json = GSON.toJson(points); + final String json = gson.toJson(points); configManager.setConfiguration(CONFIG_GROUP, "region_" + id, json); } } @@ -442,7 +444,7 @@ public class ObjectIndicatorsPlugin extends Plugin return null; } - Set points = GSON.fromJson(json, new TypeToken>() + Set points = gson.fromJson(json, new TypeToken>() { }.getType()); // Prior to multiloc support the plugin would mark objects named "null", which breaks diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java index 88dca9d214..5ec747e3f5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerPlugin.java @@ -88,6 +88,9 @@ public class ScreenMarkerPlugin extends Plugin @Inject private ScreenMarkerCreationOverlay overlay; + @Inject + private Gson gson; + @Getter @Inject private ColorPickerManager colorPickerManager; @@ -266,7 +269,6 @@ public class ScreenMarkerPlugin extends Plugin return; } - final Gson gson = new Gson(); final String json = gson .toJson(screenMarkers.stream().map(ScreenMarkerOverlay::getMarker).collect(Collectors.toList())); configManager.setConfiguration(CONFIG_GROUP, CONFIG_KEY, json); @@ -279,7 +281,6 @@ public class ScreenMarkerPlugin extends Plugin return Stream.empty(); } - final Gson gson = new Gson(); final List screenMarkerData = gson.fromJson(json, new TypeToken>() { }.getType()); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java index 720c5633e9..30d16ff573 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/timetracking/clocks/ClockManager.java @@ -53,6 +53,9 @@ public class ClockManager @Inject private Notifier notifier; + @Inject + private Gson gson; + @Getter private final List timers = new CopyOnWriteArrayList<>(); @@ -183,7 +186,6 @@ public class ClockManager if (!Strings.isNullOrEmpty(timersJson)) { - final Gson gson = new Gson(); final List timers = gson.fromJson(timersJson, new TypeToken>() { }.getType()); @@ -200,7 +202,6 @@ public class ClockManager if (!Strings.isNullOrEmpty(stopwatchesJson)) { - final Gson gson = new Gson(); final List stopwatches = gson.fromJson(stopwatchesJson, new TypeToken>() { }.getType()); @@ -227,14 +228,12 @@ public class ClockManager void saveTimers() { - final Gson gson = new Gson(); final String json = gson.toJson(timers); configManager.setConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.TIMERS, json); } void saveStopwatches() { - final Gson gson = new Gson(); final String json = gson.toJson(stopwatches); configManager.setConfiguration(TimeTrackingConfig.CONFIG_GROUP, TimeTrackingConfig.STOPWATCHES, json); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java index 8552d90eef..622e4db98b 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/wiki/WikiSearchChatboxTextInput.java @@ -67,7 +67,6 @@ public class WikiSearchChatboxTextInput extends ChatboxTextInput private static final int PREDICTION_DEBOUNCE_DELAY_MS = 200; private final ChatboxPanelManager chatboxPanelManager; - private final Gson gson = new Gson(); private Future runningRequest = null; private List predictions = ImmutableList.of(); @@ -78,7 +77,7 @@ public class WikiSearchChatboxTextInput extends ChatboxTextInput @Inject public WikiSearchChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread, ScheduledExecutorService scheduledExecutorService, @Named("developerMode") final boolean developerMode, - OkHttpClient okHttpClient) + OkHttpClient okHttpClient, Gson gson) { super(chatboxPanelManager, clientThread); this.chatboxPanelManager = chatboxPanelManager; diff --git a/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java index dfee412c03..e842005dba 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ImageCapture.java @@ -26,6 +26,7 @@ package net.runelite.client.util; import com.google.common.base.Strings; +import com.google.gson.Gson; import java.awt.Toolkit; import java.awt.TrayIcon; import java.awt.datatransfer.Clipboard; @@ -54,7 +55,6 @@ import net.runelite.api.GameState; import net.runelite.api.WorldType; import net.runelite.client.Notifier; import static net.runelite.client.RuneLite.SCREENSHOT_DIR; -import net.runelite.http.api.RuneLiteAPI; import okhttp3.Call; import okhttp3.Callback; import okhttp3.HttpUrl; @@ -75,6 +75,7 @@ public class ImageCapture private final Client client; private final Notifier notifier; private final OkHttpClient okHttpClient; + private final Gson gson; private final String imgurClientId; @Inject @@ -82,12 +83,14 @@ public class ImageCapture final Client client, final Notifier notifier, final OkHttpClient okHttpClient, + final Gson gson, @Named("runelite.imgur.client.id") final String imgurClientId ) { this.client = client; this.notifier = notifier; this.okHttpClient = okHttpClient; + this.gson = gson; this.imgurClientId = imgurClientId; } @@ -204,7 +207,7 @@ public class ImageCapture */ private void uploadScreenshot(File screenshotFile, boolean notify) throws IOException { - String json = RuneLiteAPI.GSON.toJson(new ImageUploadRequest(screenshotFile)); + String json = gson.toJson(new ImageUploadRequest(screenshotFile)); Request request = new Request.Builder() .url(IMGUR_IMAGE_UPLOAD_URL) @@ -225,8 +228,8 @@ public class ImageCapture { try (InputStream in = response.body().byteStream()) { - ImageUploadResponse imageUploadResponse = RuneLiteAPI.GSON - .fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), ImageUploadResponse.class); + ImageUploadResponse imageUploadResponse = + gson.fromJson(new InputStreamReader(in, StandardCharsets.UTF_8), ImageUploadResponse.class); if (imageUploadResponse.isSuccess()) { From 243929826b99f3dad1605c48f85f000268bdc41e Mon Sep 17 00:00:00 2001 From: Max Weber Date: Thu, 24 Dec 2020 08:42:30 -0700 Subject: [PATCH 3/7] ReflectUtil: allow privateLookupIn cross-classloader with JDK-8173978 --- .../ExternalPluginClassLoader.java | 16 ++++- .../net/runelite/client/util/ReflectUtil.java | 62 ++++++++++++++++++- 2 files changed, 75 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClassLoader.java b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClassLoader.java index 054a7779b5..5690c3d61e 100644 --- a/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClassLoader.java +++ b/runelite-client/src/main/java/net/runelite/client/externalplugins/ExternalPluginClassLoader.java @@ -24,18 +24,32 @@ */ package net.runelite.client.externalplugins; +import java.lang.invoke.MethodHandles; import java.net.URL; import java.net.URLClassLoader; import lombok.Getter; +import lombok.Setter; +import net.runelite.client.util.ReflectUtil; -class ExternalPluginClassLoader extends URLClassLoader +class ExternalPluginClassLoader extends URLClassLoader implements ReflectUtil.PrivateLookupableClassLoader { @Getter private final ExternalPluginManifest manifest; + @Getter + @Setter + private MethodHandles.Lookup lookup; + ExternalPluginClassLoader(ExternalPluginManifest manifest, URL[] urls) { super(urls, ExternalPluginClassLoader.class.getClassLoader()); this.manifest = manifest; + ReflectUtil.installLookupHelper(this); + } + + @Override + public Class defineClass0(String name, byte[] b, int off, int len) throws ClassFormatError + { + return super.defineClass(name, b, off, len); } } 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 index 60b3b305f1..fbcc28d28d 100644 --- a/runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/util/ReflectUtil.java @@ -25,6 +25,8 @@ */ package net.runelite.client.util; +import com.google.common.io.ByteStreams; +import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -36,7 +38,7 @@ public class ReflectUtil { } - public static MethodHandles.Lookup privateLookupIn(Class clazz) + public static MethodHandles.Lookup privateLookupIn(Class clazz) { try { @@ -44,7 +46,16 @@ public class ReflectUtil // 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()); + MethodHandles.Lookup caller; + if (clazz.getClassLoader() instanceof PrivateLookupableClassLoader) + { + caller = ((PrivateLookupableClassLoader) clazz.getClassLoader()).getLookup(); + } + else + { + caller = MethodHandles.lookup(); + } + return (MethodHandles.Lookup) privateLookupIn.invoke(null, clazz, caller); } catch (InvocationTargetException | IllegalAccessException e) { @@ -69,4 +80,51 @@ public class ReflectUtil } } } + + public interface PrivateLookupableClassLoader + { + // define class is protected final so this needs a different name to become public + Class defineClass0(String name, byte[] b, int off, int len) throws ClassFormatError; + + MethodHandles.Lookup getLookup(); + void setLookup(MethodHandles.Lookup lookup); + } + + /** + * Allows private Lookups to be created for classes in this ClassLoader + *

+ * Due to JDK-8173978 it is impossible to create get a lookup with module scoped permissions when teleporting + * between modules. Since external plugins are loaded in a separate classloader to us they are contained in unique + * unnamed modules. Since we (via LambdaMetafactory) are creating a hidden class in that module, we require module + * scoped access to it, and since the methods can be private, we also require private access. The only way to get + * MODULE|PRIVATE is to either 1) invokedynamic in that class, 2) call MethodHandles.lookup() from that class, or + * 3) call privateLookupIn with an existing lookup with PRIVATE|MODULE created from a class in the same module. + * Our solution is to make classloaders call this method which will define a class in the classloader's unnamed + * module that calls MethodHandles.lookup() and stores it in the classloader for later use. + */ + public static void installLookupHelper(PrivateLookupableClassLoader cl) + { + try + { + String name = PrivateLookupHelper.class.getName(); + byte[] classData = ByteStreams.toByteArray(ReflectUtil.class.getResourceAsStream("/" + name.replace('.', '/') + ".class")); + Class clazz = cl.defineClass0(name, classData, 0, classData.length); + + // force to run + clazz.getConstructor().newInstance(); + } + catch (IOException | ReflectiveOperationException e) + { + throw new RuntimeException("unable to install lookup helper", e); + } + } + + public static class PrivateLookupHelper + { + static + { + PrivateLookupableClassLoader pcl = (PrivateLookupableClassLoader) PrivateLookupHelper.class.getClassLoader(); + pcl.setLookup(MethodHandles.lookup()); + } + } } From ca56ef10823aea1ecd275c0d3c3f9a3b17838ff9 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 30 Jan 2021 13:14:33 -0500 Subject: [PATCH 4/7] Apply default font to text with unicode characters MacOS does not support fallback fonts, and any character not in our RS fonts do not render correctly. We only render unicode characters a handful of places, mostly for the check mark/cross in overlays, and on the icon text field suggestion button. So this sets the font of those places to the default system font which can render them correctly. --- .../barrows/BarrowsBrotherSlainOverlay.java | 2 ++ .../plugins/cluescrolls/clues/EmoteClue.java | 5 ++- .../cluescrolls/clues/FaloTheBardClue.java | 2 ++ .../cluescrolls/clues/SkillChallengeClue.java | 18 +++++----- .../net/runelite/client/ui/FontManager.java | 36 +++++++++---------- .../client/ui/components/IconTextField.java | 9 ++--- .../ui/overlay/components/LineComponent.java | 30 +++++++++++----- .../ui/overlay/components/TextComponent.java | 24 ++++++++++++- 8 files changed, 83 insertions(+), 43 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java index c7cdef0058..4e4eba0175 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/barrows/BarrowsBrotherSlainOverlay.java @@ -34,6 +34,7 @@ import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG; import net.runelite.api.Varbits; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.ui.FontManager; import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE; import net.runelite.client.ui.overlay.OverlayMenuEntry; import net.runelite.client.ui.overlay.OverlayPanel; @@ -82,6 +83,7 @@ public class BarrowsBrotherSlainOverlay extends OverlayPanel panelComponent.getChildren().add(LineComponent.builder() .left(brother.getName()) .right(slain) + .rightFont(FontManager.getDefaultFont()) .rightColor(brotherSlain ? Color.GREEN : Color.RED) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java index b59be0da14..ab3ac38982 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/EmoteClue.java @@ -45,6 +45,7 @@ import net.runelite.api.coords.LocalPoint; import net.runelite.api.coords.WorldPoint; import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; +import static net.runelite.client.plugins.cluescrolls.clues.Enemy.*; import net.runelite.client.plugins.cluescrolls.clues.emote.Emote; import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.*; import static net.runelite.client.plugins.cluescrolls.clues.emote.Emote.BULL_ROARER; @@ -53,7 +54,7 @@ import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.*; import static net.runelite.client.plugins.cluescrolls.clues.emote.STASHUnit.SHANTAY_PASS; import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement; import static net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirements.*; -import static net.runelite.client.plugins.cluescrolls.clues.Enemy.*; +import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @@ -258,6 +259,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu panelComponent.getChildren().add(LineComponent.builder() .left("STASH Unit:") .right(stashUnitBuilt ? UNICODE_CHECK_MARK : UNICODE_BALLOT_X) + .rightFont(FontManager.getDefaultFont()) .rightColor(stashUnitBuilt ? Color.GREEN : Color.RED) .build()); } @@ -292,6 +294,7 @@ public class EmoteClue extends ClueScroll implements TextClueScroll, LocationClu .left(requirement.getCollectiveName(client)) .leftColor(TITLED_CONTENT_COLOR) .right(combinedFulfilled ? UNICODE_CHECK_MARK : UNICODE_BALLOT_X) + .rightFont(FontManager.getDefaultFont()) .rightColor(equipmentFulfilled ? Color.GREEN : (combinedFulfilled ? Color.ORANGE : Color.RED)) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java index 16974ffd16..c208d5238f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/FaloTheBardClue.java @@ -41,6 +41,7 @@ import net.runelite.client.plugins.cluescrolls.clues.item.AnyRequirementCollecti import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.item.RangeItemRequirement; import net.runelite.client.plugins.cluescrolls.clues.item.SingleItemRequirement; +import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; @@ -134,6 +135,7 @@ public class FaloTheBardClue extends ClueScroll implements TextClueScroll, NpcCl .left(requirement.getCollectiveName(plugin.getClient())) .leftColor(TITLED_CONTENT_COLOR) .right(inventoryFulfilled ? "\u2713" : "\u2717") + .rightFont(FontManager.getDefaultFont()) .rightColor(inventoryFulfilled ? Color.GREEN : Color.RED) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java index 67de8ad26a..41f6f283cb 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/SkillChallengeClue.java @@ -25,6 +25,11 @@ package net.runelite.client.plugins.cluescrolls.clues; import com.google.common.collect.ImmutableSet; +import java.awt.Color; +import java.awt.Graphics2D; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @@ -34,25 +39,21 @@ import net.runelite.api.ItemID; import net.runelite.api.NPC; import net.runelite.api.Point; import net.runelite.api.TileObject; +import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; import net.runelite.client.plugins.cluescrolls.ClueScrollPlugin; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_BORDER_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_FILL_COLOR; import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.CLICKBOX_HOVER_BORDER_COLOR; +import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; import net.runelite.client.plugins.cluescrolls.clues.item.AnyRequirementCollection; -import static net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirements.*; import net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirement; +import static net.runelite.client.plugins.cluescrolls.clues.item.ItemRequirements.*; import net.runelite.client.plugins.cluescrolls.clues.item.SingleItemRequirement; +import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.LineComponent; import net.runelite.client.ui.overlay.components.PanelComponent; import net.runelite.client.ui.overlay.components.TitleComponent; -import java.awt.Color; -import java.awt.Graphics2D; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import static net.runelite.client.plugins.cluescrolls.ClueScrollOverlay.TITLED_CONTENT_COLOR; -import static net.runelite.client.plugins.cluescrolls.ClueScrollWorldOverlay.IMAGE_Z_OFFSET; @Getter public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, NamedObjectClueScroll @@ -379,6 +380,7 @@ public class SkillChallengeClue extends ClueScroll implements NpcClueScroll, Nam .left(requirement.getCollectiveName(plugin.getClient())) .leftColor(TITLED_CONTENT_COLOR) .right(combinedFulfilled ? "\u2713" : "\u2717") + .rightFont(FontManager.getDefaultFont()) .rightColor(equipmentFulfilled || (combinedFulfilled && !requireEquipped) ? Color.GREEN : (combinedFulfilled ? Color.ORANGE : Color.RED)) .build()); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java b/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java index 564ebcba62..5305506a41 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/FontManager.java @@ -24,17 +24,25 @@ */ package net.runelite.client.ui; -import javax.swing.text.StyleContext; import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; import java.io.IOException; +import javax.swing.text.StyleContext; +import lombok.Getter; public class FontManager { + @Getter private static final Font runescapeFont; + @Getter private static final Font runescapeSmallFont; + @Getter private static final Font runescapeBoldFont; + @Getter + private static final Font defaultFont; + @Getter + private static final Font defaultBoldFont; static { @@ -48,7 +56,7 @@ public class FontManager ge.registerFont(font); runescapeFont = StyleContext.getDefaultStyleContext() - .getFont(font.getName(), Font.PLAIN, 16); + .getFont(font.getName(), Font.PLAIN, 16); ge.registerFont(runescapeFont); Font smallFont = Font.createFont(Font.TRUETYPE_FONT, @@ -57,16 +65,16 @@ public class FontManager ge.registerFont(smallFont); runescapeSmallFont = StyleContext.getDefaultStyleContext() - .getFont(smallFont.getName(), Font.PLAIN, 16); + .getFont(smallFont.getName(), Font.PLAIN, 16); ge.registerFont(runescapeSmallFont); Font boldFont = Font.createFont(Font.TRUETYPE_FONT, - FontManager.class.getResourceAsStream("runescape_bold.ttf")) - .deriveFont(Font.BOLD, 16); + FontManager.class.getResourceAsStream("runescape_bold.ttf")) + .deriveFont(Font.BOLD, 16); ge.registerFont(boldFont); runescapeBoldFont = StyleContext.getDefaultStyleContext() - .getFont(boldFont.getName(), Font.BOLD, 16); + .getFont(boldFont.getName(), Font.BOLD, 16); ge.registerFont(runescapeBoldFont); } catch (FontFormatException ex) @@ -77,20 +85,8 @@ public class FontManager { throw new RuntimeException("Font file not found.", ex); } - } - public static Font getRunescapeFont() - { - return runescapeFont; - } - - public static Font getRunescapeSmallFont() - { - return runescapeSmallFont; - } - - public static Font getRunescapeBoldFont() - { - return runescapeBoldFont; + defaultFont = new Font(Font.DIALOG, Font.PLAIN, 16); + defaultBoldFont = new Font(Font.DIALOG, Font.BOLD, 16); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java index cb317b8afd..b4c2ff1127 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java @@ -29,6 +29,7 @@ package net.runelite.client.ui.components; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; @@ -125,7 +126,7 @@ public class IconTextField extends JPanel textField.addMouseListener(hoverEffect); innerTxt.addMouseListener(hoverEffect); - clearButton = createRHSButton(ColorScheme.PROGRESS_ERROR_COLOR, Color.PINK); + clearButton = createRHSButton(ColorScheme.PROGRESS_ERROR_COLOR, Color.PINK, FontManager.getRunescapeBoldFont()); clearButton.setText("×"); clearButton.addActionListener(evt -> { @@ -192,7 +193,7 @@ public class IconTextField extends JPanel } }); - suggestionButton = createRHSButton(ColorScheme.LIGHT_GRAY_COLOR, ColorScheme.MEDIUM_GRAY_COLOR); + suggestionButton = createRHSButton(ColorScheme.LIGHT_GRAY_COLOR, ColorScheme.MEDIUM_GRAY_COLOR, FontManager.getDefaultBoldFont()); suggestionButton.setText("▾"); suggestionButton.addActionListener(e -> { @@ -237,11 +238,11 @@ public class IconTextField extends JPanel add(rhsButtons, BorderLayout.EAST); } - private JButton createRHSButton(Color fg, Color rollover) + private JButton createRHSButton(Color fg, Color rollover, Font font) { JButton b = new JButton(); b.setPreferredSize(new Dimension(30, 0)); - b.setFont(FontManager.getRunescapeBoldFont()); + b.setFont(font); b.setBorder(null); b.setRolloverEnabled(true); SwingUtil.removeButtonDecorations(b); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java index 20638e7874..83c67c09e0 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java @@ -28,6 +28,7 @@ import com.google.common.base.MoreObjects; import com.google.common.base.Strings; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; @@ -50,6 +51,10 @@ public class LineComponent implements LayoutableRenderableEntity @Builder.Default private Color rightColor = Color.WHITE; + private Font leftFont; + + private Font rightFont; + @Builder.Default private Point preferredLocation = new Point(); @@ -67,13 +72,16 @@ public class LineComponent implements LayoutableRenderableEntity final String left = MoreObjects.firstNonNull(this.left, ""); final String right = MoreObjects.firstNonNull(this.right, ""); - final FontMetrics metrics = graphics.getFontMetrics(); + final Font leftFont = MoreObjects.firstNonNull(this.leftFont, graphics.getFont()); + final Font rightFont = MoreObjects.firstNonNull(this.rightFont, graphics.getFont()); + final FontMetrics lfm = graphics.getFontMetrics(leftFont), rfm = graphics.getFontMetrics(rightFont); + final int fmHeight = Math.max(lfm.getHeight(), rfm.getHeight()); final int baseX = preferredLocation.x; - final int baseY = preferredLocation.y + metrics.getHeight(); + final int baseY = preferredLocation.y + fmHeight; int x = baseX; int y = baseY; - final int leftFullWidth = getLineWidth(left, metrics); - final int rightFullWidth = getLineWidth(right, metrics); + final int leftFullWidth = getLineWidth(left, lfm); + final int rightFullWidth = getLineWidth(right, rfm); final TextComponent textComponent = new TextComponent(); if (preferredSize.width < leftFullWidth + rightFullWidth) @@ -87,8 +95,8 @@ public class LineComponent implements LayoutableRenderableEntity leftSmallWidth -= rightSmallWidth; } - final String[] leftSplitLines = lineBreakText(left, leftSmallWidth, metrics); - final String[] rightSplitLines = lineBreakText(right, rightSmallWidth, metrics); + final String[] leftSplitLines = lineBreakText(left, leftSmallWidth, lfm); + final String[] rightSplitLines = lineBreakText(right, rightSmallWidth, rfm); int lineCount = Math.max(leftSplitLines.length, rightSplitLines.length); @@ -100,19 +108,21 @@ public class LineComponent implements LayoutableRenderableEntity textComponent.setPosition(new Point(x, y)); textComponent.setText(leftText); textComponent.setColor(leftColor); + textComponent.setFont(leftFont); textComponent.render(graphics); } if (i < rightSplitLines.length) { final String rightText = rightSplitLines[i]; - textComponent.setPosition(new Point(x + preferredSize.width - getLineWidth(rightText, metrics), y)); + textComponent.setPosition(new Point(x + preferredSize.width - getLineWidth(rightText, rfm), y)); textComponent.setText(rightText); textComponent.setColor(rightColor); + textComponent.setFont(rightFont); textComponent.render(graphics); } - y += metrics.getHeight(); + y += fmHeight; } final Dimension dimension = new Dimension(preferredSize.width, y - baseY); @@ -126,6 +136,7 @@ public class LineComponent implements LayoutableRenderableEntity textComponent.setPosition(new Point(x, y)); textComponent.setText(left); textComponent.setColor(leftColor); + textComponent.setFont(leftFont); textComponent.render(graphics); } @@ -134,10 +145,11 @@ public class LineComponent implements LayoutableRenderableEntity textComponent.setPosition(new Point(x + preferredSize.width - rightFullWidth, y)); textComponent.setText(right); textComponent.setColor(rightColor); + textComponent.setFont(rightFont); textComponent.render(graphics); } - y += metrics.getHeight(); + y += fmHeight; final Dimension dimension = new Dimension(preferredSize.width, y - baseY); bounds.setLocation(preferredLocation); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java index 45326fea28..0b6054a466 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java @@ -26,10 +26,12 @@ package net.runelite.client.ui.overlay.components; import java.awt.Color; import java.awt.Dimension; +import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; import java.util.regex.Pattern; +import javax.annotation.Nullable; import lombok.Setter; import net.runelite.client.ui.overlay.RenderableEntity; import net.runelite.client.util.ColorUtil; @@ -45,10 +47,22 @@ public class TextComponent implements RenderableEntity private Point position = new Point(); private Color color = Color.WHITE; private boolean outline; + /** + * The text font. + */ + @Nullable + private Font font; @Override public Dimension render(Graphics2D graphics) { + Font originalFont = null; + if (font != null) + { + originalFont = graphics.getFont(); + graphics.setFont(font); + } + final FontMetrics fontMetrics = graphics.getFontMetrics(); if (COL_TAG_PATTERN_W_LOOKAHEAD.matcher(text).find()) @@ -105,6 +119,14 @@ public class TextComponent implements RenderableEntity graphics.drawString(text, position.x, position.y); } - return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight()); + int width = fontMetrics.stringWidth(text); + int height = fontMetrics.getHeight(); + + if (originalFont != null) + { + graphics.setFont(originalFont); + } + + return new Dimension(width, height); } } From cdba2ef2977e3b477de3c079f7e7a34edb398248 Mon Sep 17 00:00:00 2001 From: Broooklyn <54762282+Broooklyn@users.noreply.github.com> Date: Sun, 31 Jan 2021 11:57:00 -0500 Subject: [PATCH 5/7] hotkey button: use default font --- .../java/net/runelite/client/plugins/config/HotkeyButton.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/HotkeyButton.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/HotkeyButton.java index 55b9160c5b..131aef04bc 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/HotkeyButton.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/HotkeyButton.java @@ -32,6 +32,7 @@ import javax.swing.JButton; import lombok.Getter; import net.runelite.client.config.Keybind; import net.runelite.client.config.ModifierlessKeybind; +import net.runelite.client.ui.FontManager; class HotkeyButton extends JButton { @@ -40,6 +41,7 @@ class HotkeyButton extends JButton public HotkeyButton(Keybind value, boolean modifierless) { + setFont(FontManager.getDefaultFont().deriveFont(12.f)); setValue(value); addMouseListener(new MouseAdapter() { From ab4bb3bc977820fcdefc058c0cacd7277e3c9324 Mon Sep 17 00:00:00 2001 From: Adam Date: Sun, 31 Jan 2021 12:34:00 -0500 Subject: [PATCH 6/7] Revert "runelite-client: Don't use system specific modifier key names" This reverts commit 962bc58178503ee8ffcd0890b3b2882370ffd5eb. --- .../net/runelite/client/config/Keybind.java | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/config/Keybind.java b/runelite-client/src/main/java/net/runelite/client/config/Keybind.java index e7e338a6b3..eba500b859 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/Keybind.java +++ b/runelite-client/src/main/java/net/runelite/client/config/Keybind.java @@ -159,7 +159,7 @@ public class Keybind String mod = ""; if (modifiers != 0) { - mod = getModifiersExText(modifiers); + mod = InputEvent.getModifiersExText(modifiers); } if (mod.isEmpty() && key.isEmpty()) @@ -177,33 +177,6 @@ public class Keybind return mod; } - public static String getModifiersExText(int modifiers) - { - StringBuilder buf = new StringBuilder(); - if ((modifiers & InputEvent.META_DOWN_MASK) != 0) - { - buf.append("Meta+"); - } - if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) - { - buf.append("Ctrl+"); - } - if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) - { - buf.append("Alt+"); - } - if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) - { - buf.append("Shift+"); - } - - if (buf.length() > 0) - { - buf.setLength(buf.length() - 1); // remove trailing '+' - } - return buf.toString(); - } - @Nullable public static Integer getModifierForKeyCode(int keyCode) { From fe01c7dbf4a421c885787cec95c06fed5e168320 Mon Sep 17 00:00:00 2001 From: Psikoi Date: Sun, 31 Jan 2021 19:15:54 +0000 Subject: [PATCH 7/7] Resize and tweak hiscores boss icons --- .../plugins/hiscore/bosses/abyssal_sire.png | Bin 876 -> 687 bytes .../plugins/hiscore/bosses/alchemical_hydra.png | Bin 435 -> 366 bytes .../plugins/hiscore/bosses/barrows_chests.png | Bin 272 -> 251 bytes .../client/plugins/hiscore/bosses/bryophyta.png | Bin 594 -> 493 bytes .../client/plugins/hiscore/bosses/callisto.png | Bin 364 -> 315 bytes .../client/plugins/hiscore/bosses/cerberus.png | Bin 291 -> 276 bytes .../hiscore/bosses/chambers_of_xeric.png | Bin 518 -> 398 bytes .../bosses/chambers_of_xeric_challenge_mode.png | Bin 510 -> 358 bytes .../plugins/hiscore/bosses/chaos_elemental.png | Bin 471 -> 341 bytes .../plugins/hiscore/bosses/chaos_fanatic.png | Bin 515 -> 371 bytes .../hiscore/bosses/commander_zilyana.png | Bin 616 -> 497 bytes .../plugins/hiscore/bosses/corporeal_beast.png | Bin 861 -> 600 bytes .../hiscore/bosses/crazy_archaeologist.png | Bin 863 -> 568 bytes .../plugins/hiscore/bosses/dagannoth_prime.png | Bin 384 -> 336 bytes .../plugins/hiscore/bosses/dagannoth_rex.png | Bin 382 -> 338 bytes .../hiscore/bosses/dagannoth_supreme.png | Bin 352 -> 317 bytes .../hiscore/bosses/deranged_archaeologist.png | Bin 368 -> 323 bytes .../plugins/hiscore/bosses/general_graardor.png | Bin 531 -> 430 bytes .../plugins/hiscore/bosses/giant_mole.png | Bin 422 -> 357 bytes .../hiscore/bosses/grotesque_guardians.png | Bin 332 -> 288 bytes .../client/plugins/hiscore/bosses/hespori.png | Bin 478 -> 399 bytes .../plugins/hiscore/bosses/kalphite_queen.png | Bin 422 -> 364 bytes .../hiscore/bosses/king_black_dragon.png | Bin 331 -> 304 bytes .../client/plugins/hiscore/bosses/kraken.png | Bin 351 -> 294 bytes .../client/plugins/hiscore/bosses/kreearra.png | Bin 407 -> 343 bytes .../plugins/hiscore/bosses/kril_tsutsaroth.png | Bin 549 -> 449 bytes .../client/plugins/hiscore/bosses/mimic.png | Bin 403 -> 363 bytes .../client/plugins/hiscore/bosses/nightmare.png | Bin 609 -> 492 bytes .../client/plugins/hiscore/bosses/obor.png | Bin 627 -> 389 bytes .../client/plugins/hiscore/bosses/sarachnis.png | Bin 488 -> 409 bytes .../client/plugins/hiscore/bosses/scorpia.png | Bin 333 -> 282 bytes .../client/plugins/hiscore/bosses/skotizo.png | Bin 473 -> 382 bytes .../hiscore/bosses/the_corrupted_gauntlet.png | Bin 546 -> 419 bytes .../plugins/hiscore/bosses/the_gauntlet.png | Bin 618 -> 510 bytes .../plugins/hiscore/bosses/theatre_of_blood.png | Bin 613 -> 487 bytes .../bosses/thermonuclear_smoke_devil.png | Bin 543 -> 462 bytes .../client/plugins/hiscore/bosses/tzkal_zuk.png | Bin 583 -> 370 bytes .../client/plugins/hiscore/bosses/tztok_jad.png | Bin 315 -> 292 bytes .../client/plugins/hiscore/bosses/venenatis.png | Bin 378 -> 341 bytes .../client/plugins/hiscore/bosses/vetion.png | Bin 391 -> 347 bytes .../client/plugins/hiscore/bosses/vorkath.png | Bin 597 -> 478 bytes .../plugins/hiscore/bosses/wintertodt.png | Bin 873 -> 759 bytes .../client/plugins/hiscore/bosses/zalcano.png | Bin 485 -> 407 bytes .../client/plugins/hiscore/bosses/zulrah.png | Bin 374 -> 346 bytes 44 files changed, 0 insertions(+), 0 deletions(-) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/abyssal_sire.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/abyssal_sire.png index 0209db1f974818c6d8638e7ba7f39c3f860ca2b8..c5b238a9d09d126105b1e6ee9bea13ffd60eb814 100644 GIT binary patch literal 687 zcmeAS@N?(olHy`uVBq!ia0vp^5Xfq~I0z$e5N$R!mR=;%1w*jO4F zadNPm8XAfU3lwGe6r_1uo0*yF=%{OI8mOr$$V$sfNbvD+vokaMdAMi9ySg|yT3A|| znwt3==&30yYpKaZ$xHi7OEgas6cXUEbK=et;Yt#flaB~WD^Y(Ui zceAl~@V2#0PquNevNAKU3iL9|Ha75M(08`gP14g2*3oj)(zGyBk5N)swdI=CqK76-(xaS&*%d8UuPb< z_NTkq3|btHP50?AKJu2)tl{9#n!npu7RUy$Fr1$^RW)@X%i4~R17&{m=G91hFWt`@ zIm@!O%>C_=jca%Ie^2^*V&i#RLnqY-~l?XJ9fWy=#Wc|FN8`_3xMsy)kBJnL6) zQCgNVVRMDW{(Td@mwMhfxKlzgWJSn(?n&#^J*Irx&to=GF?I8f70Q;42^Yj|ug;w+ zv}vE(hN}weOt${I@tk`{rDn5y+=IloFQu3YzkN8>%02(P{tAheKj%zKwfn&=yS#fF g+a>i>M^8)Z|7XP%cJeCEZ3QJePgg&ebxsLQ0P8Q(s{jB1 literal 876 zcmeAS@N?(olHy`uVBq!ia0vp^qChOd!3-orr?xRNFfjfI@Ck7Ra>)QpOpI|CzyZoxWQ8k(9+jEu6fT%ioow#LR5y1LrxvVq)8E-Vbn3=9%t0vxO?3bLYs zUS`I|#*VhOB0|E>wz@(BJib11YN{$`hK6<)7T&hDlLZ;vyuDqWoGmRaqd6H&w6)C) z3>P&6%*l8)7DOBXW(FB6c!RPHZe8O(NPc=PtwyaQEak7aXC5R0Jp?UmYI|8l>XX{eYBQk#3 z($Ut{?C$F6;^F4y{QezLYXN`oE%*2 z=$$=VL_T23{=JJguim|UyZ-+ALq|MIColIAWw0#2^+nQ{^D|vjdB)S# K&t;ucLK6Vl^XKCL diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/alchemical_hydra.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/alchemical_hydra.png index 3b708b7522d2f340a64f4887fdbf6355aa2880a7..b34ed9c93e42e60fb4816b7b895caba0284349dc 100644 GIT binary patch literal 366 zcmeAS@N?(olHy`uVBq!ia0vp^5NYw@Sgt!7}2vBiwNGg_%YHAHE zEB7rdvI-3gs;t(uvyZH6NzZK#tF8CU&JBska!E;Z^$0g`^U!efP_nW~?3&;hnBeIf zW9sB*n6W%M28EiZtDnm{r-UW| D))0vD literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+3?vf;>QaH!>Hwb**Z=?j1DO!uTUe}OZy%i_ z<&~3X>g%WB=8;q^8(3E1lV4yJ8WvPp9ah(%=H%>=mF=9IYUJe;(b(*kmTnszW8mfy zP*NJ*)E-)0YZD%kS}vQ@z96Z4LR5WgKys-=K%9+NgqFQSR?F;!j{b<+W}mnMr=TPa zBO47Hn}V|5wA`kUh%8Uv7*i)dB`cfChM7@ug>GI^t{!0y&VjZLzQvUjGV@wY7Orvz zI+VF2$S;_IVcKJnic(YU~go~+5qpNFoj+Wm4|EbfM zl#QQg7F(J7iY$$1j$~n&80*cVCA-L*<(7wez;+j*8GgKyDiY2sldWXAgqcl)g?1d3 z+}hZgyel+dPo!MBmciVa`vL`@*?bW5DV@gDV<6(V=9;5O?l$Y|{ef%MGwM0|mVZ|5 zTYq(Vl73V4q_oO7li%EjY%6U}U*Emc{gS#a_wKzLmgR^2S-5Nq_t_tM9@ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/barrows_chests.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/barrows_chests.png index 89ebe418dcc6662dc8ef41f6008ba24812aad3f2..1560f1aaaa10a428c0c440741e96c10241d9c98b 100644 GIT binary patch literal 251 zcmeAS@N?(olHy`uVBq!ia0vp^5|JxJDtM+tp43W5; ztiT{4I?=+Xe}aY6be0EQQ?}@7AFOcFOW!v0P=%JBp88~GQH50vbEZySD6@=DeEQYN zz6zopr05k$hxBvhE literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+3?vf;>QaG}Wq?nJ>;M1%flLVKZ%&-un_*(2 zJbz-2oSdkwt)`WQy1u@Gs;Y#91fQd$wzjski;KRer=hR6v0Hg}Ay6B0NswPK1H-h( zQlHiXxy_y~jv*44Q!hN^JFLLLl5jjXY^~__@AWqr)2FX}+<$U9H;3lZ=qV15eB)H^ z6e=EU-ssAtkk8tu;<$G0+r2VvDm__Oue@=Xkic_z%`e3>FQ=93K3($MWRHMB``I4G zCE_pbRbRxX7bP0l+XkKGNoSE diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/bryophyta.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/bryophyta.png index e64276d9caac5de32aaf29f7895afedc036da05a..68c4e2c90442d97822113cbfb9d64caffa734f90 100644 GIT binary patch literal 493 zcmeAS@N?(olHy`uVBq!ia0vp^5NbL>q32_C|n4r2fDn8!4IMS@B zCOE6aFDJw(BHSR(Rk5KvKE1#vGtMJE-8DPQHquEk#7;K1JTN)iBQ4S;DaoQD)*?3A zG|gMp)I?56L9BIRQbl7#bxue@l237iXHJ4=bc#zxiBm$TQ+S+1L7shbhIMU%Rb`}3 zafqh2zO1T-q>K!|hzPF`KSybOSbbqwX}W)Im0MS~LsP0vPJo7kgQ~8Mq>+wFQ4jTxt1mvHZAmX~peD#j+ z@4o!{KVOt_=Y&sZ(x1#}8wEb* SpRtPu`O?$X&t;ucLK6VZvb2T( literal 594 zcmeAS@N?(olHy`uVBq!ia0vp@KrF(+3?viZxXUsyFxmz9gt!8^qylLPfy8JFL4Gb) z7Usfeoyr7l4Gqb}D9hF?qoQcd{4`sAZRxxmmxff`%xJ@sVz0t{cR2-7b#=+KAdQrC zm-Kw^q%03zLq%aBp4=#-Xm2fd5AC2ZD>olw7G@?kHkO=J+n5kzFCV?U4DX0|2TM~m z8EL`79G{eUmmoj0q70wZSStxJ0X9|^QDK27f9t|zpNtsym_WPCcsBuR84+<&eqT4^5MK*EUQPooDMKCkq$sCQKMP550ajLK78Yh}Qzan*E{}qK zdtmShlmz(&Gdx&euu&i&;qt74319ma9O5>2*8t@qkczK@Y*x*#Tspu0|msgH}T=%A~RkL=n3AY?yvvTR$#jBT}=XNO=VKgt!7}2#}GIQdU&d*3>l8 z(^FSfb+WS)5fn5xGP1L@^zm@BGBfjXb#--eEX>PDh>VB{3rk6gi3|=73h+s`G>_EQ zY@U5F5@--pNswPK!?gVWzdeDx1)eUBAsXkmUN~9AtSG>ILE)K>woLKPc zyC+VwB+ps7>RnL5OcR$E$CN(yayQspt~yy#R_ypYzUK7DuZ6EJOGa+6`)69)KyhY^!260#eF^8>?|#n6%~`BBV)qC9BpjeoSfujWJCl7<0B#> zgM%ZrHN8AslP%4io$P}Gd{UBP@^jKl3bPm(7~fs(>jj$5ToU9L%)l`1vDByaK<-vg z7sn8Z%f1s{Pdlu@(K2~~%fu7gB)8wq{`}8Ba?8!)Y4#7E8z@~aIp*Zj{k-y@wP5QB z*?j_Q6;n0OtTCC8y=|*nx2k*TT;;0WF_-tHx2?=t+;=ZOTSL+C!mOp*TLdV$JYD@<);T3K F0Ra36hnfHY diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/cerberus.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/cerberus.png index 8d0802478387885cd93eaf406d7a88cec114df56..f7dc1f8047d9fe636209a75eee663d964dd8a376 100644 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^5NI3=ggt!7}2#{xB@ZsYW6BJAl z=CtEvFyLg!7vs}lU{I5k?2;9T65EaloaenPYZ@$9{Jgkp5^5*^fd-wk;-B2^uu)ui&LQ=fb z-adTA@yS-!q3w$DjN8>qKL?@zf0MO+-}Pf3^|CEz@_#(cbgMV7 Q#v0@|Pgg&ebxsLQ0PMb93jhEB delta 280 zcmbQjw3w;BGr-TCmrII^fq{Y7)59eQNb>`+AO|y$G`+$$8At^N_=LFr|NkGz1Ohuw zh9n_QKR!+|A)zu!zF;BFG%-#WJ_dOPhI}zT15O4F1_nt!J{@@(HA%_xk{~ZW&Ic=H z_DztC5aMi;;p>$bGUsH772=#1dp?h0Vu5JA#AV+Jw}lQXaJZxf&T5%twsrfL|Mpv6 zEl_@Znz1aFx6$EgOJIV6AFqn%bXHl;*PB-I9J_kMrLAE?PWWEmrr(7&BFW69>ny+X zU3=cWRcuc3Ibq>@^I6i0`EFbiUq0^^Z{1O@4U_IDFN}SBUg5dyMqP)fUyB6h@Am)O ZW-oJ0uH+)DkaMp?2dn*B#LLXg($Xp^DOpof@A2{I>+6=HqtVva&eYYmzrWMi+2iKs$Ii~y+uP;o>Br5^ z!pX{{udjWDhpxD}thTqez`?n~!l<*fyTZiK)z*E6hir6p)!ErpPMzhs+w$SPJ z`l_r9hNH1Ff(ljp6Mm}ciXk&XFqNR(80roj9SkbIp|26%+Cn_t(wutlPb~eBMzxkS?ps#7b7AGC zIsKbwm9Cr7w4^t-yD~J*rR~_-q7{?#y2@n>iZfdZ!x{>tvT~BDvjR%fM5AJ23w-X^ z=g9zVWhx2s3uc&>|NplqkT=iM#W6(V{MHG_`C1HkTu$Eb=5bu zk#zELdbZlFr7TB|{pnrM;N5C4K~-QK<3G=gY+a=*Gv7R9oP3qfap}rv0mhKY*EaoR zth}8dC*Py>cuL!owyVN>-qkz1OU(bm__)YZ1Xzth;+b%719VbOQvjCKT+{!L0002JNklVHy~SNiad-Lu&tXfGmdPcXeQTLx%n%1Sv&6ySbp8>zKyupz zZjTr6`C)-TPzuT62<#nEDJJ3x*h`YBbVdm45=SP#V`W4?fn=yJ7QZ?-!yO6ctm=pIk!3w2Pc<9Z`MMeRNX zGr@x@NEHS6gt!7}2uKLe$xNt-3Q7z2 zPYLpl_jC?%vGY%kF3L}>KU9(*8)Yt}36oZr=78 z%1j^kdcF``qttnbc~;pB0kg#cWm}#s_^I>Nr&s9P_jvtl1u{jB2l7~=UwHg>@?5-X z(wPN82Sv7R+vnG~z{qb^fOz6e&0BrJLF~2HI0Y+SKYf^T_jK&0?+JfGv&6S6?Y5oU fUz;WP`~Op3brx3n<%={ML4o7x>gTe~DWM4f)3|>L literal 471 zcmeAS@N?(olHy`uVBq!ia0vp^{6H+g!3-q-bzC(AQqKc?LR|m<{|{sWfrV<|=InHJ zX{&3!ok12ALY&e!r%X6hlJBaQ8fad6y}x^7W}1(2o{pTu+Vms`otQIKr7KbsuCz9I z=x5}m)}_al$A{;H`=@3mRK|v6#)M=gM-_$pr{t&B2YJWE1ZM_##<|-0#{_4@g=UBQ zC40MsC5Go_Csidy7v`rmq{fyQ>)S*HrUm=NCxqpM2c%@gmnVehMhB%QMHNK`rTV!? zMFpq1+WQB4C&Y#4g!m--xS>vJ zI)^yh`kENnDDW>i2J|FTNswPK!?gVWzdeDxxt=bLAsp9z{jZ8O1qh_DGjFusAj%q@ z^XA5>CmPg?QMrVx{;8U2$&)`et$bqh|Lb0JGRYq|FKU(DJDGQC?*mYBus zgfDZraQ#=>?%VQxr%uk|$avmewfF8^VUGUiumAq6%}BekPyhXLUa8PGDq5h(@pScb JS?83{1OS#huo(aV diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/chaos_fanatic.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/chaos_fanatic.png index b27a0109358c901c0963a4727efc72884c74772e..b712e9b70a9cd1db051d4960ffc242668fee5aba 100644 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^5NVNp`gt!7}QUN0)qraD@36rrZ zqY674n+v;(4TF`nxw#&bo&ckOFSD;Uqqdf+8Xpf2I|F+Zb5v|-XqdmBx0{=*gM$-; zgN2ESvA({ZjEaloaenCpbFsq)JkF{+kNY+5dNM8Uef|D3({@TeKCbLIAvajBqVq6U@r)lA zxok`q%(=|LtT4^Z_O;{JQ??~rP5g>qtlcW;5hmKea^Xp)oAt^3XoE*9c0Y7!=ULzR z=uX8?e&@ALTJY0zQgJb>WQ^T$+k@6U`>cX^4_R`#aWrV$DErHJ*^@(8 T&v?%%P|$h0`njxgN@xNAhtnz>VB*c@ZOUR|$6({c;Gn{! z!p6X+&#dRq;P1le?8@%q%I?a~$j{8c%)-pX#KPq7fpe^&JGkd*4O9b;jyu_^z-llDzY*&jSUTDW@ggU(e`$8FE=zSI1v!N z?(=D&{8CRB#}J9jy%&y(H3bN;J@Bq@b#Rg0y_@^!5wYF(|0kAk9(MZwwEUTm;3sXK z(;pvfl5P#K5b8a;(pPb!&r-$7tO>fW&OPNm8niQLEvMMmE7E7fc3*zmxV3r3SN2~5 zD#xyc%k`>n>bSP(@=V8xg70fKmMEBpWwS2M-+VVy%kJtO`4W4*seS5~8^6>r9#`qx ve~(EbbccP5LfF%vRhuO^YvR=>)qi6AWXQk2qEB)*C@MW&{an^LB{Ts5)KZ1- diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/commander_zilyana.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/commander_zilyana.png index bec91f5bc183edc8886564f7fc6642cedb2320e5..9f1d6d20cca73317ea4192b347d000e118b05b8d 100644 GIT binary patch literal 497 zcmV3{mCLY^!>EO{ntRc~c&U(cql<5zhig<+X@6{1 zwOduER8ON(OqEJSfImBIHZsG*%cG>kxw*rEg1wfOyxhyVkdd@|d$gjWt!-|iY;B*A zkei5zl7@zm*U5`^c7D^ueQ|MnY;1LEYH_uvXohlIn2c7MO-OrjMvO*6T1`EKLOp0R zFJUh(MIjz;6%LrId&&R+00MMUPE!DuZ~yyA0002MNkljx z3`&x2HnVZjp5=1sR3#2-%ZzKZYf*C{5m?x@MVBfr#3e@`8X*TA^}rC nufkg}xP81YBI|oZ^rv|OOlA(r7G5-900000NkvXXu0mjf+z{ik literal 616 zcmV-u0+;=XP)ox;X5r!G<>MDXh_DC>ac~HWh=R32M8w2dB_yS!Wmpip*kt8I`oRaAitW=4=h)YO4MLsLXcTSu3Lk%2`|-@wq&(8$=t)Xdz}0wiK-WvyYuX=H0> zug34-2oiB}c5!uebNBG@^z!!c1^R`>&(S|1Feo@AG%UnBJR*{X!PhE^g(W&BHZI;P zAu%c0nuUQSg@qYpe=19wS31agpzX|%&|n6085jZ3n;R(+>-l#80000Xfq_vlz$e5N$R!?3Xe}*2 zTRpF%x3QqMBqc7?i=U5&nVEUp%85&7G|!z-GqbmvBZJ&R z{G1ZJoKoHG{XA^_U2Gg}Ohc_q-R(^5tqjeLv@MKP)l?Le6{OXbrQ}3K&K=o!WaqL& zTj%dxKW)+UrsnFbwyLbk{Djiv_>!!c{Djby*nsRr_sl?de=j#5dvkve6Mu6fHwQfz zBW*VWZ97X%Qws*jTzM(KavIi9QZ#)K=cK-QSg*&*B4)E=|3X%EkcLWFgrQ( zhuY%if&*I=c1@mIrMS-KdW6gx#d)93eX6->a;EW|Uz4)hlm}Zhrm(&)%jhuL8eX*S zZaB*|$A?m1Za%;DWmVSKpKJcH7wvhx;oF`mS2H{wUH#3OcKYIXcHR^Hx6aE{Zj6rQ z>J#01Yv1Dz-4&{@q9u2h-z=RkC$;t7+1+zE6?-!-oeBHN+H4|ge6ZFw4U|4SUHx3v IIVCg!068k=k^lez literal 861 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9S!3-p~d(N$3U|{?g;1l8sw+r z#LvTyiIFir+-uFENwfQFG82PEg#|Pu5fvSJ*qO=omh)s&bdRvH_e$lv1ZrW zscYtUx;a^TyI4ufbKIf^!IYhPIQk64y?{dPIk2^O^$al(&p#m+r_hTB{2H= zOM?7@87@3f=wG(r>x4ZH2Lu8NY97{rQp|r(7sn8Z%gG4`SS5ZoHgLLj#5)9dM6^hH zwz#^4_{2C(67_6}_lj~0^NVX_J(T|Vd3Z?Bv+%&s;Oh_CJ3eM-Wxjs#>ZP=Vl;muU zPsU8GH++AdJ#$u9XYHEYoVP#T{%mxT;p_7|r?)Qeo!q>*dv^QgI4Gut+5c}iu;9Uj z3mZOkoY2slka#BWqT$BEjUPEXJx^)|SnmwJe972o^QNE0ML!e$&Y#xT(9zP<)YWe1 z4h;zly?*7|RdbU=Ejwn&z`{tB0$0?W(T&edf2i&m0!fM>B0wUu}6=`^-4) z+$>x6B<1&aDnEz7#Nc{=$32_C|lmmH5E^ZFy^a#Ch zS2WRF0zIFYw z^x%*4rmz83T=jHu4AD5hb%J}*AqN3hT?4k{$%$!GHn#{_KA&U!eLuHWnD0TMs_Xx+ zu77nsUS2|LmX}KN`Jd}=7+o#Wmf>WT`@~Sc#QTfebJ=NsoCP+$c(iFpwn^yQIgJWu zroDK3v^0B`>Vae1JESYOM`~s-`@sHrTe6gB>B2M1tlUHtPHZlzjCjF!OsBCy=;PH1 zR;~9k4n6-PVc_l5DKZEX+*u(p*6<;@-9r{*L^f_M%=6@?MULAs!koRRj} z(w=s55nfsu;TEYO#uJMDW>tm-+AGUTa4<0f0fV>@ru&^*Q8mY-9`j~jz zh)1}}2RTTq$nu7{$obhxsmSv9*h+~Daj>y69pMPc06IvuB*+h#95`dPzIk4k*48rH z$k=wyvThH57LH&>)9406y>ubB^-a?P#ZvYduK;Rz=jq}YB5^r6fq_XaO)Si;OrX0_ z(4}C-s+HLpS%pP~pBq>!ww9KB{ld%B+vDr=(}C$v+B30fVb{#Im3`x5Qebp+S5FrY zH!tV+*Uz88r6?b7|G(kDf(H{W7$h!`bb2T_G4P_{#=?)Bot`IsdU%vHS7vs;l$;rP z({g9!$wfUpK0jGoU5~0RO?@glHEEH9?xWDFrdvzD^7i_k)mLZep7HYopf=o+qeUUUy_w?*$4n1*Zp7Ly?@_T<+xy3yl|0pRRSI}D@u(jf3 tkn4=+4h}1`ZWg7cFfKU3B|3qD!CArjP0R(I6rj%;JYD@<);T3K0RTiJ;~fA1 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_prime.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_prime.png index 18e004e18b9f6a4137eeffa9471463f45ad60f9b..bc6612dbf421d80be5bfa7699506a382ed90040a 100644 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^5NTmh%gt!7}2*@;6jZTgZiwP^U z)XvDyNXSSCj0ns(Q%}xLj*O4=3-Jqy3i0ssSXrqvJzLe))799*xZX~$+D2zliPnNb ztz-igFBK^#Hzx~Qi@Evgy{XD^dWxk%a?Xm9aZaM8C#pc!GnEAS1v5;`|Nq+)$eZrz z;uxZFervxw-(dqDma|hmM7`gc+W!BaGUtxYYmo!oA55$jwppmM1c*6k25kGUdUM|< z!38}BW<@^K2#I2goXFMZERem5Lwy=89kj@L>5Q$=HeZ{3ut2NxGQ)G{1zopr01&lz00000 literal 384 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv@!3-oh+|s`Ssonse5ZC|z{{xvokZG)%n3?Dw z>K_&p7M&Cw5)~4Y8dGkiQ){c|p)45~5f~XC8J`}Xk)M%On3brn?BVN?oSp2WDxG7h z?it{jmYY^>qf=n6o@S_OXl__yp|!e7XGMk1f&vA-vI07VsU*lRm|}q&W`{)02Ne%7JGnd1{-(RV?r_YmcPv=1m+g8&NY|AcZzT12J!;06>xq0$$hj;K#<&rC!p6c~tuR{8Lk!AfW Z-*Mk@VZR%vdWanqik_~1F6*2Ung9p_kLUmZ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_rex.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_rex.png index 1b73c2d416676b4884d009716817ac74dabc8ca1..a18662f7024b2f3fc78163a5b72eeea9faa8d50a 100644 GIT binary patch literal 338 zcmeAS@N?(olHy`uVBq!ia0vp^5NTmh%gt!7}2(Yy>%t;GNj`J_f zj;gLo%1jDLO$dmK^h${KP0LcPt4*yeOeimlj}G++^mX+2vM(&t&M8pO&yS1+q!l3d(?KZctGwg^ncv&&o!B0^hP}xa z+I=i`;a?3!i@eE988_LLPBVX5mwVSC@~PE1A?fGST8%Xs++V%B9Aob`^})PlZ|t2V zLYp$yy%tZ=6=u6qI$fH_EHu^DQ#dfOVlj)$#pOIM>MySR&T;zExJC7w@`2s)wW&UN aze43b1X!!~YwY_43K>sVKbLh*2~7Z3rg|*^ literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv@!3-oh+|s`SsrCS$5ZC|z{{xvoP>>ZF9qN%B z=bxDr5)tH<5bc|t8d_DASXZ0s;b9dQ>6Mlcn42C^Q4n8Ml$f04Z);^3T3Q+x z7w6^bYVKrfEGjBgQ<@ywuC*PkcIS*58G1`)WVjoWi$!o3-?1cKN{S zm+La<5qszo}OsTJ9DaS!sB}TM}MSi YnZ>trtUI+cw-pqIp00i_>zopr09^E#?f?J) diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_supreme.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/dagannoth_supreme.png index 721bd215e4c9646962dd8ad553799bb6805a3f05..4cb52e41563e8268ae248605fa3f19ab2f4ddc3e 100644 GIT binary patch literal 317 zcmeAS@N?(olHy`uVBq!ia0vp^5NQDRZgt!7}2#~hYiAoI!iSr7G zat}-Jl{8gP%8keb9y=5NEVsI%q`?uTVyC&NKQ8Tk=5vz_%+?jf$7non_})%ChpY@=-NVAb7g^xvX literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv@!3-oh+|s`SsnP(S5ZC|z{{xvoAZ?|SlpEn6 z;T96-6`AZGmf-6X>KvUG$fqnB80`_48IoQUolzQ>kR2+dCFkaEFRHIBX{zoS6reR;^Q1u9H)so|>ten5OFNW0PN^YHn-DDJ>-Dpf4mUwBS}= zJ8^O^RlV}Yi;Jw?+fv=^4bQNpc!?jn3<@PrS3j3^P6NQDIWgt!7}2ncm?@wTyE(OMYg z;Wn*2HPFGq&C)W)%X3p-<=W2DmW;@>pg?C+)7jNoojEZjF@8yYzUJE6OPcZ*HRjE$ z&2}&`$_Wq43JtL_Fo+R9AP+Q@sU*lRm|a=L;5v(IKV9w&v<_m0J~ zFF25*>GrBDqp9OfNcKa%Q~%jE-k+v;Kx6jJsOg`cahWrn@pxSmdKI;Vst0FqdHX8-^I literal 368 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}MSxF;E0Bf&XH!!*OUpn92TL8D zFjrSE8!KO1+b9pW7%xu;6QdAkr#K&y?A;>T622D@|Hpy1A`TiyHIRca@dK24sbX40v20Zn{`%Fwy+boCS;i|8M7OJGSiQ zrOA`uxlLRzu`&Puf%9u8FfbV|@hN0*bZu8@a{hk0p`Kyt74|h(U4uD5;pXY;=d#Wz Gp$Pzw@QRrL diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/general_graardor.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/general_graardor.png index f26ca05eca402a5c21078e5e88b81e5640928013..cefbc3c19b6588ad7f9bd6d1abab682d95100aee 100644 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^5NUaO-32_C|5a3{Kol+bV6BCvg z6%`&Bm{6GznjIRL8tCik?h)dA;=r1g?9ABG*qE@en5+;-M;k3Gt;~vq^7y#$@W9{% zAAf&Ozi9V_SVxCI2UiCNZyRe%7jqjMa~pGW12whA#)|bT%T_Nfp3q%fT9T7pom8A3 zQyd$UoE#mM9u(;1m7e0};p`mZ?Bwd|5EEhRY-(z1U|?gVp`aiuB_SayC>ZF(>0!m$ zG5x+V(78+{L4Lsu)AIlS_5||Qdb&7V?_Vv1uzvO?0zVzaB00%APvt*o4EZCza*?Cq@rQUWa9EGrTdT640?;$n+q zV?vyre1WnK4t|~<4uK9jmO4$DX%Rs|VF3YwUS2`zL9yZCiBVA#x{E~x1+AP-!@>d- z6l9}ALp_|Gr6eR88!Jjna;gqa$pZS8xg^Lhn1Ny1W2sN;f!s5mE{-7*mvj4H7Bx8t zv_wjU3HN&(;9k7wnNla`>s%I5|E{QODQlX&27|_t6 z#<9vPQ>!<5Nkg2*bb)iu2F{xw&O067s1mA?aeY^!i1(s^H&4B;nq-@|ExazBs5mQZ z_04y8?%lPw343#Fvct8{-qZKZx;FdShPZf^i&8x7i$A9PvMaXjZ~bcYto!MW@8R<6 zf?LaBUs%`)e=^s^eL*nGu@r~mzXIEQ`znV*OM>-E2AYku+~uxOES27igHNTkN~ RJ@TMf^>p=fS?83{1OR0($rS(q diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/giant_mole.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/giant_mole.png index 5fb3f328e8c8971b09e187c56231478407d31c9f..48619319dce9ff0fecd9b01594894251eed4f7de 100644 GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^5NaY9kgt!7}2(U5L@~}5lRh0B~ zGS=5pbg?mr40N|NRM%0JHr7*dvd|G15y(miNsSJO3-t>1b@pjlosq+d$6`9N$+mOd(QUQFRVLvvUL|;^Kb+OmZz(q%Q~loCIEpQh3NnQ literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^f} z>1!$Ks7k9UN{WgKSsAL^nrfNqDeGw|SH!r^n>X3XLdV0&sx95e)kfdb-q6>{*wx-V z)Ym!0!@|l`&rnbO+S<;$yXObEngdk?c{w@R7)J+r%qR`pvuD%huJniiH*-Us?R}XW zJJaGqz0zU=vlBx_g@iKWLz1KX7uLiSq($zTm^~psXzSKhXIFJx0y>MiB*-tAfnnNX zsZZ;H+-;sNjv*44eJ9)&YBJz)xve+NE8t=fqbLx(pZ@>9xwM4rcTLO9vptnuv{@at zPW|)Eas73}n_r_|8<^CZ88!APEwV64GmvrI)Y>7`Wh3c-@N9$5zbcvzW?wfg z>E%2yd7?pq=F1Dheu=Z5o;w{R@;d2R@eKWjJ5!$)ZJoF9mP5jB<~iD*cg4Lcv}pPs z%vBm{>O1*wo}k6t>pNnMYuNZADVgt!7}2+%jt4~`7Bu(iqTc*Ao}ynVs{-A>{T(XG5edutX?eER&htMUnp zV-Dve1rqh#oj4b2Nw1f2IJ-+hWW!#i7FX+n_ASaz=YvDyo6lywJt%FEeQwp&+fpW` z?sjf-;@mboIchtzeyZ<_1Wmc=6O!L>L@Apj*T*}sLQXv68A+A9B|Ns9$5(t7Kg0ytB zJp4So0=>*_%&qLL99$g?Obu+EY}GW>WEEshEKTwgRwkq;D5)qpdpNuKxP?ZC>KW-p zCr5|JhWm#2#-_$bB}Q>4OyU3<$6ONR7tFvg?XlFS^+4_tPZ!4!iOaDQZVNRl@VGRx zx&~z#Hm&{p|9{S*D;Ev*4=7H*D^c9ieEIM#;RDWz?w=-c95CQ|&5=Au$gy7T$Kok3 zHB+ucEkBW1bxB84e}RUu(Q{RS^&9!t=H*8;FMN7OMcE+AKV6FDN)XUHx3vIVCg!0HA1g`2YX_ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/hespori.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/hespori.png index 0c104674dbe6df264b138a22b26354cfb29d2ceb..a85a83ce3c9b4d8b527d65b8e6411307da3911cb 100644 GIT binary patch literal 399 zcmeAS@N?(olHy`uVBq!ia0vp^5NX-fG32_C|5D?<)yLCxbM_ta& z6}1}{lyz6d+FDrjHWhT&#}x-wt(slDd`98osrgYMAujgzhc>qCTh~|-TDNI&<+YHDC`-A{S~&~Z#9L4Lsu)AIlS z_5|`4c)B=-Xq;bq!CmOE0*^zWasgxb9q*jw-{<|lue+h=gVsOqdl_seX9+SYTz>Cu zr+L89OZVA<-=mF-x`HQS)GQFzG`rzo_3#D_;@cMR$7`X91uni8pK4-zM nLkvu3PF@PRe?dTYb7f7QjBAa8 za9dSXY-CnvUQ%^uP-k35cyC~piFS&BZi07aH83zZedDyRef+!b!|;^T|#0`Nk~{yQh;<;iG5v_h-Ha+U8I$7WnNuW zO--PZY@(EIr+R!~rogkrLzd5nNwv7vXjr+m4neZH=Nub_6js(!Vk zdQnPB!m)(s2NozT$?4NthH#6&Fm>2|rm=p*y?4JV`I4LG58zP~ U(`CLnBme*a07*qoM6N<$f|_5#U;qFB diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kalphite_queen.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kalphite_queen.png index 956e3a502d9fe18d57aa2cc692da9214ba109c42..c88f0bb4485af8e77a4801b2906758349f7d62b6 100644 GIT binary patch literal 364 zcmeAS@N?(olHy`uVBq!ia0vp^5NRb_at)L*b(ER6rg-PE{MFmjQeB-rBQ+8V)LnyAV{=tPl9l$JDx9`Bw|ja@+vKDO z8>@gst*8tYBU>3~Ur8G`@vR4QHy_C9pOdj*O~Rbzv9p%OOq>($V``jStf3(z>3aY4 zcc86IB|(0{4Ab)e|Mmp(mUy~2hG?AMdf_JDAq4@}fSo+E%eJq*duRIp|1O7B*fMI2 zKH53@y%R|Lyq=@uz4;qK#yojJ?Hl(P%}T6Q7WZvAGw(uGhqijEygtKiQJGt7azws9 z*LLBm4eRfHX|zV+{O4|^AeB@ljrp#I63HiaXzDGT6tt?6v1^muas{RjNxG{R<}GnH z@!52sy+eE9;;q{rBu}lG-x|+m$ild#nB#WeS@XJc(g%9k`~+S`YJtMc)78&qol`;+ E0G2j~0RR91 literal 422 zcmV;X0a^ZuP)QfwPjsxBwA=B zRAM4PO(KewWN1f4V?;q^MMR*iU_D77V{<4;Stw9pDm6hIGCdqbQ6xG<7DrVlIz=7? zyE60u000AYQchC<0G8t#@~;2@0JBL%K~xyiP0-g8f-n#T(7?4Liir(lqr?^=p#1;0 znIhso?VQ<6_AVh^`S1zxJkK?*(1SDdTl6~{3<1j+jnTfH1k=zcX7jHRL<`E6D?J=_ zw%%;x9p(GOvHh3ebWYMN7ncN`U2pdX<(vjmYIGJqi=q@laG@$aYOR)1((nZoahg>c z&8jfS7~W-?O9jtnk``f#a~I1@Hci7|+Zt_DgLW5i{LTb4N`d^}$+6q{1M(pbjOx50 QyZ`_I07*qoM6N<$f}T31$^ZZW diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/king_black_dragon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/king_black_dragon.png index 7efce3fe35e23d8305a2a42fe4aba621f5ead25e..c162208002d86654a9075123d9974daa23ae483d 100644 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^5NO=VKgt!7}2#}GKRFsnw6B1HW zR@TzcShHZk&UI@K?%1($>C&aMX6ota+_`aM)AHpj=FDC&ZQAUK6Q*``RTmdk78Vp_ zWCVD7t^FQ)2WSveNswPK!?gVWzdeDxsh%#5AsXkmPVnYCtia=PT3Xs;^1u4;`!jo` zTvc9en%lbZ8LwN~cX?Hh`#uvAn1yFO^?UVL?IzD0)`C2R{Y#`CTxoom^r>dbyh6W{ z#ox>;cV@K|zK~m(vYA~)8AeYQr=C8Bt`l>^sPupt7f@xUQ|BmX_Su*l=iQrkk3-wY8Os ziYh25n~{*Pq@=N>rMj=Ld2w*JtgED%n8UletDv7QEG&C-as=3s*8l(j19VbOQvd*# z;~Mg>0001*NklTD>5K*AxB@ID{Qbfn;ndC>MD55VUuNF@aLgt!7}2w2@C+FHuDxK*gL zg0CQxFF%nlJDMvdkh8y5sINq*xr(nnm#;pXuPmFdHk~iRmovzlGs1&&<=nYbD$3UP zi_UBp>S-35+aNTlLMSnsGclCY*PheUhSSBplnH17Q%R6tFvGO`|Gzzfykbum#}JM4 zXZ_uU8Vm%CmfWmf|NsBe%^wp^F;8J;k0?|4#lWKz!n6GY56=??PT?hjma{DNf)&b` zGOPu9924@LR=j#6wl}`^mI>E4<0nyKrSWNMiPpOwWY_)B%2NHQ;=-DKNTNH3?Rimg h_=e@DEp=fS?83{1OQC+V^IJA literal 351 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9Q!3-pIZrslUQjGyVA+G=b{|7Q5Ai|e(<=nY> zQG8i3oUJ*0F@cnEBVUu_&W3X`fG*q()n6z_}27@&TSCtDH2Kyzjo{K{ zsFO6)|EY;CSCrU`BwKEnOcjvb9XOkwyM{S oDR%C8xbA=LwoA;Ww-?oaWl#=ay=BfMDGmxFPgg&ebxsLQ0QOgVfB*mh diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kreearra.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kreearra.png index 0ef3398abf3c7852c16674016f4d47665fa5ec82..2bc96314764242724e04a310d27781a2bceef9ce 100644 GIT binary patch literal 343 zcmeAS@N?(olHy`uVBq!ia0vp^5NRZ$GJ{qp~1BA}}yB(x$7ip{=I+%(BwV#Kh-U_Lt`56lP@|NsJEk z_G-xWObfG03bA-{cFT?JeTU}eZ=8^po)8}&8M!AuVn%hCv%P(cziFt4zM`Dm(jQZE zfVMJ~1o;IsOw0fO+Y`v^_jGX#(Kx^LqC4MV10I$G87s5A!wP#Zzy3d8;-)#A{s$Qu70RLR|m<{|{tBKxchjQ&m-N zT3S>{NMB3Kq>he;T+bKR4xL$6dT4I`wC=8%{e4f)Zh3ZTPiA7`jNYD_l9I!T(R<<} zHcm(@%*v`P$j{HnxUs$OXj06K>ae=9vI%W%K|Veafr04>@m-A#4HXs6_V%SYIX%ry z0bZVpa&noGHu>@Pq5l4%9{OovRx$pjNg)>5$;qwN)$O%4@sW{Vc0RlVbR2U@kY6wZ z!?edzpVkApOFUg1LnJPTUWgQGG7w<7pfWeX!KHOYgZ82o513y3J)b7hdSU+hWof(G z1f2FKGAy2A@{{xVEuJKSJ5mjjESc8M@do~)++$C%HLn&bM&qc}+i6Z*pugj*} ztv8FVey;W-{)nAl>m8ZCSk50eHJ{$GkH4kawnyVrc2Rfqq7IY0@~No-0-0K?N7Jg9aU&q75Ae4(d1> diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kril_tsutsaroth.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/kril_tsutsaroth.png index 6b36fb211c25683884db6a057e0738e2ee3c6eaf..878a14c18beb8ac4edfb2cbccd45dd275d2cc9dd 100644 GIT binary patch literal 449 zcmeAS@N?(olHy`uVBq!ia0vp^5NNox532_C|5TL`(FvmfCr?38M zH=XImLK6&yd?YzjML45MpW0vEQkUuH zYA zqgrDu=U^yTsxNofM|z)=WSW-bR(sJkHlmTrqMg!wg_3;HBHS@ToI!%@?tJV{eC*DA z42J9satsVY@0pJS9nDk{){Bdn%#9w~R2cznfX zX?}$)=lMckgt|&^pO&eYPM8Mis> n>4hs4Z5eiTEMS^?B>lGF@uyq|jAzVr0!4(UtDnm{r-UW|E;XAn literal 549 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv@!3-oh+|s`SsXqZeA+G=b{|7Q5z=@CDSCX?w zUnoqFy-|m+Q=dJ%Pd3#T+I#H8EPt$Q$#tEMYw|m*`s`IU2XKI84I;GWcfN7&vj7u6XclGQ@Ybv zKQ6$2pOa*BZAOF;XRQujh=;{$H=XT1`ZFd~9Skr$5@?tv%DKiybgrq;R(nxrK86jR zdZh(%TfFqvdFZ5RN$&GETwpFV!A3PrnX^=1ZkemrWLwo5W4TUgzFKKMUp~$%Nxm2% zPB{jKMb26??bRcdMcw(>gM>H>CHXuhIfI2czuFhM0)5V0666=mz%cEx)Ti}8?p040 z#}J9jxf7y;n*u~yEuV9{Iyvu3TI#l_Wa*VRNlR0rZl3-0|NnG8rpw*g=ijvFUz@iz zE&G-br=nw*i_lDiuo9yw%BhvgsUl~3)<(TFJlf;=N%cw6nff%51YYS=euq?EOV5tJ zZM`mdZ4I;k!1uK+_t)8JMXSp41Y~6A&zbl1++l88v!a{tSnm4$UR5sp z%Y6I3;`UEp-^<@Qo{-S`&!9@mR(pPe30wZBPruA++xeR<9)ITExA*3o=jD70k1p!g lidGA2@!7TH|A}qeV(Oi{gtmDXOBjG++SAp~Wt~$(696}f!Mgwe diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/mimic.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/mimic.png index 0666325dfac408c4daa22fbdc5becddcc6a953d3..7f523c6b879984d87cf348fba2874394ed4b2a52 100644 GIT binary patch literal 363 zcmeAS@N?(olHy`uVBq!ia0vp^5NTmh%gt!7}C{R;lkd^Jp6bQ88 zNK4Dl4dAVb;cZUjjdJ4Xa?WUN?GLr|o;Gdq=Czd!CZ;wTrezVlMWMWDJ{(@=9LDMl z9i3B(i)(Zg7@C@TYHHdR%+3i8j*N2%N%G)`j!y17)VBs`4O2;wUogY8{Qti_fxJzg zE{-7@=ePFXj5O@A(}N6#NlEm?nUs>qDqz{^WQIPO{`v0L70tQi znh>-rBkTR&eW&NGn{;mH*{!*+ZMCF&YbP0l+XkK D+B%H+ literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv@!3-oh+|s`Ssg?kr5ZC|z{{xv25F8xoWzOMm z%@Jb95$VVg>&B7f!I9>}QC3!;7s#ulzz`jsobAtBUENw++g?;uT@=b&7Qx%zF}b^Y zT2(Z!u{uLzV|R0NZ(S^JQzCC`GVg-fIh)s3b~$IXw)Ur`<%e2&$2o-9Xqfh73QU`} zm_b&SK~0Up#MH`7RTbz0=8_=4UCs)bWFHg4>!R&RM=<`ZbyFryGP`Xj7_sEl#PZTGg-iD0{`VW}@2|gnYp2AfKd*cEY?B4H<;C_MwZ3pG r)_(bKnT*X+>06l3aOHjDzg^AfzDzt@W#_6%pm6nc^>bP0l+XkKo4=T_ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/nightmare.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/nightmare.png index f8edd9b211ec893a8f0fab554cf2f821b7d7e0c9..c0f7645c02c50ca4a8f51792daa69a258ea4e5d0 100644 GIT binary patch literal 492 zcmVik5M4dR=OEU|?r; zP-k6TWot-Ys});bKvY~kNkc7yi$js}!w+p(es=MV=oI(X~MLnHNmk*QI7}>QO zK^YRld1DjB)f|o}HjM2|lnOwVuE=&Fd+a)~?x4CYs0 z1SD`l8k5en5ONLgH(~tC;WlctejmIAANWc5zCWUy?LiJKiRg(jrTlO_CJErKqL#MZ iw|n}GlQx__{>m5gGY{Kv1ji!)0000FY^EY8+P06IG!Ir=lPy{?juQr5Qe^SZmf%8;>xb6o}Ig(ezlu=lYL`@Z&;CaQhRAq zcxF+IaZq_;MR8j{Zdg56Mld^t2Ot0d00MMUPE!DuZ~yyA0002ANklmHXB0)*cA{~tukB{&Kf*ux&?X*4_9#XnP^_@c9Uf|9Ri3BvBY#2nb0ONW^R z98R~zgjGYq+qY?D)b$EhUL-n>&v#DA+$c zXUCL`4gD$Wrj|`_Oq!h@mb7xO)DV$OfI;k{hVrfuUf#1gdl>I9w@0?S)pecHKRp`u` zu;uM>Yr2ybwZu#+3+^uP?<)$JT^HV->rL6Lw6|b>d(P~Z%+|ul>WrYC z(x}?3kebY34!I;7V6bwP1o;IsOtV>fr}#kltH$pK7WM;0_j|fHhDcmaPH13q)6;Wf z6JZc}`0Syp=+j4!#RWu!o;d}oDQRe_=_z(Dnc(f^@+-NTnpODF1Y?q5H@zM&`~z<}E++an{Q!X+i7gh$&+$4t*o(NI(J=KdVbm6vd$@?2>=8p B34QNKFXv32_C|5TM4uAj`l|sH>i) zp^|E-tH;R@Yi{bRqh+I{q$ns@Y-yTjW}L01=AxmdBPAih%bRU)Q)!@8s;8Bpreq{5 zWgsXRBFHJl$=Q^V-e6~yZfjLxZ4s)gZLgvdq9kjsAgd+FYr)CTUtHLgpO+sIp5*7d zAi!&ir*opEd6tPmfSO8-ib8;bl)_dSU7&-QN`m}?8K&j`|LqCnZS!<-4AD5hbfT-+ zVFLl@?8-MY4uzy0`+a|1qmm9o_$f6sT_R*q-C++&{gwqbXiX~MnT wBF%BGvk%KmUbmq1hZGY}M3~*O?@K2BVmh{xi^ajK(hd~Bp00i_>zopr0K9>W(f|Me literal 488 zcmeAS@N?(olHy`uVBq!ia0vp^!ayvA)3QZ!Tw%uNCXIrDYYYHck;4D_5e)a+GM%oSt} z1O>wcIRo@`JhU`yl$3O&B-BJjv+ZqsbhOkM7-Sh36a)n&czJC&8T2?AV$Ds{jP&Z$ zQoHi=jAW&XElrdBeDfp1Te33yiwi3av`je}k_~hg1b8J{nwMFbPw{k4x3#LWv6SNE z4A;`o666g~Q)zavN%|T!59ny-k|4ie28L;mr9Q0(a&LLMIEF}Ej=k`*sL4QtHQ}V= zfv61{UAY=hnmEOF1w?Pxd;dR*moatO_wZ-4Q;N>X_U=k#FlIl!XtF~ zap{yR-wzy5-=+W9=|!ftwDpR|nd0+zZ<}kl;_;i;zkBxWe967^)%^Np#{a9Pzm5HV coXzkXyJLXh-&~LM8K9{0boFyt=akR{0BxAC0ssI2 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/scorpia.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/scorpia.png index db4c0ff9888f8ebb15c87652d26b21008fb56082..f39f9baa6e10dd18972337e5398f31e10db37eba 100644 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^5NZADVgt!7}2ynEq3H0{1F*jF~ zmp9haGtkjdS5ZArlu7K!&QmO-$2bwB|(0{ z4Ab)e|Mmp(x;&u+;iW<=oc3K*&we6Ty{n6X_wfwl zx`Vn-GI|2a&K(`+7OJLPck%WKQweVpog1If7IIQw-6W&*-B}-5Oa2AlbeHx{u=r$J zqp{b{Iw{;mOXB-2?v4+^8ltuO42cW>@QPW#HS4Xl*q7MW%lGV%Nt0=xc#&(L`N_3R UFI4S!2Y`I&>FVdQ&MBb@0LM~Y!~g&Q literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tQ2{<7u0Z<#|NlS|2m-yml@t`p z^YheIRc$RSeB9lvOic}RbmU}YtT-6_Jv_X4Ihrae+;}+>qax!YBAo5)a#B(ptgVgp z^t3cJf##SS8F{(5;u=|<$jXtrZ+$D4Adt4Hd1 zEx&f`0dtSlPQy~ixqQnE-!v*dDwxu6N=5w)}^O z_qqiW7Jly0e7%U1%`$6ik^M5s$haBYtL8SXQGWYvcSOnQd+)^KcJ5xg>HG8ksmEO6 XWtXwapP4>K5fmPtu6{1-oD!MNaY9kgt!7}2vAm3OpJ<5jg1ZT z^0F~E_i=M`wzHF$kqHY3P*+uzU{E$UHWp@(krEfrNl7u*(-RRCEXvA?2@8t~3DID) zRO2#KVA0do)GW`>vorCtGVpMBa>`Fn4{}Y*Oic8)k2Th`mu1nGcy_`TXdhEakY6yv zwEX|SJ%PMEo-U3d8t2!ZJ1Nv;Aixr^Jbe>8&+4w#YH-RzX!&iPbg)a@2oa?z*IV$Ue+9YKpObZS%pAg$%t#GH%Zq`TjEylltte$_5j`nrn@W1!^($iG_v|Hj)Q$&hRZryfJs-NG)Dt<74`f0>sK0+gWTc&? zWm0sMwV9bLi?)cMV0Ln{v9Ym*v9Xl6xCDc;5{rSdqGC~2mW{Cw0|TSCeXItHr96vn zcwk^=VxpzKTUlOiT3npEs;az?zP6^Oqm7L!hrTF-ytk{Xv8KHmm$9L)t~!sguZMe(kB_^PQ+|577MJDwTF$pX zhccH0`2{mDOnWT#X+4m8%hSa%MB;Mph3xPa1p&4PcPm5B2p!G~b6O_29{dS{F%5*n)R?}Td=^n3C-d^ zwiY)E?bxx0sq5&v{D8ZU-tC*Vsv^QS)%Wj>ElumM*>bL%udQ5}D84$b<<-p%!Rvn; za=UfhJF@#_?!S*a=U@6DdB$h6n%$FQJ{MNKFp#32_C|5b!X><5@x4b#J>x z7JBa&&U!Pc>s4pNtCs2~sZoz(10Mu9zh6A}bx-rtoTNwL-e=vdx7e9XHP-&Jf7j>T zTR(1C^gAeB#TtqkDsqWRGQQGcFYC)* zR24k%ce?CpyWiPjxs|~jGu_!{y1j;)O}c72{JdKtPEG*2iK!&WFPLFk{{P>eK;B+Y z7sn8d^J^zu7iv}zaY<#YzOEuw?YaK{|I$Jk&R5B5&s(|E%Mt_rF)&7+V+z>GeB9>Y zW9xehJrX)OzG=DfPbgeExzQxkcjS_m76v#WFsAUDkI=fL*{X3>V* zUm+a0KsMuDQKLC8ef9ZpI=XPu6Z)D0CLhYK8Uzq<6kxpF8W+Dt!!EhcLv zAM?Am^SZQ#E+=*=BI}Qa?30V*UQ)k9IG{K#U7L7g00003bW%=J005Tb8uG6I007=e zL_t&-({0fEQ-VMc2k_&*mk)|Eg)~wzpCE;S*%N!3uTcO0|Hiu;1e$4oxtY)G?(Hri z|Ag`WMiB$j kf939u)|9u%*x?4k_INxJ(IlturvLx|07*qoM6N<$f{Ld3-~a#s diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/the_gauntlet.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/the_gauntlet.png index d24830e178bc468b3a7a8d05af0e77ca475ab53a..3e03f805c1124ef40e62b752f8c26b7dbb42d171 100644 GIT binary patch literal 510 zcmVM)TAr0otf67^%XH1daK*b|s-sDtl|XWDI%j0GMS6BKj&(nAYZ+!zC{RltPDdI!HIDVy zq~F((+17{k)p_*MjP1~J^Ur+K&xP#HdD6~`*3DM&$am4kVCTYd$Gtk`xoNq!P1mw& zyRkISs4~c+O{SYJxRpqol2)0JQjv;Eg@P!bfJlFRG?IBYc5gjyXDobXCTn9Ta$YQB zTr6N%C|6P%N<|GKAb$(b@c;k-0(4SNQvjB4|NBV*007EKL_t(2&#jQv(!xLtM!RR1 zmJ03;zq`8&{{9aH!?dL3lHpusbLPutV(kEhiq|60@}fyRQDI&FVF}cu2&#I%) zgyPmmDY$#;Efv&VqQplFuI$s&|DcC?bfQrTW7^&G{gcvg_NCplk1Rs9;5g+EPQ4fP)QnTR9c>uYP+#?&B9xtmqmGVh3w9b_1BE;&^hC{ zCTn9FN<}E2fMBVhKXGqnw5xT`%XQDhbIZYOzqM((uU({^eACa7+17{k)pyaxF1VFc zl#xb!dP$y?f9uSo-`8rpxH@NLG?IBVk9H_>UJW83NSl&Prkj-7*NWE7WwNL`XJSx{ zib#KbB1}daIWksisPWf;V<=dGygT$f989!cEt*GK_RSBxu3_000AYQchC< z0G8t#@~;2@0Ov_WK~xyiV_?7n7*PNdGZRP*NFl_SSwMn}%&g4F>e!eW7?_yZk;E98 zIe-e8Ik}j@3YfuWFadQlFmv-TGXX_-`S^jN%*-4DKrulfVP<9#Q894|NhxM&8CjrS zCT2Nlc`gM-C1n*=H5PSF4Q8-gm^HPub#(PK^;tAPrh?rJ6g4n3GBzG+d8X^<0xVr!V00MMUPE!Du zZ~yyA0002aNklMEU6l_g2+6x(BV|dqKhRQuA_o@deVQcw zVXW)&C=Z-=TQc?6*zKvyNglN9P1Uf5hCxqmVTU3=jIG_gUE@}OLXM_n&R4urC?YJ7khLrG-IVtbsOzp=8+rl-YgYlUoWh^(y0 zs;bALqr+uof0LBCet(}@T5)}SooQ)=)Mu@Y00003bW%=J005Tb8uG6I008kxL_t&- z(^b&vR>Ck41>lmKv=XY|LPc?*A}y|9!37jiSrowq1=PB||634f3T1xfd}n6PtWN+rAN4ou}uQ*RI-@>%@QY_TKCD^?^8gk^w$G zzY1yBWgHVD_%?ss)-O{L%n$b8e;0w-V9)}F6*d^}O9a{;00000NkvXXu0mjfBNF5IF32_C|Fu-W-WRjMZ=Nas1 zYGaU7P@0^U9iN&O5giv080PNft7odErm7?=!JC;`5S5rTp*yj*GBh|cI4Q=rAlJv) z!`Z;t$iYs})UDqgxxJ!ehguLqoj+14~N-!UA1geQmwmtn96==PRG!`S&z#};Za;PTo=so(e!lFr-uo(dZLNT-QGT>|yt>JTm}~)ML9rc) zJYq~K8h_ii%1Uwu{jcw>%Ddt2Y5B8ef_7%vQS&Pcv^h7k=q#|E+V}C(AyF+?U%8S^ z4^^JNF1mlZDy~5DF|9U_p7VugWPV_aK(c~wwQR*#BcKtL*+n`%~3ML;|0002eNklfrLx*ld92pz$;MtsqxtmwQrYj|wbkyt zDen*%hWY-{{_I)^&jh`mZGIW1-L)({&$Hp9(EMlhaCXY)TB7VK>4$V^s? ht;rvi#a@Ja_8+tP6$M+4>$m^_002ovPDHLkV1nQf)rJ57 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/tzkal_zuk.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/tzkal_zuk.png index c227671ec899df08a3ad14ee4eb70ff7c56022aa..1c6a966f19d2b07d95a35a4809ee3ee821d0d3ff 100644 GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^5NYw@Sgt!7}IPi9Lb$4=dvA2(~ zu@3g}39>NL)zS(J2ynErvN1RJFfuUF*SFW!^!N0%GBq_fHug3#a?#f_)YVm2RaI6} z@={jtGcl4B5-O4r3=!b)wzm(qvIsOcwba!K)76xfme!FJ-=HGWCo9-4$rCNW;laz! z#~42oXgzaDkY6yvG>*&L5(|Lb1)eUBAsXlRUU27QR^(y5U?4AH<@5gK*MH(Zo0>W| z$>r<(K6z<+`E4;qhkxt1t2#x#ho0pNph$#RNrL z3;bAjmUq*PQ#_|kZZuBa`RiD(QDj5SulM_ngr2{B#p`*B{cz*G^K|udS?83{ F1OU_ddc*(# literal 583 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{Rd`U{nb3332`Z|36R!83cNH`M9~s zN=sW98(W*1xjQ-8TUqI9X{oEKswgQL>gk0A1i0ASJ7{ZKn3%XaIJh}Fdb_#?`}zj^ z_=NcS23eT7=1n8` zc{n@!dwSTIo0}OKnds|#@Ur*G3T{vl2@>E`R#I}Zwe_~Q5ApU6_49Mq)6J zw6n0NZ@gUr3?0^zAirP+hH0D}Pu_g&01906ba4!kxIFj5^`Juz608ZE3OEE9g&iE0 zuJq_F5nU3_-L|ge{(oJcPy8{)b5_sIFH1Wg+5GTIL6ro6N5?t=@I3$l$zf}As(XBp7vtDXeqxh5MK4#PP zMdmJjF23n{(bKh2tIcQWF1V}s`rCw8{0-mvCFjSd9L}$pB4`lyCd2>45=MQ0QG*tl z%_nOTuiXFpGj`pz2MRgctY0lEyZ1kH^OlqC=jL=?taNZAMYgt!7}Akb&v1Ct_l47}b9 zLi!90i40O<3=&#gQs(>$*$fKa3<`-1d{5^`mvX6wF{s)xDA+MbWiyD_b#ny(buyI% z`2{mf%m4q|6Udw7>EaloaenK?+g!|wJS-QiCNJ4F{oeoo(bl_{zUcCAJ=g5SXSitj zewB%t0U>8JUaxvBWt?#N%r?1qafcKtO&mUJE4Aldns@YQqehg->{SN4%@fubdnxGu zIKmP-Wl#7*4z1dQu@kfkc5%vl+an*Hv6F%IR{w&Z`${J)l|JM>N7Sh8fJ^TBcTvAj ia~)Z1fAi<|J&epu%x~@Ee!l>^j=|H_&t;ucLK6Tn6l1Rd literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5t-T^)#uK)l42Qnc*mVsA~K~#@{ zSBY0tmVr}>Q&5e8)06>7itd_ZZNnhw#31UyDWS$7Xv!dA%D}0{z+l6`smH)6%fR5o zz$^bh_$JUG=8_=4U=NXwxhq*=8?!T}7et?wNUvN*3*wKEmgfrlhy1ZdfIzW@ux|{4#Qfk>#z^iQQcV z8xKntE3C>&Z)NW}*Dgt!7}2vC)i6A=_tl#D;!qu1$iBL8Dtn31RjU80!?Qs3GxeOn3n(lwzopr0BN^#lK=n! literal 378 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5t`2jv5uK)l42QneRjhDlbm%)mI zAwZDBiI_&|F*FL{l?TkV8g9#92hpN?$)&gkx%Vmx!RC zoglBdAg{iv>d8X~kL=#9t*9u&z_4xgsvT?B%$q!U-J(UCmM>d1Z(h=xAU2?7%q2m7 z!3+%39!q^%59Dt5ba4!kxSV_8HD8kf4{O3UUPzq7DX~#o3S)g#P%-z;6z_tMf}Pf-4@ZrPI$YzwMt?y{Qn&742`R*t+`G*{W* SU%Nd(!RP7f=d#Wzp$Pzvrixww diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/vetion.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/vetion.png index cfc9d47a03bc22fa10ec065933e3708013f243b3..67a7b3d645d3fab48a46ddb0cb58767e7ca7fb69 100644 GIT binary patch literal 347 zcmeAS@N?(olHy`uVBq!ia0vp^5NYw@Sgt!7}2vB8E?TzbkmvggX zu+(MHm0^&{=gmv!NQ>i$4c7^ekP8pz2=&wU^OW*bRdv!A)VH$Ilj4vPk=oqgQC}WV zmSdBhloS_f6cMBv6eJTEz!4DX>7}XZ72xUVrtZeT;poUMZ$C1Pd5U}7j`D59#X z$*VbCZG#)odZv;fzhH)G`Tu`=0(o7YE{-7@=eJHcE_BF%hxMaX-`u#Ddk_EruW+uw zfZ0mu?vlAzJ@SqGG^g-%OyKnH-SaX*)z#4ZoVjD-#3?WP=5ve0nqB8h+Sl?{x%bw* z8+)fJJW+pjCuUXk(dWrNjhEK-Ym4Wl@yi8?`1f2}kzm3*FaMQTa$BW>v-|O_?5eJ+ j?XEs)6N8US|6ec8Uc&Ow)7oe{D2O~={an^LB{Ts5H;QfJ literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tlLLH0T>t<74`f0>Z(L7OQk*J- zYJjJwE`x4^M}0nTo+E?334=+FO?D(lL^?-Wq^FmytzjHTY&t^_7XSLGSzt>rJwQ9vKzt!z)C$Z|i-FKAl b_OE#PZ?WvATVH(h2Zg1ltDnm{r-UW|{SSsz diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/vorkath.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/vorkath.png index 696669c35306f5dab14d48a9bbfb3f6ce5d81cef..c3732b1d0225342ec3ab508a0963fd1992713661 100644 GIT binary patch literal 478 zcmV<40U`d0P)RSjFN~{O;pX%%V?*#w!E@rp|MtrnVX}QmYk81n2k+* ziF|Wba85N za(HiUb8Bp5YB*V9R!~+^N>L|2MItpk)7Q~ro~~e;sj0E0U6rJ$ucCvEjeUlPfQ5T^ zZgW3oac68~G*VkwQdllbR8Uk+LOnu4ML;AvKOHhR5gi}^;YBF`0007XQchC~4BOD!q5OmEOz$e-#2z9EmqLPa_|VEX$dXLm(cX zK;jWA-~|b~$2_aRvO2iMlGedfXj*^^MEKU1Oz6697hSIb6g0VIBA5GfZ1=a8NK5*A zu;qyUJ+EA}-JeF6FLz3!rkat8`zL@{!7)TwR$(^b07*qoM6N<$f;hF#fdBvi literal 597 zcmV-b0;>IqP)zO=~A#k;|`P*hEBu)%P%#i_BSw!E@urnX?3sZfB7JYj3T!@A7S%9ovz zLPbD*bb4Ktq+FDuWumfTo~~|lYp%Ackd})|c!fxGe?@P3Ia_2A9UzO4hE9EoQiYM0 zosu+CTOu_)!^gk6zqY8aqJV{aaA|OAVrrF}kV0y7H&|gLIzJsUH;s$_5IdMv)r5uB1qC!TMYN!H$Y|@x z>*}fM>Khm`L)^#2EMuf&tgdTpVrpj2%n0@evxTLVwU&*ooxOvj6HLt6MaR|6-NTdB z%NwrFmD$V3*T+xSUco;ACKedv>+8!C91JyRaL5cQ+Z@kv|&>J_D`}_PoY^#pJYj8Q$zBtLcV}OU{687W;s(# zIMS>(#G*7vJ2T>XGWoAD*?KXna4^YaFN|L^eC9J*s1vtJq&6%}AS5^H4+XEzM2bP6yn3KA9O&J?2n^uB|frGS7B_}fjL`y_%VUdPf zo_I-?b-jtdI3vtZkt+3gC8bo6+z?yCK#w{RxMkw%8nLRX<=JtbVUn&!elQ6pfAOZq zXhk_Ww*pyN9p%#I3aA8+Sc9>tw4Q3L6*_IyEO#OgI%24jmgB0012v92|OSCvjpbAs!YX7Y@0L zVLL4#5DyE)qBIp16?9ApQ#u7_Hw+;f5R6|g$-1H9qG$iVe$tX`84e24tTs3r1G-}z zvtJskTNy1L7%(g#6bl1jJQA8>CHJ#+i%bEhgSd$ z2RAZ*C2M64KL7wQEeZt%1C2!h?YN2Vv4Q`-fcTbW{iJyIpnUM3Y4E&xs(VvpNG?b# zCi9wj@sMfPdt$U!?K#4ho@JN>?r?G8-2R2nGNEAlJmK z^vt2=-pmID1E7LxURhI_f@~5I3u#wKJ~1bMHZLk*PeBq63}sV8J1-?BBqT^XGn05@ zV^~lkARu{UQZy(XT2)m-JS!_GC<6uvXjx4U4i6RYSjYeX02XvoPE!CNra+HyurQhs z-symlV6oHC$WZY0SjecT0003BNklWS$a7#bNfF@ki7nV6cH zTUc6I+t}LKJ2*PAKnxRec5!uc_Ym{+^7ird^B03!5fB&@91DVH zdq%9iqq7U>q3)jEJ~3oJ3V^h+^iP;LX)+4~IuM&Ob=ve9Vq$`5!ZT;ho-=ped?7U9 z1q&A~&R-%Vj25;_mo3j{6A?x?TvUvM6V3qu*BLtJqan{R00000NkvXXu0mh|g2_5G A#sB~S diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/zalcano.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/zalcano.png index f2bdac1cea07b0239ff8fa057a8c12313ec3ce88..72a0a1714b22268e940714ba9285e09b8538689d 100644 GIT binary patch literal 407 zcmeAS@N?(olHy`uVBq!ia0vp^5NKFXv32_C|5a8kG9~>F!7aD4B zWo2n%VyLI*>gny{=H}t-Y-4V&t*x!BppcNB9+RA6>*Qo&V`FMypscDYqo5ET8yn~2 z6X)dMY-e}3P3o$Sl%%BOR0Y8@3Eu3Y;-svsBtPF6FHZ+o*Kbp0Kby$j)ss4_C2>?k zVn&Q$pRAy$pkRv>Z*M?bY&li=FZbU4Uly1)gVW-)3-`@m{-q!5lM@~%pLkGFpOD;kAht_$?m<7b z7AL+>Oxz-6ZT^j}3?Eo6v-xziW2V;a?%W}LnzMjY=X(3Lo{Bk7W}Lb4NvUU5*QZiG zvuN{&zhm#e;ESLB;qu1)sj@w%AFfEOc;cAAz;;~l>`zVR#lkP=74Li<5}z1SF;9KT uq)TsD<2CpD1v94cF=jFL>^kW2_h6i{Fh|IJq3>#-;PrI%b6Mw<&;$TbR*vxi literal 485 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5t2LgOTT>t<74`f1sS74xTNQj%4 zkBOyaKvZ# zTPG(y1EcJs;v_%cyLwXQHa4;f3J$KWu_>u>P7Yc+I!5*mpG{=HO_iOhAb7V;NUMUF)dn+p&bMp!b-VzC34_;0wB_$OlB?Vd888L#g3=BqkdOmJ$eX@dK zf}A>9TBZgDqJn}>wzjSg4!iBt{eZ4#E(!7rW?-21SnAVyAorrDi(`ny<=hE3Cp8%e zxO(a>=seV*{ciU;r87I4x_(%=q=w^U?iJF|)RxVk_S&ZC-5p@4s`}-u3K} WJ^Ttk6#{O9V#?Fi&t;ucLK6V*#jC&o diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/zulrah.png b/runelite-client/src/main/resources/net/runelite/client/plugins/hiscore/bosses/zulrah.png index 7e2dc8807f59627687bcf2f085131e8d7e648c79..44a28c4cbd98d4eb4a5d3ae9a933ff6f754f0a8f 100644 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^5NVNp`gt!7}VgNTc>xyO5CiK@9 z6{aoPB3e_&uc6N>EW)&F&%&8ATl)IS%FE+3Ga}Q|L!zRB($WGw%uLOl^pD<=-g#bX z{b7mjc_J;Hg7(3J%@g<|l6Y)gIOG&rCNE)#j$$yfWYFNda}($Yo{}KHV1|B!mwPsD zXmI#&AmI3or`AC6N>3NZ5RLP5&wC0rIq|%8N+iSGq%;z(I-@9*II+-@AB1DF&N{2Mlc-r}v$ht+glfbj|+XdbtZ4XV{#d>%M2pZ~xHUt93h5 zm?lmtdB$_b*q-m6%pc1i1rs)y`>pS?^zfC^`Rv!c`0UDC3~y($-mibhnFb0WPgg&e IbxsLQ0Amh${Qv*} literal 374 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9c!3-o<`K&zvq~-_sgt!7}VgM%>Lqrmfx(g`33| zZ4q6vc