From 8448f74b3c1f7e75e4334485fff594d3eb4ef4d8 Mon Sep 17 00:00:00 2001 From: Graham Date: Sat, 11 Dec 2021 17:33:40 +0000 Subject: [PATCH] Add ChecksumTable and VersionList classes Signed-off-by: Graham --- .../kotlin/org/openrs2/cache/ChecksumTable.kt | 62 +++++++++++++++++ .../kotlin/org/openrs2/cache/VersionList.kt | 68 +++++++++++++++++++ 2 files changed, 130 insertions(+) create mode 100644 cache/src/main/kotlin/org/openrs2/cache/ChecksumTable.kt create mode 100644 cache/src/main/kotlin/org/openrs2/cache/VersionList.kt diff --git a/cache/src/main/kotlin/org/openrs2/cache/ChecksumTable.kt b/cache/src/main/kotlin/org/openrs2/cache/ChecksumTable.kt new file mode 100644 index 00000000..f2841628 --- /dev/null +++ b/cache/src/main/kotlin/org/openrs2/cache/ChecksumTable.kt @@ -0,0 +1,62 @@ +package org.openrs2.cache + +import io.netty.buffer.ByteBuf +import org.openrs2.buffer.crc32 +import org.openrs2.buffer.use + +public class ChecksumTable( + public val entries: MutableList = mutableListOf() +) { + public fun write(buf: ByteBuf) { + for (entry in entries) { + buf.writeInt(entry) + } + + var checksum = 1234 + for (entry in entries) { + checksum = (checksum shl 1) + entry + } + + buf.writeInt(checksum) + } + + public companion object { + public fun create(store: Store): ChecksumTable { + val table = ChecksumTable() + + var nextArchive = 0 + for (archive in store.list(0)) { + val entry = store.read(0, archive).use { buf -> + buf.crc32() + } + + for (i in nextArchive until archive) { + table.entries += 0 + } + + table.entries += entry + nextArchive = archive + 1 + } + + return table + } + + public fun read(buf: ByteBuf): ChecksumTable { + val table = ChecksumTable() + + var expectedChecksum = 1234 + + while (buf.readableBytes() >= 8) { + val entry = buf.readInt() + table.entries += entry + + expectedChecksum = (expectedChecksum shl 1) + entry + } + + val actualChecksum = buf.readInt() + require(expectedChecksum == actualChecksum) + + return table + } + } +} diff --git a/cache/src/main/kotlin/org/openrs2/cache/VersionList.kt b/cache/src/main/kotlin/org/openrs2/cache/VersionList.kt new file mode 100644 index 00000000..48f58e07 --- /dev/null +++ b/cache/src/main/kotlin/org/openrs2/cache/VersionList.kt @@ -0,0 +1,68 @@ +package org.openrs2.cache + +import org.openrs2.buffer.use + +public class VersionList( + public val files: List>, + public val maps: Map, +) { + public data class File( + val version: Int, + val checksum: Int + ) + + public data class MapSquare( + val mapFile: Int, + val locFile: Int, + val freeToPlay: Boolean + ) + + public companion object { + private val NAMES = listOf("model", "anim", "midi", "map") + + public fun read(archive: JagArchive): VersionList { + val files = mutableListOf>() + + for (name in NAMES) { + val versions = archive.read("${name}_version".uppercase()).use { buf -> + IntArray(buf.readableBytes() / 2) { + buf.readUnsignedShort() + } + } + + val checksums = archive.read("${name}_crc".uppercase()).use { buf -> + IntArray(buf.readableBytes() / 4) { + buf.readInt() + } + } + + require(versions.size == checksums.size) + + files += versions.zip(checksums, ::File) + } + + val maps = mutableMapOf() + + archive.read("map_index".uppercase()).use { buf -> + while (buf.readableBytes() >= 7) { + val mapSquare = buf.readUnsignedShort() + val mapFile = buf.readUnsignedShort() + val locFile = buf.readUnsignedShort() + val freeToPlay = buf.readBoolean() + + if (maps.containsKey(mapSquare)) { + /* + * If there's a map square collision, pick the first + * entry for compatibility with the client. + */ + continue + } + + maps[mapSquare] = MapSquare(mapFile, locFile, freeToPlay) + } + } + + return VersionList(files, maps) + } + } +}