UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

159 lines (118 loc) 4.2 kB
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 }