UNPKG

@runejs/filestore

Version:

Tools for managing the RuneJS filestore.

358 lines (357 loc) 13.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TextureStore = exports.Texture = void 0; const common_1 = require("@runejs/common"); const pngjs_1 = require("pngjs"); const node_fs_1 = require("node:fs"); const sprite_store_1 = require("./sprite-store"); const model_store_1 = require("./model-store"); const util_1 = require("../util"); class Texture { static LOW_MEMORY_TEXTURE_SIZE = 64; static HIGH_MEMORY_TEXTURE_SIZE = 128; static TEXTURE_SIZE = Texture.HIGH_MEMORY_TEXTURE_SIZE; static TEXTURE_INTENSITY = 0.7; static pixelsBuffer; id; rgb; opaque; spriteIds; renderTypes; anIntArray2138; colors; direction; speed; pixels; size; static setSize(size) { Texture.TEXTURE_SIZE = size; } static setIntensity(intensity) { Texture.TEXTURE_INTENSITY = intensity; } generatePixels(spriteStore) { if (this.pixels) { return true; } const size = Texture.TEXTURE_SIZE; this.size = size; const spritePacks = []; for (let i = 0; i < this.spriteIds.length; i++) { const spritePack = spriteStore.getSpritePack(this.spriteIds[i]); if (spritePack == null) { return false; } spritePack.decode(); spritePacks.push(spritePack); } const colorCount = size * size; this.pixels = new Array(colorCount * 4); for (let i = 0; i < this.spriteIds.length; i++) { const sprite = spritePacks[i].sprites[0]; sprite.resizeToLibSize(); const spritePixels = sprite.pixelIdx; const spritePalette = sprite.palette; const color = this.colors[i]; if ((color & ~0xffffff) === 50331648) { const i_15_ = color & 0xff00ff; const i_16_ = (color >> 8) & 0xff; for (let j = 0; j < spritePalette.length; j++) { let i_18_ = spritePalette[j]; if ((i_18_ & 0xffff) === i_18_ >> 8) { i_18_ &= 0xff; spritePalette[j] = (((i_15_ * i_18_) >> 8) & 0xff00ff) | ((i_16_ * i_18_) & 0xff00); } } } for (let j = 0; j < spritePalette.length; j++) { spritePalette[j] = model_store_1.ColorUtils.method707(spritePalette[j], Texture.TEXTURE_INTENSITY); } let renderType; if (i === 0) { renderType = 0; } else { renderType = this.renderTypes[i - 1]; } if (renderType === 0) { if (sprite.width === size) { for (let j = 0; j < colorCount; j++) { this.pixels[j] = spritePalette[spritePixels[j] & 0xff]; } } else if (sprite.width === 64 && size === 128) { let index = 0; for (let i_23_ = 0; i_23_ < size; i_23_++) { for (let i_24_ = 0; i_24_ < size; i_24_++) { this.pixels[index++] = spritePalette[spritePixels[(i_24_ >> 1) + ((i_23_ >> 1) << 6)] & 0xff]; } } } else if (sprite.width === 128 && size === 64) { let index = 0; for (let i_26_ = 0; i_26_ < size; i_26_++) { for (let i_27_ = 0; i_27_ < size; i_27_++) { this.pixels[index++] = spritePalette[spritePixels[(i_27_ << 1) + ((i_26_ << 1) << 7)] & 0xff]; } } } else { throw new Error(); } } } for (let i = 0; i < colorCount; i++) { this.pixels[i] &= 0xf8f8ff; const i_29_ = this.pixels[i]; this.pixels[i + colorCount] = (i_29_ - (i_29_ >>> 3)) & 0xf8f8ff; this.pixels[i + colorCount + colorCount] = (i_29_ - (i_29_ >>> 2)) & 0xf8f8ff; this.pixels[i + colorCount + colorCount + colorCount] = (i_29_ - (i_29_ >>> 2) - (i_29_ >>> 3)) & 0xf8f8ff; } return true; } animate(gameTick) { if (this.pixels != null) { if (this.direction === 1 || this.direction === 3) { if (Texture.pixelsBuffer == null || Texture.pixelsBuffer.length < this.pixels.length) { Texture.pixelsBuffer = new Array(this.pixels.length); } let size; if (this.pixels.length === 16384) { size = 64; } else { size = 128; } const colorCount = this.pixels.length / 4; let textureSpeed = size * gameTick * this.speed; const colorCountMin1 = colorCount - 1; if (this.direction === 1) { textureSpeed = -textureSpeed; } for (let i = 0; i < colorCount; i++) { const i_4_ = (i + textureSpeed) & colorCountMin1; Texture.pixelsBuffer[i] = this.pixels[i_4_]; Texture.pixelsBuffer[i + colorCount] = this.pixels[i_4_ + colorCount]; Texture.pixelsBuffer[i + colorCount + colorCount] = this.pixels[i_4_ + colorCount + colorCount]; Texture.pixelsBuffer[i + colorCount + colorCount + colorCount] = this.pixels[i_4_ + colorCount + colorCount + colorCount]; } const is = this.pixels; this.pixels = Texture.pixelsBuffer; Texture.pixelsBuffer = is; } if (this.direction === 2 || this.direction === 4) { if (Texture.pixelsBuffer == null || Texture.pixelsBuffer.length < this.pixels.length) { Texture.pixelsBuffer = new Array(this.pixels.length); } let size; if (this.pixels.length === 16384) { size = 64; } else { size = 128; } const colorCount = this.pixels.length / 4; let textureSpeed = gameTick * this.speed; const sizeMin1 = size - 1; if (this.direction === 2) { textureSpeed = -textureSpeed; } for (let x = 0; x < colorCount; x += size) { for (let y = 0; y < size; y++) { const i_10_ = x + y; const i_11_ = x + ((y + textureSpeed) & sizeMin1); Texture.pixelsBuffer[i_10_] = this.pixels[i_11_]; Texture.pixelsBuffer[i_10_ + colorCount] = this.pixels[i_11_ + colorCount]; Texture.pixelsBuffer[i_10_ + colorCount + colorCount] = this.pixels[i_11_ + colorCount + colorCount]; Texture.pixelsBuffer[i_10_ + colorCount + colorCount + colorCount] = this.pixels[i_11_ + colorCount + colorCount + colorCount]; } } const is = this.pixels; this.pixels = Texture.pixelsBuffer; Texture.pixelsBuffer = is; } } } resetPixels() { this.pixels = null; } async writeToDisk() { return new Promise((resolve, reject) => { try { const path = './unpacked/textures'; if (!(0, node_fs_1.existsSync)(path)) { (0, node_fs_1.mkdirSync)(path); } const png = this.toPng(); png.pack(); const pngBuffer = pngjs_1.PNG.sync.write(png); (0, node_fs_1.writeFileSync)(`${path}/${this.id}.png`, pngBuffer); resolve(); } catch (e) { reject(e); } }); } /** * Converts the Texture into a base64 PNG image. */ async toBase64() { return await (0, util_1.pngToBase64)(this.toPng()); } /** * Converts the Texture into a PNG image and returns the resulting PNG object. */ toPng() { const size = this.size; const png = new pngjs_1.PNG({ width: size, height: size, filterType: -1, }); for (let x = 0; x < size; x++) { for (let y = 0; y < size; y++) { const pixel = this.pixels[size * y + x]; const [r, g, b] = (0, sprite_store_1.toRgb)(pixel); const pngIndex = (size * y + x) << 2; png.data[pngIndex] = r; png.data[pngIndex + 1] = g; png.data[pngIndex + 2] = b; png.data[pngIndex + 3] = pixel === 0 ? 0 : 255; } } return png; } } exports.Texture = Texture; class TextureStore { fileStore; constructor(fileStore) { this.fileStore = fileStore; } async writeToDisk() { (0, node_fs_1.rmdirSync)('./unpacked/textures', { recursive: true }); const ids = this.fileStore .getIndex('textures') .getArchive(0) .files.keys(); for (const id of ids) { try { const texture = this.getTexture(id); texture.generatePixels(this.fileStore.spriteStore); await texture.writeToDisk(); } catch (e) { common_1.logger.error(`Error writing texture ${id} to disk.`); common_1.logger.error(e); } } } getTexture(id) { if (!id && id !== 0) { common_1.logger.warn(`Invalid texture id specified: ${id}`); return null; } const file = this.fileStore .getIndex('textures') .getArchive(0) .getFile(id); if (file == null) { common_1.logger.warn(`Texture file ${id} not found`); return null; } const buffer = file.content; buffer.readerIndex = 0; const texture = new Texture(); texture.id = id; texture.rgb = buffer.get('SHORT', 'UNSIGNED'); texture.opaque = buffer.get('BYTE', 'UNSIGNED') === 1; const spritesCount = buffer.get('BYTE', 'UNSIGNED'); if (spritesCount < 1 || spritesCount > 4) { throw new Error(); } texture.spriteIds = new Array(spritesCount); for (let i = 0; i < spritesCount; i++) { texture.spriteIds[i] = buffer.get('SHORT', 'UNSIGNED'); } if (spritesCount > 1) { texture.renderTypes = new Array(spritesCount - 1); for (let i = 0; i < spritesCount - 1; i++) { texture.renderTypes[i] = buffer.get('BYTE', 'UNSIGNED'); } } if (spritesCount > 1) { texture.anIntArray2138 = new Array(spritesCount - 1); for (let i = 0; i < spritesCount - 1; i++) { texture.anIntArray2138[i] = buffer.get('BYTE', 'UNSIGNED'); } } texture.colors = new Array(spritesCount); for (let i = 0; i < spritesCount; i++) { texture.colors[i] = buffer.get('INT'); } texture.direction = buffer.get('BYTE', 'UNSIGNED'); texture.speed = buffer.get('BYTE', 'UNSIGNED'); texture.pixels = null; return texture; } getTexturePixels(id) { const texture = this.getTexture(id); if (texture == null) { return null; } if (texture.pixels != null) { return texture.pixels; } const generated = texture.generatePixels(this.fileStore.spriteStore); if (!generated) { return null; } if (texture.rgb === 0) { texture.resetPixels(); } else { //texture.anInt2137--; // TODO Find out why this? } return texture.pixels; } getTextureRgb(id) { const texture = this.getTexture(id); if (texture == null) { return 0; } return texture.rgb; } isTextureOpaque(id) { const texture = this.getTexture(id); if (texture == null) { return false; } return texture.opaque; } // this only works if textures are cached isTextureLowMemory(id) { const texture = this.getTexture(id); if (texture == null) { return false; } texture.generatePixels(this.fileStore.spriteStore); return texture.size === Texture.LOW_MEMORY_TEXTURE_SIZE; } } exports.TextureStore = TextureStore;