Merge pull request #2726 from ThatGamerBlue/scriptvm

mixins: make scriptvm more reliable
This commit is contained in:
Lucwousin
2020-06-28 17:17:20 +02:00
committed by GitHub
3 changed files with 66 additions and 130 deletions

View File

@@ -29,13 +29,13 @@ import org.ajoberstar.grgit.Grgit
buildscript {
repositories {
gradlePluginPortal()
mavenLocal()
maven(url = "https://repo.openosrs.com/repository/maven/")
maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master")
}
dependencies {
classpath("org.ajoberstar.grgit:grgit-core:4.0.2")
classpath("com.github.ben-manes:gradle-versions-plugin:0.28.0")
classpath("com.openosrs:injector-plugin:1.1.3")
classpath("com.openosrs:injector-plugin:1.1.4")
}
}

View File

@@ -24,22 +24,22 @@
*/
package net.runelite.api.events;
import lombok.Data;
import lombok.Value;
import net.runelite.api.ScriptEvent;
/**
* An event that is fired before the designated script is ran
*/
@Data
@Value
public class ScriptPreFired implements Event
{
/**
* The script id of the invoked script
*/
private final int scriptId;
int scriptId;
/**
* The input of the script invoke, this will be null unless it is the root script
*/
private ScriptEvent scriptEvent;
ScriptEvent scriptEvent;
}

View File

@@ -25,14 +25,9 @@
*/
package net.runelite.mixins;
import java.util.ArrayList;
import java.util.Stack;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.runelite.api.Client;
import static net.runelite.api.Opcodes.INVOKE;
import static net.runelite.api.Opcodes.RETURN;
import static net.runelite.api.Opcodes.RUNELITE_EXECUTE;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.ScriptPostFired;
import net.runelite.api.events.ScriptPreFired;
@@ -45,6 +40,7 @@ import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.rs.api.RSClient;
import net.runelite.rs.api.RSScript;
import net.runelite.rs.api.RSScriptEvent;
import static net.runelite.api.Opcodes.*;
@Mixin(RSClient.class)
public abstract class ScriptVMMixin implements RSClient
@@ -52,7 +48,6 @@ public abstract class ScriptVMMixin implements RSClient
@Shadow("client")
private static Client client;
// This field is set by the ScriptVM raw injector
@Inject
private static RSScript currentScript;
@@ -60,23 +55,20 @@ public abstract class ScriptVMMixin implements RSClient
@Inject
private static int currentScriptPC;
// Call is injected by the raw injector
@Inject
private static ScriptPostFired deferredEvent = null;
@Inject
private static Stack<Integer> scriptIds = new Stack<>();
static void setCurrentScript(RSScript script)
{
currentScript = script;
}
// Call is injected into runScript by the ScriptVM raw injector
@Inject
static boolean vmExecuteOpcode(int opcode)
{
if (deferredEvent != null)
{
client.getCallbacks().post(ScriptPostFired.class, deferredEvent);
deferredEvent = null;
}
if (opcode == RUNELITE_EXECUTE)
switch (opcode)
{
case RUNELITE_EXECUTE:
assert currentScript.getInstructions()[currentScriptPC] == RUNELITE_EXECUTE;
int stringStackSize = client.getStringStackSize();
@@ -90,7 +82,7 @@ public abstract class ScriptVMMixin implements RSClient
String fmt = client.getStringStack()[--stringStackSize];
StringBuffer out = new StringBuffer();
Matcher m = Pattern.compile("%(.)").matcher(fmt);
for (; m.find(); )
while (m.find())
{
m.appendReplacement(out, "");
switch (m.group(1).charAt(0))
@@ -120,21 +112,13 @@ public abstract class ScriptVMMixin implements RSClient
event.setEventName(stringOp);
client.getCallbacks().post(ScriptCallbackEvent.class, event);
return true;
}
else if (opcode == INVOKE)
{
int id = currentScript.getIntOperands()[currentScriptPC];
scriptIds.push(id);
ScriptPreFired event = new ScriptPreFired(id);
event.setScriptEvent(null);
client.getCallbacks().post(ScriptPreFired.class, event);
}
else if (opcode == RETURN)
{
if (scriptIds.size() > 1) // let the runScript method handle the final script
{
deferredEvent = new ScriptPostFired(scriptIds.pop()); // fire the event when we've left the script
}
case INVOKE:
int scriptId = currentScript.getIntOperands()[currentScriptPC];
client.getCallbacks().post(ScriptPreFired.class, new ScriptPreFired(scriptId, null));
return false;
case RETURN:
client.getCallbacks().post(ScriptPostFired.class, new ScriptPostFired((int) currentScript.getHash()));
return false;
}
return false;
}
@@ -149,20 +133,14 @@ public abstract class ScriptVMMixin implements RSClient
static void rl$runScript(RSScriptEvent event, int maxExecutionTime)
{
Object[] arguments = event.getArguments();
if (arguments != null && arguments.length > 0 && arguments[0] instanceof JavaScriptCallback)
assert arguments != null && arguments.length > 0;
if (arguments[0] instanceof JavaScriptCallback)
{
try
{
ScriptPreFired preFired = new ScriptPreFired(-1);
preFired.setScriptEvent(event);
client.getCallbacks().post(ScriptPreFired.class, preFired);
((JavaScriptCallback) arguments[0]).run(event);
ScriptPostFired postFired = new ScriptPostFired(-1);
client.getCallbacks().post(ScriptPostFired.class, postFired);
}
catch (Exception e) // wont catch assertions
catch (Exception e)
{
client.getLogger().error("Error in JavaScriptCallback", e);
}
@@ -171,34 +149,13 @@ public abstract class ScriptVMMixin implements RSClient
{
try
{
try
{
scriptIds.push((Integer) event.getArguments()[0]); // this is safe because it will always be the script id
ScriptPreFired preFired = new ScriptPreFired(scriptIds.peek()); // peek doesn't remove the top item
preFired.setScriptEvent(event);
client.getCallbacks().post(ScriptPreFired.class, preFired);
}
catch (ClassCastException ignored)
{
}
final ScriptPreFired pre = new ScriptPreFired((int) arguments[0], event);
client.getCallbacks().post(ScriptPreFired.class, pre);
rs$runScript(event, maxExecutionTime);
if (!scriptIds.empty())
{
ScriptPostFired postFired = new ScriptPostFired(scriptIds.pop()); // hopefully the stack should be dry at this point
assert scriptIds.empty() : "Script ID stack should be empty! Contains: " + getAllScriptIds();
client.getCallbacks().post(ScriptPostFired.class, postFired);
}
}
finally
{
currentScript = null;
while (!scriptIds.empty())
{
scriptIds.pop(); // make sure the stack is empty, something disastrous happened
}
}
}
}
@@ -214,25 +171,4 @@ public abstract class ScriptVMMixin implements RSClient
se.setArguments(args);
runScript(se, 5000000);
}
@Inject
private static String getAllScriptIds()
{
ArrayList<Integer> ids = new ArrayList<>(scriptIds);
StringBuilder sb = new StringBuilder();
boolean first = true;
for (Object item : ids)
{
if (first)
{
first = false;
}
else
{
sb.append(", ");
}
sb.append(item);
}
return sb.toString();
}
}