@codexo/exojs 0.8.4 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +55 -0
- package/README.md +26 -5
- package/dist/esm/animation/Tween.d.ts +20 -3
- package/dist/esm/animation/Tween.js +16 -8
- package/dist/esm/animation/Tween.js.map +1 -1
- package/dist/esm/animation/TweenManager.d.ts +16 -1
- package/dist/esm/animation/TweenManager.js +27 -2
- package/dist/esm/animation/TweenManager.js.map +1 -1
- package/dist/esm/audio/AudioAnalyser.d.ts +2 -0
- package/dist/esm/audio/AudioAnalyser.js +24 -9
- package/dist/esm/audio/AudioAnalyser.js.map +1 -1
- package/dist/esm/audio/AudioBus.d.ts +1 -0
- package/dist/esm/audio/AudioBus.js +8 -4
- package/dist/esm/audio/AudioBus.js.map +1 -1
- package/dist/esm/audio/AudioListener.d.ts +1 -0
- package/dist/esm/audio/AudioListener.js +7 -5
- package/dist/esm/audio/AudioListener.js.map +1 -1
- package/dist/esm/audio/AudioManager.d.ts +8 -2
- package/dist/esm/audio/AudioManager.js +14 -1
- package/dist/esm/audio/AudioManager.js.map +1 -1
- package/dist/esm/audio/BeatDetector.d.ts +2 -0
- package/dist/esm/audio/BeatDetector.js +27 -661
- package/dist/esm/audio/BeatDetector.js.map +1 -1
- package/dist/esm/audio/Music.d.ts +1 -0
- package/dist/esm/audio/Music.js +7 -3
- package/dist/esm/audio/Music.js.map +1 -1
- package/dist/esm/audio/OscillatorSound.d.ts +1 -0
- package/dist/esm/audio/OscillatorSound.js +7 -3
- package/dist/esm/audio/OscillatorSound.js.map +1 -1
- package/dist/esm/audio/Sound.d.ts +1 -0
- package/dist/esm/audio/Sound.js +7 -3
- package/dist/esm/audio/Sound.js.map +1 -1
- package/dist/esm/audio/audio-context.d.ts +2 -2
- package/dist/esm/audio/audio-context.js +4 -4
- package/dist/esm/audio/audio-context.js.map +1 -1
- package/dist/esm/audio/filters/ChorusFilter.d.ts +1 -0
- package/dist/esm/audio/filters/ChorusFilter.js +7 -3
- package/dist/esm/audio/filters/ChorusFilter.js.map +1 -1
- package/dist/esm/audio/filters/CompressorFilter.d.ts +1 -0
- package/dist/esm/audio/filters/CompressorFilter.js +7 -3
- package/dist/esm/audio/filters/CompressorFilter.js.map +1 -1
- package/dist/esm/audio/filters/DelayFilter.d.ts +1 -0
- package/dist/esm/audio/filters/DelayFilter.js +7 -3
- package/dist/esm/audio/filters/DelayFilter.js.map +1 -1
- package/dist/esm/audio/filters/EqualizerFilter.d.ts +1 -0
- package/dist/esm/audio/filters/EqualizerFilter.js +7 -3
- package/dist/esm/audio/filters/EqualizerFilter.js.map +1 -1
- package/dist/esm/audio/filters/GranularFilter.js +1 -86
- package/dist/esm/audio/filters/GranularFilter.js.map +1 -1
- package/dist/esm/audio/filters/HighpassFilter.d.ts +1 -0
- package/dist/esm/audio/filters/HighpassFilter.js +7 -3
- package/dist/esm/audio/filters/HighpassFilter.js.map +1 -1
- package/dist/esm/audio/filters/LowpassFilter.d.ts +1 -0
- package/dist/esm/audio/filters/LowpassFilter.js +7 -3
- package/dist/esm/audio/filters/LowpassFilter.js.map +1 -1
- package/dist/esm/audio/filters/PitchShiftFilter.js +1 -71
- package/dist/esm/audio/filters/PitchShiftFilter.js.map +1 -1
- package/dist/esm/audio/filters/ReverbFilter.d.ts +1 -0
- package/dist/esm/audio/filters/ReverbFilter.js +7 -3
- package/dist/esm/audio/filters/ReverbFilter.js.map +1 -1
- package/dist/esm/audio/filters/VocoderFilter.js +1 -89
- package/dist/esm/audio/filters/VocoderFilter.js.map +1 -1
- package/dist/esm/audio/filters/WorkletFilter.d.ts +2 -0
- package/dist/esm/audio/filters/WorkletFilter.js +10 -5
- package/dist/esm/audio/filters/WorkletFilter.js.map +1 -1
- package/dist/esm/audio/index.d.ts +15 -10
- package/dist/esm/audio/worklet/registerWorklet.d.ts +1 -1
- package/dist/esm/audio/worklet/registerWorklet.js +2 -2
- package/dist/esm/audio/worklet/registerWorklet.js.map +1 -1
- package/dist/esm/audio/worklets/beat-detector.worklet.d.ts +1 -0
- package/dist/esm/audio/worklets/beat-detector.worklet.js +647 -0
- package/dist/esm/audio/worklets/beat-detector.worklet.js.map +1 -0
- package/dist/esm/audio/worklets/granular.worklet.d.ts +1 -0
- package/dist/esm/audio/worklets/granular.worklet.js +89 -0
- package/dist/esm/audio/worklets/granular.worklet.js.map +1 -0
- package/dist/esm/audio/worklets/pitch-shift.worklet.d.ts +1 -0
- package/dist/esm/audio/worklets/pitch-shift.worklet.js +74 -0
- package/dist/esm/audio/worklets/pitch-shift.worklet.js.map +1 -0
- package/dist/esm/audio/worklets/vocoder.worklet.d.ts +1 -0
- package/dist/esm/audio/worklets/vocoder.worklet.js +92 -0
- package/dist/esm/audio/worklets/vocoder.worklet.js.map +1 -0
- package/dist/esm/core/Application.d.ts +62 -24
- package/dist/esm/core/Application.js +116 -40
- package/dist/esm/core/Application.js.map +1 -1
- package/dist/esm/core/Color.d.ts +0 -8
- package/dist/esm/core/Color.js +0 -24
- package/dist/esm/core/Color.js.map +1 -1
- package/dist/esm/core/Scene.d.ts +32 -72
- package/dist/esm/core/Scene.js +56 -36
- package/dist/esm/core/Scene.js.map +1 -1
- package/dist/esm/core/SceneManager.d.ts +11 -25
- package/dist/esm/core/SceneManager.js +37 -100
- package/dist/esm/core/SceneManager.js.map +1 -1
- package/dist/esm/core/SceneNode.d.ts +28 -14
- package/dist/esm/core/SceneNode.js +66 -33
- package/dist/esm/core/SceneNode.js.map +1 -1
- package/dist/esm/core/Signal.d.ts +24 -28
- package/dist/esm/core/Signal.js +64 -50
- package/dist/esm/core/Signal.js.map +1 -1
- package/dist/esm/core/Timer.d.ts +1 -0
- package/dist/esm/core/Timer.js +3 -0
- package/dist/esm/core/Timer.js.map +1 -1
- package/dist/esm/debug/BoundingBoxesLayer.js +1 -1
- package/dist/esm/debug/BoundingBoxesLayer.js.map +1 -1
- package/dist/esm/debug/HitTestLayer.js +1 -1
- package/dist/esm/debug/HitTestLayer.js.map +1 -1
- package/dist/esm/debug/PerformanceLayer.js +1 -2
- package/dist/esm/debug/PerformanceLayer.js.map +1 -1
- package/dist/esm/debug/PointerStackLayer.js +1 -2
- package/dist/esm/debug/PointerStackLayer.js.map +1 -1
- package/dist/esm/debug/RenderPassInspectorLayer.js +1 -2
- package/dist/esm/debug/RenderPassInspectorLayer.js.map +1 -1
- package/dist/esm/index.js +23 -7
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/input/InputManager.d.ts +1 -0
- package/dist/esm/input/InputManager.js +30 -3
- package/dist/esm/input/InputManager.js.map +1 -1
- package/dist/esm/input/InteractionManager.d.ts +5 -2
- package/dist/esm/input/InteractionManager.js +29 -18
- package/dist/esm/input/InteractionManager.js.map +1 -1
- package/dist/esm/input/Pointer.js +3 -2
- package/dist/esm/input/Pointer.js.map +1 -1
- package/dist/esm/input/internal/interactionManagerRegistry.d.ts +9 -0
- package/dist/esm/input/internal/interactionManagerRegistry.js +10 -0
- package/dist/esm/input/internal/interactionManagerRegistry.js.map +1 -0
- package/dist/esm/math/AbstractVector.d.ts +1 -7
- package/dist/esm/math/AbstractVector.js +6 -20
- package/dist/esm/math/AbstractVector.js.map +1 -1
- package/dist/esm/math/Circle.js +0 -2
- package/dist/esm/math/Circle.js.map +1 -1
- package/dist/esm/math/Collision.d.ts +9 -3
- package/dist/esm/math/Ellipse.d.ts +2 -5
- package/dist/esm/math/Ellipse.js +10 -7
- package/dist/esm/math/Ellipse.js.map +1 -1
- package/dist/esm/math/ObservableVector.d.ts +1 -1
- package/dist/esm/math/ObservableVector.js +3 -3
- package/dist/esm/math/ObservableVector.js.map +1 -1
- package/dist/esm/math/Polygon.d.ts +0 -2
- package/dist/esm/math/Polygon.js +1 -9
- package/dist/esm/math/Polygon.js.map +1 -1
- package/dist/esm/math/Rectangle.js +0 -2
- package/dist/esm/math/Rectangle.js.map +1 -1
- package/dist/esm/math/collision-detection.d.ts +19 -4
- package/dist/esm/math/collision-detection.js +61 -4
- package/dist/esm/math/collision-detection.js.map +1 -1
- package/dist/esm/math/swept-collision.d.ts +16 -12
- package/dist/esm/math/swept-collision.js +109 -19
- package/dist/esm/math/swept-collision.js.map +1 -1
- package/dist/esm/particles/ParticleSystem.js +1 -1
- package/dist/esm/particles/ParticleSystem.js.map +1 -1
- package/dist/esm/particles/index.d.ts +1 -0
- package/dist/esm/rendering/CallbackRenderPass.d.ts +1 -0
- package/dist/esm/rendering/CallbackRenderPass.js +1 -0
- package/dist/esm/rendering/CallbackRenderPass.js.map +1 -1
- package/dist/esm/rendering/Container.d.ts +2 -1
- package/dist/esm/rendering/Container.js +17 -16
- package/dist/esm/rendering/Container.js.map +1 -1
- package/dist/esm/rendering/RenderBackend.d.ts +1 -0
- package/dist/esm/rendering/RenderNode.d.ts +1 -3
- package/dist/esm/rendering/RenderNode.js +12 -19
- package/dist/esm/rendering/RenderNode.js.map +1 -1
- package/dist/esm/rendering/RenderPass.d.ts +1 -0
- package/dist/esm/rendering/RenderStats.d.ts +9 -0
- package/dist/esm/rendering/RenderStats.js +2 -0
- package/dist/esm/rendering/RenderStats.js.map +1 -1
- package/dist/esm/rendering/RendererRegistry.d.ts +1 -0
- package/dist/esm/rendering/RendererRegistry.js +1 -0
- package/dist/esm/rendering/RendererRegistry.js.map +1 -1
- package/dist/esm/rendering/View.d.ts +23 -0
- package/dist/esm/rendering/View.js +42 -0
- package/dist/esm/rendering/View.js.map +1 -1
- package/dist/esm/rendering/index.d.ts +89 -59
- package/dist/esm/rendering/mesh/Mesh.js +1 -1
- package/dist/esm/rendering/mesh/Mesh.js.map +1 -1
- package/dist/esm/rendering/mesh/MeshShader.d.ts +1 -0
- package/dist/esm/rendering/mesh/MeshShader.js +1 -0
- package/dist/esm/rendering/mesh/MeshShader.js.map +1 -1
- package/dist/esm/rendering/shader/Shader.d.ts +1 -0
- package/dist/esm/rendering/shader/Shader.js +1 -0
- package/dist/esm/rendering/shader/Shader.js.map +1 -1
- package/dist/esm/rendering/shader/ShaderUniform.d.ts +1 -0
- package/dist/esm/rendering/shader/ShaderUniform.js +1 -0
- package/dist/esm/rendering/shader/ShaderUniform.js.map +1 -1
- package/dist/esm/rendering/sprite/Sprite.d.ts +3 -2
- package/dist/esm/rendering/sprite/Sprite.js +15 -13
- package/dist/esm/rendering/sprite/Sprite.js.map +1 -1
- package/dist/esm/rendering/text/AbstractText.d.ts +36 -0
- package/dist/esm/rendering/text/AbstractText.js +49 -0
- package/dist/esm/rendering/text/AbstractText.js.map +1 -0
- package/dist/esm/rendering/text/BitmapText.d.ts +97 -0
- package/dist/esm/rendering/text/BitmapText.js +220 -0
- package/dist/esm/rendering/text/BitmapText.js.map +1 -0
- package/dist/esm/rendering/text/BmFont.d.ts +50 -0
- package/dist/esm/rendering/text/BmFont.js +24 -0
- package/dist/esm/rendering/text/BmFont.js.map +1 -0
- package/dist/esm/rendering/text/GlyphAtlas.d.ts +104 -0
- package/dist/esm/rendering/text/GlyphAtlas.js +347 -0
- package/dist/esm/rendering/text/GlyphAtlas.js.map +1 -0
- package/dist/esm/rendering/text/GlyphAtlasPool.d.ts +40 -0
- package/dist/esm/rendering/text/GlyphAtlasPool.js +67 -0
- package/dist/esm/rendering/text/GlyphAtlasPool.js.map +1 -0
- package/dist/esm/rendering/text/GlyphSdf.d.ts +92 -0
- package/dist/esm/rendering/text/GlyphSdf.js +220 -0
- package/dist/esm/rendering/text/GlyphSdf.js.map +1 -0
- package/dist/esm/rendering/text/HTMLText.d.ts +107 -0
- package/dist/esm/rendering/text/HTMLText.js +284 -0
- package/dist/esm/rendering/text/HTMLText.js.map +1 -0
- package/dist/esm/rendering/text/LayoutOptions.d.ts +30 -0
- package/dist/esm/rendering/text/Text.d.ts +89 -20
- package/dist/esm/rendering/text/Text.js +176 -101
- package/dist/esm/rendering/text/Text.js.map +1 -1
- package/dist/esm/rendering/text/TextLayout.d.ts +20 -8
- package/dist/esm/rendering/text/TextLayout.js +234 -25
- package/dist/esm/rendering/text/TextLayout.js.map +1 -1
- package/dist/esm/rendering/text/TextStyle.d.ts +154 -87
- package/dist/esm/rendering/text/TextStyle.js +257 -203
- package/dist/esm/rendering/text/TextStyle.js.map +1 -1
- package/dist/esm/rendering/text/types.d.ts +73 -13
- package/dist/esm/rendering/texture/Texture.d.ts +1 -0
- package/dist/esm/rendering/texture/Texture.js +1 -0
- package/dist/esm/rendering/texture/Texture.js.map +1 -1
- package/dist/esm/rendering/types.d.ts +3 -1
- package/dist/esm/rendering/types.js +2 -0
- package/dist/esm/rendering/types.js.map +1 -1
- package/dist/esm/rendering/video/Video.d.ts +2 -1
- package/dist/esm/rendering/video/Video.js +9 -5
- package/dist/esm/rendering/video/Video.js.map +1 -1
- package/dist/esm/rendering/webgl2/WebGl2Backend.js +41 -5
- package/dist/esm/rendering/webgl2/WebGl2Backend.js.map +1 -1
- package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js +4 -4
- package/dist/esm/rendering/webgl2/WebGl2MeshRenderer.js.map +1 -1
- package/dist/esm/rendering/webgl2/WebGl2TextRenderer.d.ts +56 -0
- package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js +482 -0
- package/dist/esm/rendering/webgl2/WebGl2TextRenderer.js.map +1 -0
- package/dist/esm/rendering/webgl2/glsl/text-color.frag.js +4 -0
- package/dist/esm/rendering/webgl2/glsl/text-color.frag.js.map +1 -0
- package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js +4 -0
- package/dist/esm/rendering/webgl2/glsl/text-msdf.frag.js.map +1 -0
- package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js +4 -0
- package/dist/esm/rendering/webgl2/glsl/text-sdf.frag.js.map +1 -0
- package/dist/esm/rendering/webgl2/glsl/text.vert.js +4 -0
- package/dist/esm/rendering/webgl2/glsl/text.vert.js.map +1 -0
- package/dist/esm/rendering/webgpu/WebGpuBackend.js +16 -8
- package/dist/esm/rendering/webgpu/WebGpuBackend.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuBlendState.js +26 -0
- package/dist/esm/rendering/webgpu/WebGpuBlendState.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.d.ts +2 -2
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js +23 -15
- package/dist/esm/rendering/webgpu/WebGpuMeshRenderer.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js +9 -1
- package/dist/esm/rendering/webgpu/WebGpuSpriteRenderer.js.map +1 -1
- package/dist/esm/rendering/webgpu/WebGpuTextRenderer.d.ts +70 -0
- package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js +773 -0
- package/dist/esm/rendering/webgpu/WebGpuTextRenderer.js.map +1 -0
- package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js +96 -0
- package/dist/esm/rendering/webgpu/compute/WebGpuComputePipeline.js.map +1 -0
- package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js +68 -0
- package/dist/esm/rendering/webgpu/compute/WebGpuStorageBuffer.js.map +1 -0
- package/dist/esm/resources/Asset.d.ts +23 -0
- package/dist/esm/resources/Asset.js +23 -0
- package/dist/esm/resources/Asset.js.map +1 -0
- package/dist/esm/resources/AssetDefinitions.d.ts +137 -0
- package/dist/esm/resources/Assets.d.ts +35 -0
- package/dist/esm/resources/Assets.js +32 -0
- package/dist/esm/resources/Assets.js.map +1 -0
- package/dist/esm/resources/IndexedDbDatabase.js +17 -1
- package/dist/esm/resources/IndexedDbDatabase.js.map +1 -1
- package/dist/esm/resources/IndexedDbStore.js +17 -1
- package/dist/esm/resources/IndexedDbStore.js.map +1 -1
- package/dist/esm/resources/Loader.d.ts +244 -18
- package/dist/esm/resources/Loader.js +456 -50
- package/dist/esm/resources/Loader.js.map +1 -1
- package/dist/esm/resources/LoadingQueue.d.ts +28 -0
- package/dist/esm/resources/LoadingQueue.js +59 -0
- package/dist/esm/resources/LoadingQueue.js.map +1 -0
- package/dist/esm/resources/factories/BmFontFactory.d.ts +25 -0
- package/dist/esm/resources/factories/BmFontFactory.js +96 -0
- package/dist/esm/resources/factories/BmFontFactory.js.map +1 -0
- package/dist/esm/resources/factories/CsvFactory.d.ts +35 -0
- package/dist/esm/resources/factories/CsvFactory.js +87 -0
- package/dist/esm/resources/factories/CsvFactory.js.map +1 -0
- package/dist/esm/resources/factories/MusicFactory.d.ts +8 -2
- package/dist/esm/resources/factories/MusicFactory.js +25 -14
- package/dist/esm/resources/factories/MusicFactory.js.map +1 -1
- package/dist/esm/resources/factories/SoundFactory.d.ts +2 -2
- package/dist/esm/resources/factories/SoundFactory.js.map +1 -1
- package/dist/esm/resources/factories/SubtitleFactory.d.ts +28 -0
- package/dist/esm/resources/factories/SubtitleFactory.js +203 -0
- package/dist/esm/resources/factories/SubtitleFactory.js.map +1 -0
- package/dist/esm/resources/factories/SvgFactory.d.ts +18 -1
- package/dist/esm/resources/factories/SvgFactory.js +21 -2
- package/dist/esm/resources/factories/SvgFactory.js.map +1 -1
- package/dist/esm/resources/factories/VideoFactory.d.ts +8 -2
- package/dist/esm/resources/factories/VideoFactory.js +27 -20
- package/dist/esm/resources/factories/VideoFactory.js.map +1 -1
- package/dist/esm/resources/factories/XmlFactory.d.ts +24 -0
- package/dist/esm/resources/factories/XmlFactory.js +37 -0
- package/dist/esm/resources/factories/XmlFactory.js.map +1 -0
- package/dist/esm/resources/index.d.ts +8 -1
- package/dist/esm/resources/tokens.d.ts +49 -3
- package/dist/esm/resources/tokens.js +50 -4
- package/dist/esm/resources/tokens.js.map +1 -1
- package/dist/exo.esm.js +6635 -2550
- package/dist/exo.esm.js.map +1 -1
- package/package.json +16 -4
- package/dist/esm/input/interaction-hooks.d.ts +0 -34
- package/dist/esm/input/interaction-hooks.js +0 -35
- package/dist/esm/input/interaction-hooks.js.map +0 -1
- package/dist/esm/rendering/text/DynamicGlyphAtlas.d.ts +0 -33
- package/dist/esm/rendering/text/DynamicGlyphAtlas.js +0 -134
- package/dist/esm/rendering/text/DynamicGlyphAtlas.js.map +0 -1
- package/dist/esm/rendering/text/atlas-singleton.d.ts +0 -7
- package/dist/esm/rendering/text/atlas-singleton.js +0 -17
- package/dist/esm/rendering/text/atlas-singleton.js.map +0 -1
- package/dist/esm/resources/factories/VttFactory.d.ts +0 -24
- package/dist/esm/resources/factories/VttFactory.js +0 -158
- package/dist/esm/resources/factories/VttFactory.js.map +0 -1
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
import { Music } from '../audio/Music.js';
|
|
2
2
|
import { Sound } from '../audio/Sound.js';
|
|
3
3
|
import { Signal } from '../core/Signal.js';
|
|
4
|
+
import { BmFont } from '../rendering/text/BmFont.js';
|
|
4
5
|
import { Texture } from '../rendering/texture/Texture.js';
|
|
5
6
|
import { Video } from '../rendering/video/Video.js';
|
|
7
|
+
import { AssetImpl, Asset } from './Asset.js';
|
|
6
8
|
import { defineAssetManifest, BundleLoadError } from './AssetManifest.js';
|
|
9
|
+
import { AssetsImpl } from './Assets.js';
|
|
7
10
|
import { CacheFirstStrategy } from './CacheFirstStrategy.js';
|
|
8
11
|
import { BinaryFactory } from './factories/BinaryFactory.js';
|
|
12
|
+
import { BmFontLoaderFactory } from './factories/BmFontFactory.js';
|
|
13
|
+
import { CsvFactory } from './factories/CsvFactory.js';
|
|
9
14
|
import { FontFactory } from './factories/FontFactory.js';
|
|
10
15
|
import { ImageFactory } from './factories/ImageFactory.js';
|
|
11
16
|
import { JsonFactory } from './factories/JsonFactory.js';
|
|
12
17
|
import { MusicFactory } from './factories/MusicFactory.js';
|
|
13
18
|
import { SoundFactory } from './factories/SoundFactory.js';
|
|
19
|
+
import { SubtitleFactory } from './factories/SubtitleFactory.js';
|
|
14
20
|
import { SvgFactory } from './factories/SvgFactory.js';
|
|
15
21
|
import { TextFactory } from './factories/TextFactory.js';
|
|
16
22
|
import { TextureFactory } from './factories/TextureFactory.js';
|
|
17
23
|
import { VideoFactory } from './factories/VideoFactory.js';
|
|
18
|
-
import { VttFactory } from './factories/VttFactory.js';
|
|
19
24
|
import { WasmFactory } from './factories/WasmFactory.js';
|
|
25
|
+
import { XmlFactory } from './factories/XmlFactory.js';
|
|
20
26
|
import { FactoryRegistry } from './FactoryRegistry.js';
|
|
21
|
-
import {
|
|
27
|
+
import { LoadingQueue } from './LoadingQueue.js';
|
|
28
|
+
import { FontAsset, Json, TextAsset, SvgAsset, SubtitleAsset, XmlAsset, CsvAsset, BinaryAsset, ImageAsset, WasmAsset } from './tokens.js';
|
|
22
29
|
|
|
23
30
|
// ---------------------------------------------------------------------------
|
|
24
31
|
// Loader
|
|
@@ -45,12 +52,13 @@ import { Json, TextAsset, SvgAsset, VttAsset } from './tokens.js';
|
|
|
45
52
|
*
|
|
46
53
|
* @example
|
|
47
54
|
* ```ts
|
|
48
|
-
* const loader = new Loader({
|
|
55
|
+
* const loader = new Loader({ basePath: '/assets/', cache: new IndexedDbStore('game') });
|
|
49
56
|
* const texture = await loader.load(Texture, 'hero.png');
|
|
50
57
|
* ```
|
|
51
58
|
*/
|
|
52
59
|
class Loader {
|
|
53
60
|
_registry = new FactoryRegistry();
|
|
61
|
+
_assetTypeMap = new Map();
|
|
54
62
|
_resources = new Map();
|
|
55
63
|
_manifest = new Map();
|
|
56
64
|
_bundles = new Map();
|
|
@@ -59,8 +67,19 @@ class Loader {
|
|
|
59
67
|
_preventStoreKeys = new Set();
|
|
60
68
|
_stores;
|
|
61
69
|
_cacheStrategy;
|
|
62
|
-
|
|
63
|
-
|
|
70
|
+
// ── Identity / alias tracking for the new Asset API ───────────────────────
|
|
71
|
+
// Maps alias key (`${typeId}:${alias}`) to an identity key (`id:${typeId}:${source}`)
|
|
72
|
+
_aliasKeyToIdentityKey = new Map();
|
|
73
|
+
// Maps identity key to the set of aliases registered under that identity (within same type)
|
|
74
|
+
_identityKeyToAliases = new Map();
|
|
75
|
+
// In-flight promises keyed by identity (source-based) for cross-alias dedup
|
|
76
|
+
_inFlightByIdentity = new Map();
|
|
77
|
+
// Handler entries registered via the handler-based registerAssetType overload
|
|
78
|
+
_handlerFunctions = new Map();
|
|
79
|
+
// Maps lower-case file extensions (without dot) to the constructor to use
|
|
80
|
+
_extensionMap = new Map();
|
|
81
|
+
_basePath;
|
|
82
|
+
_fetchOptions;
|
|
64
83
|
_concurrency;
|
|
65
84
|
_nextTypeId = 1;
|
|
66
85
|
_backgroundQueue = [];
|
|
@@ -77,8 +96,8 @@ class Loader {
|
|
|
77
96
|
/** Dispatched when an asset fails to load during background or bundle loading. */
|
|
78
97
|
onError = new Signal();
|
|
79
98
|
constructor(options = {}) {
|
|
80
|
-
this.
|
|
81
|
-
this.
|
|
99
|
+
this._basePath = options.basePath ?? '';
|
|
100
|
+
this._fetchOptions = options.fetchOptions ?? {};
|
|
82
101
|
this._concurrency = options.concurrency ?? 6;
|
|
83
102
|
this._stores = options.cache ? (Array.isArray(options.cache) ? options.cache : [options.cache]) : [];
|
|
84
103
|
this._cacheStrategy = options.cacheStrategy ?? new CacheFirstStrategy();
|
|
@@ -99,6 +118,47 @@ class Loader {
|
|
|
99
118
|
this._registry.register(type, factory);
|
|
100
119
|
return this;
|
|
101
120
|
}
|
|
121
|
+
registerAssetType(typeName, ctorOrHandler, factory) {
|
|
122
|
+
if (typeof ctorOrHandler === 'function') {
|
|
123
|
+
this._assetTypeMap.set(typeName, ctorOrHandler);
|
|
124
|
+
if (factory) {
|
|
125
|
+
this._registry.register(ctorOrHandler, factory);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Handler-based form: create a synthetic constructor for type identity
|
|
130
|
+
const syntheticCtor = class {
|
|
131
|
+
};
|
|
132
|
+
Object.defineProperty(syntheticCtor, 'name', { value: typeName });
|
|
133
|
+
this._assetTypeMap.set(typeName, syntheticCtor);
|
|
134
|
+
this._handlerFunctions.set(syntheticCtor, {
|
|
135
|
+
load: (config, ctx) => ctorOrHandler.load(config, ctx),
|
|
136
|
+
getIdentityKey: ctorOrHandler.getIdentityKey?.bind(ctorOrHandler),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
// -----------------------------------------------------------------------
|
|
142
|
+
// Extension registration
|
|
143
|
+
// -----------------------------------------------------------------------
|
|
144
|
+
/**
|
|
145
|
+
* Associates a file extension with an asset type so that
|
|
146
|
+
* `loader.load('path.ext')` (the single-string overload) can infer the
|
|
147
|
+
* type automatically.
|
|
148
|
+
*
|
|
149
|
+
* `ext` is matched case-insensitively and the leading dot is optional.
|
|
150
|
+
* The type must already have a registered factory (via {@link register} or
|
|
151
|
+
* {@link registerAssetType}).
|
|
152
|
+
*
|
|
153
|
+
* ```ts
|
|
154
|
+
* loader.registerExtension('tmj', TiledMap);
|
|
155
|
+
* const map = await loader.load('world.tmj'); // TiledMap
|
|
156
|
+
* ```
|
|
157
|
+
*/
|
|
158
|
+
registerExtension(ext, type) {
|
|
159
|
+
this._extensionMap.set(ext.replace(/^\./, '').toLowerCase(), type);
|
|
160
|
+
return this;
|
|
161
|
+
}
|
|
102
162
|
add(type, source) {
|
|
103
163
|
const ctor = type;
|
|
104
164
|
if (typeof source === 'string') {
|
|
@@ -219,20 +279,120 @@ class Loader {
|
|
|
219
279
|
// -----------------------------------------------------------------------
|
|
220
280
|
// Loading — implementation
|
|
221
281
|
// -----------------------------------------------------------------------
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
282
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
283
|
+
load(arg0, arg1, arg2) {
|
|
284
|
+
// 1. Single Asset<T>
|
|
285
|
+
if (arg0 instanceof AssetImpl) {
|
|
286
|
+
const asset = arg0;
|
|
287
|
+
const alias = asset._config.source;
|
|
288
|
+
return this._createLoadingQueue([{ alias, asset }], results => results.get(alias));
|
|
289
|
+
}
|
|
290
|
+
// 2. Assets<M> container
|
|
291
|
+
if (arg0 instanceof AssetsImpl) {
|
|
292
|
+
const container = arg0;
|
|
293
|
+
const items = Object.entries(container.entries).map(([alias, a]) => ({
|
|
294
|
+
alias,
|
|
295
|
+
asset: a,
|
|
296
|
+
}));
|
|
297
|
+
return this._createLoadingQueue(items, results => {
|
|
298
|
+
const out = {};
|
|
299
|
+
for (const { alias } of items) {
|
|
300
|
+
out[alias] = results.get(alias);
|
|
301
|
+
}
|
|
302
|
+
return out;
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
// 2b. Extension-based: single path string with no type token
|
|
306
|
+
if (typeof arg0 === 'string' && arg1 === undefined) {
|
|
307
|
+
const path = arg0;
|
|
308
|
+
const ext = path.match(/\.([^./?#]+)(?:[?#]|$)/)?.[1]?.toLowerCase();
|
|
309
|
+
const ctor = ext ? this._extensionMap.get(ext) : undefined;
|
|
310
|
+
if (ctor === undefined) {
|
|
311
|
+
throw new Error(`Loader: no type registered for extension ".${ext ?? '?'}" in "${path}". ` + 'Register one via loader.registerExtension().');
|
|
312
|
+
}
|
|
313
|
+
// FontAsset requires a family option — infer it from the filename when not provided
|
|
314
|
+
const options = ctor === FontAsset ? { family: (path.split('/').pop()?.split(/[?#]/)[0] ?? '').replace(/\.[^.]+$/, '') } : undefined;
|
|
315
|
+
let notifyFn = null;
|
|
316
|
+
const promise = this._loadSingle(ctor, path, options).then(v => {
|
|
317
|
+
notifyFn?.(true);
|
|
318
|
+
return v;
|
|
319
|
+
}, e => {
|
|
320
|
+
notifyFn?.(false);
|
|
321
|
+
throw e;
|
|
322
|
+
});
|
|
323
|
+
const queue = new LoadingQueue(promise, 1);
|
|
324
|
+
notifyFn = queue._notifyItem.bind(queue);
|
|
325
|
+
return queue;
|
|
226
326
|
}
|
|
227
|
-
|
|
228
|
-
|
|
327
|
+
// 3. Old path: first arg is a Loadable constructor
|
|
328
|
+
if (typeof arg0 === 'function') {
|
|
329
|
+
const ctor = arg0;
|
|
330
|
+
const source = arg1;
|
|
331
|
+
const options = arg2;
|
|
332
|
+
if (typeof source === 'string') {
|
|
333
|
+
let notifyFn = null;
|
|
334
|
+
const promise = this._loadSingle(ctor, source, options).then(v => {
|
|
335
|
+
notifyFn?.(true);
|
|
336
|
+
return v;
|
|
337
|
+
}, e => {
|
|
338
|
+
notifyFn?.(false);
|
|
339
|
+
throw e;
|
|
340
|
+
});
|
|
341
|
+
const queue = new LoadingQueue(promise, 1);
|
|
342
|
+
notifyFn = queue._notifyItem.bind(queue);
|
|
343
|
+
return queue;
|
|
344
|
+
}
|
|
345
|
+
if (Array.isArray(source)) {
|
|
346
|
+
const paths = source;
|
|
347
|
+
let notifyFn = null;
|
|
348
|
+
const results = new Array(paths.length);
|
|
349
|
+
const promises = paths.map((path, i) => this._loadSingle(ctor, path, options).then(v => {
|
|
350
|
+
results[i] = v;
|
|
351
|
+
notifyFn?.(true);
|
|
352
|
+
}, e => {
|
|
353
|
+
notifyFn?.(false);
|
|
354
|
+
throw e;
|
|
355
|
+
}));
|
|
356
|
+
const promise = Promise.all(promises).then(() => results);
|
|
357
|
+
const queue = new LoadingQueue(promise, paths.length);
|
|
358
|
+
notifyFn = queue._notifyItem.bind(queue);
|
|
359
|
+
return queue;
|
|
360
|
+
}
|
|
361
|
+
// Record<string, BatchValue>
|
|
362
|
+
const entries = Object.entries(source);
|
|
363
|
+
const result = {};
|
|
364
|
+
let notifyFn = null;
|
|
365
|
+
const promises = entries.map(([alias, pathOrConfig]) => {
|
|
366
|
+
const path = typeof pathOrConfig === 'string' ? pathOrConfig : pathOrConfig.source;
|
|
367
|
+
const itemOptions = typeof pathOrConfig === 'string'
|
|
368
|
+
? options
|
|
369
|
+
: { ...pathOrConfig, ...(typeof options === 'object' && options !== null ? options : {}) };
|
|
370
|
+
return this._loadSingle(ctor, alias, itemOptions, path).then(v => {
|
|
371
|
+
result[alias] = v;
|
|
372
|
+
notifyFn?.(true);
|
|
373
|
+
}, e => {
|
|
374
|
+
notifyFn?.(false);
|
|
375
|
+
throw e;
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
const promise = Promise.all(promises).then(() => result);
|
|
379
|
+
const queue = new LoadingQueue(promise, entries.length);
|
|
380
|
+
notifyFn = queue._notifyItem.bind(queue);
|
|
381
|
+
return queue;
|
|
229
382
|
}
|
|
230
|
-
|
|
231
|
-
const
|
|
232
|
-
|
|
233
|
-
|
|
383
|
+
// 4. Plain config map: Record<string, AssetInput>
|
|
384
|
+
const configMap = arg0;
|
|
385
|
+
const items = Object.entries(configMap).map(([alias, value]) => ({
|
|
386
|
+
alias,
|
|
387
|
+
asset: (value instanceof AssetImpl ? value : new Asset(value)),
|
|
234
388
|
}));
|
|
235
|
-
return
|
|
389
|
+
return this._createLoadingQueue(items, results => {
|
|
390
|
+
const out = {};
|
|
391
|
+
for (const { alias } of items) {
|
|
392
|
+
out[alias] = results.get(alias);
|
|
393
|
+
}
|
|
394
|
+
return out;
|
|
395
|
+
});
|
|
236
396
|
}
|
|
237
397
|
// -----------------------------------------------------------------------
|
|
238
398
|
// Background loading
|
|
@@ -308,22 +468,70 @@ class Loader {
|
|
|
308
468
|
const ctor = type;
|
|
309
469
|
return this._resources.get(ctor)?.has(alias) ?? false;
|
|
310
470
|
}
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
471
|
+
unload(arg0, arg1) {
|
|
472
|
+
if (arg0 instanceof AssetImpl) {
|
|
473
|
+
const asset = arg0;
|
|
474
|
+
const ctor = this._assetTypeMap.get(asset.type);
|
|
475
|
+
if (!ctor)
|
|
476
|
+
return this;
|
|
477
|
+
const identityKey = this._resolveAssetIdentityKey(ctor, asset);
|
|
478
|
+
const aliasSet = this._identityKeyToAliases.get(identityKey);
|
|
479
|
+
if (aliasSet && aliasSet.size > 0) {
|
|
480
|
+
// Snapshot the set because _unloadOne modifies it during iteration
|
|
481
|
+
for (const alias of [...aliasSet]) {
|
|
482
|
+
this._unloadOne(ctor, alias);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
// Asset was loaded without alias-map tracking (e.g. single-asset load).
|
|
487
|
+
// Fall back to using the source as the alias.
|
|
488
|
+
this._unloadOne(ctor, asset._config.source);
|
|
489
|
+
}
|
|
490
|
+
return this;
|
|
491
|
+
}
|
|
492
|
+
if (arg0 instanceof AssetsImpl) {
|
|
493
|
+
const container = arg0;
|
|
494
|
+
for (const [alias, a] of Object.entries(container.entries)) {
|
|
495
|
+
const assetRef = a;
|
|
496
|
+
const ctor = this._assetTypeMap.get(assetRef.type);
|
|
497
|
+
if (!ctor)
|
|
498
|
+
continue;
|
|
499
|
+
const identityKey = this._resolveAssetIdentityKey(ctor, assetRef);
|
|
500
|
+
const aliasSet = this._identityKeyToAliases.get(identityKey);
|
|
501
|
+
if (aliasSet?.has(alias)) {
|
|
502
|
+
// Also remove all other aliases that share this resource identity
|
|
503
|
+
for (const a2 of [...aliasSet]) {
|
|
504
|
+
this._unloadOne(ctor, a2);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
this._unloadOne(ctor, alias);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return this;
|
|
512
|
+
}
|
|
513
|
+
return this._unloadOne(arg0, arg1);
|
|
514
|
+
}
|
|
515
|
+
_unloadOne(type, alias) {
|
|
322
516
|
const ctor = type;
|
|
323
|
-
const
|
|
517
|
+
const aliasKey = this._key(ctor, alias);
|
|
324
518
|
this._resources.get(ctor)?.delete(alias);
|
|
325
|
-
|
|
326
|
-
|
|
519
|
+
// If a fetch is in flight (via legacy or identity-based map), prevent the
|
|
520
|
+
// result from being written to _resources once it arrives.
|
|
521
|
+
const identityKey = this._aliasKeyToIdentityKey.get(aliasKey);
|
|
522
|
+
if (this._inFlight.has(aliasKey) || (identityKey !== undefined && this._inFlightByIdentity.has(identityKey))) {
|
|
523
|
+
this._preventStoreKeys.add(aliasKey);
|
|
524
|
+
}
|
|
525
|
+
// Clean up alias ↔ identity tracking
|
|
526
|
+
if (identityKey !== undefined) {
|
|
527
|
+
this._aliasKeyToIdentityKey.delete(aliasKey);
|
|
528
|
+
const aliasSet = this._identityKeyToAliases.get(identityKey);
|
|
529
|
+
if (aliasSet) {
|
|
530
|
+
aliasSet.delete(alias);
|
|
531
|
+
if (aliasSet.size === 0) {
|
|
532
|
+
this._identityKeyToAliases.delete(identityKey);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
327
535
|
}
|
|
328
536
|
return this;
|
|
329
537
|
}
|
|
@@ -352,21 +560,21 @@ class Loader {
|
|
|
352
560
|
* Absolute URLs (starting with `http://`, `https://`, or `//`) are
|
|
353
561
|
* passed through unchanged.
|
|
354
562
|
*/
|
|
355
|
-
get
|
|
356
|
-
return this.
|
|
563
|
+
get basePath() {
|
|
564
|
+
return this._basePath;
|
|
357
565
|
}
|
|
358
|
-
set
|
|
359
|
-
this.
|
|
566
|
+
set basePath(value) {
|
|
567
|
+
this._basePath = value;
|
|
360
568
|
}
|
|
361
569
|
/**
|
|
362
570
|
* Default `RequestInit` options merged into every `fetch` call.
|
|
363
571
|
* Override per-load with the `options` argument of {@link load}.
|
|
364
572
|
*/
|
|
365
|
-
get
|
|
366
|
-
return this.
|
|
573
|
+
get fetchOptions() {
|
|
574
|
+
return this._fetchOptions;
|
|
367
575
|
}
|
|
368
|
-
set
|
|
369
|
-
this.
|
|
576
|
+
set fetchOptions(value) {
|
|
577
|
+
this._fetchOptions = value;
|
|
370
578
|
}
|
|
371
579
|
// -----------------------------------------------------------------------
|
|
372
580
|
// Lifecycle
|
|
@@ -388,6 +596,10 @@ class Loader {
|
|
|
388
596
|
this._bundles.clear();
|
|
389
597
|
this._inFlight.clear();
|
|
390
598
|
this._preventStoreKeys.clear();
|
|
599
|
+
this._inFlightByIdentity.clear();
|
|
600
|
+
this._aliasKeyToIdentityKey.clear();
|
|
601
|
+
this._identityKeyToAliases.clear();
|
|
602
|
+
this._handlerFunctions.clear();
|
|
391
603
|
this._backgroundQueue.length = 0;
|
|
392
604
|
this.onProgress.destroy();
|
|
393
605
|
this.onBundleProgress.destroy();
|
|
@@ -444,15 +656,166 @@ class Loader {
|
|
|
444
656
|
}
|
|
445
657
|
return this._waitForBackgroundEntry(type, alias);
|
|
446
658
|
}
|
|
659
|
+
_createLoadingQueue(items, buildResult) {
|
|
660
|
+
const results = new Map();
|
|
661
|
+
let notifyFn = null;
|
|
662
|
+
const itemPromises = items.map(({ alias, asset }) => {
|
|
663
|
+
const ctor = this._assetTypeMap.get(asset.type);
|
|
664
|
+
if (!ctor) {
|
|
665
|
+
// Must call _notifyItem(false) so LoadingProgress doesn't remain stuck.
|
|
666
|
+
return Promise.reject(new Error(`No constructor registered for asset type "${asset.type}". Call registerAssetType() first.`)).then(() => {
|
|
667
|
+
notifyFn?.(true);
|
|
668
|
+
}, error => {
|
|
669
|
+
notifyFn?.(false);
|
|
670
|
+
throw error;
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
return this._loadSingleAsset(ctor, alias, asset).then(resource => {
|
|
674
|
+
results.set(alias, resource);
|
|
675
|
+
notifyFn?.(true);
|
|
676
|
+
}, error => {
|
|
677
|
+
notifyFn?.(false);
|
|
678
|
+
throw error;
|
|
679
|
+
});
|
|
680
|
+
});
|
|
681
|
+
const promise = Promise.all(itemPromises).then(() => buildResult(results));
|
|
682
|
+
const queue = new LoadingQueue(promise, items.length);
|
|
683
|
+
notifyFn = queue._notifyItem.bind(queue);
|
|
684
|
+
return queue;
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Loads a single asset from an `Asset<T>` reference using identity-based
|
|
688
|
+
* in-flight deduplication.
|
|
689
|
+
*
|
|
690
|
+
* Multiple aliases that point to the same source share a single network
|
|
691
|
+
* fetch. Each alias is stored independently in `_resources` so that
|
|
692
|
+
* `get(type, alias)` works for all of them.
|
|
693
|
+
*/
|
|
694
|
+
async _loadSingleAsset(type, alias, asset) {
|
|
695
|
+
if (this._hasResource(type, alias)) {
|
|
696
|
+
return this._resources.get(type)?.get(alias);
|
|
697
|
+
}
|
|
698
|
+
const source = asset.source;
|
|
699
|
+
const rawConfig = asset._config;
|
|
700
|
+
const { type: _type, source: _src, ...extraOnly } = rawConfig;
|
|
701
|
+
// Identity key: use handler's getIdentityKey if provided (config-sensitive dedup),
|
|
702
|
+
// otherwise fall back to source-based identity (correct for URL-only assets).
|
|
703
|
+
const handlerEntry = this._handlerFunctions.get(type);
|
|
704
|
+
const discriminator = handlerEntry?.getIdentityKey?.(rawConfig) ?? source;
|
|
705
|
+
const identityKey = `id:${this._getTypeId(type)}:${discriminator}`;
|
|
706
|
+
const aliasKey = this._key(type, alias);
|
|
707
|
+
// Register alias → identity mapping for unload() semantics
|
|
708
|
+
this._aliasKeyToIdentityKey.set(aliasKey, identityKey);
|
|
709
|
+
let aliasSet = this._identityKeyToAliases.get(identityKey);
|
|
710
|
+
if (!aliasSet) {
|
|
711
|
+
aliasSet = new Set();
|
|
712
|
+
this._identityKeyToAliases.set(identityKey, aliasSet);
|
|
713
|
+
}
|
|
714
|
+
aliasSet.add(alias);
|
|
715
|
+
// Same identity already in flight? Attach to the existing promise.
|
|
716
|
+
const existing = this._inFlightByIdentity.get(identityKey);
|
|
717
|
+
if (existing) {
|
|
718
|
+
return existing.then(resource => {
|
|
719
|
+
this._storeResource(type, alias, resource);
|
|
720
|
+
return resource;
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
// Build load promise.
|
|
724
|
+
let fetchPromise;
|
|
725
|
+
if (handlerEntry) {
|
|
726
|
+
const fullConfig = { source, ...extraOnly };
|
|
727
|
+
const context = this._buildHandlerContext(identityKey);
|
|
728
|
+
fetchPromise = this._fetchWithHandler(type, alias, source, fullConfig, handlerEntry.load, context);
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
const options = Object.keys(extraOnly).length > 0 ? extraOnly : undefined;
|
|
732
|
+
fetchPromise = this._fetch(type, alias, source, options);
|
|
733
|
+
}
|
|
734
|
+
const tracked = fetchPromise
|
|
735
|
+
.finally(() => {
|
|
736
|
+
this._inFlightByIdentity.delete(identityKey);
|
|
737
|
+
})
|
|
738
|
+
.then(v => v, error => {
|
|
739
|
+
// On failure, immediately clean up alias ↔ identity tracking so
|
|
740
|
+
// stale entries don't accumulate for assets that never loaded.
|
|
741
|
+
const failedAliases = this._identityKeyToAliases.get(identityKey);
|
|
742
|
+
if (failedAliases) {
|
|
743
|
+
for (const fa of failedAliases) {
|
|
744
|
+
const faKey = this._key(type, fa);
|
|
745
|
+
this._aliasKeyToIdentityKey.delete(faKey);
|
|
746
|
+
this._preventStoreKeys.delete(faKey);
|
|
747
|
+
}
|
|
748
|
+
this._identityKeyToAliases.delete(identityKey);
|
|
749
|
+
}
|
|
750
|
+
throw error;
|
|
751
|
+
});
|
|
752
|
+
this._inFlightByIdentity.set(identityKey, tracked);
|
|
753
|
+
return tracked;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Calls a handler-based custom asset loader and stores the result.
|
|
757
|
+
*
|
|
758
|
+
* Unlike `_fetch`, this does NOT automatically bypass caching — the handler
|
|
759
|
+
* controls caching by calling `context.fetchText` / `context.fetchArrayBuffer`
|
|
760
|
+
* / `context.fetchJson`, which route through the loader's cache strategy.
|
|
761
|
+
*/
|
|
762
|
+
async _fetchWithHandler(type, alias, source, fullConfig, handler, context) {
|
|
763
|
+
const url = this._resolveUrl(source);
|
|
764
|
+
try {
|
|
765
|
+
const resource = await handler(fullConfig, context);
|
|
766
|
+
this._storeResource(type, alias, resource);
|
|
767
|
+
return resource;
|
|
768
|
+
}
|
|
769
|
+
catch (error) {
|
|
770
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
771
|
+
throw new Error(`Failed to load "${alias}" from "${url}": ${message}`, { cause: error });
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Builds an {@link AssetLoaderContext} for a handler invocation.
|
|
776
|
+
*
|
|
777
|
+
* The `fetch*` helpers on the returned context route through the loader's
|
|
778
|
+
* configured cache strategy and IDB stores, using `source` as the IDB key
|
|
779
|
+
* (so the same URL is never fetched twice regardless of the asset alias).
|
|
780
|
+
*/
|
|
781
|
+
_buildHandlerContext(identityKey) {
|
|
782
|
+
const ctx = {
|
|
783
|
+
loader: this,
|
|
784
|
+
identityKey,
|
|
785
|
+
fetchText: (source) => this._contextFetch(source, '__ctx_text', r => r.text()),
|
|
786
|
+
fetchArrayBuffer: (source) => this._contextFetch(source, '__ctx_binary', r => r.arrayBuffer()),
|
|
787
|
+
fetchJson: (source) => this._contextFetch(source, '__ctx_json', r => r.json()),
|
|
788
|
+
};
|
|
789
|
+
return ctx;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Fetches `source` through the loader's cache strategy with an inline
|
|
793
|
+
* pass-through factory, using `source` as the IDB key.
|
|
794
|
+
*
|
|
795
|
+
* `process` converts the raw `Response` to the storable intermediate form
|
|
796
|
+
* (e.g. `r.text()`, `r.arrayBuffer()`, `r.json()`). `create` is always the
|
|
797
|
+
* identity function — the cached value is returned unchanged.
|
|
798
|
+
*/
|
|
799
|
+
_contextFetch(source, storageName, process) {
|
|
800
|
+
const url = this._resolveUrl(source);
|
|
801
|
+
const factory = {
|
|
802
|
+
storageName,
|
|
803
|
+
process,
|
|
804
|
+
create: data => Promise.resolve(data),
|
|
805
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
806
|
+
destroy() { },
|
|
807
|
+
};
|
|
808
|
+
return this._cacheStrategy.resolve({ storageName, key: source, url, requestOptions: this._fetchOptions, factory, options: undefined }, this._stores);
|
|
809
|
+
}
|
|
447
810
|
async _fetch(type, alias, path, options) {
|
|
448
811
|
const factory = this._registry.resolve(type);
|
|
449
812
|
const url = this._resolveUrl(path);
|
|
450
813
|
try {
|
|
451
814
|
const resource = await this._cacheStrategy.resolve({
|
|
452
815
|
storageName: factory.storageName,
|
|
453
|
-
key:
|
|
816
|
+
key: path, // source-path as IDB key so same resource is not cached multiple times under different aliases
|
|
454
817
|
url,
|
|
455
|
-
requestOptions: this.
|
|
818
|
+
requestOptions: this._fetchOptions,
|
|
456
819
|
factory,
|
|
457
820
|
options,
|
|
458
821
|
}, this._stores);
|
|
@@ -665,19 +1028,38 @@ class Loader {
|
|
|
665
1028
|
typeResources.set(alias, resource);
|
|
666
1029
|
this.onLoaded.dispatch(type, alias, resource);
|
|
667
1030
|
}
|
|
668
|
-
|
|
1031
|
+
_getTypeId(type) {
|
|
669
1032
|
let typeId = this._typeIds.get(type);
|
|
670
1033
|
if (typeId === undefined) {
|
|
671
1034
|
typeId = this._nextTypeId++;
|
|
672
1035
|
this._typeIds.set(type, typeId);
|
|
673
1036
|
}
|
|
674
|
-
return
|
|
1037
|
+
return typeId;
|
|
1038
|
+
}
|
|
1039
|
+
_key(type, alias) {
|
|
1040
|
+
return `${this._getTypeId(type)}:${alias}`;
|
|
1041
|
+
}
|
|
1042
|
+
_identityKey(type, source) {
|
|
1043
|
+
return `id:${this._getTypeId(type)}:${source}`;
|
|
1044
|
+
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Resolves the effective identity key for an `Asset<T>` reference, mirroring
|
|
1047
|
+
* the logic used in `_loadSingleAsset`.
|
|
1048
|
+
*
|
|
1049
|
+
* For handler types with `getIdentityKey`, the config-sensitive discriminator
|
|
1050
|
+
* is used; otherwise source is the discriminator (same as `_identityKey`).
|
|
1051
|
+
*/
|
|
1052
|
+
_resolveAssetIdentityKey(type, asset) {
|
|
1053
|
+
const rawConfig = asset._config;
|
|
1054
|
+
const handlerEntry = this._handlerFunctions.get(type);
|
|
1055
|
+
const discriminator = handlerEntry?.getIdentityKey?.(rawConfig) ?? asset.source;
|
|
1056
|
+
return `id:${this._getTypeId(type)}:${discriminator}`;
|
|
675
1057
|
}
|
|
676
1058
|
_resolveUrl(path) {
|
|
677
1059
|
if (path.startsWith('http://') || path.startsWith('https://') || path.startsWith('//')) {
|
|
678
1060
|
return path;
|
|
679
1061
|
}
|
|
680
|
-
return `${this.
|
|
1062
|
+
return `${this._basePath}${path}`;
|
|
681
1063
|
}
|
|
682
1064
|
// -----------------------------------------------------------------------
|
|
683
1065
|
// Internal — built-in factory registration
|
|
@@ -690,16 +1072,40 @@ class Loader {
|
|
|
690
1072
|
this._registry.register(Json, new JsonFactory());
|
|
691
1073
|
this._registry.register(TextAsset, new TextFactory());
|
|
692
1074
|
this._registry.register(SvgAsset, new SvgFactory());
|
|
693
|
-
this._registry.register(
|
|
694
|
-
this._registry.register(
|
|
1075
|
+
this._registry.register(SubtitleAsset, new SubtitleFactory());
|
|
1076
|
+
this._registry.register(XmlAsset, new XmlFactory());
|
|
1077
|
+
this._registry.register(CsvAsset, new CsvFactory());
|
|
1078
|
+
this._registry.register(BinaryAsset, new BinaryFactory());
|
|
1079
|
+
this._assetTypeMap.set('texture', Texture);
|
|
1080
|
+
this._assetTypeMap.set('sound', Sound);
|
|
1081
|
+
this._assetTypeMap.set('music', Music);
|
|
1082
|
+
this._assetTypeMap.set('json', Json);
|
|
1083
|
+
this._assetTypeMap.set('video', Video);
|
|
1084
|
+
this._assetTypeMap.set('text', TextAsset);
|
|
1085
|
+
this._assetTypeMap.set('svg', SvgAsset);
|
|
1086
|
+
this._assetTypeMap.set('vtt', SubtitleAsset);
|
|
1087
|
+
this._assetTypeMap.set('srt', SubtitleAsset);
|
|
1088
|
+
this._assetTypeMap.set('xml', XmlAsset);
|
|
1089
|
+
this._assetTypeMap.set('csv', CsvAsset);
|
|
1090
|
+
this._assetTypeMap.set('binary', BinaryAsset);
|
|
1091
|
+
this._registry.register(BmFont, new BmFontLoaderFactory(this));
|
|
1092
|
+
this._assetTypeMap.set('bmFont', BmFont);
|
|
1093
|
+
this._extensionMap.set('fnt', BmFont);
|
|
695
1094
|
if (typeof FontFace !== 'undefined') {
|
|
696
|
-
this._registry.register(
|
|
1095
|
+
this._registry.register(FontAsset, new FontFactory());
|
|
1096
|
+
this._assetTypeMap.set('font', FontAsset);
|
|
1097
|
+
this._extensionMap.set('woff', FontAsset);
|
|
1098
|
+
this._extensionMap.set('woff2', FontAsset);
|
|
1099
|
+
this._extensionMap.set('ttf', FontAsset);
|
|
1100
|
+
this._extensionMap.set('otf', FontAsset);
|
|
697
1101
|
}
|
|
698
1102
|
if (typeof HTMLImageElement !== 'undefined') {
|
|
699
|
-
this._registry.register(
|
|
1103
|
+
this._registry.register(ImageAsset, new ImageFactory());
|
|
1104
|
+
this._assetTypeMap.set('image', ImageAsset);
|
|
700
1105
|
}
|
|
701
1106
|
if (typeof WebAssembly !== 'undefined') {
|
|
702
|
-
this._registry.register(
|
|
1107
|
+
this._registry.register(WasmAsset, new WasmFactory());
|
|
1108
|
+
this._assetTypeMap.set('wasm', WasmAsset);
|
|
703
1109
|
}
|
|
704
1110
|
}
|
|
705
1111
|
}
|