mirror of
https://github.com/skillbert/rsmv.git
synced 2025-12-23 21:47:48 -05:00
stricter typescript rules
This commit is contained in:
@@ -2,7 +2,7 @@ import { parse } from "../opdecoder";
|
||||
import { appearanceUrl, avatarStringToBytes, avatarToModel } from "./avatar";
|
||||
import * as THREE from "three";
|
||||
import { ThreejsSceneCache, mergeModelDatas, ob3ModelToThree, mergeNaiveBoneids, constModelsIds } from '../3d/modeltothree';
|
||||
import { ModelModifications, constrainedMap, TypedEmitter } from '../utils';
|
||||
import { ModelModifications, constrainedMap, TypedEmitter, CallbackPromise } from '../utils';
|
||||
import { boundMethod } from 'autobind-decorator';
|
||||
import { resolveMorphedObject, modifyMesh, MapRect, ParsemapOpts, parseMapsquare, mapsquareModels, mapsquareToThreeSingle, ChunkData, TileGrid, mapsquareSkybox, generateLocationMeshgroups, PlacedMesh } from '../3d/mapsquare';
|
||||
import { AnimationClip, AnimationMixer, Group, Material, Mesh, MeshBasicMaterial, Object3D, Skeleton, SkeletonHelper, SkinnedMesh, Texture, Vector2 } from "three";
|
||||
@@ -156,11 +156,11 @@ export async function materialToModel(sceneCache: ThreejsSceneCache, modelid: nu
|
||||
export class RSModel extends TypedEmitter<{ loaded: undefined, animchanged: number }> implements ThreeJsSceneElementSource {
|
||||
model: Promise<{ modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip }>;
|
||||
loaded: { modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip, matUvAnims: { tex: Texture, v: Vector2 }[] } | null = null;
|
||||
cache: ThreejsSceneCache;
|
||||
cache!: ThreejsSceneCache;
|
||||
rootnode = new THREE.Group();
|
||||
nullAnimLoaded: (clip: AnimationClip) => void;
|
||||
nullAnimPromise = { clip: null as AnimationClip | null, prom: new CallbackPromise<AnimationClip>() };
|
||||
anims: Record<number, { clip: AnimationClip | null, prom: Promise<AnimationClip> }> = {
|
||||
"-1": { clip: null, prom: new Promise(d => this.nullAnimLoaded = d) }
|
||||
"-1": this.nullAnimPromise
|
||||
};
|
||||
mountedanim: AnimationClip | null = null;
|
||||
mixer = new AnimationMixer(this.rootnode);
|
||||
@@ -232,8 +232,8 @@ export class RSModel extends TypedEmitter<{ loaded: undefined, animchanged: numb
|
||||
}
|
||||
});
|
||||
let nullAnim = new AnimationClip(undefined, undefined, []);
|
||||
this.nullAnimLoaded(nullAnim);
|
||||
this.anims[-1].clip = nullAnim;
|
||||
this.nullAnimPromise.clip = nullAnim;
|
||||
this.nullAnimPromise.prom.done(nullAnim);
|
||||
|
||||
this.rootnode.add(mesh);
|
||||
this.loaded = { mesh, modeldata, nullAnim, matUvAnims };
|
||||
|
||||
@@ -22,6 +22,7 @@ export class ParsedTexture {
|
||||
if (texture instanceof ImageData) {
|
||||
this.filesize = texture.data.byteLength;
|
||||
this.type = "imagedata";
|
||||
this.mipmaps = 1;
|
||||
this.cachedImageDatas = [Promise.resolve(texture)];
|
||||
} else {
|
||||
this.filesize = texture.byteLength;
|
||||
@@ -36,34 +37,35 @@ export class ParsedTexture {
|
||||
let offset = 0;
|
||||
|
||||
//peek first bytes of first image file
|
||||
let foundtype = false;
|
||||
for (let extraoffset = 0; extraoffset <= 1; extraoffset++) {
|
||||
let extraoffset = 0
|
||||
while (true) {
|
||||
let byte0 = texture.readUInt8(extraoffset + offset + 1 + 4 + 0);
|
||||
let byte1 = texture.readUInt8(extraoffset + offset + 1 + 4 + 1);
|
||||
if (byte0 == 0 && byte1 == 0) {
|
||||
//has no header magic, but starts by writing the width in uint32 BE, any widths under 65k have 0x0000xxxx
|
||||
this.type = "bmpmips";
|
||||
break;
|
||||
} else if (byte0 == 0x44 && byte1 == 0x44) {
|
||||
//0x44445320 "DDS "
|
||||
this.type = "dds";
|
||||
break;
|
||||
} else if (byte0 == 0x89 && byte1 == 0x50) {
|
||||
//0x89504e47 ".PNG"
|
||||
this.type = "png";
|
||||
break;
|
||||
} else if (byte0 == 0xab && byte1 == 0x4b) {
|
||||
//0xab4b5458 "«KTX"
|
||||
this.type = "ktx";
|
||||
} else {
|
||||
break;
|
||||
} else if (extraoffset++ <= 1) {
|
||||
continue;
|
||||
}
|
||||
foundtype = true;
|
||||
throw new Error(`failed to detect texture`);
|
||||
}
|
||||
if (extraoffset == 1) {
|
||||
let numtexs = texture.readUint8(offset++);
|
||||
//TODO figure this out further
|
||||
}
|
||||
break;
|
||||
} if (!foundtype) {
|
||||
throw new Error(`failed to detect texture`);
|
||||
}
|
||||
this.mipmaps = texture.readUInt8(offset++);
|
||||
|
||||
if (this.type == "bmpmips") {
|
||||
|
||||
9
src/cache/downloader.ts
vendored
9
src/cache/downloader.ts
vendored
@@ -4,7 +4,7 @@ import * as net from "net";
|
||||
import fetch from "node-fetch";
|
||||
import { crc32 } from "../libs/crc32util";
|
||||
import { FileParser } from "../opdecoder";
|
||||
import { delay } from "../utils";
|
||||
import { CallbackPromise, delay } from "../utils";
|
||||
import { cacheMajors } from "../constants";
|
||||
|
||||
const maxblocksize = 102400;
|
||||
@@ -96,7 +96,7 @@ function trackDataUsage(len: number) {
|
||||
|
||||
class DownloadSocket {
|
||||
pending: PendingFile[] = [];
|
||||
ready: Promise<void>;
|
||||
ready = new CallbackPromise();
|
||||
socket: net.Socket;
|
||||
config: ParsedClientconfig;
|
||||
|
||||
@@ -148,8 +148,8 @@ class DownloadSocket {
|
||||
}
|
||||
|
||||
async run() {
|
||||
this.ready = this.connect();
|
||||
await this.ready;
|
||||
await this.connect();
|
||||
this.ready.done();
|
||||
while (true) {
|
||||
let bytesread = 0;
|
||||
try { var chunk = await this.getChunk(1 + 4); }
|
||||
@@ -235,7 +235,6 @@ export class CacheDownloader extends DirectCacheFileSource {
|
||||
configPromise: Promise<ParsedClientconfig>;
|
||||
socket: DownloadSocket | null = null;
|
||||
socketPromise: Promise<DownloadSocket> | null = null;
|
||||
pending: PendingFile[];
|
||||
|
||||
constructor() {
|
||||
super(true);
|
||||
|
||||
2
src/cache/index.ts
vendored
2
src/cache/index.ts
vendored
@@ -328,7 +328,7 @@ export abstract class CacheFileSource {
|
||||
export abstract class DirectCacheFileSource extends CacheFileSource {
|
||||
indexMap = new Map<number, Promise<CacheIndexFile>>();
|
||||
requiresCrc: boolean;
|
||||
xteakeys: XteaTable | null;
|
||||
xteakeys: XteaTable | null = null;
|
||||
|
||||
constructor(needscrc: boolean) {
|
||||
super();
|
||||
|
||||
1
src/cache/rawfiles.ts
vendored
1
src/cache/rawfiles.ts
vendored
@@ -5,7 +5,6 @@ import { CacheFileSource, CacheIndex, CacheIndexFile, SubFile } from "./index";
|
||||
|
||||
export class RawFileLoader extends CacheFileSource {
|
||||
cachedir: string;
|
||||
writable: boolean;
|
||||
virtualMajor: number;
|
||||
index: CacheIndex[];
|
||||
files = new Map<number, string>();
|
||||
|
||||
2
src/cache/sqlitewasm.ts
vendored
2
src/cache/sqlitewasm.ts
vendored
@@ -4,8 +4,6 @@ import type { WorkerPackets } from "./sqlitewasmworker";
|
||||
|
||||
|
||||
export class WasmGameCacheLoader extends cache.CacheFileSource {
|
||||
cachedir: string;
|
||||
writable: boolean;
|
||||
indices = new Map<number, Promise<cache.CacheIndexFile>>();
|
||||
dbfiles: Record<string, Blob> = {};
|
||||
worker: Worker;
|
||||
|
||||
@@ -41,7 +41,7 @@ export const cacheMajors = {
|
||||
achievements: 57,
|
||||
|
||||
index: 255
|
||||
}
|
||||
} as const;
|
||||
|
||||
//represents the largest build number that this application is aware off
|
||||
//is used as default value when a cache is considered "current"
|
||||
@@ -53,7 +53,7 @@ export const cacheMapFiles = {
|
||||
squares: 3,
|
||||
squaresWater: 4,
|
||||
square_nxt: 5
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const cacheConfigPages = {
|
||||
mapunderlays: 1,
|
||||
@@ -69,7 +69,7 @@ export const cacheConfigPages = {
|
||||
npcs_old: 9,
|
||||
items_old: 10,
|
||||
spotanim_old: 13
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const lastLegacyBuildnr = 377;
|
||||
//unclear if there ended up beign overlap with (public) rs2 since this was 12 years after rs2 release
|
||||
|
||||
@@ -91,7 +91,6 @@ export class FileEdit {
|
||||
minor: number;
|
||||
subfile: number;
|
||||
action: FileAction;
|
||||
source: CacheFileSource;
|
||||
before: Buffer | Loadable | null;
|
||||
after: Buffer | Loadable | null;
|
||||
constructor(action: FileAction, type: CacheEditType, major: number, minor: number, subfile: number, before: Buffer | Loadable | null, after: Buffer | Loadable | null) {
|
||||
|
||||
99
src/utils.ts
99
src/utils.ts
@@ -368,90 +368,6 @@ export function packedHSL2HSL(hsl: number) {
|
||||
return [h, s, l];
|
||||
}
|
||||
|
||||
/*function packedHSL2RGBAArray(hsl)
|
||||
{
|
||||
var packedRGBA = packedHSL2RGBA(hsl);
|
||||
var rgba = [];
|
||||
rgba.push((packedRGBA ) & 0xFF);
|
||||
rgba.push((packedRGBA >> 8) & 0xFF);
|
||||
rgba.push((packedRGBA >> 16) & 0xFF);
|
||||
rgba.push((packedRGBA >> 24) & 0xFF);
|
||||
return rgba;
|
||||
}*/
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_model_view_projection#Perspective_matrix
|
||||
export function getProjectionMatrix(fieldOfViewInRadians: number, aspectRatio: number, near: number, far: number) {
|
||||
var f = 1.0 / Math.tan(fieldOfViewInRadians / 2);
|
||||
var rangeInv = 1 / (near - far);
|
||||
|
||||
return [
|
||||
f / aspectRatio, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, (near + far) * rangeInv, -1,
|
||||
0, 0, near * far * rangeInv * 2, 0
|
||||
];
|
||||
}
|
||||
|
||||
export namespace Matrix4x4Utils {
|
||||
export function mul(a: number[], b: number[]) {
|
||||
var c: number[] = [];
|
||||
for (var y = 0; y < 4; ++y) {
|
||||
for (var x = 0; x < 4; ++x) {
|
||||
var sum = 0;
|
||||
for (var n = 0; n < 4; ++n) {
|
||||
sum += a[n + y * 4] * b[x + n * 4];
|
||||
}
|
||||
c.push(sum);
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
export function identity() {
|
||||
return [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
];
|
||||
}
|
||||
|
||||
export function translation(x: number, y: number, z: number) {
|
||||
return [
|
||||
1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
x, y, z, 1.0
|
||||
];
|
||||
}
|
||||
|
||||
export function rotation(axis: "x" | "y" | "z", angle: number) {
|
||||
var a = 0, b = 0;
|
||||
if (axis == "x") {
|
||||
a = 1;
|
||||
b = 2;
|
||||
}
|
||||
else if (axis == "y") {
|
||||
a = 0;
|
||||
b = 2;
|
||||
}
|
||||
else if (axis == "z") {
|
||||
a = 0;
|
||||
b = 1;
|
||||
}
|
||||
else
|
||||
//TODO throw here?
|
||||
return; // Incorrect axis parameter, ya basic!
|
||||
|
||||
var matrix = this.identity();
|
||||
matrix[a + a * 4] = Math.cos(angle);
|
||||
matrix[b + b * 4] = Math.cos(angle);
|
||||
matrix[b + a * 4] = -Math.sin(angle);
|
||||
matrix[a + b * 4] = Math.sin(angle);
|
||||
return matrix;
|
||||
}
|
||||
}
|
||||
|
||||
export class TypedEmitter<T extends Record<string, any>> {
|
||||
protected listeners: { [key in keyof T]?: Set<(v: T[key]) => void> } = {};
|
||||
on<K extends keyof T>(event: K, listener: (v: T[K]) => void) {
|
||||
@@ -475,3 +391,18 @@ export class TypedEmitter<T extends Record<string, any>> {
|
||||
listeners.forEach(cb => cb(value));
|
||||
}
|
||||
}
|
||||
|
||||
export class CallbackPromise<T = void> extends Promise<T> {
|
||||
done!: (v: T) => void;
|
||||
err!: (e: Error) => void;
|
||||
constructor(exe = (done: (v: T) => void, err: (e: Error) => void) => { }) {
|
||||
//tmp vars since i can't access this during the super callback
|
||||
let tmpdone: (v: T) => void;
|
||||
let tmperr: (e: Error) => void;
|
||||
super((done, err) => { tmpdone = done; tmperr = err; return exe(done, err); });
|
||||
this.done = tmpdone!;
|
||||
this.err = tmperr!;
|
||||
}
|
||||
}
|
||||
|
||||
globalThis.promhack = CallbackPromise;
|
||||
@@ -2,7 +2,10 @@
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"module": "ESNext",
|
||||
"lib": [ "ESNext","DOM"],
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"DOM"
|
||||
],
|
||||
"target": "ES2020",
|
||||
"sourceMap": false,
|
||||
"alwaysStrict": true,
|
||||
@@ -14,8 +17,14 @@
|
||||
"rootDir": "./src",
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": true,
|
||||
"resolveJsonModule": true
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitThis": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictPropertyInitialization":true
|
||||
},
|
||||
"exclude": [ "node_modules", "./generated"],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"./generated"
|
||||
],
|
||||
"compileOnSave": false
|
||||
}
|
||||
Reference in New Issue
Block a user