From dfe6443e2d5b119679f7c9276e5a4395f9f6527a Mon Sep 17 00:00:00 2001 From: Trevor Guidry Date: Wed, 9 Jan 2019 02:11:33 -0500 Subject: [PATCH 01/72] Add priority to the eventbus --- .../java/net/runelite/client/eventbus/EventBus.java | 13 +++++++++---- .../net/runelite/client/eventbus/Subscribe.java | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java index a28f2f4371..97b28da323 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/EventBus.java @@ -38,6 +38,7 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.Comparator; import java.util.function.Consumer; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; @@ -62,6 +63,7 @@ public class EventBus { private final Object object; private final Method method; + private final float priority; @EqualsAndHashCode.Exclude private final SubscriberMethod lamda; @@ -105,6 +107,9 @@ public class EventBus builder.putAll(subscribers); } + builder.orderValuesBy(Comparator.comparing(Subscriber::getPriority) + .thenComparing(s -> s.object.getClass().getName())); + for (Class clazz = object.getClass(); clazz != null; clazz = clazz.getSuperclass()) { for (final Method method : clazz.getDeclaredMethods()) @@ -160,7 +165,7 @@ public class EventBus log.warn("Unable to create lambda for method {}", method, e); } - final Subscriber subscriber = new Subscriber(object, method, lambda); + final Subscriber subscriber = new Subscriber(object, method, sub.priority(), lambda); builder.put(parameterClazz, subscriber); log.debug("Registering {} - {}", parameterClazz, subscriber); } @@ -196,7 +201,7 @@ public class EventBus } final Class parameterClazz = method.getParameterTypes()[0]; - map.remove(parameterClazz, new Subscriber(object, method, null)); + map.remove(parameterClazz, new Subscriber(object, method, sub.priority(), null)); } } @@ -204,8 +209,8 @@ public class EventBus } /** - * Posts provided event to all registered subscribers. Subscriber calls are invoked immediately and in order - * in which subscribers were registered. + * Posts provided event to all registered subscribers. Subscriber calls are invoked immediately, + * ordered by priority then their declaring class' name. * * @param event event to post */ diff --git a/runelite-client/src/main/java/net/runelite/client/eventbus/Subscribe.java b/runelite-client/src/main/java/net/runelite/client/eventbus/Subscribe.java index e34e350be0..d3a7c0514b 100644 --- a/runelite-client/src/main/java/net/runelite/client/eventbus/Subscribe.java +++ b/runelite-client/src/main/java/net/runelite/client/eventbus/Subscribe.java @@ -38,4 +38,5 @@ import java.lang.annotation.Target; @Documented public @interface Subscribe { + float priority() default 0; } From c879a38f637ef55344977a72767541befc514704 Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Wed, 11 Sep 2019 20:53:29 -0600 Subject: [PATCH 02/72] tzhaartimersplugin fixes no longer requires eventbus --- .../plugins/tzhaartimers/TzhaarTimersPlugin | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin new file mode 100644 index 0000000000..51e9c462e5 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2019, winterdaze + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.tzhaartimers; + +import lombok.Getter; +import net.runelite.api.ChatMessageType; +import net.runelite.api.Client; +import net.runelite.api.events.ChatMessage; +import net.runelite.api.events.GameStateChanged; +import net.runelite.api.util.Text; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.game.ItemManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; +import net.runelite.client.eventbus.EventBus; + +import javax.inject.Inject; +import java.time.Duration; +import java.time.Instant; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static net.runelite.api.ItemID.FIRE_CAPE; +import static net.runelite.api.ItemID.INFERNAL_CAPE; + +@PluginDescriptor( + name = "Tzhaar Timers", + description = "Display elapsed time in the Fight Caves and Inferno", + tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar"} +) +public class TzhaarTimersPlugin extends Plugin +{ + private static final Pattern WAVE_MESSAGE = Pattern.compile("Wave: (\\d+)"); + private static final String DEFEATED_MESSAGE = "You have been defeated!"; + private static final Pattern COMPLETE_MESSAGE = Pattern.compile("Your (TzTok-Jad|TzKal-Zuk) kill count is:"); + private static final Pattern PAUSED_MESSAGE = Pattern.compile("The (Inferno|Fight Cave) has been paused. You may now log out."); + private static final String CONFIG_GROUP = "tzhaartimers"; + private static final String CONFIG_TIME = "time"; + private static final String CONFIG_STARTED = "started"; + private static final String CONFIG_LASTTIME = "lasttime"; + + @Inject + private InfoBoxManager infoBoxManager; + + @Inject + private Client client; + + @Inject + private ItemManager itemManager; + + @Inject + private ConfigManager configManager; + + @Inject + private EventBus eventBus; + + @Getter + private TzhaarTimers timer; + + private Instant startTime; + private Instant lastTime; + private Boolean started = false; + private boolean loggingIn; + + @Override + public void startUp() + { + addSubscriptions(); + } + + public void onGameStateChanged(GameStateChanged event) + { + switch (event.getGameState()) + { + case LOGGED_IN: + if (loggingIn) + { + loggingIn = false; + loadConfig(); + resetConfig(); + } + break; + case LOGGING_IN: + loggingIn = true; + break; + case LOADING: + if (!loggingIn) + { + updateInfoBoxState(); + } + break; + case HOPPING: + loggingIn = true; + case LOGIN_SCREEN: + removeTimer(); + saveConfig(); + break; + default: + break; + } + } + + public void onChatMessage(ChatMessage event) + { + if (event.getType() != ChatMessageType.GAMEMESSAGE && event.getType() != ChatMessageType.SPAM) + { + return; + } + + String message = Text.removeTags(event.getMessage()); + Matcher matcher = COMPLETE_MESSAGE.matcher(message); + + if (message.contains(DEFEATED_MESSAGE) || matcher.matches()) + { + removeTimer(); + resetConfig(); + resetVars(); + return; + } + + Instant now = Instant.now(); + matcher = PAUSED_MESSAGE.matcher(message); + if (matcher.matches()) + { + lastTime = now; + createTimer(startTime, now); + return; + } + + matcher = WAVE_MESSAGE.matcher(message); + if (!matcher.matches()) + { + return; + } + + if (!started) + { + int wave = Integer.parseInt(matcher.group(1)); + if (wave != 1) + { + return; + } + + started = true; + startTime = now; + } + else if (lastTime != null) + { + startTime = startTime.plus(Duration.between(startTime, now)).minus(Duration.between(startTime, lastTime)); + lastTime = null; + } + + createTimer(startTime, lastTime); + } + + private void updateInfoBoxState() + { + if (timer == null) + { + return; + } + + if (!checkInFightCaves() && !checkInInferno()) + { + removeTimer(); + resetConfig(); + resetVars(); + } + } + + private boolean checkInFightCaves() + { + return client.getMapRegions() != null && Arrays.stream(client.getMapRegions()) + .filter(x -> x == 9551) + .toArray().length > 0; + } + + private boolean checkInInferno() + { + return client.getMapRegions() != null && Arrays.stream(client.getMapRegions()) + .filter(x -> x == 9043) + .toArray().length > 0; + } + + private void resetVars() + { + startTime = null; + lastTime = null; + started = false; + } + + private void removeTimer() + { + infoBoxManager.removeInfoBox(timer); + timer = null; + } + + private void createTimer(Instant startTime, Instant lastTime) + { + if (timer != null) + { + infoBoxManager.removeInfoBox(timer); + } + + if (checkInFightCaves()) + { + timer = new TzhaarTimers(itemManager.getImage(FIRE_CAPE), this, startTime, lastTime); + infoBoxManager.addInfoBox(timer); + } + else if (checkInInferno()) + { + timer = new TzhaarTimers(itemManager.getImage(INFERNAL_CAPE), this, startTime, lastTime); + infoBoxManager.addInfoBox(timer); + } + } + + @Override + protected void shutDown() throws Exception + { + eventBus.unregister(this); + removeTimer(); + resetConfig(); + resetVars(); + } + + private void addSubscriptions() + { + eventBus.subscribe(GameStateChanged.class, this, this::onGameStateChanged); + eventBus.subscribe(ChatMessage.class, this, this::onChatMessage); + } + + private void loadConfig() + { + startTime = configManager.getConfiguration(CONFIG_GROUP, CONFIG_TIME, Instant.class); + started = configManager.getConfiguration(CONFIG_GROUP, CONFIG_STARTED, Boolean.class); + lastTime = configManager.getConfiguration(CONFIG_GROUP, CONFIG_LASTTIME, Instant.class); + if (started == null) + { + started = false; + } + } + + private void resetConfig() + { + configManager.unsetConfiguration(CONFIG_GROUP, CONFIG_TIME); + configManager.unsetConfiguration(CONFIG_GROUP, CONFIG_STARTED); + configManager.unsetConfiguration(CONFIG_GROUP, CONFIG_LASTTIME); + } + + private void saveConfig() + { + if (startTime == null) + { + return; + } + + if (lastTime == null) + { + lastTime = Instant.now(); + } + + configManager.setConfiguration(CONFIG_GROUP, CONFIG_TIME, startTime); + configManager.setConfiguration(CONFIG_GROUP, CONFIG_STARTED, started); + configManager.setConfiguration(CONFIG_GROUP, CONFIG_LASTTIME, lastTime); + resetVars(); + } +} From 41320564fc039d7049b1473a7edbdfc872dd7a1a Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Wed, 11 Sep 2019 20:54:08 -0600 Subject: [PATCH 03/72] tzhaartimers fixes the requirement of modified eventbus --- .../client/plugins/tzhaartimers/TzhaarTimers | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers new file mode 100644 index 0000000000..d0d187b56a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019, winterdaze + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.plugins.tzhaartimers; + +import net.runelite.client.ui.overlay.infobox.InfoBox; + +import java.awt.image.BufferedImage; +import java.awt.Color; +import java.time.Duration; +import java.time.Instant; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; + +public class TzhaarTimers extends InfoBox +{ + private final Instant startTime; + private LocalTime time; + private Instant lastTime; + + public TzhaarTimers(BufferedImage image, TzhaarTimersPlugin plugin, Instant startTime, Instant lastTime) + { + super(image, plugin); + this.startTime = startTime; + this.lastTime = lastTime; + } + + @Override + public String getText() + { + if (startTime == null) + { + return ""; + } + + if (lastTime == null) + { + Duration elapsed = Duration.between(startTime, Instant.now()); + time = LocalTime.ofSecondOfDay(elapsed.getSeconds()); + } + else + { + Duration elapsed = Duration.between(startTime, lastTime); + time = LocalTime.ofSecondOfDay(elapsed.getSeconds()); + } + + if (time.getHour() > 0) + { + return time.format(DateTimeFormatter.ofPattern("HH:mm")); + } + return time.format(DateTimeFormatter.ofPattern("mm:ss")); + } + + @Override + public Color getTextColor() + { + return Color.WHITE; + } + + @Override + public String getTooltip() + { + StringBuilder builder = new StringBuilder(); + builder.append("Elapsed time: "); + builder.append(time.format(DateTimeFormatter.ofPattern("HH:mm:ss"))); + + return builder.toString(); + } +} From d03576463c676999ad2c1f5c2e025efc3903ea49 Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Wed, 11 Sep 2019 20:57:06 -0600 Subject: [PATCH 04/72] tzhaartimers added.java .java --- .../plugins/tzhaartimers/{TzhaarTimers => TzhaarTimers.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/{TzhaarTimers => TzhaarTimers.java} (100%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers.java similarity index 100% rename from runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers rename to runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers.java From e5134ab6371b5cad2d9563bb4f55af4743176f3a Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Wed, 11 Sep 2019 20:57:37 -0600 Subject: [PATCH 05/72] tzhaartimersplugin.java adds.java --- .../tzhaartimers/{TzhaarTimersPlugin => TzhaarTimersPlugin.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/{TzhaarTimersPlugin => TzhaarTimersPlugin.java} (100%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin.java similarity index 100% rename from runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin rename to runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin.java From a6df8993268aec5e0c89962ed16b75903c7dfc2a Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Thu, 12 Sep 2019 21:39:12 -0600 Subject: [PATCH 06/72] Bosstimetracker:renamed renamed --- .../{TzhaarTimers.java => BossTimeTracker.java} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/{TzhaarTimers.java => BossTimeTracker.java} (92%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers.java b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTracker.java similarity index 92% rename from runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers.java rename to runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTracker.java index d0d187b56a..882f415c9f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimers.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTracker.java @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.tzhaartimers; +package net.runelite.client.plugins.bosstimetracker; import net.runelite.client.ui.overlay.infobox.InfoBox; @@ -33,13 +33,13 @@ import java.time.Instant; import java.time.LocalTime; import java.time.format.DateTimeFormatter; -public class TzhaarTimers extends InfoBox +public class BossTimeTracker extends InfoBox { private final Instant startTime; private LocalTime time; private Instant lastTime; - public TzhaarTimers(BufferedImage image, TzhaarTimersPlugin plugin, Instant startTime, Instant lastTime) + public BossTimeTracker(BufferedImage image, BossTimeTrackerPlugin plugin, Instant startTime, Instant lastTime) { super(image, plugin); this.startTime = startTime; From 42c6a4341b1581d9b34f2dc3f49449b1f36dc61c Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Thu, 12 Sep 2019 21:40:10 -0600 Subject: [PATCH 07/72] bosstimetrackerplugin:rename renamed --- ...imersPlugin.java => BossTimeTrackerPlugin.java} | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) rename runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/{TzhaarTimersPlugin.java => BossTimeTrackerPlugin.java} (94%) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java similarity index 94% rename from runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin.java rename to runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java index 51e9c462e5..1d49a841e7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/TzhaarTimersPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package net.runelite.client.plugins.tzhaartimers; +package net.runelite.client.plugins.bosstimetracker; import lombok.Getter; import net.runelite.api.ChatMessageType; @@ -48,17 +48,17 @@ import static net.runelite.api.ItemID.FIRE_CAPE; import static net.runelite.api.ItemID.INFERNAL_CAPE; @PluginDescriptor( - name = "Tzhaar Timers", + name = "Boss Time Tracker", description = "Display elapsed time in the Fight Caves and Inferno", tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar"} ) -public class TzhaarTimersPlugin extends Plugin +public class BossTimeTrackerPlugin extends Plugin { private static final Pattern WAVE_MESSAGE = Pattern.compile("Wave: (\\d+)"); private static final String DEFEATED_MESSAGE = "You have been defeated!"; private static final Pattern COMPLETE_MESSAGE = Pattern.compile("Your (TzTok-Jad|TzKal-Zuk) kill count is:"); private static final Pattern PAUSED_MESSAGE = Pattern.compile("The (Inferno|Fight Cave) has been paused. You may now log out."); - private static final String CONFIG_GROUP = "tzhaartimers"; + private static final String CONFIG_GROUP = "Boss Time Tracker"; private static final String CONFIG_TIME = "time"; private static final String CONFIG_STARTED = "started"; private static final String CONFIG_LASTTIME = "lasttime"; @@ -79,7 +79,7 @@ public class TzhaarTimersPlugin extends Plugin private EventBus eventBus; @Getter - private TzhaarTimers timer; + private BossTimeTracker timer; private Instant startTime; private Instant lastTime; @@ -228,12 +228,12 @@ public class TzhaarTimersPlugin extends Plugin if (checkInFightCaves()) { - timer = new TzhaarTimers(itemManager.getImage(FIRE_CAPE), this, startTime, lastTime); + timer = new BossTimeTracker(itemManager.getImage(FIRE_CAPE), this, startTime, lastTime); infoBoxManager.addInfoBox(timer); } else if (checkInInferno()) { - timer = new TzhaarTimers(itemManager.getImage(INFERNAL_CAPE), this, startTime, lastTime); + timer = new BossTimeTracker(itemManager.getImage(INFERNAL_CAPE), this, startTime, lastTime); infoBoxManager.addInfoBox(timer); } } From 6cb3fb01e29a9237acb63005a13f42e86bec8db0 Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Thu, 12 Sep 2019 22:59:24 -0600 Subject: [PATCH 08/72] bosstimetrackerplugin: rl+ified it Added type = PluginType.PVM, enabledByDefault = false --- .../client/plugins/tzhaartimers/BossTimeTrackerPlugin.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java index 1d49a841e7..964fc70406 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java @@ -50,7 +50,9 @@ import static net.runelite.api.ItemID.INFERNAL_CAPE; @PluginDescriptor( name = "Boss Time Tracker", description = "Display elapsed time in the Fight Caves and Inferno", - tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar"} + tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar"}, + type = PluginType.PVM, + enabledByDefault = false ) public class BossTimeTrackerPlugin extends Plugin { From 6822f2aa2ddce18403502a57edd294df3e845dde Mon Sep 17 00:00:00 2001 From: Crystalknoct Date: Thu, 12 Sep 2019 23:24:03 -0600 Subject: [PATCH 09/72] bosstimetrackerplugin:checkstyle ima derp --- .../client/plugins/tzhaartimers/BossTimeTrackerPlugin.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java index 964fc70406..02979340d1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/tzhaartimers/BossTimeTrackerPlugin.java @@ -34,6 +34,7 @@ import net.runelite.client.config.ConfigManager; import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.PluginType; import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.eventbus.EventBus; @@ -50,7 +51,7 @@ import static net.runelite.api.ItemID.INFERNAL_CAPE; @PluginDescriptor( name = "Boss Time Tracker", description = "Display elapsed time in the Fight Caves and Inferno", - tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar"}, + tags = {"inferno", "fight", "caves", "cape", "timer", "tzhaar", "pvm"}, type = PluginType.PVM, enabledByDefault = false ) From 3f33f0975770da62eb77ebb061bd2476be01a96e Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Fri, 18 Oct 2019 02:54:31 +0100 Subject: [PATCH 10/72] clues: add question text to all applicable clues --- .../cluescrolls/clues/AnagramClue.java | 140 +++++++++--------- .../plugins/cluescrolls/clues/CipherClue.java | 41 ++--- .../cluescrolls/clues/CrypticClue.java | 33 ++++- 3 files changed, 121 insertions(+), 93 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java index 27391e39bf..5c8e38e72a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/AnagramClue.java @@ -51,109 +51,109 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private static final String ANAGRAM_TEXT_BEGINNER = "The anagram reveals who to speak to next: "; private static final Set CLUES = ImmutableSet.of( - new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "5"), - new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "6"), + new AnagramClue("A BAKER", "Baraek", new WorldPoint(3217, 3434, 0), "Varrock square", "How many stalls are there in Varrock Square?", "5"), + new AnagramClue("A BASIC ANTI POT", "Captain Tobias", new WorldPoint(3026, 3216, 0), "Port Sarim", "How many ships are there docked at Port Sarim currently?", "6"), new AnagramClue("A ELF KNOWS", "Snowflake", new WorldPoint(2872, 3934, 0), "Weiss"), - new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "2"), + new AnagramClue("A HEART", "Aretha", new WorldPoint(1814, 3851, 0), "Soul altar", "32 - 5x = 22, what is x?", "2"), new AnagramClue("A ZEN SHE", "Zenesha", new WorldPoint(2652, 3295, 0), "Platebody Southern Ardougne centre square"), new AnagramClue("ACE MATCH ELM", "Cam The Camel", new WorldPoint(3300, 3231, 0), "North of the glider in Al Kharid"), new AnagramClue("AHA JAR", "Jaraah", new WorldPoint(3359, 3276, 0), "Duel Arena hospital"), new AnagramClue("AN PAINT TONIC", "Captain Ninto", new WorldPoint(2865, 9877, 0), "Bar under White Wolf Mountain"), - new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North Witchaven next to the row boat", "11"), - new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain West of Edgeville", "48"), - new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "South entrance of Varrock", "0"), + new AnagramClue("ARC O LINE", "Caroline", new WorldPoint(2715, 3302, 0), "North Witchaven next to the row boat", "How many fishermen are there on the fishing platform?", "11"), + new AnagramClue("ARE COL", "Oracle", new WorldPoint(3013, 3501, 0), "Ice Mountain West of Edgeville", "If x is 15 and y is 3 what is 3x + y?", "48"), + new AnagramClue("ARMCHAIR THE PELT", "Charlie the Tramp", new WorldPoint(3209, 3392, 0), "South entrance of Varrock", "How many coins would I have if I had 0 coins and attempted to buy 3 loaves of bread?", "0"), new AnagramClue("ARR! SO I AM A CRUST, AND?", "Ramara du Croissant", new WorldPoint(2339, 3677, 0), "Piscatoris Fishing Colony"), - new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "General Store, Arceuus, Zeah", "25"), + new AnagramClue("AT HERG", "Regath", new WorldPoint(1719, 3723, 0), "General Store, Arceuus, Zeah", "What is -5 to the power of 2?", "25"), new AnagramClue("A BAS", "Saba", new WorldPoint(2858, 3577, 0), "Death Plateau"), - new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "19 or 20"), + new AnagramClue("AREA CHEF TREK", "Father Aereck", new WorldPoint(3243, 3208, 0), "Lumbridge Church", "How many gravestones are in the church graveyard?", "19 or 20"), new AnagramClue("BAIL TRIMS", "Brimstail", new WorldPoint(2402, 3419, 0), "West of Stronghold Slayer Cave"), new AnagramClue("BAKER CLIMB", "Brambickle", new WorldPoint(2783, 3861, 0), "Trollweiss mountain"), new AnagramClue("BLUE GRIM GUIDED", "Lumbridge Guide", new WorldPoint(3232, 3232, 0), "Lumbridge"), - new AnagramClue("BY LOOK", "Bolkoy", new WorldPoint(2529, 3162, 0), "Tree Gnome Village general store", "13"), - new AnagramClue("CALAMARI MADE MUD", "Madame Caldarium", new WorldPoint(2553, 2868, 0), "Corsair Cove", "6"), + new AnagramClue("BY LOOK", "Bolkoy", new WorldPoint(2529, 3162, 0), "Tree Gnome Village general store", "How many flowers are there in the clearing below this platform?", "13"), + new AnagramClue("CALAMARI MADE MUD", "Madame Caldarium", new WorldPoint(2553, 2868, 0), "Corsair Cove", "What is 3(5-3)?", "6"), new AnagramClue("CAR IF ICES", "Sacrifice", new WorldPoint(2209, 3056, 0), "Zul-Andra"), - new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "25"), - new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "4"), - new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "6"), - new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "619"), - new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "12"), + new AnagramClue("CAREER IN MOON", "Oneiromancer", new WorldPoint(2150, 3866, 0), "Astral altar", "How many Suqah inhabit Lunar isle?", "25"), + new AnagramClue("CLASH ION", "Nicholas", new WorldPoint(1841, 3803, 0), "North of Port Piscarilius fishing shop", "How many windows are in Tynan's shop?", "4"), + new AnagramClue("C ON GAME HOC", "Gnome Coach", new WorldPoint(2395, 3486, 0), "Gnome Ball course", "How many gnomes on the Gnome ball field have red patches on their uniforms?", "6"), + new AnagramClue("COOL NERD", "Old crone", new WorldPoint(3462, 3557, 0), "East of the Slayer Tower", "What is the combined combat level of each species that live in Slayer tower?", "619"), + new AnagramClue("COPPER ORE CRYPTS", "Prospector Percy", new WorldPoint(3061, 3377, 0), "Motherlode Mine", "During a party, everyone shook hands with everyone else. There were 66 handshakes. How many people were at the party?", "12"), new AnagramClue("DED WAR", "Edward", new WorldPoint(3284, 3943, 0), "Inside Rogue's Castle"), - new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "13"), - new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "95"), - new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "28 or Puzzle box"), - new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "28, Light box or Puzzle box"), - new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Side of Keldagrim", "Puzzle box"), - new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "40"), - new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka, main hall", "4"), + new AnagramClue("DEKAGRAM", "Dark mage", new WorldPoint(3039, 4835, 0), "Centre of the Abyss", "How many rifts are found here in the abyss?", "13"), + new AnagramClue("DO SAY MORE", "Doomsayer", new WorldPoint(3230, 3230, 0), "East of Lumbridge Castle", "What is 40 divided by 1/2 plus 15?", "95"), + new AnagramClue("DIM THARN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area"), + new AnagramClue("DR HITMAN", "Mandrith", new WorldPoint(3182, 3946, 0), "Wilderness Resource Area", "How many scorpions live under the pit?", "28"), + new AnagramClue("DR WARDEN FUNK", "Drunken Dwarf", new WorldPoint(2913, 10221, 0), "East Side of Keldagrim"), + new AnagramClue("DRAGONS LAMENT", "Strange Old Man", new WorldPoint(3564, 3288, 0), "Barrows", "One pipe fills a barrel in 1 hour while another pipe can fill the same barrel in 2 hours. How many minutes will it take to fill the take if both pipes are used?", "40"), + new AnagramClue("DT RUN B", "Brundt the Chieftain", new WorldPoint(2658, 3670, 0), "Rellekka, main hall", "How many people are waiting for the next bard to perform?", "4"), new AnagramClue("DUO PLUG", "Dugopul", new WorldPoint(2803, 2744, 0), "Graveyard on Ape Atoll"), - new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "40"), + new AnagramClue("EEK ZERO OP", "Zoo keeper", new WorldPoint(2613, 3269, 0), "Ardougne Zoo", "How many animals are in the Ardougne Zoo?", "40"), new AnagramClue("EL OW", "Lowe", new WorldPoint(3233, 3423, 0), "Varrock archery store"), - new AnagramClue("ERR CURE IT", "Recruiter", new WorldPoint(2541, 3305, 0), "West Ardougne centre square", "20"), + new AnagramClue("ERR CURE IT", "Recruiter", new WorldPoint(2541, 3305, 0), "West Ardougne centre square", "How many houses have a cross on the door?", "20"), new AnagramClue("FORLUN", "Runolf", new WorldPoint(2512, 10256, 0), "Miscellania & Etceteria Dungeon"), new AnagramClue("GOBLIN KERN", "King Bolren", new WorldPoint(2541, 3170, 0), "Tree Gnome Village"), - new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Centre of Tai Bwo Wannai", "11"), + new AnagramClue("GOT A BOY", "Gabooty", new WorldPoint(2790, 3066, 0), "Centre of Tai Bwo Wannai", "How many buildings in the village?", "11"), new AnagramClue("GULAG RUN", "Uglug Nar", new WorldPoint(2442, 3051, 0), "West of Jiggig"), - new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "2"), - new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja", "33 (or none)"), + new AnagramClue("GOBLETS ODD TOES", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many types of dragon are there beneath the whirlpool's cavern?", "2"), + new AnagramClue("HALT US", "Luthas", new WorldPoint(2938, 3152, 0), "Banana plantation, Karamja"), new AnagramClue("HE DO POSE. IT IS CULTRRL, MK?", "Riki the sculptor's model", new WorldPoint(2904, 10206, 0), "East Keldagrim, south of kebab seller."), - new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Top floor of Burthorpe Castle", "36"), - new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library, Zeah", "1"), - new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Allotment patch, South of Hosidius chapel", "5"), + new AnagramClue("HEORIC", "Eohric", new WorldPoint(2900, 3565, 0), "Top floor of Burthorpe Castle", "King Arthur and Merlin sit down at the Round Table with 8 knights. How many degrees does each get?", "36"), + new AnagramClue("HIS PHOR", "Horphis", new WorldPoint(1639, 3812, 0), "Arceuus Library, Zeah", "On a scale of 1-10, how helpful is Logosia?", "1"), + new AnagramClue("I AM SIR", "Marisi", new WorldPoint(1737, 3557, 0), "Allotment patch, South of Hosidius chapel", "How many cities form the Kingdom of Great Kourend?", "5"), new AnagramClue("ICY FE", "Fycie", new WorldPoint(2630, 2997, 0), "East Feldip Hills"), - new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "9,500"), + new AnagramClue("I DOOM ICON INN", "Dominic Onion", new WorldPoint(2609, 3116, 0), "Nightmare Zone", "How many reward points does a herb box cost?", "9,500"), new AnagramClue("I EAT ITS CHART HINTS DO U", "Shiratti the Custodian", new WorldPoint(3427, 2927, 0), "North of fountain, Nardah"), - new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "The slayer master in Gnome Stronghold", "2"), + new AnagramClue("I EVEN", "Nieve", new WorldPoint(2432, 3422, 0), "The slayer master in Gnome Stronghold", "How many farming patches are there in Gnome stronghold?", "2"), new AnagramClue("I FAFFY RUN", "Fairy Nuff", new WorldPoint(3201, 3169, 0), "North of the bank in Zanaris"), new AnagramClue("IM N ZEZIM", "Impling", new WorldPoint(2592, 4324, 0), "The Imp inside Puro-Puro"), - new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "The courtyard in Camelot Castle", "6"), - new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Rising Sun Inn in Falador", "18"), + new AnagramClue("KAY SIR", "Sir Kay", new WorldPoint(2760, 3496, 0), "The courtyard in Camelot Castle", "How many fountains are there within the grounds of Camelot castle.", "6"), + new AnagramClue("LEAKEY", "Kaylee", new WorldPoint(2957, 3370, 0), "Rising Sun Inn in Falador", "How many chairs are there in the Rising Sun?", "18"), new AnagramClue("LAND DOOMD", "Odd Old Man", new WorldPoint(3359, 3506, 0), "Limestone mine northeast of Varrock"), - new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Ground floor of Varrock castle", "24"), - new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Vinery in the Great Kourend", "12"), - new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "3"), + new AnagramClue("LARK IN DOG", "King Roald", new WorldPoint(3220, 3476, 0), "Ground floor of Varrock castle", "How many bookcases are there in the Varrock palace library?", "24"), + new AnagramClue("LOW LAG", "Gallow", new WorldPoint(1805, 3566, 0), "Vinery in the Great Kourend", "How many vine patches can you find in this vinery?", "12"), + new AnagramClue("LADDER MEMO GUV", "Guard Vemmeldo", new WorldPoint(2447, 3418, 1), "Gnome Stronghold Bank", "How many magic trees can you find inside the Gnome Stronghold?", "3"), new AnagramClue("MAL IN TAU", "Luminata", new WorldPoint(3508, 3237, 0), "Near Burgh de Rott entrance"), new AnagramClue("ME AM THE CALC", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena"), - new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena", "6"), + new AnagramClue("MACHETE CLAM", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Outside Duel Arena", "How many items can carry water in RuneScape?", "6"), new AnagramClue("ME IF", "Femi", new WorldPoint(2461, 3382, 0), "Gates of Tree Gnome Stronghold"), new AnagramClue("MOLD LA RAN", "Old Man Ral", new WorldPoint(3602, 3209, 0), "Meiyerditch"), - new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Monastery south of Ardougne", "129"), + new AnagramClue("MOTHERBOARD", "Brother Omad", new WorldPoint(2606, 3211, 0), "Monastery south of Ardougne", "What is the next number? 12, 13, 15, 17, 111, 113, 117, 119, 123....?", "129"), new AnagramClue("MUS KIL READER", "Radimus Erkle", new WorldPoint(2726, 3368, 0), "Legends' Guild"), new AnagramClue("MY MANGLE LAL", "Lammy Langle", new WorldPoint(1688, 3540, 0), "Hosidius spirit tree patch"), - new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya Seamstress shop in Lletya", "20"), - new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "Behind the most NW house in East Ardougne", "3"), - new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "33"), - new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Ground floor of Lumbridge Castle", "9"), + new AnagramClue("NO OWNER", "Oronwen", new WorldPoint(1162, 3178, 0), "Lletya Seamstress shop in Lletya", "What is the minimum amount of quest points required to reach Lletya?", "20"), + new AnagramClue("NOD MED", "Edmond", new WorldPoint(2566, 3332, 0), "Behind the most NW house in East Ardougne", "How many pigeon cages are there around the back of Jerico's house?", "3"), + new AnagramClue("O BIRDZ A ZANY EN PC", "Cap'n Izzy No-Beard", new WorldPoint(2807, 3191, 0), "Brimhaven Agility Arena", "How many Banana Trees are there in the plantation?", "33"), + new AnagramClue("OK CO", "Cook", new WorldPoint(3207, 3214, 0), "Ground floor of Lumbridge Castle", "How many cannons does Lumbridge Castle have?", "9"), new AnagramClue("OR ZINC FUMES WARD", "Wizard Frumscone", new WorldPoint(2594, 3086, 0), "Downstairs in the Wizards' Guild"), - new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1575, 3590, 0), "Shayzien Infirmary", "19"), - new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1561, 3602, 0), "Building east of Shayzien combat ring", "113"), - new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Flax field south of Seers Village", "676"), + new AnagramClue("OUR OWN NEEDS", "Nurse Wooned", new WorldPoint(1575, 3590, 0), "Shayzien Infirmary", "How many injured soldiers are in this tent?", "19"), + new AnagramClue("PACINNG A TAIE", "Captain Ginea", new WorldPoint(1561, 3602, 0), "Building east of Shayzien combat ring", "1 soldier can deal with 6 lizardmen. How many soldiers do we need for an army of 678 lizardmen?", "113"), + new AnagramClue("PEAK REFLEX", "Flax keeper", new WorldPoint(2744, 3444, 0), "Flax field south of Seers Village", "If I have 1014 flax, and I spin a third of them into bowstring, how many flax do I have left?", "676"), new AnagramClue("PEATY PERT", "Party Pete", new WorldPoint(3047, 3376, 0), "Falador Party Room"), new AnagramClue("PROFS LOSE WRONG PIE", "Professor Onglewip", new WorldPoint(3113, 3162, 0), "Ground floor of Wizards Tower"), - new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "7"), - new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle Courtyard", "654"), - new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid Kebab shop", "5"), - new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "2"), + new AnagramClue("QUIT HORRIBLE TYRANT", "Brother Tranquility", new WorldPoint(3681, 2963, 0), "Mos Le'Harmless or Harmony Island", "If I have 49 bottles of rum to share between 7 pirates, how many would each pirate get?", "7"), + new AnagramClue("QUE SIR", "Squire", new WorldPoint(2975, 3343, 0), "Falador Castle Courtyard", "White knights are superior to black knights. 2 white knights can handle 3 black knights. How many knights do we need for an army of 981 black knights?", "654"), + new AnagramClue("R AK MI", "Karim", new WorldPoint(3273, 3181, 0), "Al Kharid Kebab shop", "I have 16 kebabs, I eat one myself and share the rest equally between 3 friends. How many do they have each?", "5"), + new AnagramClue("RAT MAT WITHIN", "Martin Thwait", new WorldPoint(2906, 3537, 0), "Rogues' Den", "How many natural fires burn in Rogue's Den?", "2"), new AnagramClue("RED ART TANS", "Trader Stan", new WorldPoint(3041, 3193, 0), "Port Sarim Charter ship"), - new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "7"), - new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine, Zeah", "738"), + new AnagramClue("RATAI", "Taria", new WorldPoint(2940, 3223, 0), "Rimmington bush patch", "How many buildings are there in Rimmington?", "7"), + new AnagramClue("R SLICER", "Clerris", new WorldPoint(1761, 3850, 0), "Arceuus mine, Zeah", "If I have 1,000 blood runes, and cast 131 ice barrage spells, how many blood runes do I have left?", "738"), new AnagramClue("RIP MAUL", "Primula", new WorldPoint(2454, 2853, 1), "Myth's Guild, first floor"), - new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil in north east Burthorpe", "8"), + new AnagramClue("SAND NUT", "Dunstan", new WorldPoint(2919, 3574, 0), "Anvil in north east Burthorpe", "How much smithing experience does one receive for smelting a blurite bar?", "8"), new AnagramClue("SEQUIN DIRGE", "Queen Sigrid", new WorldPoint(2612, 3867, 0), "Throne room of Etceteria Castle."), new AnagramClue("SLAM DUSTER GRAIL", "Guildmaster Lars", new WorldPoint(1649, 3498, 0), "Woodcutting guild, Zeah"), - new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "28"), + new AnagramClue("SLIDE WOMAN", "Wise Old Man", new WorldPoint(3088, 3253, 0), "Draynor Village", "How many bookcases are in the Wise Old Man's house?", "28"), new AnagramClue("SNAH", "Hans", new WorldPoint(3218, 3219, 0), "Lumbridge Castle courtyard"), - new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "2"), - new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "5"), + new AnagramClue("SNAKES SO I SAIL", "Lisse Isaakson", new WorldPoint(2351, 3801, 0), "Neitiznot", "How many arctic logs are required to make a large fremennik round shield?", "2"), + new AnagramClue("TAMED ROCKS", "Dockmaster", new WorldPoint(1822, 3739, 0), "Port Piscarilius, NE of General store", "What is the cube root of 125?", "5"), new AnagramClue("TEN WIGS ON", "Wingstone", new WorldPoint(3389, 2877, 0), "Between Nardah & Agility Pyramid"), new AnagramClue("THEM CAL CAME", "Cam the Camel", new WorldPoint(3300, 3231, 0), "Just outside of the Duel Arena"), - new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby fletching shop", "2"), + new AnagramClue("THICKNO", "Hickton", new WorldPoint(2822, 3442, 0), "Catherby fletching shop", "How many ranges are there in Catherby?", "2"), new AnagramClue("TWENTY CURE IRON", "New recruit Tony", new WorldPoint(1498, 3544, 0), "Shayzien Graveyard"), - new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka", "302"), - new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Wyvern Area or Stronghold Slayer Cave", "2"), - new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "666"), - new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "24"), + new AnagramClue("UNLEASH NIGHT MIST", "Sigli the Huntsman", new WorldPoint(2660, 3654, 0), "Rellekka", "What is the combined slayer requirement of every monster in the slayer cave?", "302"), + new AnagramClue("VESTE", "Steve", new WorldPoint(2432, 3423, 0), "Upstairs Wyvern Area or Stronghold Slayer Cave", "How many farming patches are there in Gnome stronghold?", "2"), + new AnagramClue("VEIL VEDA", "Evil Dave", new WorldPoint(3079, 9892, 0), "Doris' basement, Edgeville", "What is 333 multiplied by 2?", "666"), + new AnagramClue("WOO AN EGG KIWI", "Awowogei", ObjectID.AWOWOGEI, new WorldPoint(2802, 2765, 0), "Ape Atoll", "If I have 303 bananas, and share them between 31 friends evenly, only handing out full bananas. How many will I have left over?", "24"), new AnagramClue("YAWNS GY", "Ysgawyn", new WorldPoint(2340, 3167, 0), "Lletya"), - new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "2505"), + new AnagramClue("MAJORS LAVA BADS AIR", "Ambassador Alvijar", new WorldPoint(2736, 5351, 1), "Dorgesh-Kaan, NE Middle Level", "Double the miles before the initial Dorgeshuun veteran.", "2505"), new AnagramClue("AN EARL", "Ranael", new WorldPoint(3315, 3163, 0), "Al Kharid skirt shop"), new AnagramClue("CARPET AHOY", "Apothecary", new WorldPoint(3195, 3404, 0), "Southwest Varrock"), new AnagramClue("DISORDER", "Sedridor", new WorldPoint(3102, 9570, 0), "Wizards' Tower basement"), @@ -163,7 +163,7 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc new AnagramClue("RUG DETER", "Gertrude", new WorldPoint(3151, 3412, 0), "West of Varrock, south of the Cooks' Guild"), new AnagramClue("SIR SHARE RED", "Hairdresser", new WorldPoint(2944, 3381, 0), "Western Falador"), new AnagramClue("TAUNT ROOF", "Fortunato", new WorldPoint(3080, 3250, 0), "Draynor Village Market"), - new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne", "38"), + new AnagramClue("HICK JET", "Jethick", new WorldPoint(2541, 3305, 0), "West Ardougne", "How many graves are there in the city graveyard?", "38"), new AnagramClue("RUE GO", "Goreu", new WorldPoint(2335, 3162, 0), "Lletya") ); @@ -171,27 +171,29 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc private final String npc; private final WorldPoint location; private final String area; + private final String question; private final String answer; private int objectId; private AnagramClue(String text, String npc, WorldPoint location, String area) { - this(text, npc, location, area, null); + this(text, npc, location, area, "", null); } - private AnagramClue(String text, String npc, WorldPoint location, String area, String answer) + private AnagramClue(String text, String npc, WorldPoint location, String area, String question, String answer) { this.text = text; this.npc = npc; this.location = location; this.area = area; + this.question = question; this.answer = answer; this.objectId = -1; } - private AnagramClue(String text, String npc, int objectId, WorldPoint location, String area, String answer) + private AnagramClue(String text, String npc, int objectId, WorldPoint location, String area, String question, String answer) { - this(text, npc, location, area, answer); + this(text, npc, location, area, question, answer); this.objectId = objectId; } @@ -257,7 +259,9 @@ public class AnagramClue extends ClueScroll implements TextClueScroll, NpcClueSc { for (AnagramClue clue : CLUES) { - if (text.equalsIgnoreCase(ANAGRAM_TEXT + clue.text) || text.equalsIgnoreCase(ANAGRAM_TEXT_BEGINNER + clue.text)) + if (text.equalsIgnoreCase(ANAGRAM_TEXT + clue.text) + || text.equalsIgnoreCase(ANAGRAM_TEXT_BEGINNER + clue.text) + || text.equalsIgnoreCase(clue.question)) { return clue; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java index 1126e24492..e59e25eb56 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CipherClue.java @@ -43,35 +43,42 @@ import net.runelite.client.ui.overlay.components.TitleComponent; public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScroll, LocationClueScroll { private static final Set CLUES = ImmutableSet.of( - new CipherClue("BMJ UIF LFCBC TFMMFS", "Ali the Kebab seller", new WorldPoint(3354, 2974, 0), "Pollnivneach", "399"), - new CipherClue("GUHCHO", "Drezel", new WorldPoint(3440, 9895, 0), "Paterdomus", "7"), - new CipherClue("ZCZL", "Adam", new WorldPoint(3227, 3227, 0), "Outside Lumbridge castle", "666"), - new CipherClue("ZHLUG ROG PDQ", "Weird Old Man", new WorldPoint(3224, 3112, 0), "Kalphite Lair entrance. Fairy ring BIQ", "150"), - new CipherClue("ECRVCKP MJCNGF", "Captain Khaled", new WorldPoint(1845, 3754, 0), "Large eastern building in Port Piscarilius", "5"), - new CipherClue("OVEXON", "Eluned", new WorldPoint(2289, 3144, 0), "Outside Lletya", "53,000"), - new CipherClue("VTYR APCNTGLW", "King Percival", new WorldPoint(2634, 4682, 1), "Fisher Realm, first floor. Fairy ring BJR", "5"), - new CipherClue("UZZU MUJHRKYYKJ", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "3"), - new CipherClue("USBJCPSO", "Traiborn", new WorldPoint(3112, 3162, 0), "First floor of Wizards Tower", "3150"), - new CipherClue("HCKTA IQFHCVJGT", "Fairy Godfather", new WorldPoint(2446, 4428, 0), "Zanaris throne room", "64"), - new CipherClue("ZSBKDO ZODO", "Pirate Pete", new WorldPoint(3680, 3537, 0), "Dock northeast of the Ectofunctus", "Puzzle"), - new CipherClue("GBJSZ RVFFO", "Fairy Queen", new WorldPoint(2347, 4435, 0), "Fairy Resistance Hideout", "Puzzle"), - new CipherClue("QSPGFTTPS HSBDLMFCPOF", "Professor Gracklebone", new WorldPoint(1625, 3802, 0), "Ground floor of Arceuus Library", "9"), - new CipherClue("IWPPLQTP", "Gunnjorn", new WorldPoint(2541, 3548, 0), "Barbarian Outpost Agility course", "Puzzle"), - new CipherClue("BSOPME MZETQPS", "Arnold Lydspor", new WorldPoint(2329, 3689, 0), "Piscatoris Fishing Colony general store/bank", "Puzzle") + new CipherClue("BMJ UIF LFCBC TFMMFS", "Ali the Kebab seller", new WorldPoint(3354, 2974, 0), "Pollnivneach", "How many coins would you need to purchase 133 kebabs from me?", "399"), + new CipherClue("GUHCHO", "Drezel", new WorldPoint(3440, 9895, 0), "Paterdomus", "Please solve this for x: 7x - 28=21", "7"), + new CipherClue("ZCZL", "Adam", new WorldPoint(3227, 3227, 0), "Outside Lumbridge castle", "How many snakeskins are needed in order to craft 44 boots, 29 vambraces and 34 bandanas?", "666"), + new CipherClue("ZHLUG ROG PDQ", "Weird Old Man", new WorldPoint(3224, 3112, 0), "Kalphite Lair entrance. Fairy ring BIQ", "SIX LEGS! All of them have 6! There are 25 of them! How many legs?", "150"), + new CipherClue("ECRVCKP MJCNGF", "Captain Khaled", new WorldPoint(1845, 3754, 0), "Large eastern building in Port Piscarilius", "How many fishing cranes can you find around here?", "5"), + new CipherClue("OVEXON", "Eluned", new WorldPoint(2289, 3144, 0), "Outside Lletya", "A question on elven crystal math. I have 5 and 3 crystals, large and small respectively. A large crystal is worth 10,000 coins and a small is worth but 1,000. How much are all my crystals worth?", "53,000"), + new CipherClue("VTYR APCNTGLW", "King Percival", new WorldPoint(2634, 4682, 1), "Fisher Realm, first floor. Fairy ring BJR", "How many cannons are on this here castle?", "5"), + new CipherClue("UZZU MUJHRKYYKJ", "Otto Godblessed", new WorldPoint(2501, 3487, 0), "Otto's Grotto", "How many pyre sites are found around this lake?", "3"), + new CipherClue("USBJCPSO", "Traiborn", new WorldPoint(3112, 3162, 0), "First floor of Wizards Tower", "How many air runes would I need to cast 630 wind waves?", "3150"), + new CipherClue("HCKTA IQFHCVJGT", "Fairy Godfather", new WorldPoint(2446, 4428, 0), "Zanaris throne room", "There are 3 inputs and 4 letters on each ring How many total individual fairy ring codes are possible?", "64"), + new CipherClue("ZSBKDO ZODO", "Pirate Pete", new WorldPoint(3680, 3537, 0), "Dock northeast of the Ectofunctus"), + new CipherClue("GBJSZ RVFFO", "Fairy Queen", new WorldPoint(2347, 4435, 0), "Fairy Resistance Hideout"), + new CipherClue("QSPGFTTPS HSBDLMFCPOF", "Professor Gracklebone", new WorldPoint(1625, 3802, 0), "Ground floor of Arceuus Library", "How many round tables can be found on this floor of the library?", "9"), + new CipherClue("IWPPLQTP", "Gunnjorn", new WorldPoint(2541, 3548, 0), "Barbarian Outpost Agility course"), + new CipherClue("BSOPME MZETQPS", "Arnold Lydspor", new WorldPoint(2329, 3689, 0), "Piscatoris Fishing Colony general store/bank") ); private String text; private String npc; private WorldPoint location; private String area; + private String question; private String answer; - private CipherClue(String text, String npc, WorldPoint location, String area, String answer) + private CipherClue(String text, String npc, WorldPoint location, String area) + { + this(text, npc, location, area, "", null); + } + + private CipherClue(String text, String npc, WorldPoint location, String area, String question, String answer) { this.text = "The cipher reveals who to speak to next: " + text; this.npc = npc; this.location = location; this.area = area; + this.question = question; this.answer = answer; } @@ -122,7 +129,7 @@ public class CipherClue extends ClueScroll implements TextClueScroll, NpcClueScr { for (CipherClue clue : CLUES) { - if (clue.text.equalsIgnoreCase(text)) + if (clue.text.equalsIgnoreCase(text) || clue.question.equalsIgnoreCase(text)) { return clue; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java index 17eb5278f0..29a9ca5f75 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CrypticClue.java @@ -61,7 +61,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Search the crates in a bank in Varrock.", CRATE_5107, new WorldPoint(3187, 9825, 0), "Search in the basement of the West Varrock bank."), new CrypticClue("Falo the bard wants to see you.", "Falo the Bard", new WorldPoint(2689, 3550, 0), "Speak to Falo the Bard located between Seer's Village and Rellekka. Southwest of fairy ring CJR."), new CrypticClue("Search a bookcase in the Wizards tower.", BOOKCASE_12539, new WorldPoint(3113, 3159, 0), "The bookcase located on the ground floor."), - new CrypticClue("Come have a cip with this great soot covered denizen.", "Miner Magnus", new WorldPoint(2527, 3891, 0), "Talk to Miner Magnus east of the fairy ring CIP. Answer: 8"), + new CrypticClue("Come have a cip with this great soot covered denizen.", "Miner Magnus", new WorldPoint(2527, 3891, 0), "Talk to Miner Magnus east of the fairy ring CIP. Answer: 8", "How many coal rocks are around here?"), new CrypticClue("Citric cellar.", "Heckel Funch", new WorldPoint(2490, 3488, 0), "Speak to Heckel Funch on the first floor in the Grand Tree."), new CrypticClue("I burn between heroes and legends.", "Candle maker", new WorldPoint(2799, 3438, 0), "Speak to the Candle maker in Catherby."), new CrypticClue("Speak to Sarah at Falador farm.", "Sarah", new WorldPoint(3038, 3292, 0), "Talk to Sarah at Falador farm, north of Port Sarim."), @@ -110,7 +110,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Dig between some ominous stones in Falador.", new WorldPoint(3040, 3399, 0), "Three standing stones inside a walled area. East of the northern Falador gate."), new CrypticClue("Speak to Rusty north of Falador.", "Rusty", new WorldPoint(2979, 3435, 0), "Rusty can be found northeast of Falador on the way to the Mind altar."), new CrypticClue("Search a wardrobe in Draynor.", WARDROBE_5622, new WorldPoint(3087, 3261, 0), "Go to Aggie's house and search the wardrobe in northern wall."), - new CrypticClue("I have many arms but legs, I have just one. I have little family but my seed you can grow on, I am not dead, yet I am but a spirit, and my power, on your quests, you will earn the right to free it.", NULL_1293, new WorldPoint(2544, 3170, 0), "Spirit Tree in Tree Gnome Village. Answer: 13112221"), + new CrypticClue("I have many arms but legs, I have just one. I have little family but my seed you can grow on, I am not dead, yet I am but a spirit, and my power, on your quests, you will earn the right to free it.", NULL_1293, new WorldPoint(2544, 3170, 0), "Spirit Tree in Tree Gnome Village. Answer: 13112221", "What is the next number in the sequence? 1, 11, 21, 1211, 111221, 312211"), new CrypticClue("I am the one who watches the giants. The giants in turn watch me. I watch with two while they watch with one. Come seek where I may be.", "Kamfreena", new WorldPoint(2845, 3539, 0), "Speak to Kamfreena on the top floor of the Warriors' Guild."), new CrypticClue("In a town where wizards are known to gather, search upstairs in a large house to the north.", "Man", 375, new WorldPoint(2593, 3108, 1), "Search the chest upstairs in the house north of Yanille Wizard's Guild. Kill a man for the key."), new CrypticClue("Probably filled with wizards socks.", "Wizard", DRAWERS_350, new WorldPoint(3116, 9562, 0), "Search the drawers in the basement of the Wizard's Tower south of Draynor Village. Kill one of the Wizards for the key. Fairy ring DIS"), @@ -138,7 +138,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("46 is my number. My body is the colour of burnt orange and crawls among those with eight. Three mouths I have, yet I cannot eat. My blinking blue eye hides my grave.", new WorldPoint(3170, 3885, 0), "Sapphire respawn in the Spider's Nest, lvl 46 Wilderness. Dig under the sapphire spawn."), new CrypticClue("Green is the colour of my death as the winter-guise, I swoop towards the ground.", new WorldPoint(2780, 3783, 0), "Players need to slide down to where Trollweiss grows on Trollweiss Mountain."), new CrypticClue("Talk to a party-goer in Falador.", "Lucy", new WorldPoint(3046, 3382, 0), "Lucy is the bartender on the first floor of the party room."), - new CrypticClue("He knows just how easy it is to lose track of time.", "Brother Kojo", new WorldPoint(2570, 3250, 0), "Speak to Brother Kojo in the Clock Tower. Answer: 22"), + new CrypticClue("He knows just how easy it is to lose track of time.", "Brother Kojo", new WorldPoint(2570, 3250, 0), "Speak to Brother Kojo in the Clock Tower. Answer: 22", "On a clock, how many times a day do the minute hand and the hour hand overlap?"), new CrypticClue("A great view - watch the rapidly drying hides get splashed. Check the box you are sitting on.", BOXES, new WorldPoint(2523, 3493, 1), "Almera's House north of Baxtorian Falls, search boxes on the first floor."), new CrypticClue("Search the Coffin in Edgeville.", COFFIN, new WorldPoint(3091, 3477, 0), "Search the coffin located by the Wilderness teleport lever."), new CrypticClue("When no weapons are at hand, then is the time to reflect. In Saradomin's name, redemption draws closer...", DRAWERS_350, new WorldPoint(2818, 3351, 0), "On Entrana, search the southern drawer in the house with the cooking range."), @@ -211,7 +211,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Great demons, dragons and spiders protect this blue rock, beneath which, you may find what you seek.", new WorldPoint(3045, 10265, 0), "Dig by the runite rock in the Lava Maze Dungeon"), new CrypticClue("My giant guardians below the market streets would be fans of rock and roll, if only they could grab hold of it. Dig near my green bubbles!", new WorldPoint(3161, 9904, 0), "Dig near the cauldron by Moss Giants under Varrock Sewers"), new CrypticClue("Varrock is where I reside, not the land of the dead, but I am so old, I should be there instead. Let's hope your reward is as good as it says, just 1 gold one and you can have it read.", "Gypsy Aris", new WorldPoint(3203, 3424, 0), "Talk to Gypsy Aris, West of varrock main square."), - new CrypticClue("Speak to a referee.", "Gnome ball referee", new WorldPoint(2386, 3487, 0), "Talk to a Gnome ball referee found on the Gnome ball field in the Gnome Stronghold. Answer: 5096"), + new CrypticClue("Speak to a referee.", "Gnome ball referee", new WorldPoint(2386, 3487, 0), "Talk to a Gnome ball referee found on the Gnome ball field in the Gnome Stronghold. Answer: 5096", "What is 57 x 89 + 23?"), new CrypticClue("This crate holds a better reward than a broken arrow.", CRATE_356, new WorldPoint(2671, 3437, 0), "Inside the Ranging Guild. Search the crate behind the northern most building."), new CrypticClue("Search the drawers in the house next to the Port Sarim mage shop.", DRAWERS, new WorldPoint(3024, 3259, 0), "House east of Betty's. Contains a cooking sink."), new CrypticClue("With a name like that, you'd expect a little more than just a few scimitars.", "Daga", new WorldPoint(2759, 2775, 0), "Speak to Daga on Ape Atoll."), @@ -300,7 +300,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc new CrypticClue("Search the open crate found in the Hosidius kitchens.", CRATE_27533, new WorldPoint(1683, 3616, 0), "The kitchens are north-west of the town in Hosidius."), new CrypticClue("Dig under Ithoi's cabin.", new WorldPoint(2529, 2838, 0), "Dig under Ithoi's cabin in the Corsair Cove."), new CrypticClue("Search the drawers, upstairs in the bank to the East of Varrock.", DRAWERS_7194, new WorldPoint(3250, 3420, 1), "Search the drawers upstairs in Varrock east bank."), - new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859"), + new CrypticClue("Speak to Hazelmere.", "Hazelmere", new WorldPoint(2677, 3088, 1), "Located upstairs in the house to the north of fairy ring CLS. Answer: 6859", "What is 19 to the power of 3?"), new CrypticClue("The effects of this fire are magnified.", new WorldPoint(1179, 3626, 0), "Dig by the fire beside Ket'sal K'uk in the westernmost part of the Kebos Swamp. "), new CrypticClue("Always walking around the castle grounds and somehow knows everyone's age.", "Hans", new WorldPoint(3221, 3218, 0), "Talk to Hans walking around Lumbridge Castle."), new CrypticClue("In the place Duke Horacio calls home, talk to a man with a hat dropped by goblins.", "Cook", new WorldPoint(3208, 3213, 0), "Talk to the Cook in Lumbridge Castle."), @@ -331,6 +331,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private final int objectId; private final WorldPoint location; private final String solution; + private final String questionText; private CrypticClue(String text, WorldPoint location, String solution) { @@ -339,21 +340,37 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc private CrypticClue(String text, int objectId, WorldPoint location, String solution) { - this(text, null, objectId, location, solution); + this(text, null, objectId, location, solution, ""); } private CrypticClue(String text, String npc, WorldPoint location, String solution) { - this(text, npc, -1, location, solution); + this(text, npc, -1, location, solution, ""); + } + + private CrypticClue(String text, int objectId, WorldPoint location, String solution, String questionText) + { + this(text, null, objectId, location, solution, questionText); + } + + private CrypticClue(String text, String npc, WorldPoint location, String solution, String questionText) + { + this(text, npc, -1, location, solution, questionText); } private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution) + { + this(text, npc, objectId, location, solution, ""); + } + + private CrypticClue(String text, String npc, int objectId, WorldPoint location, String solution, String questionText) { this.text = text; this.npc = npc; this.objectId = objectId; this.location = location; this.solution = solution; + this.questionText = questionText; setRequiresSpade(getLocation() != null && getNpc() == null && objectId == -1); } @@ -442,7 +459,7 @@ public class CrypticClue extends ClueScroll implements TextClueScroll, NpcClueSc { for (CrypticClue clue : CLUES) { - if (clue.text.equalsIgnoreCase(text)) + if (clue.text.equalsIgnoreCase(text) || clue.questionText.equalsIgnoreCase(text)) { return clue; } From d4e40b63421f150e536543f651fb279e020284a4 Mon Sep 17 00:00:00 2001 From: Hydrox6 Date: Fri, 18 Oct 2019 02:54:38 +0100 Subject: [PATCH 11/72] clues: make Anagram and Cipher clues check all clue text --- .../plugins/cluescrolls/ClueScrollPlugin.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java index 47c64a5488..0bbd3b661e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollPlugin.java @@ -504,17 +504,6 @@ public class ClueScrollPlugin extends Plugin } } - // (This|The) anagram reveals who to speak to next: - if (text.contains("anagram reveals who to speak to next:")) - { - return AnagramClue.forText(text); - } - - if (text.startsWith("the cipher reveals who to speak to next:")) - { - return CipherClue.forText(text); - } - if (text.startsWith("i'd like to hear some music.")) { return MusicClue.forText(clueScrollText.getText()); @@ -525,6 +514,18 @@ public class ClueScrollPlugin extends Plugin return coordinatesToWorldPoint(text); } + final AnagramClue anagramClue = AnagramClue.forText(text); + if (anagramClue != null) + { + return anagramClue; + } + + final CipherClue cipherClue = CipherClue.forText(text); + if (cipherClue != null) + { + return cipherClue; + } + final CrypticClue crypticClue = CrypticClue.forText(text); if (crypticClue != null) From 7b82d61e09bac82ed23934a93f3d519766c381a7 Mon Sep 17 00:00:00 2001 From: trimbe Date: Sun, 27 Oct 2019 16:11:28 -0400 Subject: [PATCH 12/72] clues plugin: add fairy rings to coord clues --- .../cluescrolls/clues/CoordinateClue.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java index 3d833104d7..43965ade9d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/clues/CoordinateClue.java @@ -63,7 +63,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(2383, 3370, 0), "West of the outpost") .put(new WorldPoint(3312, 3375, 0), "North-west of Exam Centre, on the hill.") .put(new WorldPoint(3121, 3384, 0), "North-east of Draynor Manor, near River Lum.") - .put(new WorldPoint(3430, 3388, 0), "West of Mort Myre Swamp.") + .put(new WorldPoint(3430, 3388, 0), "West of Mort Myre Swamp (BKR).") .put(new WorldPoint(2920, 3403, 0), "South-east of Taverley, near Lady of the Lake.") .put(new WorldPoint(2594, 2899, 0), "South-east of Feldip Hills, by the crimson swifts (AKS).") .put(new WorldPoint(2387, 3435, 0), "West of Tree Gnome Stronghold, near the pen containing terrorbirds.") @@ -71,21 +71,21 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(2381, 3468, 0), "West of Tree Gnome Stronghold, north of the pen with terrorbirds.") .put(new WorldPoint(3005, 3475, 0), "Ice Mountain, west of Edgeville.") .put(new WorldPoint(2585, 3505, 0), "By the shore line north of the Coal Trucks.") - .put(new WorldPoint(3443, 3515, 0), "South of Slayer Tower.") + .put(new WorldPoint(3443, 3515, 0), "South of Slayer Tower (CKS).") .put(new WorldPoint(2416, 3516, 0), "Tree Gnome Stronghold, west of Grand Tree, near swamp.") - .put(new WorldPoint(3429, 3523, 0), "South of Slayer Tower.") - .put(new WorldPoint(2363, 3531, 0), "North-east of Eagles' Peak.") + .put(new WorldPoint(3429, 3523, 0), "South of Slayer Tower (CKS).") + .put(new WorldPoint(2363, 3531, 0), "North-east of Eagles' Peak (AKQ).") .put(new WorldPoint(2919, 3535, 0), "East of Burthorpe pub.") .put(new WorldPoint(3548, 3560, 0), "Inside Fenkenstrain's Castle.") .put(new WorldPoint(1456, 3620, 0), "Graveyard west of Shayzien (DJR).") .put(new WorldPoint(2735, 3638, 0), "East of Rellekka, north-west of Golden Apple Tree (AJR).") .put(new WorldPoint(2681, 3653, 0), "Rellekka, in the garden of the south-east house.") - .put(new WorldPoint(2537, 3881, 0), "Miscellania.") + .put(new WorldPoint(2537, 3881, 0), "Miscellania (CIP).") .put(new WorldPoint(2828, 3234, 0), "Southern coast of Crandor.") .put(new WorldPoint(1247, 3726, 0), "Just inside the Farming Guild") .put(new WorldPoint(3770, 3898, 0), "On the small island north-east of Fossil Island's mushroom forest.") // Hard - .put(new WorldPoint(2209, 3161, 0), "North-east of Tyras Camp.") + .put(new WorldPoint(2209, 3161, 0), "North-east of Tyras Camp (BJS).") .put(new WorldPoint(2181, 3206, 0), "South of Elf Camp.") .put(new WorldPoint(3081, 3209, 0), "Small Island (CLP).") .put(new WorldPoint(3374, 3250, 0), "Duel Arena combat area.") @@ -98,12 +98,12 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(2581, 3030, 0), "Gu'Tanoth island, enter cave north-west of Feldip Hills (AKS).") .put(new WorldPoint(2961, 3024, 0), "Ship yard (DKP).") .put(new WorldPoint(2339, 3311, 0), "East of Prifddinas on Arandar mountain pass.") - .put(new WorldPoint(3440, 3341, 0), "Nature Spirit's grotto.") - .put(new WorldPoint(2763, 2974, 0), "Cairn Isle, west of Shilo Village.") + .put(new WorldPoint(3440, 3341, 0), "Nature Spirit's grotto (BIP).") + .put(new WorldPoint(2763, 2974, 0), "Cairn Isle, west of Shilo Village (CKR).") .put(new WorldPoint(3138, 2969, 0), "West of Bandit Camp in Kharidian Desert.") .put(new WorldPoint(2924, 2963, 0), "On the southern part of eastern Karamja.") - .put(new WorldPoint(2838, 2914, 0), "Kharazi Jungle, near water pool.") - .put(new WorldPoint(3441, 3419, 0), "Mort Myre Swamp.") + .put(new WorldPoint(2838, 2914, 0), "Kharazi Jungle, near water pool (CKR).") + .put(new WorldPoint(3441, 3419, 0), "Mort Myre Swamp (BKR).") .put(new WorldPoint(2950, 2902, 0), "South-east of Kharazi Jungle.") .put(new WorldPoint(2775, 2891, 0), "South-west of Kharazi Jungle.") .put(new WorldPoint(3113, 3602, 0), "Wilderness. North of Edgeville (level 11).") @@ -113,8 +113,8 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(3305, 3692, 0), "Wilderness. West of eastern green dragon.") .put(new WorldPoint(3055, 3696, 0), "Wilderness. Bandit Camp.") .put(new WorldPoint(3302, 3696, 0), "Wilderness. West of eastern green dragon.") - .put(new WorldPoint(1479, 3696, 0), "Lizardman Canyon.") - .put(new WorldPoint(2712, 3732, 0), "North-east of Rellekka.") + .put(new WorldPoint(1479, 3696, 0), "Lizardman Canyon (DJR).") + .put(new WorldPoint(2712, 3732, 0), "North-east of Rellekka (DKS).") .put(new WorldPoint(2970, 3749, 0), "Wilderness. Forgotten Cemetery.") .put(new WorldPoint(3094, 3764, 0), "Wilderness. Mining site north of Bandit Camp.") .put(new WorldPoint(3311, 3769, 0), "Wilderness. North of Venenatis.") @@ -188,7 +188,7 @@ public class CoordinateClue extends ClueScroll implements TextClueScroll, Locati .put(new WorldPoint(1698, 3792, 0), "Arceuus church.") .put(new WorldPoint(2951, 3820, 0), "Wilderness. Chaos Temple (level 38).") .put(new WorldPoint(2202, 3825, 0), "Pirates' Cove, between Lunar Isle and Rellekka.") - .put(new WorldPoint(1761, 3853, 0), "Arceuus essence mine.") + .put(new WorldPoint(1761, 3853, 0), "Arceuus essence mine (CIS).") .put(new WorldPoint(2090, 3863, 0), "South of Lunar Isle, west of Astral altar.") .put(new WorldPoint(1442, 3878, 0), "Sulphur Mine.") .put(new WorldPoint(3380, 3929, 0), "Wilderness. Near Volcano.") From 169f305707fa4be132e25ed6063ff5967645379e Mon Sep 17 00:00:00 2001 From: Max Weber Date: Tue, 29 Oct 2019 21:26:57 -0600 Subject: [PATCH 13/72] runelite-client/chat: Be more thread safe --- .../net/runelite/client/chat/ChatCommandManager.java | 4 ++-- .../net/runelite/client/chat/ChatMessageManager.java | 11 ++--------- .../java/net/runelite/client/chat/CommandManager.java | 4 ++-- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java index f930992d08..1000ba641c 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatCommandManager.java @@ -24,8 +24,8 @@ */ package net.runelite.client.chat; -import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledExecutorService; import java.util.function.BiConsumer; import java.util.function.BiPredicate; @@ -43,7 +43,7 @@ import net.runelite.client.events.PrivateMessageInput; @Singleton public class ChatCommandManager implements ChatboxInputListener { - private final Map commands = new HashMap<>(); + private final Map commands = new ConcurrentHashMap<>(); private final Client client; private final ScheduledExecutorService scheduledExecutorService; diff --git a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java index fe0bfe0851..991cce5a88 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/ChatMessageManager.java @@ -556,16 +556,9 @@ public class ChatMessageManager public void process() { - if (!queuedMessages.isEmpty()) + for (QueuedMessage msg; (msg = queuedMessages.poll()) != null; ) { - try - { - queuedMessages.forEach(this::add); - } - finally - { - queuedMessages.clear(); - } + add(msg); } } diff --git a/runelite-client/src/main/java/net/runelite/client/chat/CommandManager.java b/runelite-client/src/main/java/net/runelite/client/chat/CommandManager.java index c066d47681..6c725df06c 100644 --- a/runelite-client/src/main/java/net/runelite/client/chat/CommandManager.java +++ b/runelite-client/src/main/java/net/runelite/client/chat/CommandManager.java @@ -25,9 +25,9 @@ */ package net.runelite.client.chat; -import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; @@ -55,7 +55,7 @@ public class CommandManager private final ClientThread clientThread; private boolean sending; - private final List chatboxInputListenerList = new ArrayList<>(); + private final List chatboxInputListenerList = new CopyOnWriteArrayList<>(); @Inject private CommandManager(Client client, EventBus eventBus, ClientThread clientThread) From 79dda8b7d0bc773039e780708908aa2673d1b250 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 31 Oct 2019 18:24:01 -0400 Subject: [PATCH 14/72] npc highlight: use local location for south-west highlight --- .../plugins/npchighlight/NpcSceneOverlay.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java index fef1b03c8a..66b4a97224 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/npchighlight/NpcSceneOverlay.java @@ -148,12 +148,24 @@ public class NpcSceneOverlay extends Overlay switch (config.renderStyle()) { case SOUTH_WEST_TILE: - LocalPoint lp1 = LocalPoint.fromWorld(client, actor.getWorldLocation()); - Polygon tilePoly1 = Perspective.getCanvasTilePoly(client, lp1); + { + int size = 1; + NPCComposition composition = actor.getTransformedComposition(); + if (composition != null) + { + size = composition.getSize(); + } - renderPoly(graphics, color, tilePoly1); + LocalPoint localPoint = actor.getLocalLocation(); + + int x = localPoint.getX() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); + int y = localPoint.getY() - ((size - 1) * Perspective.LOCAL_TILE_SIZE / 2); + + Polygon tilePoly = Perspective.getCanvasTilePoly(client, new LocalPoint(x, y)); + + renderPoly(graphics, color, tilePoly); break; - + } case TILE: int size = 1; NPCComposition composition = actor.getTransformedComposition(); From bbe38dae95ca158ecaa6e6f4560e227094448d63 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 31 Oct 2019 16:55:29 -0400 Subject: [PATCH 15/72] osb exchange service: validate price averages After an update they get reset to 0 for a time and it is overwriting our price cache --- .../http/service/osbuddy/OSBGrandExchangeService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java b/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java index 797d7e76e2..49e9e4a636 100644 --- a/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java +++ b/http-service/src/main/java/net/runelite/http/service/osbuddy/OSBGrandExchangeService.java @@ -98,6 +98,11 @@ public class OSBGrandExchangeService Integer itemId = entry.getKey(); OsbuddySummaryItem item = entry.getValue(); + if (item.getBuy_average() <= 0 || item.getSell_average() <= 0 || item.getOverall_average() <= 0) + { + continue; + } + query .addParameter("itemId", itemId) .addParameter("buyAverage", item.getBuy_average()) From dde308f2e8c1908146570cc80234c7747325e39a Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 31 Oct 2019 17:02:05 -0400 Subject: [PATCH 16/72] login screen: remove paste to password Jagex has added this now into their own client --- .../client/plugins/loginscreen/LoginScreenPlugin.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java index bda2e5cdf2..e495afab1d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/loginscreen/LoginScreenPlugin.java @@ -53,7 +53,6 @@ import net.runelite.client.util.OSType; public class LoginScreenPlugin extends Plugin implements KeyListener { private static final int MAX_USERNAME_LENGTH = 254; - private static final int MAX_PASSWORD_LENGTH = 20; private static final int MAX_PIN_LENGTH = 6; @Inject @@ -194,11 +193,6 @@ public class LoginScreenPlugin extends Plugin implements KeyListener // Truncate data to maximum username length if necessary client.setUsername(data.substring(0, Math.min(data.length(), MAX_USERNAME_LENGTH))); } - else - { - // Truncate data to maximum password length if necessary - client.setPassword(data.substring(0, Math.min(data.length(), MAX_PASSWORD_LENGTH))); - } break; // Authenticator form From a103da9118ecc929e0037ff97e66182d24b8b38a Mon Sep 17 00:00:00 2001 From: Ron Young Date: Thu, 31 Oct 2019 12:21:05 -0500 Subject: [PATCH 17/72] grandexchange: rebuild GE item text on rebuild script event Co-authored-by: Adam --- .../grandexchange/GrandExchangePlugin.java | 61 +++++++++++++------ 1 file changed, 41 insertions(+), 20 deletions(-) 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 b7936c243e..5aa10b539e 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 @@ -54,13 +54,10 @@ import net.runelite.api.events.ChatMessage; import net.runelite.api.events.ConfigChanged; import net.runelite.api.events.FocusChanged; import net.runelite.api.events.GameStateChanged; -import net.runelite.api.events.GameTick; import net.runelite.api.events.GrandExchangeOfferChanged; import net.runelite.api.events.MenuEntryAdded; -import net.runelite.client.events.SessionClose; -import net.runelite.client.events.SessionOpen; -import net.runelite.api.events.WidgetLoaded; import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.WidgetLoaded; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; @@ -69,6 +66,8 @@ import net.runelite.client.account.AccountSession; import net.runelite.client.account.SessionManager; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.SessionClose; +import net.runelite.client.events.SessionOpen; import net.runelite.client.game.ItemManager; import net.runelite.client.input.KeyManager; import net.runelite.client.input.MouseManager; @@ -152,6 +151,9 @@ public class GrandExchangePlugin extends Plugin private Widget grandExchangeItem; private Map itemGELimits; + private int osbItem; + private OSBGrandExchangeResult osbGrandExchangeResult; + private GrandExchangeClient grandExchangeClient; private SavedOffer getOffer(int slot) @@ -209,6 +211,9 @@ public class GrandExchangePlugin extends Plugin { grandExchangeClient = new GrandExchangeClient(accountSession.getUuid()); } + + osbItem = -1; + osbGrandExchangeResult = null; } @Override @@ -432,6 +437,11 @@ public class GrandExchangePlugin extends Plugin @Subscribe public void onScriptCallbackEvent(ScriptCallbackEvent event) { + if (event.getEventName().equals("geBuilt")) + { + rebuildGeText(); + } + if (!event.getEventName().equals("setGETitle") || !config.showTotal()) { return; @@ -472,8 +482,7 @@ public class GrandExchangePlugin extends Plugin stringStack[stringStackSize - 1] += titleBuilder.toString(); } - @Subscribe - public void onGameTick(GameTick event) + private void rebuildGeText() { if (grandExchangeText == null || grandExchangeItem == null || grandExchangeItem.isHidden()) { @@ -481,7 +490,6 @@ public class GrandExchangePlugin extends Plugin } final Widget geText = grandExchangeText; - final String geTextString = geText.getText(); final int itemId = grandExchangeItem.getItemId(); if (itemId == OFFER_DEFAULT_ITEM_ID || itemId == -1) @@ -490,39 +498,52 @@ public class GrandExchangePlugin extends Plugin return; } - if (config.enableGELimits() && itemGELimits != null && !geTextString.contains(BUY_LIMIT_GE_TEXT)) + String[] lines = geText.getText().split("
"); + String text = lines[0]; // remove any limit or OSB ge values + + if (config.enableGELimits() && itemGELimits != null) { final Integer itemLimit = itemGELimits.get(itemId); // If we have item buy limit, append it if (itemLimit != null) { - final String text = geText.getText() + BUY_LIMIT_GE_TEXT + QuantityFormatter.formatNumber(itemLimit); - geText.setText(text); + text += BUY_LIMIT_GE_TEXT + QuantityFormatter.formatNumber(itemLimit); } } - if (!config.enableOsbPrices() || geTextString.contains(OSB_GE_TEXT)) + geText.setText(text); + + if (!config.enableOsbPrices()) { - // OSB prices are disabled or price was already looked up, so no need to set it again return; } + // If we already have the result, use it + if (osbGrandExchangeResult != null && osbGrandExchangeResult.getItem_id() == itemId && osbGrandExchangeResult.getOverall_average() > 0) + { + geText.setText(text + OSB_GE_TEXT + QuantityFormatter.formatNumber(osbGrandExchangeResult.getOverall_average())); + } + + if (osbItem == itemId) + { + // avoid starting duplicate lookups + return; + } + + osbItem = itemId; + log.debug("Looking up OSB item price {}", itemId); + final String start = text; executorService.submit(() -> { - if (geText.getText().contains(OSB_GE_TEXT)) - { - // If there are multiple tasks queued and one of them have already added the price - return; - } - try { final OSBGrandExchangeResult result = CLIENT.lookupItem(itemId); - final String text = geText.getText() + OSB_GE_TEXT + QuantityFormatter.formatNumber(result.getOverall_average()); - geText.setText(text); + osbGrandExchangeResult = result; + // Update the text on the widget too + geText.setText(start + OSB_GE_TEXT + QuantityFormatter.formatNumber(result.getOverall_average())); } catch (IOException e) { From ec0858548ff52986a0e84706472b85180df22ac1 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 1 Nov 2019 10:14:44 -0400 Subject: [PATCH 18/72] container calculation: fix overflow computing ge price --- .../runelite/client/plugins/bank/ContainerCalculation.java | 2 +- .../client/plugins/bank/ContainerCalculationTest.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/bank/ContainerCalculation.java b/runelite-client/src/main/java/net/runelite/client/plugins/bank/ContainerCalculation.java index d78298b213..ca383bc81a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/bank/ContainerCalculation.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/bank/ContainerCalculation.java @@ -86,7 +86,7 @@ class ContainerCalculation final long storePrice = itemManager.getItemComposition(id).getPrice(); final long alchPrice = (long) (storePrice * Constants.HIGH_ALCHEMY_MULTIPLIER); alch += alchPrice * qty; - ge += itemManager.getItemPrice(id) * qty; + ge += (long) itemManager.getItemPrice(id) * qty; break; } diff --git a/runelite-client/src/test/java/net/runelite/client/plugins/bank/ContainerCalculationTest.java b/runelite-client/src/test/java/net/runelite/client/plugins/bank/ContainerCalculationTest.java index ca52a5bff2..1f220f4b64 100644 --- a/runelite-client/src/test/java/net/runelite/client/plugins/bank/ContainerCalculationTest.java +++ b/runelite-client/src/test/java/net/runelite/client/plugins/bank/ContainerCalculationTest.java @@ -81,11 +81,13 @@ public class ContainerCalculationTest .thenReturn(7); // 7 * .6 = 4, 4 * 1m overflows when(itemManager.getItemComposition(ItemID.ABYSSAL_WHIP)) .thenReturn(whipComp); + when(itemManager.getItemPrice(ItemID.ABYSSAL_WHIP)) + .thenReturn(3); // 1b * 3 overflows final ContainerPrices prices = containerCalculation.calculate(items); assertNotNull(prices); - long value = prices.getHighAlchPrice(); - assertTrue(value > Integer.MAX_VALUE); + assertTrue(prices.getHighAlchPrice() > Integer.MAX_VALUE); + assertTrue(prices.getGePrice() > Integer.MAX_VALUE); } } From 866659e653d6d97844843ef53b8e197fb532a041 Mon Sep 17 00:00:00 2001 From: benjaminlgur Date: Sat, 2 Nov 2019 01:57:06 -0400 Subject: [PATCH 19/72] woodcutting: added gpearned for woodcutting --- .../woodcutting/WoodcuttingConfig.java | 11 ++++ .../woodcutting/WoodcuttingOverlay.java | 8 +++ .../woodcutting/WoodcuttingPlugin.java | 61 +++++++++++++++++++ 3 files changed, 80 insertions(+) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java index 55cb5e3637..4c58fe4369 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingConfig.java @@ -74,4 +74,15 @@ public interface WoodcuttingConfig extends Config { return true; } + + @ConfigItem( + position = 5, + keyName = "showGPEarned", + name = "Show GP earned", + description = "Configures whether to show amount of gp earned by chopping trees" + ) + default boolean showGPEarned() + { + return false; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java index 9bb29e9824..a7408d5ea3 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java @@ -42,6 +42,7 @@ import net.runelite.client.ui.overlay.components.TitleComponent; import net.runelite.client.ui.overlay.components.table.TableAlignment; import net.runelite.client.ui.overlay.components.table.TableComponent; + @Singleton class WoodcuttingOverlay extends Overlay { @@ -50,6 +51,7 @@ class WoodcuttingOverlay extends Overlay private final XpTrackerService xpTrackerService; private final PanelComponent panelComponent = new PanelComponent(); + @Inject private WoodcuttingOverlay(final Client client, final WoodcuttingPlugin plugin, final XpTrackerService xpTrackerService) { @@ -101,6 +103,11 @@ class WoodcuttingOverlay extends Overlay { tableComponent.addRow("Logs cut:", Integer.toString(actions)); + if (plugin.isShowGPEarned()) + { + tableComponent.addRow("GP earned", Integer.toString((plugin.getGpEarned()))); + } + if (actions > 2) { tableComponent.addRow("Logs/hr:", Integer.toString(xpTrackerService.getActionsHr(Skill.WOODCUTTING))); @@ -112,4 +119,5 @@ class WoodcuttingOverlay extends Overlay return panelComponent.render(graphics); } + } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java index 7bc066283c..3ad7a7fe84 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -37,6 +37,8 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.GameState; +import net.runelite.api.Item; +import net.runelite.api.ItemID; import net.runelite.api.Player; import net.runelite.api.events.AnimationChanged; import net.runelite.api.events.ChatMessage; @@ -49,6 +51,7 @@ import net.runelite.api.events.GameTick; import net.runelite.client.Notifier; import net.runelite.client.config.ConfigManager; import net.runelite.client.eventbus.EventBus; +import net.runelite.client.game.ItemManager; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDependency; import net.runelite.client.plugins.PluginDescriptor; @@ -82,6 +85,9 @@ public class WoodcuttingPlugin extends Plugin @Inject private WoodcuttingConfig config; + @Inject + private ItemManager itemManager; + @Inject private EventBus eventBus; @@ -100,6 +106,12 @@ public class WoodcuttingPlugin extends Plugin private boolean showWoodcuttingStats; @Getter(AccessLevel.PACKAGE) private boolean showRedwoodTrees; + @Getter(AccessLevel.PACKAGE) + private boolean showGPEarned; + + private int treeTypeID; + @Getter(AccessLevel.PACKAGE) + private int gpEarned; @Provides WoodcuttingConfig getConfig(ConfigManager configManager) @@ -167,9 +179,13 @@ public class WoodcuttingPlugin extends Plugin if (session == null) { session = new WoodcuttingSession(); + gpEarned = 0; } session.setLastLogCut(); + + typeOfLogCut(event); + gpEarned = gpEarned + itemManager.getItemPrice(treeTypeID); } if (event.getMessage().contains("A bird's nest falls out of the tree") && this.showNestNotification) @@ -179,6 +195,50 @@ public class WoodcuttingPlugin extends Plugin } } + private void typeOfLogCut(ChatMessage event) + { + if (event.getMessage().contains("mushrooms.")) + { + return; //TO DO Add valuation for scullicep mushroom cutting. + } + else if (event.getMessage().contains("oak")) + { + treeTypeID = ItemID.OAK_LOGS; + } + else if (event.getMessage().contains("willow")) + { + treeTypeID = ItemID.WILLOW_LOGS; + } + else if (event.getMessage().contains("yew")) + { + treeTypeID = ItemID.YEW_LOGS; + } + else if (event.getMessage().contains("redwood")) + { + treeTypeID = ItemID.REDWOOD_LOGS; + } + else if (event.getMessage().contains("magic")) + { + treeTypeID = ItemID.MAGIC_LOGS; + } + else if (event.getMessage().contains("teak")) + { + treeTypeID = ItemID.TEAK_LOGS; + } + else if (event.getMessage().contains("mahogany")) + { + treeTypeID = ItemID.MAHOGANY_LOGS; + } + else if (event.getMessage().contains("maple")) + { + treeTypeID = ItemID.MAPLE_LOGS; + } + else + { + treeTypeID = ItemID.LOGS; + } + } + private void onGameObjectSpawned(final GameObjectSpawned event) { GameObject gameObject = event.getGameObject(); @@ -241,5 +301,6 @@ public class WoodcuttingPlugin extends Plugin this.showNestNotification = config.showNestNotification(); this.showWoodcuttingStats = config.showWoodcuttingStats(); this.showRedwoodTrees = config.showRedwoodTrees(); + this.showGPEarned = config.showGPEarned(); } } \ No newline at end of file From 13e280e6ae7bd1989941005c519a2d4f3c9b56c4 Mon Sep 17 00:00:00 2001 From: benjaminlgur Date: Sat, 2 Nov 2019 02:08:23 -0400 Subject: [PATCH 20/72] checkstyle fix --- .../runelite/client/plugins/woodcutting/WoodcuttingPlugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java index 3ad7a7fe84..e9bd610e38 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -37,7 +37,6 @@ import net.runelite.api.ChatMessageType; import net.runelite.api.Client; import net.runelite.api.GameObject; import net.runelite.api.GameState; -import net.runelite.api.Item; import net.runelite.api.ItemID; import net.runelite.api.Player; import net.runelite.api.events.AnimationChanged; From 71e548052470332a25c56d26e6f1d70b0ea9bac5 Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 1 Nov 2019 15:49:12 +0100 Subject: [PATCH 21/72] Fix ScreenshotPlugin Kingdom of Miscellania double screenshot --- .../net/runelite/client/plugins/screenshot/ScreenshotPlugin.java | 1 - 1 file changed, 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java index 27a78a59d4..c32ae795e8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenshot/ScreenshotPlugin.java @@ -451,7 +451,6 @@ public class ScreenshotPlugin extends Plugin case KINGDOM_GROUP_ID: { fileName = "Kingdom " + LocalDate.now(); - takeScreenshot(fileName); break; } case CHAMBERS_OF_XERIC_REWARD_GROUP_ID: From c1c546cb9aa27ee4a56532bb67fea6449c0fcdfe Mon Sep 17 00:00:00 2001 From: benjaminlgur Date: Sat, 2 Nov 2019 16:43:43 -0400 Subject: [PATCH 22/72] added colon for consistancy --- .../runelite/client/plugins/woodcutting/WoodcuttingOverlay.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java index a7408d5ea3..697f82d6ac 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java @@ -105,7 +105,7 @@ class WoodcuttingOverlay extends Overlay if (plugin.isShowGPEarned()) { - tableComponent.addRow("GP earned", Integer.toString((plugin.getGpEarned()))); + tableComponent.addRow("GP earned:", Integer.toString((plugin.getGpEarned()))); } if (actions > 2) From 68943b823a87c72c63bf71b20b27b273a467c93b Mon Sep 17 00:00:00 2001 From: benjaminlgur Date: Sat, 2 Nov 2019 16:48:18 -0400 Subject: [PATCH 23/72] Made requested changes --- .../woodcutting/WoodcuttingPlugin.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java index e9bd610e38..5fa67a2d65 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingPlugin.java @@ -183,8 +183,8 @@ public class WoodcuttingPlugin extends Plugin session.setLastLogCut(); - typeOfLogCut(event); - gpEarned = gpEarned + itemManager.getItemPrice(treeTypeID); + typeOfLogCut(event.getMessage()); + gpEarned += itemManager.getItemPrice(treeTypeID); } if (event.getMessage().contains("A bird's nest falls out of the tree") && this.showNestNotification) @@ -194,41 +194,41 @@ public class WoodcuttingPlugin extends Plugin } } - private void typeOfLogCut(ChatMessage event) + private void typeOfLogCut(String message) { - if (event.getMessage().contains("mushrooms.")) + if (message.contains("mushrooms.")) { return; //TO DO Add valuation for scullicep mushroom cutting. } - else if (event.getMessage().contains("oak")) + else if (message.contains("oak")) { treeTypeID = ItemID.OAK_LOGS; } - else if (event.getMessage().contains("willow")) + else if (message.contains("willow")) { treeTypeID = ItemID.WILLOW_LOGS; } - else if (event.getMessage().contains("yew")) + else if (message.contains("yew")) { treeTypeID = ItemID.YEW_LOGS; } - else if (event.getMessage().contains("redwood")) + else if (message.contains("redwood")) { treeTypeID = ItemID.REDWOOD_LOGS; } - else if (event.getMessage().contains("magic")) + else if (message.contains("magic")) { treeTypeID = ItemID.MAGIC_LOGS; } - else if (event.getMessage().contains("teak")) + else if (message.contains("teak")) { treeTypeID = ItemID.TEAK_LOGS; } - else if (event.getMessage().contains("mahogany")) + else if (message.contains("mahogany")) { treeTypeID = ItemID.MAHOGANY_LOGS; } - else if (event.getMessage().contains("maple")) + else if (message.contains("maple")) { treeTypeID = ItemID.MAPLE_LOGS; } From 796bc816ee36ac042157d70363d0ad62820f7d2c Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Wed, 30 Oct 2019 10:08:37 +0100 Subject: [PATCH 24/72] Change RS api types to the ones used in rsclient --- .../src/main/java/net/runelite/rs/api/RSClient.java | 6 +++--- .../src/main/java/net/runelite/rs/api/RSWidget.java | 2 +- .../main/java/net/runelite/rs/api/RSWorldMapElement.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index a726a2a385..c0f8542430 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -454,11 +454,11 @@ public interface RSClient extends RSGameShell, Client @Import("archive8") @Override - RSAbstractArchive getIndexSprites(); + RSArchive getIndexSprites(); @Import("archive12") @Override - RSAbstractArchive getIndexScripts(); + RSArchive getIndexScripts(); @Import("widgetClickMasks") @Override @@ -1040,7 +1040,7 @@ public interface RSClient extends RSGameShell, Client RSPcmStreamMixer getSoundEffectAudioQueue(); @Import("archive4") - RSAbstractArchive getIndexCache4(); + RSArchive getIndexCache4(); @Import("decimator") RSDecimator getSoundEffectResampler(); diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index f292e9c117..78ec802de9 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -446,7 +446,7 @@ public interface RSWidget extends Widget @Import("getFont") @Override - RSAbstractFont getFont(); + RSFont getFont(); @Import("fill") @Override diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWorldMapElement.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWorldMapElement.java index f627dd8a63..297da4c8e9 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWorldMapElement.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWorldMapElement.java @@ -5,7 +5,7 @@ import net.runelite.mapping.Import; public interface RSWorldMapElement extends RSDualNode, MapElementConfig { - @Import("getSprite") + @Import("getSpriteBool") @Override RSSprite getMapIcon(boolean var1); } From e9991bccdccac41d1c4e609b0ebfc056d7f0ec47 Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Wed, 30 Oct 2019 10:09:59 +0100 Subject: [PATCH 25/72] Change rs api package to openosrs --- runescape-api/runescape-api.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runescape-api/runescape-api.gradle.kts b/runescape-api/runescape-api.gradle.kts index 5746b30ae4..2d9532a92e 100644 --- a/runescape-api/runescape-api.gradle.kts +++ b/runescape-api/runescape-api.gradle.kts @@ -23,7 +23,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -group = "us.runelitepl.rs" +group = "com.openosrs.rs" description = "RuneScape API" dependencies { From c84f0d5b10c2caf0cf7ea288a07e1ce0f97c6bcc Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Wed, 30 Oct 2019 10:13:08 +0100 Subject: [PATCH 26/72] Add annotations dep to deob --- deobfuscator/deobfuscator.gradle.kts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/deobfuscator/deobfuscator.gradle.kts b/deobfuscator/deobfuscator.gradle.kts index c818fa5808..a307aa9b04 100644 --- a/deobfuscator/deobfuscator.gradle.kts +++ b/deobfuscator/deobfuscator.gradle.kts @@ -35,11 +35,12 @@ dependencies { deobjars(group = "net.runelite.rs", name = "vanilla", version = ProjectVersions.rsversion.toString()) deobjars(project(":runescape-client")) - implementation(Libraries.gson) - implementation(Libraries.guava) - implementation(Libraries.fernflower) + implementation(Libraries.annotations) implementation(Libraries.asmAll) implementation(Libraries.asmUtil) + implementation(Libraries.fernflower) + implementation(Libraries.gson) + implementation(Libraries.guava) implementation(Libraries.slf4jApi) implementation(project(":runelite-api")) implementation(project(":runescape-api")) From f93984a743cb8c3a8870513675807867d72c727f Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Wed, 30 Oct 2019 10:30:37 +0100 Subject: [PATCH 27/72] Deob changes for injector and general usability --- .../main/java/net/runelite/asm/Annotated.java | 17 +++++ .../main/java/net/runelite/asm/ClassFile.java | 8 +-- .../java/net/runelite/asm/ClassGroup.java | 18 ++++- .../src/main/java/net/runelite/asm/Field.java | 9 +-- .../java/net/runelite/asm/Interfaces.java | 10 ++- .../main/java/net/runelite/asm/Method.java | 6 +- .../src/main/java/net/runelite/asm/Named.java | 6 ++ .../runelite/asm/attributes/Annotations.java | 27 +++++--- .../net/runelite/asm/attributes/Code.java | 19 +++--- .../asm/attributes/annotation/Annotation.java | 61 +++++++++++------ .../attributes/annotation/ArrayElement.java | 42 ++++++++++++ .../asm/attributes/annotation/Element.java | 57 +++++++++++----- .../attributes/annotation/SimpleElement.java | 15 ++++ .../asm/attributes/code/Instructions.java | 26 ++++++- ...tor.java => AnnotationElementVisitor.java} | 59 ++++++++++------ .../asm/visitors/ClassAnnotationVisitor.java | 68 ------------------- .../asm/visitors/ClassFieldVisitor.java | 24 +++---- .../asm/visitors/ClassFileVisitor.java | 9 ++- .../runelite/asm/visitors/CodeVisitor.java | 14 ++-- .../asm/visitors/FieldAnnotationVisitor.java | 68 ------------------- .../net/runelite/deob/DeobAnnotations.java | 2 +- .../runelite/deob/deobfuscators/Renamer.java | 1 + .../constparam/ConstantParameter.java | 10 ++- .../mapping/AnnotationMapper.java | 15 ++-- .../deob/updater/AnnotationAdder.java | 23 +++---- .../deob/updater/AnnotationCopier.java | 10 ++- .../deob/updater/AnnotationRenamer.java | 4 -- .../java/net/runelite/deob/util/JarUtil.java | 37 ++++++++++ .../java/net/runelite/osb/HookImporter.java | 5 +- 29 files changed, 365 insertions(+), 305 deletions(-) create mode 100644 deobfuscator/src/main/java/net/runelite/asm/Annotated.java create mode 100644 deobfuscator/src/main/java/net/runelite/asm/Named.java create mode 100644 deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java create mode 100644 deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java rename deobfuscator/src/main/java/net/runelite/asm/visitors/{MethodAnnotationVisitor.java => AnnotationElementVisitor.java} (62%) delete mode 100644 deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java delete mode 100644 deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java diff --git a/deobfuscator/src/main/java/net/runelite/asm/Annotated.java b/deobfuscator/src/main/java/net/runelite/asm/Annotated.java new file mode 100644 index 0000000000..4645fa23a2 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/Annotated.java @@ -0,0 +1,17 @@ +package net.runelite.asm; + +import java.util.Iterator; +import net.runelite.asm.attributes.Annotations; +import net.runelite.asm.attributes.annotation.Annotation; +import org.jetbrains.annotations.NotNull; + +public interface Annotated extends Iterable +{ + Annotations getAnnotations(); + + @NotNull + default Iterator iterator() + { + return getAnnotations().iterator(); + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java index a5f3a6ecb6..fd2ba5a40a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassFile.java @@ -31,13 +31,12 @@ import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.pool.Class; import net.runelite.asm.signature.Signature; import static net.runelite.deob.DeobAnnotations.*; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; -public class ClassFile +public class ClassFile implements Annotated, Named { private ClassGroup group; @@ -100,10 +99,9 @@ public class ClassFile visitor.visit(version, access, name.getName(), null, super_class.getName(), ints); visitor.visitSource(source, null); - for (Annotation annotation : annotations.getAnnotations()) + for (Annotation annotation : annotations) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } for (Field field : fields) diff --git a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java index 33ab161acc..fabde88742 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java +++ b/deobfuscator/src/main/java/net/runelite/asm/ClassGroup.java @@ -27,13 +27,16 @@ package net.runelite.asm; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import net.runelite.asm.attributes.Code; import net.runelite.asm.signature.Signature; import static net.runelite.deob.DeobAnnotations.*; +import org.jetbrains.annotations.NotNull; -public class ClassGroup +public class ClassGroup implements Iterable { private final List classes = new ArrayList<>(); // to keep order private final Map classMap = new HashMap<>(); @@ -156,4 +159,17 @@ public class ClassGroup return findClass(name); } + + @NotNull + @Override + public Iterator iterator() + { + return this.classes.iterator(); + } + + @Override + public void forEach(Consumer action) + { + this.classes.forEach(action); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/Field.java b/deobfuscator/src/main/java/net/runelite/asm/Field.java index 39590b021c..1a9fd7a776 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Field.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Field.java @@ -27,15 +27,13 @@ package net.runelite.asm; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.deob.DeobAnnotations; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Opcodes; - import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PROTECTED; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -public class Field +public class Field implements Annotated, Named { public static final int ACCESS_MODIFIERS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; @@ -53,15 +51,14 @@ public class Field this.name = name; this.type = type; - annotations = new Annotations(); + this.annotations = new Annotations(); } public void accept(FieldVisitor visitor) { for (Annotation annotation : annotations.getAnnotations()) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } visitor.visitEnd(); diff --git a/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java b/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java index f5994ad1d3..9bc15d5100 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Interfaces.java @@ -25,12 +25,14 @@ package net.runelite.asm; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import net.runelite.asm.pool.Class; import net.runelite.deob.DeobAnnotations; +import org.jetbrains.annotations.NotNull; -public class Interfaces +public class Interfaces implements Iterable { private final ClassFile classFile; @@ -107,4 +109,10 @@ public class Interfaces return names; } + + @NotNull + public Iterator iterator() + { + return this.interfaces.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/Method.java b/deobfuscator/src/main/java/net/runelite/asm/Method.java index ad7394c7be..b13e98aa3f 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/Method.java +++ b/deobfuscator/src/main/java/net/runelite/asm/Method.java @@ -36,7 +36,6 @@ import net.runelite.asm.attributes.code.Parameter; import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; import net.runelite.asm.signature.Signature; import net.runelite.deob.DeobAnnotations; -import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import static org.objectweb.asm.Opcodes.ACC_FINAL; @@ -47,7 +46,7 @@ import static org.objectweb.asm.Opcodes.ACC_PUBLIC; import static org.objectweb.asm.Opcodes.ACC_STATIC; import static org.objectweb.asm.Opcodes.ACC_SYNCHRONIZED; -public class Method +public class Method implements Annotated, Named { public static final int ACCESS_MODIFIERS = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED; @@ -92,8 +91,7 @@ public class Method for (Annotation annotation : annotations.getAnnotations()) { - AnnotationVisitor av = visitor.visitAnnotation(annotation.getType().toString(), true); - annotation.accept(av); + annotation.accept(visitor.visitAnnotation(annotation.getType().toString(), true)); } if (code != null) diff --git a/deobfuscator/src/main/java/net/runelite/asm/Named.java b/deobfuscator/src/main/java/net/runelite/asm/Named.java new file mode 100644 index 0000000000..ec2bc0b6a9 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/Named.java @@ -0,0 +1,6 @@ +package net.runelite.asm; + +public interface Named +{ + String getName(); +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java index b14d761c28..7c1a6ba535 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/Annotations.java @@ -26,13 +26,16 @@ package net.runelite.asm.attributes; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import net.runelite.asm.Type; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; +import org.jetbrains.annotations.NotNull; -public class Annotations +public class Annotations implements Iterable { private final List annotations = new ArrayList<>(); @@ -40,7 +43,7 @@ public class Annotations { return annotations; } - + public void addAnnotation(Annotation annotation) { annotations.add(annotation); @@ -55,7 +58,7 @@ public class Annotations { annotations.clear(); } - + public Annotation find(Type type) { for (Annotation a : annotations) @@ -68,18 +71,22 @@ public class Annotations { return annotations.size(); } - + public Annotation addAnnotation(Type type, String name, Object value) { - Annotation annotation = new Annotation(this); - annotation.setType(type); + Annotation annotation = new Annotation(type); addAnnotation(annotation); - - Element element = new Element(annotation); - element.setName(name); - element.setValue(value); + + Element element = new SimpleElement(name, value); annotation.addElement(element); return annotation; } + + @NotNull + @Override + public Iterator iterator() + { + return this.annotations.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java index b20c183fea..58c759844a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/Code.java @@ -41,11 +41,11 @@ public class Code private int maxStack; private Instructions instructions; private final Exceptions exceptions; - + public Code(Method method) { this.method = method; - + exceptions = new Exceptions(this); instructions = new Instructions(this); } @@ -59,12 +59,12 @@ public class Code { return maxStack; } - + public void setMaxStack(int maxStack) { this.maxStack = maxStack; } - + private int getMaxLocalsFromSig() { Method m = getMethod(); @@ -77,12 +77,11 @@ public class Code /** * calculates the size of the lvt required for this method - * @return */ public int getMaxLocals() { int max = -1; - + for (Instruction ins : instructions.getInstructions()) { if (ins instanceof LVTInstruction) @@ -96,19 +95,19 @@ public class Code } } } - + int fromSig = getMaxLocalsFromSig(); if (fromSig > max) max = fromSig; - + return max; } - + public Exceptions getExceptions() { return exceptions; } - + public Instructions getInstructions() { return instructions; diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java index 7c727eb788..6f3a459eb3 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Annotation.java @@ -26,30 +26,26 @@ package net.runelite.asm.attributes.annotation; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; - import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; +import org.jetbrains.annotations.NotNull; import org.objectweb.asm.AnnotationVisitor; -public class Annotation +public class Annotation extends Element> implements Iterable { - private final Annotations annotations; - private Type type; - private final List elements = new ArrayList<>(); + private final Type type; - public Annotation(Annotations annotations) + public Annotation(Type type) { - this.annotations = annotations; + this.value = new ArrayList<>(); + this.type = type; } - public Annotations getAnnotations() - { - return annotations; - } - - public void setType(Type type) + public Annotation(String name, Type type) { + this.value = new ArrayList<>(); + this.name = name; this.type = type; } @@ -60,23 +56,44 @@ public class Annotation public List getElements() { - return elements; + return value; } - + public Element getElement() { - return elements.get(0); + return value.get(0); } - + public void addElement(Element element) { - elements.add(element); + value.add(element); } - + + @Override + public final void setValue(List value) + { + throw new UnsupportedOperationException(); + } + public void accept(AnnotationVisitor visitor) { - for (Element element : elements) - visitor.visit(element.getName(), element.getValue()); + if (visitor == null) + { + return; + } + + for (Element element : this) + { + accept(visitor, element.name, element.value); + } + visitor.visitEnd(); } + + @NotNull + @Override + public Iterator iterator() + { + return this.value.iterator(); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java new file mode 100644 index 0000000000..b7e2b7ef84 --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/ArrayElement.java @@ -0,0 +1,42 @@ +package net.runelite.asm.attributes.annotation; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Stream; +import org.jetbrains.annotations.NotNull; + +public class ArrayElement extends Element implements Iterable +{ + public ArrayElement(String name) + { + this.name = name; + this.value = new ArrayList<>(); + } + + @SuppressWarnings("unchecked") + public void addValue(Object value) + { + this.value.add(value); + } + + @Override + public final void setValue(List value) + { + throw new UnsupportedOperationException(); + } + + @NotNull + @Override + @SuppressWarnings("unchecked") + public Iterator iterator() + { + return this.value.iterator(); + } + + @SuppressWarnings("unchecked") + public Stream stream() + { + return this.value.stream(); + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java index 18fdfa33f4..10b59b5b27 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/Element.java @@ -25,21 +25,14 @@ package net.runelite.asm.attributes.annotation; -public class Element -{ - private final Annotation annotation; - private String name; - private Object value; - - public Element(Annotation annotation) - { - this.annotation = annotation; - } +import java.util.List; +import org.objectweb.asm.AnnotationVisitor; - public Annotation getAnnotation() - { - return annotation; - } +public abstract class Element +{ + String name = "value"; + + T value; public String getName() { @@ -51,18 +44,48 @@ public class Element this.name = name; } - public Object getValue() + public T getValue() { return value; } - public void setValue(Object value) + public void setValue(T value) { this.value = value; } - + public String getString() { return value.toString(); } + + public static void accept(AnnotationVisitor visitor, final String name, final Object value) + { + if (visitor == null) + { + return; + } + + if (value instanceof Annotation) + { + Annotation annotation = (Annotation) value; + annotation.accept(visitor.visitAnnotation(name, annotation.getType().toString())); + } + else if (value instanceof List) + { + AnnotationVisitor arr = visitor.visitArray(name); + List arrayValue = (List) value; + + for (Object o : arrayValue) + { + accept(arr, null, o); + } + + arr.visitEnd(); + } + else + { + visitor.visit(name, value); + } + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java new file mode 100644 index 0000000000..52e25e295c --- /dev/null +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/annotation/SimpleElement.java @@ -0,0 +1,15 @@ +package net.runelite.asm.attributes.annotation; + +public class SimpleElement extends Element +{ + public SimpleElement(Object value) + { + this.value = value; + } + + public SimpleElement(String name, Object value) + { + this.name = name; + this.value = value; + } +} diff --git a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java index a528950d0a..212c168998 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java +++ b/deobfuscator/src/main/java/net/runelite/asm/attributes/code/Instructions.java @@ -26,11 +26,14 @@ package net.runelite.asm.attributes.code; import java.util.ArrayList; import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import java.util.Map; import net.runelite.asm.attributes.Code; +import org.jetbrains.annotations.NotNull; -public class Instructions +public class Instructions implements Iterable { private final Code code; private final List instructions = new ArrayList<>(); @@ -186,4 +189,25 @@ public class Instructions return i; } + + public int size() + { + return this.instructions.size(); + } + + @NotNull + public Iterator iterator() + { + return this.instructions.iterator(); + } + + public ListIterator listIterator() + { + return this.instructions.listIterator(); + } + + public ListIterator listIterator(int i) + { + return this.instructions.listIterator(i); + } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java similarity index 62% rename from deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java rename to deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java index bcce61aedd..7bd5811813 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/MethodAnnotationVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/AnnotationElementVisitor.java @@ -25,44 +25,59 @@ package net.runelite.asm.visitors; -import net.runelite.asm.Method; import net.runelite.asm.Type; import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.ArrayElement; +import net.runelite.asm.attributes.annotation.SimpleElement; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Opcodes; -public class MethodAnnotationVisitor extends AnnotationVisitor +public class AnnotationElementVisitor extends AnnotationVisitor { - private final Method method; - private final Type type; private final Annotation annotation; - - public MethodAnnotationVisitor(Method method, Type type) + + AnnotationElementVisitor(Annotation annotation) { super(Opcodes.ASM5); - - this.method = method; - this.type = type; - - annotation = new Annotation(method.getAnnotations()); - annotation.setType(type); + + this.annotation = annotation; } - + @Override public void visit(String name, Object value) { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - + SimpleElement element = new SimpleElement(name, value); annotation.addElement(element); } - + @Override - public void visitEnd() + public AnnotationVisitor visitArray(String name) { - method.getAnnotations().addAnnotation(annotation); + ArrayElement element = new ArrayElement(name); + this.annotation.addElement(element); + return new AnnotationVisitor(Opcodes.ASM5) + { + @Override + public void visit(String name, Object value) + { + element.addValue(value); + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String descriptor) + { + Annotation annotation = new Annotation(name, new Type(descriptor)); + element.addValue(annotation); + return new AnnotationElementVisitor(annotation); + } + }; + } + + @Override + public AnnotationVisitor visitAnnotation(String name, String descriptor) + { + Annotation annotation = new Annotation(name, new Type(descriptor)); + this.annotation.addElement(annotation); + return new AnnotationElementVisitor(annotation); } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java deleted file mode 100644 index f9f62fc82a..0000000000 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassAnnotationVisitor.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.runelite.asm.visitors; - -import net.runelite.asm.ClassFile; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Opcodes; - -public class ClassAnnotationVisitor extends AnnotationVisitor -{ - private final ClassFile classFile; - private final Type type; - private final Annotation annotation; - - public ClassAnnotationVisitor(ClassFile classFile, Type type) - { - super(Opcodes.ASM5); - - this.classFile = classFile; - this.type = type; - - annotation = new Annotation(classFile.getAnnotations()); - annotation.setType(type); - } - - @Override - public void visit(String name, Object value) - { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - - annotation.addElement(element); - } - - @Override - public void visitEnd() - { - classFile.getAnnotations().addAnnotation(annotation); - } -} diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java index 37478d26e3..c9012b162c 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFieldVisitor.java @@ -22,12 +22,12 @@ * (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.asm.visitors; import net.runelite.asm.ClassFile; import net.runelite.asm.Field; import net.runelite.asm.Type; +import net.runelite.asm.attributes.annotation.Annotation; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.Attribute; import org.objectweb.asm.FieldVisitor; @@ -35,25 +35,25 @@ import org.objectweb.asm.Opcodes; public class ClassFieldVisitor extends FieldVisitor { - private final ClassFile classFile; private final Field field; - public ClassFieldVisitor(ClassFile cf, int access, String name, Type desc, Object value) + ClassFieldVisitor(ClassFile cf, int access, String name, Type desc, Object value) { super(Opcodes.ASM5); - this.classFile = cf; + this.field = new Field(cf, name, desc); + this.field.setAccessFlags(access); + this.field.setValue(value); - field = new Field(cf, name, desc); - field.setAccessFlags(access); - field.setValue(value); + cf.addField(field); } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new FieldAnnotationVisitor(field, type); + Annotation element = new Annotation(new Type(desc)); + this.field.getAnnotations().addAnnotation(element); + return new AnnotationElementVisitor(element); } @Override @@ -61,10 +61,4 @@ public class ClassFieldVisitor extends FieldVisitor { System.out.println(attr); } - - @Override - public void visitEnd() - { - classFile.addField(field); - } } diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java index abaf4e919d..d96ec550b1 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/ClassFileVisitor.java @@ -27,6 +27,7 @@ package net.runelite.asm.visitors; import net.runelite.asm.ClassFile; import net.runelite.asm.Type; +import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.signature.Signature; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; @@ -55,7 +56,7 @@ public class ClassFileVisitor extends ClassVisitor classFile.setSuperName(superName); classFile.setVersion(version); classFile.setAccess(access); - + for (String inter : interfaces) classFile.getInterfaces().addInterface(new net.runelite.asm.pool.Class(inter)); } @@ -69,8 +70,10 @@ public class ClassFileVisitor extends ClassVisitor @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new ClassAnnotationVisitor(classFile, type); + Annotation annotation = new Annotation(new Type(desc)); + classFile.getAnnotations().addAnnotation(annotation); + + return new AnnotationElementVisitor(annotation); } @Override diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java index d01873b83b..7746cd7a7a 100644 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java +++ b/deobfuscator/src/main/java/net/runelite/asm/visitors/CodeVisitor.java @@ -32,6 +32,7 @@ import net.runelite.asm.ClassFile; import net.runelite.asm.Method; import net.runelite.asm.Type; import net.runelite.asm.attributes.Code; +import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.code.Exceptions; import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.InstructionType; @@ -72,18 +73,14 @@ import static org.objectweb.asm.Opcodes.ICONST_5; import static org.objectweb.asm.Opcodes.ICONST_M1; import static org.objectweb.asm.Opcodes.LCONST_0; import static org.objectweb.asm.Opcodes.LCONST_1; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class CodeVisitor extends MethodVisitor { - private static final Logger logger = LoggerFactory.getLogger(CodeVisitor.class); - private final ClassFile classFile; private final Method method; private Code code; - public CodeVisitor(ClassFile classFile, int access, String name, Signature signature, String[] sexceptions) + CodeVisitor(ClassFile classFile, int access, String name, Signature signature, String[] sexceptions) { super(Opcodes.ASM5); @@ -111,8 +108,9 @@ public class CodeVisitor extends MethodVisitor @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - Type type = new Type(desc); - return new MethodAnnotationVisitor(method, type); + Annotation element = new Annotation(new Type(desc)); + this.method.getAnnotations().addAnnotation(element); + return new AnnotationElementVisitor(element); } @Override @@ -333,7 +331,7 @@ public class CodeVisitor extends MethodVisitor if (cst instanceof org.objectweb.asm.Type) { org.objectweb.asm.Type t = (org.objectweb.asm.Type) cst; - entry = new net.runelite.asm.pool.Class((String) t.getClassName()); + entry = new net.runelite.asm.pool.Class(t.getClassName()); } LDC ldc = new LDC(code.getInstructions(), entry); diff --git a/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java b/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java deleted file mode 100644 index 962328f272..0000000000 --- a/deobfuscator/src/main/java/net/runelite/asm/visitors/FieldAnnotationVisitor.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package net.runelite.asm.visitors; - -import net.runelite.asm.Field; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.annotation.Element; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Opcodes; - -public class FieldAnnotationVisitor extends AnnotationVisitor -{ - private final Field field; - private final Type type; - private final Annotation annotation; - - public FieldAnnotationVisitor(Field field, Type type) - { - super(Opcodes.ASM5); - - this.field = field; - this.type = type; - - annotation = new Annotation(field.getAnnotations()); - annotation.setType(type); - } - - @Override - public void visit(String name, Object value) - { - Element element = new Element(annotation); - - element.setName(name); - element.setValue(value); - - annotation.addElement(element); - } - - @Override - public void visitEnd() - { - field.getAnnotations().addAnnotation(annotation); - } -} diff --git a/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java b/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java index 2881148caa..6294574e74 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java +++ b/deobfuscator/src/main/java/net/runelite/deob/DeobAnnotations.java @@ -95,7 +95,7 @@ public class DeobAnnotations { return null; } - + return (Number) an.getElement().getValue(); } diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java index 418802ef5a..588b840918 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/Renamer.java @@ -193,6 +193,7 @@ public class Renamer implements Deobfuscator } @Override + @SuppressWarnings("unchecked") public void run(ClassGroup group) { group.buildClassGraph(); diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java index 0970a9b3e1..b2a0c369b3 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/constparam/ConstantParameter.java @@ -37,6 +37,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.asm.attributes.code.Instruction; import net.runelite.asm.attributes.code.InstructionType; import net.runelite.asm.attributes.code.Instructions; @@ -113,7 +114,6 @@ public class ConstantParameter implements Deobfuscator List pops = invokeCtx.getPops(); - outer: // object is popped first, then param 1, 2, 3, etc. double and long take two slots. for (int lvtOffset = offset, parameterIndex = 0; parameterIndex < method.getDescriptor().size(); @@ -451,9 +451,7 @@ public class ConstantParameter implements Deobfuscator } // Add garbage value - Element element = new Element(obfuscatedSignature); - element.setName("garbageValue"); - element.setValue(value.toString()); + Element element = new SimpleElement("garbageValue", value.toString()); obfuscatedSignature.addElement(element); } } @@ -464,12 +462,12 @@ public class ConstantParameter implements Deobfuscator public void run(ClassGroup group) { Execution execution = new Execution(group); - execution.addExecutionVisitor(i -> findParameters(i)); + execution.addExecutionVisitor(this::findParameters); execution.populateInitialMethods(); execution.run(); execution = new Execution(group); - execution.addMethodContextVisitor(mc -> findDeadParameters(mc)); + execution.addMethodContextVisitor(this::findDeadParameters); execution.populateInitialMethods(); execution.run(); diff --git a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java index 87e01ac4ae..bd60ec165e 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java +++ b/deobfuscator/src/main/java/net/runelite/deob/deobfuscators/mapping/AnnotationMapper.java @@ -32,6 +32,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.deob.DeobAnnotations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,7 +40,7 @@ import org.slf4j.LoggerFactory; public class AnnotationMapper { private static final Logger logger = LoggerFactory.getLogger(AnnotationMapper.class); - + private final ClassGroup source, target; private final ParallelExecutorMapping mapping; @@ -119,20 +120,17 @@ public class AnnotationMapper if (from.getAnnotations() == null) return count; - + for (Annotation a : from.getAnnotations()) { if (isCopyable(a)) { - Annotation annotation = new Annotation(to); - annotation.setType(a.getType()); + Annotation annotation = new Annotation(a.getType()); to.addAnnotation(annotation); for (Element e : a.getElements()) { - Element element = new Element(annotation); - element.setName(e.getName()); - element.setValue(e.getValue()); + Element element = new SimpleElement(e.getName(), e.getValue()); annotation.addElement(element); } @@ -155,7 +153,6 @@ public class AnnotationMapper private boolean isCopyable(Annotation a) { return a.getType().equals(DeobAnnotations.EXPORT) - || a.getType().equals(DeobAnnotations.IMPLEMENTS) - || a.getType().equals(DeobAnnotations.HOOK); + || a.getType().equals(DeobAnnotations.IMPLEMENTS); } } diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java index a01628d863..d2c3d62034 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationAdder.java @@ -8,6 +8,7 @@ import net.runelite.asm.Method; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; import net.runelite.deob.Deob; import net.runelite.deob.DeobAnnotations; import org.slf4j.Logger; @@ -23,6 +24,7 @@ public class AnnotationAdder private final ClassGroup group; private final Logger log = LoggerFactory.getLogger(AnnotationAdder.class); + @SuppressWarnings("unchecked") public void run() { int impl = 0; @@ -50,12 +52,9 @@ public class AnnotationAdder { Annotations an = c.getAnnotations(); - Annotation implAn = new Annotation(an); - implAn.setType(DeobAnnotations.IMPLEMENTS); + Annotation implAn = new Annotation(DeobAnnotations.IMPLEMENTS); - Element value = new Element(implAn); - value.setValue(c.getClassName()); - value.setName("value"); + Element value = new SimpleElement(c.getClassName()); implAn.addElement(value); an.addAnnotation(implAn); @@ -81,12 +80,9 @@ public class AnnotationAdder Annotation a = an.find(DeobAnnotations.EXPORT); if (a == null) { - a = new Annotation(an); - a.setType(DeobAnnotations.EXPORT); + a = new Annotation(DeobAnnotations.EXPORT); - Element value = new Element(a); - value.setValue(fieldName); - value.setName("value"); + Element value = new SimpleElement(fieldName); a.addElement(value); an.addAnnotation(a); @@ -114,12 +110,9 @@ public class AnnotationAdder Annotation a = an.find(DeobAnnotations.EXPORT); if (a == null) { - a = new Annotation(an); - a.setType(DeobAnnotations.EXPORT); + a = new Annotation(DeobAnnotations.EXPORT); - Element value = new Element(a); - value.setValue(methodName); - value.setName("value"); + Element value = new SimpleElement(methodName); a.addElement(value); an.addAnnotation(a); diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java index 0c594cfe19..5d495b9029 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationCopier.java @@ -34,6 +34,7 @@ import net.runelite.asm.Type; import net.runelite.asm.attributes.Annotations; import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.asm.attributes.annotation.Element; +import net.runelite.asm.attributes.annotation.SimpleElement; public class AnnotationCopier { @@ -97,15 +98,12 @@ public class AnnotationCopier { if (!isType(a.getType())) continue; - - Annotation a2 = new Annotation(an2); - a2.setType(a.getType()); + + Annotation a2 = new Annotation(a.getType()); for (Element element : a.getElements()) { - Element element2 = new Element(a2); - element2.setName(element.getName()); - element2.setValue(element.getValue()); + Element element2 = new SimpleElement(element.getName(), element.getValue()); a2.addElement(element2); } diff --git a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java index 7d0f2f03d2..da920899bc 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java +++ b/deobfuscator/src/main/java/net/runelite/deob/updater/AnnotationRenamer.java @@ -34,13 +34,9 @@ import net.runelite.asm.attributes.annotation.Annotation; import net.runelite.deob.DeobAnnotations; import net.runelite.deob.deobfuscators.Renamer; import net.runelite.deob.util.NameMappings; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; public class AnnotationRenamer { - private static final Logger logger = LoggerFactory.getLogger(AnnotationRenamer.class); - private ClassGroup group; public AnnotationRenamer(ClassGroup group) diff --git a/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java b/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java index 1b0435d3d0..67364468c0 100644 --- a/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java +++ b/deobfuscator/src/main/java/net/runelite/deob/util/JarUtil.java @@ -25,9 +25,11 @@ package net.runelite.deob.util; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -79,6 +81,41 @@ public class JarUtil return group; } + public static ClassFile loadClass(byte[] bytes) + { + ClassReader reader = new ClassReader(bytes); + ClassFileVisitor cv = new ClassFileVisitor(); + reader.accept(cv, ClassReader.SKIP_FRAMES); + return cv.getClassFile(); + } + + public static ClassGroup loadClasses(Collection files) throws IOException + { + final ClassGroup group = new ClassGroup(); + + for (File file : files) + { + if (!file.getName().endsWith(".class")) + { + continue; + } + + try (InputStream is = new FileInputStream(file)) + { + ClassReader reader = new ClassReader(is); + ClassFileVisitor cv = new ClassFileVisitor(); + + reader.accept(cv, ClassReader.SKIP_FRAMES); + + group.addClass(cv.getClassFile()); + } + } + + group.initialize(); + + return group; + } + public static void saveJar(ClassGroup group, File jarfile) throws IOException { try (JarOutputStream jout = new JarOutputStream(new FileOutputStream(jarfile), new Manifest())) diff --git a/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java b/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java index bf8e2bed2b..dbb17bfe55 100644 --- a/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java +++ b/deobfuscator/src/test/java/net/runelite/osb/HookImporter.java @@ -276,8 +276,7 @@ public class HookImporter { for (Element e : a.getElements()) { - String str = (String) e.getValue(); - return str; + return (String) e.getValue(); } } } @@ -288,7 +287,7 @@ public class HookImporter private Signature getObfuscatedMethodSignature(Method method) { String sig = getAnnotation(method.getAnnotations(), OBFUSCATED_SIGNATURE); - if (sig.isEmpty() == false) + if (!sig.isEmpty()) { return toObSignature(new Signature(sig)); // if it is annoted, use that } From 3b36541b30060738348ea858952dab9faeaaa763 Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Wed, 30 Oct 2019 10:31:44 +0100 Subject: [PATCH 28/72] Remove duplicate api annotations --- .../java/net/runelite/mapping/Export.java | 40 ------------------- .../java/net/runelite/mapping/Import.java | 40 ------------------- .../runelite/mapping/ObfuscatedGetter.java | 39 ------------------ .../java/net/runelite/mapping/Protect.java | 40 ------------------- 4 files changed, 159 deletions(-) delete mode 100644 runelite-api/src/main/java/net/runelite/mapping/Export.java delete mode 100644 runelite-api/src/main/java/net/runelite/mapping/Import.java delete mode 100644 runelite-api/src/main/java/net/runelite/mapping/ObfuscatedGetter.java delete mode 100644 runelite-api/src/main/java/net/runelite/mapping/Protect.java diff --git a/runelite-api/src/main/java/net/runelite/mapping/Export.java b/runelite-api/src/main/java/net/runelite/mapping/Export.java deleted file mode 100644 index cd789618cd..0000000000 --- a/runelite-api/src/main/java/net/runelite/mapping/Export.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.mapping; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target( -{ - ElementType.FIELD, ElementType.METHOD -}) -public @interface Export -{ - String value(); -} diff --git a/runelite-api/src/main/java/net/runelite/mapping/Import.java b/runelite-api/src/main/java/net/runelite/mapping/Import.java deleted file mode 100644 index 97e4e81d7f..0000000000 --- a/runelite-api/src/main/java/net/runelite/mapping/Import.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.mapping; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target( -{ - ElementType.FIELD, ElementType.METHOD -}) -public @interface Import -{ - String value(); -} diff --git a/runelite-api/src/main/java/net/runelite/mapping/ObfuscatedGetter.java b/runelite-api/src/main/java/net/runelite/mapping/ObfuscatedGetter.java deleted file mode 100644 index b8e2873006..0000000000 --- a/runelite-api/src/main/java/net/runelite/mapping/ObfuscatedGetter.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.mapping; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.FIELD) -public @interface ObfuscatedGetter -{ - int intValue() default 0; - - long longValue() default 0L; -} diff --git a/runelite-api/src/main/java/net/runelite/mapping/Protect.java b/runelite-api/src/main/java/net/runelite/mapping/Protect.java deleted file mode 100644 index a5c780a94d..0000000000 --- a/runelite-api/src/main/java/net/runelite/mapping/Protect.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.mapping; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Used to indicate a method can only be called from within mixins. - * Calling methods annotated with this annotation outside mixins results in a AbstractMethodError. - * Only works in net.runelite.rs.api.* - */ -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Protect -{ -} From e0142c7f77f08d1672788b807cd06ecd5643051d Mon Sep 17 00:00:00 2001 From: Lucwousin Date: Thu, 31 Oct 2019 01:00:10 +0100 Subject: [PATCH 29/72] Remove injector plugin --- injector-plugin/injector-plugin.gradle.kts | 83 -- .../java/net/runelite/injector/Inject.java | 580 ---------- .../runelite/injector/InjectConstruct.java | 171 --- .../net/runelite/injector/InjectGetter.java | 155 --- .../net/runelite/injector/InjectHook.java | 396 ------- .../runelite/injector/InjectHookMethod.java | 255 ----- .../net/runelite/injector/InjectInvoker.java | 291 ----- .../net/runelite/injector/InjectMojo.java | 152 --- .../net/runelite/injector/InjectSetter.java | 158 --- .../net/runelite/injector/InjectUtil.java | 281 ----- .../runelite/injector/InjectionException.java | 44 - .../java/net/runelite/injector/Injector.java | 85 -- .../runelite/injector/InjectorValidator.java | 196 ---- .../net/runelite/injector/MixinInjector.java | 998 ------------------ .../injector/raw/ClearColorBuffer.java | 124 --- .../injector/raw/DrawAfterWidgets.java | 264 ----- .../net/runelite/injector/raw/DrawMenu.java | 135 --- .../injector/raw/HidePlayerAttacks.java | 202 ---- .../net/runelite/injector/raw/Occluder.java | 83 -- .../net/runelite/injector/raw/RenderDraw.java | 86 -- .../net/runelite/injector/raw/ScriptVM.java | 306 ------ .../injector/InjectConstructTest.java | 63 -- .../runelite/injector/InjectSetterTest.java | 116 -- .../net/runelite/injector/InjectTest.java | 74 -- .../runelite/injector/MixinInjectorTest.java | 267 ----- .../injector/raw/DrawAfterWidgetsTest.java | 80 -- .../drawafterwidgets/Client_deob153.class | Bin 103334 -> 0 bytes .../drawafterwidgets/Client_deob160.class | Bin 126443 -> 0 bytes .../drawafterwidgets/Client_deob180.class | Bin 119603 -> 0 bytes .../drawafterwidgets/Client_ob153.class | Bin 645897 -> 0 bytes .../drawafterwidgets/Client_ob160.class | Bin 691407 -> 0 bytes .../drawafterwidgets/Client_ob180.class | Bin 705642 -> 0 bytes .../Rasterizer2D_deob153.class | Bin 16462 -> 0 bytes .../Rasterizer2D_deob160.class | Bin 16628 -> 0 bytes .../Rasterizer2D_deob180.class | Bin 13344 -> 0 bytes .../drawafterwidgets/Rasterizer2D_ob153.class | Bin 52056 -> 0 bytes .../drawafterwidgets/Rasterizer2D_ob160.class | Bin 50268 -> 0 bytes .../drawafterwidgets/Rasterizer2D_ob180.class | Bin 43336 -> 0 bytes runelite-client/runelite-client.gradle.kts | 2 - 39 files changed, 5647 deletions(-) delete mode 100644 injector-plugin/injector-plugin.gradle.kts delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/Inject.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectHook.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectionException.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/Injector.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/DrawMenu.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/HidePlayerAttacks.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/Occluder.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/RenderDraw.java delete mode 100644 injector-plugin/src/main/java/net/runelite/injector/raw/ScriptVM.java delete mode 100644 injector-plugin/src/test/java/net/runelite/injector/InjectConstructTest.java delete mode 100644 injector-plugin/src/test/java/net/runelite/injector/InjectSetterTest.java delete mode 100644 injector-plugin/src/test/java/net/runelite/injector/InjectTest.java delete mode 100644 injector-plugin/src/test/java/net/runelite/injector/MixinInjectorTest.java delete mode 100644 injector-plugin/src/test/java/net/runelite/injector/raw/DrawAfterWidgetsTest.java delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_deob153.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_deob160.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_deob180.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_ob153.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_ob160.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Client_ob180.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_deob153.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_deob160.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_deob180.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_ob153.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_ob160.class delete mode 100644 injector-plugin/src/test/resources/drawafterwidgets/Rasterizer2D_ob180.class diff --git a/injector-plugin/injector-plugin.gradle.kts b/injector-plugin/injector-plugin.gradle.kts deleted file mode 100644 index 97d3974575..0000000000 --- a/injector-plugin/injector-plugin.gradle.kts +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2019 Owain van Brakel - * 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. - */ - -group = "com.openosrs.rs" -description = "Injector" - -val deobfuscatedJar = "${project.extra["rootPath"]}/runescape-client/build/libs/runescape-client-${ProjectVersions.rlVersion}.jar" -val vanillaJar = "${buildDir}/vanilla-${ProjectVersions.rsversion}.jar" - -val vanilla = configurations.create("vanilla") - -dependencies { - annotationProcessor(Libraries.sisu) - - compileOnly(Libraries.mavenPluginAnnotations) - - implementation(Libraries.guava) - implementation(Libraries.mavenPluginApi) - implementation(Libraries.asmAll) - implementation(Libraries.asmUtil) - implementation(project(":deobfuscator")) - implementation(project(":runelite-mixins")) - implementation(project(":runelite-api")) - implementation(project(":runescape-api")) - - testImplementation(Libraries.junit) - testImplementation(Libraries.mockitoCore) - testImplementation(project(":deobfuscator")) - testImplementation(project(path = ":deobfuscator", configuration = "testArchives")) - - vanilla(Libraries.vanilla) -} - -tasks { - register("copyVanilla") { - copy { - from(configurations.get("vanilla")) - into("$buildDir") - } - } - - register("inject") { - dependsOn("copyVanilla") - - classpath = project.sourceSets.main.get().runtimeClasspath - main = "net.runelite.injector.Injector" - args(listOf(deobfuscatedJar, vanillaJar, project.extra["injectedClassesPath"])) - } - - compileJava { - dependsOn(":runescape-client:build") - - inputs.dir(project(":runescape-client").projectDir.absolutePath) - inputs.dir(project(":runescape-api").projectDir.absolutePath) - inputs.dir(project(":runelite-mixins").projectDir.absolutePath) - } - - jar { - dependsOn("inject") - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/Inject.java b/injector-plugin/src/main/java/net/runelite/injector/Inject.java deleted file mode 100644 index 4a87466311..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/Inject.java +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.HashMap; -import java.util.Map; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Field; -import net.runelite.asm.Interfaces; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.DLoad; -import net.runelite.asm.attributes.code.instructions.FLoad; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.LLoad; -import net.runelite.asm.pool.Class; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import net.runelite.deob.deobfuscators.arithmetic.DMath; -import static net.runelite.injector.InjectUtil.getFieldType; -import net.runelite.injector.raw.ClearColorBuffer; -import net.runelite.injector.raw.DrawAfterWidgets; -import net.runelite.injector.raw.Occluder; -import net.runelite.injector.raw.RasterizerAlpha; -import net.runelite.injector.raw.RenderDraw; -import net.runelite.injector.raw.ScriptVM; -import net.runelite.mapping.Import; -import net.runelite.rs.api.RSClient; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import net.runelite.injector.raw.HidePlayerAttacks; - -public class Inject -{ - public static final java.lang.Class CLIENT_CLASS = RSClient.class; - public static final String API_PACKAGE_BASE = "net.runelite.rs.api.RS"; - public static final String RL_API_PACKAGE_BASE = "net.runelite.api."; - private static final Logger logger = LoggerFactory.getLogger(Inject.class); - private final InjectHookMethod hookMethod = new InjectHookMethod(this); - - private final InjectGetter getters = new InjectGetter(this); - private final InjectSetter setters = new InjectSetter(this); - private final InjectInvoker invokes = new InjectInvoker(this); - private final InjectConstruct construct = new InjectConstruct(this); - - private final MixinInjector mixinInjector = new MixinInjector(this); - - // deobfuscated contains exports etc to apply to vanilla - private final ClassGroup deobfuscated, vanilla; - - public Inject(ClassGroup deobfuscated, ClassGroup vanilla) - { - this.deobfuscated = deobfuscated; - this.vanilla = vanilla; - } - - /** - * Convert a java.lang.Class to a Type - * - * @param c - * @return - */ - public static Type classToType(java.lang.Class c) - { - int dimms = 0; - while (c.isArray()) - { - c = c.getComponentType(); - ++dimms; - } - - if (c.isPrimitive()) - { - String s; - - switch (c.getName()) - { - case "int": - s = "I"; - break; - case "long": - s = "J"; - break; - case "boolean": - s = "Z"; - break; - case "char": - s = "C"; - break; - case "short": - s = "S"; - break; - case "float": - s = "F"; - break; - case "double": - s = "D"; - break; - case "byte": - s = "B"; - break; - case "void": - s = "V"; - break; - default: - throw new RuntimeException("unknown primitive type " + c.getName()); - } - - return Type.getType(s, dimms); - } - - return Type.getType("L" + c.getName().replace('.', '/') + ";", dimms); - } - - public Signature getMethodSignature(Method m) - { - Signature signature = m.getDescriptor(); - - Annotation obfSignature = m.getAnnotations().find(DeobAnnotations.OBFUSCATED_SIGNATURE); - if (obfSignature != null) - { - //Annotation exists. Signature was updated by us during deobfuscation - signature = DeobAnnotations.getObfuscatedSignature(m); - } - - return signature; - } - - /** - * Build a Signature from a java method - * - * @param method - * @return - */ - public Signature javaMethodToSignature(java.lang.reflect.Method method) - { - Signature.Builder builder = new Signature.Builder() - .setReturnType(classToType(method.getReturnType())); - for (java.lang.Class clazz : method.getParameterTypes()) - { - builder.addArgument(classToType(clazz)); - } - return builder.build(); - } - - public void run() throws InjectionException - { - Map implemented = new HashMap<>(); - - // inject interfaces first, so the validateTypeIsConvertibleTo - // check below works - for (ClassFile cf : deobfuscated.getClasses()) - { - Annotations an = cf.getAnnotations(); - - if (an == null || an.size() == 0) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - java.lang.Class implementingClass = injectInterface(cf, other); - // it can not implement an interface but still have exported static fields, which are - // moved to client - - implemented.put(cf, implementingClass); - } - - // Has to be done before mixins - // well, can be done after really - // but why do that when you can do it before - new RasterizerAlpha(this).inject(); - - // requires interfaces to be injected - mixinInjector.inject(); - construct.inject(implemented); - - for (ClassFile cf : deobfuscated.getClasses()) - { - java.lang.Class implementingClass = implemented.get(cf); - Annotations an = cf.getAnnotations(); - - if (an == null || an.size() == 0) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - for (Field f : cf.getFields()) - { - an = f.getAnnotations(); - - if (an == null || an.find(DeobAnnotations.EXPORT) == null) - { - continue; // not an exported field - } - - Annotation exportAnnotation = an.find(DeobAnnotations.EXPORT); - String exportedName = exportAnnotation.getElement().getString(); - - obfuscatedName = DeobAnnotations.getObfuscatedName(an); - - Annotation getterAnnotation = an.find(DeobAnnotations.OBFUSCATED_GETTER); - Number getter = null; - if (getterAnnotation != null) - { - getter = (Number) getterAnnotation.getElement().getValue(); - } - // the ob jar is the same as the vanilla so this field must exist in this class. - - Type obType = getFieldType(f); - Field otherf = other.findField(obfuscatedName, obType); - assert otherf != null; - - assert f.isStatic() == otherf.isStatic(); - - ClassFile targetClass = f.isStatic() ? vanilla.findClass("client") : other; // target class for getter - java.lang.Class targetApiClass = f.isStatic() ? CLIENT_CLASS : implementingClass; // target api class for getter - if (targetApiClass == null) - { - assert !f.isStatic(); - - // non static field exported on non exported interface - // logger.debug("Non static exported field {} on non exported interface", exportedName); - continue; - } - - java.lang.reflect.Method apiMethod = findImportMethodOnApi(targetApiClass, exportedName, true); - if (apiMethod != null) - { - Number setter = null; - if (getter != null) - { - setter = DMath.modInverse(getter); // inverse getter to get the setter - } - - setters.injectSetter(targetClass, targetApiClass, otherf, exportedName, setter); - } - - apiMethod = findImportMethodOnApi(targetApiClass, exportedName, false); - if (apiMethod == null) - { - //logger.debug("Unable to find import method on api class {} with imported name {}, not injecting getter", targetApiClass, exportedName); - continue; - } - - // check that otherf is converable to apiMethod's - // return type - Type fieldType = otherf.getType(); - Type returnType = classToType(apiMethod.getReturnType()); - if (!validateTypeIsConvertibleTo(fieldType, returnType)) - { - throw new InjectionException("Type " + fieldType + " is not convertable to " + returnType + " for getter " + apiMethod); - } - - getters.injectGetter(targetClass, apiMethod, otherf, getter); - } - - for (Method m : cf.getMethods()) - { - hookMethod.process(m); - invokes.process(m, other, implementingClass); - } - } - - logger.info("Injected {} getters, {} setters, {} invokers", - getters.getInjectedGetters(), - setters.getInjectedSetters(), invokes.getInjectedInvokers()); - - new DrawAfterWidgets(this).inject(); - new ScriptVM(this).inject(); - new ClearColorBuffer(this).inject(); - new RenderDraw(this).inject(); - // new DrawMenu(this).inject(); - new Occluder(this).inject(); - new HidePlayerAttacks(this).inject(); - } - - private java.lang.Class injectInterface(ClassFile cf, ClassFile other) - { - Annotations an = cf.getAnnotations(); - if (an == null) - { - return null; - } - - Annotation a = an.find(DeobAnnotations.IMPLEMENTS); - if (a == null) - { - return null; - } - - String ifaceName = API_PACKAGE_BASE + a.getElement().getString(); - java.lang.Class apiClass; - - try - { - apiClass = java.lang.Class.forName(ifaceName); - } - catch (ClassNotFoundException ex) - { - logger.trace("Class {} implements nonexistent interface {}, skipping interface injection", - cf.getName(), - ifaceName); - return null; - } - - String ifaceNameInternal = ifaceName.replace('.', '/'); // to internal name - Class clazz = new Class(ifaceNameInternal); - - Interfaces interfaces = other.getInterfaces(); - interfaces.addInterface(clazz); - - return apiClass; - } - - public java.lang.reflect.Method findImportMethodOnApi(java.lang.Class clazz, String name, Boolean setter) - { - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) - { - if (method.isSynthetic()) - { - /* - * If you override an interface method in another interface - * with a return type that is a child of the overriden methods - * return type, both methods end up in the interface, and both - * are *annotated*. But the base one is synthetic. - */ - continue; - } - - Import i = method.getAnnotation(Import.class); - - if (i == null || !name.equals(i.value()) || (setter != null && (method.getParameterCount() > 0) != setter)) - { - continue; - } - - return method; - } - - return null; - } - - /** - * create a load instruction for a variable of type from a given index - * - * @param instructions - * @param type - * @param index - * @return - */ - public Instruction createLoadForTypeIndex(Instructions instructions, Type type, int index) - { - if (type.getDimensions() > 0 || !type.isPrimitive()) - { - return new ALoad(instructions, index); - } - - switch (type.toString()) - { - case "B": - case "C": - case "I": - case "S": - case "Z": - return new ILoad(instructions, index); - case "D": - return new DLoad(instructions, index); - case "F": - return new FLoad(instructions, index); - case "J": - return new LLoad(instructions, index); - default: - throw new RuntimeException("Unknown type"); - } - } - - ClassFile toDeobClass(ClassFile obClass) - { - for (ClassFile cf : deobfuscated.getClasses()) - { - String obfuscatedName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - - if (obClass.getName().equalsIgnoreCase(obfuscatedName)) - { - return cf; - } - } - - return null; - } - - Type deobfuscatedTypeToApiType(Type type) throws InjectionException - { - if (type.isPrimitive()) - { - return type; - } - - ClassFile cf = deobfuscated.findClass(type.getInternalName()); - if (cf == null) - { - return type; // not my type - } - - java.lang.Class rsApiType; - try - { - rsApiType = java.lang.Class.forName(API_PACKAGE_BASE + cf.getName().replace("/", ".")); - } - catch (ClassNotFoundException ex) - { - throw new InjectionException("Deobfuscated type " + type.getInternalName() + " has no API type", ex); - } - - java.lang.Class rlApiType = null; - - for (java.lang.Class inter : rsApiType.getInterfaces()) - { - if (inter.getName().startsWith(RL_API_PACKAGE_BASE)) - { - rlApiType = inter; - } - } - - // if (rlApiType == null) - // { - // throw new InjectionException("RS API type " + rsApiType + " does not extend RL API interface"); - // } - - final java.lang.Class finalType = rlApiType == null ? rsApiType : rlApiType; - - return Type.getType("L" + finalType.getName().replace('.', '/') + ";", type.getDimensions()); - } - - Type apiTypeToDeobfuscatedType(Type type) - { - if (type.isPrimitive()) - { - return type; - } - - String internalName = type.getInternalName().replace('/', '.'); - if (!internalName.startsWith(API_PACKAGE_BASE)) - { - return type; // not an rs api type - } - - return Type.getType("L" + type.getInternalName().substring(API_PACKAGE_BASE.length()) + ";", type.getDimensions()); - } - - ClassFile findVanillaForInterface(java.lang.Class clazz) - { - String className = clazz.getName().replace('.', '/'); - for (ClassFile cf : getVanilla().getClasses()) - { - for (net.runelite.asm.pool.Class cl : cf.getInterfaces().getInterfaces()) - { - if (cl.getName().equals(className)) - { - return cf; - } - } - } - return null; - } - - private boolean validateTypeIsConvertibleTo(Type from, Type to) throws InjectionException - { - if (from.getDimensions() != to.getDimensions()) - { - throw new InjectionException("Array dimension mismatch"); - } - - if (from.isPrimitive()) - { - return true; - } - - ClassFile vanillaClass = vanilla.findClass(from.getInternalName()); - if (vanillaClass == null) - { - return true; - } - - boolean okay = false; - for (Class inter : vanillaClass.getInterfaces().getInterfaces()) - { - java.lang.Class c; - - try - { - c = java.lang.Class.forName(inter.getName().replace('/', '.')); - } - catch (ClassNotFoundException ex) - { - continue; - } - - okay |= check(c, to); - } - - return okay; - } - - private boolean check(java.lang.Class c, Type type) - { - String s = type.getInternalName() - .replace('/', '.'); - - if (c.getName().equals(s)) - { - return true; - } - - for (java.lang.Class c2 : c.getInterfaces()) - { - if (check(c2, type)) - { - return true; - } - } - return false; - } - - public final ClassGroup getDeobfuscated() - { - return deobfuscated; - } - - public final ClassGroup getVanilla() - { - return vanilla; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java b/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java deleted file mode 100644 index 8a87451da6..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectConstruct.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.Dup; -import net.runelite.asm.attributes.code.instructions.InvokeSpecial; -import net.runelite.asm.attributes.code.instructions.New; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import net.runelite.mapping.Construct; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InjectConstruct -{ - private static final Logger logger = LoggerFactory.getLogger(InjectConstruct.class); - - private final Inject inject; - - InjectConstruct(Inject inject) - { - this.inject = inject; - } - - public void inject(Map implemented) throws InjectionException - { - for (Entry entry : implemented.entrySet()) - { - Class clazz = entry.getValue(); - ClassFile cf = entry.getKey(); - - if (clazz == null) - { - continue; - } - - for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) - { - if (method.isSynthetic()) - { - continue; - } - - Construct construct = method.getAnnotation(Construct.class); - if (construct == null) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - if (obfuscatedName == null) - { - obfuscatedName = cf.getName(); - } - - ClassGroup vanilla = inject.getVanilla(); - ClassFile other = vanilla.findClass(obfuscatedName); - assert other != null : "unable to find vanilla class from obfuscated name: " + obfuscatedName; - - injectConstruct(other, method); - } - } - } - - void injectConstruct(ClassFile targetClass, java.lang.reflect.Method apiMethod) throws InjectionException - { - logger.info("Injecting construct for {}", apiMethod); - - assert targetClass.findMethod(apiMethod.getName()) == null; - - Class typeToConstruct = apiMethod.getReturnType(); - ClassFile vanillaClass = inject.findVanillaForInterface(typeToConstruct); - if (vanillaClass == null) - { - throw new InjectionException("Unable to find vanilla class which implements interface " + typeToConstruct); - } - - Signature sig = inject.javaMethodToSignature(apiMethod); - - Signature constructorSig = new Signature.Builder() - .addArguments(Stream.of(apiMethod.getParameterTypes()) - .map(arg -> - { - ClassFile vanilla = inject.findVanillaForInterface(arg); - if (vanilla != null) - { - return new Type("L" + vanilla.getName() + ";"); - } - return Inject.classToType(arg); - }) - .collect(Collectors.toList())) - .setReturnType(Type.VOID) - .build(); - Method vanillaConstructor = vanillaClass.findMethod("", constructorSig); - if (vanillaConstructor == null) - { - throw new InjectionException("Unable to find constructor for " + vanillaClass.getName() + "." + constructorSig); - } - - Method setterMethod = new Method(targetClass, apiMethod.getName(), sig); - setterMethod.setAccessFlags(ACC_PUBLIC); - targetClass.addMethod(setterMethod); - - Code code = new Code(setterMethod); - setterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - ins.add(new New(instructions, vanillaClass.getPoolClass())); - ins.add(new Dup(instructions)); - int idx = 1; - int parameter = 0; - for (Type type : vanillaConstructor.getDescriptor().getArguments()) - { - Instruction load = inject.createLoadForTypeIndex(instructions, type, idx); - idx += type.getSize(); - ins.add(load); - - Type paramType = sig.getTypeOfArg(parameter); - if (!type.equals(paramType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(type); - ins.add(checkCast); - } - - ++parameter; - } - ins.add(new InvokeSpecial(instructions, vanillaConstructor.getPoolMethod())); - ins.add(new Return(instructions)); - - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java b/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java deleted file mode 100644 index cd94ee80d8..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectGetter.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.GetField; -import net.runelite.asm.attributes.code.instructions.GetStatic; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.signature.Signature; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectGetter -{ - private static final Logger logger = LoggerFactory.getLogger(InjectGetter.class); - - private final Inject inject; - - private int injectedGetters; - - InjectGetter(Inject inject) - { - this.inject = inject; - } - - void injectGetter(ClassFile clazz, java.lang.reflect.Method method, Field field, Number getter) - { - // clazz = class file we're injecting the method into. - // method = api method (java reflect) that we're overriding - // field = field we're getting. might not be in this class if static. - // getter = encryption getter - - assert clazz.findMethod(method.getName()) == null; - assert field.isStatic() || field.getClassFile() == clazz; - - Signature sig = new Signature.Builder() - .setReturnType(Inject.classToType(method.getReturnType())) - .build(); - Method getterMethod = new Method(clazz, method.getName(), sig); - getterMethod.setAccessFlags(ACC_PUBLIC); - - // create code - Code code = new Code(getterMethod); - getterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - if (field.isStatic()) - { - code.setMaxStack(1); - - ins.add(new GetStatic(instructions, field.getPoolField())); - } - else - { - code.setMaxStack(2); - - ins.add(new ALoad(instructions, 0)); - ins.add(new GetField(instructions, field.getPoolField())); - } - - if (getter != null) - { - code.setMaxStack(2); - - assert getter instanceof Integer || getter instanceof Long; - - if (getter instanceof Integer) - { - ins.add(new LDC(instructions, (int) getter)); - ins.add(new IMul(instructions)); - } - else - { - ins.add(new LDC(instructions, (long) getter)); - ins.add(new LMul(instructions)); - } - } - - InstructionType returnType; - if (field.getType().isPrimitive() && field.getType().getDimensions() == 0) - { - switch (field.getType().toString()) - { - case "B": - case "C": - case "I": - case "S": - case "Z": - returnType = InstructionType.IRETURN; - break; - case "D": - returnType = InstructionType.DRETURN; - break; - case "F": - returnType = InstructionType.FRETURN; - break; - case "J": - returnType = InstructionType.LRETURN; - break; - default: - throw new RuntimeException("Unknown type"); - } - } - else - { - returnType = InstructionType.ARETURN; - } - - ins.add(new Return(instructions, returnType)); - - clazz.addMethod(getterMethod); - ++injectedGetters; - } - - int getInjectedGetters() - { - return injectedGetters; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java b/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java deleted file mode 100644 index 19ae3a3df6..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectHook.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import com.google.common.collect.Lists; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.DupInstruction; -import net.runelite.asm.attributes.code.instruction.types.SetFieldInstruction; -import net.runelite.asm.attributes.code.instructions.ArrayStore; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.Dup; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.attributes.code.instructions.Swap; -import net.runelite.asm.execution.Execution; -import net.runelite.asm.execution.InstructionContext; -import net.runelite.asm.execution.StackContext; -import net.runelite.asm.signature.Signature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectHook -{ - private static final Logger logger = LoggerFactory.getLogger(InjectHook.class); - private static final String HOOK_METHOD_SIGNATURE = "(I)V"; - private static final String CLINIT = ""; - private final Inject inject; - private final Map hooked = new HashMap<>(); - private int injectedHooks; - - InjectHook(Inject inject) - { - this.inject = inject; - } - - void hook(Field field, HookInfo hookInfo) - { - hooked.put(field, hookInfo); - } - - void run() - { - Execution e = new Execution(inject.getVanilla()); - e.populateInitialMethods(); - - Set done = new HashSet<>(); - Set doneIh = new HashSet<>(); - - e.addExecutionVisitor((InstructionContext ic) -> - { - Instruction i = ic.getInstruction(); - Instructions ins = i.getInstructions(); - Code code = ins.getCode(); - Method method = code.getMethod(); - - if (method.getName().equals(CLINIT)) - { - return; - } - - if (!(i instanceof SetFieldInstruction)) - { - return; - } - - if (!done.add(i)) - { - return; - } - - SetFieldInstruction sfi = (SetFieldInstruction) i; - Field fieldBeingSet = sfi.getMyField(); - - if (fieldBeingSet == null) - { - return; - } - - HookInfo hookInfo = hooked.get(fieldBeingSet); - if (hookInfo == null) - { - return; - } - - String hookName = hookInfo.fieldName; - assert hookName != null; - - logger.trace("Found injection location for hook {} at instruction {}", hookName, sfi); - ++injectedHooks; - - StackContext value = ic.getPops().get(0); - - StackContext objectStackContext = null; - if (sfi instanceof PutField) - { - objectStackContext = ic.getPops().get(1); - } - - int idx = ins.getInstructions().indexOf(sfi); - assert idx != -1; - - try - { - if (hookInfo.before) - { - injectCallbackBefore(ins, idx, hookInfo, null, objectStackContext, value); - } - else - { - // idx + 1 to insert after the set - injectCallback(ins, idx + 1, hookInfo, null, objectStackContext); - } - } - catch (InjectionException ex) - { - throw new RuntimeException(ex); - } - }); - - // these look like: - // getfield - // iload_0 - // iconst_0 - // iastore - e.addExecutionVisitor((InstructionContext ic) -> - { - Instruction i = ic.getInstruction(); - Instructions ins = i.getInstructions(); - Code code = ins.getCode(); - Method method = code.getMethod(); - - if (method.getName().equals(CLINIT)) - { - return; - } - - if (!(i instanceof ArrayStore)) - { - return; - } - - if (!doneIh.add(i)) - { - return; - } - - ArrayStore as = (ArrayStore) i; - - Field fieldBeingSet = as.getMyField(ic); - if (fieldBeingSet == null) - { - return; - } - - HookInfo hookInfo = hooked.get(fieldBeingSet); - if (hookInfo == null) - { - return; - } - - String hookName = hookInfo.fieldName; - - StackContext value = ic.getPops().get(0); - StackContext index = ic.getPops().get(1); - - StackContext arrayReference = ic.getPops().get(2); - InstructionContext arrayReferencePushed = arrayReference.getPushed(); - - StackContext objectStackContext = null; - if (arrayReferencePushed.getInstruction().getType() == InstructionType.GETFIELD) - { - objectStackContext = arrayReferencePushed.getPops().get(0); - } - - // inject hook after 'i' - logger.info("Found array injection location for hook {} at instruction {}", hookName, i); - ++injectedHooks; - - int idx = ins.getInstructions().indexOf(i); - assert idx != -1; - - try - { - if (hookInfo.before) - { - injectCallbackBefore(ins, idx, hookInfo, index, objectStackContext, value); - } - else - { - injectCallback(ins, idx + 1, hookInfo, index, objectStackContext); - } - } - catch (InjectionException ex) - { - throw new RuntimeException(ex); - } - }); - - e.run(); - } - - private void injectCallbackBefore(Instructions ins, int idx, HookInfo hookInfo, StackContext index, StackContext object, StackContext value) throws InjectionException - { - Signature signature = hookInfo.method.getDescriptor(); - Type methodArgumentType = signature.getTypeOfArg(0); - - if (!hookInfo.method.isStatic()) - { - if (object == null) - { - throw new InjectionException("null object"); - } - - ins.getInstructions().add(idx++, new Dup(ins)); // dup value - idx = recursivelyPush(ins, idx, object); - ins.getInstructions().add(idx++, new Swap(ins)); - if (hookInfo.getter != null) - { - assert hookInfo.getter instanceof Integer || hookInfo.getter instanceof Long; - - if (hookInfo.getter instanceof Integer) - { - ins.getInstructions().add(idx++, new LDC(ins, (int) hookInfo.getter)); - ins.getInstructions().add(idx++, new IMul(ins)); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, (long) hookInfo.getter)); - ins.getInstructions().add(idx++, new LMul(ins)); - } - } - if (!value.type.equals(methodArgumentType)) - { - CheckCast checkCast = new CheckCast(ins); - checkCast.setType(methodArgumentType); - ins.getInstructions().add(idx++, checkCast); - } - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - - InvokeVirtual invoke = new InvokeVirtual(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - signature - ) - ); - ins.getInstructions().add(idx++, invoke); - } - else - { - ins.getInstructions().add(idx++, new Dup(ins)); // dup value - if (!value.type.equals(methodArgumentType)) - { - CheckCast checkCast = new CheckCast(ins); - checkCast.setType(methodArgumentType); - ins.getInstructions().add(idx++, checkCast); - } - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - - InvokeStatic invoke = new InvokeStatic(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - signature - ) - ); - ins.getInstructions().add(idx++, invoke); - } - } - - private int recursivelyPush(Instructions ins, int idx, StackContext sctx) - { - InstructionContext ctx = sctx.getPushed(); - if (ctx.getInstruction() instanceof DupInstruction) - { - DupInstruction dupInstruction = (DupInstruction) ctx.getInstruction(); - sctx = dupInstruction.getOriginal(sctx); - ctx = sctx.getPushed(); - } - - for (StackContext s : Lists.reverse(ctx.getPops())) - { - idx = recursivelyPush(ins, idx, s); - } - - ins.getInstructions().add(idx++, ctx.getInstruction().clone()); - return idx; - } - - private void injectCallback(Instructions ins, int idx, HookInfo hookInfo, StackContext index, StackContext objectPusher) throws InjectionException - { - if (!hookInfo.method.isStatic()) - { - if (objectPusher == null) - { - throw new InjectionException("Null object pusher"); - } - - idx = recursivelyPush(ins, idx, objectPusher); - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, -1)); - } - - InvokeVirtual invoke = new InvokeVirtual(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - new Signature(HOOK_METHOD_SIGNATURE) - ) - ); - ins.getInstructions().add(idx++, invoke); - - } - else - { - if (index != null) - { - idx = recursivelyPush(ins, idx, index); - } - else - { - ins.getInstructions().add(idx++, new LDC(ins, -1)); - } - - InvokeStatic invoke = new InvokeStatic(ins, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(hookInfo.clazz), - hookInfo.method.getName(), - new Signature(HOOK_METHOD_SIGNATURE) - ) - ); - ins.getInstructions().add(idx++, invoke); - } - } - - int getInjectedHooks() - { - return injectedHooks; - } - - static class HookInfo - { - String fieldName; - String clazz; - Method method; - boolean before; - Number getter; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java b/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java deleted file mode 100644 index 3c304807be..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectHookMethod.java +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class InjectHookMethod -{ - public static final String HOOKS = "net/runelite/client/callback/Hooks"; - private static final Logger logger = LoggerFactory.getLogger(InjectHookMethod.class); - private final Inject inject; - - InjectHookMethod(Inject inject) - { - this.inject = inject; - } - - void process(Method method) throws InjectionException - { - Annotations an = method.getAnnotations(); - if (an == null) - { - return; - } - - Annotation a = an.find(DeobAnnotations.HOOK); - if (a == null) - { - return; - } - - String hookName = a.getElement().getString(); - boolean end = a.getElements().size() == 2 && a.getElements().get(1).getValue().equals(true); - - inject(null, method, hookName, end, true); - } - - public void inject(Method hookMethod, Method method, String name, boolean end, boolean useHooks) throws InjectionException - { - Annotations an = method.getAnnotations(); - - // Method is hooked - // Find equivalent method in vanilla, and insert callback at the beginning - ClassFile cf = method.getClassFile(); - String obfuscatedMethodName = DeobAnnotations.getObfuscatedName(an), - obfuscatedClassName = DeobAnnotations.getObfuscatedName(cf.getAnnotations()); - - // might be a constructor - if (obfuscatedMethodName == null) - { - obfuscatedMethodName = method.getName(); - } - - assert obfuscatedClassName != null : "hook on method in class with no obfuscated name"; - assert obfuscatedMethodName != null : "hook on method with no obfuscated name"; - - Signature obfuscatedSignature = inject.getMethodSignature(method); - - ClassGroup vanilla = inject.getVanilla(); - ClassFile vanillaClass = vanilla.findClass(obfuscatedClassName); - Method vanillaMethod = vanillaClass.findMethod(obfuscatedMethodName, obfuscatedSignature); - assert method.isStatic() == vanillaMethod.isStatic(); - - // Insert instructions at beginning of method - injectHookMethod(hookMethod, name, end, method, vanillaMethod, useHooks); - } - - private void injectHookMethod(Method hookMethod, String hookName, boolean end, Method deobMethod, Method vanillaMethod, boolean useHooks) throws InjectionException - { - Code code = vanillaMethod.getCode(); - if (code == null) - { - logger.warn(vanillaMethod + " code is null"); - } - Instructions instructions = code.getInstructions(); - - Signature.Builder builder = new Signature.Builder() - .setReturnType(Type.VOID); // Hooks always return void - - for (Type type : deobMethod.getDescriptor().getArguments()) - { - builder.addArgument(inject.deobfuscatedTypeToApiType(type)); - } - - assert deobMethod.isStatic() == vanillaMethod.isStatic(); - - boolean modifiedSignature = false; - if (!deobMethod.isStatic() && useHooks) - { - // Add variable to signature - builder.addArgument(0, inject.deobfuscatedTypeToApiType(new Type(deobMethod.getClassFile().getName()))); - modifiedSignature = true; - } - - Signature signature = builder.build(); - - List insertIndexes = findHookLocations(hookName, end, vanillaMethod); - insertIndexes.sort((a, b) -> Integer.compare(b, a)); - - for (int insertPos : insertIndexes) - { - if (!deobMethod.isStatic()) - { - instructions.addInstruction(insertPos++, new ALoad(instructions, 0)); - } - - int signatureStart = modifiedSignature ? 1 : 0; - int index = deobMethod.isStatic() ? 0 : 1; // current variable index - - for (int i = signatureStart; i < signature.size(); ++i) - { - Type type = signature.getTypeOfArg(i); - - Instruction load = inject.createLoadForTypeIndex(instructions, type, index); - instructions.addInstruction(insertPos++, load); - - index += type.getSize(); - } - - InvokeInstruction invoke; - - // use old Hooks callback - if (useHooks) - { - // Invoke callback - invoke = new InvokeStatic(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(HOOKS), - hookName, - signature - ) - ); - } - else - { - // Invoke methodhook - assert hookMethod != null; - - if (vanillaMethod.isStatic()) - { - invoke = new InvokeStatic(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class("client"), // Static methods are in client - hookMethod.getName(), - signature - ) - ); - } - else - { - // otherwise invoke member function - //instructions.addInstruction(insertPos++, new ALoad(instructions, 0)); - invoke = new InvokeVirtual(instructions, - new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(vanillaMethod.getClassFile().getName()), - hookMethod.getName(), - hookMethod.getDescriptor() - ) - ); - } - } - - instructions.addInstruction(insertPos++, (Instruction) invoke); - } - - logger.info("Injected method hook {} in {} with {} args: {}", - hookName, vanillaMethod, signature.size(), - signature.getArguments()); - } - - private List findHookLocations(String hookName, boolean end, Method vanillaMethod) throws InjectionException - { - Instructions instructions = vanillaMethod.getCode().getInstructions(); - - if (end) - { - // find return - List returns = instructions.getInstructions().stream() - .filter(i -> i instanceof ReturnInstruction) - .collect(Collectors.toList()); - List indexes = new ArrayList<>(); - - for (Instruction ret : returns) - { - int idx = instructions.getInstructions().indexOf(ret); - assert idx != -1; - indexes.add(idx); - } - - return indexes; - } - - if (!vanillaMethod.getName().equals("")) - { - return Arrays.asList(0); - } - - // Find index after invokespecial - for (int i = 0; i < instructions.getInstructions().size(); ++i) - { - Instruction in = instructions.getInstructions().get(i); - - if (in.getType() == InstructionType.INVOKESPECIAL) - { - return Arrays.asList(i + 1); // one after - } - } - - throw new IllegalStateException("constructor with no invokespecial"); - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java b/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java deleted file mode 100644 index 3367b26c7a..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectInvoker.java +++ /dev/null @@ -1,291 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Annotations; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.InstructionType; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.BiPush; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.DLoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.InvokeVirtual; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LLoad; -import net.runelite.asm.attributes.code.instructions.Return; -import net.runelite.asm.attributes.code.instructions.SiPush; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; -import static net.runelite.deob.DeobAnnotations.EXPORT; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectInvoker -{ - private static final Logger logger = LoggerFactory.getLogger(InjectInvoker.class); - - private final Inject inject; - - private int injectedInvokers; - - InjectInvoker(Inject inject) - { - this.inject = inject; - } - - /** - * Inject an invoker for a method - * - * @param m Method in the deobfuscated client to inject an invoker for - * @param other Class in the vanilla client of the same class m is a - * member of - * @param implementingClass Java class for the API interface the class - * will implement - */ - void process(Method m, ClassFile other, java.lang.Class implementingClass) - { - Annotations an = m.getAnnotations(); - - if (an == null || an.find(EXPORT) == null) - { - return; // not an exported method - } - - String exportedName = DeobAnnotations.getExportedName(an); - String obfuscatedName = DeobAnnotations.getObfuscatedName(an); - - if (obfuscatedName == null) - { - obfuscatedName = m.getName(); - } - - String garbage = DeobAnnotations.getDecoder(m); - Method otherm = other.findMethod(obfuscatedName, inject.getMethodSignature(m)); - - assert otherm != null; - assert m.isStatic() == otherm.isStatic(); - - ClassGroup vanilla = inject.getVanilla(); - - ClassFile targetClass = m.isStatic() ? vanilla.findClass("client") : other; - - // Place into implementing class, unless the method is static - java.lang.Class targetClassJava = m.isStatic() ? Inject.CLIENT_CLASS : implementingClass; - - if (targetClassJava == null) - { - assert !m.isStatic(); - - // non static exported method on non exported interface, weird. - // logger.debug("Non static exported method {} on non exported interface", exportedName); - return; - } - - java.lang.reflect.Method apiMethod = inject.findImportMethodOnApi(targetClassJava, exportedName, null); // api method to invoke 'otherm' - if (apiMethod == null) - { - // logger.debug("Unable to find api method on {} with imported name {}, not injecting invoker", targetClassJava, exportedName); - return; - } - - injectInvoker(targetClass, apiMethod, m, otherm, garbage); - ++injectedInvokers; - } - - private void injectInvoker(ClassFile clazz, java.lang.reflect.Method method, Method deobfuscatedMethod, Method invokeMethod, String garbage) - { - // clazz = clazz to add invoker to - // method = api method to override - // deobfuscatedMethod = deobfuscated method, used to get the deobfuscated signature - // invokeMethod = method to invoke, obfuscated - - if (clazz.findMethod(method.getName(), deobfuscatedMethod.getDescriptor()) != null) - { - logger.warn("Not injecting method {} because it already exists!", method); - return; // this can happen from exporting a field and method with the same name - } - - assert invokeMethod.isStatic() == deobfuscatedMethod.isStatic(); - assert invokeMethod.isStatic() || invokeMethod.getClassFile() == clazz; - - Type lastGarbageArgumentType = null; - - if (deobfuscatedMethod.getDescriptor().getArguments().size() != invokeMethod.getDescriptor().getArguments().size()) - { - // allow for obfuscated method to have a single bogus signature at the end - assert deobfuscatedMethod.getDescriptor().size() + 1 == invokeMethod.getDescriptor().size(); - - List arguments = invokeMethod.getDescriptor().getArguments(); - lastGarbageArgumentType = arguments.get(arguments.size() - 1); - } - - // Injected method signature is always the same as the API - Signature apiSignature = inject.javaMethodToSignature(method); - Method invokerMethodSignature = new Method(clazz, method.getName(), apiSignature); - invokerMethodSignature.setAccessFlags(ACC_PUBLIC); - - // create code attribute - Code code = new Code(invokerMethodSignature); - invokerMethodSignature.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - code.setMaxStack(1 + invokeMethod.getDescriptor().size()); // this + arguments - - // load function arguments onto the stack. - int index = 0; - if (!invokeMethod.isStatic()) - { - ins.add(new ALoad(instructions, index++)); // this - } - else - { - ++index; // this method is always non static - } - for (int i = 0; i < deobfuscatedMethod.getDescriptor().size(); ++i) - { - Type type = deobfuscatedMethod.getDescriptor().getTypeOfArg(i); - - Instruction loadInstruction = inject.createLoadForTypeIndex(instructions, type, index); - ins.add(loadInstruction); - - Signature invokeDesc = invokeMethod.getDescriptor(); - Type obType = invokeDesc.getTypeOfArg(i); - if (!type.equals(obType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(obType); - ins.add(checkCast); - } - - if (loadInstruction instanceof DLoad || loadInstruction instanceof LLoad) - { - index += 2; - } - else - { - index += 1; - } - } - - if (lastGarbageArgumentType != null) - { - // function requires garbage value - - // if garbage is null here it might just be an unused parameter, not part of the obfuscation - if (garbage == null) - { - garbage = "0"; - } - - switch (lastGarbageArgumentType.toString()) - { - case "Z": - case "B": - case "C": - ins.add(new BiPush(instructions, Byte.parseByte(garbage))); - break; - case "S": - ins.add(new SiPush(instructions, Short.parseShort(garbage))); - break; - case "I": - ins.add(new LDC(instructions, Integer.parseInt(garbage))); - break; - case "D": - ins.add(new LDC(instructions, Double.parseDouble(garbage))); - break; - case "F": - ins.add(new LDC(instructions, Float.parseFloat(garbage))); - break; - case "J": - ins.add(new LDC(instructions, Long.parseLong(garbage))); - break; - default: - throw new RuntimeException("Unknown type"); - } - } - - if (invokeMethod.isStatic()) - { - ins.add(new InvokeStatic(instructions, invokeMethod.getPoolMethod())); - } - else - { - ins.add(new InvokeVirtual(instructions, invokeMethod.getPoolMethod())); - } - - Type returnValue = invokeMethod.getDescriptor().getReturnValue(); - InstructionType returnType; - - if (returnValue.isPrimitive() && returnValue.getDimensions() == 0) - { - switch (returnValue.toString()) - { - case "Z": - case "I": - returnType = InstructionType.IRETURN; - break; - case "J": - returnType = InstructionType.LRETURN; - break; - case "F": - returnType = InstructionType.FRETURN; - break; - case "D": - returnType = InstructionType.DRETURN; - break; - case "V": - returnType = InstructionType.RETURN; - break; - default: - assert false; - return; - } - } - else - { - returnType = InstructionType.ARETURN; - } - - ins.add(new Return(instructions, returnType)); - - clazz.addMethod(invokerMethodSignature); - } - - int getInjectedInvokers() - { - return injectedInvokers; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java b/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java deleted file mode 100644 index b7c22194fe..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectMojo.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.clientver.ClientVersion; -import net.runelite.deob.util.JarUtil; -import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugin.MojoFailureException; -import org.apache.maven.plugin.logging.Log; -import org.apache.maven.plugins.annotations.LifecyclePhase; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; - -@Mojo( - name = "runelite-injector", - defaultPhase = LifecyclePhase.GENERATE_RESOURCES -) -public class InjectMojo extends AbstractMojo -{ - private final Log log = getLog(); - @Parameter(defaultValue = "${project.build.outputDirectory}") - private File outputDirectory; - @Parameter(defaultValue = "./runescape-client/target/rs-client-${project.version}.jar", readonly = true, required = true) - private String rsClientPath; - @Parameter(defaultValue = "${net.runelite.rs:vanilla:jar}", readonly = true, required = true) - private String vanillaPath; - - @Override - public void execute() throws MojoExecutionException, MojoFailureException - { - ClientVersion ver = new ClientVersion(new File(vanillaPath)); - int version; - try - { - version = ver.getVersion(); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to read vanilla client version", ex); - } - - log.info("Vanilla client version " + version); - - ClassGroup rs; - ClassGroup vanilla; - - try - { - rs = JarUtil.loadJar(new File(rsClientPath)); - vanilla = JarUtil.loadJar(new File(vanillaPath)); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to load dependency jars", ex); - } - - Injector injector = new Injector(rs, vanilla); - try - { - injector.inject(); - } - catch (InjectionException ex) - { - throw new MojoExecutionException("Error injecting client", ex); - } - - InjectorValidator iv = new InjectorValidator(vanilla); - iv.validate(); - - if (iv.getError() > 0) - { - throw new MojoExecutionException("Error building injected jar"); - } - - if (iv.getMissing() > 0) - { - throw new MojoExecutionException("Unable to inject all methods"); - } - - try - { - writeClasses(vanilla, outputDirectory); - } - catch (IOException ex) - { - throw new MojoExecutionException("Unable to write classes", ex); - } - - log.info("Injector wrote " + vanilla.getClasses().size() + " classes, " + iv.getOkay() + " injected methods"); - } - - private void writeClasses(ClassGroup group, File outputDirectory) throws IOException - { - for (ClassFile cf : group.getClasses()) - { - File classFile = getClassFile(outputDirectory, cf); - byte[] classData = JarUtil.writeClass(group, cf); - - try (FileOutputStream fout = new FileOutputStream(classFile, false)) - { - fout.write(classData); - } - } - } - - private File getClassFile(File base, ClassFile cf) - { - File f = base; - - String[] parts = cf.getName().split("/"); - for (int i = 0; i < parts.length - 1; ++i) - { - String part = parts[i]; - - f = new File(f, part); - } - - f.mkdirs(); - f = new File(f, parts[parts.length - 1] + ".class"); - - return f; - } - -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java b/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java deleted file mode 100644 index 58c225fa87..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectSetter.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.util.List; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.attributes.code.instructions.LMul; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.attributes.code.instructions.PutStatic; -import net.runelite.asm.attributes.code.instructions.VReturn; -import net.runelite.asm.signature.Signature; -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class InjectSetter -{ - private static final Logger logger = LoggerFactory.getLogger(InjectSetter.class); - - private final Inject inject; - - private int injectedSetters; - - InjectSetter(Inject inject) - { - this.inject = inject; - } - - /** - * inject a setter into the vanilla classgroup - * - * @param targetClass Class where to inject the setter (field's class, - * or client) - * @param targetApiClass API targetClass implements, which may have the - * setter declared - * @param field Field of vanilla that will be set - * @param exportedName exported name of field - */ - void injectSetter(ClassFile targetClass, Class targetApiClass, Field field, String exportedName, Number setter) - { - java.lang.reflect.Method method = inject.findImportMethodOnApi(targetApiClass, exportedName, true); - if (method == null) - { - logger.warn("Setter injection for field {} but an API method was not found on {}", exportedName, targetApiClass); - return; - } - - if (method.getParameterCount() != 1) - { - logger.warn("Setter {} with not parameter count != 1?", exportedName); - return; - } - - logger.info("Injecting setter for {} on {}", exportedName, targetApiClass); - - assert targetClass.findMethod(method.getName()) == null; - assert field.isStatic() || field.getClassFile() == targetClass; - - Signature sig = new Signature.Builder() - .setReturnType(Type.VOID) - .addArgument(Inject.classToType(method.getParameterTypes()[0])) - .build(); - - Method setterMethod = new Method(targetClass, method.getName(), sig); - setterMethod.setAccessFlags(ACC_PUBLIC); - targetClass.addMethod(setterMethod); - ++injectedSetters; - - Code code = new Code(setterMethod); - setterMethod.setCode(code); - - Instructions instructions = code.getInstructions(); - List ins = instructions.getInstructions(); - - // load this - if (!field.isStatic()) - { - ins.add(new ALoad(instructions, 0)); - } - - // load argument - Type argumentType = sig.getTypeOfArg(0); - ins.add(inject.createLoadForTypeIndex(instructions, argumentType, 1)); - - // cast argument to field type - Type fieldType = field.getType(); - if (!argumentType.equals(fieldType)) - { - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(fieldType); - ins.add(checkCast); - } - - if (setter != null) - { - assert setter instanceof Integer || setter instanceof Long; - - if (setter instanceof Integer) - { - ins.add(new LDC(instructions, (int) setter)); - ins.add(new IMul(instructions)); - } - else - { - ins.add(new LDC(instructions, (long) setter)); - ins.add(new LMul(instructions)); - } - } - - if (field.isStatic()) - { - ins.add(new PutStatic(instructions, field)); - } - else - { - ins.add(new PutField(instructions, field)); - } - - ins.add(new VReturn(instructions)); - } - - int getInjectedSetters() - { - return injectedSetters; - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java b/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java deleted file mode 100644 index 2292b349ab..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectUtil.java +++ /dev/null @@ -1,281 +0,0 @@ -package net.runelite.injector; - -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.signature.Signature; -import net.runelite.deob.DeobAnnotations; - -public class InjectUtil -{ - public static ClassFile toObClass(final ClassGroup vanilla, final ClassFile deobCf) throws InjectionException - { - final String obfuscatedName = DeobAnnotations.getObfuscatedName(deobCf.getAnnotations()); - final ClassFile obCf = vanilla.findClass(obfuscatedName); - - if (obCf == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", obfuscatedName)); - } - - return obCf; - } - - public static Field toObField(final ClassGroup vanilla, final Field field) throws InjectionException - { - String obfuscatedClassName = DeobAnnotations.getObfuscatedName(field.getClassFile().getAnnotations()); - String obfuscatedFieldName = DeobAnnotations.getObfuscatedName(field.getAnnotations()); // obfuscated name of field - Type type = getFieldType(field); - - ClassFile obfuscatedClass = vanilla.findClass(obfuscatedClassName); - if (obfuscatedClass == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", obfuscatedClassName)); - } - - Field obfuscatedField = obfuscatedClass.findFieldDeep(obfuscatedFieldName, type); - if (obfuscatedField == null) - { - throw new InjectionException(String.format("Field \"%s\" could not be found.", obfuscatedFieldName)); - } - - return obfuscatedField; - } - - public static ClassFile toDeobClass(final ClassFile obCf, final ClassGroup deob) throws InjectionException - { - final ClassFile wowThatWasQuick = deob.findObfuscatedName(obCf.getName()); - if (wowThatWasQuick == null) - { - throw new InjectionException("It wasn't obfscated enough, or a bit too much. Whatever it was it, wasn't in deob"); - } - return wowThatWasQuick; - } - - public static Type getFieldType(final Field f) - { - Type type = f.getType(); - - Annotation obfSignature = f.getAnnotations().find(DeobAnnotations.OBFUSCATED_SIGNATURE); - if (obfSignature != null) - { - //Annotation exists. Type was updated by us during deobfuscation - type = DeobAnnotations.getObfuscatedType(f); - } - - return type; - } - - /** - * Find a static method in ClassGroup group. Check the class with name hint first. - * (useful for static methods which are in the class they belong to) - */ - public static Method findStaticMethod(final ClassGroup group, final String name, final String hint) throws InjectionException - { - final ClassFile cf = group.findClass(hint); - - if (cf == null) - { - throw new InjectionException(String.format("ClassFile \"%s\" could not be found.", hint)); - } - - Method m = cf.findStaticMethod(name); - - if (m == null) - { - m = group.findStaticMethod(name); - } - - return m; - } - - /** - * Find a static method in ClassGroup group. Throws exception if not found. - */ - public static Method findStaticMethod(final ClassGroup group, final String name) throws InjectionException - { - Method m = group.findStaticMethod(name); - - if (m == null) - { - throw new InjectionException(String.format("Static method \"%s\" could not be found.", name)); - } - - return m; - } - - /** - * Find a static method in ClassGroup group. Throws exception if not found. - */ - public static Method findStaticMethod(final ClassGroup group, final String name, Signature sig) throws InjectionException - { - Method m = group.findStaticMethod(name, sig); - - if (m == null) - { - throw new InjectionException(String.format("Static method \"%s\" could not be found.", name)); - } - - return m; - } - - public static Method findMethod(Inject inject, String name) throws InjectionException - { - return findMethod(inject, name, null); - } - - public static Method findMethod(Inject inject, String name, String hint) throws InjectionException - { - if (hint != null) - { - ClassFile c = inject.getDeobfuscated().findClass(hint); - - if (c == null) - { - throw new InjectionException("Class " + hint + " doesn't exist. (check capitalization)"); - } - - Method deob = c.findMethod(name); - - if (deob != null) - { - String obfuscatedName = DeobAnnotations.getObfuscatedName(deob.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(deob); - - ClassFile ob = toObClass(inject.getVanilla(), c); - - return ob.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : deob.getDescriptor()); - } - } - - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Method m : c.getMethods()) - { - if (!m.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(m); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - - return c2.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : m.getDescriptor()); - } - } - - throw new InjectionException("Couldn't find method " + name); - } - - public static Method findStaticMethod(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Method m : c.getMethods()) - { - if (!m.isStatic() || !m.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(m.getAnnotations()); - Signature obfuscatedSignature = DeobAnnotations.getObfuscatedSignature(m); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - - return c2.findMethod(obfuscatedName, (obfuscatedSignature != null) ? obfuscatedSignature : m.getDescriptor()); - } - } - - throw new InjectionException("Couldn't find static method " + name); - } - - - public static Field findObField(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getVanilla().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - return f; - } - } - - throw new InjectionException(String.format("Field \"%s\" could not be found.", name)); - } - - public static Field findDeobField(Inject inject, String name) throws InjectionException - { - return findDeobField(inject, name, null); - } - - public static Field findDeobField(Inject inject, String name, String hint) throws InjectionException - { - if (hint != null) - { - ClassFile c = inject.getDeobfuscated().findClass(hint); - if (c == null) - { - throw new InjectionException("Class " + hint + " doesn't exist. (check capitalization)"); - } - - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - return c2.findField(obfuscatedName); - } - } - - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - String obfuscatedName = DeobAnnotations.getObfuscatedName(f.getAnnotations()); - - ClassFile c2 = toObClass(inject.getVanilla(), c); - return c2.findField(obfuscatedName); - } - } - - throw new InjectionException(String.format("Mapped field \"%s\" could not be found.", name)); - } - - public static Field findDeobFieldButUseless(Inject inject, String name) throws InjectionException - { - for (ClassFile c : inject.getDeobfuscated().getClasses()) - { - for (Field f : c.getFields()) - { - if (!f.getName().equals(name)) - { - continue; - } - - return f; - } - } - - throw new InjectionException(String.format("Mapped field \"%s\" could not be found.", name)); - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectionException.java b/injector-plugin/src/main/java/net/runelite/injector/InjectionException.java deleted file mode 100644 index 7881ba739e..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectionException.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -public class InjectionException extends Exception -{ - public InjectionException(String message) - { - super(message); - } - - public InjectionException(Throwable cause) - { - super(cause); - } - - public InjectionException(String message, Throwable cause) - { - super(message, cause); - } - -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/Injector.java b/injector-plugin/src/main/java/net/runelite/injector/Injector.java deleted file mode 100644 index 4543ed5b46..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/Injector.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.io.File; -import java.io.IOException; - -import com.google.common.io.Files; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.deob.util.JarUtil; - -public class Injector -{ - private final ClassGroup deobfuscated, vanilla; - - public Injector(ClassGroup deobfuscated, ClassGroup vanilla) - { - this.deobfuscated = deobfuscated; - this.vanilla = vanilla; - } - - public static void main(String[] args) throws IOException, InjectionException - { - if (args.length < 3) - { - System.exit(-1); - } - - ClassGroup deobfuscated = JarUtil.loadJar(new File(args[0])); - ClassGroup vanilla = JarUtil.loadJar(new File(args[1])); - - Injector u = new Injector( - deobfuscated, - vanilla - ); - u.inject(); - - InjectorValidator iv = new InjectorValidator(vanilla); - iv.validate(); - - u.save(new File(args[2])); - } - - public void inject() throws InjectionException - { - Inject instance = new Inject(deobfuscated, vanilla); - instance.run(); - } - - private void save(File out) throws IOException - { - out.mkdirs(); - for (ClassFile cf : vanilla.getClasses()) - { - File f = new File(out, cf.getClassName() + ".class"); - byte[] data = JarUtil.writeClass(vanilla, cf); - Files.write(data, f); - } - } - - -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java b/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java deleted file mode 100644 index a49df63a3a..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/InjectorValidator.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; -import net.runelite.asm.ClassFile; -import net.runelite.asm.ClassGroup; -import net.runelite.asm.signature.Signature; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Verifies the injected jar is valid - * - * @author Adam - */ -class InjectorValidator -{ - private static final Logger logger = LoggerFactory.getLogger(InjectorValidator.class); - - private static final String API_PACKAGE_BASE = "net/runelite/rs/api/"; - - private final ClassGroup group; - - private int error, missing, okay; - - InjectorValidator(ClassGroup group) - { - this.group = group; - } - - void validate() - { - for (ClassFile cf : group.getClasses()) - { - validate(cf); - } - - logger.info("{} overridden methods, {} missing", okay, missing); - } - - private void validate(ClassFile cf) - { - // find methods of the interface not implemented in the class - for (net.runelite.asm.pool.Class clazz : cf.getInterfaces().getInterfaces()) - { - if (!clazz.getName().startsWith(API_PACKAGE_BASE)) - { - continue; - } - - Class c; - try - { - c = Class.forName(clazz.getName().replace('/', '.')); - } - catch (ClassNotFoundException ex) - { - logger.warn(null, ex); - continue; - } - - if (cf.isAbstract()) - { - // Abstract classes don't have to implement anything - continue; - } - - for (Method method : c.getMethods()) - { - if (method.isSynthetic() || method.isDefault()) - { - continue; - } - - // could check method signature here too but it is - // annoying to deal with both runelite api and java - // reflection api - if (cf.findMethodDeep(method.getName()) == null) - { - logger.warn("Class {} implements interface {} but not does implement method {}", - cf.getName(), c.getSimpleName(), method); - ++missing; - } - else - { - ++okay; - } - } - } - - Set signatures = new HashSet<>(); - - for (net.runelite.asm.Method method : cf.getMethods()) - { - NameAndSignature nas = new NameAndSignature(method.getName(), method.getDescriptor()); - - if (signatures.contains(nas)) - { - logger.error("Class {} has duplicate method with same name and signature {} {}", - cf.getName(), method.getName(), method.getDescriptor()); - ++error; - } - - signatures.add(nas); - } - } - - int getError() - { - return error; - } - - int getMissing() - { - return missing; - } - - int getOkay() - { - return okay; - } - - static final class NameAndSignature - { - String name; - Signature signature; - - NameAndSignature(String name, Signature signature) - { - this.name = name; - this.signature = signature; - } - - @Override - public int hashCode() - { - int hash = 3; - hash = 67 * hash + Objects.hashCode(this.name); - hash = 67 * hash + Objects.hashCode(this.signature); - return hash; - } - - @Override - public boolean equals(Object obj) - { - if (this == obj) - { - return true; - } - if (obj == null) - { - return false; - } - if (getClass() != obj.getClass()) - { - return false; - } - final NameAndSignature other = (NameAndSignature) obj; - if (!Objects.equals(this.name, other.name)) - { - return false; - } - if (!Objects.equals(this.signature, other.signature)) - { - return false; - } - return true; - } - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java b/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java deleted file mode 100644 index bf4627c785..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/MixinInjector.java +++ /dev/null @@ -1,998 +0,0 @@ -/* - * Copyright (c) 2017, Adam - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package net.runelite.injector; - -import com.google.common.reflect.ClassPath; -import com.google.common.reflect.ClassPath.ClassInfo; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import net.runelite.api.mixins.Mixin; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Field; -import net.runelite.asm.Method; -import net.runelite.asm.Type; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.annotation.Annotation; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instruction.types.FieldInstruction; -import net.runelite.asm.attributes.code.instruction.types.InvokeInstruction; -import net.runelite.asm.attributes.code.instruction.types.LVTInstruction; -import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction; -import net.runelite.asm.attributes.code.instruction.types.ReturnInstruction; -import net.runelite.asm.attributes.code.instructions.ALoad; -import net.runelite.asm.attributes.code.instructions.ANewArray; -import net.runelite.asm.attributes.code.instructions.CheckCast; -import net.runelite.asm.attributes.code.instructions.GetField; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.InvokeDynamic; -import net.runelite.asm.attributes.code.instructions.InvokeSpecial; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.Pop; -import net.runelite.asm.attributes.code.instructions.PutField; -import net.runelite.asm.signature.Signature; -import net.runelite.asm.visitors.ClassFileVisitor; -import net.runelite.deob.DeobAnnotations; -import static net.runelite.injector.InjectUtil.findStaticMethod; -import static net.runelite.injector.InjectUtil.toDeobClass; -import static net.runelite.injector.InjectUtil.toObClass; -import static net.runelite.injector.InjectUtil.toObField; -import org.objectweb.asm.ClassReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class MixinInjector -{ - private static final Logger logger = LoggerFactory.getLogger(MixinInjector.class); - - private static final Type INJECT = new Type("Lnet/runelite/api/mixins/Inject;"); - private static final Type SHADOW = new Type("Lnet/runelite/api/mixins/Shadow;"); - private static final Type COPY = new Type("Lnet/runelite/api/mixins/Copy;"); - private static final Type REPLACE = new Type("Lnet/runelite/api/mixins/Replace;"); - private static final Type FIELDHOOK = new Type("Lnet/runelite/api/mixins/FieldHook;"); - private static final Type METHODHOOK = new Type("Lnet/runelite/api/mixins/MethodHook;"); - private static final Type JAVAX_INJECT = new Type("Ljavax/inject/Inject;"); - private static final Type NAMED = new Type("Ljavax/inject/Named;"); - - private static final String MIXIN_BASE = "net.runelite.mixins"; - private static final String ASSERTION_FIELD = "$assertionsDisabled"; - - private final Inject inject; - - // field name -> Field of injected fields - private final Map injectedFields = new HashMap<>(); - // Use net.runelite.asm.pool.Field instead of Field because the pool version has hashcode implemented - private final Map shadowFields = new HashMap<>(); - - MixinInjector(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - ClassPath classPath; - - try - { - classPath = ClassPath.from(this.getClass().getClassLoader()); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - // key: mixin class - // value: mixin targets - Map, List> mixinClasses = new HashMap<>(); - - // Find mixins and populate mixinClasses - for (ClassInfo classInfo : classPath.getTopLevelClasses(MIXIN_BASE)) - { - Class mixinClass = classInfo.load(); - List mixinTargets = new ArrayList<>(); - - for (Mixin mixin : mixinClass.getAnnotationsByType(Mixin.class)) - { - Class implementInto = mixin.value(); - - ClassFile targetCf = inject.findVanillaForInterface(implementInto); - - if (targetCf == null) - { - throw new InjectionException("No class implements " + implementInto + " for mixin " + mixinClass); - } - - mixinTargets.add(targetCf); - } - - mixinClasses.put(mixinClass, mixinTargets); - } - - inject(mixinClasses); - } - - public void inject(Map, List> mixinClasses) throws InjectionException - { - injectFields(mixinClasses); - findShadowFields(mixinClasses); - - for (Class mixinClass : mixinClasses.keySet()) - { - try - { - for (ClassFile cf : mixinClasses.get(mixinClass)) - { - // Make a new mixin ClassFile copy every time, - // so they don't share Code references - ClassFile mixinCf = loadClass(mixinClass); - - injectMethods(mixinCf, cf, shadowFields); - } - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - } - - injectFieldHooks(mixinClasses); - injectMethodHooks(mixinClasses); - } - - /** - * Finds fields that are marked @Inject and inject them into the target - */ - private void injectFields(Map, List> mixinClasses) throws InjectionException - { - // Inject fields, and put them in injectedFields if they can be used by other mixins - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Field field : mixinCf.getFields()) - { - // Always inject $assertionsEnabled if its missing. - if (ASSERTION_FIELD.equals(field.getName())) - { - if (cf.findField(ASSERTION_FIELD, Type.BOOLEAN) != null) - { - continue; - } - } - else - { - Annotation inject = field.getAnnotations().find(INJECT); - - if (inject == null) - { - continue; - } - } - - Field copy = new Field(cf, field.getName(), field.getType()); - copy.setAccessFlags(field.getAccessFlags()); - copy.setPublic(); - copy.setValue(field.getValue()); - - Annotation jInject = field.getAnnotations().find(JAVAX_INJECT); - if (jInject != null) - { - copy.getAnnotations().addAnnotation(jInject); - logger.info("Added javax inject to {}.{}", cf.getClassName(), copy.getName()); - - Annotation named = field.getAnnotations().find(NAMED); - if (named != null) - { - copy.getAnnotations().addAnnotation(named); - logger.info("Added javax named to {}.{}", cf.getClassName(), copy.getName()); - } - } - - cf.addField(copy); - - if (injectedFields.containsKey(field.getName()) && !field.getName().equals(ASSERTION_FIELD)) - { - java.util.logging.Logger.getAnonymousLogger().severe("Duplicate field : " + field.getName()); - throw new InjectionException("Injected field names must be globally unique"); - } - - injectedFields.put(field.getName(), copy); - } - } - - } - } - - /** - * Find fields which are marked @Shadow, and what they shadow - */ - private void findShadowFields(Map, List> mixinClasses) throws InjectionException - { - // Find shadow fields - // Injected static fields take precedence when looking up shadowed fields - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - for (Field field : mixinCf.getFields()) - { - Annotation shadow = field.getAnnotations().find(SHADOW); - if (shadow != null) - { - if (!field.isStatic()) - { - throw new InjectionException("Can only shadow static fields"); - } - - String shadowName = shadow.getElement().getString(); // shadow this field - - Field injectedField = injectedFields.get(shadowName); - if (injectedField != null) - { - // Shadow a field injected by a mixin - shadowFields.put(field.getPoolField(), injectedField); - } - else - { - // Shadow a field already in the gamepack - Field shadowField = InjectUtil.findDeobFieldButUseless(inject, shadowName); - - if (shadowField == null) - { - throw new InjectionException("Shadow of nonexistent field " + shadowName); - } - - Field obShadow = toObField(inject.getVanilla(), shadowField); - assert obShadow != null; - shadowFields.put(field.getPoolField(), obShadow); - } - } - } - } - } - - private ClassFile loadClass(Class clazz) throws IOException - { - try (InputStream is = clazz.getClassLoader().getResourceAsStream(clazz.getName().replace('.', '/') + ".class")) - { - ClassReader reader = new ClassReader(is); - ClassFileVisitor cv = new ClassFileVisitor(); - - reader.accept(cv, 0); - - return cv.getClassFile(); - } - } - - private void injectMethods(ClassFile mixinCf, ClassFile cf, Map shadowFields) - throws InjectionException - { - // Keeps mappings between methods annotated with @Copy -> the copied method within the vanilla pack - Map copiedMethods = new HashMap<>(); - - // Handle the copy mixins first, so all other mixins know of the copies - for (Method method : mixinCf.getMethods()) - { - Annotation copyAnnotation = method.getAnnotations().find(COPY); - - if (copyAnnotation == null) - { - continue; - } - - String deobMethodName = (String) copyAnnotation.getElement().getValue(); - Method deobMethod; - if (method.isStatic()) - { - deobMethod = findStaticMethod(inject.getDeobfuscated(), deobMethodName, method.getDescriptor().rsApiToRsClient()); - } - else - { - ClassFile deobCf = toDeobClass(cf, inject.getDeobfuscated()); - deobMethod = deobCf.findMethod(deobMethodName, method.getDescriptor().rsApiToRsClient()); - } - - - if (deobMethod == null) - { - throw new InjectionException("Failed to find the deob method " + deobMethodName + " for mixin " + mixinCf); - } - - if (method.isStatic() != deobMethod.isStatic()) - { - throw new InjectionException("Mixin method " + method + " should be " + (deobMethod.isStatic() ? "static" : "non-static")); - } - - // Find the vanilla class where the method to copy is in - String obClassName = DeobAnnotations.getObfuscatedName(deobMethod.getClassFile().getAnnotations()); - ClassFile obCf = inject.getVanilla().findClass(obClassName); - assert obCf != null : "unable to find vanilla class from obfuscated name " + obClassName; - - String obMethodName = DeobAnnotations.getObfuscatedName(deobMethod.getAnnotations()); - Signature obMethodSignature = DeobAnnotations.getObfuscatedSignature(deobMethod); - - if (obMethodName == null) - { - obMethodName = deobMethod.getName(); - } - if (obMethodSignature == null) - { - obMethodSignature = deobMethod.getDescriptor(); - } - - Method obMethod = obCf.findMethod(obMethodName, obMethodSignature); - if (obMethod == null) - { - throw new InjectionException("Failed to find the ob method " + obMethodName + " for mixin " + mixinCf); - } - - if (method.getDescriptor().size() > obMethod.getDescriptor().size()) - { - throw new InjectionException("Mixin methods cannot have more parameters than their corresponding ob method"); - } - - Method copy = new Method(cf, "copy$" + deobMethodName, obMethodSignature); - moveCode(copy, obMethod.getCode()); - copy.setAccessFlags(obMethod.getAccessFlags()); - copy.setPublic(); - copy.getExceptions().getExceptions().addAll(obMethod.getExceptions().getExceptions()); - copy.getAnnotations().getAnnotations().addAll(obMethod.getAnnotations().getAnnotations()); - cf.addMethod(copy); - - /* - If the desc for the mixin method and the desc for the ob method - are the same in length, assume that the mixin method is taking - care of the garbage parameter itself. - */ - boolean hasGarbageValue = method.getDescriptor().size() != obMethod.getDescriptor().size() - && deobMethod.getDescriptor().size() < obMethodSignature.size(); - copiedMethods.put(method.getPoolMethod(), new CopiedMethod(copy, hasGarbageValue)); - - logger.debug("Injected copy of {} to {}", obMethod, copy); - } - - // Handle the rest of the mixin types - for (Method method : mixinCf.getMethods()) - { - boolean isClinit = "".equals(method.getName()); - boolean isInit = "".equals(method.getName()); - boolean hasInject = method.getAnnotations().find(INJECT) != null; - - // You can't annotate clinit, so its always injected - if ((hasInject && isInit) || isClinit) - { - if (!"()V".equals(method.getDescriptor().toString())) - { - throw new InjectionException("Injected constructors cannot have arguments"); - } - - Method[] originalMethods = cf.getMethods().stream() - .filter(n -> n.getName().equals(method.getName())) - .toArray(Method[]::new); - // If there isn't a already just inject ours, otherwise rename it - // This is always true for - String name = method.getName(); - if (originalMethods.length > 0) - { - name = "rl$$" + (isInit ? "init" : "clinit"); - } - String numberlessName = name; - for (int i = 1; cf.findMethod(name, method.getDescriptor()) != null; i++) - { - name = numberlessName + i; - } - - Method copy = new Method(cf, name, method.getDescriptor()); - moveCode(copy, method.getCode()); - copy.setAccessFlags(method.getAccessFlags()); - copy.setPrivate(); - assert method.getExceptions().getExceptions().isEmpty(); - - // Remove the call to the superclass's ctor - if (isInit) - { - Instructions instructions = copy.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof InvokeSpecial) - { - InvokeSpecial invoke = (InvokeSpecial) instr; - assert invoke.getMethod().getName().equals(""); - listIter.remove(); - int pops = invoke.getMethod().getType().getArguments().size() + 1; - for (int i = 0; i < pops; i++) - { - listIter.add(new Pop(instructions)); - } - break; - } - } - } - - setOwnersToTargetClass(mixinCf, cf, copy, shadowFields, copiedMethods); - cf.addMethod(copy); - - // Call our method at the return point of the matching method(s) - for (Method om : originalMethods) - { - Instructions instructions = om.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof ReturnInstruction) - { - listIter.previous(); - if (isInit) - { - listIter.add(new ALoad(instructions, 0)); - listIter.add(new InvokeSpecial(instructions, copy.getPoolMethod())); - } - else if (isClinit) - { - listIter.add(new InvokeStatic(instructions, copy.getPoolMethod())); - } - listIter.next(); - } - } - } - - logger.debug("Injected mixin method {} to {}", copy, cf); - } - else if (hasInject) - { - // Make sure the method doesn't invoke copied methods - for (Instruction i : method.getCode().getInstructions().getInstructions()) - { - if (i instanceof InvokeInstruction) - { - InvokeInstruction ii = (InvokeInstruction) i; - - if (copiedMethods.containsKey(ii.getMethod())) - { - throw new InjectionException("Injected methods cannot invoke copied methods"); - } - } - } - - Method copy = new Method(cf, method.getName(), method.getDescriptor()); - moveCode(copy, method.getCode()); - copy.setAccessFlags(method.getAccessFlags()); - copy.setPublic(); - assert method.getExceptions().getExceptions().isEmpty(); - - setOwnersToTargetClass(mixinCf, cf, copy, shadowFields, copiedMethods); - - cf.addMethod(copy); - - logger.debug("Injected mixin method {} to {}", copy, cf); - } - else if (method.getAnnotations().find(REPLACE) != null) - { - Annotation replaceAnnotation = method.getAnnotations().find(REPLACE); - String deobMethodName = (String) replaceAnnotation.getElement().getValue(); - - ClassFile deobCf = inject.toDeobClass(cf); - Method deobMethod = findDeobMethod(deobCf, deobMethodName, method.getDescriptor()); - - if (deobMethod == null) - { - throw new InjectionException("Failed to find the deob method " + deobMethodName + " for mixin " + mixinCf); - } - - if (method.isStatic() != deobMethod.isStatic()) - { - throw new InjectionException("Mixin method " + method + " should be " - + (deobMethod.isStatic() ? "static" : "non-static")); - } - - String obMethodName = DeobAnnotations.getObfuscatedName(deobMethod.getAnnotations()); - Signature obMethodSignature = DeobAnnotations.getObfuscatedSignature(deobMethod); - - // Deob signature is the same as ob signature - if (obMethodName == null) - { - obMethodName = deobMethod.getName(); - } - if (obMethodSignature == null) - { - obMethodSignature = deobMethod.getDescriptor(); - } - - // Find the vanilla class where the method to copy is in - String obClassName = DeobAnnotations.getObfuscatedName(deobMethod.getClassFile().getAnnotations()); - ClassFile obCf = inject.getVanilla().findClass(obClassName); - - Method obMethod = obCf.findMethod(obMethodName, obMethodSignature); - assert obMethod != null : "obfuscated method " + obMethodName + obMethodSignature + " does not exist"; - - if (method.getDescriptor().size() > obMethod.getDescriptor().size()) - { - throw new InjectionException("Mixin methods cannot have more parameters than their corresponding ob method"); - } - - Type returnType = method.getDescriptor().getReturnValue(); - Type deobReturnType = inject.apiTypeToDeobfuscatedType(returnType); - if (!returnType.equals(deobReturnType)) - { - ClassFile deobReturnTypeClassFile = inject.getDeobfuscated() - .findClass(deobReturnType.getInternalName()); - if (deobReturnTypeClassFile != null) - { - ClassFile obReturnTypeClass = toObClass(inject.getVanilla(), deobReturnTypeClassFile); - - Instructions instructions = method.getCode().getInstructions(); - ListIterator listIter = instructions.getInstructions().listIterator(); - for (; listIter.hasNext(); ) - { - Instruction instr = listIter.next(); - if (instr instanceof ReturnInstruction) - { - listIter.previous(); - CheckCast checkCast = new CheckCast(instructions); - checkCast.setType(new Type(obReturnTypeClass.getName())); - listIter.add(checkCast); - listIter.next(); - } - } - } - } - - moveCode(obMethod, method.getCode()); - - boolean hasGarbageValue = method.getDescriptor().size() != obMethod.getDescriptor().size() - && deobMethod.getDescriptor().size() < obMethodSignature.size(); - - if (hasGarbageValue) - { - int garbageIndex = obMethod.isStatic() - ? obMethod.getDescriptor().size() - 1 - : obMethod.getDescriptor().size(); - - /* - If the mixin method doesn't have the garbage parameter, - the compiler will have produced code that uses the garbage - parameter's local variable index for other things, - so we'll have to add 1 to all loads/stores to indices - that are >= garbageIndex. - */ - shiftLocalIndices(obMethod.getCode().getInstructions(), garbageIndex); - } - - setOwnersToTargetClass(mixinCf, cf, obMethod, shadowFields, copiedMethods); - - logger.debug("Replaced method {} with mixin method {}", obMethod, method); - } - } - } - - private void moveCode(Method method, Code code) - { - Code newCode = new Code(method); - newCode.setMaxStack(code.getMaxStack()); - newCode.getInstructions().getInstructions().addAll(code.getInstructions().getInstructions()); - // Update instructions for each instruction - for (Instruction i : newCode.getInstructions().getInstructions()) - { - i.setInstructions(newCode.getInstructions()); - } - newCode.getExceptions().getExceptions().addAll(code.getExceptions().getExceptions()); - for (net.runelite.asm.attributes.code.Exception e : newCode.getExceptions().getExceptions()) - { - e.setExceptions(newCode.getExceptions()); - } - method.setCode(newCode); - } - - private void setOwnersToTargetClass(ClassFile mixinCf, ClassFile cf, Method method, - Map shadowFields, - Map copiedMethods) - throws InjectionException - { - ListIterator iterator = method.getCode().getInstructions().getInstructions().listIterator(); - - while (iterator.hasNext()) - { - Instruction i = iterator.next(); - - if (i instanceof ANewArray) - { - Type type = ((ANewArray) i).getType_(); - ClassFile deobCf = inject.getDeobfuscated().findClass(type.toString().replace("Lnet/runelite/rs/api/RS", "").replace(";", "")); - - if (deobCf != null) - { - ClassFile obReturnTypeClass = toObClass(inject.getVanilla(), deobCf); - Type newType = new Type("L" + obReturnTypeClass.getName() + ";"); - - ((ANewArray) i).setType(newType); - logger.info("Replaced {} type {} with type {}", i, type, newType); - } - } - - if (i instanceof InvokeInstruction) - { - InvokeInstruction ii = (InvokeInstruction) i; - - CopiedMethod copiedMethod = copiedMethods.get(ii.getMethod()); - if (copiedMethod != null) - { - ii.setMethod(copiedMethod.obMethod.getPoolMethod()); - - // Pass through garbage value if the method has one - if (copiedMethod.hasGarbageValue) - { - int garbageIndex = copiedMethod.obMethod.isStatic() - ? copiedMethod.obMethod.getDescriptor().size() - 1 - : copiedMethod.obMethod.getDescriptor().size(); - - iterator.previous(); - iterator.add(new ILoad(method.getCode().getInstructions(), garbageIndex)); - iterator.next(); - } - } - else if (ii.getMethod().getClazz().getName().equals(mixinCf.getName())) - { - ii.setMethod(new net.runelite.asm.pool.Method( - new net.runelite.asm.pool.Class(cf.getName()), - ii.getMethod().getName(), - ii.getMethod().getType() - )); - } - } - else if (i instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) i; - - Field shadowed = shadowFields.get(fi.getField()); - if (shadowed != null) - { - fi.setField(shadowed.getPoolField()); - } - else if (fi.getField().getClazz().getName().equals(mixinCf.getName())) - { - fi.setField(new net.runelite.asm.pool.Field( - new net.runelite.asm.pool.Class(cf.getName()), - fi.getField().getName(), - fi.getField().getType() - )); - } - } - else if (i instanceof PushConstantInstruction) - { - PushConstantInstruction pi = (PushConstantInstruction) i; - if (mixinCf.getPoolClass().equals(pi.getConstant())) - { - pi.setConstant(cf.getPoolClass()); - } - } - - verify(mixinCf, i); - } - } - - private void shiftLocalIndices(Instructions instructions, int startIdx) - { - for (Instruction i : instructions.getInstructions()) - { - if (i instanceof LVTInstruction) - { - LVTInstruction lvti = (LVTInstruction) i; - - if (lvti.getVariableIndex() >= startIdx) - { - lvti.setVariableIndex(lvti.getVariableIndex() + 1); - } - } - } - } - - private Method findDeobMethod(ClassFile deobCf, String deobMethodName, Signature descriptor) - throws InjectionException - { - List matchingMethods = new ArrayList<>(); - - for (Method m : deobCf.getMethods()) - { - if (!deobMethodName.equals(m.getName())) - { - continue; - } - - Type returnType = inject.apiTypeToDeobfuscatedType(descriptor.getReturnValue()); - Type returnType2 = m.getDescriptor().getReturnValue(); - - if (!returnType.equals(returnType2)) - { - continue; - } - - List args = descriptor.getArguments(); - List args2 = m.getDescriptor().getArguments(); - - if (args.size() > args2.size()) - { - continue; - } - - boolean matchingArgs = true; - - for (int i = 0; i < args.size(); i++) - { - Type type = inject.apiTypeToDeobfuscatedType(args.get(i)); - Type type2 = args2.get(i); - - if (!type.equals(type2)) - { - matchingArgs = false; - break; - } - } - - if (!matchingArgs) - { - continue; - } - - matchingMethods.add(m); - } - - if (matchingMethods.size() > 1) - { - // this happens when it has found several deob methods for some mixin method, - // to get rid of the error, refine your search by making your mixin method have more parameters - throw new InjectionException("There are several matching methods when there should only be one"); - } - else if (matchingMethods.size() == 1) - { - return matchingMethods.get(0); - } - - Method method = deobCf.findMethod(deobMethodName); - - if (method == null) - { - // Look for static methods if an instance method couldn't be found - for (ClassFile deobCf2 : inject.getDeobfuscated().getClasses()) - { - if (deobCf2 != deobCf) - { - method = deobCf2.findMethod(deobMethodName); - - if (method != null) - { - break; - } - } - } - } - - return method; - } - - private void verify(ClassFile mixinCf, Instruction i) throws InjectionException - { - if (i instanceof FieldInstruction) - { - FieldInstruction fi = (FieldInstruction) i; - - if (fi.getField().getClazz().getName().equals(mixinCf.getName())) - { - if (i instanceof PutField || i instanceof GetField) - { - throw new InjectionException("Access to non static member field of mixin"); - } - - Field field = fi.getMyField(); - if (field != null && !field.isPublic()) - { - throw new InjectionException("Static access to non public field " + field); - } - } - } - else if (i instanceof InvokeStatic) - { - InvokeStatic is = (InvokeStatic) i; - - if (is.getMethod().getClazz() != mixinCf.getPoolClass() - && is.getMethod().getClazz().getName().startsWith(MIXIN_BASE.replace(".", "/"))) - { - throw new InjectionException("Invoking static methods of other mixins is not supported"); - } - } - else if (i instanceof InvokeDynamic) - { - // RS classes don't verify under java 7+ due to the - // super() invokespecial being inside of a try{} - throw new InjectionException("Injected bytecode must be Java 6 compatible"); - } - } - - private void injectFieldHooks(Map, List> mixinClasses) throws InjectionException - { - InjectHook injectHook = new InjectHook(inject); - - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Method method : mixinCf.getMethods()) - { - Annotation fieldHook = method.getAnnotations().find(FIELDHOOK); - if (fieldHook != null) - { - String hookName = fieldHook.getElement().getString(); - boolean before = fieldHook.getElements().size() == 2 && fieldHook.getElements().get(1).getValue().equals(true); - ClassFile deobCf = inject.toDeobClass(cf); - Field targetField = deobCf.findField(hookName); - if (targetField == null) - { - // first try non static fields, then static - targetField = InjectUtil.findDeobFieldButUseless(inject, hookName); - } - - if (targetField == null) - { - throw new InjectionException("Field hook for nonexistent field " + hookName + " on " + method); - } - - Annotation an = targetField.getAnnotations().find(DeobAnnotations.OBFUSCATED_GETTER); - Number getter = null; - if (an != null) - { - getter = (Number) an.getElement().getValue(); - } - - Field obField = toObField(inject.getVanilla(), targetField); - - if (method.isStatic() != targetField.isStatic()) - { - throw new InjectionException("Field hook method static flag must match target field"); - } - - // cf is the target class to invoke - InjectHook.HookInfo hookInfo = new InjectHook.HookInfo(); - hookInfo.clazz = cf.getName(); - hookInfo.fieldName = hookName; - hookInfo.method = method; - hookInfo.before = before; - hookInfo.getter = getter; - injectHook.hook(obField, hookInfo); - } - } - } - } - - injectHook.run(); - - logger.info("Injected {} field hooks", injectHook.getInjectedHooks()); - } - - private void injectMethodHooks(Map, List> mixinClasses) throws InjectionException - { - InjectHookMethod injectHookMethod = new InjectHookMethod(inject); - - for (Class mixinClass : mixinClasses.keySet()) - { - ClassFile mixinCf; - - try - { - mixinCf = loadClass(mixinClass); - } - catch (IOException ex) - { - throw new InjectionException(ex); - } - - List targetCfs = mixinClasses.get(mixinClass); - - for (ClassFile cf : targetCfs) - { - for (Method method : mixinCf.getMethods()) - { - Annotation methodHook = method.getAnnotations().find(METHODHOOK); - - if (methodHook == null) - { - continue; - } - - String hookName = methodHook.getElement().getString(); - boolean end = methodHook.getElements().size() == 2 && methodHook.getElements().get(1).getValue().equals(true); - ClassFile deobCf = inject.toDeobClass(cf); - Method targetMethod = findDeobMethod(deobCf, hookName, method.getDescriptor()); - - if (targetMethod == null) - { - throw new InjectionException("Method hook for nonexistent method " + hookName + " on " + method); - } - - if (method.isStatic() != targetMethod.isStatic()) - { - throw new InjectionException("Method hook static flag must match target - " + hookName); - } - - injectHookMethod.inject(method, targetMethod, hookName, end, false); - } - } - } - } - - private static class CopiedMethod - { - private Method obMethod; - private boolean hasGarbageValue; - - private CopiedMethod(Method obMethod, boolean hasGarbageValue) - { - this.obMethod = obMethod; - this.hasGarbageValue = hasGarbageValue; - } - } -} diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java b/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java deleted file mode 100644 index f4de5d056e..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/raw/ClearColorBuffer.java +++ /dev/null @@ -1,124 +0,0 @@ -package net.runelite.injector.raw; - -import java.util.ListIterator; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.Code; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.instructions.ILoad; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.attributes.code.instructions.LDC; -import net.runelite.asm.pool.Class; -import net.runelite.asm.signature.Signature; -import net.runelite.injector.Inject; -import net.runelite.injector.InjectUtil; -import net.runelite.injector.InjectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ClearColorBuffer -{ - private static final Logger log = LoggerFactory.getLogger(ClearColorBuffer.class); - private static final net.runelite.asm.pool.Method clearBuffer = new net.runelite.asm.pool.Method( - new Class("net.runelite.client.callback.Hooks"), - "clearColorBuffer", - new Signature("(IIIII)V") - ); - private final Inject inject; - - public ClearColorBuffer(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - injectColorBufferHooks(); - } - - private void injectColorBufferHooks() throws InjectionException - { - net.runelite.asm.pool.Method fillRectangle = InjectUtil.findStaticMethod(inject, "Rasterizer2D_fillRectangle").getPoolMethod(); - - int count = 0; - int replaced = 0; - - for (ClassFile cf : inject.getVanilla().getClasses()) - { - for (Method m : cf.getMethods()) - { - if (!m.isStatic()) - { - continue; - } - - Code c = m.getCode(); - if (c == null) - { - continue; - } - - Instructions ins = c.getInstructions(); - ListIterator it = ins.getInstructions().listIterator(); - - for (; it.hasNext(); ) - { - Instruction i = it.next(); - if (!(i instanceof InvokeStatic)) - { - continue; - } - - if (!((InvokeStatic) i).getMethod().equals(fillRectangle)) - { - continue; - } - - int indexToReturnTo = it.nextIndex(); - count++; - it.previous(); - Instruction current = it.previous(); - if (current instanceof LDC && ((LDC) current).getConstantAsInt() == 0) - { - int varIdx = 0; - for (; ; ) - { - current = it.previous(); - if (current instanceof ILoad && ((ILoad) current).getVariableIndex() == 3 - varIdx) - { - varIdx++; - log.debug(varIdx + " we can count yay"); - continue; - } - - break; - } - - if (varIdx == 4) - { - for (; !(current instanceof InvokeStatic); ) - { - current = it.next(); - } - assert it.nextIndex() == indexToReturnTo; - - it.set(new InvokeStatic(ins, clearBuffer)); - replaced++; - log.debug("Found drawRectangle at {}. Found: {}, replaced {}", m.getName(), count, replaced); - } - else - { - log.debug("Welp, guess this wasn't it chief " + m); - } - } - - while (it.nextIndex() != indexToReturnTo) - { - it.next(); - } - } - } - } - } -} \ No newline at end of file diff --git a/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java b/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java deleted file mode 100644 index 5b6f6fbd50..0000000000 --- a/injector-plugin/src/main/java/net/runelite/injector/raw/DrawAfterWidgets.java +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (c) 2018, Lotto - * 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.injector.raw; - -import java.util.HashSet; -import java.util.ListIterator; -import java.util.Set; -import net.runelite.asm.ClassFile; -import net.runelite.asm.Method; -import net.runelite.asm.attributes.code.Instruction; -import net.runelite.asm.attributes.code.Instructions; -import net.runelite.asm.attributes.code.Label; -import net.runelite.asm.attributes.code.instruction.types.JumpingInstruction; -import net.runelite.asm.attributes.code.instruction.types.PushConstantInstruction; -import net.runelite.asm.attributes.code.instructions.GetStatic; -import net.runelite.asm.attributes.code.instructions.IMul; -import net.runelite.asm.attributes.code.instructions.InvokeStatic; -import net.runelite.asm.signature.Signature; -import net.runelite.injector.Inject; -import static net.runelite.injector.InjectHookMethod.HOOKS; -import static net.runelite.injector.InjectUtil.findStaticMethod; -import net.runelite.injector.InjectionException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class DrawAfterWidgets -{ - private static final Logger logger = LoggerFactory.getLogger(DrawAfterWidgets.class); - - private final Inject inject; - - public DrawAfterWidgets(Inject inject) - { - this.inject = inject; - } - - public void inject() throws InjectionException - { - injectDrawAfterWidgets(); - } - - private void injectDrawAfterWidgets() throws InjectionException - { - /* - This call has to be injected using raw injection because the - drawWidgets method gets inlined in some revisions. If it wouldn't be, - mixins would be used to add the call to the end of drawWidgets. - - --> This hook depends on the positions of "if (535573958 * kl != -1)" and "jz.db();". - - - Revision 180 - client.gs(): - ______________________________________________________ - - @Export("drawLoggedIn") - final void drawLoggedIn() { - if(rootInterface != -1) { - ClientPreferences.method1809(rootInterface); - } - - int var1; - for(var1 = 0; var1 < rootWidgetCount; ++var1) { - if(__client_od[var1]) { - __client_ot[var1] = true; - } - - __client_oq[var1] = __client_od[var1]; - __client_od[var1] = false; - } - - __client_oo = cycle; - __client_lq = -1; - __client_ln = -1; - UserComparator6.__fg_jh = null; - if(rootInterface != -1) { - rootWidgetCount = 0; - Interpreter.method1977(rootInterface, 0, 0, SoundCache.canvasWidth, Huffman.canvasHeight, 0, 0, -1); - } - - < -- here appearantly - - Rasterizer2D.Rasterizer2D_resetClip(); - ______________________________________________________ - */ - - boolean injected = false; - - Method noClip = findStaticMethod(inject, "Rasterizer2D_resetClip"); // !!!!! - - if (noClip == null) - { - throw new InjectionException("Mapped method \"Rasterizer2D_resetClip\" could not be found."); - } - - net.runelite.asm.pool.Method poolNoClip = noClip.getPoolMethod(); - - for (ClassFile c : inject.getVanilla().getClasses()) - { - for (Method m : c.getMethods()) - { - if (m.getCode() == null) - { - continue; - } - - Instructions instructions = m.getCode().getInstructions(); - - Set