diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index c9e857a099..c3313ffc76 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -1894,6 +1894,14 @@ public interface Client extends OAuthApi, GameEngine */ void setBlacklistDeadNpcs(Set blacklist); + /** + * Adds a custom clientscript to the list of available clientscripts. + * + * @param script compiled clientscript code + * @return the id of the newly-added script + */ + int addClientScript(byte[] script); + /** * Gets an array of tile collision data. *

diff --git a/runelite-api/src/main/java/net/runelite/api/overlay/OverlayIndex.java b/runelite-api/src/main/java/net/runelite/api/overlay/OverlayIndex.java index 9af2b6cc35..5263a255eb 100644 --- a/runelite-api/src/main/java/net/runelite/api/overlay/OverlayIndex.java +++ b/runelite-api/src/main/java/net/runelite/api/overlay/OverlayIndex.java @@ -29,11 +29,13 @@ import java.io.IOException; import java.io.InputStream; import java.util.HashSet; import java.util.Set; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; @Slf4j public class OverlayIndex { + @Getter private static final Set overlays = new HashSet<>(); static diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSAbstractArchiveMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSAbstractArchiveMixin.java index 854ad7fab0..03226f81fc 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSAbstractArchiveMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSAbstractArchiveMixin.java @@ -1,14 +1,11 @@ package net.runelite.mixins; -import com.google.common.base.Charsets; import com.google.common.hash.Hashing; import com.google.common.io.ByteStreams; import com.google.common.io.CharStreams; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.List; import java.util.Map; import net.runelite.api.mixins.Copy; import net.runelite.api.mixins.Inject; @@ -19,7 +16,6 @@ import net.runelite.api.overlay.OverlayIndex; import net.runelite.rs.api.RSAbstractArchive; import net.runelite.rs.api.RSArchive; import net.runelite.rs.api.RSClient; -import org.apache.commons.io.IOUtils; import org.slf4j.Logger; @Mixin(RSAbstractArchive.class) @@ -28,11 +24,11 @@ public abstract class RSAbstractArchiveMixin implements RSAbstractArchive @Shadow("client") private static RSClient client; - @Inject - private boolean overlayOutdated; + @Shadow("customClientScripts") + private static Map customClientScripts; @Inject - private Map scriptNames; + private boolean overlayOutdated; @Inject @Override @@ -54,34 +50,6 @@ public abstract class RSAbstractArchiveMixin implements RSAbstractArchive return rsData; } - if (scriptNames == null) - try - { - scriptNames = new HashMap<>(); - InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("scripts/"); - if (is != null) - { - List files = IOUtils.readLines(is, Charsets.UTF_8); - for (String s : files) - { - if (s.endsWith(".rs2asm")) - continue; - - String scriptName = s.replace(".hash", ""); - InputStream hashStream = ClassLoader.getSystemClassLoader().getResourceAsStream("scripts/" + scriptName + ".hash"); - if (hashStream != null) - { - String scriptHash = (String) IOUtils.readLines(hashStream, Charsets.UTF_8).toArray()[0]; - scriptNames.put(scriptHash, scriptName); - } - } - } - } - catch (IOException e) - { - e.printStackTrace(); - } - final Logger log = client.getLogger(); final String path = String.format("/runelite/%s/%s", archiveId, groupId); @@ -105,12 +73,16 @@ public abstract class RSAbstractArchiveMixin implements RSAbstractArchive if (!overlayHash.equalsIgnoreCase(originalHash)) { log.error("Script " + groupId + " is invalid, and will not be overlaid. This will break plugin(s)!"); - client.setOutdatedScript(scriptNames.get(overlayHash)); overlayOutdated = true; return rsData; } } + if (customClientScripts.containsKey(archiveId << 16 | groupId)) + { + return customClientScripts.get(archiveId << 16 | groupId); + } + try (final InputStream ovlIn = getClass().getResourceAsStream(path)) { return ByteStreams.toByteArray(ovlIn); diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java index d1a1b4299a..aa1bff19cb 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSClientMixin.java @@ -33,6 +33,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -132,6 +133,7 @@ import net.runelite.api.mixins.MethodHook; import net.runelite.api.mixins.Mixin; import net.runelite.api.mixins.Replace; import net.runelite.api.mixins.Shadow; +import net.runelite.api.overlay.OverlayIndex; import net.runelite.api.vars.AccountType; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetConfig; @@ -315,6 +317,9 @@ public abstract class RSClientMixin implements RSClient @Inject private static int tmpMenuOptionsCount; + @Inject + private static final Map customClientScripts = new HashMap<>(); + @Inject @Override public void setPrintMenuActions(boolean yes) @@ -3055,5 +3060,37 @@ public abstract class RSClientMixin implements RSClient return null; } + + @Inject + @Override + public int addClientScript(byte[] script) + { + assert this.isClientThread() : "addClientScript must be called on client thread"; + + int highestUsedScript = -1; + for (int index : OverlayIndex.getOverlays()) + { + if ((index >> 16) != 12) + { + continue; + } + + int scriptId = index & 0xFFFF; + if (scriptId > highestUsedScript) + { + highestUsedScript = scriptId; + } + } + + if (highestUsedScript == -1) + { + highestUsedScript = 10000; + } + + int newScriptId = highestUsedScript + 1; + OverlayIndex.getOverlays().add((12 << 16) | newScriptId); + customClientScripts.put((12 << 16) | newScriptId, script); + return newScriptId; + } }