From 6a552a81d6b94359cb62a295e179288316c725fd Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 1 Jun 2017 19:14:47 -0400 Subject: [PATCH] cache: add area definition and loader --- .../java/net/runelite/cache/ConfigType.java | 3 +- .../cache/definitions/AreaDefinition.java | 42 ++++ .../cache/definitions/loaders/AreaLoader.java | 190 ++++++++++++++++++ .../net/runelite/cache/io/InputStream.java | 9 + .../java/net/runelite/cache/AreaDumper.java | 80 ++++++++ 5 files changed, 323 insertions(+), 1 deletion(-) create mode 100644 cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java create mode 100644 cache/src/test/java/net/runelite/cache/AreaDumper.java diff --git a/cache/src/main/java/net/runelite/cache/ConfigType.java b/cache/src/main/java/net/runelite/cache/ConfigType.java index 2cbb6e0266..d7e20d5131 100644 --- a/cache/src/main/java/net/runelite/cache/ConfigType.java +++ b/cache/src/main/java/net/runelite/cache/ConfigType.java @@ -41,7 +41,8 @@ public enum ConfigType VARBIT(14), VARCLIENT(19), VARCLIENTSTRING(15), - VARPLAYER(16); + VARPLAYER(16), + AREA(35); private final int id; diff --git a/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java new file mode 100644 index 0000000000..fe615b4250 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/AreaDefinition.java @@ -0,0 +1,42 @@ +/* + * 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.cache.definitions; + +public class AreaDefinition +{ + public int id; + public int[] field3292; + public int spriteId = -1; + public int field3294 = -1; + public String name; + public int field3296; + public int field3297 = -1; + public String[] field3298 = new String[5]; + public int[] field3300; + public String field3308; + public byte[] field3309; + public int field3310; + +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java new file mode 100644 index 0000000000..7b47358678 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/AreaLoader.java @@ -0,0 +1,190 @@ +/* + * 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.cache.definitions.loaders; + +import net.runelite.cache.definitions.AreaDefinition; +import net.runelite.cache.io.InputStream; + +public class AreaLoader +{ + public AreaDefinition load(byte[] b, int id) + { + InputStream in = new InputStream(b); + AreaDefinition def = new AreaDefinition(); + def.id = id; + + for (;;) + { + int opcode = in.readUnsignedByte(); + if (opcode == 0) + { + break; + } + + processOpcode(def, in, opcode); + } + + return def; + } + + private void processOpcode(AreaDefinition def, InputStream in, int opcode) + { + if (opcode == 1) + { + def.spriteId = in.readBigSmart2(); + } + else if (opcode == 2) + { + def.field3294 = in.readBigSmart2(); + } + else if (opcode == 3) + { + def.name = in.readString(); + } + else if (opcode == 4) + { + def.field3296 = in.read24BitInt(); + } + else if (opcode == 5) + { + in.read24BitInt(); + } + else if (opcode == 6) + { + def.field3310 = in.readUnsignedByte(); + } + else if (opcode == 7) + { + int var3 = in.readUnsignedByte(); + if ((var3 & 1) == 0) + { + ; + } + + if ((var3 & 2) == 2) + { + ; + } + } + else if (opcode == 8) + { + in.readUnsignedByte(); + } + else if (opcode >= 10 && opcode <= 14) + { + def.field3298[opcode - 10] = in.readString(); + } + else if (opcode == 15) + { + int var3 = in.readUnsignedByte(); + def.field3300 = new int[var3 * 2]; + + int var4; + for (var4 = 0; var4 < var3 * 2; ++var4) + { + def.field3300[var4] = in.readShort(); + } + + in.readInt(); + var4 = in.readUnsignedByte(); + def.field3292 = new int[var4]; + + int var5; + for (var5 = 0; var5 < def.field3292.length; ++var5) + { + def.field3292[var5] = in.readInt(); + } + + def.field3309 = new byte[var3]; + + for (var5 = 0; var5 < var3; ++var5) + { + def.field3309[var5] = in.readByte(); + } + } + else if (opcode == 16) + { + + } + else if (opcode == 17) + { + def.field3308 = in.readString(); + } + else if (opcode == 18) + { + in.readBigSmart2(); + } + else if (opcode == 19) + { + def.field3297 = in.readUnsignedShort(); + } + else if (opcode == 21) + { + in.readInt(); + } + else if (opcode == 22) + { + in.readInt(); + } + else if (opcode == 23) + { + in.readUnsignedByte(); + in.readUnsignedByte(); + in.readUnsignedByte(); + } + else if (opcode == 24) + { + in.readShort(); + in.readShort(); + } + else if (opcode == 25) + { + in.readBigSmart2(); + } + else if (opcode == 28) + { + in.readUnsignedByte(); + } + else if (opcode == 29) + { + in.skip(1); +// class257[] var6 = new class257[] +// { +// class257.field3538, class257.field3539, class257.field3540 +// }; +// this.field3299 = (class257) Item.method1751(var6, var1.readUnsignedByte()); + } + else if (opcode == 30) + { + in.skip(1); +// class239[] var7 = new class239[] +// { +// class239.field3273, class239.field3275, class239.field3271 +// }; +// this.field3306 = (class239) Item.method1751(var7, var1.readUnsignedByte()); + } + + } +} diff --git a/cache/src/main/java/net/runelite/cache/io/InputStream.java b/cache/src/main/java/net/runelite/cache/io/InputStream.java index c02a12d4b3..19f19c4942 100644 --- a/cache/src/main/java/net/runelite/cache/io/InputStream.java +++ b/cache/src/main/java/net/runelite/cache/io/InputStream.java @@ -135,6 +135,15 @@ public class InputStream extends java.io.InputStream return peek() >= 0 ? this.readUnsignedShort() : Integer.MAX_VALUE & this.readInt(); } + public int readBigSmart2() + { + if (peek() < 0) + return readInt() & Integer.MAX_VALUE; // and off sign bit + + int value = readUnsignedShort(); + return value == 32767 ? -1 : value; + } + public int readShortSmart() { int peek = this.peek() & 0xFF; diff --git a/cache/src/test/java/net/runelite/cache/AreaDumper.java b/cache/src/test/java/net/runelite/cache/AreaDumper.java new file mode 100644 index 0000000000..dee69587e7 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/AreaDumper.java @@ -0,0 +1,80 @@ +/* + * 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.cache; + +import com.google.common.io.Files; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import java.io.IOException; +import java.nio.charset.Charset; +import net.runelite.cache.definitions.AreaDefinition; +import net.runelite.cache.definitions.loaders.AreaLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.File; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Store; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class AreaDumper +{ + private static final Logger logger = LoggerFactory.getLogger(AreaDumper.class); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Test + public void extract() throws IOException + { + java.io.File base = StoreLocation.LOCATION, + outDir = folder.newFolder(); + + int count = 0; + + try (Store store = new Store(base)) + { + store.load(); + + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.AREA.getId()); + + for (File file : archive.getFiles()) + { + AreaLoader loader = new AreaLoader(); + AreaDefinition area = loader.load(file.getContents(), file.getFileId()); + + Files.write(gson.toJson(area), new java.io.File(outDir, file.getFileId() + ".json"), Charset.defaultCharset()); + ++count; + } + } + + logger.info("Dumped {} areas to {}", count, outDir); + } +}