@runejs/filestore
Version:
Tools for managing the RuneJS filestore.
358 lines (357 loc) • 13.3 kB
JavaScript
"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;