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 { appearanceUrl, avatarStringToBytes, avatarToModel } from "./avatar";
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { ThreejsSceneCache, mergeModelDatas, ob3ModelToThree, mergeNaiveBoneids, constModelsIds } from '../3d/modeltothree';
|
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 { boundMethod } from 'autobind-decorator';
|
||||||
import { resolveMorphedObject, modifyMesh, MapRect, ParsemapOpts, parseMapsquare, mapsquareModels, mapsquareToThreeSingle, ChunkData, TileGrid, mapsquareSkybox, generateLocationMeshgroups, PlacedMesh } from '../3d/mapsquare';
|
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";
|
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 {
|
export class RSModel extends TypedEmitter<{ loaded: undefined, animchanged: number }> implements ThreeJsSceneElementSource {
|
||||||
model: Promise<{ modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip }>;
|
model: Promise<{ modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip }>;
|
||||||
loaded: { modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip, matUvAnims: { tex: Texture, v: Vector2 }[] } | null = null;
|
loaded: { modeldata: ModelData, mesh: Object3D, nullAnim: AnimationClip, matUvAnims: { tex: Texture, v: Vector2 }[] } | null = null;
|
||||||
cache: ThreejsSceneCache;
|
cache!: ThreejsSceneCache;
|
||||||
rootnode = new THREE.Group();
|
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> }> = {
|
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;
|
mountedanim: AnimationClip | null = null;
|
||||||
mixer = new AnimationMixer(this.rootnode);
|
mixer = new AnimationMixer(this.rootnode);
|
||||||
@@ -232,8 +232,8 @@ export class RSModel extends TypedEmitter<{ loaded: undefined, animchanged: numb
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let nullAnim = new AnimationClip(undefined, undefined, []);
|
let nullAnim = new AnimationClip(undefined, undefined, []);
|
||||||
this.nullAnimLoaded(nullAnim);
|
this.nullAnimPromise.clip = nullAnim;
|
||||||
this.anims[-1].clip = nullAnim;
|
this.nullAnimPromise.prom.done(nullAnim);
|
||||||
|
|
||||||
this.rootnode.add(mesh);
|
this.rootnode.add(mesh);
|
||||||
this.loaded = { mesh, modeldata, nullAnim, matUvAnims };
|
this.loaded = { mesh, modeldata, nullAnim, matUvAnims };
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export class ParsedTexture {
|
|||||||
if (texture instanceof ImageData) {
|
if (texture instanceof ImageData) {
|
||||||
this.filesize = texture.data.byteLength;
|
this.filesize = texture.data.byteLength;
|
||||||
this.type = "imagedata";
|
this.type = "imagedata";
|
||||||
|
this.mipmaps = 1;
|
||||||
this.cachedImageDatas = [Promise.resolve(texture)];
|
this.cachedImageDatas = [Promise.resolve(texture)];
|
||||||
} else {
|
} else {
|
||||||
this.filesize = texture.byteLength;
|
this.filesize = texture.byteLength;
|
||||||
@@ -36,34 +37,35 @@ export class ParsedTexture {
|
|||||||
let offset = 0;
|
let offset = 0;
|
||||||
|
|
||||||
//peek first bytes of first image file
|
//peek first bytes of first image file
|
||||||
let foundtype = false;
|
let extraoffset = 0
|
||||||
for (let extraoffset = 0; extraoffset <= 1; extraoffset++) {
|
while (true) {
|
||||||
let byte0 = texture.readUInt8(extraoffset + offset + 1 + 4 + 0);
|
let byte0 = texture.readUInt8(extraoffset + offset + 1 + 4 + 0);
|
||||||
let byte1 = texture.readUInt8(extraoffset + offset + 1 + 4 + 1);
|
let byte1 = texture.readUInt8(extraoffset + offset + 1 + 4 + 1);
|
||||||
if (byte0 == 0 && byte1 == 0) {
|
if (byte0 == 0 && byte1 == 0) {
|
||||||
//has no header magic, but starts by writing the width in uint32 BE, any widths under 65k have 0x0000xxxx
|
//has no header magic, but starts by writing the width in uint32 BE, any widths under 65k have 0x0000xxxx
|
||||||
this.type = "bmpmips";
|
this.type = "bmpmips";
|
||||||
|
break;
|
||||||
} else if (byte0 == 0x44 && byte1 == 0x44) {
|
} else if (byte0 == 0x44 && byte1 == 0x44) {
|
||||||
//0x44445320 "DDS "
|
//0x44445320 "DDS "
|
||||||
this.type = "dds";
|
this.type = "dds";
|
||||||
|
break;
|
||||||
} else if (byte0 == 0x89 && byte1 == 0x50) {
|
} else if (byte0 == 0x89 && byte1 == 0x50) {
|
||||||
//0x89504e47 ".PNG"
|
//0x89504e47 ".PNG"
|
||||||
this.type = "png";
|
this.type = "png";
|
||||||
|
break;
|
||||||
} else if (byte0 == 0xab && byte1 == 0x4b) {
|
} else if (byte0 == 0xab && byte1 == 0x4b) {
|
||||||
//0xab4b5458 "«KTX"
|
//0xab4b5458 "«KTX"
|
||||||
this.type = "ktx";
|
this.type = "ktx";
|
||||||
} else {
|
break;
|
||||||
|
} else if (extraoffset++ <= 1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
foundtype = true;
|
|
||||||
if (extraoffset == 1) {
|
|
||||||
let numtexs = texture.readUint8(offset++);
|
|
||||||
//TODO figure this out further
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} if (!foundtype) {
|
|
||||||
throw new Error(`failed to detect texture`);
|
throw new Error(`failed to detect texture`);
|
||||||
}
|
}
|
||||||
|
if (extraoffset == 1) {
|
||||||
|
let numtexs = texture.readUint8(offset++);
|
||||||
|
//TODO figure this out further
|
||||||
|
}
|
||||||
this.mipmaps = texture.readUInt8(offset++);
|
this.mipmaps = texture.readUInt8(offset++);
|
||||||
|
|
||||||
if (this.type == "bmpmips") {
|
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 fetch from "node-fetch";
|
||||||
import { crc32 } from "../libs/crc32util";
|
import { crc32 } from "../libs/crc32util";
|
||||||
import { FileParser } from "../opdecoder";
|
import { FileParser } from "../opdecoder";
|
||||||
import { delay } from "../utils";
|
import { CallbackPromise, delay } from "../utils";
|
||||||
import { cacheMajors } from "../constants";
|
import { cacheMajors } from "../constants";
|
||||||
|
|
||||||
const maxblocksize = 102400;
|
const maxblocksize = 102400;
|
||||||
@@ -96,7 +96,7 @@ function trackDataUsage(len: number) {
|
|||||||
|
|
||||||
class DownloadSocket {
|
class DownloadSocket {
|
||||||
pending: PendingFile[] = [];
|
pending: PendingFile[] = [];
|
||||||
ready: Promise<void>;
|
ready = new CallbackPromise();
|
||||||
socket: net.Socket;
|
socket: net.Socket;
|
||||||
config: ParsedClientconfig;
|
config: ParsedClientconfig;
|
||||||
|
|
||||||
@@ -148,8 +148,8 @@ class DownloadSocket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
this.ready = this.connect();
|
await this.connect();
|
||||||
await this.ready;
|
this.ready.done();
|
||||||
while (true) {
|
while (true) {
|
||||||
let bytesread = 0;
|
let bytesread = 0;
|
||||||
try { var chunk = await this.getChunk(1 + 4); }
|
try { var chunk = await this.getChunk(1 + 4); }
|
||||||
@@ -235,7 +235,6 @@ export class CacheDownloader extends DirectCacheFileSource {
|
|||||||
configPromise: Promise<ParsedClientconfig>;
|
configPromise: Promise<ParsedClientconfig>;
|
||||||
socket: DownloadSocket | null = null;
|
socket: DownloadSocket | null = null;
|
||||||
socketPromise: Promise<DownloadSocket> | null = null;
|
socketPromise: Promise<DownloadSocket> | null = null;
|
||||||
pending: PendingFile[];
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true);
|
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 {
|
export abstract class DirectCacheFileSource extends CacheFileSource {
|
||||||
indexMap = new Map<number, Promise<CacheIndexFile>>();
|
indexMap = new Map<number, Promise<CacheIndexFile>>();
|
||||||
requiresCrc: boolean;
|
requiresCrc: boolean;
|
||||||
xteakeys: XteaTable | null;
|
xteakeys: XteaTable | null = null;
|
||||||
|
|
||||||
constructor(needscrc: boolean) {
|
constructor(needscrc: boolean) {
|
||||||
super();
|
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 {
|
export class RawFileLoader extends CacheFileSource {
|
||||||
cachedir: string;
|
cachedir: string;
|
||||||
writable: boolean;
|
|
||||||
virtualMajor: number;
|
virtualMajor: number;
|
||||||
index: CacheIndex[];
|
index: CacheIndex[];
|
||||||
files = new Map<number, string>();
|
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 {
|
export class WasmGameCacheLoader extends cache.CacheFileSource {
|
||||||
cachedir: string;
|
|
||||||
writable: boolean;
|
|
||||||
indices = new Map<number, Promise<cache.CacheIndexFile>>();
|
indices = new Map<number, Promise<cache.CacheIndexFile>>();
|
||||||
dbfiles: Record<string, Blob> = {};
|
dbfiles: Record<string, Blob> = {};
|
||||||
worker: Worker;
|
worker: Worker;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export const cacheMajors = {
|
|||||||
achievements: 57,
|
achievements: 57,
|
||||||
|
|
||||||
index: 255
|
index: 255
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
//represents the largest build number that this application is aware off
|
//represents the largest build number that this application is aware off
|
||||||
//is used as default value when a cache is considered "current"
|
//is used as default value when a cache is considered "current"
|
||||||
@@ -53,7 +53,7 @@ export const cacheMapFiles = {
|
|||||||
squares: 3,
|
squares: 3,
|
||||||
squaresWater: 4,
|
squaresWater: 4,
|
||||||
square_nxt: 5
|
square_nxt: 5
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
export const cacheConfigPages = {
|
export const cacheConfigPages = {
|
||||||
mapunderlays: 1,
|
mapunderlays: 1,
|
||||||
@@ -69,7 +69,7 @@ export const cacheConfigPages = {
|
|||||||
npcs_old: 9,
|
npcs_old: 9,
|
||||||
items_old: 10,
|
items_old: 10,
|
||||||
spotanim_old: 13
|
spotanim_old: 13
|
||||||
}
|
} as const;
|
||||||
|
|
||||||
export const lastLegacyBuildnr = 377;
|
export const lastLegacyBuildnr = 377;
|
||||||
//unclear if there ended up beign overlap with (public) rs2 since this was 12 years after rs2 release
|
//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;
|
minor: number;
|
||||||
subfile: number;
|
subfile: number;
|
||||||
action: FileAction;
|
action: FileAction;
|
||||||
source: CacheFileSource;
|
|
||||||
before: Buffer | Loadable | null;
|
before: Buffer | Loadable | null;
|
||||||
after: 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) {
|
constructor(action: FileAction, type: CacheEditType, major: number, minor: number, subfile: number, before: Buffer | Loadable | null, after: Buffer | Loadable | null) {
|
||||||
|
|||||||
101
src/utils.ts
101
src/utils.ts
@@ -368,90 +368,6 @@ export function packedHSL2HSL(hsl: number) {
|
|||||||
return [h, s, l];
|
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>> {
|
export class TypedEmitter<T extends Record<string, any>> {
|
||||||
protected listeners: { [key in keyof T]?: Set<(v: T[key]) => void> } = {};
|
protected listeners: { [key in keyof T]?: Set<(v: T[key]) => void> } = {};
|
||||||
on<K extends keyof T>(event: K, listener: (v: T[K]) => void) {
|
on<K extends keyof T>(event: K, listener: (v: T[K]) => void) {
|
||||||
@@ -474,4 +390,19 @@ export class TypedEmitter<T extends Record<string, any>> {
|
|||||||
let listeners = this.listeners[event] ?? (this.listeners[event] = new Set());
|
let listeners = this.listeners[event] ?? (this.listeners[event] = new Set());
|
||||||
listeners.forEach(cb => cb(value));
|
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": {
|
"compilerOptions": {
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"lib": [ "ESNext","DOM"],
|
"lib": [
|
||||||
|
"ESNext",
|
||||||
|
"DOM"
|
||||||
|
],
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"sourceMap": false,
|
"sourceMap": false,
|
||||||
"alwaysStrict": true,
|
"alwaysStrict": true,
|
||||||
@@ -14,8 +17,14 @@
|
|||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"strictFunctionTypes": true,
|
||||||
|
"strictPropertyInitialization":true
|
||||||
},
|
},
|
||||||
"exclude": [ "node_modules", "./generated"],
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"./generated"
|
||||||
|
],
|
||||||
"compileOnSave": false
|
"compileOnSave": false
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user