UNPKG

@abextm/cache2

Version:

Utilities for reading OSRS "caches"

124 lines (123 loc) 3.87 kB
import { Loadable } from "../Loadable.js"; import { Reader } from "../Reader.js"; import { Typed } from "../reflect.js"; const decoder = new TextDecoder("utf-8"); export class GameVal extends Loadable { gameValID; otherID; constructor(gameValID, otherID) { super(); this.gameValID = gameValID; this.otherID = otherID; } static index = 24; name; files = undefined; static async loadData(cache, gameValID, otherID) { let archive = await cache.getArchive(this.index, gameValID); let version = await cache.getVersion(this.index); let data = archive?.getFile(otherID)?.data; return data ? new Reader(data, version) : undefined; } static async nameFor(cache, obj) { let clazz = obj?.constructor; if (clazz && "gameval" in clazz) { let gv = await this.load(cache, clazz.gameval, obj.id); return gv?.name; } return undefined; } static decode(r, gameValID, otherID) { const v = new GameVal(gameValID, otherID); switch (gameValID) { case 10: { // DBTable r.u8(); // always 1, very useful v.name = r.string(); let files = v.files = new Map(); for (let id = 0;; id++) { let counter = r.u8(); if (counter == 0 && isEnd(r)) { break; } files.set(id, r.string()); } break; } case 13: { // legacy widget v.name = r.string(); let files = v.files = new Map(); let msb = 0; let lastId = 0; for (;;) { let id = r.u8(); if (id == 255 && isEnd(r)) { break; } if (id < lastId) { msb += 0x100; } lastId = id; files.set(msb + id, r.string()); } break; } case 14: { // widget v.name = r.string(); let files = v.files = new Map(); for (;;) { let id = r.u16(); if (id === 0xFFFF) { break; } files.set(id, r.string()); } break; } default: v.name = decoder.decode(r.view); } return v; } static async all(cache, id) { let c = await cache; if (id === undefined) { let ids = await c.getArchives(this.index); if (!ids) { return undefined; } return new Map(await Promise.all(ids.map(id => this.all(c, id) .then(v => [id, v])))); } let version = await c.getVersion(this.index); let ar = await c.getArchive(this.index, id); if (!ar) { return undefined; } return new Map(Array.from(ar.getFiles().entries()) .map(([fid, file]) => { try { return [fid, this.decode(new Reader(file.data, version), id, fid)]; } catch (e) { if (typeof e === "object" && e && "message" in e) { let ea = e; ea.message = `${id}:${fid}: ${ea.message}`; } throw e; } })); } } function isEnd(r) { let off = r.offset; for (; r.offset < r.length;) { if (r.u8() != 0) { r.offset = off; return false; } } return true; }