@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
159 lines (118 loc) • 4.2 kB
JavaScript
import { max2 } from "../../../../core/math/max2.js";
import Mesh from "./Mesh.js";
import Task from "../../../../core/process/task/Task.js";
import { TaskSignal } from "../../../../core/process/task/TaskSignal.js";
import { assert } from "../../../../core/assert.js";
import { assetTypeByPath } from "./assetTypeByPath.js";
import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
import { clamp01 } from "../../../../core/math/clamp01.js";
/**
* Produces a task that will wait for all existing Meshes of a dataset to be loaded, will fail upon timeout being reached
* @param {EntityComponentDataset} ecd Dataset
* @param {Engine} engine
* @param {number} timeout in milliseconds, measured in wall-clock-time, from initialization of the task
* @return {Task}
*/
export function createTaskWaitForMeshesToLoad(ecd, engine, timeout) {
assert.isNumber(timeout, 'timeout');
assert.notNaN(timeout, 'timeout');
/**
*
* @type {AssetManager}
*/
const am = engine.assetManager;
/**
*
* @type {string[]}
*/
const remaining = [];
/**
*
* @type {Set<string>}
*/
const seen = new Set();
/**
*
* @param {Mesh} m
*/
function collectMesh(m) {
if (seen.has(m.url)) {
// already seen, ignore
return;
}
seen.add(m.url);
}
let cursor = 0;
let startTime = 0;
let currentTime = 0;
const estimatedDuration = timeout / 1000;
const task = new Task({
name: 'Waiting for meshes to load',
initializer() {
remaining.splice(0, remaining.length);
seen.clear();
ecd.traverseComponents(Mesh, collectMesh);
collectIteratorValueToArray(remaining, seen.values());
cursor = 0;
startTime = performance.now();
currentTime = startTime;
},
estimatedDuration,
computeProgress() {
const n = remaining.length;
if (n === 0) {
return 1;
}
const progress = cursor / n;
if (progress >= 1) {
return 1;
}
if (timeout === 0 || !Number.isFinite(timeout)) {
return progress;
}
const relativeExpiredTime = (currentTime - startTime) / timeout;
const p = max2(progress, relativeExpiredTime);
return clamp01(p);
},
cycleFunction() {
currentTime = performance.now();
if (cursor >= remaining.length) {
return TaskSignal.EndSuccess;
}
const path = remaining[cursor];
if (path === null) {
// No path
cursor++;
return TaskSignal.Continue;
}
const type = assetTypeByPath(path);
if (type === null) {
// Failed to figure out asset type
cursor++;
return TaskSignal.Continue;
}
const asset = am.tryGet(path, type);
const is_mesh_loaded = asset !== null;
if (is_mesh_loaded) {
// console.log(`${cursor}/${remaining.length} loaded : ${path}`);
cursor++;
return TaskSignal.Continue;
}
// check if asset failed to load
const failed_to_load = am.isFailed(path, type);
if (failed_to_load) {
// skip and continue
console.log(`Skipped asset failure '${path}'`);
cursor++;
return TaskSignal.Continue;
}
// console.log(`\t!${cursor}/${remaining.length} not loaded : ${path}`);
if ((currentTime - startTime) >= timeout) {
return TaskSignal.EndFailure;
} else {
return TaskSignal.Yield;
}
}
});
return task
}