From 36971a2add714a5f48b13c7359275c6f02ecc335 Mon Sep 17 00:00:00 2001 From: Max Weber Date: Sat, 8 Sep 2018 07:04:40 -0600 Subject: [PATCH] cache: Disassemble CS1s --- .../definitions/ClientScript1Instruction.java | 61 +++++++++++++++++++ .../definitions/InterfaceDefinition.java | 2 +- .../definitions/loaders/InterfaceLoader.java | 29 +++++++-- .../definitions/savers/InterfaceSaver.java | 23 ++++++- .../savers/InterfaceSaverTest.java | 5 +- 5 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 cache/src/main/java/net/runelite/cache/definitions/ClientScript1Instruction.java diff --git a/cache/src/main/java/net/runelite/cache/definitions/ClientScript1Instruction.java b/cache/src/main/java/net/runelite/cache/definitions/ClientScript1Instruction.java new file mode 100644 index 0000000000..f0fe7d4683 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/ClientScript1Instruction.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 Abex + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.cache.definitions; + +import lombok.RequiredArgsConstructor; + +public class ClientScript1Instruction +{ + @RequiredArgsConstructor + public enum Opcode + { + RETURN(0), + BOOSTED_SKILL_LEVELS(1), + REAL_SKILL_LEVELS(1), + SKILL_EXPERIENCE(1), + WIDGET_CONTAINS_ITEM_GET_QUANTITY(3), + VARP(1), + EXPERIENCE_AT_LEVEL_FOR_SKILL(1), + VARP_TIMES_469(1), + COMBAT_LEVEL(1), + TOTAL_LEVEL(0), + WIDGET_CONTAINS_ITEM_STAR(3), + RUN_ENERGY(0), + WEIGHT(0), + VARP_TESTBIT(2), + VARBIT(1), + MINUS(0), + DIV(0), + MUL(0), + WORLD_X(0), + WORLD_Y(1), + CONSTANT(1); + + public final int argumentCount; + } + + public Opcode opcode; + public int[] operands; +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/InterfaceDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/InterfaceDefinition.java index dfc0c72792..4bbee579e2 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/InterfaceDefinition.java +++ b/cache/src/main/java/net/runelite/cache/definitions/InterfaceDefinition.java @@ -107,7 +107,7 @@ public class InterfaceDefinition public int hoveredSiblingId; public int[] alternateOperators; public int[] alternateRhs; - public int[][] clientScripts; + public ClientScript1Instruction[][] clientScripts; public int[] itemIds; public int[] itemQuantities; public int xPitch; diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/InterfaceLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/InterfaceLoader.java index 4e08ac6821..69db420f9f 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/loaders/InterfaceLoader.java +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/InterfaceLoader.java @@ -24,6 +24,10 @@ */ package net.runelite.cache.definitions.loaders; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import net.runelite.cache.definitions.ClientScript1Instruction; import net.runelite.cache.definitions.InterfaceDefinition; import net.runelite.cache.io.InputStream; @@ -92,20 +96,35 @@ public class InterfaceLoader int var6; if (var3 > 0) { - iface.clientScripts = new int[var3][]; + iface.clientScripts = new ClientScript1Instruction[var3][]; for (var4 = 0; var4 < var3; ++var4) { var5 = var1.readUnsignedShort(); - iface.clientScripts[var4] = new int[var5]; + int[] bytecode = new int[var5]; for (var6 = 0; var6 < var5; ++var6) { - iface.clientScripts[var4][var6] = var1.readUnsignedShort(); - if (iface.clientScripts[var4][var6] == 0xFFFF) + bytecode[var6] = var1.readUnsignedShort(); + if (bytecode[var6] == 0xFFFF) { - iface.clientScripts[var4][var6] = -1; + bytecode[var6] = -1; } + + List instructions = new ArrayList<>(); + for (int i = 0; i < bytecode.length;) + { + ClientScript1Instruction ins = new ClientScript1Instruction(); + + ins.opcode = ClientScript1Instruction.Opcode.values()[bytecode[i++]]; + + int ac = ins.opcode.argumentCount; + ins.operands = Arrays.copyOfRange(bytecode, i, i + ac); + + instructions.add(ins); + i += ac; + } + iface.clientScripts[var4] = instructions.toArray(new ClientScript1Instruction[0]); } } } diff --git a/cache/src/main/java/net/runelite/cache/definitions/savers/InterfaceSaver.java b/cache/src/main/java/net/runelite/cache/definitions/savers/InterfaceSaver.java index af64c9dfe3..61151a4158 100644 --- a/cache/src/main/java/net/runelite/cache/definitions/savers/InterfaceSaver.java +++ b/cache/src/main/java/net/runelite/cache/definitions/savers/InterfaceSaver.java @@ -24,6 +24,7 @@ */ package net.runelite.cache.definitions.savers; +import net.runelite.cache.definitions.ClientScript1Instruction; import net.runelite.cache.definitions.InterfaceDefinition; import net.runelite.cache.io.OutputStream; @@ -77,10 +78,28 @@ public class InterfaceSaver out.writeByte(def.clientScripts.length); for (int i = 0; i < def.clientScripts.length; ++i) { - out.writeShort(def.clientScripts[i].length); + int len = 0; for (int j = 0; j < def.clientScripts[i].length; ++j) { - out.writeShort(def.clientScripts[i][j]); + ClientScript1Instruction ins = def.clientScripts[i][j]; + len++; + if (ins.operands != null) + { + len += ins.operands.length; + } + } + out.writeShort(len); + for (int j = 0; j < def.clientScripts[i].length; ++j) + { + ClientScript1Instruction ins = def.clientScripts[i][j]; + out.writeShort(ins.opcode.ordinal()); + if (ins.operands != null) + { + for (int op : ins.operands) + { + out.writeShort(op); + } + } } } } diff --git a/cache/src/test/java/net/runelite/cache/definitions/savers/InterfaceSaverTest.java b/cache/src/test/java/net/runelite/cache/definitions/savers/InterfaceSaverTest.java index cc4bf51a5c..6d95f445a9 100644 --- a/cache/src/test/java/net/runelite/cache/definitions/savers/InterfaceSaverTest.java +++ b/cache/src/test/java/net/runelite/cache/definitions/savers/InterfaceSaverTest.java @@ -40,7 +40,6 @@ import org.junit.Test; public class InterfaceSaverTest { - @Test public void testSave() throws Exception { @@ -51,10 +50,10 @@ public class InterfaceSaverTest Storage storage = store.getStorage(); Index index = store.getIndex(IndexType.INTERFACES); - Archive archive = index.getArchive(149); + Archive archive = index.getArchive(31); byte[] archiveData = storage.loadArchive(archive); ArchiveFiles files = archive.getFiles(archiveData); - FSFile file = files.findFile(0); + FSFile file = files.findFile(76); byte[] contents = file.getContents(); InterfaceDefinition def = new InterfaceLoader().load(0, contents);