From 2eaf57187d796c47ea872ab0eca76dac2c24b380 Mon Sep 17 00:00:00 2001 From: Hexagon Date: Mon, 20 Jan 2020 17:42:15 -0300 Subject: [PATCH] cache: Add hitsplat definition --- .../java/net/runelite/cache/ConfigType.java | 1 + .../cache/definitions/HitSplatDefinition.java | 48 +++++++ .../definitions/loaders/HitSplatLoader.java | 133 ++++++++++++++++++ .../net/runelite/cache/io/InputStream.java | 12 ++ .../net/runelite/cache/HitSplatDumper.java | 88 ++++++++++++ 5 files changed, 282 insertions(+) create mode 100644 cache/src/main/java/net/runelite/cache/definitions/HitSplatDefinition.java create mode 100644 cache/src/main/java/net/runelite/cache/definitions/loaders/HitSplatLoader.java create mode 100644 cache/src/test/java/net/runelite/cache/HitSplatDumper.java diff --git a/cache/src/main/java/net/runelite/cache/ConfigType.java b/cache/src/main/java/net/runelite/cache/ConfigType.java index 13056e2e33..4ca51a0b33 100644 --- a/cache/src/main/java/net/runelite/cache/ConfigType.java +++ b/cache/src/main/java/net/runelite/cache/ConfigType.java @@ -43,6 +43,7 @@ public enum ConfigType VARCLIENT(19), VARCLIENTSTRING(15), VARPLAYER(16), + HITSPLAT(32), STRUCT(34), AREA(35); diff --git a/cache/src/main/java/net/runelite/cache/definitions/HitSplatDefinition.java b/cache/src/main/java/net/runelite/cache/definitions/HitSplatDefinition.java new file mode 100644 index 0000000000..2f9a0d1359 --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/HitSplatDefinition.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Hexagon + * 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.Data; + +@Data +public class HitSplatDefinition +{ + private String stringFormat = ""; + private int varbitID = -1; + private int leftSprite = -1; + private int leftSprite2 = -1; + private int rightSpriteId = -1; + private int fontType = -1; + private int backgroundSprite = -1; + private int varpID = -1; + private int useDamage = -1; + private int textColor = 0xFFFFFF; + private int displayCycles = 70; + private int[] multihitsplats; + private int scrollToOffsetX = 0; + private int fadeStartCycle = -1; + private int scrollToOffsetY = 0; + private int textOffsetY = 0; +} diff --git a/cache/src/main/java/net/runelite/cache/definitions/loaders/HitSplatLoader.java b/cache/src/main/java/net/runelite/cache/definitions/loaders/HitSplatLoader.java new file mode 100644 index 0000000000..adf8c37ffc --- /dev/null +++ b/cache/src/main/java/net/runelite/cache/definitions/loaders/HitSplatLoader.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020, Hexagon + * 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.HitSplatDefinition; +import net.runelite.cache.io.InputStream; + +public class HitSplatLoader +{ + public HitSplatDefinition load(byte[] data) + { + HitSplatDefinition def = new HitSplatDefinition(); + InputStream stream = new InputStream(data); + + for (; ; ) + { + int opcode = stream.readUnsignedByte(); + + switch (opcode) + { + case 0: + return def; + case 1: + def.setFontType(stream.readBigSmart2()); + break; + case 2: + def.setTextColor(stream.read24BitInt()); + break; + case 3: + def.setLeftSprite(stream.readBigSmart2()); + break; + case 4: + def.setLeftSprite2(stream.readBigSmart2()); + break; + case 5: + def.setBackgroundSprite(stream.readBigSmart2()); + break; + case 6: + def.setRightSpriteId(stream.readBigSmart2()); + break; + case 7: + def.setScrollToOffsetX(stream.readShort()); + break; + case 8: + def.setStringFormat(stream.readString2()); + break; + case 9: + def.setDisplayCycles(stream.readUnsignedShort()); + break; + case 10: + def.setScrollToOffsetY(stream.readShort()); + break; + case 11: + def.setFadeStartCycle(0); + break; + case 12: + def.setUseDamage(stream.readUnsignedByte()); + break; + case 13: + def.setTextOffsetY(stream.readShort()); + break; + case 14: + def.setFadeStartCycle(stream.readUnsignedShort()); + break; + case 17: + case 18: + int varbitId = stream.readUnsignedShort(); + + if (varbitId == 0xFFFF) + { + varbitId = -1; + } + def.setVarbitID(varbitId); + + int varp = stream.readUnsignedShort(); + if (varp == 0xFFFF) + { + varp = -1; + } + def.setVarpID(varp); + + int id = -1; + if (opcode == 18) + { + id = stream.readUnsignedShort(); + if (id == 0xFFFF) + { + id = -1; + } + } + + int length = stream.readUnsignedByte(); + int[] multihitsplats = new int[length + 2]; + + for (int i = 0; i <= length; i++) + { + multihitsplats[i] = stream.readUnsignedShort(); + if (multihitsplats[i] == 0xFFFF) + { + multihitsplats[i] = -1; + } + } + + multihitsplats[length + 1] = id; + + def.setMultihitsplats(multihitsplats); + break; + } + } + } +} 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 1fde0d97a3..33c2cd484c 100644 --- a/cache/src/main/java/net/runelite/cache/io/InputStream.java +++ b/cache/src/main/java/net/runelite/cache/io/InputStream.java @@ -200,6 +200,18 @@ public class InputStream extends java.io.InputStream return sb.toString(); } + public String readString2() + { + if (this.readByte() != 0) + { + throw new IllegalStateException("Invalid jstr2"); + } + else + { + return readString(); + } + } + public String readStringOrNull() { if (this.peek() != 0) diff --git a/cache/src/test/java/net/runelite/cache/HitSplatDumper.java b/cache/src/test/java/net/runelite/cache/HitSplatDumper.java new file mode 100644 index 0000000000..09d3fa2b61 --- /dev/null +++ b/cache/src/test/java/net/runelite/cache/HitSplatDumper.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, Hexagon + * 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.File; +import java.io.IOException; +import java.nio.charset.Charset; +import lombok.extern.slf4j.Slf4j; +import net.runelite.cache.definitions.HitSplatDefinition; +import net.runelite.cache.definitions.loaders.HitSplatLoader; +import net.runelite.cache.fs.Archive; +import net.runelite.cache.fs.ArchiveFiles; +import net.runelite.cache.fs.FSFile; +import net.runelite.cache.fs.Index; +import net.runelite.cache.fs.Storage; +import net.runelite.cache.fs.Store; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +@Slf4j +public class HitSplatDumper +{ + private Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + @Rule + public TemporaryFolder folder = StoreLocation.getTemporaryFolder(); + + @Test + @Ignore + public void test() throws IOException + { + File dumpDir = folder.newFolder(); + int count = 0; + + try (Store store = new Store(StoreLocation.LOCATION)) + { + store.load(); + + Storage storage = store.getStorage(); + Index index = store.getIndex(IndexType.CONFIGS); + Archive archive = index.getArchive(ConfigType.HITSPLAT.getId()); + + HitSplatLoader loader = new HitSplatLoader(); + + byte[] archiveData = storage.loadArchive(archive); + ArchiveFiles files = archive.getFiles(archiveData); + + for (FSFile file : files.getFiles()) + { + byte[] b = file.getContents(); + + HitSplatDefinition def = loader.load(b); + + Files.asCharSink(new File(dumpDir, file.getFileId() + ".json"), Charset.defaultCharset()).write(gson.toJson(def)); + ++count; + } + } + + log.info("Dumped {} hitsplats to {}", count, dumpDir); + } +}