diff --git a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt index a23548f4..d2f2e4bd 100644 --- a/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt +++ b/archive/src/main/kotlin/org/openrs2/archive/cache/CacheImporter.kt @@ -43,6 +43,7 @@ public class CacheImporter @Inject constructor( public val encrypted: Boolean = uncompressed == null public val uncompressedLen: Int? = uncompressed?.readableBytes() public val uncompressedCrc32: Int? = uncompressed?.crc32() + public val emptyLoc: Boolean = Js5Compression.isEmptyLoc(compressed.slice()) public fun release() { compressed.release() @@ -696,7 +697,8 @@ public class CacheImporter @Inject constructor( uncompressed_length INTEGER NULL, uncompressed_crc32 INTEGER NULL, data BYTEA NOT NULL, - encrypted BOOLEAN NOT NULL + encrypted BOOLEAN NOT NULL, + empty_loc BOOLEAN NULL ) ON COMMIT DROP """.trimIndent() ).use { stmt -> @@ -719,8 +721,8 @@ public class CacheImporter @Inject constructor( connection.prepareStatement( """ - INSERT INTO tmp_containers (index, crc32, whirlpool, data, uncompressed_length, uncompressed_crc32, encrypted) - VALUES (?, ?, ?, ?, ?, ?, ?) + INSERT INTO tmp_containers (index, crc32, whirlpool, data, uncompressed_length, uncompressed_crc32, encrypted, empty_loc) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) """.trimIndent() ).use { stmt -> for ((i, container) in containers.withIndex()) { @@ -731,6 +733,13 @@ public class CacheImporter @Inject constructor( stmt.setObject(5, container.uncompressedLen, Types.INTEGER) stmt.setObject(6, container.uncompressedCrc32, Types.INTEGER) stmt.setBoolean(7, container.encrypted) + + if (container.encrypted) { + stmt.setBoolean(8, container.emptyLoc) + } else { + stmt.setNull(8, Types.BOOLEAN) + } + stmt.addBatch() } @@ -739,8 +748,8 @@ public class CacheImporter @Inject constructor( connection.prepareStatement( """ - INSERT INTO containers (crc32, whirlpool, data, uncompressed_length, uncompressed_crc32, encrypted) - SELECT t.crc32, t.whirlpool, t.data, t.uncompressed_length, t.uncompressed_crc32, t.encrypted + INSERT INTO containers (crc32, whirlpool, data, uncompressed_length, uncompressed_crc32, encrypted, empty_loc) + SELECT t.crc32, t.whirlpool, t.data, t.uncompressed_length, t.uncompressed_crc32, t.encrypted, t.empty_loc FROM tmp_containers t LEFT JOIN containers c ON c.whirlpool = t.whirlpool WHERE c.whirlpool IS NULL diff --git a/archive/src/main/resources/org/openrs2/archive/V1__init.sql b/archive/src/main/resources/org/openrs2/archive/V1__init.sql index 4954c868..a5b8eb58 100644 --- a/archive/src/main/resources/org/openrs2/archive/V1__init.sql +++ b/archive/src/main/resources/org/openrs2/archive/V1__init.sql @@ -34,6 +34,7 @@ CREATE TABLE containers ( uncompressed_length INTEGER NULL, uncompressed_crc32 INTEGER NULL, encrypted BOOLEAN NOT NULL, + empty_loc BOOLEAN NULL, key_id BIGINT NULL REFERENCES keys (id) ); @@ -168,7 +169,12 @@ GROUP BY a.master_index_id; CREATE UNIQUE INDEX ON master_index_archive_stats (master_index_id); CREATE MATERIALIZED VIEW master_index_group_stats (master_index_id, groups, valid_groups, keys, valid_keys) AS -SELECT v.master_index_id, COUNT(*), COUNT(c.id), COUNT(*) FILTER (WHERE c.encrypted), COUNT(k.id) +SELECT + v.master_index_id, + COUNT(*), + COUNT(c.id), + COUNT(*) FILTER (WHERE c.encrypted), + COUNT(*) FILTER (WHERE c.key_id IS NOT NULL OR (c.empty_loc IS NOT NULL AND c.empty_loc)) FROM master_index_valid_indexes v JOIN index_groups ig ON ig.container_id = v.container_id LEFT JOIN groups g ON g.archive_id = v.archive_id AND g.group_id = ig.group_id AND ( diff --git a/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html b/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html index 7f5ea87d..54a3df88 100644 --- a/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html +++ b/archive/src/main/resources/org/openrs2/archive/templates/caches/index.html @@ -15,7 +15,7 @@
+ [1]: Map squares in the middle of the sea are unreachable by + normal players, making it impossible to obtain the keys for + their loc groups. However, the loc groups for these map squares + are empty. As XTEA does not hide the length of the compressed + data, this service infers which encrypted loc groups are empty + and includes them in the number of valid keys, regardless of + whether we know the key or not. After downloading a cache from + this service, a cache editor may be used to replace the empty + encrypted loc groups with unencrypted replacements. +