UNPKG

@runejs/filestore

Version:

Tools for managing the RuneJS filestore.

230 lines (229 loc) 8.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NpcStore = exports.NpcConfig = void 0; const common_1 = require("@runejs/common"); /** * Contains game client need-to-know level information about a single game npc. */ class NpcConfig { gameId; name = null; animations = { stand: -1, walk: -1, turnAround: -1, turnRight: -1, turnLeft: -1, }; options; minimapVisible = true; combatLevel = -1; headIcon = -1; clickable = true; turnDegrees = 32; varbitId = -1; settingId = -1; parentId; childrenIds; /** * 3d modelling information for this npc. */ model = {}; /** * Additional rendering details. */ rendering = { boundary: 1, sizeX: 128, sizeY: 128, renderPriority: false, }; } exports.NpcConfig = NpcConfig; /** * Controls files within the NPC Archive of the configuration index. */ class NpcStore { configStore; /** * The NPC Archive, containing details about every game NPC. */ npcArchive; children = new Map(); constructor(configStore) { this.configStore = configStore; this.npcArchive = this.configStore.getArchive('npcs'); } /** * Fetches the NpcConfig object for the specified npc game id. * @param npcId The game id of the npc to find. */ getNpc(npcId) { const npcArchive = this.npcArchive; if (!npcArchive) { common_1.logger.error('Npc archive not found.'); return null; } const npcFile = npcArchive.getFile(npcId) || null; if (!npcFile) { common_1.logger.error('Npc file not found.'); return null; } return this.decodeNpcFile(npcFile); } /** * Parses a raw npc data file into a readable NpcConfig object. * @param npcFile The raw file-store npc data. */ decodeNpcFile(npcFile) { const npcConfig = new NpcConfig(); const buffer = npcFile.content; npcConfig.gameId = npcFile.fileId; let run = true; while (run) { const opcode = buffer.get('BYTE', 'UNSIGNED'); if (opcode === 0) { run = false; break; } if (opcode === 1) { const length = buffer.get('BYTE', 'UNSIGNED'); npcConfig.model.models = new Array(length); for (let idx = 0; idx < length; ++idx) { npcConfig.model.models[idx] = buffer.get('SHORT', 'UNSIGNED'); } } else if (opcode === 2) { npcConfig.name = buffer.getString(); } else if (opcode === 12) { npcConfig.rendering.boundary = buffer.get('BYTE', 'UNSIGNED'); } else if (opcode === 13) { npcConfig.animations.stand = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 14) { npcConfig.animations.walk = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 15) { buffer.get('SHORT', 'UNSIGNED'); // junk } else if (opcode === 16) { buffer.get('SHORT', 'UNSIGNED'); // junk } else if (opcode === 17) { npcConfig.animations.walk = buffer.get('SHORT', 'UNSIGNED'); npcConfig.animations.turnAround = buffer.get('SHORT', 'UNSIGNED'); npcConfig.animations.turnRight = buffer.get('SHORT', 'UNSIGNED'); npcConfig.animations.turnLeft = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode >= 30 && opcode < 35) { if (!npcConfig.options) { npcConfig.options = new Array(5).fill(null); } const option = buffer.getString(); npcConfig.options[opcode - 30] = option.toLowerCase() === 'hidden' ? null : option; } else if (opcode === 40) { // Model color replacement const length = buffer.get('BYTE', 'UNSIGNED'); for (let i = 0; i < length; i++) { buffer.get('SHORT', 'UNSIGNED'); buffer.get('SHORT', 'UNSIGNED'); } } else if (opcode === 60) { const length = buffer.get('BYTE', 'UNSIGNED'); npcConfig.model.headModels = new Array(length); for (let i = 0; length > i; i++) { npcConfig.model.headModels[i] = buffer.get('SHORT', 'UNSIGNED'); } } else if (opcode === 93) { npcConfig.minimapVisible = false; } else if (opcode === 95) { npcConfig.combatLevel = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 97) { npcConfig.rendering.sizeX = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 98) { npcConfig.rendering.sizeY = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 99) { npcConfig.rendering.renderPriority = true; } else if (opcode === 100) { const ambient = buffer.get('BYTE'); } else if (opcode === 101) { const contrast = buffer.get('BYTE') * 5; } else if (opcode === 102) { npcConfig.headIcon = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 103) { npcConfig.turnDegrees = buffer.get('SHORT', 'UNSIGNED'); } else if (opcode === 106) { npcConfig.varbitId = buffer.get('SHORT', 'UNSIGNED'); npcConfig.settingId = buffer.get('SHORT', 'UNSIGNED'); if (npcConfig.varbitId === 65535) { npcConfig.varbitId = -1; } if (npcConfig.settingId === 65535) { npcConfig.settingId = -1; } npcConfig.childrenIds = []; const childCount = buffer.get('BYTE', 'UNSIGNED'); for (let i = 0; childCount >= i; i++) { npcConfig.childrenIds[i] = buffer.get('SHORT', 'UNSIGNED'); if (npcConfig.childrenIds[i] === 0xffff) { npcConfig.childrenIds[i] = -1; } } } else if (opcode === 107) { npcConfig.clickable = false; } } npcFile.content.readerIndex = 0; return npcConfig; } /** * Decodes every npc file within the npc archive and returns * the resulting NpcConfig array. */ decodeNpcStore() { if (!this.npcArchive) { common_1.logger.error('Npc archive not found.'); return null; } const npcCount = this.npcArchive.files.size; const npcList = new Array(npcCount); for (let npcId = 0; npcId < npcCount; npcId++) { const npcFile = this.npcArchive.getFile(npcId) || null; if (!npcFile) { common_1.logger.error('Npc file not found.'); return null; } npcList[npcId] = this.decodeNpcFile(npcFile); if (npcList[npcId].childrenIds) { this.children.set(npcList[npcId].gameId, npcList[npcId].childrenIds); } } for (const childrenEntry of this.children.entries()) { const parentId = childrenEntry[0]; const childrenIds = childrenEntry[1]; for (const childId of childrenIds) { if (npcList[childId]) { npcList[childId].parentId = parentId; } } } return npcList; } } exports.NpcStore = NpcStore;