@zephyr3d/scene 0.9.25 → 0.9.27
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/dist/animation/animationset.js +92 -30
- package/dist/animation/animationset.js.map +1 -1
- package/dist/animation/hair/gpu_hair_simulation.js +1090 -0
- package/dist/animation/hair/gpu_hair_simulation.js.map +1 -0
- package/dist/animation/joint_dynamics/controller.js +7 -5
- package/dist/animation/joint_dynamics/controller.js.map +1 -1
- package/dist/animation/joint_dynamics/convex_collider.js +320 -0
- package/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
- package/dist/animation/joint_dynamics/joint_dynamics_system.js +81 -5
- package/dist/animation/joint_dynamics/joint_dynamics_system.js.map +1 -1
- package/dist/animation/morphtrack.js +3 -4
- package/dist/animation/morphtrack.js.map +1 -1
- package/dist/animation/skeleton.js +79 -25
- package/dist/animation/skeleton.js.map +1 -1
- package/dist/animation/spring/multi_chain_spring_system.js +577 -179
- package/dist/animation/spring/multi_chain_spring_system.js.map +1 -1
- package/dist/animation/spring/spring_collider.js +4 -3
- package/dist/animation/spring/spring_collider.js.map +1 -1
- package/dist/animation/spring/spring_node_pose_tracker.js +40 -0
- package/dist/animation/spring/spring_node_pose_tracker.js.map +1 -0
- package/dist/animation/spring/spring_particle.js +2 -0
- package/dist/animation/spring/spring_particle.js.map +1 -1
- package/dist/animation/spring/spring_system.js +11 -3
- package/dist/animation/spring/spring_system.js.map +1 -1
- package/dist/animation/spring_modifier.js +10 -0
- package/dist/animation/spring_modifier.js.map +1 -1
- package/dist/app/engine.js +53 -43
- package/dist/app/engine.js.map +1 -1
- package/dist/app/scriptingsystem.js +119 -6
- package/dist/app/scriptingsystem.js.map +1 -1
- package/dist/app/scriptregistry.js +3 -2
- package/dist/app/scriptregistry.js.map +1 -1
- package/dist/asset/assetmanager.js +284 -67
- package/dist/asset/assetmanager.js.map +1 -1
- package/dist/asset/loaders/zhair/zhair_format.js +288 -0
- package/dist/asset/loaders/zhair/zhair_format.js.map +1 -0
- package/dist/asset/loaders/zhair/zhair_loader.js +221 -0
- package/dist/asset/loaders/zhair/zhair_loader.js.map +1 -0
- package/dist/asset/model.js +184 -69
- package/dist/asset/model.js.map +1 -1
- package/dist/camera/camera.js +268 -44
- package/dist/camera/camera.js.map +1 -1
- package/dist/camera/perspectivecamera.js +3 -1
- package/dist/camera/perspectivecamera.js.map +1 -1
- package/dist/index.d.ts +9044 -5139
- package/dist/index.js +17 -6
- package/dist/index.js.map +1 -1
- package/dist/material/eye.js +932 -0
- package/dist/material/eye.js.map +1 -0
- package/dist/material/hair.js +917 -0
- package/dist/material/hair.js.map +1 -0
- package/dist/material/hairstrand.js +842 -0
- package/dist/material/hairstrand.js.map +1 -0
- package/dist/material/hairstrand_data.js +162 -0
- package/dist/material/hairstrand_data.js.map +1 -0
- package/dist/material/lambert.js +5 -2
- package/dist/material/lambert.js.map +1 -1
- package/dist/material/material.js +48 -10
- package/dist/material/material.js.map +1 -1
- package/dist/material/meshmaterial.js +120 -19
- package/dist/material/meshmaterial.js.map +1 -1
- package/dist/material/mixins/albedocolor.js +1 -1
- package/dist/material/mixins/albedocolor.js.map +1 -1
- package/dist/material/mixins/lightmodel/blinnphong.js +5 -3
- package/dist/material/mixins/lightmodel/blinnphong.js.map +1 -1
- package/dist/material/mixins/lightmodel/lambert.js +5 -4
- package/dist/material/mixins/lightmodel/lambert.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js +3 -3
- package/dist/material/mixins/lightmodel/pbrblueprintmixin.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js +5 -5
- package/dist/material/mixins/lightmodel/pbrmetallicroughness.js.map +1 -1
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js +3 -3
- package/dist/material/mixins/lightmodel/pbrspecularglossness.js.map +1 -1
- package/dist/material/mixins/lit.js +106 -19
- package/dist/material/mixins/lit.js.map +1 -1
- package/dist/material/mixins/pbr/common.js +4 -4
- package/dist/material/mixins/pbr/common.js.map +1 -1
- package/dist/material/mixins/texture.js +48 -11
- package/dist/material/mixins/texture.js.map +1 -1
- package/dist/material/mtoon.js +6 -5
- package/dist/material/mtoon.js.map +1 -1
- package/dist/material/pbrblueprint.js +146 -28
- package/dist/material/pbrblueprint.js.map +1 -1
- package/dist/material/pbrblueprint_instance.js +501 -0
- package/dist/material/pbrblueprint_instance.js.map +1 -0
- package/dist/material/pbrmr.js +15 -16
- package/dist/material/pbrmr.js.map +1 -1
- package/dist/material/shader/helper.js +734 -23
- package/dist/material/shader/helper.js.map +1 -1
- package/dist/material/shader/terrain_blend.js +55 -0
- package/dist/material/shader/terrain_blend.js.map +1 -0
- package/dist/material/skin.js +192 -32
- package/dist/material/skin.js.map +1 -1
- package/dist/material/spriteblueprint.js +16 -1
- package/dist/material/spriteblueprint.js.map +1 -1
- package/dist/material/subsurfaceprofile.js +86 -23
- package/dist/material/subsurfaceprofile.js.map +1 -1
- package/dist/material/water.js +2059 -72
- package/dist/material/water.js.map +1 -1
- package/dist/posteffect/bloom.js +167 -7
- package/dist/posteffect/bloom.js.map +1 -1
- package/dist/posteffect/coloradjust.js +2 -1
- package/dist/posteffect/coloradjust.js.map +1 -1
- package/dist/posteffect/compositor.js.map +1 -1
- package/dist/posteffect/fxaa.js +2 -1
- package/dist/posteffect/fxaa.js.map +1 -1
- package/dist/posteffect/grayscale.js +3 -1
- package/dist/posteffect/grayscale.js.map +1 -1
- package/dist/posteffect/motionblur.js +664 -56
- package/dist/posteffect/motionblur.js.map +1 -1
- package/dist/posteffect/posteffect.js +12 -1
- package/dist/posteffect/posteffect.js.map +1 -1
- package/dist/posteffect/sao.js +46 -44
- package/dist/posteffect/sao.js.map +1 -1
- package/dist/posteffect/skinsss.js +368 -69
- package/dist/posteffect/skinsss.js.map +1 -1
- package/dist/posteffect/ssgi.js +16 -9
- package/dist/posteffect/ssgi.js.map +1 -1
- package/dist/posteffect/ssr.js +3 -0
- package/dist/posteffect/ssr.js.map +1 -1
- package/dist/posteffect/sss.js +121 -36
- package/dist/posteffect/sss.js.map +1 -1
- package/dist/posteffect/taa.js.map +1 -1
- package/dist/posteffect/tonemap.js +44 -1
- package/dist/posteffect/tonemap.js.map +1 -1
- package/dist/render/abuffer_oit.js +8 -2
- package/dist/render/abuffer_oit.js.map +1 -1
- package/dist/render/clipmap.js +156 -5
- package/dist/render/clipmap.js.map +1 -1
- package/dist/render/cull_visitor.js +20 -0
- package/dist/render/cull_visitor.js.map +1 -1
- package/dist/render/depthpass.js +36 -2
- package/dist/render/depthpass.js.map +1 -1
- package/dist/render/drawable_mixin.js +26 -1
- package/dist/render/drawable_mixin.js.map +1 -1
- package/dist/render/dualdepthpeeling_oit.js +3 -2
- package/dist/render/dualdepthpeeling_oit.js.map +1 -1
- package/dist/render/envlight.js +1 -1
- package/dist/render/envlight.js.map +1 -1
- package/dist/render/fbm_wavegenerator.js +6 -3
- package/dist/render/fbm_wavegenerator.js.map +1 -1
- package/dist/render/fft_wavegenerator.js +57 -15
- package/dist/render/fft_wavegenerator.js.map +1 -1
- package/dist/render/gerstner_wavegenerator.js +130 -20
- package/dist/render/gerstner_wavegenerator.js.map +1 -1
- package/dist/render/globalbindgroup_allocator.js +3 -0
- package/dist/render/globalbindgroup_allocator.js.map +1 -1
- package/dist/render/hzb.js +80 -22
- package/dist/render/hzb.js.map +1 -1
- package/dist/render/lightpass.js +6 -3
- package/dist/render/lightpass.js.map +1 -1
- package/dist/render/oit.js +29 -0
- package/dist/render/oit.js.map +1 -0
- package/dist/render/render_queue.js +39 -0
- package/dist/render/render_queue.js.map +1 -1
- package/dist/render/renderer.js +4 -0
- package/dist/render/renderer.js.map +1 -1
- package/dist/render/rendergraph/blackboard.js +1 -0
- package/dist/render/rendergraph/blackboard.js.map +1 -1
- package/dist/render/rendergraph/device_pool_allocator.js.map +1 -1
- package/dist/render/rendergraph/executor.js +2 -0
- package/dist/render/rendergraph/executor.js.map +1 -1
- package/dist/render/rendergraph/forward_plus_builder.js +379 -10
- package/dist/render/rendergraph/forward_plus_builder.js.map +1 -1
- package/dist/render/rendergraph/frame_resource_requirements.js +1 -0
- package/dist/render/rendergraph/frame_resource_requirements.js.map +1 -1
- package/dist/render/rendergraph/history_resources.js +8 -1
- package/dist/render/rendergraph/history_resources.js.map +1 -1
- package/dist/render/rendergraph/rendergraph.js.map +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js +1 -1
- package/dist/render/rendergraph/texture_affinity_cache.js.map +1 -1
- package/dist/render/rendergraph/types.js.map +1 -1
- package/dist/render/shadow_mask_pass.js +73 -8
- package/dist/render/shadow_mask_pass.js.map +1 -1
- package/dist/render/sky.js +166 -126
- package/dist/render/sky.js.map +1 -1
- package/dist/render/underwater.js +624 -0
- package/dist/render/underwater.js.map +1 -0
- package/dist/render/water_caustics.js +1380 -0
- package/dist/render/water_caustics.js.map +1 -0
- package/dist/render/weightedblended_oit.js +3 -2
- package/dist/render/weightedblended_oit.js.map +1 -1
- package/dist/scene/basesprite.js +8 -0
- package/dist/scene/basesprite.js.map +1 -1
- package/dist/scene/batchgroup.js +3 -0
- package/dist/scene/batchgroup.js.map +1 -1
- package/dist/scene/environment.js +4 -1
- package/dist/scene/environment.js.map +1 -1
- package/dist/scene/hair.js +963 -0
- package/dist/scene/hair.js.map +1 -0
- package/dist/scene/light.js +5 -1
- package/dist/scene/light.js.map +1 -1
- package/dist/scene/mesh.js +481 -47
- package/dist/scene/mesh.js.map +1 -1
- package/dist/scene/meshdrawable.js +6 -0
- package/dist/scene/meshdrawable.js.map +1 -1
- package/dist/scene/msdftext.js +3 -0
- package/dist/scene/msdftext.js.map +1 -1
- package/dist/scene/msdftextsprite.js +3 -0
- package/dist/scene/msdftextsprite.js.map +1 -1
- package/dist/scene/particlesys.js +6 -0
- package/dist/scene/particlesys.js.map +1 -1
- package/dist/scene/scene.js +3 -0
- package/dist/scene/scene.js.map +1 -1
- package/dist/scene/scene_node.js +6 -1
- package/dist/scene/scene_node.js.map +1 -1
- package/dist/scene/terrain-cm/grass.js +3 -0
- package/dist/scene/terrain-cm/grass.js.map +1 -1
- package/dist/scene/terrain-cm/grassmaterial.js +3 -0
- package/dist/scene/terrain-cm/grassmaterial.js.map +1 -1
- package/dist/scene/terrain-cm/terrain-cm.js +6 -0
- package/dist/scene/terrain-cm/terrain-cm.js.map +1 -1
- package/dist/scene/terrain-cm/texture_cache.js +309 -0
- package/dist/scene/terrain-cm/texture_cache.js.map +1 -0
- package/dist/scene/water.js +546 -4
- package/dist/scene/water.js.map +1 -1
- package/dist/shaders/atmosphere.js.map +1 -1
- package/dist/shaders/diffusion.js +54 -0
- package/dist/shaders/diffusion.js.map +1 -0
- package/dist/shaders/shadow.js +33 -21
- package/dist/shaders/shadow.js.map +1 -1
- package/dist/shaders/temporal.js +71 -33
- package/dist/shaders/temporal.js.map +1 -1
- package/dist/shaders/water.js +22 -19
- package/dist/shaders/water.js.map +1 -1
- package/dist/shaders/water_medium.js +56 -0
- package/dist/shaders/water_medium.js.map +1 -0
- package/dist/shadow/dom.js +546 -0
- package/dist/shadow/dom.js.map +1 -0
- package/dist/shadow/pcf_opt.js +3 -5
- package/dist/shadow/pcf_opt.js.map +1 -1
- package/dist/shadow/pcf_pd.js +1 -1
- package/dist/shadow/pcf_pd.js.map +1 -1
- package/dist/shadow/receiver_bias.js +41 -0
- package/dist/shadow/receiver_bias.js.map +1 -0
- package/dist/shadow/shader.js +20 -60
- package/dist/shadow/shader.js.map +1 -1
- package/dist/shadow/shadow_impl.js +89 -0
- package/dist/shadow/shadow_impl.js.map +1 -1
- package/dist/shadow/shadow_region.js +1 -1
- package/dist/shadow/shadow_region.js.map +1 -1
- package/dist/shadow/shadowmapper.js +150 -37
- package/dist/shadow/shadowmapper.js.map +1 -1
- package/dist/shapes/shape.js +11 -2
- package/dist/shapes/shape.js.map +1 -1
- package/dist/shapes/sphere.js +50 -9
- package/dist/shapes/sphere.js.map +1 -1
- package/dist/utility/blueprint/common/constants.js +112 -2
- package/dist/utility/blueprint/common/constants.js.map +1 -1
- package/dist/utility/blueprint/material/func.js +142 -49
- package/dist/utility/blueprint/material/func.js.map +1 -1
- package/dist/utility/blueprint/material/ir.js +490 -25
- package/dist/utility/blueprint/material/ir.js.map +1 -1
- package/dist/utility/blueprint/material/texture.js +898 -4
- package/dist/utility/blueprint/material/texture.js.map +1 -1
- package/dist/utility/serialization/manager.js +434 -101
- package/dist/utility/serialization/manager.js.map +1 -1
- package/dist/utility/serialization/scene/animation.js +401 -5
- package/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/utility/serialization/scene/batch.js +4 -0
- package/dist/utility/serialization/scene/batch.js.map +1 -1
- package/dist/utility/serialization/scene/camera.js +186 -26
- package/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/utility/serialization/scene/common.js +26 -5
- package/dist/utility/serialization/scene/common.js.map +1 -1
- package/dist/utility/serialization/scene/hair.js +1141 -0
- package/dist/utility/serialization/scene/hair.js.map +1 -0
- package/dist/utility/serialization/scene/light.js +84 -4
- package/dist/utility/serialization/scene/light.js.map +1 -1
- package/dist/utility/serialization/scene/material.js +1867 -166
- package/dist/utility/serialization/scene/material.js.map +1 -1
- package/dist/utility/serialization/scene/mesh.js +231 -14
- package/dist/utility/serialization/scene/mesh.js.map +1 -1
- package/dist/utility/serialization/scene/node.js +141 -7
- package/dist/utility/serialization/scene/node.js.map +1 -1
- package/dist/utility/serialization/scene/particle.js +4 -0
- package/dist/utility/serialization/scene/particle.js.map +1 -1
- package/dist/utility/serialization/scene/primitive.js +18 -0
- package/dist/utility/serialization/scene/primitive.js.map +1 -1
- package/dist/utility/serialization/scene/sprite.js +4 -0
- package/dist/utility/serialization/scene/sprite.js.map +1 -1
- package/dist/utility/serialization/scene/terrain.js +4 -0
- package/dist/utility/serialization/scene/terrain.js.map +1 -1
- package/dist/utility/serialization/scene/text.js +4 -0
- package/dist/utility/serialization/scene/text.js.map +1 -1
- package/dist/utility/serialization/scene/water.js +1105 -21
- package/dist/utility/serialization/scene/water.js.map +1 -1
- package/dist/utility/serialization/types.js.map +1 -1
- package/dist/utility/shprojector.js +9 -8
- package/dist/utility/shprojector.js.map +1 -1
- package/dist/values.js +49 -2
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
- package/dist/render/rendergraph/frame_graph_context.js +0 -41
- package/dist/render/rendergraph/frame_graph_context.js.map +0 -1
- package/dist/shaders/ssgi.js +0 -63
- package/dist/shaders/ssgi.js.map +0 -1
- package/dist/shaders/ssgi_reprojection.js +0 -118
- package/dist/shaders/ssgi_reprojection.js.map +0 -1
package/dist/app/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sources":["../../src/app/engine.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, ReadOptions } from '@zephyr3d/base';\r\nimport { MemoryFS, objectEntries } from '@zephyr3d/base';\r\nimport { DRef } from '@zephyr3d/base';\r\nimport { HttpFS, type VFS } from '@zephyr3d/base';\r\nimport { ScriptingSystem } from './scriptingsystem';\r\nimport type { Host } from './scriptingsystem';\r\nimport type { RuntimeScript, RuntimeScriptConfig } from './runtimescript';\r\nimport { ResourceManager } from '../utility/serialization/manager';\r\nimport type { Scene } from '../scene';\r\nimport {\r\n BoxShape,\r\n CapsuleShape,\r\n CylinderShape,\r\n PlaneShape,\r\n SphereShape,\r\n TetrahedronShape,\r\n TorusShape\r\n} from '../shapes';\r\nimport {\r\n BlinnMaterial,\r\n LambertMaterial,\r\n PBRMetallicRoughnessMaterial,\r\n PBRSpecularGlossinessMaterial,\r\n UnlitMaterial\r\n} from '../material';\r\nimport { StandardSpriteMaterial } from '../material/sprite_std';\r\nimport { SkinMaterial } from '../material/skin';\r\nimport { ScreenAdapter } from './screen';\r\nimport { MSDFTextAtlasManager } from '../text/runtime';\r\n\r\n/**\r\n * Interface for objects that can be rendered.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderable extends IDisposable {\r\n render(): void;\r\n}\r\n\r\n/**\r\n * Type for render functions that can be registered as renderables.\r\n *\r\n * @public\r\n */\r\nexport type RenderFunc = () => void;\r\n\r\n/**\r\n * Interface for render hooks to customize rendering behavior.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderHook {\r\n // If presents, called before rendering the renderable. Return `false` to skip rendering.\r\n beforeRender?: (renderable: any) => boolean | void;\r\n // If presents, called after rendering the renderable.\r\n afterRender?: (renderable: any) => void;\r\n}\r\n\r\n/**\r\n * Core engine class managing scripting, serialization, and rendering.\r\n *\r\n * Responsibilities:\r\n * - Manages a {@link ScriptingSystem} for dynamic script attachment and lifecycle.\r\n * - Manages a {@link ResourceManager} for loading scenes and assets.\r\n * - Maintains a list of active renderable objects to be rendered each frame.\r\n * - Provides methods to attach/detach scripts, update scripts, load scenes, and read files.\r\n * - Supports enabling/disabling of runtime operations.\r\n *\r\n * @remarks\r\n * The engine can be configured with a virtual file system (VFS) and script root path.\r\n * It exposes methods to manage scripts on host objects, update scripts each frame,\r\n * load scenes from files, and render active objects.\r\n *\r\n * @public\r\n */\r\nexport class Engine {\r\n private _builtinsVFS: Nullable<MemoryFS>;\r\n private _scriptingSystem: ScriptingSystem;\r\n private _resourceManager: ResourceManager;\r\n private _msdfTextAtlasManager: MSDFTextAtlasManager;\r\n private _enabled: boolean;\r\n private _screen: ScreenAdapter;\r\n protected _activeRenderables: {\r\n renderable: Nullable<RenderFunc> | DRef<IRenderable>;\r\n hook: Nullable<IRenderHook>;\r\n }[];\r\n private _loadingScenes: Partial<Record<string, Promise<Nullable<Scene>>>>;\r\n /**\r\n * Creates a new runtime manager.\r\n *\r\n * @param VFS - Optional virtual file system passed to the internal {@link ScriptingSystem}.\r\n * @param scriptsRoot - Optional scripts root path within the VFS. Defaults as in `ScriptingSystem`.\r\n * @param enabled - Whether runtime operations are active. Defaults to `true`.\r\n */\r\n constructor(VFS?: VFS, scriptsRoot?: string, enabled?: boolean) {\r\n VFS = VFS ?? new HttpFS('./');\r\n this._builtinsVFS = null;\r\n this._scriptingSystem = new ScriptingSystem({ VFS, scriptsRoot });\r\n this._resourceManager = new ResourceManager(VFS);\r\n this._msdfTextAtlasManager = new MSDFTextAtlasManager();\r\n this._enabled = enabled ?? true;\r\n this._activeRenderables = [];\r\n this._loadingScenes = {};\r\n this._screen = new ScreenAdapter();\r\n }\r\n /**\r\n * Exposes the instance of {@link ScriptingSystem}.\r\n */\r\n get scriptingSystem() {\r\n return this._scriptingSystem;\r\n }\r\n /**\r\n * Exposes the virtual file system used by the underlying {@link ScriptingSystem}'s registry.\r\n */\r\n get VFS() {\r\n return this._scriptingSystem.registry.VFS;\r\n }\r\n set VFS(vfs: VFS) {\r\n if (vfs !== this._resourceManager.VFS) {\r\n this._resourceManager.VFS?.close();\r\n this._resourceManager.VFS = vfs;\r\n this._scriptingSystem.registry.VFS = vfs;\r\n this.ensureBuiltinVFS();\r\n }\r\n }\r\n /**\r\n * Exposes the instance of {@link ResourceManager}.\r\n */\r\n get resourceManager() {\r\n return this._resourceManager;\r\n }\r\n /**\r\n * Exposes the shared runtime MSDF text atlas manager.\r\n */\r\n get msdfTextAtlasManager() {\r\n return this._msdfTextAtlasManager;\r\n }\r\n /**\r\n * Releases a loaded font asset from the resource cache and disposes its shared MSDF atlas textures.\r\n *\r\n * Existing scene nodes that still reference this font asset are not updated automatically.\r\n * Call this only after you have stopped using the font, or when you intentionally want it to rebuild later.\r\n *\r\n * @param font - The loaded font asset path to release.\r\n * @returns `true` if either the atlas cache or the font cache had an entry to remove.\r\n */\r\n releaseFontAsset(font: string) {\r\n const fontAsset = this._resourceManager.getFontAsset(font);\r\n if (!fontAsset) {\r\n return false;\r\n }\r\n const atlasReleased = this._msdfTextAtlasManager.releaseAtlas(fontAsset);\r\n const fontReleased = this._resourceManager.releaseFontAsset(fontAsset);\r\n return atlasReleased || fontReleased;\r\n }\r\n /**\r\n * Configures the MSDF atlas for a given font asset, creating or replacing the atlas as needed.\r\n *\r\n * This is useful to customize the glyph size, atlas page size, distance range, and padding for MSDF text rendering.\r\n * Existing scene nodes that reference this font asset will use the updated atlas automatically.\r\n *\r\n * @param font - The font asset path to configure the MSDF atlas for.\r\n * @param pageSize - The size of each atlas page in pixels (e.g., 512, 1024).\r\n * @param glyphSize - The size of each glyph in pixels (e.g., 32, 64).\r\n * @param distanceRange - The distance range for MSDF generation. Defaults to 4.\r\n * @param padding - The padding between glyphs in the atlas in pixels. Defaults to 2.\r\n * @returns `true` if the atlas was successfully configured, or `false` if the font asset was not found.\r\n *\r\n * @remarks\r\n * The font asset must be loaded and available in the resource manager for the atlas to be configured.\r\n */\r\n configureMSDFAtlas(\r\n font: string,\r\n pageSize: number,\r\n glyphSize: number,\r\n distanceRange?: number,\r\n padding?: number\r\n ) {\r\n const fontAsset = this._resourceManager.getFontAsset(font);\r\n if (!fontAsset) {\r\n console.warn(`Font asset '${font}' not found for MSDF atlas configuration.`);\r\n return false;\r\n }\r\n this._msdfTextAtlasManager.configureAtlas(fontAsset, pageSize, glyphSize, distanceRange, padding);\r\n return true;\r\n }\r\n /**\r\n * Exposes the active {@link ScreenAdapter}.\r\n */\r\n get screen() {\r\n return this._screen;\r\n }\r\n /** @internal */\r\n async init() {\r\n await this.ensureBuiltinVFS();\r\n }\r\n /**\r\n * Detaches all scripts from all hosts, if enabled.\r\n *\r\n * No-op when `enabled === false`.\r\n */\r\n detachAllScripts() {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachAllScripts();\r\n }\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<Nullable<{ url: string; cls: GenericConstructor<RuntimeScript<T>> }>> {\r\n return await this._scriptingSystem.loadRuntimeScriptClass(module);\r\n }\r\n /**\r\n * Attaches a script module to the given host, if enabled.\r\n *\r\n * When disabled, this method resolves to `null` without side effects.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host object to attach the script to.\r\n * @param module - Module identifier to resolve and load.\r\n * @param config - Optional configuration passed to the script instance.\r\n * @returns The `RuntimeScript<T>` instance, or `null` if disabled or on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ) {\r\n return this._enabled ? await this._scriptingSystem.attachScript(host, module, config) : null;\r\n }\r\n /**\r\n * Detaches a script from a host, by module ID or instance, if enabled.\r\n *\r\n * No-op when disabled.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host to detach from.\r\n * @param idOrInstance - Target script by module ID or instance reference.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance: string | RuntimeScript<T>) {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachScript(host, idOrInstance);\r\n }\r\n }\r\n /**\r\n * Gets all scripts attached to a host.\r\n *\r\n * Delegates to {@link ScriptingSystem.getScriptObjects}.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - Host object to query.\r\n * @returns Script instances attached to the host, or an empty array.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown) {\r\n return this._scriptingSystem.getScriptObjects(host) as T[];\r\n }\r\n /**\r\n * Ticks all attached scripts by calling their `onUpdate` hooks, if enabled.\r\n *\r\n * @param deltaTime - Time since last update in Seconds.\r\n * @param elapsedTime - Total elapsed time in Seconds.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._enabled) {\r\n this._scriptingSystem.update(deltaTime, elapsedTime);\r\n }\r\n }\r\n /**\r\n * Loads a scene from a file path.\r\n *\r\n * Concurrent requests for the same normalized path share the same loading promise.\r\n * Scripts declared on the scene and its nodes are attached after the scene is loaded.\r\n *\r\n * @param path - Scene file path in the current VFS.\r\n * @returns The loaded scene, or `null` when loading fails.\r\n */\r\n async loadSceneFromFile(path: string) {\r\n path = this.VFS.normalizePath(path);\r\n if (!this._loadingScenes[path]) {\r\n this._loadingScenes[path] = this._loadScene(path);\r\n }\r\n return this._loadingScenes[path]!;\r\n }\r\n /**\r\n * Sets or clears the renderable for a render layer.\r\n *\r\n * Passing `null` clears the layer. Object renderables are held through a strong reference wrapper,\r\n * while render functions are stored directly.\r\n *\r\n * @param renderable - Renderable object or render function to assign, or `null` to clear.\r\n * @param layer - Render layer index. Defaults to `0`.\r\n * @param hook - Optional render hook invoked before and after this layer renders.\r\n */\r\n setRenderable(renderable: Nullable<IRenderable | RenderFunc>, layer = 0, hook?: IRenderHook) {\r\n const entry = this._activeRenderables[layer];\r\n if (!entry) {\r\n this._activeRenderables[layer] = {\r\n renderable: renderable\r\n ? typeof renderable === 'function'\r\n ? renderable\r\n : new DRef<IRenderable>(renderable)\r\n : null,\r\n hook: hook ?? null\r\n };\r\n } else {\r\n if (entry.renderable) {\r\n if (entry.renderable instanceof DRef) {\r\n entry.renderable.dispose();\r\n }\r\n entry.renderable = null;\r\n }\r\n if (typeof renderable === 'function') {\r\n entry.renderable = renderable;\r\n } else if (renderable) {\r\n entry.renderable = new DRef<IRenderable>(renderable);\r\n }\r\n entry.hook = hook ?? null;\r\n }\r\n }\r\n /**\r\n * Reads a file from the current VFS.\r\n *\r\n * @typeParam T - Requested read encoding.\r\n * @param path - File path to read.\r\n * @param encoding - Optional read encoding. Defaults to `binary`.\r\n * @returns The file content, or `null` when the read fails.\r\n */\r\n async readFile<T extends ReadOptions['encoding'] = 'binary'>(path: string, encoding?: T) {\r\n try {\r\n const content = await this.VFS.readFile(path, { encoding: encoding ?? 'binary' });\r\n return content as T extends 'binary' ? ArrayBuffer : string;\r\n } catch (err) {\r\n console.error(`Read file '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Starts the runtime by optionally showing a splash screen, running a startup script,\r\n * and loading the startup scene.\r\n *\r\n * @param startupScene - Optional scene path rendered on layer `0` after startup completes.\r\n * @param splashScreen - Optional scene path rendered on a temporary splash layer during startup.\r\n * @param startupScript - Optional startup script module path. A trailing `.ts` or `.js`\r\n * extension is removed before loading.\r\n */\r\n async startup(\r\n startupScene?: Nullable<string>,\r\n splashScreen?: Nullable<string>,\r\n startupScript?: Nullable<string>\r\n ) {\r\n const splashScreenLayer = 9999;\r\n if (splashScreen) {\r\n const splashScreenScene = await this.loadSceneFromFile(splashScreen);\r\n if (splashScreenScene) {\r\n this.setRenderable(splashScreenScene, splashScreenLayer);\r\n }\r\n }\r\n if (startupScript) {\r\n const path =\r\n startupScript.toLowerCase().endsWith('.ts') || startupScript.toLowerCase().endsWith('.js')\r\n ? startupScript.slice(0, -3)\r\n : startupScript;\r\n await this.attachScript(null, path);\r\n }\r\n if (startupScene) {\r\n const scene = await this.loadSceneFromFile(startupScene);\r\n this.setRenderable(scene, 0);\r\n }\r\n this.setRenderable(null, splashScreenLayer);\r\n }\r\n /**\r\n * Renders all active render layers.\r\n *\r\n * Each layer's `beforeRender` hook can return `false` to skip rendering that layer.\r\n * The `afterRender` hook is invoked after the render attempt.\r\n */\r\n render() {\r\n this._activeRenderables.forEach((info) => {\r\n if (!info.renderable) {\r\n return;\r\n }\r\n const render = info.hook?.beforeRender\r\n ? (info.hook.beforeRender(\r\n typeof info.renderable === 'function' ? info.renderable : info.renderable.get()\r\n ) ?? true)\r\n : true;\r\n if (render) {\r\n if (typeof info.renderable === 'function') {\r\n info.renderable();\r\n } else {\r\n info.renderable.get()?.render();\r\n }\r\n }\r\n if (info.hook?.afterRender) {\r\n info.hook.afterRender(\r\n typeof info.renderable === 'function' ? info.renderable : info.renderable.get()\r\n );\r\n }\r\n });\r\n }\r\n private async ensureBuiltinVFS() {\r\n if (!this._builtinsVFS) {\r\n this._builtinsVFS = await this.createBuiltinVFS();\r\n }\r\n this.VFS.unmount('/assets/@builtins');\r\n this.VFS.mount('/assets/@builtins', this._builtinsVFS);\r\n }\r\n private async createBuiltinVFS() {\r\n const fs = new MemoryFS();\r\n const shapeClsMap = {\r\n '/primitives/box.zmsh': BoxShape,\r\n '/primitives/sphere.zmsh': SphereShape,\r\n '/primitives/cylinder.zmsh': CylinderShape,\r\n '/primitives/plane.zmsh': PlaneShape,\r\n '/primitives/torus.zmsh': TorusShape,\r\n '/primitives/tetrahedron.zmsh': TetrahedronShape,\r\n '/primitives/capsule.zmsh': CapsuleShape,\r\n '/materials/unlit.zmtl': UnlitMaterial,\r\n '/materials/lambert.zmtl': LambertMaterial,\r\n '/materials/blinnphong.zmtl': BlinnMaterial,\r\n '/materials/pbr_metallic_roughness.zmtl': PBRMetallicRoughnessMaterial,\r\n '/materials/pbr_specular_glossiness.zmtl': PBRSpecularGlossinessMaterial,\r\n '/materials/sprite_std.zmtl': StandardSpriteMaterial,\r\n '/materials/skin.zmtl': SkinMaterial\r\n } as const;\r\n for (const [key] of objectEntries(shapeClsMap)) {\r\n const obj = new shapeClsMap[key]();\r\n await this.writeSerializableObject(fs, 'Default', obj, key);\r\n obj.dispose();\r\n }\r\n fs.readOnly = true;\r\n return fs;\r\n }\r\n private async writeSerializableObject(VFS: VFS, type: string, obj: any, path: string) {\r\n try {\r\n const data = await this.resourceManager.serializeObject(obj);\r\n const content = JSON.stringify({ type, data }, null, 2);\r\n await VFS.writeFile(path, content, { encoding: 'utf8', create: true });\r\n } catch (err) {\r\n console.error(`Write file '${path}' failed: ${err}`);\r\n }\r\n }\r\n private async _loadScene(path: string) {\r\n try {\r\n const scene = await this._resourceManager.loadScene(path);\r\n if (scene) {\r\n const sceneScripts =\r\n scene.scripts.length > 0\r\n ? scene.scripts\r\n : scene.script\r\n ? [{ script: scene.script, config: scene.scriptConfig }]\r\n : [];\r\n for (const attachment of sceneScripts) {\r\n if (!attachment.script) {\r\n continue;\r\n }\r\n try {\r\n await this.attachScript(\r\n scene,\r\n attachment.script,\r\n (attachment.config ?? null) as RuntimeScriptConfig | null\r\n );\r\n } catch (err) {\r\n console.error(`Attach script failed: ${err}`);\r\n }\r\n }\r\n const nodes: (typeof scene.rootNode)[] = [];\r\n scene.rootNode.iterate((node) => {\r\n nodes.push(node);\r\n });\r\n const attachTasks = nodes.map(async (node) => {\r\n const attachments =\r\n node.scripts.length > 0\r\n ? node.scripts\r\n : node.script\r\n ? [{ script: node.script, config: node.scriptConfig }]\r\n : [];\r\n for (const attachment of attachments) {\r\n if (!attachment.script) {\r\n continue;\r\n }\r\n try {\r\n await this.attachScript(\r\n node,\r\n attachment.script,\r\n (attachment.config ?? null) as RuntimeScriptConfig | null\r\n );\r\n } catch (err) {\r\n console.error(`Attach script failed: ${err}`);\r\n }\r\n }\r\n });\r\n if (attachTasks.length > 0) {\r\n await Promise.allSettled(attachTasks);\r\n }\r\n }\r\n return scene;\r\n } catch (err) {\r\n console.error(`Load scene from '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n}\r\n\r\nexport { MSDFTextAtlasManager };\r\n"],"names":["Engine","_builtinsVFS","_scriptingSystem","_resourceManager","_msdfTextAtlasManager","_enabled","_screen","_activeRenderables","_loadingScenes","VFS","scriptsRoot","enabled","HttpFS","ScriptingSystem","ResourceManager","MSDFTextAtlasManager","ScreenAdapter","scriptingSystem","registry","vfs","close","ensureBuiltinVFS","resourceManager","msdfTextAtlasManager","releaseFontAsset","font","fontAsset","getFontAsset","atlasReleased","releaseAtlas","fontReleased","configureMSDFAtlas","pageSize","glyphSize","distanceRange","padding","console","warn","configureAtlas","screen","init","detachAllScripts","loadRuntimeScriptClass","module","attachScript","host","config","detachScript","idOrInstance","getScriptObjects","update","deltaTime","elapsedTime","loadSceneFromFile","path","normalizePath","_loadScene","setRenderable","renderable","layer","hook","entry","DRef","dispose","readFile","encoding","content","err","error","startup","startupScene","splashScreen","startupScript","splashScreenLayer","splashScreenScene","toLowerCase","endsWith","slice","scene","render","forEach","info","beforeRender","get","afterRender","createBuiltinVFS","unmount","mount","fs","MemoryFS","shapeClsMap","BoxShape","SphereShape","CylinderShape","PlaneShape","TorusShape","TetrahedronShape","CapsuleShape","UnlitMaterial","LambertMaterial","BlinnMaterial","PBRMetallicRoughnessMaterial","PBRSpecularGlossinessMaterial","StandardSpriteMaterial","SkinMaterial","key","objectEntries","obj","writeSerializableObject","readOnly","type","data","serializeObject","JSON","stringify","writeFile","create","loadScene","sceneScripts","scripts","length","script","scriptConfig","attachment","nodes","rootNode","iterate","node","push","attachTasks","map","attachments","Promise","allSettled"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"engine.js","sources":["../../src/app/engine.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, ReadOptions } from '@zephyr3d/base';\r\nimport { MemoryFS, objectEntries } from '@zephyr3d/base';\r\nimport { DRef } from '@zephyr3d/base';\r\nimport { HttpFS, type VFS } from '@zephyr3d/base';\r\nimport { createDeclarativeScriptSignature, ScriptingSystem } from './scriptingsystem';\r\nimport type { Host } from './scriptingsystem';\r\nimport type { RuntimeScript, RuntimeScriptConfig } from './runtimescript';\r\nimport { ResourceManager } from '../utility/serialization/manager';\r\nimport type { Scene, SceneNode } from '../scene';\r\nimport {\r\n BoxShape,\r\n CapsuleShape,\r\n CylinderShape,\r\n PlaneShape,\r\n SphereShape,\r\n TetrahedronShape,\r\n TorusShape\r\n} from '../shapes';\r\nimport {\r\n BlinnMaterial,\r\n EyeMaterial,\r\n LambertMaterial,\r\n PBRMetallicRoughnessMaterial,\r\n PBRSpecularGlossinessMaterial,\r\n UnlitMaterial\r\n} from '../material';\r\nimport { StandardSpriteMaterial } from '../material/sprite_std';\r\nimport { SkinMaterial } from '../material/skin';\r\nimport { HairMaterial } from '../material/hair';\r\nimport { ScreenAdapter } from './screen';\r\nimport { MSDFTextAtlasManager } from '../text/runtime';\r\n\r\n/**\r\n * Interface for objects that can be rendered.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderable extends IDisposable {\r\n render(): void;\r\n}\r\n\r\n/**\r\n * Type for render functions that can be registered as renderables.\r\n *\r\n * @public\r\n */\r\nexport type RenderFunc = () => void;\r\n\r\n/**\r\n * Interface for render hooks to customize rendering behavior.\r\n *\r\n * @public\r\n */\r\nexport interface IRenderHook {\r\n // If presents, called before rendering the renderable. Return `false` to skip rendering.\r\n beforeRender?: (renderable: any) => boolean | void;\r\n // If presents, called after rendering the renderable.\r\n afterRender?: (renderable: any) => void;\r\n}\r\n\r\n/**\r\n * Core engine class managing scripting, serialization, and rendering.\r\n *\r\n * Responsibilities:\r\n * - Manages a {@link ScriptingSystem} for dynamic script attachment and lifecycle.\r\n * - Manages a {@link ResourceManager} for loading scenes and assets.\r\n * - Maintains a list of active renderable objects to be rendered each frame.\r\n * - Provides methods to attach/detach scripts, update scripts, load scenes, and read files.\r\n * - Supports enabling/disabling of runtime operations.\r\n *\r\n * @remarks\r\n * The engine can be configured with a virtual file system (VFS) and script root path.\r\n * It exposes methods to manage scripts on host objects, update scripts each frame,\r\n * load scenes from files, and render active objects.\r\n *\r\n * @public\r\n */\r\nexport class Engine {\r\n private _builtinsVFS: Nullable<MemoryFS>;\r\n private _scriptingSystem: ScriptingSystem;\r\n private _resourceManager: ResourceManager;\r\n private _msdfTextAtlasManager: MSDFTextAtlasManager;\r\n private _enabled: boolean;\r\n private _screen: ScreenAdapter;\r\n protected _activeRenderables: {\r\n renderable: Nullable<RenderFunc> | DRef<IRenderable>;\r\n hook: Nullable<IRenderHook>;\r\n }[];\r\n private _loadingScenes: Partial<Record<string, Promise<Nullable<Scene>>>>;\r\n /**\r\n * Creates a new runtime manager.\r\n *\r\n * @param VFS - Optional virtual file system passed to the internal {@link ScriptingSystem}.\r\n * @param scriptsRoot - Optional scripts root path within the VFS. Defaults as in `ScriptingSystem`.\r\n * @param enabled - Whether runtime operations are active. Defaults to `true`.\r\n */\r\n constructor(VFS?: VFS, scriptsRoot?: string, enabled?: boolean) {\r\n VFS = VFS ?? new HttpFS('./');\r\n this._builtinsVFS = null;\r\n this._scriptingSystem = new ScriptingSystem({ VFS, scriptsRoot });\r\n this._resourceManager = new ResourceManager(VFS);\r\n this._msdfTextAtlasManager = new MSDFTextAtlasManager();\r\n this._enabled = enabled ?? true;\r\n this._activeRenderables = [];\r\n this._loadingScenes = {};\r\n this._screen = new ScreenAdapter();\r\n }\r\n /**\r\n * Exposes the instance of {@link ScriptingSystem}.\r\n */\r\n get scriptingSystem() {\r\n return this._scriptingSystem;\r\n }\r\n /**\r\n * Exposes the virtual file system used by the underlying {@link ScriptingSystem}'s registry.\r\n */\r\n get VFS() {\r\n return this._scriptingSystem.registry.VFS;\r\n }\r\n set VFS(vfs: VFS) {\r\n if (vfs !== this._resourceManager.VFS) {\r\n this._resourceManager.VFS?.close();\r\n this._resourceManager.VFS = vfs;\r\n this._scriptingSystem.registry.VFS = vfs;\r\n this.ensureBuiltinVFS();\r\n }\r\n }\r\n /**\r\n * Exposes the instance of {@link ResourceManager}.\r\n */\r\n get resourceManager() {\r\n return this._resourceManager;\r\n }\r\n /**\r\n * Exposes the shared runtime MSDF text atlas manager.\r\n */\r\n get msdfTextAtlasManager() {\r\n return this._msdfTextAtlasManager;\r\n }\r\n /**\r\n * Releases a loaded font asset from the resource cache and disposes its shared MSDF atlas textures.\r\n *\r\n * Existing scene nodes that still reference this font asset are not updated automatically.\r\n * Call this only after you have stopped using the font, or when you intentionally want it to rebuild later.\r\n *\r\n * @param font - The loaded font asset path to release.\r\n * @returns `true` if either the atlas cache or the font cache had an entry to remove.\r\n */\r\n releaseFontAsset(font: string) {\r\n const fontAsset = this._resourceManager.getFontAsset(font);\r\n if (!fontAsset) {\r\n return false;\r\n }\r\n const atlasReleased = this._msdfTextAtlasManager.releaseAtlas(fontAsset);\r\n const fontReleased = this._resourceManager.releaseFontAsset(fontAsset);\r\n return atlasReleased || fontReleased;\r\n }\r\n /**\r\n * Configures the MSDF atlas for a given font asset, creating or replacing the atlas as needed.\r\n *\r\n * This is useful to customize the glyph size, atlas page size, distance range, and padding for MSDF text rendering.\r\n * Existing scene nodes that reference this font asset will use the updated atlas automatically.\r\n *\r\n * @param font - The font asset path to configure the MSDF atlas for.\r\n * @param pageSize - The size of each atlas page in pixels (e.g., 512, 1024).\r\n * @param glyphSize - The size of each glyph in pixels (e.g., 32, 64).\r\n * @param distanceRange - The distance range for MSDF generation. Defaults to 4.\r\n * @param padding - The padding between glyphs in the atlas in pixels. Defaults to 2.\r\n * @returns `true` if the atlas was successfully configured, or `false` if the font asset was not found.\r\n *\r\n * @remarks\r\n * The font asset must be loaded and available in the resource manager for the atlas to be configured.\r\n */\r\n configureMSDFAtlas(\r\n font: string,\r\n pageSize: number,\r\n glyphSize: number,\r\n distanceRange?: number,\r\n padding?: number\r\n ) {\r\n const fontAsset = this._resourceManager.getFontAsset(font);\r\n if (!fontAsset) {\r\n console.warn(`Font asset '${font}' not found for MSDF atlas configuration.`);\r\n return false;\r\n }\r\n this._msdfTextAtlasManager.configureAtlas(fontAsset, pageSize, glyphSize, distanceRange, padding);\r\n return true;\r\n }\r\n /**\r\n * Exposes the active {@link ScreenAdapter}.\r\n */\r\n get screen() {\r\n return this._screen;\r\n }\r\n /** @internal */\r\n async init() {\r\n await this.ensureBuiltinVFS();\r\n }\r\n /**\r\n * Detaches all scripts from all hosts, if enabled.\r\n *\r\n * No-op when `enabled === false`.\r\n */\r\n detachAllScripts() {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachAllScripts();\r\n }\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<Nullable<{ url: string; cls: GenericConstructor<RuntimeScript<T>> }>> {\r\n return await this._scriptingSystem.loadRuntimeScriptClass(module);\r\n }\r\n /**\r\n * Attaches a script module to the given host, if enabled.\r\n *\r\n * When disabled, this method resolves to `null` without side effects.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host object to attach the script to.\r\n * @param module - Module identifier to resolve and load.\r\n * @param config - Optional configuration passed to the script instance.\r\n * @returns The `RuntimeScript<T>` instance, or `null` if disabled or on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ) {\r\n return this._enabled ? await this._scriptingSystem.attachScript(host, module, config) : null;\r\n }\r\n /**\r\n * Attaches all serialized script declarations on a scene node subtree.\r\n *\r\n * The operation is explicit and idempotent. Repeated or concurrent calls reuse\r\n * instances already attached for the same declaration, while duplicate declarations\r\n * within one host remain distinct.\r\n *\r\n * @param root - Root node whose own declarations and descendants are processed.\r\n * @returns Script instances in host/declaration order. Failed declarations are omitted.\r\n */\r\n async attachScriptsInSubtree(root: SceneNode) {\r\n if (!this._enabled) {\r\n return [];\r\n }\r\n const nodes: SceneNode[] = [];\r\n root.iterate((node) => {\r\n nodes.push(node);\r\n });\r\n const results = await Promise.all(nodes.map((node) => this.attachDeclaredScripts(node)));\r\n return results.flat();\r\n }\r\n /**\r\n * Detaches a script from a host, by module ID or instance, if enabled.\r\n *\r\n * No-op when disabled.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - Host to detach from.\r\n * @param idOrInstance - Target script by module ID or instance reference.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance: string | RuntimeScript<T>) {\r\n if (this._enabled) {\r\n this._scriptingSystem.detachScript(host, idOrInstance);\r\n }\r\n }\r\n /**\r\n * Gets all scripts attached to a host.\r\n *\r\n * Delegates to {@link ScriptingSystem.getScriptObjects}.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - Host object to query.\r\n * @returns Script instances attached to the host, or an empty array.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown) {\r\n return this._scriptingSystem.getScriptObjects(host) as T[];\r\n }\r\n /**\r\n * Ticks all attached scripts by calling their `onUpdate` hooks, if enabled.\r\n *\r\n * @param deltaTime - Time since last update in Seconds.\r\n * @param elapsedTime - Total elapsed time in Seconds.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._enabled) {\r\n this._scriptingSystem.update(deltaTime, elapsedTime);\r\n }\r\n }\r\n /**\r\n * Loads a scene from a file path.\r\n *\r\n * Concurrent requests for the same normalized path share the same loading promise.\r\n * Scripts declared on the scene and its nodes are attached after the scene is loaded.\r\n *\r\n * @param path - Scene file path in the current VFS.\r\n * @returns The loaded scene, or `null` when loading fails.\r\n */\r\n async loadSceneFromFile(path: string) {\r\n path = this.VFS.normalizePath(path);\r\n if (!this._loadingScenes[path]) {\r\n this._loadingScenes[path] = this._loadScene(path);\r\n }\r\n return this._loadingScenes[path]!;\r\n }\r\n /**\r\n * Sets or clears the renderable for a render layer.\r\n *\r\n * Passing `null` clears the layer. Object renderables are held through a strong reference wrapper,\r\n * while render functions are stored directly.\r\n *\r\n * @param renderable - Renderable object or render function to assign, or `null` to clear.\r\n * @param layer - Render layer index. Defaults to `0`.\r\n * @param hook - Optional render hook invoked before and after this layer renders.\r\n */\r\n setRenderable(renderable: Nullable<IRenderable | RenderFunc>, layer = 0, hook?: IRenderHook) {\r\n const entry = this._activeRenderables[layer];\r\n if (!entry) {\r\n this._activeRenderables[layer] = {\r\n renderable: renderable\r\n ? typeof renderable === 'function'\r\n ? renderable\r\n : new DRef<IRenderable>(renderable)\r\n : null,\r\n hook: hook ?? null\r\n };\r\n } else {\r\n if (entry.renderable) {\r\n if (entry.renderable instanceof DRef) {\r\n entry.renderable.dispose();\r\n }\r\n entry.renderable = null;\r\n }\r\n if (typeof renderable === 'function') {\r\n entry.renderable = renderable;\r\n } else if (renderable) {\r\n entry.renderable = new DRef<IRenderable>(renderable);\r\n }\r\n entry.hook = hook ?? null;\r\n }\r\n }\r\n /**\r\n * Reads a file from the current VFS.\r\n *\r\n * @typeParam T - Requested read encoding.\r\n * @param path - File path to read.\r\n * @param encoding - Optional read encoding. Defaults to `binary`.\r\n * @returns The file content, or `null` when the read fails.\r\n */\r\n async readFile<T extends ReadOptions['encoding'] = 'binary'>(path: string, encoding?: T) {\r\n try {\r\n const content = await this.VFS.readFile(path, { encoding: encoding ?? 'binary' });\r\n return content as T extends 'binary' ? ArrayBuffer : string;\r\n } catch (err) {\r\n console.error(`Read file '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Starts the runtime by optionally showing a splash screen, running a startup script,\r\n * and loading the startup scene.\r\n *\r\n * @param startupScene - Optional scene path rendered on layer `0` after startup completes.\r\n * @param splashScreen - Optional scene path rendered on a temporary splash layer during startup.\r\n * @param startupScript - Optional startup script module path. A trailing `.ts` or `.js`\r\n * extension is removed before loading.\r\n */\r\n async startup(\r\n startupScene?: Nullable<string>,\r\n splashScreen?: Nullable<string>,\r\n startupScript?: Nullable<string>\r\n ) {\r\n const splashScreenLayer = 9999;\r\n if (splashScreen) {\r\n const splashScreenScene = await this.loadSceneFromFile(splashScreen);\r\n if (splashScreenScene) {\r\n this.setRenderable(splashScreenScene, splashScreenLayer);\r\n }\r\n }\r\n if (startupScript) {\r\n const path =\r\n startupScript.toLowerCase().endsWith('.ts') || startupScript.toLowerCase().endsWith('.js')\r\n ? startupScript.slice(0, -3)\r\n : startupScript;\r\n await this.attachScript(null, path);\r\n }\r\n if (startupScene) {\r\n const scene = await this.loadSceneFromFile(startupScene);\r\n this.setRenderable(scene, 0);\r\n }\r\n this.setRenderable(null, splashScreenLayer);\r\n }\r\n /**\r\n * Renders all active render layers.\r\n *\r\n * Each layer's `beforeRender` hook can return `false` to skip rendering that layer.\r\n * The `afterRender` hook is invoked after the render attempt.\r\n */\r\n render() {\r\n this._activeRenderables.forEach((info) => {\r\n if (!info.renderable) {\r\n return;\r\n }\r\n const render = info.hook?.beforeRender\r\n ? (info.hook.beforeRender(\r\n typeof info.renderable === 'function' ? info.renderable : info.renderable.get()\r\n ) ?? true)\r\n : true;\r\n if (render) {\r\n if (typeof info.renderable === 'function') {\r\n info.renderable();\r\n } else {\r\n info.renderable.get()?.render();\r\n }\r\n }\r\n if (info.hook?.afterRender) {\r\n info.hook.afterRender(\r\n typeof info.renderable === 'function' ? info.renderable : info.renderable.get()\r\n );\r\n }\r\n });\r\n }\r\n private async ensureBuiltinVFS() {\r\n if (!this._builtinsVFS) {\r\n this._builtinsVFS = await this.createBuiltinVFS();\r\n }\r\n this.VFS.unmount('/assets/@builtins');\r\n this.VFS.mount('/assets/@builtins', this._builtinsVFS);\r\n }\r\n private async createBuiltinVFS() {\r\n const fs = new MemoryFS();\r\n const shapeClsMap = {\r\n '/primitives/box.zmsh': BoxShape,\r\n '/primitives/sphere.zmsh': SphereShape,\r\n '/primitives/cylinder.zmsh': CylinderShape,\r\n '/primitives/plane.zmsh': PlaneShape,\r\n '/primitives/torus.zmsh': TorusShape,\r\n '/primitives/tetrahedron.zmsh': TetrahedronShape,\r\n '/primitives/capsule.zmsh': CapsuleShape,\r\n '/materials/unlit.zmtl': UnlitMaterial,\r\n '/materials/lambert.zmtl': LambertMaterial,\r\n '/materials/blinnphong.zmtl': BlinnMaterial,\r\n '/materials/pbr_metallic_roughness.zmtl': PBRMetallicRoughnessMaterial,\r\n '/materials/pbr_specular_glossiness.zmtl': PBRSpecularGlossinessMaterial,\r\n '/materials/sprite_std.zmtl': StandardSpriteMaterial,\r\n '/materials/skin.zmtl': SkinMaterial,\r\n '/materials/hair.zmtl': HairMaterial,\r\n '/materials/eye.zmtl': EyeMaterial\r\n } as const;\r\n for (const [key] of objectEntries(shapeClsMap)) {\r\n const obj = new shapeClsMap[key]();\r\n await this.writeSerializableObject(fs, 'Default', obj, key);\r\n obj.dispose();\r\n }\r\n fs.readOnly = true;\r\n return fs;\r\n }\r\n private async writeSerializableObject(VFS: VFS, type: string, obj: any, path: string) {\r\n try {\r\n const data = await this.resourceManager.serializeObject(obj);\r\n const content = JSON.stringify({ type, data }, null, 2);\r\n await VFS.writeFile(path, content, { encoding: 'utf8', create: true });\r\n } catch (err) {\r\n console.error(`Write file '${path}' failed: ${err}`);\r\n }\r\n }\r\n private async _loadScene(path: string) {\r\n try {\r\n const scene = await this._resourceManager.loadScene(path);\r\n if (scene) {\r\n await this.attachDeclaredScripts(scene);\r\n await this.attachScriptsInSubtree(scene.rootNode);\r\n }\r\n return scene;\r\n } catch (err) {\r\n console.error(`Load scene from '${path}' failed: ${err}`);\r\n return null;\r\n }\r\n }\r\n private async attachDeclaredScripts<\r\n T extends Host & {\r\n scripts: { script: string; config: unknown }[];\r\n script: string;\r\n scriptConfig: unknown;\r\n }\r\n >(host: T) {\r\n const attachments =\r\n host.scripts.length > 0\r\n ? host.scripts\r\n : host.script\r\n ? [{ script: host.script, config: host.scriptConfig }]\r\n : [];\r\n const occurrences = new Map<string, number>();\r\n const declarationKeys = new Set<string>();\r\n const requests = attachments\r\n .filter((attachment) => !!attachment.script)\r\n .map((attachment) => {\r\n const config = (attachment.config ?? null) as RuntimeScriptConfig | null;\r\n const signature = createDeclarativeScriptSignature(attachment.script, config);\r\n const occurrence = occurrences.get(signature) ?? 0;\r\n occurrences.set(signature, occurrence + 1);\r\n declarationKeys.add(`${signature}\\n${occurrence}`);\r\n return this._scriptingSystem\r\n .attachDeclarativeScript(host, attachment.script, config, occurrence)\r\n .catch((err) => {\r\n console.error(`Attach script '${attachment.script}' failed: ${err}`);\r\n return null;\r\n });\r\n });\r\n this._scriptingSystem.synchronizeDeclarativeScripts(host, declarationKeys);\r\n const instances = await Promise.all(requests);\r\n return instances.filter((instance): instance is RuntimeScript<T> => !!instance);\r\n }\r\n}\r\n\r\nexport { MSDFTextAtlasManager };\r\n"],"names":["Engine","_builtinsVFS","_scriptingSystem","_resourceManager","_msdfTextAtlasManager","_enabled","_screen","_activeRenderables","_loadingScenes","VFS","scriptsRoot","enabled","HttpFS","ScriptingSystem","ResourceManager","MSDFTextAtlasManager","ScreenAdapter","scriptingSystem","registry","vfs","close","ensureBuiltinVFS","resourceManager","msdfTextAtlasManager","releaseFontAsset","font","fontAsset","getFontAsset","atlasReleased","releaseAtlas","fontReleased","configureMSDFAtlas","pageSize","glyphSize","distanceRange","padding","console","warn","configureAtlas","screen","init","detachAllScripts","loadRuntimeScriptClass","module","attachScript","host","config","attachScriptsInSubtree","root","nodes","iterate","node","push","results","Promise","all","map","attachDeclaredScripts","flat","detachScript","idOrInstance","getScriptObjects","update","deltaTime","elapsedTime","loadSceneFromFile","path","normalizePath","_loadScene","setRenderable","renderable","layer","hook","entry","DRef","dispose","readFile","encoding","content","err","error","startup","startupScene","splashScreen","startupScript","splashScreenLayer","splashScreenScene","toLowerCase","endsWith","slice","scene","render","forEach","info","beforeRender","get","afterRender","createBuiltinVFS","unmount","mount","fs","MemoryFS","shapeClsMap","BoxShape","SphereShape","CylinderShape","PlaneShape","TorusShape","TetrahedronShape","CapsuleShape","UnlitMaterial","LambertMaterial","BlinnMaterial","PBRMetallicRoughnessMaterial","PBRSpecularGlossinessMaterial","StandardSpriteMaterial","SkinMaterial","HairMaterial","EyeMaterial","key","objectEntries","obj","writeSerializableObject","readOnly","type","data","serializeObject","JSON","stringify","writeFile","create","loadScene","rootNode","attachments","scripts","length","script","scriptConfig","occurrences","Map","declarationKeys","Set","requests","filter","attachment","signature","createDeclarativeScriptSignature","occurrence","set","add","attachDeclarativeScript","catch","synchronizeDeclarativeScripts","instances","instance"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4DA;;;;;;;;;;;;;;;;AAgBC,IACM,MAAMA,MAAAA,CAAAA;IACHC,YAAiC;IACjCC,gBAAkC;IAClCC,gBAAkC;IAClCC,qBAA4C;IAC5CC,QAAkB;IAClBC,OAAuB;IACrBC,kBAGN;IACIC,cAAkE;AAC1E;;;;;;AAMC,MACD,YAAYC,GAAS,EAAEC,WAAoB,EAAEC,OAAiB,CAAE;QAC9DF,GAAMA,GAAAA,GAAAA,IAAO,IAAIG,MAAO,CAAA,IAAA,CAAA;QACxB,IAAI,CAACX,YAAY,GAAG,IAAA;AACpB,QAAA,IAAI,CAACC,gBAAgB,GAAG,IAAIW,eAAgB,CAAA;AAAEJ,YAAAA,GAAAA;AAAKC,YAAAA;AAAY,SAAA,CAAA;AAC/D,QAAA,IAAI,CAACP,gBAAgB,GAAG,IAAIW,eAAgBL,CAAAA,GAAAA,CAAAA;QAC5C,IAAI,CAACL,qBAAqB,GAAG,IAAIW,oBAAAA,EAAAA;QACjC,IAAI,CAACV,QAAQ,GAAGM,OAAW,IAAA,IAAA;QAC3B,IAAI,CAACJ,kBAAkB,GAAG,EAAE;QAC5B,IAAI,CAACC,cAAc,GAAG,EAAC;QACvB,IAAI,CAACF,OAAO,GAAG,IAAIU,aAAAA,EAAAA;AACrB;AACA;;AAEC,MACD,IAAIC,eAAkB,GAAA;QACpB,OAAO,IAAI,CAACf,gBAAgB;AAC9B;AACA;;AAEC,MACD,IAAIO,GAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAACP,gBAAgB,CAACgB,QAAQ,CAACT,GAAG;AAC3C;IACA,IAAIA,GAAAA,CAAIU,GAAQ,EAAE;AAChB,QAAA,IAAIA,QAAQ,IAAI,CAAChB,gBAAgB,CAACM,GAAG,EAAE;AACrC,YAAA,IAAI,CAACN,gBAAgB,CAACM,GAAG,EAAEW,KAAAA,EAAAA;AAC3B,YAAA,IAAI,CAACjB,gBAAgB,CAACM,GAAG,GAAGU,GAAAA;AAC5B,YAAA,IAAI,CAACjB,gBAAgB,CAACgB,QAAQ,CAACT,GAAG,GAAGU,GAAAA;AACrC,YAAA,IAAI,CAACE,gBAAgB,EAAA;AACvB;AACF;AACA;;AAEC,MACD,IAAIC,eAAkB,GAAA;QACpB,OAAO,IAAI,CAACnB,gBAAgB;AAC9B;AACA;;AAEC,MACD,IAAIoB,oBAAuB,GAAA;QACzB,OAAO,IAAI,CAACnB,qBAAqB;AACnC;AACA;;;;;;;;MASAoB,gBAAAA,CAAiBC,IAAY,EAAE;AAC7B,QAAA,MAAMC,YAAY,IAAI,CAACvB,gBAAgB,CAACwB,YAAY,CAACF,IAAAA,CAAAA;AACrD,QAAA,IAAI,CAACC,SAAW,EAAA;YACd,OAAO,KAAA;AACT;AACA,QAAA,MAAME,gBAAgB,IAAI,CAACxB,qBAAqB,CAACyB,YAAY,CAACH,SAAAA,CAAAA;AAC9D,QAAA,MAAMI,eAAe,IAAI,CAAC3B,gBAAgB,CAACqB,gBAAgB,CAACE,SAAAA,CAAAA;AAC5D,QAAA,OAAOE,aAAiBE,IAAAA,YAAAA;AAC1B;AACA;;;;;;;;;;;;;;;MAgBAC,kBAAAA,CACEN,IAAY,EACZO,QAAgB,EAChBC,SAAiB,EACjBC,aAAsB,EACtBC,OAAgB,EAChB;AACA,QAAA,MAAMT,YAAY,IAAI,CAACvB,gBAAgB,CAACwB,YAAY,CAACF,IAAAA,CAAAA;AACrD,QAAA,IAAI,CAACC,SAAW,EAAA;AACdU,YAAAA,OAAAA,CAAQC,IAAI,CAAC,CAAC,YAAY,EAAEZ,IAAAA,CAAK,yCAAyC,CAAC,CAAA;YAC3E,OAAO,KAAA;AACT;QACA,IAAI,CAACrB,qBAAqB,CAACkC,cAAc,CAACZ,SAAWM,EAAAA,QAAAA,EAAUC,WAAWC,aAAeC,EAAAA,OAAAA,CAAAA;QACzF,OAAO,IAAA;AACT;AACA;;AAEC,MACD,IAAII,MAAS,GAAA;QACX,OAAO,IAAI,CAACjC,OAAO;AACrB;qBAEA,MAAMkC,IAAO,GAAA;QACX,MAAM,IAAI,CAACnB,gBAAgB,EAAA;AAC7B;AACA;;;;AAIC,MACDoB,gBAAmB,GAAA;QACjB,IAAI,IAAI,CAACpC,QAAQ,EAAE;YACjB,IAAI,CAACH,gBAAgB,CAACuC,gBAAgB,EAAA;AACxC;AACF;AACA;;;;MAKA,MAAMC,sBACJC,CAAAA,MAAc,EACiE;AAC/E,QAAA,OAAO,MAAM,IAAI,CAACzC,gBAAgB,CAACwC,sBAAsB,CAACC,MAAAA,CAAAA;AAC5D;AACA;;;;;;;;;;AAUC,MACD,MAAMC,YACJC,CAAAA,IAAiB,EACjBF,MAAc,EACdG,MAAsC,EACtC;AACA,QAAA,OAAO,IAAI,CAACzC,QAAQ,GAAG,MAAM,IAAI,CAACH,gBAAgB,CAAC0C,YAAY,CAACC,IAAAA,EAAMF,QAAQG,MAAU,CAAA,GAAA,IAAA;AAC1F;AACA;;;;;;;;;MAUA,MAAMC,sBAAuBC,CAAAA,IAAe,EAAE;AAC5C,QAAA,IAAI,CAAC,IAAI,CAAC3C,QAAQ,EAAE;AAClB,YAAA,OAAO,EAAE;AACX;AACA,QAAA,MAAM4C,QAAqB,EAAE;QAC7BD,IAAKE,CAAAA,OAAO,CAAC,CAACC,IAAAA,GAAAA;AACZF,YAAAA,KAAAA,CAAMG,IAAI,CAACD,IAAAA,CAAAA;AACb,SAAA,CAAA;AACA,QAAA,MAAME,OAAU,GAAA,MAAMC,OAAQC,CAAAA,GAAG,CAACN,KAAAA,CAAMO,GAAG,CAAC,CAACL,IAAAA,GAAS,IAAI,CAACM,qBAAqB,CAACN,IAAAA,CAAAA,CAAAA,CAAAA;AACjF,QAAA,OAAOE,QAAQK,IAAI,EAAA;AACrB;AACA;;;;;;;;AAQC,MACDC,YAA6Bd,CAAAA,IAAO,EAAEe,YAAuC,EAAE;QAC7E,IAAI,IAAI,CAACvD,QAAQ,EAAE;AACjB,YAAA,IAAI,CAACH,gBAAgB,CAACyD,YAAY,CAACd,IAAMe,EAAAA,YAAAA,CAAAA;AAC3C;AACF;AACA;;;;;;;;MASAC,gBAAAA,CAA+ChB,IAAa,EAAE;AAC5D,QAAA,OAAO,IAAI,CAAC3C,gBAAgB,CAAC2D,gBAAgB,CAAChB,IAAAA,CAAAA;AAChD;AACA;;;;;AAKC,MACDiB,MAAOC,CAAAA,SAAiB,EAAEC,WAAmB,EAAE;QAC7C,IAAI,IAAI,CAAC3D,QAAQ,EAAE;AACjB,YAAA,IAAI,CAACH,gBAAgB,CAAC4D,MAAM,CAACC,SAAWC,EAAAA,WAAAA,CAAAA;AAC1C;AACF;AACA;;;;;;;;MASA,MAAMC,iBAAkBC,CAAAA,IAAY,EAAE;AACpCA,QAAAA,IAAAA,GAAO,IAAI,CAACzD,GAAG,CAAC0D,aAAa,CAACD,IAAAA,CAAAA;AAC9B,QAAA,IAAI,CAAC,IAAI,CAAC1D,cAAc,CAAC0D,KAAK,EAAE;YAC9B,IAAI,CAAC1D,cAAc,CAAC0D,IAAAA,CAAK,GAAG,IAAI,CAACE,UAAU,CAACF,IAAAA,CAAAA;AAC9C;AACA,QAAA,OAAO,IAAI,CAAC1D,cAAc,CAAC0D,IAAK,CAAA;AAClC;AACA;;;;;;;;;AASC,MACDG,cAAcC,UAA8C,EAAEC,QAAQ,CAAC,EAAEC,IAAkB,EAAE;AAC3F,QAAA,MAAMC,KAAQ,GAAA,IAAI,CAAClE,kBAAkB,CAACgE,KAAM,CAAA;AAC5C,QAAA,IAAI,CAACE,KAAO,EAAA;AACV,YAAA,IAAI,CAAClE,kBAAkB,CAACgE,KAAAA,CAAM,GAAG;AAC/BD,gBAAAA,UAAAA,EAAYA,aACR,OAAOA,UAAAA,KAAe,aACpBA,UACA,GAAA,IAAII,KAAkBJ,UACxB,CAAA,GAAA,IAAA;AACJE,gBAAAA,IAAAA,EAAMA,IAAQ,IAAA;AAChB,aAAA;SACK,MAAA;YACL,IAAIC,KAAAA,CAAMH,UAAU,EAAE;gBACpB,IAAIG,KAAAA,CAAMH,UAAU,YAAYI,IAAM,EAAA;oBACpCD,KAAMH,CAAAA,UAAU,CAACK,OAAO,EAAA;AAC1B;AACAF,gBAAAA,KAAAA,CAAMH,UAAU,GAAG,IAAA;AACrB;YACA,IAAI,OAAOA,eAAe,UAAY,EAAA;AACpCG,gBAAAA,KAAAA,CAAMH,UAAU,GAAGA,UAAAA;AACrB,aAAA,MAAO,IAAIA,UAAY,EAAA;gBACrBG,KAAMH,CAAAA,UAAU,GAAG,IAAII,IAAkBJ,CAAAA,UAAAA,CAAAA;AAC3C;YACAG,KAAMD,CAAAA,IAAI,GAAGA,IAAQ,IAAA,IAAA;AACvB;AACF;AACA;;;;;;;AAOC,MACD,MAAMI,QAAAA,CAAuDV,IAAY,EAAEW,QAAY,EAAE;QACvF,IAAI;YACF,MAAMC,OAAAA,GAAU,MAAM,IAAI,CAACrE,GAAG,CAACmE,QAAQ,CAACV,IAAM,EAAA;AAAEW,gBAAAA,QAAAA,EAAUA,QAAY,IAAA;AAAS,aAAA,CAAA;YAC/E,OAAOC,OAAAA;AACT,SAAA,CAAE,OAAOC,GAAK,EAAA;YACZ3C,OAAQ4C,CAAAA,KAAK,CAAC,CAAC,WAAW,EAAEd,IAAK,CAAA,UAAU,EAAEa,GAAK,CAAA,CAAA,CAAA;YAClD,OAAO,IAAA;AACT;AACF;AACA;;;;;;;;AAQC,MACD,MAAME,OACJC,CAAAA,YAA+B,EAC/BC,YAA+B,EAC/BC,aAAgC,EAChC;AACA,QAAA,MAAMC,iBAAoB,GAAA,IAAA;AAC1B,QAAA,IAAIF,YAAc,EAAA;AAChB,YAAA,MAAMG,iBAAoB,GAAA,MAAM,IAAI,CAACrB,iBAAiB,CAACkB,YAAAA,CAAAA;AACvD,YAAA,IAAIG,iBAAmB,EAAA;gBACrB,IAAI,CAACjB,aAAa,CAACiB,iBAAmBD,EAAAA,iBAAAA,CAAAA;AACxC;AACF;AACA,QAAA,IAAID,aAAe,EAAA;AACjB,YAAA,MAAMlB,OACJkB,aAAcG,CAAAA,WAAW,GAAGC,QAAQ,CAAC,UAAUJ,aAAcG,CAAAA,WAAW,EAAGC,CAAAA,QAAQ,CAAC,KAChFJ,CAAAA,GAAAA,aAAAA,CAAcK,KAAK,CAAC,CAAA,EAAG,EACvBL,CAAAA,GAAAA,aAAAA;AACN,YAAA,MAAM,IAAI,CAACxC,YAAY,CAAC,IAAMsB,EAAAA,IAAAA,CAAAA;AAChC;AACA,QAAA,IAAIgB,YAAc,EAAA;AAChB,YAAA,MAAMQ,KAAQ,GAAA,MAAM,IAAI,CAACzB,iBAAiB,CAACiB,YAAAA,CAAAA;YAC3C,IAAI,CAACb,aAAa,CAACqB,KAAO,EAAA,CAAA,CAAA;AAC5B;QACA,IAAI,CAACrB,aAAa,CAAC,IAAMgB,EAAAA,iBAAAA,CAAAA;AAC3B;AACA;;;;;AAKC,MACDM,MAAS,GAAA;AACP,QAAA,IAAI,CAACpF,kBAAkB,CAACqF,OAAO,CAAC,CAACC,IAAAA,GAAAA;YAC/B,IAAI,CAACA,IAAKvB,CAAAA,UAAU,EAAE;AACpB,gBAAA;AACF;YACA,MAAMqB,MAAAA,GAASE,KAAKrB,IAAI,EAAEsB,eACrBD,IAAKrB,CAAAA,IAAI,CAACsB,YAAY,CACrB,OAAOD,KAAKvB,UAAU,KAAK,UAAauB,GAAAA,IAAAA,CAAKvB,UAAU,GAAGuB,KAAKvB,UAAU,CAACyB,GAAG,EAAA,CAAA,IAC1E,IACL,GAAA,IAAA;AACJ,YAAA,IAAIJ,MAAQ,EAAA;AACV,gBAAA,IAAI,OAAOE,IAAAA,CAAKvB,UAAU,KAAK,UAAY,EAAA;AACzCuB,oBAAAA,IAAAA,CAAKvB,UAAU,EAAA;iBACV,MAAA;oBACLuB,IAAKvB,CAAAA,UAAU,CAACyB,GAAG,EAAIJ,EAAAA,MAAAA,EAAAA;AACzB;AACF;YACA,IAAIE,IAAAA,CAAKrB,IAAI,EAAEwB,WAAa,EAAA;AAC1BH,gBAAAA,IAAAA,CAAKrB,IAAI,CAACwB,WAAW,CACnB,OAAOH,IAAKvB,CAAAA,UAAU,KAAK,UAAA,GAAauB,KAAKvB,UAAU,GAAGuB,IAAKvB,CAAAA,UAAU,CAACyB,GAAG,EAAA,CAAA;AAEjF;AACF,SAAA,CAAA;AACF;AACA,IAAA,MAAc1E,gBAAmB,GAAA;AAC/B,QAAA,IAAI,CAAC,IAAI,CAACpB,YAAY,EAAE;AACtB,YAAA,IAAI,CAACA,YAAY,GAAG,MAAM,IAAI,CAACgG,gBAAgB,EAAA;AACjD;AACA,QAAA,IAAI,CAACxF,GAAG,CAACyF,OAAO,CAAC,mBAAA,CAAA;QACjB,IAAI,CAACzF,GAAG,CAAC0F,KAAK,CAAC,mBAAqB,EAAA,IAAI,CAAClG,YAAY,CAAA;AACvD;AACA,IAAA,MAAcgG,gBAAmB,GAAA;AAC/B,QAAA,MAAMG,KAAK,IAAIC,QAAAA,EAAAA;AACf,QAAA,MAAMC,WAAc,GAAA;YAClB,sBAAwBC,EAAAA,QAAAA;YACxB,yBAA2BC,EAAAA,WAAAA;YAC3B,2BAA6BC,EAAAA,aAAAA;YAC7B,wBAA0BC,EAAAA,UAAAA;YAC1B,wBAA0BC,EAAAA,UAAAA;YAC1B,8BAAgCC,EAAAA,gBAAAA;YAChC,0BAA4BC,EAAAA,YAAAA;YAC5B,uBAAyBC,EAAAA,aAAAA;YACzB,yBAA2BC,EAAAA,eAAAA;YAC3B,4BAA8BC,EAAAA,aAAAA;YAC9B,wCAA0CC,EAAAA,4BAAAA;YAC1C,yCAA2CC,EAAAA,6BAAAA;YAC3C,4BAA8BC,EAAAA,sBAAAA;YAC9B,sBAAwBC,EAAAA,YAAAA;YACxB,sBAAwBC,EAAAA,YAAAA;YACxB,qBAAuBC,EAAAA;AACzB,SAAA;AACA,QAAA,KAAK,MAAM,CAACC,GAAI,CAAA,IAAIC,cAAclB,WAAc,CAAA,CAAA;AAC9C,YAAA,MAAMmB,GAAM,GAAA,IAAInB,WAAW,CAACiB,GAAI,CAAA,EAAA;AAChC,YAAA,MAAM,IAAI,CAACG,uBAAuB,CAACtB,EAAAA,EAAI,WAAWqB,GAAKF,EAAAA,GAAAA,CAAAA;AACvDE,YAAAA,GAAAA,CAAI9C,OAAO,EAAA;AACb;AACAyB,QAAAA,EAAAA,CAAGuB,QAAQ,GAAG,IAAA;QACd,OAAOvB,EAAAA;AACT;IACA,MAAcsB,uBAAAA,CAAwBjH,GAAQ,EAAEmH,IAAY,EAAEH,GAAQ,EAAEvD,IAAY,EAAE;QACpF,IAAI;AACF,YAAA,MAAM2D,OAAO,MAAM,IAAI,CAACvG,eAAe,CAACwG,eAAe,CAACL,GAAAA,CAAAA;YACxD,MAAM3C,OAAAA,GAAUiD,IAAKC,CAAAA,SAAS,CAAC;AAAEJ,gBAAAA,IAAAA;AAAMC,gBAAAA;AAAK,aAAA,EAAG,IAAM,EAAA,CAAA,CAAA;AACrD,YAAA,MAAMpH,GAAIwH,CAAAA,SAAS,CAAC/D,IAAAA,EAAMY,OAAS,EAAA;gBAAED,QAAU,EAAA,MAAA;gBAAQqD,MAAQ,EAAA;AAAK,aAAA,CAAA;AACtE,SAAA,CAAE,OAAOnD,GAAK,EAAA;YACZ3C,OAAQ4C,CAAAA,KAAK,CAAC,CAAC,YAAY,EAAEd,IAAK,CAAA,UAAU,EAAEa,GAAK,CAAA,CAAA,CAAA;AACrD;AACF;IACA,MAAcX,UAAAA,CAAWF,IAAY,EAAE;QACrC,IAAI;AACF,YAAA,MAAMwB,QAAQ,MAAM,IAAI,CAACvF,gBAAgB,CAACgI,SAAS,CAACjE,IAAAA,CAAAA;AACpD,YAAA,IAAIwB,KAAO,EAAA;gBACT,MAAM,IAAI,CAACjC,qBAAqB,CAACiC,KAAAA,CAAAA;AACjC,gBAAA,MAAM,IAAI,CAAC3C,sBAAsB,CAAC2C,MAAM0C,QAAQ,CAAA;AAClD;YACA,OAAO1C,KAAAA;AACT,SAAA,CAAE,OAAOX,GAAK,EAAA;YACZ3C,OAAQ4C,CAAAA,KAAK,CAAC,CAAC,iBAAiB,EAAEd,IAAK,CAAA,UAAU,EAAEa,GAAK,CAAA,CAAA,CAAA;YACxD,OAAO,IAAA;AACT;AACF;IACA,MAActB,qBAAAA,CAMZZ,IAAO,EAAE;AACT,QAAA,MAAMwF,WACJxF,GAAAA,IAAAA,CAAKyF,OAAO,CAACC,MAAM,GAAG,CAClB1F,GAAAA,IAAAA,CAAKyF,OAAO,GACZzF,IAAK2F,CAAAA,MAAM,GACT;AAAC,YAAA;AAAEA,gBAAAA,MAAAA,EAAQ3F,KAAK2F,MAAM;AAAE1F,gBAAAA,MAAAA,EAAQD,KAAK4F;AAAa;AAAE,SAAA,GACpD,EAAE;AACV,QAAA,MAAMC,cAAc,IAAIC,GAAAA,EAAAA;AACxB,QAAA,MAAMC,kBAAkB,IAAIC,GAAAA,EAAAA;AAC5B,QAAA,MAAMC,QAAWT,GAAAA,WAAAA,CACdU,MAAM,CAAC,CAACC,UAAAA,GAAe,CAAC,CAACA,UAAWR,CAAAA,MAAM,CAC1ChF,CAAAA,GAAG,CAAC,CAACwF,UAAAA,GAAAA;YACJ,MAAMlG,MAAAA,GAAUkG,UAAWlG,CAAAA,MAAM,IAAI,IAAA;AACrC,YAAA,MAAMmG,SAAYC,GAAAA,gCAAAA,CAAiCF,UAAWR,CAAAA,MAAM,EAAE1F,MAAAA,CAAAA;AACtE,YAAA,MAAMqG,UAAaT,GAAAA,WAAAA,CAAY3C,GAAG,CAACkD,SAAc,CAAA,IAAA,CAAA;YACjDP,WAAYU,CAAAA,GAAG,CAACH,SAAAA,EAAWE,UAAa,GAAA,CAAA,CAAA;AACxCP,YAAAA,eAAAA,CAAgBS,GAAG,CAAC,CAAA,EAAGJ,SAAU,CAAA,EAAE,EAAEE,UAAY,CAAA,CAAA,CAAA;AACjD,YAAA,OAAO,IAAI,CAACjJ,gBAAgB,CACzBoJ,uBAAuB,CAACzG,IAAAA,EAAMmG,UAAWR,CAAAA,MAAM,EAAE1F,MAAAA,EAAQqG,UACzDI,CAAAA,CAAAA,KAAK,CAAC,CAACxE,GAAAA,GAAAA;gBACN3C,OAAQ4C,CAAAA,KAAK,CAAC,CAAC,eAAe,EAAEgE,WAAWR,MAAM,CAAC,UAAU,EAAEzD,GAAK,CAAA,CAAA,CAAA;gBACnE,OAAO,IAAA;AACT,aAAA,CAAA;AACJ,SAAA,CAAA;AACF,QAAA,IAAI,CAAC7E,gBAAgB,CAACsJ,6BAA6B,CAAC3G,IAAM+F,EAAAA,eAAAA,CAAAA;AAC1D,QAAA,MAAMa,SAAY,GAAA,MAAMnG,OAAQC,CAAAA,GAAG,CAACuF,QAAAA,CAAAA;AACpC,QAAA,OAAOW,UAAUV,MAAM,CAAC,CAACW,QAAAA,GAA2C,CAAC,CAACA,QAAAA,CAAAA;AACxE;AACF;;;;"}
|
|
@@ -21,6 +21,21 @@ function resolveCreatedHook(instance) {
|
|
|
21
21
|
hook: ()=>instance.onCreated()
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
|
+
function stableSerializeScriptConfig(value) {
|
|
25
|
+
if (value === null || typeof value !== 'object') {
|
|
26
|
+
return JSON.stringify(value) ?? String(value);
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
return `[${value.map((item)=>stableSerializeScriptConfig(item)).join(',')}]`;
|
|
30
|
+
}
|
|
31
|
+
return `{${Object.keys(value).sort().map((key)=>`${JSON.stringify(key)}:${stableSerializeScriptConfig(value[key])}`).join(',')}}`;
|
|
32
|
+
}
|
|
33
|
+
function createDeclarativeScriptKey(module, config, occurrence) {
|
|
34
|
+
return `${module}\n${stableSerializeScriptConfig(config ?? null)}\n${occurrence}`;
|
|
35
|
+
}
|
|
36
|
+
/** @internal */ function createDeclarativeScriptSignature(module, config) {
|
|
37
|
+
return `${module}\n${stableSerializeScriptConfig(config ?? null)}`;
|
|
38
|
+
}
|
|
24
39
|
/**
|
|
25
40
|
* Script system that resolves, loads, and manages lifecycle of runtime scripts.
|
|
26
41
|
*
|
|
@@ -42,6 +57,9 @@ function resolveCreatedHook(instance) {
|
|
|
42
57
|
_registry;
|
|
43
58
|
_hostScripts;
|
|
44
59
|
_scriptHosts;
|
|
60
|
+
_declarativeScripts;
|
|
61
|
+
_pendingDeclarativeScripts;
|
|
62
|
+
_activeDeclarativeKeys;
|
|
45
63
|
_onLoadError;
|
|
46
64
|
_importComment;
|
|
47
65
|
/**
|
|
@@ -52,6 +70,9 @@ function resolveCreatedHook(instance) {
|
|
|
52
70
|
this._registry = new ScriptRegistry(opts.VFS ?? new HttpFS('./'), opts.scriptsRoot ?? '/');
|
|
53
71
|
this._hostScripts = new Map();
|
|
54
72
|
this._scriptHosts = new Map();
|
|
73
|
+
this._declarativeScripts = new Map();
|
|
74
|
+
this._pendingDeclarativeScripts = new Map();
|
|
75
|
+
this._activeDeclarativeKeys = new Map();
|
|
55
76
|
this._importComment = opts.importComment;
|
|
56
77
|
this._onLoadError = opts.onLoadError;
|
|
57
78
|
}
|
|
@@ -143,7 +164,9 @@ function resolveCreatedHook(instance) {
|
|
|
143
164
|
this._hostScripts.set(host, list);
|
|
144
165
|
if (host) {
|
|
145
166
|
host.on('dispose', ()=>{
|
|
167
|
+
this._activeDeclarativeKeys.set(host, new Set());
|
|
146
168
|
this.detachScript(host);
|
|
169
|
+
this.cleanupDeclarativeHost(host);
|
|
147
170
|
});
|
|
148
171
|
}
|
|
149
172
|
}
|
|
@@ -179,6 +202,78 @@ function resolveCreatedHook(instance) {
|
|
|
179
202
|
return info ? await this.attachScriptIndirect(host, info, config) : null;
|
|
180
203
|
}
|
|
181
204
|
/**
|
|
205
|
+
* Attaches a serialized script declaration once for a host.
|
|
206
|
+
*
|
|
207
|
+
* Repeated or concurrent calls with the same module, configuration and occurrence
|
|
208
|
+
* return the existing instance. The occurrence distinguishes duplicate declarations
|
|
209
|
+
* that intentionally appear more than once on the same host.
|
|
210
|
+
*
|
|
211
|
+
* @param host - Host object to attach the script to.
|
|
212
|
+
* @param module - Logical script module identifier.
|
|
213
|
+
* @param config - Serialized script configuration.
|
|
214
|
+
* @param occurrence - Zero-based occurrence among equivalent declarations on the host.
|
|
215
|
+
*/ async attachDeclarativeScript(host, module, config, occurrence = 0) {
|
|
216
|
+
const key = createDeclarativeScriptKey(module, config ?? null, occurrence);
|
|
217
|
+
const attached = this._declarativeScripts.get(host)?.get(key);
|
|
218
|
+
if (attached) {
|
|
219
|
+
return attached;
|
|
220
|
+
}
|
|
221
|
+
const pending = this._pendingDeclarativeScripts.get(host)?.get(key);
|
|
222
|
+
if (pending) {
|
|
223
|
+
return await pending;
|
|
224
|
+
}
|
|
225
|
+
let hostPending = this._pendingDeclarativeScripts.get(host);
|
|
226
|
+
if (!hostPending) {
|
|
227
|
+
hostPending = new Map();
|
|
228
|
+
this._pendingDeclarativeScripts.set(host, hostPending);
|
|
229
|
+
}
|
|
230
|
+
const request = this.attachScript(host, module, config).then((instance)=>{
|
|
231
|
+
if (instance) {
|
|
232
|
+
const activeKeys = this._activeDeclarativeKeys.get(host);
|
|
233
|
+
if (activeKeys && !activeKeys.has(key)) {
|
|
234
|
+
this.detachScript(host, instance);
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
let hostAttached = this._declarativeScripts.get(host);
|
|
238
|
+
if (!hostAttached) {
|
|
239
|
+
hostAttached = new Map();
|
|
240
|
+
this._declarativeScripts.set(host, hostAttached);
|
|
241
|
+
}
|
|
242
|
+
hostAttached.set(key, instance);
|
|
243
|
+
}
|
|
244
|
+
return instance;
|
|
245
|
+
});
|
|
246
|
+
hostPending.set(key, request);
|
|
247
|
+
try {
|
|
248
|
+
return await request;
|
|
249
|
+
} finally{
|
|
250
|
+
if (hostPending.get(key) === request) {
|
|
251
|
+
hostPending.delete(key);
|
|
252
|
+
}
|
|
253
|
+
if (hostPending.size === 0) {
|
|
254
|
+
this._pendingDeclarativeScripts.delete(host);
|
|
255
|
+
this.cleanupDeclarativeHost(host);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Detaches declarative script instances whose keys are no longer present on a host.
|
|
261
|
+
*
|
|
262
|
+
* @param host - Host whose serialized declarations changed.
|
|
263
|
+
* @param activeKeys - Complete set of declaration keys currently present on the host.
|
|
264
|
+
*/ synchronizeDeclarativeScripts(host, activeKeys) {
|
|
265
|
+
this._activeDeclarativeKeys.set(host, new Set(activeKeys));
|
|
266
|
+
const declarative = this._declarativeScripts.get(host);
|
|
267
|
+
if (!declarative) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
for (const [key, instance] of declarative){
|
|
271
|
+
if (!activeKeys.has(key)) {
|
|
272
|
+
this.detachScript(host, instance);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
182
277
|
* Detaches script(s) from a host.
|
|
183
278
|
*
|
|
184
279
|
* Behavior:
|
|
@@ -198,7 +293,7 @@ function resolveCreatedHook(instance) {
|
|
|
198
293
|
}
|
|
199
294
|
for(let i = list.length - 1; i >= 0; i--){
|
|
200
295
|
const it = list[i];
|
|
201
|
-
const hit = !idOrInstance || typeof idOrInstance === 'string' ? it.id === idOrInstance : it.instance === idOrInstance;
|
|
296
|
+
const hit = !idOrInstance || (typeof idOrInstance === 'string' ? it.id === idOrInstance : it.instance === idOrInstance);
|
|
202
297
|
if (hit) {
|
|
203
298
|
list.splice(i, 1);
|
|
204
299
|
try {
|
|
@@ -227,6 +322,18 @@ function resolveCreatedHook(instance) {
|
|
|
227
322
|
if (list.length === 0) {
|
|
228
323
|
this._hostScripts.delete(host);
|
|
229
324
|
}
|
|
325
|
+
const declarative = this._declarativeScripts.get(host);
|
|
326
|
+
if (declarative) {
|
|
327
|
+
for (const [key, instance] of declarative){
|
|
328
|
+
if (!this._scriptHosts.get(instance)?.includes(host)) {
|
|
329
|
+
declarative.delete(key);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
if (declarative.size === 0) {
|
|
333
|
+
this._declarativeScripts.delete(host);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
this.cleanupDeclarativeHost(host);
|
|
230
337
|
}
|
|
231
338
|
/**
|
|
232
339
|
* Get all script instances attached to a host.
|
|
@@ -265,15 +372,21 @@ function resolveCreatedHook(instance) {
|
|
|
265
372
|
*
|
|
266
373
|
* Iteratively calls {@link ScriptingSystem.detachScript} on each host until no attachments remain.
|
|
267
374
|
*/ detachAllScripts() {
|
|
375
|
+
for (const host of this._activeDeclarativeKeys.keys()){
|
|
376
|
+
this._activeDeclarativeKeys.set(host, new Set());
|
|
377
|
+
}
|
|
268
378
|
while(this._hostScripts.size > 0){
|
|
269
|
-
for (const
|
|
270
|
-
|
|
271
|
-
this.detachScript(entry[0]);
|
|
272
|
-
}
|
|
379
|
+
for (const [host] of this._hostScripts){
|
|
380
|
+
this.detachScript(host);
|
|
273
381
|
}
|
|
274
382
|
}
|
|
275
383
|
}
|
|
384
|
+
cleanupDeclarativeHost(host) {
|
|
385
|
+
if (!this._hostScripts.has(host) && !this._declarativeScripts.has(host) && !this._pendingDeclarativeScripts.has(host)) {
|
|
386
|
+
this._activeDeclarativeKeys.delete(host);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
276
389
|
}
|
|
277
390
|
|
|
278
|
-
export { ScriptingSystem };
|
|
391
|
+
export { ScriptingSystem, createDeclarativeScriptSignature };
|
|
279
392
|
//# sourceMappingURL=scriptingsystem.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptingsystem.js","sources":["../../src/app/scriptingsystem.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, VFS } from '@zephyr3d/base';\r\nimport { HttpFS } from '@zephyr3d/base';\r\nimport { ScriptRegistry } from './scriptregistry';\r\nimport { applyRuntimeScriptConfig, RuntimeScript, type RuntimeScriptConfig } from './runtimescript';\r\n\r\nfunction resolveCreatedHook(instance: RuntimeScript<any>) {\r\n if (instance.onCreated !== RuntimeScript.prototype.onCreated) {\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n }\r\n const legacyHook = (instance as RuntimeScript<any> & { onCreate?: () => void | Promise<void> }).onCreate;\r\n if (typeof legacyHook === 'function') {\r\n return {\r\n legacy: true,\r\n hook: () => legacyHook.call(instance)\r\n };\r\n }\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n}\r\n\r\n/**\r\n * A host object that supports disposal.\r\n *\r\n * Hosts are objects to which scripts can be attached. They are expected to\r\n * emit a `'dispose'` event compatible with `IDisposable` so that scripts\r\n * can be automatically detached when the host is destroyed.\r\n *\r\n * @public\r\n */\r\nexport type Host = IDisposable;\r\n\r\n/**\r\n * Options for configuring a `ScriptingSystem`.\r\n *\r\n * @public\r\n */\r\nexport type ScriptingSystemOptions = {\r\n /** Virtual file system used by the script registry. Defaults to `new HttpFS('./')`. */\r\n VFS?: VFS;\r\n /** Root path for scripts within the VFS. Defaults to `/`. */\r\n scriptsRoot?: string;\r\n /**\r\n * Optional string appended to dynamic import URLs (e.g., for cache busting).\r\n * Example: `'?v=' + Date.now()`\r\n */\r\n importComment?: string;\r\n /**\r\n * Optional callback invoked when a module fails to load.\r\n * @param e - The error that occurred.\r\n * @param id - The module ID that failed to load.\r\n */\r\n onLoadError?: (e: unknown, id: string) => void;\r\n};\r\n\r\n/**\r\n * Information about a script attached to a host.\r\n *\r\n * @public\r\n */\r\nexport interface IAttachedScript {\r\n /** The logical module identifier used to resolve the script. */\r\n id: string;\r\n /** The resolved runtime URL used for dynamic import. */\r\n url: string;\r\n /** The instantiated runtime script. */\r\n instance: RuntimeScript<any>;\r\n}\r\n\r\n/**\r\n * Script system that resolves, loads, and manages lifecycle of runtime scripts.\r\n *\r\n * Responsibilities:\r\n * - Resolves module IDs to URLs via {@link ScriptRegistry}\r\n * - Dynamically imports modules and instantiates a `RuntimeScript` (default export)\r\n * - Tracks attachments between hosts and script instances\r\n * - Bridges script lifecycle hooks: `onCreated`, `onAttached`, `onDetached`, `onDestroy`, `onUpdate`\r\n * - Auto-detaches scripts when a host is disposed\r\n *\r\n * Notes:\r\n * - Multiple hosts can reference the same `RuntimeScript` instance; destruction\r\n * occurs when the last host detaches.\r\n * - Errors during load/attach/update are caught and logged; an optional\r\n * `onLoadError` callback can be provided.\r\n *\r\n * @public\r\n */\r\nexport class ScriptingSystem {\r\n private _registry: ScriptRegistry;\r\n private _hostScripts: Map<Nullable<Host>, IAttachedScript[]>;\r\n private _scriptHosts: Map<RuntimeScript<any>, Nullable<Host>[]>;\r\n private _onLoadError?: (e: unknown, id: string) => void;\r\n private _importComment?: string;\r\n\r\n /**\r\n * Constructs a new scripting system.\r\n *\r\n * @param opts - Optional configuration.\r\n */\r\n constructor(opts: ScriptingSystemOptions = {}) {\r\n this._registry = new ScriptRegistry(opts.VFS ?? new HttpFS('./'), opts.scriptsRoot ?? '/');\r\n this._hostScripts = new Map();\r\n this._scriptHosts = new Map();\r\n this._importComment = opts.importComment;\r\n this._onLoadError = opts.onLoadError;\r\n }\r\n\r\n /**\r\n * Accessor for the underlying script registry used for module resolution.\r\n */\r\n get registry() {\r\n return this._registry;\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<\r\n Nullable<{\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n }>\r\n > {\r\n let mod: any = null;\r\n const moduleName = module ? String(module).slice(0, 64) : '';\r\n let url = '';\r\n try {\r\n url = await this._registry.resolveRuntimeUrl(module);\r\n if (!url) {\r\n return null;\r\n }\r\n mod = await import(url + (this._importComment ?? ''));\r\n } catch (e) {\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n }\r\n if (mod && typeof mod.default === 'function') {\r\n return { url, id: module, cls: mod.default as GenericConstructor<RuntimeScript<T>> };\r\n } else {\r\n console.error(`No runtime class exported from '${moduleName}'`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Creates a script from a dynamic loaded class and attachs it to a host and returns the `RuntimeScript` instance.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param classInfo - The dynamic loaded class information\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScriptIndirect<T extends Host>(\r\n host: Nullable<T>,\r\n classInfo: {\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n },\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n try {\r\n const { url, id, cls } = classInfo;\r\n let instance: Nullable<RuntimeScript<T>> = new cls();\r\n if (instance instanceof RuntimeScript) {\r\n applyRuntimeScriptConfig(instance, config);\r\n if (!this._scriptHosts.has(instance)) {\r\n const createdHook = resolveCreatedHook(instance);\r\n if (createdHook.legacy) {\r\n console.warn(`Script '${id}' uses deprecated onCreate(); rename it to onCreated().`);\r\n }\r\n const P = createdHook.hook();\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n }\r\n } else {\r\n instance = null;\r\n }\r\n if (!instance) {\r\n console.warn(`Script '${url}' does not have RuntimeScript class exported as default`);\r\n return null;\r\n }\r\n\r\n let hostList = this._scriptHosts.get(instance);\r\n if (!hostList) {\r\n hostList = [];\r\n this._scriptHosts.set(instance, hostList);\r\n }\r\n if (hostList.includes(host)) {\r\n console.warn(`Script '${url}' already attached`);\r\n return instance;\r\n }\r\n hostList.push(host);\r\n\r\n const P = instance.onAttached(host);\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n\r\n const attached: IAttachedScript = {\r\n id,\r\n url,\r\n instance\r\n };\r\n\r\n let list = this._hostScripts.get(host);\r\n if (!list) {\r\n list = [];\r\n this._hostScripts.set(host, list);\r\n if (host) {\r\n host.on('dispose', () => {\r\n this.detachScript(host);\r\n });\r\n }\r\n }\r\n list.push(attached);\r\n\r\n return attached.instance;\r\n } catch (e) {\r\n const moduleName = classInfo.id ? String(classInfo.id).slice(0, 64) : '';\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n this._onLoadError?.(e, classInfo.id);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Attaches a script to a host and returns the `RuntimeScript` instance.\r\n *\r\n * Process:\r\n * 1. Resolve module ID to a runtime URL via the registry.\r\n * 2. Dynamically import the module.\r\n * 3. Instantiate the default export if it is a constructor.\r\n * 4. If this is the first time the instance is seen, call `onCreated()`.\r\n * 5. Link the instance to the host, and call `onAttached(host)`.\r\n * 6. Subscribe to the host's `'dispose'` event to auto-detach.\r\n *\r\n * If the module cannot be resolved or does not export a default `RuntimeScript`\r\n * subclass, a warning is logged and `null` is returned.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param module - Module identifier used by the registry (logical ID or path).\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n const info = await this.loadRuntimeScriptClass(module);\r\n return info ? await this.attachScriptIndirect(host, info, config) : null;\r\n }\r\n\r\n /**\r\n * Detaches script(s) from a host.\r\n *\r\n * Behavior:\r\n * - If `idOrInstance` is omitted, detaches all scripts from the host.\r\n * - If a module ID is provided, detaches only the matching script.\r\n * - If a `RuntimeScript` instance is provided, detaches that instance.\r\n * - Invokes `onDetached(host)` on each detached instance.\r\n * - If the instance has no remaining hosts, invokes `onDestroy()` and disposes tracking.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host to detach from.\r\n * @param idOrInstance - Optional module ID or script instance to target.\r\n */\r\n detachScript<T extends Host>(host: T, idOrInstance?: string | RuntimeScript<T>) {\r\n const list = this._hostScripts.get(host);\r\n if (!list || list.length === 0) {\r\n return;\r\n }\r\n for (let i = list.length - 1; i >= 0; i--) {\r\n const it = list[i];\r\n const hit =\r\n !idOrInstance || typeof idOrInstance === 'string'\r\n ? it.id === idOrInstance\r\n : it.instance === idOrInstance;\r\n if (hit) {\r\n list.splice(i, 1);\r\n try {\r\n it.instance.onDetached(host);\r\n } catch (err) {\r\n console.error(`Error occured at onDetach() of module '${it.id}': ${err}`);\r\n }\r\n\r\n const hostList = this._scriptHosts.get(it.instance);\r\n if (hostList) {\r\n const index = hostList.indexOf(host);\r\n if (index >= 0) {\r\n hostList.splice(index, 1);\r\n }\r\n }\r\n if (!hostList || hostList.length === 0) {\r\n try {\r\n it.instance.onDestroy();\r\n } catch (err) {\r\n console.error(`Error occured at onDestroy() of module '${it.id}': ${err}`);\r\n } finally {\r\n this._scriptHosts.delete(it.instance);\r\n }\r\n }\r\n }\r\n }\r\n if (list.length === 0) {\r\n this._hostScripts.delete(host);\r\n }\r\n }\r\n\r\n /**\r\n * Get all script instances attached to a host.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - The host whose scripts to retrieve.\r\n * @returns Script instances attached to the host, or an empty array if none.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown): T[] {\r\n return (this._hostScripts.get(host as Host) as unknown as T[]) || [];\r\n }\r\n\r\n /**\r\n * Ticks all attached script instances.\r\n *\r\n * Calls `onUpdate(deltaTime, elapsedTime)` on every attached script instance\r\n * across all hosts. Exceptions thrown by a script are caught and logged,\r\n * allowing other scripts to continue updating.\r\n *\r\n * @param deltaTime - Time in seconds since last update.\r\n * @param elapsedTime - Total time in seconds since start.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._hostScripts.size === 0) {\r\n return;\r\n }\r\n for (const list of this._hostScripts.values()) {\r\n for (const s of list) {\r\n try {\r\n s.instance.onUpdate(deltaTime, elapsedTime);\r\n } catch (err) {\r\n console.error(`Error occured at onUpdate() of module '${s.id}': ${err}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches all scripts from all hosts.\r\n *\r\n * Iteratively calls {@link ScriptingSystem.detachScript} on each host until no attachments remain.\r\n */\r\n detachAllScripts() {\r\n while (this._hostScripts.size > 0) {\r\n for (const entry of this._hostScripts) {\r\n if (entry[0]) {\r\n this.detachScript(entry[0]);\r\n }\r\n }\r\n }\r\n }\r\n}\r\n"],"names":["resolveCreatedHook","instance","onCreated","RuntimeScript","prototype","legacy","hook","legacyHook","onCreate","call","ScriptingSystem","_registry","_hostScripts","_scriptHosts","_onLoadError","_importComment","opts","ScriptRegistry","VFS","HttpFS","scriptsRoot","Map","importComment","onLoadError","registry","loadRuntimeScriptClass","module","mod","moduleName","String","slice","url","resolveRuntimeUrl","e","console","error","default","id","cls","attachScriptIndirect","host","classInfo","config","applyRuntimeScriptConfig","has","createdHook","warn","P","Promise","hostList","get","set","includes","push","onAttached","attached","list","on","detachScript","attachScript","info","idOrInstance","length","i","it","hit","splice","onDetached","err","index","indexOf","onDestroy","delete","getScriptObjects","update","deltaTime","elapsedTime","size","values","s","onUpdate","detachAllScripts","entry"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"scriptingsystem.js","sources":["../../src/app/scriptingsystem.ts"],"sourcesContent":["import type { GenericConstructor, IDisposable, Nullable, VFS } from '@zephyr3d/base';\r\nimport { HttpFS } from '@zephyr3d/base';\r\nimport { ScriptRegistry } from './scriptregistry';\r\nimport { applyRuntimeScriptConfig, RuntimeScript, type RuntimeScriptConfig } from './runtimescript';\r\n\r\nfunction resolveCreatedHook(instance: RuntimeScript<any>) {\r\n if (instance.onCreated !== RuntimeScript.prototype.onCreated) {\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n }\r\n const legacyHook = (instance as RuntimeScript<any> & { onCreate?: () => void | Promise<void> }).onCreate;\r\n if (typeof legacyHook === 'function') {\r\n return {\r\n legacy: true,\r\n hook: () => legacyHook.call(instance)\r\n };\r\n }\r\n return {\r\n legacy: false,\r\n hook: () => instance.onCreated()\r\n };\r\n}\r\n\r\n/**\r\n * A host object that supports disposal.\r\n *\r\n * Hosts are objects to which scripts can be attached. They are expected to\r\n * emit a `'dispose'` event compatible with `IDisposable` so that scripts\r\n * can be automatically detached when the host is destroyed.\r\n *\r\n * @public\r\n */\r\nexport type Host = IDisposable;\r\n\r\n/**\r\n * Options for configuring a `ScriptingSystem`.\r\n *\r\n * @public\r\n */\r\nexport type ScriptingSystemOptions = {\r\n /** Virtual file system used by the script registry. Defaults to `new HttpFS('./')`. */\r\n VFS?: VFS;\r\n /** Root path for scripts within the VFS. Defaults to `/`. */\r\n scriptsRoot?: string;\r\n /**\r\n * Optional string appended to dynamic import URLs (e.g., for cache busting).\r\n * Example: `'?v=' + Date.now()`\r\n */\r\n importComment?: string;\r\n /**\r\n * Optional callback invoked when a module fails to load.\r\n * @param e - The error that occurred.\r\n * @param id - The module ID that failed to load.\r\n */\r\n onLoadError?: (e: unknown, id: string) => void;\r\n};\r\n\r\n/**\r\n * Information about a script attached to a host.\r\n *\r\n * @public\r\n */\r\nexport interface IAttachedScript {\r\n /** The logical module identifier used to resolve the script. */\r\n id: string;\r\n /** The resolved runtime URL used for dynamic import. */\r\n url: string;\r\n /** The instantiated runtime script. */\r\n instance: RuntimeScript<any>;\r\n}\r\n\r\nfunction stableSerializeScriptConfig(value: unknown): string {\r\n if (value === null || typeof value !== 'object') {\r\n return JSON.stringify(value) ?? String(value);\r\n }\r\n if (Array.isArray(value)) {\r\n return `[${value.map((item) => stableSerializeScriptConfig(item)).join(',')}]`;\r\n }\r\n return `{${Object.keys(value as Record<string, unknown>)\r\n .sort()\r\n .map(\r\n (key) =>\r\n `${JSON.stringify(key)}:${stableSerializeScriptConfig((value as Record<string, unknown>)[key])}`\r\n )\r\n .join(',')}}`;\r\n}\r\n\r\nfunction createDeclarativeScriptKey(\r\n module: string,\r\n config: Nullable<RuntimeScriptConfig>,\r\n occurrence: number\r\n) {\r\n return `${module}\\n${stableSerializeScriptConfig(config ?? null)}\\n${occurrence}`;\r\n}\r\n\r\n/** @internal */\r\nexport function createDeclarativeScriptSignature(module: string, config: Nullable<RuntimeScriptConfig>) {\r\n return `${module}\\n${stableSerializeScriptConfig(config ?? null)}`;\r\n}\r\n\r\n/**\r\n * Script system that resolves, loads, and manages lifecycle of runtime scripts.\r\n *\r\n * Responsibilities:\r\n * - Resolves module IDs to URLs via {@link ScriptRegistry}\r\n * - Dynamically imports modules and instantiates a `RuntimeScript` (default export)\r\n * - Tracks attachments between hosts and script instances\r\n * - Bridges script lifecycle hooks: `onCreated`, `onAttached`, `onDetached`, `onDestroy`, `onUpdate`\r\n * - Auto-detaches scripts when a host is disposed\r\n *\r\n * Notes:\r\n * - Multiple hosts can reference the same `RuntimeScript` instance; destruction\r\n * occurs when the last host detaches.\r\n * - Errors during load/attach/update are caught and logged; an optional\r\n * `onLoadError` callback can be provided.\r\n *\r\n * @public\r\n */\r\nexport class ScriptingSystem {\r\n private _registry: ScriptRegistry;\r\n private _hostScripts: Map<Nullable<Host>, IAttachedScript[]>;\r\n private _scriptHosts: Map<RuntimeScript<any>, Nullable<Host>[]>;\r\n private _declarativeScripts: Map<Nullable<Host>, Map<string, RuntimeScript<any>>>;\r\n private _pendingDeclarativeScripts: Map<Nullable<Host>, Map<string, Promise<Nullable<RuntimeScript<any>>>>>;\r\n private _activeDeclarativeKeys: Map<Nullable<Host>, ReadonlySet<string>>;\r\n private _onLoadError?: (e: unknown, id: string) => void;\r\n private _importComment?: string;\r\n\r\n /**\r\n * Constructs a new scripting system.\r\n *\r\n * @param opts - Optional configuration.\r\n */\r\n constructor(opts: ScriptingSystemOptions = {}) {\r\n this._registry = new ScriptRegistry(opts.VFS ?? new HttpFS('./'), opts.scriptsRoot ?? '/');\r\n this._hostScripts = new Map();\r\n this._scriptHosts = new Map();\r\n this._declarativeScripts = new Map();\r\n this._pendingDeclarativeScripts = new Map();\r\n this._activeDeclarativeKeys = new Map();\r\n this._importComment = opts.importComment;\r\n this._onLoadError = opts.onLoadError;\r\n }\r\n\r\n /**\r\n * Accessor for the underlying script registry used for module resolution.\r\n */\r\n get registry() {\r\n return this._registry;\r\n }\r\n /**\r\n * Loads a runtime script class from file\r\n * @param module - file path\r\n * @returns The runtime script class or null\r\n */\r\n async loadRuntimeScriptClass<T extends Host = Host>(\r\n module: string\r\n ): Promise<\r\n Nullable<{\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n }>\r\n > {\r\n let mod: any = null;\r\n const moduleName = module ? String(module).slice(0, 64) : '';\r\n let url = '';\r\n try {\r\n url = await this._registry.resolveRuntimeUrl(module);\r\n if (!url) {\r\n return null;\r\n }\r\n mod = await import(url + (this._importComment ?? ''));\r\n } catch (e) {\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n }\r\n if (mod && typeof mod.default === 'function') {\r\n return { url, id: module, cls: mod.default as GenericConstructor<RuntimeScript<T>> };\r\n } else {\r\n console.error(`No runtime class exported from '${moduleName}'`);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Creates a script from a dynamic loaded class and attachs it to a host and returns the `RuntimeScript` instance.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param classInfo - The dynamic loaded class information\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScriptIndirect<T extends Host>(\r\n host: Nullable<T>,\r\n classInfo: {\r\n url: string;\r\n id: string;\r\n cls: GenericConstructor<RuntimeScript<T>>;\r\n },\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n try {\r\n const { url, id, cls } = classInfo;\r\n let instance: Nullable<RuntimeScript<T>> = new cls();\r\n if (instance instanceof RuntimeScript) {\r\n applyRuntimeScriptConfig(instance, config);\r\n if (!this._scriptHosts.has(instance)) {\r\n const createdHook = resolveCreatedHook(instance);\r\n if (createdHook.legacy) {\r\n console.warn(`Script '${id}' uses deprecated onCreate(); rename it to onCreated().`);\r\n }\r\n const P = createdHook.hook();\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n }\r\n } else {\r\n instance = null;\r\n }\r\n if (!instance) {\r\n console.warn(`Script '${url}' does not have RuntimeScript class exported as default`);\r\n return null;\r\n }\r\n\r\n let hostList = this._scriptHosts.get(instance);\r\n if (!hostList) {\r\n hostList = [];\r\n this._scriptHosts.set(instance, hostList);\r\n }\r\n if (hostList.includes(host)) {\r\n console.warn(`Script '${url}' already attached`);\r\n return instance;\r\n }\r\n hostList.push(host);\r\n\r\n const P = instance.onAttached(host);\r\n if (P instanceof Promise) {\r\n await P;\r\n }\r\n\r\n const attached: IAttachedScript = {\r\n id,\r\n url,\r\n instance\r\n };\r\n\r\n let list = this._hostScripts.get(host);\r\n if (!list) {\r\n list = [];\r\n this._hostScripts.set(host, list);\r\n if (host) {\r\n host.on('dispose', () => {\r\n this._activeDeclarativeKeys.set(host, new Set());\r\n this.detachScript(host);\r\n this.cleanupDeclarativeHost(host);\r\n });\r\n }\r\n }\r\n list.push(attached);\r\n\r\n return attached.instance;\r\n } catch (e) {\r\n const moduleName = classInfo.id ? String(classInfo.id).slice(0, 64) : '';\r\n console.error(`Load module '${moduleName}' failed: ${e}`);\r\n this._onLoadError?.(e, classInfo.id);\r\n return null;\r\n }\r\n }\r\n /**\r\n * Attaches a script to a host and returns the `RuntimeScript` instance.\r\n *\r\n * Process:\r\n * 1. Resolve module ID to a runtime URL via the registry.\r\n * 2. Dynamically import the module.\r\n * 3. Instantiate the default export if it is a constructor.\r\n * 4. If this is the first time the instance is seen, call `onCreated()`.\r\n * 5. Link the instance to the host, and call `onAttached(host)`.\r\n * 6. Subscribe to the host's `'dispose'` event to auto-detach.\r\n *\r\n * If the module cannot be resolved or does not export a default `RuntimeScript`\r\n * subclass, a warning is logged and `null` is returned.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host object to attach the script to.\r\n * @param module - Module identifier used by the registry (logical ID or path).\r\n * @returns The instantiated `RuntimeScript<T>` or `null` on failure.\r\n */\r\n async attachScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n const info = await this.loadRuntimeScriptClass(module);\r\n return info ? await this.attachScriptIndirect(host, info, config) : null;\r\n }\r\n\r\n /**\r\n * Attaches a serialized script declaration once for a host.\r\n *\r\n * Repeated or concurrent calls with the same module, configuration and occurrence\r\n * return the existing instance. The occurrence distinguishes duplicate declarations\r\n * that intentionally appear more than once on the same host.\r\n *\r\n * @param host - Host object to attach the script to.\r\n * @param module - Logical script module identifier.\r\n * @param config - Serialized script configuration.\r\n * @param occurrence - Zero-based occurrence among equivalent declarations on the host.\r\n */\r\n async attachDeclarativeScript<T extends Host>(\r\n host: Nullable<T>,\r\n module: string,\r\n config?: Nullable<RuntimeScriptConfig>,\r\n occurrence = 0\r\n ): Promise<Nullable<RuntimeScript<T>>> {\r\n const key = createDeclarativeScriptKey(module, config ?? null, occurrence);\r\n const attached = this._declarativeScripts.get(host)?.get(key);\r\n if (attached) {\r\n return attached as RuntimeScript<T>;\r\n }\r\n const pending = this._pendingDeclarativeScripts.get(host)?.get(key);\r\n if (pending) {\r\n return (await pending) as Nullable<RuntimeScript<T>>;\r\n }\r\n\r\n let hostPending = this._pendingDeclarativeScripts.get(host);\r\n if (!hostPending) {\r\n hostPending = new Map();\r\n this._pendingDeclarativeScripts.set(host, hostPending);\r\n }\r\n const request = this.attachScript(host, module, config).then((instance) => {\r\n if (instance) {\r\n const activeKeys = this._activeDeclarativeKeys.get(host);\r\n if (activeKeys && !activeKeys.has(key)) {\r\n this.detachScript(host as T, instance);\r\n return null;\r\n }\r\n let hostAttached = this._declarativeScripts.get(host);\r\n if (!hostAttached) {\r\n hostAttached = new Map();\r\n this._declarativeScripts.set(host, hostAttached);\r\n }\r\n hostAttached.set(key, instance);\r\n }\r\n return instance;\r\n });\r\n hostPending.set(key, request);\r\n try {\r\n return await request;\r\n } finally {\r\n if (hostPending.get(key) === request) {\r\n hostPending.delete(key);\r\n }\r\n if (hostPending.size === 0) {\r\n this._pendingDeclarativeScripts.delete(host);\r\n this.cleanupDeclarativeHost(host);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches declarative script instances whose keys are no longer present on a host.\r\n *\r\n * @param host - Host whose serialized declarations changed.\r\n * @param activeKeys - Complete set of declaration keys currently present on the host.\r\n */\r\n synchronizeDeclarativeScripts<T extends Host>(host: Nullable<T>, activeKeys: ReadonlySet<string>) {\r\n this._activeDeclarativeKeys.set(host, new Set(activeKeys));\r\n const declarative = this._declarativeScripts.get(host);\r\n if (!declarative) {\r\n return;\r\n }\r\n for (const [key, instance] of declarative) {\r\n if (!activeKeys.has(key)) {\r\n this.detachScript(host as T, instance as RuntimeScript<T>);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches script(s) from a host.\r\n *\r\n * Behavior:\r\n * - If `idOrInstance` is omitted, detaches all scripts from the host.\r\n * - If a module ID is provided, detaches only the matching script.\r\n * - If a `RuntimeScript` instance is provided, detaches that instance.\r\n * - Invokes `onDetached(host)` on each detached instance.\r\n * - If the instance has no remaining hosts, invokes `onDestroy()` and disposes tracking.\r\n *\r\n * @typeParam T - Host type.\r\n * @param host - The host to detach from.\r\n * @param idOrInstance - Optional module ID or script instance to target.\r\n */\r\n detachScript<T extends Host>(host: Nullable<T>, idOrInstance?: string | RuntimeScript<T>) {\r\n const list = this._hostScripts.get(host);\r\n if (!list || list.length === 0) {\r\n return;\r\n }\r\n for (let i = list.length - 1; i >= 0; i--) {\r\n const it = list[i];\r\n const hit =\r\n !idOrInstance ||\r\n (typeof idOrInstance === 'string' ? it.id === idOrInstance : it.instance === idOrInstance);\r\n if (hit) {\r\n list.splice(i, 1);\r\n try {\r\n it.instance.onDetached(host as T);\r\n } catch (err) {\r\n console.error(`Error occured at onDetach() of module '${it.id}': ${err}`);\r\n }\r\n\r\n const hostList = this._scriptHosts.get(it.instance);\r\n if (hostList) {\r\n const index = hostList.indexOf(host);\r\n if (index >= 0) {\r\n hostList.splice(index, 1);\r\n }\r\n }\r\n if (!hostList || hostList.length === 0) {\r\n try {\r\n it.instance.onDestroy();\r\n } catch (err) {\r\n console.error(`Error occured at onDestroy() of module '${it.id}': ${err}`);\r\n } finally {\r\n this._scriptHosts.delete(it.instance);\r\n }\r\n }\r\n }\r\n }\r\n if (list.length === 0) {\r\n this._hostScripts.delete(host);\r\n }\r\n const declarative = this._declarativeScripts.get(host);\r\n if (declarative) {\r\n for (const [key, instance] of declarative) {\r\n if (!this._scriptHosts.get(instance)?.includes(host)) {\r\n declarative.delete(key);\r\n }\r\n }\r\n if (declarative.size === 0) {\r\n this._declarativeScripts.delete(host);\r\n }\r\n }\r\n this.cleanupDeclarativeHost(host);\r\n }\r\n\r\n /**\r\n * Get all script instances attached to a host.\r\n *\r\n * @typeParam T - Expected script type.\r\n * @param host - The host whose scripts to retrieve.\r\n * @returns Script instances attached to the host, or an empty array if none.\r\n */\r\n getScriptObjects<T extends RuntimeScript<any>>(host: unknown): T[] {\r\n return (this._hostScripts.get(host as Host) as unknown as T[]) || [];\r\n }\r\n\r\n /**\r\n * Ticks all attached script instances.\r\n *\r\n * Calls `onUpdate(deltaTime, elapsedTime)` on every attached script instance\r\n * across all hosts. Exceptions thrown by a script are caught and logged,\r\n * allowing other scripts to continue updating.\r\n *\r\n * @param deltaTime - Time in seconds since last update.\r\n * @param elapsedTime - Total time in seconds since start.\r\n */\r\n update(deltaTime: number, elapsedTime: number) {\r\n if (this._hostScripts.size === 0) {\r\n return;\r\n }\r\n for (const list of this._hostScripts.values()) {\r\n for (const s of list) {\r\n try {\r\n s.instance.onUpdate(deltaTime, elapsedTime);\r\n } catch (err) {\r\n console.error(`Error occured at onUpdate() of module '${s.id}': ${err}`);\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Detaches all scripts from all hosts.\r\n *\r\n * Iteratively calls {@link ScriptingSystem.detachScript} on each host until no attachments remain.\r\n */\r\n detachAllScripts() {\r\n for (const host of this._activeDeclarativeKeys.keys()) {\r\n this._activeDeclarativeKeys.set(host, new Set());\r\n }\r\n while (this._hostScripts.size > 0) {\r\n for (const [host] of this._hostScripts) {\r\n this.detachScript(host);\r\n }\r\n }\r\n }\r\n\r\n private cleanupDeclarativeHost(host: Nullable<Host>) {\r\n if (\r\n !this._hostScripts.has(host) &&\r\n !this._declarativeScripts.has(host) &&\r\n !this._pendingDeclarativeScripts.has(host)\r\n ) {\r\n this._activeDeclarativeKeys.delete(host);\r\n }\r\n }\r\n}\r\n"],"names":["resolveCreatedHook","instance","onCreated","RuntimeScript","prototype","legacy","hook","legacyHook","onCreate","call","stableSerializeScriptConfig","value","JSON","stringify","String","Array","isArray","map","item","join","Object","keys","sort","key","createDeclarativeScriptKey","module","config","occurrence","createDeclarativeScriptSignature","ScriptingSystem","_registry","_hostScripts","_scriptHosts","_declarativeScripts","_pendingDeclarativeScripts","_activeDeclarativeKeys","_onLoadError","_importComment","opts","ScriptRegistry","VFS","HttpFS","scriptsRoot","Map","importComment","onLoadError","registry","loadRuntimeScriptClass","mod","moduleName","slice","url","resolveRuntimeUrl","e","console","error","default","id","cls","attachScriptIndirect","host","classInfo","applyRuntimeScriptConfig","has","createdHook","warn","P","Promise","hostList","get","set","includes","push","onAttached","attached","list","on","Set","detachScript","cleanupDeclarativeHost","attachScript","info","attachDeclarativeScript","pending","hostPending","request","then","activeKeys","hostAttached","delete","size","synchronizeDeclarativeScripts","declarative","idOrInstance","length","i","it","hit","splice","onDetached","err","index","indexOf","onDestroy","getScriptObjects","update","deltaTime","elapsedTime","values","s","onUpdate","detachAllScripts"],"mappings":"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"}
|
|
@@ -254,10 +254,11 @@ function nextScriptRegistryNamespace() {
|
|
|
254
254
|
* @returns A URL string that can be used in `import(...)`.
|
|
255
255
|
*/ async resolveRuntimeUrl(entryId) {
|
|
256
256
|
const id = await this.resolveLogicalId(entryId);
|
|
257
|
-
|
|
257
|
+
const { path, suffix } = splitSpecifierQuery(String(id));
|
|
258
|
+
if (path.startsWith('/assets/@builtins/')) {
|
|
258
259
|
return await this.build(String(id));
|
|
259
260
|
}
|
|
260
|
-
return getApp().editorMode !== 'none' ? await this.build(String(id)) : id.endsWith('.js') || id.endsWith('.mjs') ? id : id.endsWith('.ts') ? `${id.slice(0, -3)}.js` : `${id}.js`;
|
|
261
|
+
return getApp().editorMode !== 'none' ? await this.build(String(id)) : id.endsWith('.js') || id.endsWith('.mjs') ? `${id}${suffix}` : id.endsWith('.ts') ? `${id.slice(0, -3)}.js${suffix}` : `${id}.js${suffix}`;
|
|
261
262
|
}
|
|
262
263
|
/**
|
|
263
264
|
* Recursively gathers direct static and dynamic import dependencies for a module.
|