Merge pull request #2726 from ThatGamerBlue/scriptvm
mixins: make scriptvm more reliable
This commit is contained in:
@@ -29,13 +29,13 @@ import org.ajoberstar.grgit.Grgit
|
|||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
mavenLocal()
|
maven(url = "https://repo.openosrs.com/repository/maven/")
|
||||||
maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master")
|
maven(url = "https://raw.githubusercontent.com/open-osrs/hosting/master")
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath("org.ajoberstar.grgit:grgit-core:4.0.2")
|
classpath("org.ajoberstar.grgit:grgit-core:4.0.2")
|
||||||
classpath("com.github.ben-manes:gradle-versions-plugin:0.28.0")
|
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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,22 +24,22 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.api.events;
|
package net.runelite.api.events;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Value;
|
||||||
import net.runelite.api.ScriptEvent;
|
import net.runelite.api.ScriptEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An event that is fired before the designated script is ran
|
* An event that is fired before the designated script is ran
|
||||||
*/
|
*/
|
||||||
@Data
|
@Value
|
||||||
public class ScriptPreFired implements Event
|
public class ScriptPreFired implements Event
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The script id of the invoked script
|
* 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
|
* The input of the script invoke, this will be null unless it is the root script
|
||||||
*/
|
*/
|
||||||
private ScriptEvent scriptEvent;
|
ScriptEvent scriptEvent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,14 +25,9 @@
|
|||||||
*/
|
*/
|
||||||
package net.runelite.mixins;
|
package net.runelite.mixins;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Stack;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import net.runelite.api.Client;
|
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.ScriptCallbackEvent;
|
||||||
import net.runelite.api.events.ScriptPostFired;
|
import net.runelite.api.events.ScriptPostFired;
|
||||||
import net.runelite.api.events.ScriptPreFired;
|
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.RSClient;
|
||||||
import net.runelite.rs.api.RSScript;
|
import net.runelite.rs.api.RSScript;
|
||||||
import net.runelite.rs.api.RSScriptEvent;
|
import net.runelite.rs.api.RSScriptEvent;
|
||||||
|
import static net.runelite.api.Opcodes.*;
|
||||||
|
|
||||||
@Mixin(RSClient.class)
|
@Mixin(RSClient.class)
|
||||||
public abstract class ScriptVMMixin implements RSClient
|
public abstract class ScriptVMMixin implements RSClient
|
||||||
@@ -52,7 +48,6 @@ public abstract class ScriptVMMixin implements RSClient
|
|||||||
@Shadow("client")
|
@Shadow("client")
|
||||||
private static Client client;
|
private static Client client;
|
||||||
|
|
||||||
// This field is set by the ScriptVM raw injector
|
|
||||||
@Inject
|
@Inject
|
||||||
private static RSScript currentScript;
|
private static RSScript currentScript;
|
||||||
|
|
||||||
@@ -60,81 +55,70 @@ public abstract class ScriptVMMixin implements RSClient
|
|||||||
@Inject
|
@Inject
|
||||||
private static int currentScriptPC;
|
private static int currentScriptPC;
|
||||||
|
|
||||||
|
// Call is injected by the raw injector
|
||||||
@Inject
|
@Inject
|
||||||
private static ScriptPostFired deferredEvent = null;
|
static void setCurrentScript(RSScript script)
|
||||||
|
{
|
||||||
@Inject
|
currentScript = script;
|
||||||
private static Stack<Integer> scriptIds = new Stack<>();
|
}
|
||||||
|
|
||||||
// Call is injected into runScript by the ScriptVM raw injector
|
// Call is injected into runScript by the ScriptVM raw injector
|
||||||
@Inject
|
@Inject
|
||||||
static boolean vmExecuteOpcode(int opcode)
|
static boolean vmExecuteOpcode(int opcode)
|
||||||
{
|
{
|
||||||
if (deferredEvent != null)
|
switch (opcode)
|
||||||
{
|
{
|
||||||
client.getCallbacks().post(ScriptPostFired.class, deferredEvent);
|
case RUNELITE_EXECUTE:
|
||||||
deferredEvent = null;
|
assert currentScript.getInstructions()[currentScriptPC] == RUNELITE_EXECUTE;
|
||||||
}
|
|
||||||
if (opcode == RUNELITE_EXECUTE)
|
|
||||||
{
|
|
||||||
assert currentScript.getInstructions()[currentScriptPC] == RUNELITE_EXECUTE;
|
|
||||||
|
|
||||||
int stringStackSize = client.getStringStackSize();
|
|
||||||
String stringOp = client.getStringStack()[--stringStackSize];
|
|
||||||
client.setStringStackSize(stringStackSize);
|
|
||||||
|
|
||||||
if ("debug".equals(stringOp))
|
|
||||||
{
|
|
||||||
int intStackSize = client.getIntStackSize();
|
|
||||||
|
|
||||||
String fmt = client.getStringStack()[--stringStackSize];
|
|
||||||
StringBuffer out = new StringBuffer();
|
|
||||||
Matcher m = Pattern.compile("%(.)").matcher(fmt);
|
|
||||||
for (; m.find(); )
|
|
||||||
{
|
|
||||||
m.appendReplacement(out, "");
|
|
||||||
switch (m.group(1).charAt(0))
|
|
||||||
{
|
|
||||||
case 'i':
|
|
||||||
case 'd':
|
|
||||||
out.append(client.getIntStack()[--intStackSize]);
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
out.append(client.getStringStack()[--stringStackSize]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
out.append(m.group(0)).append("=unknown");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m.appendTail(out);
|
|
||||||
|
|
||||||
client.getLogger().debug(out.toString());
|
|
||||||
|
|
||||||
|
int stringStackSize = client.getStringStackSize();
|
||||||
|
String stringOp = client.getStringStack()[--stringStackSize];
|
||||||
client.setStringStackSize(stringStackSize);
|
client.setStringStackSize(stringStackSize);
|
||||||
client.setIntStackSize(intStackSize);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptCallbackEvent event = new ScriptCallbackEvent();
|
if ("debug".equals(stringOp))
|
||||||
event.setScript(currentScript);
|
{
|
||||||
event.setEventName(stringOp);
|
int intStackSize = client.getIntStackSize();
|
||||||
client.getCallbacks().post(ScriptCallbackEvent.class, event);
|
|
||||||
return true;
|
String fmt = client.getStringStack()[--stringStackSize];
|
||||||
}
|
StringBuffer out = new StringBuffer();
|
||||||
else if (opcode == INVOKE)
|
Matcher m = Pattern.compile("%(.)").matcher(fmt);
|
||||||
{
|
while (m.find())
|
||||||
int id = currentScript.getIntOperands()[currentScriptPC];
|
{
|
||||||
scriptIds.push(id);
|
m.appendReplacement(out, "");
|
||||||
ScriptPreFired event = new ScriptPreFired(id);
|
switch (m.group(1).charAt(0))
|
||||||
event.setScriptEvent(null);
|
{
|
||||||
client.getCallbacks().post(ScriptPreFired.class, event);
|
case 'i':
|
||||||
}
|
case 'd':
|
||||||
else if (opcode == RETURN)
|
out.append(client.getIntStack()[--intStackSize]);
|
||||||
{
|
break;
|
||||||
if (scriptIds.size() > 1) // let the runScript method handle the final script
|
case 's':
|
||||||
{
|
out.append(client.getStringStack()[--stringStackSize]);
|
||||||
deferredEvent = new ScriptPostFired(scriptIds.pop()); // fire the event when we've left the script
|
break;
|
||||||
}
|
default:
|
||||||
|
out.append(m.group(0)).append("=unknown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.appendTail(out);
|
||||||
|
|
||||||
|
client.getLogger().debug(out.toString());
|
||||||
|
|
||||||
|
client.setStringStackSize(stringStackSize);
|
||||||
|
client.setIntStackSize(intStackSize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptCallbackEvent event = new ScriptCallbackEvent();
|
||||||
|
event.setScript(currentScript);
|
||||||
|
event.setEventName(stringOp);
|
||||||
|
client.getCallbacks().post(ScriptCallbackEvent.class, event);
|
||||||
|
return true;
|
||||||
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -149,20 +133,14 @@ public abstract class ScriptVMMixin implements RSClient
|
|||||||
static void rl$runScript(RSScriptEvent event, int maxExecutionTime)
|
static void rl$runScript(RSScriptEvent event, int maxExecutionTime)
|
||||||
{
|
{
|
||||||
Object[] arguments = event.getArguments();
|
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
|
try
|
||||||
{
|
{
|
||||||
ScriptPreFired preFired = new ScriptPreFired(-1);
|
|
||||||
preFired.setScriptEvent(event);
|
|
||||||
client.getCallbacks().post(ScriptPreFired.class, preFired);
|
|
||||||
|
|
||||||
((JavaScriptCallback) arguments[0]).run(event);
|
((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);
|
client.getLogger().error("Error in JavaScriptCallback", e);
|
||||||
}
|
}
|
||||||
@@ -171,34 +149,13 @@ public abstract class ScriptVMMixin implements RSClient
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
try
|
final ScriptPreFired pre = new ScriptPreFired((int) arguments[0], event);
|
||||||
{
|
client.getCallbacks().post(ScriptPreFired.class, pre);
|
||||||
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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
rs$runScript(event, maxExecutionTime);
|
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
|
finally
|
||||||
{
|
{
|
||||||
currentScript = null;
|
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);
|
se.setArguments(args);
|
||||||
runScript(se, 5000000);
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user