Skip to content

Commit

Permalink
feat: improve manager config (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
fallenoak authored Jan 6, 2024
1 parent 1b11362 commit 296942b
Show file tree
Hide file tree
Showing 14 changed files with 136 additions and 287 deletions.
72 changes: 0 additions & 72 deletions src/lib/AssetManager.ts

This file was deleted.

24 changes: 10 additions & 14 deletions src/lib/FormatManager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import AssetManager from './AssetManager.js';
import { normalizePath } from './util.js';
import { AssetHost, loadAsset, normalizePath } from './asset.js';

interface FormatConstructor<T> {
new (...args: any[]): T;
Expand All @@ -9,21 +8,18 @@ interface Format<T> {
load: (data: ArrayBuffer) => T;
}

type FormatManagerOptions = {
host: AssetHost;
};

class FormatManager {
#assetManager: AssetManager;
#host: AssetHost;

#loaded = new Map<string, any>();
#loading = new Map<string, Promise<any>>();

constructor(assetManager: AssetManager) {
this.#assetManager = assetManager;
}

get baseUrl() {
return this.#assetManager.baseUrl;
}

get normalizePath() {
return this.#assetManager.normalizePath;
constructor(options: FormatManagerOptions) {
this.#host = options.host;
}

get<T extends Format<T>>(
Expand Down Expand Up @@ -61,7 +57,7 @@ class FormatManager {
): Promise<T> {
let instance: T;
try {
const data = await this.#assetManager.get(path);
const data = await loadAsset(this.#host, path);
instance = new FormatClass(...formatConstructorArgs).load(data);

this.#loaded.set(cacheKey, instance);
Expand Down
31 changes: 31 additions & 0 deletions src/lib/asset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
type AssetHost = {
baseUrl: string;
normalizePath: boolean;
};

const getAssetUrl = (host: AssetHost, path: string) => {
const urlPath = host.normalizePath ? normalizePath(path) : path;
return `${host.baseUrl}/${urlPath}`;
};

const loadAsset = async (host: AssetHost, path: string) => {
const response = await fetch(getAssetUrl(host, path));

// Handle non-2xx responses
if (!response.ok) {
throw new Error(`Error loading asset: ${response.status} ${response.statusText}`);
}

return response.arrayBuffer();
};

/**
* Given an MPQ-style path, return a normalized version of the path with all backslashes turned
* to forward slashes, leading and trailing whitespace removed, and all characters turned to
* lowercase.
*
* @param path
*/
const normalizePath = (path: string) => path.trim().toLowerCase().replaceAll(/\\/g, '/');

export { AssetHost, getAssetUrl, loadAsset, normalizePath };
1 change: 0 additions & 1 deletion src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
export * from './util.js';
export * from './controls/OrbitControls.js';
export * from './controls/MapControls.js';
export * from './AssetManager.js';
export * from './FormatManager.js';
export * from './SceneWorker.js';
export * from './model/ModelManager.js';
Expand Down
17 changes: 14 additions & 3 deletions src/lib/map/DoodadManager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import * as THREE from 'three';
import { MapArea } from '@wowserhq/format';
import ModelManager from '../model/ModelManager.js';
import FormatManager from '../FormatManager.js';
import TextureManager from '../texture/TextureManager.js';
import { AssetHost } from '../asset.js';

type DoodadManagerOptions = {
host: AssetHost;
textureManager?: TextureManager;
};

class DoodadManager {
#host: AssetHost;
#modelManager: ModelManager;

constructor(formatManager: FormatManager, textureManager: TextureManager) {
this.#modelManager = new ModelManager(formatManager, textureManager);
constructor(options: DoodadManagerOptions) {
this.#host = options.host;

this.#modelManager = new ModelManager({
host: options.host,
textureManager: options.textureManager,
});
}

async getArea(area: MapArea) {
Expand Down
43 changes: 31 additions & 12 deletions src/lib/map/MapManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import FormatManager from '../FormatManager.js';
import TerrainManager from '../terrain/TerrainManager.js';
import TextureManager from '../texture/TextureManager.js';
import DoodadManager from './DoodadManager.js';
import { AssetHost } from '../asset.js';

type MapManagerOptions = {
host: AssetHost;
formatManager?: FormatManager;
textureManager?: TextureManager;
};

class MapManager {
#mapName: string;
Expand All @@ -28,28 +35,28 @@ class MapManager {
#targetChunkX: number;
#targetChunkY: number;

#viewDistance = 1277.0;
#viewDistance = 577.0;
#projScreenMatrix = new THREE.Matrix4();
#cameraFrustum = new THREE.Frustum();

#desiredAreas = new Set<number>();

constructor(mapName: string, formatManager: FormatManager, textureManager: TextureManager) {
this.#mapName = mapName;
this.#mapDir = `world/maps/${mapName}`;
constructor(options: MapManagerOptions) {
this.#formatManager = new FormatManager({ host: options.host });
this.#textureManager = options.textureManager ?? new TextureManager({ host: options.host });

this.#formatManager = formatManager;
this.#textureManager = textureManager;
this.#terrainManager = new TerrainManager(this.#textureManager);
this.#doodadManager = new DoodadManager(this.#formatManager, this.#textureManager);
this.#terrainManager = new TerrainManager({
host: options.host,
textureManager: this.#textureManager,
});
this.#doodadManager = new DoodadManager({
host: options.host,
textureManager: this.#textureManager,
});

this.#root = new THREE.Group();
this.#root.name = this.#mapName;
this.#root.matrixAutoUpdate = false;
this.#root.matrixWorldAutoUpdate = false;

this.#loadMap().catch((error) => console.error(error));
this.#syncAreas().catch((error) => console.error(error));
}

get mapMame() {
Expand All @@ -60,6 +67,18 @@ class MapManager {
return this.#root;
}

load(mapName: string) {
this.#mapName = mapName;
this.#mapDir = `world/maps/${mapName}`;

this.#root.name = `map:${mapName}`;

this.#loadMap().catch((error) => console.error(error));
this.#syncAreas().catch((error) => console.error(error));

return this;
}

setTarget(x: number, y: number) {
this.#target.set(x, y);

Expand Down
18 changes: 13 additions & 5 deletions src/lib/model/ModelManager.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as THREE from 'three';
import { M2_TEXTURE_COMPONENT, M2_TEXTURE_FLAG } from '@wowserhq/format';
import TextureManager from '../texture/TextureManager.js';
import FormatManager from '../FormatManager.js';
import { normalizePath } from '../util.js';
import { AssetHost, normalizePath } from '../asset.js';
import ModelMesh from './ModelMesh.js';
import ModelMaterial from './ModelMaterial.js';
import { getVertexShader } from './shader/vertex.js';
Expand All @@ -17,15 +16,24 @@ type ModelResources = {
materials: THREE.Material[];
};

type ModelManagerOptions = {
host: AssetHost;
textureManager?: TextureManager;
};

class ModelManager {
#host: AssetHost;
#textureManager: TextureManager;

#loader: ModelLoader;
#loaded = new globalThis.Map<string, ModelResources>();
#loading = new globalThis.Map<string, Promise<ModelResources>>();

constructor(formatManager: FormatManager, textureManager: TextureManager) {
this.#textureManager = textureManager;
this.#loader = new ModelLoader(formatManager.baseUrl, formatManager.normalizePath);
constructor(options: ModelManagerOptions) {
this.#host = options.host;

this.#textureManager = options.textureManager ?? new TextureManager({ host: options.host });
this.#loader = new ModelLoader({ host: options.host });
}

async get(path: string) {
Expand Down
9 changes: 7 additions & 2 deletions src/lib/model/loader/ModelLoader.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import SceneWorkerController from '../../worker/SceneWorkerController.js';
import { ModelSpec } from './types.js';
import { AssetHost } from '../../asset.js';

const createWorker = () =>
new Worker(new URL('./worker.js', import.meta.url), {
name: 'model-loader',
type: 'module',
});

type ModelLoaderOptions = {
host: AssetHost;
};

class ModelLoader extends SceneWorkerController {
constructor(baseUrl: string, normalizePath: boolean = false) {
super(createWorker, baseUrl, normalizePath);
constructor(options: ModelLoaderOptions) {
super(createWorker, { host: options.host });
}

loadSpec(path: string): Promise<ModelSpec> {
Expand Down
34 changes: 10 additions & 24 deletions src/lib/model/loader/ModelLoaderWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,29 @@ import { M2Batch, M2Model, M2SkinProfile } from '@wowserhq/format';
import { ModelSpec } from './types.js';
import { getFragmentShader, getVertexShader } from './util.js';
import SceneWorker from '../../worker/SceneWorker.js';
import { normalizePath } from '../../util.js';
import { AssetHost, loadAsset } from '../../asset.js';

type ModelLoaderWorkerOptions = {
host: AssetHost;
};

class ModelLoaderWorker extends SceneWorker {
#baseUrl: string;
#normalizePath: boolean;
#host: AssetHost;

initialize(baseUrl: string, normalizePath: boolean) {
this.#baseUrl = baseUrl;
this.#normalizePath = normalizePath;
initialize(options: ModelLoaderWorkerOptions) {
this.#host = options.host;
}

async loadSpec(path: string) {
const modelData = await this.#loadData(path);
const modelData = await loadAsset(this.#host, path);
const model = new M2Model().load(modelData);

const modelBasePath = path.split('.').at(0);
const skinProfileIndex = model.skinProfileCount - 1;
const skinProfileSuffix = skinProfileIndex.toString().padStart(2, '0');
const skinProfilePath = `${modelBasePath}${skinProfileSuffix}.skin`;

const skinProfileData = await this.#loadData(skinProfilePath);
const skinProfileData = await loadAsset(this.#host, skinProfilePath);
const skinProfile = new M2SkinProfile(model).load(skinProfileData);

const geometry = this.#createGeometrySpec(model, skinProfile);
Expand All @@ -39,17 +41,6 @@ class ModelLoaderWorker extends SceneWorker {
return [spec, transfer];
}

async #loadData(path: string) {
const response = await fetch(this.#getFullUrl(path));

// Handle non-2xx responses
if (!response.ok) {
throw new Error(`Error fetching data: ${response.status} ${response.statusText}`);
}

return response.arrayBuffer();
}

#extractVertices(model: M2Model, skinProfile: M2SkinProfile) {
const vertexArray = new Uint8Array(skinProfile.vertices.length * 48);
const sourceArray = new Uint8Array(model.vertices);
Expand Down Expand Up @@ -109,11 +100,6 @@ class ModelLoaderWorker extends SceneWorker {
fragmentShader,
};
}

#getFullUrl(path: string) {
const urlPath = this.#normalizePath ? normalizePath(path) : path;
return `${this.#baseUrl}/${urlPath}`;
}
}

export default ModelLoaderWorker;
Loading

0 comments on commit 296942b

Please sign in to comment.