@hology/core 0.0.209 → 0.0.211
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/data/surface-definition.d.ts +3 -0
- package/dist/data/surface-definition.js +4 -0
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/services/physics/abstract-physics-system.d.ts +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +2 -1
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/rendering.js +1 -1
- package/dist/scene/batched-mesh-2.d.ts +2 -0
- package/dist/scene/batched-mesh-2.js +1 -1
- package/dist/scene/custom-param-runtime-types.js +1 -1
- package/dist/scene/landscape/landscape-manager.d.ts +2 -1
- package/dist/scene/landscape/landscape-manager.js +1 -1
- package/dist/scene/materializer.d.ts +48 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/model.d.ts +3 -0
- package/dist/scene/scatter/painted-scatter-manager.d.ts +45 -0
- package/dist/scene/scatter/painted-scatter-manager.js +4 -0
- package/dist/scene/scatter/scatter-limits.d.ts +2 -0
- package/dist/scene/scatter/scatter-limits.js +4 -0
- package/dist/scene/scatter/surface-scatter-manager.js +1 -1
- package/dist/scene/storage/storage.js +1 -1
- package/dist/scene/surface-query.d.ts +4 -0
- package/dist/scene/surface-query.js +4 -0
- package/dist/shader/builtin/landscape-composite-shader.d.ts +1 -0
- package/dist/shader/builtin/landscape-composite-shader.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/graph/compiler.d.ts +7 -4
- package/dist/shader/graph/compiler.js +1 -1
- package/dist/shader/graph/model.d.ts +1 -1
- package/dist/shader/graph/model.js +1 -1
- package/dist/shader/graph/parameters.js +1 -1
- package/dist/shader/sprite-shader.js +1 -1
- package/dist/test/material-assignment.test.js +1 -1
- package/dist/test/materializer-prefetch.test.js +1 -1
- package/dist/test/painted-scatter-manager.test.d.ts +2 -0
- package/dist/test/painted-scatter-manager.test.js +4 -0
- package/dist/test/runtime-param-type-inference.test.js +1 -1
- package/dist/test/sequence-post-process.test.js +1 -1
- package/dist/test/shader-graph.test.js +1 -1
- package/package.json +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as r}from"tslib";import{DataAssetDefinition as s}from"../shader";let t=class{};t=r([s("base.surface",{abstract:!0})],t);export{t as BaseSurfaceDefinition};/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{BehaviorSubject as e,Subject as t}from"rxjs";import*as a from"three";import{AnimationMixer as s,Color as r,Euler as i,Object3D as n,Quaternion as o,Vector2 as l,Vector3 as c,Vector4 as h}from"three";import{VisualEffect as u}from"../../effects/vfx/vfx-param.js";import{BaseActor as p}from"../../gameplay/actors/actor.js";import d from"../../gameplay/actors/builtin/index.js";import{Prefab as f,PrefabOf as m}from"../../scene/objects/prefab.js";import{SerializedParamType as y}from"../../scene/model.js";import{customParamValueNeedsAsyncResolution as C,deserializeCustomParamValue as v,deserializeCustomParamValueSync as g}from"../../scene/custom-param-deserialize.js";import{getAudioParameterDefinition as A}from"./audio-parameters.js";import{getMaterialSubTrackMatchMode as S,Sequence as w}from"./sequence-data.js";import{getSequenceSubTrackDefinition as P,getSequenceTrackDefinition as b}from"./sequence-definitions.js";import{applyInterpolation as k,evaluateCustomParamValueKeyframes as x,evaluateNumericKeyframes as T,findKeyframeSpan as I}from"./sequence-value-lane.js";import{buildRetimedAnimationClip as M,getAnimationClipRetimingSignature as q,isAnimationClipUsingRetiming as B}from"./sequence-animation-retiming.js";import{SkeletonUtils as O}from"three-stdlib";import{CharacterAnimationComponent as F,CharacterMovementComponent as E}from"../../gameplay/actors/index.js";import{RootMotionClip as j}from"../../gameplay/animation/root-motion.js";import{hashCameraShakeSeed as _}from"../../gameplay/services/camera-shake.js";import{buildShaderGraphPostProcessMaterial as L,shaderGraphPostProcessWeightUniformName as R}from"../../shader/graph/index.js";export var SequencePlaybackState;!function(e){e.Stopped="stopped",e.Playing="playing",e.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new e(SequencePlaybackState.Stopped),this._time=new e(0),this._duration=0,this._timescale=1,this._loop=!1,this._externalTimeControl=!1,this._inEditor=!1,this.bindings=new Map,this.roleBindings=new Map,this.sequenceData=null,this.onComplete=new t,this.onLoop=new t,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.viewController=null,this._cameraControlEnabled=!1,this._cameraControlTrackId=null,this.sequenceCameras=new Map,this.cameraPlayables=new Map,this.cameraBlendCamera=null,this.cameraBlendSource=null,this.cameraBlendOutSource=null,this.cameraOverrideHandle=null,this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null,this.activeCameraShakeClipKeys=new Set,this.nextCameraShakeClipKeys=new Set,this.activePostProcessClips=new Map,this.nextPostProcessClipKeys=new Set,this.audioListener=null,this.audioBuffers=new Map,this.loadingAudioBuffers=new Map,this.animationClips=new Map,this.loadingAnimationClips=new Map,this.retimedAnimationClips=new Map,this.audioByClip=new Map,this.activeAudioClips=new Set,this.audioGainNodes=new Map,this.audioStartInFlight=new Map,this.lastAudioStartAttemptTime=new Map,this.audioStartRetryIntervalSeconds=.25,this.world=null,this.assetLoader=null,this.actorFactory=null,this.vfxService=null,this.spawnedInstances=new Map,this.activeClips=new Set,this.pendingSpawns=new Set,this.vfxActors=new Map,this.activeVfxClips=new Set,this.locatorMarkers=new Map,this.clearCounter=0,this.propertyPathSegments=new Map,this.propertyResolutionCache=new Map,this.propertySnapshots=new Map,this.materialResolutionCache=new Map,this.materialSnapshots=new Map,this.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set,this.sequenceEventSyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e)},this.sequenceEventAsyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e),texture:e=>this.assetLoader?.getTextureByAssetId(e)??null,sampler2DNode:e=>this.assetLoader?.getTextureByAssetId(e)??null,object3D:async e=>{const t=await(this.assetLoader?.getModelByAssetId(e));return t?.scene??null},material:e=>this.assetLoader?.getMaterialByAssetId(e)??null,audioBuffer:e=>this.assetLoader?.getAudioByAssetId(e)??null,visualEffect:async e=>{if(!this.assetLoader||!this.actorFactory)return null;const t=await this.assetLoader.getAsset(e);return t?new u(this.actorFactory,t):null},prefab:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new f(t.asset):null},prefabActor:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new m(new f(t.asset)):null},sequence:e=>this.resolveSequenceEventSequence(e),animationClip:e=>this.resolveSequenceEventAnimationClip(e)},this.trackRuntimeEvaluators={object:(e,t,a)=>{t&&this.evaluateObjectTrack(e,t,a)},locator:(e,t,a)=>{t&&this.evaluateLocatorTrack(e,t,a)},camera:(e,t,a)=>this.evaluateCameraTrack(e,a),cameraShake:(e,t,a)=>this.evaluateCameraShakeTrack(e,a),postProcess:(e,t,a)=>this.evaluatePostProcessTrack(e,a),audio:(e,t,a)=>this.evaluateAudioTrack(e,a),vfx:(e,t,a)=>this.evaluateVfxTrack(e,a),spawn:(e,t,a)=>this.evaluateSpawnTrack(e,t,a),group:(e,t,a)=>{if("group"===e.type)for(const t of e.childTracks)this.evaluateTrack(t,a)}},this.subTrackRuntimeEvaluators={transform:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateTransformSubTrack(e,s,a)},animation:(e,t,a)=>this.evaluateAnimationSubTrack(e,t,a),visibility:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateVisibilitySubTrack(e,s,a)},parameter:(e,t,a)=>this.evaluateParameterSubTrack(e,t.target||null,a),event:(e,t,a)=>this.evaluateEventSubTrack(e,t.target||null,a)}}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(e){this._timescale=Math.max(.01,e)}get loop(){return this._loop}set loop(e){this._loop=e}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(e){this._externalTimeControl=e}get inEditor(){return this._inEditor}set inEditor(e){this._inEditor=e,this.updateLocatorMarkerVisibility()}get cameraControlEnabled(){return this._cameraControlEnabled}set cameraControlEnabled(e){this._cameraControlEnabled=e,e||this.releaseCameraOverride()}get cameraControlTrackId(){return this._cameraControlTrackId}set cameraControlTrackId(e){this._cameraControlTrackId!==e&&(this._cameraControlTrackId=e,this.releaseCameraOverride())}setViewController(e){this.viewController&&this.viewController!==e&&this.viewController.clearCameraShakeContributionsForOwner(this),this.viewController=e}setWorld(e){this.world!==e&&(this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.world=e,this.clearCounter++,this.vfxActors.clear(),this.spawnedInstances.clear(),this.bindings.clear(),this.activeClips.clear(),this.activeVfxClips.clear(),this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear(),this.loadingAudioBuffers.clear(),this.audioFilters.clear(),this.audioPannerNodes.clear(),this.pendingSpawns.clear(),this.propertyResolutionCache.clear(),this.materialResolutionCache.clear(),this.clearRetimedAnimationClipCache(),this._state.next(SequencePlaybackState.Stopped),this.sequenceData&&this.initializeLocatorBindings())}setAudioListener(e){this.audioListener=e}setAssetLoader(e){if(this.assetLoader=e,this.sequenceData){const e=this.clearCounter;this.preloadSequenceResources(this.sequenceData,e)}}setActorFactory(e){this.actorFactory=e}setVfxService(e){this.vfxService=e}load(e){if(this.stop(),this.clearCounter++,this.clearLocatorBindings(),this.clearSequenceCameras(),this.sequenceData=e,this._duration=e.duration,this._loop=e.loop,this._timescale=e.playbackRate,this.clearRetimedAnimationClipCache(),this.bindings.clear(),this.initializeLocatorBindings(),this.loopCount=0,this.assetLoader){const t=this.clearCounter;this.preloadSequenceResources(e,t)}}preloadSequenceResources(e,t){return Promise.all([this.preloadAudioBuffersForSequence(e,t),this.preloadAnimationClipsForSequence(e,t)]).then(()=>{})}getAudioAssetIdsForSequence(e){const t=new Set;for(const a of e.tracks){if("audio"!==a.type)continue;const e=a;for(const a of e.clips??[])a.audioAssetId&&t.add(a.audioAssetId)}return[...t]}async preloadAudioBuffersForSequence(e,t){if(!this.assetLoader)return;const a=this.getAudioAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{if(t!==this.clearCounter)return;if(this.audioBuffers.has(e))return;let a=this.loadingAudioBuffers.get(e);a||(a=this.assetLoader.getAudioByAssetId(e),this.loadingAudioBuffers.set(e,a));try{const s=await a;if(t!==this.clearCounter)return;this.audioBuffers.set(e,s)}catch(e){}finally{this.loadingAudioBuffers.get(e)===a&&this.loadingAudioBuffers.delete(e)}}))}getAnimationClipAssetIdsForSequence(e){const t=new Set;for(const a of H(e.tracks))if("subTracks"in a)for(const e of a.subTracks)if("animation"===e.type)for(const a of e.clips)a.animationClipAssetId&&t.add(a.animationClipAssetId);return[...t]}async preloadAnimationClipsForSequence(e,t){if(!this.assetLoader)return;const a=this.getAnimationClipAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{t===this.clearCounter&&await this.ensureAnimationClip(e)}))}bindRole(e,t){this.roleBindings.set(e,t),this.sequenceData&&this.resolveBindings()}bindObject(e,t){if(this.sequenceData)for(const a of this.sequenceData.tracks)"object"===a.type&&a.targetId===e&&this.createBinding(a,t)}getLocator(e){return this.getLocators(e)[0]??null}getLocators(e){const t=J(e);if(!t||!this.sequenceData)return[];const a=[];for(const e of H(this.sequenceData.tracks)){if("locator"!==e.type)continue;if(J(e.bindingId)!==t)continue;const s=this.bindings.get(e.id),r=s?this.getPlayableObject(s):null;r&&(r.updateWorldMatrix(!0,!1),a.push({trackId:e.id,name:e.name,bindingId:e.bindingId,position:r.getWorldPosition(new c),rotation:r.getWorldQuaternion(new o),scale:r.getWorldScale(new c)}))}return a}resolveBindings(){if(this.sequenceData)for(const e of this.sequenceData.tracks)this.resolveTrackBinding(e)}initializeLocatorBindings(){if(this.sequenceData)for(const e of H(this.sequenceData.tracks)){if("locator"!==e.type||this.bindings.has(e.id))continue;const t=new n;t.name=e.name||"Locator",t.userData.sequenceLocatorTrackId=e.id,this.world?.scene&&null==t.parent&&this.world.scene.add(t);const a=ee(e.name);a.visible=this._inEditor,t.add(a),this.locatorMarkers.set(e.id,a),this.disableLocatorInteraction(t),this.createBinding(e,t)}}clearLocatorBindings(){for(const e of this.locatorMarkers.values())te(e);for(const e of this.bindings.values()){if("locator"!==e.track.type)continue;const t=this.getPlayableObject(e);t?.parent&&t.removeFromParent()}this.locatorMarkers.clear()}updateLocatorMarkerVisibility(){for(const e of this.locatorMarkers.values())e.visible=this._inEditor}disableLocatorInteraction(e){e.traverse(e=>{e.raycast=()=>{}})}resolveTrackBinding(e){if("object"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("spawn"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("group"===e.type)for(const t of e.childTracks)this.resolveTrackBinding(t)}createBinding(e,t){const a=t instanceof p?t.object:t,r=this.bindings.get(e.id),i=null!=r?r.target instanceof p?r.target.object:r.target:null,n=null!=r&&r.target===t&&i===a,o=e.subTracks.some(e=>"animation"===e.type);if(null!=r&&!n){for(const e of r.activeActions.values())e.stop();r.activeActions.clear(),r.mixer?.stopAllAction(),r.charAnimComponent?.stopSequenceAnimation(),r.charAnimComponent=void 0,r.charAnimActionKeys?.clear()}const l=n?r:{track:e,target:t,activeActions:new Map};l.track=e,l.target=t,l.originalTransform={position:a.position.clone(),rotation:a.rotation.clone(),scale:a.scale.clone()},l.originalParent=a.parent,o&&null==l.mixer?l.mixer=new s(a):o||(l.mixer=void 0),this.bindings.set(e.id,l)}play(){this._state.value!==SequencePlaybackState.Playing&&this.sequenceData&&(this._state.value===SequencePlaybackState.Stopped&&(this._time.next(0),this.loopCount=0,this.resolveBindings(),this.captureOriginalTransforms()),this._state.next(SequencePlaybackState.Playing),this.evaluate(this._time.value),this.resumeVfx())}pause(){this._state.value===SequencePlaybackState.Playing&&(this._state.next(SequencePlaybackState.Paused),this.pauseAudio(),this.pauseVfx())}pauseAudio(){for(const e of this.audioByClip.values())e.pause()}pauseVfx(){for(const e of this.vfxActors.values())e.pause()}resumeVfx(){for(const[e,t]of this.vfxActors.entries())(this.activeVfxClips.has(e)||t.getParticleCount()>0)&&t.play()}cancel(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}restart(){this.stop(),this.play()}seek(e){const t=Math.max(0,Math.min(e,this._duration));t<this._time.value&&this.resetVfxForTimeReset(t),this._time.next(t),this.evaluate(t)}update(e){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale);return}const t=this._time.value+e*this._timescale;if(t>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this.releaseCameraOverride(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();{this.loopCount++;const e=t%this._duration;this.resetVfxForTimeReset(e),this._time.next(e),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}}else this._time.next(t);this.evaluate(this._time.value);for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale)}evaluate(e){if(this.sequenceData){this.nextCameraShakeClipKeys.clear(),this.nextPostProcessClipKeys.clear();for(const t of this.sequenceData.tracks){if(!t.muted&&("object"===t.type||"locator"===t.type||"camera"===t.type||"spawn"===t.type||"vfx"===t.type)){const e=this.bindings.get(t.id);this.updateTrackParenting(t,e)}this.evaluateTrack(t,e)}this.updateCameraControl(e),this.syncCameraShakeContributions(),this.syncPostProcessEffects()}}evaluateTrack(e,t){if(e.muted)return;const a=this.bindings.get(e.id);(0,this.trackRuntimeEvaluators[b(e.type).runtimeEvaluator])(e,a,t)}evaluateObjectTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}evaluateLocatorTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}getActiveTrackObjects(e){if(!this.sequenceData)return[];const t=H(this.sequenceData.tracks).find(t=>t.id===e);return t?this.getActiveObjectsForTrack(t):[]}evaluateSubTracks(e,t,a){for(const s of e){if(s.muted)continue;(0,this.subTrackRuntimeEvaluators[P(s.type).runtimeEvaluator])(s,t,a)}}evaluateTransformSubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;const{prev:r,next:i,t:n}=I(s,a);if(r)if(i&&r!==i){const a=k(n,r.interpolation);e.components.position&&r.position&&i.position&&t.position.lerpVectors(ae.fromArray(r.position),se.fromArray(i.position),a),e.components.rotation&&r.rotation&&i.rotation&&(ie.setFromEuler(oe.fromArray([...r.rotation,"XYZ"])),ne.setFromEuler(le.fromArray([...i.rotation,"XYZ"])),t.quaternion.slerpQuaternions(ie,ne,a)),e.components.scale&&r.scale&&i.scale&&t.scale.lerpVectors(ae.fromArray(r.scale),se.fromArray(i.scale),a)}else e.components.position&&r.position&&t.position.fromArray(r.position),e.components.rotation&&r.rotation&&t.rotation.fromArray([...r.rotation,"XYZ"]),e.components.scale&&r.scale&&t.scale.fromArray(r.scale)}evaluateAnimationSubTrack(e,t,s){if(!t.mixer||!t.activeActions)return;if(t.target instanceof p?t.target.object:t.target)for(const r of e.clips){const i=r.startTime+r.duration,n=s>=r.startTime&&s<i,o=`${e.id}-${r.id}`;let l=t.activeActions.get(o),c=!1;if(n){if(!l){c=!0;const e=r.animationClipAssetId;if(null==e)continue;const s=this.animationClips.get(e);if(null==s){this.ensureAnimationClip(e);continue}const i=this.prepareAnimationPlayback(e,s,r),n=t;let h=!1;if(t.target instanceof p){n.charAnimComponent||(n.charAnimComponent=t.target.getComponent(F)??void 0);const a=n.charAnimComponent;if(null!=a){const c=r.rootMotion?B(r)?this.getPlayableAnimationClip(e,s,r,!0):j.fromClip(i.clip,!1):i.clip;if(this._externalTimeControl)l=a.beginExternalAnimationControl(c,{timeScale:i.timeScale});else if(a.play(c,{inPlace:!r.rootMotion,loop:!1,priority:20,timeScale:i.timeScale,fadeTime:r.fadeInDuration??.2,offset:i.startOffset}),l=a.getFullBodyAction(),r.rootMotion){const e=t.target.getComponent(E);e&&e.setRootMotionAction(l,{cancelWithJump:e.allowRootMotionJumpCancel,onJumpCancel:()=>this.cancel()})}t.activeActions.set(o,l),n.charAnimActionKeys||(n.charAnimActionKeys=new Set),n.charAnimActionKeys.add(o),h=!0}}h||(l=t.mixer.clipAction(i.clip),l.setLoop(a.LoopOnce,1),l.clampWhenFinished=!0,l.timeScale=i.timeScale,i.startOffset>0&&(l.time=i.startOffset),t.activeActions.set(o,l),l.play())}if(l){const e=t;if(this._externalTimeControl){e.charAnimComponent?.beginExternalControl();const a=this.getAnimationPlaybackLocalTime(r,s),i=Math.min(a,l.getClip().duration);(c||Math.abs(l.time-i)>.001)&&(l.time=i,l.paused=!1,l.play(),e.charAnimComponent?e.charAnimComponent.getMixer()?.update(0):t.mixer&&t.mixer.update(0))}else e.charAnimComponent?.endExternalControl()}}else if(l){t.activeActions.delete(o);const e=t;e.charAnimActionKeys?.has(o)?(e.charAnimActionKeys.delete(o),l.stop(),0===e.charAnimActionKeys.size&&e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0)):(l.stop(),this._externalTimeControl&&t.mixer&&t.mixer.update(0))}}}evaluateVisibilitySubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;let r=s[0];for(const e of s){if(!(e.time<=a))break;r=e}t.visible=r.visible}evaluatePropertySubTrack(e,t,a){const s=x(e.keyframes,a,{min:e.range?.[0],max:e.range?.[1],stepOnly:V(e)});s&&this.applyResolvedPropertyValue(e,t,s)}evaluateParameterSubTrack(e,t,a){if("audioParameter"===e.type)return;const s=x(e.keyframes,a,"property"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:V(e)}:"material"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:D(e)}:{});s&&("property"!==e.type?this.applyResolvedMaterialValue(e,t,s):this.applyResolvedPropertyValue(e,t,s))}evaluateEventSubTrack(e,t,a){if(t instanceof p&&this._state.value===SequencePlaybackState.Playing)for(const s of e.events){const r=`${e.id}-${s.id}`;if(a>=s.time&&!this.firedEvents.has(r)){if(this.firedEvents.add(r),s.editorOnly&&!this._inEditor)continue;if(!s.functionName)continue;const e=t[s.functionName];"function"==typeof e?this.invokeSequenceEvent(t,s.functionName,e,s.arguments??[]):console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>a&&this.firedEvents.delete(r)}}evaluateCameraTrack(e,t){const a=this.ensureSequenceCamera(e);this.applyCameraTrackSettings(e,a),this.evaluateSubTracks(e.subTracks,this.getCameraPlayable(e,a),t),a.updateProjectionMatrix()}evaluateCameraShakeTrack(e,t){if(this.viewController)for(const a of e.clips??[]){if(!this.isCameraShakeClipActive(a,t))continue;const e=t-a.startTime,s=a.id;this.nextCameraShakeClipKeys.add(s),this.viewController.setCameraShakeContribution(this,s,a,e,a.seed??_(a.id))}}evaluatePostProcessTrack(e,t){if(this.viewController&&this.assetLoader){for(const a of e.clips??[]){if(!this.isPostProcessClipActive(a,t))continue;const s=this.getPostProcessClipKey(e,a);this.nextPostProcessClipKeys.add(s),this.ensurePostProcessClipEffect(e,a,s);const r=this.activePostProcessClips.get(s);r?.handle&&(r.handle.stage=e.stage,r.handle.priority=e.priority,r.handle.enabled=!0,this.applyPostProcessClipWeight(r.handle,a,t))}this.evaluatePostProcessMaterialSubTracks(e,t)}}evaluatePostProcessMaterialSubTracks(e,t){for(const a of e.subTracks){if(a.muted||"material"!==a.type)continue;const s=x(a.keyframes,t,{min:a.range?.[0],max:a.range?.[1],stepOnly:D(a)});s&&this.applyPostProcessMaterialValue(e.id,a,s)}}applyPostProcessMaterialValue(e,t,a){if(t.uniformName)for(const s of this.activePostProcessClips.values()){if(s.trackId!==e||!s.handle)continue;const r=s.handle.material,i=r.uniforms?.[t.uniformName];if(!i)continue;const n=G(i.value,a);n.applied&&(i.value=n.value,r.uniformsNeedUpdate=!0)}}isPostProcessClipActive(e,t){return t>=e.startTime&&t<e.startTime+e.duration}getPostProcessClipKey(e,t){return`${e.id}-${t.id}`}ensurePostProcessClipEffect(e,t,a){const s=t.shaderGraphAssetId;if(!s)return void this.releasePostProcessClipEffect(a);const r=JSON.stringify(t.shaderGraphParams??{}),i=this.activePostProcessClips.get(a);if(i?.assetId===s&&i.paramsSignature===r)return;this.releasePostProcessClipEffect(a);const n={key:a,trackId:e.id,clipId:t.id,assetId:s,paramsSignature:r,version:this.clearCounter};this.activePostProcessClips.set(a,n),this.loadPostProcessClipEffect(e,t,n)}async loadPostProcessClipEffect(e,t,a){if(this.assetLoader&&this.viewController)try{const s=await this.assetLoader.getShaderGraphByAssetId(a.assetId);if(!this.isPostProcessClipEntryCurrent(a))return;if("postProcess"!==s.target)return console.warn(`Sequence post-process clip references shader graph "${a.assetId}" with target "${s.target}"`),void this.releasePostProcessClipEffect(a.key);const r=await this.assetLoader.prepareShaderGraphParameters(s,t.shaderGraphParams??{});if(!this.isPostProcessClipEntryCurrent(a))return;const i=L(s,{parameters:r});if(!this.isPostProcessClipEntryCurrent(a))return void i.dispose();a.handle=this.viewController.addPostProcessEffect(i,{stage:e.stage,priority:e.priority,enabled:!0}),this.applyPostProcessClipWeight(a.handle,t,this._time.value)}catch(e){this.isPostProcessClipEntryCurrent(a)&&this.releasePostProcessClipEffect(a.key),console.error(`Failed to create post-process effect for clip ${t.id}:`,e)}}isPostProcessClipEntryCurrent(e){return this.clearCounter===e.version&&this.activePostProcessClips.get(e.key)===e}applyPostProcessClipWeight(e,t,a){const s=e.material.uniforms?.[R];null!=s&&(s.value=this.getPostProcessClipWeight(t,a),e.material.uniformsNeedUpdate=!0)}getPostProcessClipWeight(e,t){const a=Math.max(0,t-e.startTime),s=Math.max(0,e.startTime+e.duration-t);let r=1;const i=Math.max(0,e.fadeInDuration??0);i>0&&(r=Math.min(r,a/i));const n=Math.max(0,e.fadeOutDuration??0);return n>0&&(r=Math.min(r,s/n)),Math.max(0,Math.min(1,r))}syncPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.nextPostProcessClipKeys.has(e)||this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}clearPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}releasePostProcessClipEffect(e){const t=this.activePostProcessClips.get(e);if(t&&(this.activePostProcessClips.delete(e),t.handle)){const e=t.handle.material;t.handle.dispose(),e.dispose()}}getCameraPlayable(e,t){let a=this.cameraPlayables.get(e.id);return a?a.target=t:(a={target:t},this.cameraPlayables.set(e.id,a)),a}ensureSequenceCamera(e){let t=this.sequenceCameras.get(e.id);if(t)null==t.parent&&this.world?.scene.add(t);else{const s=e.cameraSettings??{fov:60,near:.1,far:1e3};t=new a.PerspectiveCamera(s.fov??60,this.getCurrentCameraAspect(),s.near??.1,s.far??1e3),t.name=e.name||"Sequence Camera",t.userData.sequenceCameraTrackId=e.id,t.layers.mask=this.viewController?.getBaseCamera().layers.mask??t.layers.mask,this.sequenceCameras.set(e.id,t),this.world?.scene.add(t)}return t}clearSequenceCameras(){this.releaseCameraOverride();for(const e of this.sequenceCameras.values())e.removeFromParent();this.sequenceCameras.clear(),this.cameraPlayables.clear()}applyCameraTrackSettings(e,t){const a=e.cameraSettings??{fov:60,near:.1,far:1e3};t.fov=a.fov??60,t.near=a.near??.1,t.far=a.far??1e3,t.aspect=this.getCurrentCameraAspect()}getCurrentCameraAspect(){const e=this.viewController?.getBaseCamera();if(e instanceof a.PerspectiveCamera&&Number.isFinite(e.aspect)&&e.aspect>0)return e.aspect;const t=this.viewController?.getSourceCamera();return t instanceof a.PerspectiveCamera&&Number.isFinite(t.aspect)&&t.aspect>0?t.aspect:1}updateCameraControl(e){if(!this._cameraControlEnabled||!this.viewController||!this.sequenceData)return void this.releaseCameraOverride();const t=this.findActiveCameraShot(e);if(t)return void this.updateActiveCameraShot(t,e);const a=this.findBlendOutCameraShot(e);a?this.updateCameraBlendOut(a,e):this.releaseCameraOverride()}findActiveCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of H(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const r of s)this.isCameraClipActive(r,e)&&(t={track:a,clip:r,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,r)})}return t}findBlendOutCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of H(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const r of s){const s=Math.max(0,r.blendOutDuration??0);if(s<=0)continue;const i=this.getCameraClipEnd(r);e>=i&&e<i+s&&(t={track:a,clip:r,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,r)})}}return t}isCameraControlTrackEligible(e){return null==this._cameraControlTrackId||e.id===this._cameraControlTrackId}updateActiveCameraShot(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();this.activeCameraClipKey!==e.key&&(this.copyCameraState(this.viewController.getSourceCamera(),this.ensureCameraBlendSource()),this.activeCameraClipKey=e.key,this.cameraBlendOutClipKey=null);const s=Math.max(0,e.clip.blendInDuration??0),r=s<=0?1:this.evaluateCameraBlendAlpha((t-e.clip.startTime)/s,e.clip);r>=1?this.copyCameraState(e.camera,a):this.blendCameraState(this.ensureCameraBlendSource(),e.camera,a,r),a.updateProjectionMatrix(),this.ensureCameraOverride()}updateCameraBlendOut(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();if(this.cameraBlendOutClipKey!==e.key){const t=this.activeCameraClipKey===e.key?this.viewController.getSourceCamera():e.camera;this.copyCameraState(t,this.ensureCameraBlendOutSource()),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=e.key}const s=this.getCameraClipEnd(e.clip),r=Math.max(0,e.clip.blendOutDuration??0),i=r<=0?1:this.evaluateCameraBlendAlpha((t-s)/r,e.clip);this.blendCameraState(this.ensureCameraBlendOutSource(),this.viewController.getBaseCamera(),a,i),a.updateProjectionMatrix(),this.ensureCameraOverride()}ensureCameraBlendCamera(){return this.cameraBlendCamera||(this.cameraBlendCamera=new a.PerspectiveCamera(60,this.getCurrentCameraAspect(),.1,1e3),this.cameraBlendCamera.name="Sequence Camera Blend"),this.cameraBlendCamera}ensureCameraBlendSource(){return this.cameraBlendSource||(this.cameraBlendSource=new a.PerspectiveCamera),this.cameraBlendSource}ensureCameraBlendOutSource(){return this.cameraBlendOutSource||(this.cameraBlendOutSource=new a.PerspectiveCamera),this.cameraBlendOutSource}ensureCameraOverride(){this.viewController&&!this.cameraOverrideHandle&&(this.cameraOverrideHandle=this.viewController.pushCameraOverride(this.ensureCameraBlendCamera(),this))}releaseCameraOverride(){this.cameraOverrideHandle?.release(),this.cameraOverrideHandle=null,this.viewController?.releaseCameraOverridesForOwner(this),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null}isCameraClipActive(e,t){return t>=e.startTime&&t<this.getCameraClipEnd(e)}getCameraClipEnd(e){return e.startTime+Math.max(0,e.duration)}isCameraShakeClipActive(e,t){return t>=e.startTime&&t<this.getCameraShakeClipEnd(e)}getCameraShakeClipEnd(e){return e.startTime+Math.max(0,e.duration)}getCameraClipKey(e,t){return`${e.id}-${t.id}`}evaluateCameraBlendAlpha(e,t){return k(Math.max(0,Math.min(1,e)),t.blendInterpolation??"cubic")}syncCameraShakeContributions(){if(!this.viewController)return this.activeCameraShakeClipKeys.clear(),void this.nextCameraShakeClipKeys.clear();for(const e of this.activeCameraShakeClipKeys)this.nextCameraShakeClipKeys.has(e)||this.viewController.removeCameraShakeContribution(this,e);this.activeCameraShakeClipKeys.clear();for(const e of this.nextCameraShakeClipKeys)this.activeCameraShakeClipKeys.add(e);this.nextCameraShakeClipKeys.clear()}clearCameraShakeContributions(){this.activeCameraShakeClipKeys.clear(),this.nextCameraShakeClipKeys.clear(),this.viewController?.clearCameraShakeContributionsForOwner(this)}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(ae)),t.quaternion.copy(e.getWorldQuaternion(ie)),t.scale.copy(e.getWorldScale(se)),e instanceof a.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect):t.aspect=this.getCurrentCameraAspect(),t.layers.mask=e.layers.mask}blendCameraState(e,t,s,r){e.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!1),s.position.lerpVectors(e.getWorldPosition(ae),t.getWorldPosition(se),r),s.quaternion.slerpQuaternions(e.getWorldQuaternion(ie),t.getWorldQuaternion(ne),r),s.scale.lerpVectors(e.getWorldScale(ae),t.getWorldScale(se),r),e instanceof a.PerspectiveCamera&&t instanceof a.PerspectiveCamera?(s.fov=e.fov+(t.fov-e.fov)*r,s.near=e.near+(t.near-e.near)*r,s.far=e.far+(t.far-e.far)*r,s.aspect=t.aspect):t instanceof a.PerspectiveCamera?(s.fov=t.fov,s.near=t.near,s.far=t.far,s.aspect=t.aspect):s.aspect=this.getCurrentCameraAspect(),s.layers.mask=t.layers.mask}evaluateAudioTrack(e,t){if(!this.assetLoader||!e.clips||0===e.clips.length)return;const a=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(e,t);e.volume;for(const r of e.clips){const i=r.startTime+r.duration,n=t>=r.startTime&&t<i,o=`${e.id}-${r.id}`;if(n){if(this.activeAudioClips.has(o)||this.activeAudioClips.add(o),a){const a=this.audioByClip.get(o);a&&a.isPlaying||this.tryStartAudioClip(e,r,o,t,s)}const i=this.audioByClip.get(o);i&&this.applyAudioParameters(i,e,r,o,t,s)}else this.activeAudioClips.has(o)&&(this.activeAudioClips.delete(o),this.lastAudioStartAttemptTime.delete(o),this.audioStartInFlight.delete(o),this.stopAudioClip(o))}}tryStartAudioClip(e,t,a,s,r){if(this.audioStartInFlight.has(a))return;const i=this.lastAudioStartAttemptTime.get(a);if(void 0!==i&&s-i<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(a,s);const n=this.playAudioClip(e,t,a,s,r).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(a)===n&&this.audioStartInFlight.delete(a)});this.audioStartInFlight.set(a,n)}applyAudioParameters(e,t,s,r,i,n){const o=n.volume??1,l=this.stringToRandom(r+t.id),c=s.volumeRandomization?(2*l-1)*s.volumeRandomization:0;let h=1;const u=i-s.startTime;u<s.fadeInDuration&&s.fadeInDuration>0?h=u/s.fadeInDuration:u>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(h=(s.duration-u)/s.fadeOutDuration);const p=Math.max(0,(t.volume??1)*o*(s.volume+c)*h);e.setVolume(p);let d=n.detune??0;if(s.pitchRandomization){d+=(2*this.stringToRandom(r+"_pitch")-1)*s.pitchRandomization}if(e.setDetune(d),e.hasPlaybackControl&&e.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,i=[],o=n.lowpass,l=n.highpass;let c=this.audioFilters.get(r);if(void 0!==o||void 0!==l)c||(c=s.createBiquadFilter(),this.audioFilters.set(r,c)),void 0!==o?(c.type="lowpass",c.frequency.value=o):void 0!==l&&(c.type="highpass",c.frequency.value=l),i.push(c);else if(c){try{c.disconnect()}catch{}this.audioFilters.delete(r)}const h=n.pan;if(!t.spatial&&e instanceof a.Audio&&void 0!==h&&"function"==typeof s.createStereoPanner){let e=this.audioPannerNodes.get(r);e||(e=s.createStereoPanner(),this.audioPannerNodes.set(r,e)),e.pan.value=h,i.push(e)}else{const e=this.audioPannerNodes.get(r);if(e){try{e.disconnect()}catch{}this.audioPannerNodes.delete(r)}}e.setFilters(i)}t.spatial&&e instanceof a.PositionalAudio?this.updatePositionalAudioTransform(e,t,s,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(e,t,s,r){let i=null,n=null;const o=s.attachedToTrackId||t.parent?.trackId,l=s.attachmentSocketName||t.parent?.socketName;if(o){const e=this.sequenceData?.tracks.find(e=>e.id===o);if(e){const t=this.getActiveObjectsForTrack(e);if(t.length>0){const e=t[0];if(i=ae,n=ie,e.getWorldPosition(i),e.getWorldQuaternion(n),l){const t=this.findSocket(e,l);t&&(t.getWorldPosition(i),t.getWorldQuaternion(n))}}}}if(i&&n){const t="number"==typeof r?a.MathUtils.clamp(r,0,1):1;if(t<1&&this.audioListener){const e=re;this.audioListener.getWorldPosition(e),i=i.clone().lerp(e,1-t)}e.position.copy(i),e.quaternion.copy(n),e.updateMatrixWorld()}}async playAudioClip(e,t,s,r,i){if(!this.assetLoader||!t.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(e){return void console.warn("Failed to resume audio context:",e)}this.stopAudioClip(s);const n=this.clearCounter;try{let r=this.audioBuffers.get(t.audioAssetId);if(!r){let e=this.loadingAudioBuffers.get(t.audioAssetId);e||(e=this.assetLoader.getAudioByAssetId(t.audioAssetId),this.loadingAudioBuffers.set(t.audioAssetId,e));try{r=await e,this.audioBuffers.set(t.audioAssetId,r)}finally{this.loadingAudioBuffers.delete(t.audioAssetId)}}if(n!==this.clearCounter)return;const o=this._time.value,l=t.startTime+t.duration;if(!(o>=t.startTime&&o<l))return;const c=Math.max(0,o-t.startTime),h=t.clipStartOffset+c*t.playbackRate;if(h>=r.duration||c>=t.duration)return;let u=this.audioByClip.get(s);const p=!0===e.spatial,d=u&&!0===u.isPositionalAudio;if(u&&p!==d&&(u.isPlaying&&u.stop(),u.disconnect(),this.audioByClip.delete(s),u=void 0),!u){if(p){const e=new a.PositionalAudio(this.audioListener);e.setRefDistance(10),e.setRolloffFactor(1),u=e}else u=new a.Audio(this.audioListener);this.world&&this.world.scene.add(u),this.audioByClip.set(s,u)}Math.min((t.duration-c)/t.playbackRate,(r.duration-h)/t.playbackRate);u.setLoopStart(t.clipStartOffset),u.setLoopEnd(Math.min(t.clipStartOffset+t.duration,r.duration)),u.setLoop(!0),u.setBuffer(r),this.applyAudioParameters(u,e,t,s,o,i),u.isPlaying||u.play()}catch(e){console.error(`Failed to play audio clip ${t.id}:`,e)}}stopAudioClip(e){const t=this.audioByClip.get(e);if(t){try{t.isPlaying&&t.stop()}catch(e){}t.parent&&t.parent.remove(t),this.audioByClip.delete(e)}const a=this.audioGainNodes.get(e);a&&(a.disconnect(),this.audioGainNodes.delete(e));const s=this.audioFilters.get(e);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(e)}const r=this.audioPannerNodes.get(e);if(r){try{r.disconnect()}catch{}this.audioPannerNodes.delete(e)}}stopAllAudio(){for(const e of this.audioByClip.keys())this.stopAudioClip(e);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(e,t){if(!this.vfxService||!this.world||!e.clips||0===e.clips.length)return;const a=new Set,s=new Map;for(const r of e.clips){const i=this.getVfxClipKey(e,r);s.set(i,r),this.isVfxClipActiveAtTime(r,t)&&a.add(i)}const r=[];for(const t of this.activeVfxClips)t.startsWith(`${e.id}-`)&&(a.has(t)||r.push(t));for(const e of r)this.activeVfxClips.delete(e);for(const[r,i]of s.entries()){const s=this.vfxActors.get(r);a.has(r)&&!this.activeVfxClips.has(r)?(this.activeVfxClips.add(r),this.ensureVfxActor(e,i,r)):a.has(r)&&s?(this.updateVfxTransform(e,s,t),this._state.value===SequencePlaybackState.Playing&&s.play()):s&&this.applyInactiveVfxClipBehavior(i,s,t)}}getVfxClipKey(e,t){return`${e.id}-${t.id}-${t.vfxAssetId}`}isVfxClipActiveAtTime(e,t){const a=e.startTime+e.duration;return t>=e.startTime&&t<a}resetVfxForTimeReset(e){const t=new Set;if(this.sequenceData)for(const a of H(this.sequenceData.tracks))if("vfx"===a.type)for(const s of a.clips??[])this.isVfxClipActiveAtTime(s,e)&&t.add(this.getVfxClipKey(a,s));this.activeVfxClips.clear();for(const[e,a]of this.vfxActors.entries())t.has(e)||(a.restart(),a.stop(),a.pause())}applyInactiveVfxClipBehavior(e,t,a){const s=e.endBehavior??"finish";if("finish"===s)return void t.stop();if("kill"===s)return void t.applyClipEndBehavior(s);const r=e.startTime+e.duration,i=Math.max(a-r,0),n=Math.max(0,e.expireWithinSeconds??.25),o=Math.max(0,n-i);t.applyClipEndBehavior(s,o)}async ensureVfxActor(e,t,a){if(!this.vfxService||!t.vfxAssetId)return;if(this.vfxActors.has(a)){const e=this.vfxActors.get(a);return e.restart(),void e.play()}const s=this.clearCounter;try{const r=await this.vfxService.createFromAssetId(t.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(r));const{position:i,rotation:n,scale:o}=this.getVfxTransform(e,t.startTime);r.object.position.copy(i),r.object.rotation.copy(n),r.object.scale.copy(o),this.vfxActors.set(a,r),this._state.value===SequencePlaybackState.Playing&&r.play()}catch(e){console.error(`Failed to create VFX actor for clip ${t.id}:`,e)}}getVfxTransform(e,t){const a=new c,s=new i,r=new c(1,1,1),n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,next:i,t:l}=I(n.keyframes,t);if(e&&(e.position&&a.fromArray(e.position),e.rotation&&s.fromArray([...e.rotation,"XYZ"]),e.scale&&r.fromArray(e.scale)),i&&e!==i&&e.time!==i.time){const t=k(l,e.interpolation);if(e.position&&i.position&&a.lerpVectors(ae.fromArray(e.position),se.fromArray(i.position),t),e.rotation&&i.rotation){ie.setFromEuler(oe.fromArray([...e.rotation,"XYZ"])),ne.setFromEuler(le.fromArray([...i.rotation,"XYZ"]));const a=new o;a.slerpQuaternions(ie,ne,t),s.setFromQuaternion(a)}e.scale&&i.scale&&r.lerpVectors(ae.fromArray(e.scale),se.fromArray(i.scale),t)}}else a.fromArray(e.position),s.fromArray([...e.rotation,"XYZ"]),r.fromArray(e.scale);return{position:a,rotation:s,scale:r}}updateVfxTransform(e,t,a){const{position:s,rotation:r,scale:i}=this.getVfxTransform(e,a);t.object.position.copy(s),t.object.rotation.copy(r),t.object.scale.copy(i)}resolveActorType(e){const t=this.actorFactory.classes[e];if(null!=t)return t;const a=d[e];return a||(console.warn(`Could not resolve actor type: ${e}`),null)}async spawnActorForClip(e,t,a,s){if(!this.world||!e.actorType)return null;const r=this.resolveActorType(e.actorType);if(!r)return null;try{return await this.world.spawnActor(r,a,s)}catch(t){return console.error(`Failed to spawn actor ${e.actorType}:`,t),null}}async spawnPrefabForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.prefabId)return null;try{const t=await this.assetLoader.getPrefabById(e.prefabId);if(!t)return null;return await this.world.spawnPrefab(t,a,s)}catch(t){return console.error(`Failed to spawn prefab ${e.prefabId}:`,t),null}}async spawnMeshForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.meshId)return null;try{const t=await this.assetLoader.getAsset(e.meshId),r=await this.assetLoader.getModelByAssetId(e.meshId),i=O.clone(r.scene);if(i.position.copy(a),i.rotation.copy(s),t){await this.assetLoader.applyMaterials(t,i);const e=t.mesh?.rescale;null!=e&&1!==e&&i.scale.multiplyScalar(e)}return this.world.scene.add(i),i}catch(t){return console.error(`Failed to spawn mesh ${e.meshId}:`,t),null}}despawnInstance(e){if(this.restorePropertySnapshotsForInstance(e),this.restoreMaterialSnapshotsForInstance(e),this.world)switch(e?.type){case"actor":this.world.removeActor(e.instance);break;case"prefab":this.world.removePrefab(e.instance);break;case"mesh":this.world.scene.remove(e.instance)}}despawnAll(){for(const e of this.spawnedInstances.values())this.despawnInstance(e);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(e,t,a){const s=new c,r=new i,n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e}=I(n.keyframes,a);e&&(e.position&&s.fromArray(e.position),e.rotation&&r.fromArray([...e.rotation,"XYZ"]))}else t.initialPosition&&s.fromArray(t.initialPosition),t.initialRotation&&r.fromArray([...t.initialRotation,"XYZ"]);return{position:s,rotation:r}}evaluateSpawnTrack(e,t,a){if(!e.clips||0===e.clips.length)return;const s=t||this.bindings.get(e.id);if(s&&s.target)for(const t of e.clips){const r=t.startTime+t.duration,i=a>=t.startTime&&a<r,n=`${e.id}-${t.id}`;if(i){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:s.target}));(s.target instanceof p?s.target.object:s.target)&&this.evaluateSubTracks(e.subTracks,s,a)}else this.activeClips.has(n)&&(this.restorePropertySnapshotsForTarget(s.target),this.restoreMaterialSnapshotsForTarget(s.target),this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const t of e.clips){const s=t.startTime+t.duration,r=a>=t.startTime&&a<s,i=`${e.id}-${t.id}`,n=this.spawnedInstances.has(i),o=this.pendingSpawns.has(i);if(!r||n||o){if(r&&n){const t=this.spawnedInstances.get(i);t&&"proxy"!==t.type&&this.evaluateSubTracks(e.subTracks,t,a)}else if(!r&&n){const e=this.spawnedInstances.get(i);e&&(this.despawnInstance(e),this.spawnedInstances.delete(i),this.activeClips.delete(i))}}else{const{position:a,rotation:s}=this.getInitialTransform(e,t,t.startTime);this.pendingSpawns.add(i),this.spawnForClip(e,t,a,s,i)}}}getInstanceObject(e){switch(e.type){case"actor":return e.instance.object;case"prefab":return e.instance.mainActor?.object||e.instance.object;case"mesh":return e.instance;case"proxy":return e.target instanceof p?e.target.object:e.target;default:return null}}async spawnForClip(e,t,a,r,i){const n=this.clearCounter;let o=null;try{switch(e.spawnType){case"actor":const s=await this.spawnActorForClip(e,t,a,r);s&&(o={type:"actor",instance:s});break;case"prefab":const i=await this.spawnPrefabForClip(e,t,a,r);i&&(o={type:"prefab",instance:i});break;case"mesh":const n=await this.spawnMeshForClip(e,t,a,r);n&&(o={type:"mesh",instance:n})}if(n!==this.clearCounter)return void(o&&this.despawnInstance(o));const l=this._time.value,c=l>=t.startTime&&l<t.startTime+t.duration;if(o&&c){const t=this.getInstanceObject(o);"proxy"===o.type||("actor"===o.type?o.target=o.instance:"prefab"===o.type?o.target=o.instance.mainActor||o.instance.object:o.target=t);e.subTracks.some(e=>"animation"===e.type)&&t&&(o.mixer=new s(t),o.activeActions=new Map),this.spawnedInstances.set(i,o),this.activeClips.add(i)}else o&&this.despawnInstance(o)}finally{this.pendingSpawns.delete(i)}}getPlayableObject(e){return e.target instanceof p?e.target.object:e.target??null}applyResolvedPropertyValue(e,t,a){if(!t||!e.propertyPath)return;const s=this.getPropertyResolution(t,e);if(!s)return;const r=this.getPropertySnapshotKey(e);this.capturePropertySnapshot(t,r,s);const n=function(e,t){switch(t.type){case y.Number:return"number"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.String:return"string"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return N(e,t.value);case y.Vector3:return U(e,t.value);case y.Vector4:return W(e,t.value);case y.Euler:return function(e,t){const a=Q(t,3);if(!a)return{applied:!1};const s=Array.isArray(t)&&"string"==typeof t[3]?t[3]:"XYZ";if(e instanceof i)return e.set(a[0],a[1],a[2],s),{applied:!0,value:e};return{applied:!0,value:new i(a[0],a[1],a[2],s)}}(e,t.value);case y.Color:return X(e,t.value);default:return{applied:!1}}}(s.owner[s.key],a);n.applied&&(s.owner[s.key]=n.value)}getPropertyResolution(e,t){const a=e,s=this.getPropertySnapshotKey(t);let r=this.propertyResolutionCache.get(a);if(r||(r=new Map,this.propertyResolutionCache.set(a,r)),r.has(s))return r.get(s)??null;const i=this.getPropertyPathSegments(t.propertyPath);if(0===i.length)return r.set(s,null),null;let n=e;for(let e=0;e<i.length-1;e++){if(!K(n))return r.set(s,null),null;n=n[i[e]]}if(!K(n))return r.set(s,null),null;const o={owner:n,key:i[i.length-1]};return r.set(s,o),o}getPropertyPathSegments(e){const t=this.propertyPathSegments.get(e);if(t)return t;const a=e.split(".").map(e=>e.trim()).filter(Boolean);return this.propertyPathSegments.set(e,a),a}getPropertySnapshotKey(e){return`${e.id}:${e.propertyPath}`}capturePropertySnapshot(e,t,a){const s=e;let r=this.propertySnapshots.get(s);if(r||(r=new Map,this.propertySnapshots.set(s,r)),r.has(t))return;const i=a.owner[a.key];r.set(t,{resolution:a,hadOwnProperty:Object.prototype.hasOwnProperty.call(a.owner,a.key),value:i,valueSnapshot:Z(i)})}restorePropertySnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restorePropertySnapshotsForTarget(e.instance);break;case"prefab":this.restorePropertySnapshotsForTarget(e.target??null),this.restorePropertySnapshotsForTarget(e.instance.mainActor??null),this.restorePropertySnapshotsForTarget(e.instance.object);break;case"proxy":this.restorePropertySnapshotsForTarget(e.target)}}restorePropertySnapshotsForTarget(e){if(!e)return;const t=e,a=this.propertySnapshots.get(t);if(a){for(const e of a.values())z(e);this.propertySnapshots.delete(t),this.propertyResolutionCache.delete(t)}}restoreAllPropertySnapshots(){for(const e of Array.from(this.propertySnapshots.keys()))this.restorePropertySnapshotsForTarget(e)}restoreMaterialSnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restoreMaterialSnapshotsForTarget(e.instance);break;case"prefab":this.restoreMaterialSnapshotsForTarget(e.target??null),this.restoreMaterialSnapshotsForTarget(e.instance.mainActor??null),this.restoreMaterialSnapshotsForTarget(e.instance.object);break;case"proxy":this.restoreMaterialSnapshotsForTarget(e.target)}}restoreMaterialSnapshotsForTarget(e){if(!e)return;const t=e;this.materialResolutionCache.delete(t);const a=this.materialSnapshots.get(t);if(a){for(const e of a.values())null==e.materialIndex?e.owner.material=e.originalMaterial:Array.isArray(e.owner.material)&&(e.owner.material[e.materialIndex]=e.originalMaterial),e.controlledMaterial!==e.originalMaterial&&e.controlledMaterial.dispose();this.materialSnapshots.delete(t)}}restoreAllMaterialSnapshots(){for(const e of Array.from(this.materialSnapshots.keys()))this.restoreMaterialSnapshotsForTarget(e)}applyResolvedMaterialValue(e,t,a){if(!t||!e.uniformName)return;if("asset"===S(e)&&!e.materialAssetId)return;const s=this.getMaterialSlotResolutions(t,e);for(const r of s){const s=this.ensureSequenceControlledMaterial(t,r),i=s.uniforms?.[e.uniformName];if(!i)continue;const n=G(i.value,a);n.applied&&(i.value=n.value,s.uniformsNeedUpdate=!0)}}getMaterialSlotResolutions(e,t){const a=e,s=S(t),r=`${t.id}:${s}:${t.materialAssetId??""}:${t.uniformName}`;let i=this.materialResolutionCache.get(a);i||(i=new Map,this.materialResolutionCache.set(a,i));const n=i.get(r);if(n)return n;const o=e instanceof p?e.object:e,l=[];return o.traverse(e=>{const a=e.material;if(Array.isArray(a))for(let s=0;s<a.length;s++){const r=a[s];$(r,t)&&l.push({owner:e,materialIndex:s,material:r,key:`${e.uuid}:${s}`})}else $(a,t)&&l.push({owner:e,materialIndex:null,material:a,key:`${e.uuid}:material`})}),i.set(r,l),l}ensureSequenceControlledMaterial(e,t){const a=e;let s=this.materialSnapshots.get(a);s||(s=new Map,this.materialSnapshots.set(a,s));const r=s.get(t.key);if(r)return r.controlledMaterial;const i=t.material.clone();return null==t.materialIndex?t.owner.material=i:Array.isArray(t.owner.material)&&(t.owner.material[t.materialIndex]=i),s.set(t.key,{owner:t.owner,materialIndex:t.materialIndex,originalMaterial:t.material,controlledMaterial:i}),i}async ensureAnimationClip(e){if(!this.assetLoader)return null;const t=this.animationClips.get(e);if(t)return t;const a=this.loadingAnimationClips.get(e);if(a)return a;const s=(async()=>{try{const t=await this.assetLoader.getAnimationClipByAssetId(e);return t&&this.animationClips.set(e,t),t}catch(t){return console.error(`Failed to load animation clip for asset ${e}:`,t),null}finally{this.loadingAnimationClips.get(e)===s&&this.loadingAnimationClips.delete(e)}})();return this.loadingAnimationClips.set(e,s),s}prepareAnimationPlayback(e,t,a){if(!B(a)){let e=t;return a.clipEndOffset>0&&(e=e.clone(),e.duration=Math.max(0,e.duration-a.clipEndOffset)),{clip:e,timeScale:a.playbackRate,startOffset:a.clipStartOffset}}return{clip:this.getPlayableAnimationClip(e,t,a,!1),timeScale:1,startOffset:0}}getPlayableAnimationClip(e,t,a,s){if(!B(a))return s?j.fromClip(t,!1):t;const r=`${a.id}:${s?"root":"base"}`,i=`${q(a)}|${s?"root":"base"}`,n=this.retimedAnimationClips.get(r);if(n&&n.assetId===e&&n.signature===i)return n.clip;const o=M(t,a),l=s?j.fromClip(o,!1):o;return this.retimedAnimationClips.set(r,{assetId:e,signature:i,clip:l}),l}getAnimationPlaybackLocalTime(e,t){const a=Math.max(0,t-e.startTime);return B(e)?a:a*e.playbackRate+e.clipStartOffset}clearRetimedAnimationClipCache(e){if(null!=e)for(const[t,a]of this.retimedAnimationClips.entries())a.assetId===e&&this.retimedAnimationClips.delete(t);else this.retimedAnimationClips.clear()}captureOriginalTransforms(){for(const e of this.bindings.values()){const t=e.target instanceof p?e.target.object:e.target;t&&(e.originalTransform={position:t.position.clone(),rotation:t.rotation.clone(),scale:t.scale.clone()})}}restoreOriginalTransforms(){for(const e of this.bindings.values())if(e.originalTransform){const t=e.target instanceof p?e.target.object:e.target;t&&(t.position.copy(e.originalTransform.position),t.rotation.copy(e.originalTransform.rotation),t.scale.copy(e.originalTransform.scale))}}stopAllAnimations(){for(const e of this.bindings.values()){for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer&&e.mixer.stopAllAction(),e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0),e.charAnimActionKeys?.clear()}}stopAllVfx(){for(const e of this.vfxActors.values())e.paused||e.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const e of this.vfxActors.values())this.world.removeActor(e);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.loadingAnimationClips.clear(),this.clearRetimedAnimationClipCache(),this.audioByClip.clear()}updateTrackParenting(e,t){const a=this.getActiveObjectsForTrack(e);if(0===a.length)return;let s=null;const r=e.parent?.trackId;if(r){const t=this.sequenceData?H(this.sequenceData.tracks).find(e=>e.id===r):void 0;if(t){const a=this.getActiveObjectsForTrack(t);if(a.length>0&&(s=a[0],e.parent?.socketName)){const t=this.findSocket(s,e.parent.socketName);t&&(s=t)}}}if(!s&&"camera"===e.type&&e.parentRole&&this.roleBindings.has(e.parentRole)){const t=this.roleBindings.get(e.parentRole);if(s=t instanceof p?t.object:t,e.parentRoleSocketName){const t=this.findSocket(s,e.parentRoleSocketName);t&&(s=t)}}for(const r of a)s?r.parent!==s&&(s.add(r),!t||"object"!==e.type&&"locator"!==e.type||(t.currentParent=s)):t?.currentParent&&t.currentParent===r.parent?this.restoreObjectParent(t,r):r.parent&&r.parent!==this.world?.scene&&"object"!==e.type&&"locator"!==e.type&&this.world?.scene.add(r)}findSocket(e,t){if(e.name===t)return e;if(e instanceof a.SkinnedMesh){const a=e.skeleton.bones.find(e=>e.name===t);if(a)return a}return e.getObjectByName(t)||null}getActiveObjectsForTrack(e){if("object"===e.type){const t=this.bindings.get(e.id);if(t&&t.target)return[t.target instanceof p?t.target.object:t.target]}else if("locator"===e.type){const t=this.bindings.get(e.id);if(t&&t.target instanceof n)return[t.target]}else{if("camera"===e.type)return[this.ensureSequenceCamera(e)];if("spawn"===e.type){const t=[];for(const[a,s]of this.spawnedInstances)if(a.startsWith(e.id+"-")&&this.activeClips.has(a)){const e=this.getInstanceObject(s);e&&t.push(e)}return t}if("vfx"===e.type){const t=[];for(const a of this.activeVfxClips)if(a.startsWith(e.id+"-")){const e=this.vfxActors.get(a);e&&t.push(e.object)}return t}}return[]}restoreObjectParent(e,t){e.originalParent?e.originalParent.add(t):this.world&&this.world.scene.add(t),e.currentParent=void 0}restoreOriginalParents(){for(const e of this.bindings.values())if(e.currentParent){const t=e.target instanceof p?e.target.object:e.target;t&&this.restoreObjectParent(e,t)}}evaluateAudioSubTracks(e,t){const a={};for(const s of e.subTracks)if("audioParameter"===s.type){const e=s,r=A(e.parameter),i=T(e.keyframes,t,{min:r.min,max:r.max});void 0!==i&&(a[e.parameter]=i)}return a}stringToRandom(e){let t=0;for(let a=0;a<e.length;a++){t=(t<<5)-t+e.charCodeAt(a),t&=t}const a=1e4*Math.sin(t);return a-Math.floor(a)}async refreshAsset(e){let t=!1;this.assetLoader?.clearCacheById(e),this.animationClips.delete(e),this.loadingAnimationClips.delete(e),this.clearRetimedAnimationClipCache(e),this.vfxService?.clearPool(e),t=this.refreshVfxActorsForAssetIds(new Set([e]))||t;for(const[a,s]of this.activePostProcessClips.entries())s.assetId===e&&(this.releasePostProcessClipEffect(a),t=!0);t=this.refreshSpawnedInstancesForClipKeys(this.getSpawnClipKeysForAsset(e))||t;const a=await this.getAssetOrNull(e);return"shaderGraph"===a?.type&&(t=await this.refreshShaderGraphDependentAssets(e)||t),t}refreshVfxActorsForAssetIds(e){let t=!1;for(const[a,s]of this.vfxActors.entries())this.vfxClipKeyUsesAnyAsset(a,e)&&(this.world&&this.world.removeActor(s),this.vfxActors.delete(a),this.activeVfxClips.delete(a),t=!0);return t}vfxClipKeyUsesAnyAsset(e,t){for(const a of t)if(e.endsWith(`-${a}`))return!0;return!1}refreshSpawnedInstancesForClipKeys(e){let t=!1;for(const[a,s]of this.spawnedInstances.entries())e.has(a)&&(this.despawnInstance(s),this.spawnedInstances.delete(a),this.activeClips.delete(a),t=!0);return t}getSpawnClipKeysForAsset(e){const t=new Set;if(!this.sequenceData)return t;for(const a of H(this.sequenceData.tracks))if("spawn"===a.type&&(a.prefabId===e||a.meshId===e))for(const e of a.clips)t.add(`${a.id}-${e.id}`);return t}async refreshShaderGraphDependentAssets(e){const t=await this.findSequenceVfxAssetIdsUsingShaderGraph(e);for(const e of t)this.vfxService?.clearPool(e);const a=this.refreshVfxActorsForAssetIds(t),s=this.refreshSpawnedInstancesForClipKeys(await this.findSpawnClipKeysUsingShaderGraph(e));return a||s}async findSequenceVfxAssetIdsUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of H(this.sequenceData.tracks))if("vfx"===s.type)for(const r of s.clips)null==r.vfxAssetId||t.has(r.vfxAssetId)||await this.assetUsesShaderGraph(r.vfxAssetId,e,a)&&t.add(r.vfxAssetId);return t}async findSpawnClipKeysUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of H(this.sequenceData.tracks))if("spawn"===s.type&&await this.spawnTrackUsesShaderGraph(s,e,a))for(const e of s.clips)t.add(`${s.id}-${e.id}`);return t}async spawnTrackUsesShaderGraph(e,t,a){if(null!=e.meshId&&await this.assetUsesShaderGraph(e.meshId,t,a))return!0;if(null!=e.prefabId&&await this.assetUsesShaderGraph(e.prefabId,t,a))return!0;for(const s of e.subTracks??[])if("material"===s.type&&null!=s.materialAssetId&&await this.assetUsesShaderGraph(s.materialAssetId,t,a))return!0;return!1}assetUsesShaderGraph(e,t,a,s=new Set){if(e===t)return Promise.resolve(!0);if(s.has(e))return Promise.resolve(!1);if(a.has(e))return a.get(e);const r=this.assetUsesShaderGraphUncached(e,t,a,s);return a.set(e,r),r}async assetUsesShaderGraphUncached(e,t,a,s){if(s.has(e))return!1;const r=await this.getAssetOrNull(e);if(null==r)return!1;const i=new Set(s);return i.add(e),!!this.materialAssetUsesShaderGraph(r,t)||("mesh"===r.type?this.materialAssignmentsUseShaderGraph(r.materialAssignments,t,a,i):"prefab"===r.type?this.sceneObjectsUseShaderGraph(r.prefab?.objects,t,a,i):"vfx"===r.type&&this.vfxAssetUsesShaderGraph(r,t,a,i))}materialAssetUsesShaderGraph(e,t){return"shaderGraph"===e.type?e.id===t:"asset"===e.material?.shaderGraph?.source&&e.material.shaderGraph.assetId===t}async materialAssignmentsUseShaderGraph(e,t,a,s){for(const r of e??[])if(null!=r.materialId&&"null"!==r.materialId&&await this.assetUsesShaderGraph(r.materialId,t,a,s))return!0;return!1}async sceneObjectsUseShaderGraph(e,t,a,s){for(const r of e??[]){if(await this.materialAssignmentsUseShaderGraph(r.materialAssignments,t,a,s))return!0;if(null!=r.assetId&&("asset_mesh"===r.type||"prefab"===r.type||"vfx"===r.type)&&await this.assetUsesShaderGraph(r.assetId,t,a,s))return!0;if(await this.sceneObjectsUseShaderGraph(r.children,t,a,s))return!0}return!1}async vfxAssetUsesShaderGraph(e,t,a,s){for(const r of e.vfx?.emitters??[])if(await this.emitterUsesShaderGraph(r,t,a,s))return!0;return!1}async emitterUsesShaderGraph(e,t,a,s){if(await this.emitterOutputUsesShaderGraph(e.output,t,a,s))return!0;for(const r of e.children??[])if(await this.emitterUsesShaderGraph(r,t,a,s))return!0;return!1}async emitterOutputUsesShaderGraph(e,t,a,s){const r=e.materialSource??("asset"===e.shaderGraph?.source?"shaderGraph":void 0);return"shaderGraph"===r&&"asset"===e.shaderGraph?.source&&e.shaderGraph.assetId===t||!("material"!==r||!("material"in e)||null==e.material||!await this.assetUsesShaderGraph(e.material,t,a,s))}async getAssetOrNull(e){if(!this.assetLoader)return null;try{return await this.assetLoader.getAsset(e)??null}catch{return null}}async invokeSequenceEvent(e,t,a,s){let r=!1;for(let e=0;e<s.length;e++)if(C(s[e])){r=!0;break}if(r)try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=v(s[e],this.sequenceEventAsyncResolvers);const r=await Promise.all(t);await a.call(e,...r)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}else try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=g(s[e],this.sequenceEventSyncResolvers);a.call(e,...t)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}}resolveSequenceEventActorReference(e){if(!this.world||null==e)return null;const t=e,a="object"==typeof t&&null!=t?.id?t.id:"string"==typeof t?t:null;if(null==a)return null;for(const e of this.world.actors){const t=e.object.userData.src??e.object.userData._src;if(t?.id===a)return e}return null}resolveSequenceEventSequence(e){return function(e){return"object"==typeof e&&null!=e&&"duration"in e&&"tracks"in e}(e)?new w(e):this.assetLoader&&"string"==typeof e?this.assetLoader.getSequenceById(e):null}async resolveSequenceEventAnimationClip(e){const t="string"==typeof e?e:"object"==typeof e&&null!=e?e.assetId??null:null;return null!=t&&this.assetLoader?this.assetLoader.getAnimationClipByAssetId(t):null}}function V(e){return e.options?.length>0||e.propertyType===y.Boolean||e.propertyType===y.String}function D(e){return e.valueType===y.Boolean||e.valueType===y.String}function K(e){return"object"==typeof e&&null!=e||"function"==typeof e}function G(e,t){switch(t.type){case y.Number:return function(e){if("number"==typeof e)return Number.isFinite(e)?{applied:!0,value:e}:{applied:!1};if("string"==typeof e){const t=parseFloat(e);return Number.isFinite(t)?{applied:!0,value:t}:{applied:!1}}return{applied:!1}}(t.value);case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return N(e,t.value);case y.Vector3:return U(e,t.value);case y.Vector4:return W(e,t.value);case y.Color:return function(e,t){if(e instanceof c){const a=ce.set(0);return Y(a,t)?(e.set(a.r,a.g,a.b),{applied:!0,value:e}):{applied:!1}}if(e instanceof h){const a=ce.set(0);return Y(a,t)?(e.set(a.r,a.g,a.b,e.w),{applied:!0,value:e}):{applied:!1}}return X(e,t)}(e,t.value);default:return{applied:!1}}}function $(e,t){const s=S(t);return function(e){return e instanceof a.Material||!0===e?.isMaterial}(e)&&null!=e.uniforms?.[t.uniformName]&&("parameterName"===s||e.userData?.assetId===t.materialAssetId)}function N(e,t){const a=Q(t,2);return a?e instanceof l?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new l(a[0],a[1])}:{applied:!1}}function U(e,t){const a=Q(t,3);return a?e instanceof c?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new c(a[0],a[1],a[2])}:{applied:!1}}function W(e,t){const a=Q(t,4);return a?e instanceof h?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new h(a[0],a[1],a[2],a[3])}:{applied:!1}}function X(e,t){if(e instanceof r)return Y(e,t)?{applied:!0,value:e}:{applied:!1};const a=new r;return Y(a,t)?{applied:!0,value:a}:{applied:!1}}function Q(e,t){if(!Array.isArray(e)||e.length<t)return null;const a=new Array(t);for(let s=0;s<t;s++){if("number"!=typeof e[s])return null;a[s]=e[s]}return a}function Y(e,t){return t instanceof r||"string"==typeof t||"number"==typeof t?(e.set(t),!0):!!(Array.isArray(t)&&t.length>=3)&&(e.setRGB("number"==typeof t[0]?t[0]:0,"number"==typeof t[1]?t[1]:0,"number"==typeof t[2]?t[2]:0),!0)}function Z(e){if(e instanceof l||e instanceof c||e instanceof h||e instanceof r||e instanceof i)return e.clone()}function z(e){const{owner:t,key:a}=e.resolution;e.hadOwnProperty?(!function(e,t){if(e instanceof l&&t instanceof l)return e.copy(t),!0;if(e instanceof c&&t instanceof c)return e.copy(t),!0;if(e instanceof h&&t instanceof h)return e.copy(t),!0;if(e instanceof r&&t instanceof r)return e.copy(t),!0;if(e instanceof i&&t instanceof i)return e.copy(t),!0}(e.value,e.valueSnapshot),t[a]=e.value):delete t[a]}function H(e){const t=[];for(const a of e)t.push(a),"group"===a.type&&t.push(...H(a.childTracks));return t}function J(e){if("string"!=typeof e)return null;const t=e.trim();return t.length>0?t:null}function ee(e){const t=new a.Group;t.name=`SequenceLocatorMarker:${e}`,t.renderOrder=1e3;const s=new a.AxesHelper(.35);s.renderOrder=1e3;const r=Array.isArray(s.material)?s.material:[s.material];for(const e of r)e.depthTest=!1,e.transparent=!0,e.opacity=.9,e.toneMapped=!1;t.add(s);const i=function(e){if("undefined"==typeof document)return null;const t=document.createElement("canvas");t.width=256,t.height=64;const s=t.getContext("2d");if(!s)return null;s.clearRect(0,0,t.width,t.height),s.fillStyle="rgba(16, 18, 24, 0.78)",function(e,t,a,s,r,i){const n=t+s,o=a+r;e.beginPath(),e.moveTo(t+i,a),e.lineTo(n-i,a),e.quadraticCurveTo(n,a,n,a+i),e.lineTo(n,o-i),e.quadraticCurveTo(n,o,n-i,o),e.lineTo(t+i,o),e.quadraticCurveTo(t,o,t,o-i),e.lineTo(t,a+i),e.quadraticCurveTo(t,a,t+i,a),e.closePath()}(s,0,8,t.width,48,8),s.fill(),s.font="24px sans-serif",s.textAlign="center",s.textBaseline="middle",s.fillStyle="#f8fafc",s.fillText(e||"Locator",t.width/2,t.height/2);const r=new a.CanvasTexture(t);r.needsUpdate=!0;const i=new a.SpriteMaterial({map:r,transparent:!0,depthTest:!1});i.toneMapped=!1;const n=new a.Sprite(i);return n.scale.set(.9,.225,1),n}(e);return i&&(i.position.set(0,.45,0),i.renderOrder=1001,t.add(i)),t.traverse(e=>{e.raycast=()=>{}}),t}function te(e){e.traverse(e=>{const t=e.material;if(Array.isArray(t))for(const e of t)e?.dispose?.(),e?.map?.dispose?.();else t?.dispose?.(),t?.map?.dispose?.()})}const ae=new c,se=new c,re=new c,ie=new o,ne=new o,oe=new i,le=new i,ce=new r;/*
|
|
1
|
+
import{BehaviorSubject as e,Subject as t}from"rxjs";import*as a from"three";import{AnimationMixer as s,Color as r,Euler as i,Object3D as n,Quaternion as o,Vector2 as l,Vector3 as c,Vector4 as h}from"three";import{VisualEffect as u}from"../../effects/vfx/vfx-param.js";import{BaseActor as p}from"../../gameplay/actors/actor.js";import d from"../../gameplay/actors/builtin/index.js";import{Prefab as f,PrefabOf as m}from"../../scene/objects/prefab.js";import{SerializedParamType as y}from"../../scene/model.js";import{customParamValueNeedsAsyncResolution as C,deserializeCustomParamValue as v,deserializeCustomParamValueSync as g}from"../../scene/custom-param-deserialize.js";import{getAudioParameterDefinition as A}from"./audio-parameters.js";import{getMaterialSubTrackMatchMode as S,Sequence as w}from"./sequence-data.js";import{getSequenceSubTrackDefinition as P,getSequenceTrackDefinition as b}from"./sequence-definitions.js";import{applyInterpolation as k,evaluateCustomParamValueKeyframes as x,evaluateNumericKeyframes as T,findKeyframeSpan as I}from"./sequence-value-lane.js";import{buildRetimedAnimationClip as M,getAnimationClipRetimingSignature as q,isAnimationClipUsingRetiming as B}from"./sequence-animation-retiming.js";import{SkeletonUtils as O}from"three-stdlib";import{CharacterAnimationComponent as F,CharacterMovementComponent as E}from"../../gameplay/actors/index.js";import{RootMotionClip as j}from"../../gameplay/animation/root-motion.js";import{hashCameraShakeSeed as L}from"../../gameplay/services/camera-shake.js";import{buildShaderGraphPostProcessMaterial as _,shaderGraphPostProcessWeightUniformName as R}from"../../shader/graph/index.js";export var SequencePlaybackState;!function(e){e.Stopped="stopped",e.Playing="playing",e.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new e(SequencePlaybackState.Stopped),this._time=new e(0),this._duration=0,this._timescale=1,this._loop=!1,this._externalTimeControl=!1,this._inEditor=!1,this.bindings=new Map,this.roleBindings=new Map,this.sequenceData=null,this.onComplete=new t,this.onLoop=new t,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.viewController=null,this._cameraControlEnabled=!1,this._cameraControlTrackId=null,this.sequenceCameras=new Map,this.cameraPlayables=new Map,this.cameraBlendCamera=null,this.cameraBlendSource=null,this.cameraBlendOutSource=null,this.cameraOverrideHandle=null,this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null,this.activeCameraShakeClipKeys=new Set,this.nextCameraShakeClipKeys=new Set,this.activePostProcessClips=new Map,this.nextPostProcessClipKeys=new Set,this.audioListener=null,this.audioBuffers=new Map,this.loadingAudioBuffers=new Map,this.animationClips=new Map,this.loadingAnimationClips=new Map,this.retimedAnimationClips=new Map,this.audioByClip=new Map,this.activeAudioClips=new Set,this.audioGainNodes=new Map,this.audioStartInFlight=new Map,this.lastAudioStartAttemptTime=new Map,this.audioStartRetryIntervalSeconds=.25,this.world=null,this.assetLoader=null,this.actorFactory=null,this.vfxService=null,this.spawnedInstances=new Map,this.activeClips=new Set,this.pendingSpawns=new Set,this.vfxActors=new Map,this.activeVfxClips=new Set,this.locatorMarkers=new Map,this.clearCounter=0,this.propertyPathSegments=new Map,this.propertyResolutionCache=new Map,this.propertySnapshots=new Map,this.materialResolutionCache=new Map,this.materialSnapshots=new Map,this.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set,this.sequenceEventSyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e)},this.sequenceEventAsyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e),texture:e=>this.assetLoader?.getTextureByAssetId(e)??null,sampler2DNode:e=>this.assetLoader?.getTextureByAssetId(e)??null,object3D:async e=>{const t=await(this.assetLoader?.getModelByAssetId(e));return t?.scene??null},material:e=>this.assetLoader?.getMaterialByAssetId(e)??null,audioBuffer:e=>this.assetLoader?.getAudioByAssetId(e)??null,visualEffect:async e=>{if(!this.assetLoader||!this.actorFactory)return null;const t=await this.assetLoader.getAsset(e);return t?new u(this.actorFactory,t):null},prefab:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new f(t.asset):null},prefabActor:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new m(new f(t.asset)):null},sequence:e=>this.resolveSequenceEventSequence(e),animationClip:e=>this.resolveSequenceEventAnimationClip(e)},this.trackRuntimeEvaluators={object:(e,t,a)=>{t&&this.evaluateObjectTrack(e,t,a)},locator:(e,t,a)=>{t&&this.evaluateLocatorTrack(e,t,a)},camera:(e,t,a)=>this.evaluateCameraTrack(e,a),cameraShake:(e,t,a)=>this.evaluateCameraShakeTrack(e,a),postProcess:(e,t,a)=>this.evaluatePostProcessTrack(e,a),audio:(e,t,a)=>this.evaluateAudioTrack(e,a),vfx:(e,t,a)=>this.evaluateVfxTrack(e,a),spawn:(e,t,a)=>this.evaluateSpawnTrack(e,t,a),group:(e,t,a)=>{if("group"===e.type)for(const t of e.childTracks)this.evaluateTrack(t,a)}},this.subTrackRuntimeEvaluators={transform:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateTransformSubTrack(e,s,a)},animation:(e,t,a)=>this.evaluateAnimationSubTrack(e,t,a),visibility:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateVisibilitySubTrack(e,s,a)},parameter:(e,t,a)=>this.evaluateParameterSubTrack(e,t.target||null,a),event:(e,t,a)=>this.evaluateEventSubTrack(e,t.target||null,a)}}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(e){this._timescale=Math.max(.01,e)}get loop(){return this._loop}set loop(e){this._loop=e}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(e){this._externalTimeControl=e}get inEditor(){return this._inEditor}set inEditor(e){this._inEditor=e,this.updateLocatorMarkerVisibility()}get cameraControlEnabled(){return this._cameraControlEnabled}set cameraControlEnabled(e){this._cameraControlEnabled=e,e||this.releaseCameraOverride()}get cameraControlTrackId(){return this._cameraControlTrackId}set cameraControlTrackId(e){this._cameraControlTrackId!==e&&(this._cameraControlTrackId=e,this.releaseCameraOverride())}setViewController(e){this.viewController&&this.viewController!==e&&this.viewController.clearCameraShakeContributionsForOwner(this),this.viewController=e}setWorld(e){this.world!==e&&(this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.world=e,this.clearCounter++,this.vfxActors.clear(),this.spawnedInstances.clear(),this.bindings.clear(),this.activeClips.clear(),this.activeVfxClips.clear(),this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear(),this.loadingAudioBuffers.clear(),this.audioFilters.clear(),this.audioPannerNodes.clear(),this.pendingSpawns.clear(),this.propertyResolutionCache.clear(),this.materialResolutionCache.clear(),this.clearRetimedAnimationClipCache(),this._state.next(SequencePlaybackState.Stopped),this.sequenceData&&this.initializeLocatorBindings())}setAudioListener(e){this.audioListener=e}setAssetLoader(e){if(this.assetLoader=e,this.sequenceData){const e=this.clearCounter;this.preloadSequenceResources(this.sequenceData,e)}}setActorFactory(e){this.actorFactory=e}setVfxService(e){this.vfxService=e}load(e){if(this.stop(),this.clearCounter++,this.clearLocatorBindings(),this.clearSequenceCameras(),this.sequenceData=e,this._duration=e.duration,this._loop=e.loop,this._timescale=e.playbackRate,this.clearRetimedAnimationClipCache(),this.bindings.clear(),this.initializeLocatorBindings(),this.loopCount=0,this.assetLoader){const t=this.clearCounter;this.preloadSequenceResources(e,t)}}preloadSequenceResources(e,t){return Promise.all([this.preloadAudioBuffersForSequence(e,t),this.preloadAnimationClipsForSequence(e,t)]).then(()=>{})}getAudioAssetIdsForSequence(e){const t=new Set;for(const a of e.tracks){if("audio"!==a.type)continue;const e=a;for(const a of e.clips??[])a.audioAssetId&&t.add(a.audioAssetId)}return[...t]}async preloadAudioBuffersForSequence(e,t){if(!this.assetLoader)return;const a=this.getAudioAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{if(t!==this.clearCounter)return;if(this.audioBuffers.has(e))return;let a=this.loadingAudioBuffers.get(e);a||(a=this.assetLoader.getAudioByAssetId(e),this.loadingAudioBuffers.set(e,a));try{const s=await a;if(t!==this.clearCounter)return;this.audioBuffers.set(e,s)}catch(e){}finally{this.loadingAudioBuffers.get(e)===a&&this.loadingAudioBuffers.delete(e)}}))}getAnimationClipAssetIdsForSequence(e){const t=new Set;for(const a of H(e.tracks))if("subTracks"in a)for(const e of a.subTracks)if("animation"===e.type)for(const a of e.clips)a.animationClipAssetId&&t.add(a.animationClipAssetId);return[...t]}async preloadAnimationClipsForSequence(e,t){if(!this.assetLoader)return;const a=this.getAnimationClipAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{t===this.clearCounter&&await this.ensureAnimationClip(e)}))}bindRole(e,t){this.roleBindings.set(e,t),this.sequenceData&&this.resolveBindings()}bindObject(e,t){if(this.sequenceData)for(const a of this.sequenceData.tracks)"object"===a.type&&a.targetId===e&&this.createBinding(a,t)}getLocator(e){return this.getLocators(e)[0]??null}getLocators(e){const t=J(e);if(!t||!this.sequenceData)return[];const a=[];for(const e of H(this.sequenceData.tracks)){if("locator"!==e.type)continue;if(J(e.bindingId)!==t)continue;const s=this.bindings.get(e.id),r=s?this.getPlayableObject(s):null;r&&(r.updateWorldMatrix(!0,!1),a.push({trackId:e.id,name:e.name,bindingId:e.bindingId,position:r.getWorldPosition(new c),rotation:r.getWorldQuaternion(new o),scale:r.getWorldScale(new c)}))}return a}resolveBindings(){if(this.sequenceData)for(const e of this.sequenceData.tracks)this.resolveTrackBinding(e)}initializeLocatorBindings(){if(this.sequenceData)for(const e of H(this.sequenceData.tracks)){if("locator"!==e.type||this.bindings.has(e.id))continue;const t=new n;t.name=e.name||"Locator",t.userData.sequenceLocatorTrackId=e.id,this.world?.scene&&null==t.parent&&this.world.scene.add(t);const a=ee(e.name);a.visible=this._inEditor,t.add(a),this.locatorMarkers.set(e.id,a),this.disableLocatorInteraction(t),this.createBinding(e,t)}}clearLocatorBindings(){for(const e of this.locatorMarkers.values())te(e);for(const e of this.bindings.values()){if("locator"!==e.track.type)continue;const t=this.getPlayableObject(e);t?.parent&&t.removeFromParent()}this.locatorMarkers.clear()}updateLocatorMarkerVisibility(){for(const e of this.locatorMarkers.values())e.visible=this._inEditor}disableLocatorInteraction(e){e.traverse(e=>{e.raycast=()=>{}})}resolveTrackBinding(e){if("object"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("spawn"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("group"===e.type)for(const t of e.childTracks)this.resolveTrackBinding(t)}createBinding(e,t){const a=t instanceof p?t.object:t,r=this.bindings.get(e.id),i=null!=r?r.target instanceof p?r.target.object:r.target:null,n=null!=r&&r.target===t&&i===a,o=e.subTracks.some(e=>"animation"===e.type);if(null!=r&&!n){for(const e of r.activeActions.values())e.stop();r.activeActions.clear(),r.mixer?.stopAllAction(),r.charAnimComponent?.stopSequenceAnimation(),r.charAnimComponent=void 0,r.charAnimActionKeys?.clear()}const l=n?r:{track:e,target:t,activeActions:new Map};l.track=e,l.target=t,l.originalTransform={position:a.position.clone(),rotation:a.rotation.clone(),scale:a.scale.clone()},l.originalParent=a.parent,o&&null==l.mixer?l.mixer=new s(a):o||(l.mixer=void 0),this.bindings.set(e.id,l)}play(){this._state.value!==SequencePlaybackState.Playing&&this.sequenceData&&(this._state.value===SequencePlaybackState.Stopped&&(this._time.next(0),this.loopCount=0,this.resolveBindings(),this.captureOriginalTransforms()),this._state.next(SequencePlaybackState.Playing),this.evaluate(this._time.value),this.resumeVfx())}pause(){this._state.value===SequencePlaybackState.Playing&&(this._state.next(SequencePlaybackState.Paused),this.pauseAudio(),this.pauseVfx())}pauseAudio(){for(const e of this.audioByClip.values())e.pause()}pauseVfx(){for(const e of this.vfxActors.values())e.pause()}resumeVfx(){for(const[e,t]of this.vfxActors.entries())(this.activeVfxClips.has(e)||t.getParticleCount()>0)&&t.play()}cancel(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}restart(){this.stop(),this.play()}seek(e){const t=Math.max(0,Math.min(e,this._duration));t<this._time.value&&this.resetVfxForTimeReset(t),this._time.next(t),this.evaluate(t)}update(e){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale);return}const t=this._time.value+e*this._timescale;if(t>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this.releaseCameraOverride(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();{this.loopCount++;const e=t%this._duration;this.resetVfxForTimeReset(e),this._time.next(e),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}}else this._time.next(t);this.evaluate(this._time.value);for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale)}evaluate(e){if(this.sequenceData){this.nextCameraShakeClipKeys.clear(),this.nextPostProcessClipKeys.clear();for(const t of this.sequenceData.tracks){if(!t.muted&&("object"===t.type||"locator"===t.type||"camera"===t.type||"spawn"===t.type||"vfx"===t.type)){const e=this.bindings.get(t.id);this.updateTrackParenting(t,e)}this.evaluateTrack(t,e)}this.updateCameraControl(e),this.syncCameraShakeContributions(),this.syncPostProcessEffects()}}evaluateTrack(e,t){if(e.muted)return;const a=this.bindings.get(e.id);(0,this.trackRuntimeEvaluators[b(e.type).runtimeEvaluator])(e,a,t)}evaluateObjectTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}evaluateLocatorTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}getActiveTrackObjects(e){if(!this.sequenceData)return[];const t=H(this.sequenceData.tracks).find(t=>t.id===e);return t?this.getActiveObjectsForTrack(t):[]}evaluateSubTracks(e,t,a){for(const s of e){if(s.muted)continue;(0,this.subTrackRuntimeEvaluators[P(s.type).runtimeEvaluator])(s,t,a)}}evaluateTransformSubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;const{prev:r,next:i,t:n}=I(s,a);if(r)if(i&&r!==i){const a=k(n,r.interpolation);e.components.position&&r.position&&i.position&&t.position.lerpVectors(ae.fromArray(r.position),se.fromArray(i.position),a),e.components.rotation&&r.rotation&&i.rotation&&(ie.setFromEuler(oe.fromArray([...r.rotation,"XYZ"])),ne.setFromEuler(le.fromArray([...i.rotation,"XYZ"])),t.quaternion.slerpQuaternions(ie,ne,a)),e.components.scale&&r.scale&&i.scale&&t.scale.lerpVectors(ae.fromArray(r.scale),se.fromArray(i.scale),a)}else e.components.position&&r.position&&t.position.fromArray(r.position),e.components.rotation&&r.rotation&&t.rotation.fromArray([...r.rotation,"XYZ"]),e.components.scale&&r.scale&&t.scale.fromArray(r.scale)}evaluateAnimationSubTrack(e,t,s){if(!t.mixer||!t.activeActions)return;if(t.target instanceof p?t.target.object:t.target)for(const r of e.clips){const i=r.startTime+r.duration,n=s>=r.startTime&&s<i,o=`${e.id}-${r.id}`;let l=t.activeActions.get(o),c=!1;if(n){if(!l){c=!0;const e=r.animationClipAssetId;if(null==e)continue;const s=this.animationClips.get(e);if(null==s){this.ensureAnimationClip(e);continue}const i=this.prepareAnimationPlayback(e,s,r),n=t;let h=!1;if(t.target instanceof p){n.charAnimComponent||(n.charAnimComponent=t.target.getComponent(F)??void 0);const a=n.charAnimComponent;if(null!=a){const c=r.rootMotion?B(r)?this.getPlayableAnimationClip(e,s,r,!0):j.fromClip(i.clip,!1):i.clip;if(this._externalTimeControl)l=a.beginExternalAnimationControl(c,{timeScale:i.timeScale});else if(a.play(c,{inPlace:!r.rootMotion,loop:!1,priority:20,timeScale:i.timeScale,fadeTime:r.fadeInDuration??.2,offset:i.startOffset}),l=a.getFullBodyAction(),r.rootMotion){const e=t.target.getComponent(E);e&&e.setRootMotionAction(l,{cancelWithJump:e.allowRootMotionJumpCancel,onJumpCancel:()=>this.cancel()})}t.activeActions.set(o,l),n.charAnimActionKeys||(n.charAnimActionKeys=new Set),n.charAnimActionKeys.add(o),h=!0}}h||(l=t.mixer.clipAction(i.clip),l.setLoop(a.LoopOnce,1),l.clampWhenFinished=!0,l.timeScale=i.timeScale,i.startOffset>0&&(l.time=i.startOffset),t.activeActions.set(o,l),l.play())}if(l){const e=t;if(this._externalTimeControl){e.charAnimComponent?.beginExternalControl();const a=this.getAnimationPlaybackLocalTime(r,s),i=Math.min(a,l.getClip().duration);(c||Math.abs(l.time-i)>.001)&&(l.time=i,l.paused=!1,l.play(),e.charAnimComponent?e.charAnimComponent.getMixer()?.update(0):t.mixer&&t.mixer.update(0))}else e.charAnimComponent?.endExternalControl()}}else if(l){t.activeActions.delete(o);const e=t;e.charAnimActionKeys?.has(o)?(e.charAnimActionKeys.delete(o),l.stop(),0===e.charAnimActionKeys.size&&e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0)):(l.stop(),this._externalTimeControl&&t.mixer&&t.mixer.update(0))}}}evaluateVisibilitySubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;let r=s[0];for(const e of s){if(!(e.time<=a))break;r=e}t.visible=r.visible}evaluatePropertySubTrack(e,t,a){const s=x(e.keyframes,a,{min:e.range?.[0],max:e.range?.[1],stepOnly:V(e)});s&&this.applyResolvedPropertyValue(e,t,s)}evaluateParameterSubTrack(e,t,a){if("audioParameter"===e.type)return;const s=x(e.keyframes,a,"property"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:V(e)}:"material"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:D(e)}:{});s&&("property"!==e.type?this.applyResolvedMaterialValue(e,t,s):this.applyResolvedPropertyValue(e,t,s))}evaluateEventSubTrack(e,t,a){if(t instanceof p&&this._state.value===SequencePlaybackState.Playing)for(const s of e.events){const r=`${e.id}-${s.id}`;if(a>=s.time&&!this.firedEvents.has(r)){if(this.firedEvents.add(r),s.editorOnly&&!this._inEditor)continue;if(!s.functionName)continue;const e=t[s.functionName];"function"==typeof e?this.invokeSequenceEvent(t,s.functionName,e,s.arguments??[]):console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>a&&this.firedEvents.delete(r)}}evaluateCameraTrack(e,t){const a=this.ensureSequenceCamera(e);this.applyCameraTrackSettings(e,a),this.evaluateSubTracks(e.subTracks,this.getCameraPlayable(e,a),t),a.updateProjectionMatrix()}evaluateCameraShakeTrack(e,t){if(this.viewController)for(const a of e.clips??[]){if(!this.isCameraShakeClipActive(a,t))continue;const e=t-a.startTime,s=a.id;this.nextCameraShakeClipKeys.add(s),this.viewController.setCameraShakeContribution(this,s,a,e,a.seed??L(a.id))}}evaluatePostProcessTrack(e,t){if(this.viewController&&this.assetLoader){for(const a of e.clips??[]){if(!this.isPostProcessClipActive(a,t))continue;const s=this.getPostProcessClipKey(e,a);this.nextPostProcessClipKeys.add(s),this.ensurePostProcessClipEffect(e,a,s);const r=this.activePostProcessClips.get(s);r?.handle&&(r.handle.stage=e.stage,r.handle.priority=e.priority,r.handle.enabled=!0,this.applyPostProcessClipWeight(r.handle,a,t))}this.evaluatePostProcessMaterialSubTracks(e,t)}}evaluatePostProcessMaterialSubTracks(e,t){for(const a of e.subTracks){if(a.muted||"material"!==a.type)continue;const s=x(a.keyframes,t,{min:a.range?.[0],max:a.range?.[1],stepOnly:D(a)});s&&this.applyPostProcessMaterialValue(e.id,a,s)}}applyPostProcessMaterialValue(e,t,a){if(t.uniformName)for(const s of this.activePostProcessClips.values()){if(s.trackId!==e||!s.handle)continue;const r=s.handle.material,i=r.uniforms?.[t.uniformName];if(!i)continue;const n=G(i.value,a);n.applied&&(i.value=n.value,r.uniformsNeedUpdate=!0)}}isPostProcessClipActive(e,t){return t>=e.startTime&&t<e.startTime+e.duration}getPostProcessClipKey(e,t){return`${e.id}-${t.id}`}ensurePostProcessClipEffect(e,t,a){const s=t.shaderGraphAssetId;if(!s)return void this.releasePostProcessClipEffect(a);const r=JSON.stringify(t.shaderGraphParams??{}),i=this.activePostProcessClips.get(a);if(i?.assetId===s&&i.paramsSignature===r)return;this.releasePostProcessClipEffect(a);const n={key:a,trackId:e.id,clipId:t.id,assetId:s,paramsSignature:r,version:this.clearCounter};this.activePostProcessClips.set(a,n),this.loadPostProcessClipEffect(e,t,n)}async loadPostProcessClipEffect(e,t,a){if(this.assetLoader&&this.viewController)try{const s=await this.assetLoader.getShaderGraphByAssetId(a.assetId);if(!this.isPostProcessClipEntryCurrent(a))return;if("postProcess"!==s.target)return console.warn(`Sequence post-process clip references shader graph "${a.assetId}" with target "${s.target}"`),void this.releasePostProcessClipEffect(a.key);const r=await this.assetLoader.prepareShaderGraphParameters(s,t.shaderGraphParams??{});if(!this.isPostProcessClipEntryCurrent(a))return;const i=_(s,{parameters:r});if(!this.isPostProcessClipEntryCurrent(a))return void i.dispose();a.handle=this.viewController.addPostProcessEffect(i,{stage:e.stage,priority:e.priority,enabled:!0}),this.applyPostProcessClipWeight(a.handle,t,this._time.value)}catch(e){this.isPostProcessClipEntryCurrent(a)&&this.releasePostProcessClipEffect(a.key),console.error(`Failed to create post-process effect for clip ${t.id}:`,e)}}isPostProcessClipEntryCurrent(e){return this.clearCounter===e.version&&this.activePostProcessClips.get(e.key)===e}applyPostProcessClipWeight(e,t,a){const s=e.material.uniforms?.[R];null!=s&&(s.value=this.getPostProcessClipWeight(t,a),e.material.uniformsNeedUpdate=!0)}getPostProcessClipWeight(e,t){const a=Math.max(0,t-e.startTime),s=Math.max(0,e.startTime+e.duration-t);let r=1;const i=Math.max(0,e.fadeInDuration??0);i>0&&(r=Math.min(r,a/i));const n=Math.max(0,e.fadeOutDuration??0);return n>0&&(r=Math.min(r,s/n)),Math.max(0,Math.min(1,r))}syncPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.nextPostProcessClipKeys.has(e)||this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}clearPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}releasePostProcessClipEffect(e){const t=this.activePostProcessClips.get(e);if(t&&(this.activePostProcessClips.delete(e),t.handle)){const e=t.handle.material;t.handle.dispose(),e.dispose()}}getCameraPlayable(e,t){let a=this.cameraPlayables.get(e.id);return a?a.target=t:(a={target:t},this.cameraPlayables.set(e.id,a)),a}ensureSequenceCamera(e){let t=this.sequenceCameras.get(e.id);if(t)null==t.parent&&this.world?.scene.add(t);else{const s=e.cameraSettings??{fov:60,near:.1,far:1e3};t=new a.PerspectiveCamera(s.fov??60,this.getCurrentCameraAspect(),s.near??.1,s.far??1e3),t.name=e.name||"Sequence Camera",t.userData.sequenceCameraTrackId=e.id,t.layers.mask=this.viewController?.getBaseCamera().layers.mask??t.layers.mask,this.sequenceCameras.set(e.id,t),this.world?.scene.add(t)}return t}clearSequenceCameras(){this.releaseCameraOverride();for(const e of this.sequenceCameras.values())e.removeFromParent();this.sequenceCameras.clear(),this.cameraPlayables.clear()}applyCameraTrackSettings(e,t){const a=e.cameraSettings??{fov:60,near:.1,far:1e3};t.fov=a.fov??60,t.near=a.near??.1,t.far=a.far??1e3,t.aspect=this.getCurrentCameraAspect()}getCurrentCameraAspect(){const e=this.viewController?.getBaseCamera();if(e instanceof a.PerspectiveCamera&&Number.isFinite(e.aspect)&&e.aspect>0)return e.aspect;const t=this.viewController?.getSourceCamera();return t instanceof a.PerspectiveCamera&&Number.isFinite(t.aspect)&&t.aspect>0?t.aspect:1}updateCameraControl(e){if(!this._cameraControlEnabled||!this.viewController||!this.sequenceData)return void this.releaseCameraOverride();const t=this.findActiveCameraShot(e);if(t)return void this.updateActiveCameraShot(t,e);const a=this.findBlendOutCameraShot(e);a?this.updateCameraBlendOut(a,e):this.releaseCameraOverride()}findActiveCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of H(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const r of s)this.isCameraClipActive(r,e)&&(t={track:a,clip:r,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,r)})}return t}findBlendOutCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of H(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const r of s){const s=Math.max(0,r.blendOutDuration??0);if(s<=0)continue;const i=this.getCameraClipEnd(r);e>=i&&e<i+s&&(t={track:a,clip:r,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,r)})}}return t}isCameraControlTrackEligible(e){return null==this._cameraControlTrackId||e.id===this._cameraControlTrackId}updateActiveCameraShot(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();this.activeCameraClipKey!==e.key&&(this.copyCameraState(this.viewController.getSourceCamera(),this.ensureCameraBlendSource()),this.activeCameraClipKey=e.key,this.cameraBlendOutClipKey=null);const s=Math.max(0,e.clip.blendInDuration??0),r=s<=0?1:this.evaluateCameraBlendAlpha((t-e.clip.startTime)/s,e.clip);r>=1?this.copyCameraState(e.camera,a):this.blendCameraState(this.ensureCameraBlendSource(),e.camera,a,r),a.updateProjectionMatrix(),this.ensureCameraOverride()}updateCameraBlendOut(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();if(this.cameraBlendOutClipKey!==e.key){const t=this.activeCameraClipKey===e.key?this.viewController.getSourceCamera():e.camera;this.copyCameraState(t,this.ensureCameraBlendOutSource()),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=e.key}const s=this.getCameraClipEnd(e.clip),r=Math.max(0,e.clip.blendOutDuration??0),i=r<=0?1:this.evaluateCameraBlendAlpha((t-s)/r,e.clip);this.blendCameraState(this.ensureCameraBlendOutSource(),this.viewController.getBaseCamera(),a,i),a.updateProjectionMatrix(),this.ensureCameraOverride()}ensureCameraBlendCamera(){return this.cameraBlendCamera||(this.cameraBlendCamera=new a.PerspectiveCamera(60,this.getCurrentCameraAspect(),.1,1e3),this.cameraBlendCamera.name="Sequence Camera Blend"),this.cameraBlendCamera}ensureCameraBlendSource(){return this.cameraBlendSource||(this.cameraBlendSource=new a.PerspectiveCamera),this.cameraBlendSource}ensureCameraBlendOutSource(){return this.cameraBlendOutSource||(this.cameraBlendOutSource=new a.PerspectiveCamera),this.cameraBlendOutSource}ensureCameraOverride(){this.viewController&&!this.cameraOverrideHandle&&(this.cameraOverrideHandle=this.viewController.pushCameraOverride(this.ensureCameraBlendCamera(),this))}releaseCameraOverride(){this.cameraOverrideHandle?.release(),this.cameraOverrideHandle=null,this.viewController?.releaseCameraOverridesForOwner(this),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null}isCameraClipActive(e,t){return t>=e.startTime&&t<this.getCameraClipEnd(e)}getCameraClipEnd(e){return e.startTime+Math.max(0,e.duration)}isCameraShakeClipActive(e,t){return t>=e.startTime&&t<this.getCameraShakeClipEnd(e)}getCameraShakeClipEnd(e){return e.startTime+Math.max(0,e.duration)}getCameraClipKey(e,t){return`${e.id}-${t.id}`}evaluateCameraBlendAlpha(e,t){return k(Math.max(0,Math.min(1,e)),t.blendInterpolation??"cubic")}syncCameraShakeContributions(){if(!this.viewController)return this.activeCameraShakeClipKeys.clear(),void this.nextCameraShakeClipKeys.clear();for(const e of this.activeCameraShakeClipKeys)this.nextCameraShakeClipKeys.has(e)||this.viewController.removeCameraShakeContribution(this,e);this.activeCameraShakeClipKeys.clear();for(const e of this.nextCameraShakeClipKeys)this.activeCameraShakeClipKeys.add(e);this.nextCameraShakeClipKeys.clear()}clearCameraShakeContributions(){this.activeCameraShakeClipKeys.clear(),this.nextCameraShakeClipKeys.clear(),this.viewController?.clearCameraShakeContributionsForOwner(this)}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(ae)),t.quaternion.copy(e.getWorldQuaternion(ie)),t.scale.copy(e.getWorldScale(se)),e instanceof a.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect):t.aspect=this.getCurrentCameraAspect(),t.layers.mask=e.layers.mask}blendCameraState(e,t,s,r){e.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!1),s.position.lerpVectors(e.getWorldPosition(ae),t.getWorldPosition(se),r),s.quaternion.slerpQuaternions(e.getWorldQuaternion(ie),t.getWorldQuaternion(ne),r),s.scale.lerpVectors(e.getWorldScale(ae),t.getWorldScale(se),r),e instanceof a.PerspectiveCamera&&t instanceof a.PerspectiveCamera?(s.fov=e.fov+(t.fov-e.fov)*r,s.near=e.near+(t.near-e.near)*r,s.far=e.far+(t.far-e.far)*r,s.aspect=t.aspect):t instanceof a.PerspectiveCamera?(s.fov=t.fov,s.near=t.near,s.far=t.far,s.aspect=t.aspect):s.aspect=this.getCurrentCameraAspect(),s.layers.mask=t.layers.mask}evaluateAudioTrack(e,t){if(!this.assetLoader||!e.clips||0===e.clips.length)return;const a=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(e,t);e.volume;for(const r of e.clips){const i=r.startTime+r.duration,n=t>=r.startTime&&t<i,o=`${e.id}-${r.id}`;if(n){if(this.activeAudioClips.has(o)||this.activeAudioClips.add(o),a){const a=this.audioByClip.get(o);a&&a.isPlaying||this.tryStartAudioClip(e,r,o,t,s)}const i=this.audioByClip.get(o);i&&this.applyAudioParameters(i,e,r,o,t,s)}else this.activeAudioClips.has(o)&&(this.activeAudioClips.delete(o),this.lastAudioStartAttemptTime.delete(o),this.audioStartInFlight.delete(o),this.stopAudioClip(o))}}tryStartAudioClip(e,t,a,s,r){if(this.audioStartInFlight.has(a))return;const i=this.lastAudioStartAttemptTime.get(a);if(void 0!==i&&s-i<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(a,s);const n=this.playAudioClip(e,t,a,s,r).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(a)===n&&this.audioStartInFlight.delete(a)});this.audioStartInFlight.set(a,n)}applyAudioParameters(e,t,s,r,i,n){const o=n.volume??1,l=Math.random(),c=s.volumeRandomization?(2*l-1)*s.volumeRandomization:0;let h=1;const u=i-s.startTime;u<s.fadeInDuration&&s.fadeInDuration>0?h=u/s.fadeInDuration:u>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(h=(s.duration-u)/s.fadeOutDuration);const p=Math.max(0,(t.volume??1)*o*(s.volume+c)*h);e.setVolume(p);let d=n.detune??0;if(s.pitchRandomization){d+=(2*Math.random()-1)*s.pitchRandomization}if(e.setDetune(d),e.hasPlaybackControl&&e.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,i=[],o=n.lowpass,l=n.highpass;let c=this.audioFilters.get(r);if(void 0!==o||void 0!==l)c||(c=s.createBiquadFilter(),this.audioFilters.set(r,c)),void 0!==o?(c.type="lowpass",c.frequency.value=o):void 0!==l&&(c.type="highpass",c.frequency.value=l),i.push(c);else if(c){try{c.disconnect()}catch{}this.audioFilters.delete(r)}const h=n.pan;if(!t.spatial&&e instanceof a.Audio&&void 0!==h&&"function"==typeof s.createStereoPanner){let e=this.audioPannerNodes.get(r);e||(e=s.createStereoPanner(),this.audioPannerNodes.set(r,e)),e.pan.value=h,i.push(e)}else{const e=this.audioPannerNodes.get(r);if(e){try{e.disconnect()}catch{}this.audioPannerNodes.delete(r)}}e.setFilters(i)}t.spatial&&e instanceof a.PositionalAudio?this.updatePositionalAudioTransform(e,t,s,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(e,t,s,r){let i=null,n=null;const o=s.attachedToTrackId||t.parent?.trackId,l=s.attachmentSocketName||t.parent?.socketName;if(o){const e=this.sequenceData?.tracks.find(e=>e.id===o);if(e){const t=this.getActiveObjectsForTrack(e);if(t.length>0){const e=t[0];if(i=ae,n=ie,e.getWorldPosition(i),e.getWorldQuaternion(n),l){const t=this.findSocket(e,l);t&&(t.getWorldPosition(i),t.getWorldQuaternion(n))}}}}if(i&&n){const t="number"==typeof r?a.MathUtils.clamp(r,0,1):1;if(t<1&&this.audioListener){const e=re;this.audioListener.getWorldPosition(e),i=i.clone().lerp(e,1-t)}e.position.copy(i),e.quaternion.copy(n),e.updateMatrixWorld()}}async playAudioClip(e,t,s,r,i){if(!this.assetLoader||!t.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(e){return void console.warn("Failed to resume audio context:",e)}this.stopAudioClip(s);const n=this.clearCounter;try{let r=this.audioBuffers.get(t.audioAssetId);if(!r){let e=this.loadingAudioBuffers.get(t.audioAssetId);e||(e=this.assetLoader.getAudioByAssetId(t.audioAssetId),this.loadingAudioBuffers.set(t.audioAssetId,e));try{r=await e,this.audioBuffers.set(t.audioAssetId,r)}finally{this.loadingAudioBuffers.delete(t.audioAssetId)}}if(n!==this.clearCounter)return;const o=this._time.value,l=t.startTime+t.duration;if(!(o>=t.startTime&&o<l))return;const c=Math.max(0,o-t.startTime),h=t.clipStartOffset+c*t.playbackRate;if(h>=r.duration||c>=t.duration)return;let u=this.audioByClip.get(s);const p=!0===e.spatial,d=u&&!0===u.isPositionalAudio;if(u&&p!==d&&(u.isPlaying&&u.stop(),u.disconnect(),this.audioByClip.delete(s),u=void 0),!u){if(p){const e=new a.PositionalAudio(this.audioListener);e.setRefDistance(10),e.setRolloffFactor(1),u=e}else u=new a.Audio(this.audioListener);this.world&&this.world.scene.add(u),this.audioByClip.set(s,u)}Math.min((t.duration-c)/t.playbackRate,(r.duration-h)/t.playbackRate);u.setLoopStart(t.clipStartOffset),u.setLoopEnd(Math.min(t.clipStartOffset+t.duration,r.duration)),u.setLoop(!0),u.setBuffer(r),this.applyAudioParameters(u,e,t,s,o,i),u.isPlaying||u.play()}catch(e){console.error(`Failed to play audio clip ${t.id}:`,e)}}stopAudioClip(e){const t=this.audioByClip.get(e);if(t){try{t.isPlaying&&t.stop()}catch(e){}t.parent&&t.parent.remove(t),this.audioByClip.delete(e)}const a=this.audioGainNodes.get(e);a&&(a.disconnect(),this.audioGainNodes.delete(e));const s=this.audioFilters.get(e);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(e)}const r=this.audioPannerNodes.get(e);if(r){try{r.disconnect()}catch{}this.audioPannerNodes.delete(e)}}stopAllAudio(){for(const e of this.audioByClip.keys())this.stopAudioClip(e);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(e,t){if(!this.vfxService||!this.world||!e.clips||0===e.clips.length)return;const a=new Set,s=new Map;for(const r of e.clips){const i=this.getVfxClipKey(e,r);s.set(i,r),this.isVfxClipActiveAtTime(r,t)&&a.add(i)}const r=[];for(const t of this.activeVfxClips)t.startsWith(`${e.id}-`)&&(a.has(t)||r.push(t));for(const e of r)this.activeVfxClips.delete(e);for(const[r,i]of s.entries()){const s=this.vfxActors.get(r);a.has(r)&&!this.activeVfxClips.has(r)?(this.activeVfxClips.add(r),this.ensureVfxActor(e,i,r)):a.has(r)&&s?(this.updateVfxTransform(e,s,t),this._state.value===SequencePlaybackState.Playing&&s.play()):s&&this.applyInactiveVfxClipBehavior(i,s,t)}}getVfxClipKey(e,t){return`${e.id}-${t.id}-${t.vfxAssetId}`}isVfxClipActiveAtTime(e,t){const a=e.startTime+e.duration;return t>=e.startTime&&t<a}resetVfxForTimeReset(e){const t=new Set;if(this.sequenceData)for(const a of H(this.sequenceData.tracks))if("vfx"===a.type)for(const s of a.clips??[])this.isVfxClipActiveAtTime(s,e)&&t.add(this.getVfxClipKey(a,s));this.activeVfxClips.clear();for(const[e,a]of this.vfxActors.entries())t.has(e)||(a.restart(),a.stop(),a.pause())}applyInactiveVfxClipBehavior(e,t,a){const s=e.endBehavior??"finish";if("finish"===s)return void t.stop();if("kill"===s)return void t.applyClipEndBehavior(s);const r=e.startTime+e.duration,i=Math.max(a-r,0),n=Math.max(0,e.expireWithinSeconds??.25),o=Math.max(0,n-i);t.applyClipEndBehavior(s,o)}async ensureVfxActor(e,t,a){if(!this.vfxService||!t.vfxAssetId)return;if(this.vfxActors.has(a)){const e=this.vfxActors.get(a);return e.restart(),void e.play()}const s=this.clearCounter;try{const r=await this.vfxService.createFromAssetId(t.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(r));const{position:i,rotation:n,scale:o}=this.getVfxTransform(e,t.startTime);r.object.position.copy(i),r.object.rotation.copy(n),r.object.scale.copy(o),this.vfxActors.set(a,r),this._state.value===SequencePlaybackState.Playing&&r.play()}catch(e){console.error(`Failed to create VFX actor for clip ${t.id}:`,e)}}getVfxTransform(e,t){const a=new c,s=new i,r=new c(1,1,1),n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,next:i,t:l}=I(n.keyframes,t);if(e&&(e.position&&a.fromArray(e.position),e.rotation&&s.fromArray([...e.rotation,"XYZ"]),e.scale&&r.fromArray(e.scale)),i&&e!==i&&e.time!==i.time){const t=k(l,e.interpolation);if(e.position&&i.position&&a.lerpVectors(ae.fromArray(e.position),se.fromArray(i.position),t),e.rotation&&i.rotation){ie.setFromEuler(oe.fromArray([...e.rotation,"XYZ"])),ne.setFromEuler(le.fromArray([...i.rotation,"XYZ"]));const a=new o;a.slerpQuaternions(ie,ne,t),s.setFromQuaternion(a)}e.scale&&i.scale&&r.lerpVectors(ae.fromArray(e.scale),se.fromArray(i.scale),t)}}else a.fromArray(e.position),s.fromArray([...e.rotation,"XYZ"]),r.fromArray(e.scale);return{position:a,rotation:s,scale:r}}updateVfxTransform(e,t,a){const{position:s,rotation:r,scale:i}=this.getVfxTransform(e,a);t.object.position.copy(s),t.object.rotation.copy(r),t.object.scale.copy(i)}resolveActorType(e){const t=this.actorFactory.classes[e];if(null!=t)return t;const a=d[e];return a||(console.warn(`Could not resolve actor type: ${e}`),null)}async spawnActorForClip(e,t,a,s){if(!this.world||!e.actorType)return null;const r=this.resolveActorType(e.actorType);if(!r)return null;try{return await this.world.spawnActor(r,a,s)}catch(t){return console.error(`Failed to spawn actor ${e.actorType}:`,t),null}}async spawnPrefabForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.prefabId)return null;try{const t=await this.assetLoader.getPrefabById(e.prefabId);if(!t)return null;return await this.world.spawnPrefab(t,a,s)}catch(t){return console.error(`Failed to spawn prefab ${e.prefabId}:`,t),null}}async spawnMeshForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.meshId)return null;try{const t=await this.assetLoader.getAsset(e.meshId),r=await this.assetLoader.getModelByAssetId(e.meshId),i=O.clone(r.scene);if(i.position.copy(a),i.rotation.copy(s),t){await this.assetLoader.applyMaterials(t,i);const e=t.mesh?.rescale;null!=e&&1!==e&&i.scale.multiplyScalar(e)}return this.world.scene.add(i),i}catch(t){return console.error(`Failed to spawn mesh ${e.meshId}:`,t),null}}despawnInstance(e){if(this.restorePropertySnapshotsForInstance(e),this.restoreMaterialSnapshotsForInstance(e),this.world)switch(e?.type){case"actor":this.world.removeActor(e.instance);break;case"prefab":this.world.removePrefab(e.instance);break;case"mesh":this.world.scene.remove(e.instance)}}despawnAll(){for(const e of this.spawnedInstances.values())this.despawnInstance(e);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(e,t,a){const s=new c,r=new i,n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e}=I(n.keyframes,a);e&&(e.position&&s.fromArray(e.position),e.rotation&&r.fromArray([...e.rotation,"XYZ"]))}else t.initialPosition&&s.fromArray(t.initialPosition),t.initialRotation&&r.fromArray([...t.initialRotation,"XYZ"]);return{position:s,rotation:r}}evaluateSpawnTrack(e,t,a){if(!e.clips||0===e.clips.length)return;const s=t||this.bindings.get(e.id);if(s&&s.target)for(const t of e.clips){const r=t.startTime+t.duration,i=a>=t.startTime&&a<r,n=`${e.id}-${t.id}`;if(i){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:s.target}));(s.target instanceof p?s.target.object:s.target)&&this.evaluateSubTracks(e.subTracks,s,a)}else this.activeClips.has(n)&&(this.restorePropertySnapshotsForTarget(s.target),this.restoreMaterialSnapshotsForTarget(s.target),this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const t of e.clips){const s=t.startTime+t.duration,r=a>=t.startTime&&a<s,i=`${e.id}-${t.id}`,n=this.spawnedInstances.has(i),o=this.pendingSpawns.has(i);if(!r||n||o){if(r&&n){const t=this.spawnedInstances.get(i);t&&"proxy"!==t.type&&this.evaluateSubTracks(e.subTracks,t,a)}else if(!r&&n){const e=this.spawnedInstances.get(i);e&&(this.despawnInstance(e),this.spawnedInstances.delete(i),this.activeClips.delete(i))}}else{const{position:a,rotation:s}=this.getInitialTransform(e,t,t.startTime);this.pendingSpawns.add(i),this.spawnForClip(e,t,a,s,i)}}}getInstanceObject(e){switch(e.type){case"actor":return e.instance.object;case"prefab":return e.instance.mainActor?.object||e.instance.object;case"mesh":return e.instance;case"proxy":return e.target instanceof p?e.target.object:e.target;default:return null}}async spawnForClip(e,t,a,r,i){const n=this.clearCounter;let o=null;try{switch(e.spawnType){case"actor":const s=await this.spawnActorForClip(e,t,a,r);s&&(o={type:"actor",instance:s});break;case"prefab":const i=await this.spawnPrefabForClip(e,t,a,r);i&&(o={type:"prefab",instance:i});break;case"mesh":const n=await this.spawnMeshForClip(e,t,a,r);n&&(o={type:"mesh",instance:n})}if(n!==this.clearCounter)return void(o&&this.despawnInstance(o));const l=this._time.value,c=l>=t.startTime&&l<t.startTime+t.duration;if(o&&c){const t=this.getInstanceObject(o);"proxy"===o.type||("actor"===o.type?o.target=o.instance:"prefab"===o.type?o.target=o.instance.mainActor||o.instance.object:o.target=t);e.subTracks.some(e=>"animation"===e.type)&&t&&(o.mixer=new s(t),o.activeActions=new Map),this.spawnedInstances.set(i,o),this.activeClips.add(i)}else o&&this.despawnInstance(o)}finally{this.pendingSpawns.delete(i)}}getPlayableObject(e){return e.target instanceof p?e.target.object:e.target??null}applyResolvedPropertyValue(e,t,a){if(!t||!e.propertyPath)return;const s=this.getPropertyResolution(t,e);if(!s)return;const r=this.getPropertySnapshotKey(e);this.capturePropertySnapshot(t,r,s);const n=function(e,t){switch(t.type){case y.Number:return"number"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.String:return"string"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return N(e,t.value);case y.Vector3:return U(e,t.value);case y.Vector4:return W(e,t.value);case y.Euler:return function(e,t){const a=Q(t,3);if(!a)return{applied:!1};const s=Array.isArray(t)&&"string"==typeof t[3]?t[3]:"XYZ";if(e instanceof i)return e.set(a[0],a[1],a[2],s),{applied:!0,value:e};return{applied:!0,value:new i(a[0],a[1],a[2],s)}}(e,t.value);case y.Color:return X(e,t.value);default:return{applied:!1}}}(s.owner[s.key],a);n.applied&&(s.owner[s.key]=n.value)}getPropertyResolution(e,t){const a=e,s=this.getPropertySnapshotKey(t);let r=this.propertyResolutionCache.get(a);if(r||(r=new Map,this.propertyResolutionCache.set(a,r)),r.has(s))return r.get(s)??null;const i=this.getPropertyPathSegments(t.propertyPath);if(0===i.length)return r.set(s,null),null;let n=e;for(let e=0;e<i.length-1;e++){if(!K(n))return r.set(s,null),null;n=n[i[e]]}if(!K(n))return r.set(s,null),null;const o={owner:n,key:i[i.length-1]};return r.set(s,o),o}getPropertyPathSegments(e){const t=this.propertyPathSegments.get(e);if(t)return t;const a=e.split(".").map(e=>e.trim()).filter(Boolean);return this.propertyPathSegments.set(e,a),a}getPropertySnapshotKey(e){return`${e.id}:${e.propertyPath}`}capturePropertySnapshot(e,t,a){const s=e;let r=this.propertySnapshots.get(s);if(r||(r=new Map,this.propertySnapshots.set(s,r)),r.has(t))return;const i=a.owner[a.key];r.set(t,{resolution:a,hadOwnProperty:Object.prototype.hasOwnProperty.call(a.owner,a.key),value:i,valueSnapshot:Z(i)})}restorePropertySnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restorePropertySnapshotsForTarget(e.instance);break;case"prefab":this.restorePropertySnapshotsForTarget(e.target??null),this.restorePropertySnapshotsForTarget(e.instance.mainActor??null),this.restorePropertySnapshotsForTarget(e.instance.object);break;case"proxy":this.restorePropertySnapshotsForTarget(e.target)}}restorePropertySnapshotsForTarget(e){if(!e)return;const t=e,a=this.propertySnapshots.get(t);if(a){for(const e of a.values())z(e);this.propertySnapshots.delete(t),this.propertyResolutionCache.delete(t)}}restoreAllPropertySnapshots(){for(const e of Array.from(this.propertySnapshots.keys()))this.restorePropertySnapshotsForTarget(e)}restoreMaterialSnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restoreMaterialSnapshotsForTarget(e.instance);break;case"prefab":this.restoreMaterialSnapshotsForTarget(e.target??null),this.restoreMaterialSnapshotsForTarget(e.instance.mainActor??null),this.restoreMaterialSnapshotsForTarget(e.instance.object);break;case"proxy":this.restoreMaterialSnapshotsForTarget(e.target)}}restoreMaterialSnapshotsForTarget(e){if(!e)return;const t=e;this.materialResolutionCache.delete(t);const a=this.materialSnapshots.get(t);if(a){for(const e of a.values())null==e.materialIndex?e.owner.material=e.originalMaterial:Array.isArray(e.owner.material)&&(e.owner.material[e.materialIndex]=e.originalMaterial),e.controlledMaterial!==e.originalMaterial&&e.controlledMaterial.dispose();this.materialSnapshots.delete(t)}}restoreAllMaterialSnapshots(){for(const e of Array.from(this.materialSnapshots.keys()))this.restoreMaterialSnapshotsForTarget(e)}applyResolvedMaterialValue(e,t,a){if(!t||!e.uniformName)return;if("asset"===S(e)&&!e.materialAssetId)return;const s=this.getMaterialSlotResolutions(t,e);for(const r of s){const s=this.ensureSequenceControlledMaterial(t,r),i=s.uniforms?.[e.uniformName];if(!i)continue;const n=G(i.value,a);n.applied&&(i.value=n.value,s.uniformsNeedUpdate=!0)}}getMaterialSlotResolutions(e,t){const a=e,s=S(t),r=`${t.id}:${s}:${t.materialAssetId??""}:${t.uniformName}`;let i=this.materialResolutionCache.get(a);i||(i=new Map,this.materialResolutionCache.set(a,i));const n=i.get(r);if(n)return n;const o=e instanceof p?e.object:e,l=[];return o.traverse(e=>{const a=e.material;if(Array.isArray(a))for(let s=0;s<a.length;s++){const r=a[s];$(r,t)&&l.push({owner:e,materialIndex:s,material:r,key:`${e.uuid}:${s}`})}else $(a,t)&&l.push({owner:e,materialIndex:null,material:a,key:`${e.uuid}:material`})}),i.set(r,l),l}ensureSequenceControlledMaterial(e,t){const a=e;let s=this.materialSnapshots.get(a);s||(s=new Map,this.materialSnapshots.set(a,s));const r=s.get(t.key);if(r)return r.controlledMaterial;const i=t.material.clone();return i.userData={...t.material.userData??{}},null==t.materialIndex?t.owner.material=i:Array.isArray(t.owner.material)&&(t.owner.material[t.materialIndex]=i),s.set(t.key,{owner:t.owner,materialIndex:t.materialIndex,originalMaterial:t.material,controlledMaterial:i}),i}async ensureAnimationClip(e){if(!this.assetLoader)return null;const t=this.animationClips.get(e);if(t)return t;const a=this.loadingAnimationClips.get(e);if(a)return a;const s=(async()=>{try{const t=await this.assetLoader.getAnimationClipByAssetId(e);return t&&this.animationClips.set(e,t),t}catch(t){return console.error(`Failed to load animation clip for asset ${e}:`,t),null}finally{this.loadingAnimationClips.get(e)===s&&this.loadingAnimationClips.delete(e)}})();return this.loadingAnimationClips.set(e,s),s}prepareAnimationPlayback(e,t,a){if(!B(a)){let e=t;return a.clipEndOffset>0&&(e=e.clone(),e.duration=Math.max(0,e.duration-a.clipEndOffset)),{clip:e,timeScale:a.playbackRate,startOffset:a.clipStartOffset}}return{clip:this.getPlayableAnimationClip(e,t,a,!1),timeScale:1,startOffset:0}}getPlayableAnimationClip(e,t,a,s){if(!B(a))return s?j.fromClip(t,!1):t;const r=`${a.id}:${s?"root":"base"}`,i=`${q(a)}|${s?"root":"base"}`,n=this.retimedAnimationClips.get(r);if(n&&n.assetId===e&&n.signature===i)return n.clip;const o=M(t,a),l=s?j.fromClip(o,!1):o;return this.retimedAnimationClips.set(r,{assetId:e,signature:i,clip:l}),l}getAnimationPlaybackLocalTime(e,t){const a=Math.max(0,t-e.startTime);return B(e)?a:a*e.playbackRate+e.clipStartOffset}clearRetimedAnimationClipCache(e){if(null!=e)for(const[t,a]of this.retimedAnimationClips.entries())a.assetId===e&&this.retimedAnimationClips.delete(t);else this.retimedAnimationClips.clear()}captureOriginalTransforms(){for(const e of this.bindings.values()){const t=e.target instanceof p?e.target.object:e.target;t&&(e.originalTransform={position:t.position.clone(),rotation:t.rotation.clone(),scale:t.scale.clone()})}}restoreOriginalTransforms(){for(const e of this.bindings.values())if(e.originalTransform){const t=e.target instanceof p?e.target.object:e.target;t&&(t.position.copy(e.originalTransform.position),t.rotation.copy(e.originalTransform.rotation),t.scale.copy(e.originalTransform.scale))}}stopAllAnimations(){for(const e of this.bindings.values()){for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer&&e.mixer.stopAllAction(),e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0),e.charAnimActionKeys?.clear()}}stopAllVfx(){for(const e of this.vfxActors.values())e.paused||e.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const e of this.vfxActors.values())this.world.removeActor(e);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.loadingAnimationClips.clear(),this.clearRetimedAnimationClipCache(),this.audioByClip.clear()}updateTrackParenting(e,t){const a=this.getActiveObjectsForTrack(e);if(0===a.length)return;let s=null;const r=e.parent?.trackId;if(r){const t=this.sequenceData?H(this.sequenceData.tracks).find(e=>e.id===r):void 0;if(t){const a=this.getActiveObjectsForTrack(t);if(a.length>0&&(s=a[0],e.parent?.socketName)){const t=this.findSocket(s,e.parent.socketName);t&&(s=t)}}}if(!s&&"camera"===e.type&&e.parentRole&&this.roleBindings.has(e.parentRole)){const t=this.roleBindings.get(e.parentRole);if(s=t instanceof p?t.object:t,e.parentRoleSocketName){const t=this.findSocket(s,e.parentRoleSocketName);t&&(s=t)}}for(const r of a)s?r.parent!==s&&(s.add(r),!t||"object"!==e.type&&"locator"!==e.type||(t.currentParent=s)):t?.currentParent&&t.currentParent===r.parent?this.restoreObjectParent(t,r):r.parent&&r.parent!==this.world?.scene&&"object"!==e.type&&"locator"!==e.type&&this.world?.scene.add(r)}findSocket(e,t){if(e.name===t)return e;if(e instanceof a.SkinnedMesh){const a=e.skeleton.bones.find(e=>e.name===t);if(a)return a}return e.getObjectByName(t)||null}getActiveObjectsForTrack(e){if("object"===e.type){const t=this.bindings.get(e.id);if(t&&t.target)return[t.target instanceof p?t.target.object:t.target]}else if("locator"===e.type){const t=this.bindings.get(e.id);if(t&&t.target instanceof n)return[t.target]}else{if("camera"===e.type)return[this.ensureSequenceCamera(e)];if("spawn"===e.type){const t=[];for(const[a,s]of this.spawnedInstances)if(a.startsWith(e.id+"-")&&this.activeClips.has(a)){const e=this.getInstanceObject(s);e&&t.push(e)}return t}if("vfx"===e.type){const t=[];for(const a of this.activeVfxClips)if(a.startsWith(e.id+"-")){const e=this.vfxActors.get(a);e&&t.push(e.object)}return t}}return[]}restoreObjectParent(e,t){e.originalParent?e.originalParent.add(t):this.world&&this.world.scene.add(t),e.currentParent=void 0}restoreOriginalParents(){for(const e of this.bindings.values())if(e.currentParent){const t=e.target instanceof p?e.target.object:e.target;t&&this.restoreObjectParent(e,t)}}evaluateAudioSubTracks(e,t){const a={};for(const s of e.subTracks)if("audioParameter"===s.type){const e=s,r=A(e.parameter),i=T(e.keyframes,t,{min:r.min,max:r.max});void 0!==i&&(a[e.parameter]=i)}return a}stringToRandom(e){let t=0;for(let a=0;a<e.length;a++){t=(t<<5)-t+e.charCodeAt(a),t&=t}const a=1e4*Math.sin(t);return a-Math.floor(a)}async refreshAsset(e){let t=!1;this.assetLoader?.clearCacheById(e),this.animationClips.delete(e),this.loadingAnimationClips.delete(e),this.clearRetimedAnimationClipCache(e),this.vfxService?.clearPool(e),t=this.refreshVfxActorsForAssetIds(new Set([e]))||t;for(const[a,s]of this.activePostProcessClips.entries())s.assetId===e&&(this.releasePostProcessClipEffect(a),t=!0);t=this.refreshSpawnedInstancesForClipKeys(this.getSpawnClipKeysForAsset(e))||t;const a=await this.getAssetOrNull(e);return"shaderGraph"===a?.type&&(t=await this.refreshShaderGraphDependentAssets(e)||t),t}refreshVfxActorsForAssetIds(e){let t=!1;for(const[a,s]of this.vfxActors.entries())this.vfxClipKeyUsesAnyAsset(a,e)&&(this.world&&this.world.removeActor(s),this.vfxActors.delete(a),this.activeVfxClips.delete(a),t=!0);return t}vfxClipKeyUsesAnyAsset(e,t){for(const a of t)if(e.endsWith(`-${a}`))return!0;return!1}refreshSpawnedInstancesForClipKeys(e){let t=!1;for(const[a,s]of this.spawnedInstances.entries())e.has(a)&&(this.despawnInstance(s),this.spawnedInstances.delete(a),this.activeClips.delete(a),t=!0);return t}getSpawnClipKeysForAsset(e){const t=new Set;if(!this.sequenceData)return t;for(const a of H(this.sequenceData.tracks))if("spawn"===a.type&&(a.prefabId===e||a.meshId===e))for(const e of a.clips)t.add(`${a.id}-${e.id}`);return t}async refreshShaderGraphDependentAssets(e){const t=await this.findSequenceVfxAssetIdsUsingShaderGraph(e);for(const e of t)this.vfxService?.clearPool(e);const a=this.refreshVfxActorsForAssetIds(t),s=this.refreshSpawnedInstancesForClipKeys(await this.findSpawnClipKeysUsingShaderGraph(e));return a||s}async findSequenceVfxAssetIdsUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of H(this.sequenceData.tracks))if("vfx"===s.type)for(const r of s.clips)null==r.vfxAssetId||t.has(r.vfxAssetId)||await this.assetUsesShaderGraph(r.vfxAssetId,e,a)&&t.add(r.vfxAssetId);return t}async findSpawnClipKeysUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of H(this.sequenceData.tracks))if("spawn"===s.type&&await this.spawnTrackUsesShaderGraph(s,e,a))for(const e of s.clips)t.add(`${s.id}-${e.id}`);return t}async spawnTrackUsesShaderGraph(e,t,a){if(null!=e.meshId&&await this.assetUsesShaderGraph(e.meshId,t,a))return!0;if(null!=e.prefabId&&await this.assetUsesShaderGraph(e.prefabId,t,a))return!0;for(const s of e.subTracks??[])if("material"===s.type&&null!=s.materialAssetId&&await this.assetUsesShaderGraph(s.materialAssetId,t,a))return!0;return!1}assetUsesShaderGraph(e,t,a,s=new Set){if(e===t)return Promise.resolve(!0);if(s.has(e))return Promise.resolve(!1);if(a.has(e))return a.get(e);const r=this.assetUsesShaderGraphUncached(e,t,a,s);return a.set(e,r),r}async assetUsesShaderGraphUncached(e,t,a,s){if(s.has(e))return!1;const r=await this.getAssetOrNull(e);if(null==r)return!1;const i=new Set(s);return i.add(e),!!this.materialAssetUsesShaderGraph(r,t)||("mesh"===r.type?this.materialAssignmentsUseShaderGraph(r.materialAssignments,t,a,i):"prefab"===r.type?this.sceneObjectsUseShaderGraph(r.prefab?.objects,t,a,i):"vfx"===r.type&&this.vfxAssetUsesShaderGraph(r,t,a,i))}materialAssetUsesShaderGraph(e,t){return"shaderGraph"===e.type?e.id===t:"asset"===e.material?.shaderGraph?.source&&e.material.shaderGraph.assetId===t}async materialAssignmentsUseShaderGraph(e,t,a,s){for(const r of e??[])if(null!=r.materialId&&"null"!==r.materialId&&await this.assetUsesShaderGraph(r.materialId,t,a,s))return!0;return!1}async sceneObjectsUseShaderGraph(e,t,a,s){for(const r of e??[]){if(await this.materialAssignmentsUseShaderGraph(r.materialAssignments,t,a,s))return!0;if(null!=r.assetId&&("asset_mesh"===r.type||"prefab"===r.type||"vfx"===r.type)&&await this.assetUsesShaderGraph(r.assetId,t,a,s))return!0;if(await this.sceneObjectsUseShaderGraph(r.children,t,a,s))return!0}return!1}async vfxAssetUsesShaderGraph(e,t,a,s){for(const r of e.vfx?.emitters??[])if(await this.emitterUsesShaderGraph(r,t,a,s))return!0;return!1}async emitterUsesShaderGraph(e,t,a,s){if(await this.emitterOutputUsesShaderGraph(e.output,t,a,s))return!0;for(const r of e.children??[])if(await this.emitterUsesShaderGraph(r,t,a,s))return!0;return!1}async emitterOutputUsesShaderGraph(e,t,a,s){const r=e.materialSource??("asset"===e.shaderGraph?.source?"shaderGraph":void 0);return"shaderGraph"===r&&"asset"===e.shaderGraph?.source&&e.shaderGraph.assetId===t||!("material"!==r||!("material"in e)||null==e.material||!await this.assetUsesShaderGraph(e.material,t,a,s))}async getAssetOrNull(e){if(!this.assetLoader)return null;try{return await this.assetLoader.getAsset(e)??null}catch{return null}}async invokeSequenceEvent(e,t,a,s){let r=!1;for(let e=0;e<s.length;e++)if(C(s[e])){r=!0;break}if(r)try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=v(s[e],this.sequenceEventAsyncResolvers);const r=await Promise.all(t);await a.call(e,...r)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}else try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=g(s[e],this.sequenceEventSyncResolvers);a.call(e,...t)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}}resolveSequenceEventActorReference(e){if(!this.world||null==e)return null;const t=e,a="object"==typeof t&&null!=t?.id?t.id:"string"==typeof t?t:null;if(null==a)return null;for(const e of this.world.actors){const t=e.object.userData.src??e.object.userData._src;if(t?.id===a)return e}return null}resolveSequenceEventSequence(e){return function(e){return"object"==typeof e&&null!=e&&"duration"in e&&"tracks"in e}(e)?new w(e):this.assetLoader&&"string"==typeof e?this.assetLoader.getSequenceById(e):null}async resolveSequenceEventAnimationClip(e){const t="string"==typeof e?e:"object"==typeof e&&null!=e?e.assetId??null:null;return null!=t&&this.assetLoader?this.assetLoader.getAnimationClipByAssetId(t):null}}function V(e){return e.options?.length>0||e.propertyType===y.Boolean||e.propertyType===y.String}function D(e){return e.valueType===y.Boolean||e.valueType===y.String}function K(e){return"object"==typeof e&&null!=e||"function"==typeof e}function G(e,t){switch(t.type){case y.Number:return function(e){if("number"==typeof e)return Number.isFinite(e)?{applied:!0,value:e}:{applied:!1};if("string"==typeof e){const t=parseFloat(e);return Number.isFinite(t)?{applied:!0,value:t}:{applied:!1}}return{applied:!1}}(t.value);case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return N(e,t.value);case y.Vector3:return U(e,t.value);case y.Vector4:return W(e,t.value);case y.Color:return function(e,t){if(e instanceof c){const a=ce.set(0);return Y(a,t)?(e.set(a.r,a.g,a.b),{applied:!0,value:e}):{applied:!1}}if(e instanceof h){const a=ce.set(0);return Y(a,t)?(e.set(a.r,a.g,a.b,e.w),{applied:!0,value:e}):{applied:!1}}return X(e,t)}(e,t.value);default:return{applied:!1}}}function $(e,t){const s=S(t);return function(e){return e instanceof a.Material||!0===e?.isMaterial}(e)&&null!=e.uniforms?.[t.uniformName]&&("parameterName"===s||e.userData?.assetId===t.materialAssetId)}function N(e,t){const a=Q(t,2);return a?e instanceof l?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new l(a[0],a[1])}:{applied:!1}}function U(e,t){const a=Q(t,3);return a?e instanceof c?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new c(a[0],a[1],a[2])}:{applied:!1}}function W(e,t){const a=Q(t,4);return a?e instanceof h?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new h(a[0],a[1],a[2],a[3])}:{applied:!1}}function X(e,t){if(e instanceof r)return Y(e,t)?{applied:!0,value:e}:{applied:!1};const a=new r;return Y(a,t)?{applied:!0,value:a}:{applied:!1}}function Q(e,t){if(!Array.isArray(e)||e.length<t)return null;const a=new Array(t);for(let s=0;s<t;s++){if("number"!=typeof e[s])return null;a[s]=e[s]}return a}function Y(e,t){return t instanceof r||"string"==typeof t||"number"==typeof t?(e.set(t),!0):!!(Array.isArray(t)&&t.length>=3)&&(e.setRGB("number"==typeof t[0]?t[0]:0,"number"==typeof t[1]?t[1]:0,"number"==typeof t[2]?t[2]:0),!0)}function Z(e){if(e instanceof l||e instanceof c||e instanceof h||e instanceof r||e instanceof i)return e.clone()}function z(e){const{owner:t,key:a}=e.resolution;e.hadOwnProperty?(!function(e,t){if(e instanceof l&&t instanceof l)return e.copy(t),!0;if(e instanceof c&&t instanceof c)return e.copy(t),!0;if(e instanceof h&&t instanceof h)return e.copy(t),!0;if(e instanceof r&&t instanceof r)return e.copy(t),!0;if(e instanceof i&&t instanceof i)return e.copy(t),!0}(e.value,e.valueSnapshot),t[a]=e.value):delete t[a]}function H(e){const t=[];for(const a of e)t.push(a),"group"===a.type&&t.push(...H(a.childTracks));return t}function J(e){if("string"!=typeof e)return null;const t=e.trim();return t.length>0?t:null}function ee(e){const t=new a.Group;t.name=`SequenceLocatorMarker:${e}`,t.renderOrder=1e3;const s=new a.AxesHelper(.35);s.renderOrder=1e3;const r=Array.isArray(s.material)?s.material:[s.material];for(const e of r)e.depthTest=!1,e.transparent=!0,e.opacity=.9,e.toneMapped=!1;t.add(s);const i=function(e){if("undefined"==typeof document)return null;const t=document.createElement("canvas");t.width=256,t.height=64;const s=t.getContext("2d");if(!s)return null;s.clearRect(0,0,t.width,t.height),s.fillStyle="rgba(16, 18, 24, 0.78)",function(e,t,a,s,r,i){const n=t+s,o=a+r;e.beginPath(),e.moveTo(t+i,a),e.lineTo(n-i,a),e.quadraticCurveTo(n,a,n,a+i),e.lineTo(n,o-i),e.quadraticCurveTo(n,o,n-i,o),e.lineTo(t+i,o),e.quadraticCurveTo(t,o,t,o-i),e.lineTo(t,a+i),e.quadraticCurveTo(t,a,t+i,a),e.closePath()}(s,0,8,t.width,48,8),s.fill(),s.font="24px sans-serif",s.textAlign="center",s.textBaseline="middle",s.fillStyle="#f8fafc",s.fillText(e||"Locator",t.width/2,t.height/2);const r=new a.CanvasTexture(t);r.needsUpdate=!0;const i=new a.SpriteMaterial({map:r,transparent:!0,depthTest:!1});i.toneMapped=!1;const n=new a.Sprite(i);return n.scale.set(.9,.225,1),n}(e);return i&&(i.position.set(0,.45,0),i.renderOrder=1001,t.add(i)),t.traverse(e=>{e.raycast=()=>{}}),t}function te(e){e.traverse(e=>{const t=e.material;if(Array.isArray(t))for(const e of t)e?.dispose?.(),e?.map?.dispose?.();else t?.dispose?.(),t?.map?.dispose?.()})}const ae=new c,se=new c,re=new c,ie=new o,ne=new o,oe=new i,le=new i,ce=new r;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as o,AttributeVec4Node as l,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as h,Vec3ExpressionNode as d,Vec4Node as m,attributeFloat as f,attributeVec3 as y,attributeVec4 as g,attributes as w,clamp as b,float as v,glslFunction as E,lambertMaterial as A,log as M,pow as x,rgb as P,rgba as S,smoothstep as I,standardMaterial as T,textureSampler2d as C,uniformFloat as R,uniforms as B,varying as k,varyingAttributes as j,varyingVec3 as D,varyingVec4 as G}from"three-shader-graph";import{prepareClassParameters as V,prepareShaderGraphParameters as F,prepareShapeParameters as z}from"../../scene/materializer.js";import{SerializedParamType as L}from"../../scene/model.js";import{ShapeLibrary as O}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as W,linearEyeDepth as Q}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as H,particleTimeUniformName as U,particleUniforms as q,particleVelcoityUniformName as J}from"../../shader-nodes/particle.js";import{sampleFlipbook as N}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as X}from"./initializsers.js";import{DelayRate as _,OnceRate as K}from"./rates.js";import{StretchedSprite as Y}from"./stretched-sprite.js";import{ThreeBlendingMode as Z}from"./vfx-asset.js";import{VfxBehaviourLibrary as $,VfxInitializserLibrary as ee}from"./vfx-defs.js";import{MultiRenderer as te}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ae}from"./vfx-collision-behaviour.js";import{getSpritePosition as re,SpriteNodeShaderMaterial as se}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ie}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as ne}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as oe,createBoundInitializer as le}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as ce}from"../../shader/graph/index.js";export async function materializeVfx(t,a,r,s,o,l,c,p,u){let h=a;for(;null!=h.parent;)h=h.parent;const d=new n;d.name="particle system local",a.add(d);const m=new n;m.name="particle system world";const f=new te(m,d,i,s),y=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await pe(e,r,c,p,y,o,l,u,a);return t.setParentRecursive(y),t.emit()}))).forEach(e=>y.addEmitter(e)),y.addRenderer(f).emit({onEnd:()=>{}}),{container:m,system:y,dispose:()=>{m.removeFromParent(),d.removeFromParent(),f.dispose()}}}async function pe(e,t,r,p,v,x,P,T,D){const V=function(e){let t;switch(e.rate.type){case"continuous":t=new _(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new K(e.rate.delay??0,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),t=new s(0,1/0)}return t}(e);let F;switch(e.output.type){case"decal":F=new a(await async function(e,t,a,r,s){if("shaderGraph"===me(e)){const t=await de(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return null!=e.renderOrder&&(a.renderOrder=e.renderOrder),a}}const n=!1!==e.unlit?new ie:new ne;n.color=new i.Color(e.color),n instanceof ie?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const o=n.build();o.blending=Z[e.blendingMode]??i.NormalBlending,o.transparent=!0,o.side=i.BackSide,o.depthTest=!1,null!=o&&!0===e.bloom&&(o.userData.hasBloom=!0);o.defines.IS_PARTICLE="";const l=new i.BoxGeometry(1,1,1),c=new i.Mesh(l,o);null!=e.renderOrder&&(c.renderOrder=e.renderOrder);return c}(e.output,t,r,p,P));break;case"sprite":F=new a(await async function(e,t,a,r,s){let n=null;const o=me(e);"shaderGraph"===o&&(n=await de(e,"sprite",a,r,s));null==n&&"shader"===o&&null!=e.shader&&(n=await he(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):ue,r=C(a);let s=r.sample(j.uv);e.flipbook?.enabled&&(s=N(r,w.uv,e.flipbook.columns,e.flipbook.rows,q.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),o=new h("color").rgb,l=R("opacity",1),c=Q.subtract(W).divide(Q);let p=l;switch(e.opacityChannel??"red"){case"none":break;case"red":p=p.multiply(s.r);break;case"alpha":p=p.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=b(c,0,1e3);p=p.multiply(I(0,.2*e.softness,t))}const d=re(n),m=S(o.multiply(s.rgb).multiplyScalar(e.intensity??1),p);var f=new se({color:m,emissive:m.rgb.multiplyScalar(p),transparent:!0,position:d,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});f.alphaHash=!0,null!=f&&!0===e.bloom&&(f.userData.hasBloom=!0);return f.blending=Z[e.blendingMode]??i.NormalBlending,f}(e,t));fe(n,e);const l=new i.Mesh(new i.PlaneGeometry(1,1),n);return l.name="sprite",l}(e.output,t,r,p,P));break;case"stretchedSprite":F=new a(await async function(e,t){"shaderGraph"===me(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):ue,r=C(a).sample(j.uv),s=G(new l("color")),n=s.rgb.multiply(r.rgb);let o=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":o=o.multiply(r.r);break;case"alpha":o=o.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=Q.subtract(W).divide(M(Q)),a=b(t,0,1e3);o=o.multiply(I(0,.2*e.softness,a))}const c=E(m,{position:w.position,offset:y("offset"),modelViewMatrix:B.modelViewMatrix,velocity:g("velocity"),size:y("size"),rotation:f("rotation")},"\n float lengthFactor = velocity.w;\n float avgSize = (size.x + size.y) * 0.5;\n\n vec4 mvPosition = modelViewMatrix * vec4( offset , 1.0 );\n vec3 viewVelocity = normalMatrix * velocity.xyz;\n float vlength = length(viewVelocity); \n mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, viewVelocity)) * avgSize; \n mvPosition.xyz -= (position.x + 0.5) * viewVelocity * (1.0 + lengthFactor / vlength) * avgSize;\n return projectionMatrix * mvPosition;\n ");var p=new se({color:S(n.multiplyScalar(e.intensity??1),o),alphaTest:.1,transparent:!0,position:c,uniforms:{color:{value:new i.Color(e.color)}}});null!=p&&!0===e.bloom&&(p.userData.hasBloom=!0);p.blending=Z[e.blendingMode]??i.NormalBlending;const u=new Y(new i.PlaneGeometry(1,1),p);return u.scaleFactor=e.scale,u}(e.output,t));break;case"shape":F=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const l=O[e.shape];if(null==l)return console.error(`No shape with type ${e.shape}`),new n;const p=z(e.params??{}),u=l.geometry(p);let h=null;const m=me(e);"shaderGraph"===m&&(h=await de(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await he(e,t,s));null==h&&(h="material"===m&&null!=e.material?ye(await t.getMaterial(e.material)):function(){const e=k(new d("instanceColor")).rgb,t=k(new o("particleData")).x;return new c({color:A({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());return fe(h,e),new i.Mesh(u,h)}(e.output,t,r,p,P));break;case"mesh":F=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const o=await t.getMesh(e.assetId),l=await t.getAsset(e.assetId),c=me(e);if("shaderGraph"===c||"shader"===c||"material"===c){let n;"shaderGraph"===c?n=await de(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await he(e,t,s):"material"===c&&null!=e.material&&(n=ye(await t.getMaterial(e.material))),fe(n,e),o.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=l.materialAssignments)for(const a of l.materialAssignments)o.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(o.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),1===p.length){const e=p[0];return e.updateWorldMatrix(!0,!0),e.updateMatrixWorld(),e.matrix.copy(e.matrixWorld),e.matrixWorld.decompose(e.position,e.quaternion,e.scale),e.removeFromParent(),e}return o}(e.output,t,r,p,P));break;case"trail":{const s="shaderGraph"===me(e.output)?await de(e.output,"trail",r,p,P,{trailBillboard:e.output.billboard??!1}):null;F=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:s instanceof i.ShaderMaterial?s:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,width:e.output.width,billboard:e.output.billboard??!1});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const H=new we(D);H.parent=v,H.setRate(V),H._space=e.output.space;const U=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=ee[e.type]).map(async e=>{const t=ee[e.type],a=await z(e.params??{});return le(t,e.params??{},a,T)}));U.push(F,new X),H.addInitializers(U);const J=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=$[e.type]).map(async e=>{const t=$[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==L.Curve&&(r.type=L.Curve);const a=await z(e.params??{},r,p);return oe(t,e.params??{},a,T)}).sort((e,t)=>e instanceof ae?1:0));J.push(new ge);for(const e of J)e instanceof ae&&(e.physics=x);H.addBehaviours(J);for(const a of e.children??[]){const e=await pe(a,t,r,p,v,x,P,T,D),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=H.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&H.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=H.eventDispatcher,n=new Map;H.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(H.detachChildEmitterFromParticle(t,e),n.delete(e.id))});let o="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":o="PARTICLE_COLLISION";break;case"start":o="PARTICLE_CREATED"}i.addEventListener(o,e=>{const t=s.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),H.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=H.system,t.emit()})}return H}const ue=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");async function he(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type,n=await V(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}async function de(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const o=await a.getAsset(n.assetId),l=o?.shaderGraph;if(null==l)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(l.target!==t)return console.warn(`Shader graph "${o.name}" targets "${l.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await F(e.shaderGraphParams??{},l,a,r,void 0,s.shaders),o=ce(l,{parameters:t,trailBillboard:i.trailBillboard});return o.userData.customShaderName=`shaderGraph:${n.assetId}`,fe(o,e),o}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}function me(e){return null!=e.materialSource?e.materialSource:"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}function fe(e,t){null!=e&&("bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=Z[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type&&(e.blending=Z[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")))}function ye(e){const t=k(new d("instanceColor")).rgb;let a,r=k(new o("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(P(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(j.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(j.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:P(e.emissive),emissiveIntensity:v(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:A({color:s}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class ge extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[H]||null!=t.uniforms[U]||t.uniforms[J])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;a instanceof c&&(null!=a.uniforms[H]&&(a.uniforms[H].value=this.energy),null!=a.uniforms[U]&&(a.uniforms[U].value=e.age),null!=a.uniforms[J]&&(a.uniforms[J].value=e.velocity))}})}}class we extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(be.copy(t),"local"===a&&"world"===r?be.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(ve.copy(this.transformRoot.matrixWorld).invert(),be.applyMatrix4(ve)),e.position.copy(be)):e.position.copy(t)}clone(){const e=new we(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const be=new i.Vector3,ve=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
|
|
1
|
+
import e,{Behaviour as t,Body as a,Emitter as r,Rate as s}from"@hology/nebula";import*as i from"three";import{Object3D as n}from"three";import{AttributeVec3Node as o,AttributeVec4Node as l,NodeShaderMaterial as c,RgbNode as p,UniformFloatNode as u,UniformVec3Node as h,Vec3ExpressionNode as d,Vec4Node as m,attributeFloat as f,attributeVec3 as y,attributeVec4 as g,attributes as w,clamp as b,float as v,glslFunction as E,lambertMaterial as A,log as M,pow as x,rgb as P,rgba as S,smoothstep as I,standardMaterial as T,textureSampler2d as C,uniformFloat as R,uniforms as B,varying as k,varyingAttributes as j,varyingVec3 as D,varyingVec4 as G}from"three-shader-graph";import{prepareClassParameters as V,prepareShaderGraphParameters as F,prepareShapeParameters as z}from"../../scene/materializer.js";import{SerializedParamType as L}from"../../scene/model.js";import{ShapeLibrary as O}from"../../scene/objects/shapes.js";import{fragmentLinearEyeDepth as W,linearEyeDepth as Q}from"../../shader-nodes/depth.js";import{particleEnergyUniformName as H,particleTimeUniformName as U,particleUniforms as q,particleVelcoityUniformName as J}from"../../shader-nodes/particle.js";import{sampleFlipbook as N}from"../../shader-nodes/texture-sequence.js";import{DefaultInitializer as X}from"./initializsers.js";import{DelayRate as _,OnceRate as K}from"./rates.js";import{StretchedSprite as Y}from"./stretched-sprite.js";import{ThreeBlendingMode as Z}from"./vfx-asset.js";import{VfxBehaviourLibrary as $,VfxInitializserLibrary as ee}from"./vfx-defs.js";import{MultiRenderer as te}from"./vfx-renderers.js";import{WorldCollisionBehaviour as ae}from"./vfx-collision-behaviour.js";import{getSpritePosition as re,SpriteNodeShaderMaterial as se}from"../../shader/sprite-shader.js";import{DecalUnlitShader as ie}from"../../shader/builtin/decal-unlit-shader.js";import{DecalStandardShader as ne}from"../../shader/builtin/decal-standard-shader.js";import{createBoundBehaviour as oe,createBoundInitializer as le}from"./vfx-binding-runtime.js";import{buildShaderGraphMaterial as ce}from"../../shader/graph/index.js";export async function materializeVfx(t,a,r,s,o,l,c,p,u){let h=a;for(;null!=h.parent;)h=h.parent;const d=new n;d.name="particle system local",a.add(d);const m=new n;m.name="particle system world";const f=new te(m,d,i,s),y=new e;return(await Promise.all(t.vfx.emitters.slice().sort((e,t)=>(t.output.renderOrder??0)-(e.output.renderOrder??0)).map(async e=>{const t=await pe(e,r,c,p,y,o,l,u,a);return t.setParentRecursive(y),t.emit()}))).forEach(e=>y.addEmitter(e)),y.addRenderer(f).emit({onEnd:()=>{}}),{container:m,system:y,dispose:()=>{m.removeFromParent(),d.removeFromParent(),f.dispose()}}}async function pe(e,t,r,p,v,x,P,T,D){const V=function(e){let t;switch(e.rate.type){case"continuous":t=new _(e.rate.delay??0,e.rate.count,e.rate.time,e.rate.duration);break;case"once":t=new K(e.rate.delay??0,e.rate.count);break;default:console.warn(`Failed to configure rate for emitter: ${JSON.stringify(e)}`),t=new s(0,1/0)}return t}(e);let F;switch(e.output.type){case"decal":F=new a(await async function(e,t,a,r,s){if("shaderGraph"===me(e)){const t=await de(e,"decal",a,r,s);if(null!=t){const a=new i.Mesh(new i.BoxGeometry(1,1,1),t);return null!=e.renderOrder&&(a.renderOrder=e.renderOrder),a}}const n=!1!==e.unlit?new ie:new ne;n.color=new i.Color(e.color),n instanceof ie?n.intensity=e.intensity??1:n.emissiveIntensity=e.intensity??1;if(e.colorMap){const a=await t.getTexture(e.colorMap);n.colorMap=a}if(e.alphaMap){const a=await t.getTexture(e.alphaMap);n.alphaMap=a}const o=n.build();o.blending=Z[e.blendingMode]??i.NormalBlending,o.transparent=!0,o.side=i.BackSide,o.depthTest=!1,null!=o&&!0===e.bloom&&(o.userData.hasBloom=!0);o.defines.IS_PARTICLE="";const l=new i.BoxGeometry(1,1,1),c=new i.Mesh(l,o);null!=e.renderOrder&&(c.renderOrder=e.renderOrder);return c}(e.output,t,r,p,P));break;case"sprite":F=new a(await async function(e,t,a,r,s){let n=null;const o=me(e);"shaderGraph"===o&&(n=await de(e,"sprite",a,r,s));null==n&&"shader"===o&&null!=e.shader&&(n=await he(e,t,s));null==n&&(n=await async function(e,t){const a=null!=e.texture?await t.getTexture(e.texture):ue,r=C(a);let s=r.sample(j.uv);e.flipbook?.enabled&&(s=N(r,w.uv,e.flipbook.columns,e.flipbook.rows,q.time,e.flipbook.fps,e.flipbook.mode));const n=new u("rotation",0),o=new h("color").rgb,l=R("opacity",1),c=Q.subtract(W).divide(Q);let p=l;switch(e.opacityChannel??"red"){case"none":break;case"red":p=p.multiply(s.r);break;case"alpha":p=p.multiply(s.a)}if("number"==typeof e.softness&&e.softness>0){const t=b(c,0,1e3);p=p.multiply(I(0,.2*e.softness,t))}const d=re(n),m=S(o.multiply(s.rgb).multiplyScalar(e.intensity??1),p);var f=new se({color:m,emissive:m.rgb.multiplyScalar(p),transparent:!0,position:d,alphaTest:1e-4,uniforms:{color:{value:new i.Color(e.color)}}});f.alphaHash=!0,null!=f&&!0===e.bloom&&(f.userData.hasBloom=!0);return f.blending=Z[e.blendingMode]??i.NormalBlending,f}(e,t));fe(n,e);const l=new i.Mesh(new i.PlaneGeometry(1,1),n);return l.name="sprite",l}(e.output,t,r,p,P));break;case"stretchedSprite":F=new a(await async function(e,t){"shaderGraph"===me(e)&&console.warn("Shader graph materials are not supported for stretched sprite VFX outputs yet. Falling back to the default stretched sprite material.");const a=null!=e.texture?await t.getTexture(e.texture):ue,r=C(a).sample(j.uv),s=G(new l("color")),n=s.rgb.multiply(r.rgb);let o=s.w;switch(e.opacityChannel??"red"){case"none":break;case"red":o=o.multiply(r.r);break;case"alpha":o=o.multiply(r.a)}if("number"==typeof e.softness&&e.softness>0){const t=Q.subtract(W).divide(M(Q)),a=b(t,0,1e3);o=o.multiply(I(0,.2*e.softness,a))}const c=E(m,{position:w.position,offset:y("offset"),modelViewMatrix:B.modelViewMatrix,velocity:g("velocity"),size:y("size"),rotation:f("rotation")},"\n float lengthFactor = velocity.w;\n float avgSize = (size.x + size.y) * 0.5;\n\n vec4 mvPosition = modelViewMatrix * vec4( offset , 1.0 );\n vec3 viewVelocity = normalMatrix * velocity.xyz;\n float vlength = length(viewVelocity); \n mvPosition.xyz += position.y * normalize(cross(mvPosition.xyz, viewVelocity)) * avgSize; \n mvPosition.xyz -= (position.x + 0.5) * viewVelocity * (1.0 + lengthFactor / vlength) * avgSize;\n return projectionMatrix * mvPosition;\n ");var p=new se({color:S(n.multiplyScalar(e.intensity??1),o),alphaTest:.1,transparent:!0,position:c,uniforms:{color:{value:new i.Color(e.color)}}});null!=p&&!0===e.bloom&&(p.userData.hasBloom=!0);p.blending=Z[e.blendingMode]??i.NormalBlending;const u=new Y(new i.PlaneGeometry(1,1),p);return u.scaleFactor=e.scale,u}(e.output,t));break;case"shape":F=new a(await async function(e,t,a,r,s){if(null==e.shape)return console.log("Shape is null"),new n;const l=O[e.shape];if(null==l)return console.error(`No shape with type ${e.shape}`),new n;const p=z(e.params??{}),u=l.geometry(p);let h=null;const m=me(e);"shaderGraph"===m&&(h=await de(e,"surface",a,r,s));null==h&&"shader"===m&&null!=e.shader&&(h=await he(e,t,s));null==h&&(h="material"===m&&null!=e.material?ye(await t.getMaterial(e.material)):function(){const e=k(new d("instanceColor")).rgb,t=k(new o("particleData")).x;return new c({color:A({color:e}).rgb.rgba(t),opacity:t,transparent:!0})}());return fe(h,e),new i.Mesh(u,h)}(e.output,t,r,p,P));break;case"mesh":F=new a(await async function(e,t,a,r,s){if(null==e.assetId)return console.warn("Can't use mesh as particle without asset id"),new n;const o=await t.getMesh(e.assetId),l=await t.getAsset(e.assetId),c=me(e);if("shaderGraph"===c||"shader"===c||"material"===c){let n;"shaderGraph"===c?n=await de(e,"surface",a,r,s):"shader"===c&&null!=e.shader?n=await he(e,t,s):"material"===c&&null!=e.material&&(n=ye(await t.getMaterial(e.material))),fe(n,e),o.traverse(e=>{e instanceof i.Mesh&&null!=n&&(e.material=n)})}else{const e=[];if(null!=l.materialAssignments)for(const a of l.materialAssignments)o.traverse(r=>{r instanceof i.Mesh&&r.material instanceof i.Material&&r.material.color instanceof i.Color&&(r.material.name!=a.name&&null!=a.name||"#"+r.material.color.getHexString()!==a.color||e.push(t.getMaterial(a.materialId).then(e=>r.material=e)))});await Promise.all(e)}const p=[];if(o.traverse(e=>{e instanceof i.Mesh&&p.push(e)}),1===p.length){const e=p[0];return e.updateWorldMatrix(!0,!0),e.updateMatrixWorld(),e.matrix.copy(e.matrixWorld),e.matrixWorld.decompose(e.position,e.quaternion,e.scale),e.removeFromParent(),e}return o}(e.output,t,r,p,P));break;case"trail":{const s="shaderGraph"===me(e.output)?await de(e.output,"trail",r,p,P,{trailBillboard:e.output.billboard??!1}):null;F=new a({type:"trail",taper:e.output.taper,headGeometry:null,material:s instanceof i.ShaderMaterial?s:void 0,dragTexture:!1,texture:null!=e.output.texture?await t.getTexture(e.output.texture):null,opacityChannel:e.output.opacityChannel,color:e.output.color,colorEnd:e.output.colorEnd,intensity:e.output.intensity??1,intensityEnd:e.output.intensityEnd??1,length:e.output.length,opacityStart:e.output.opacityStart,opacityEnd:e.output.opacityEnd,bloom:e.output.bloom,scrollSpeed:e.output.scrollSpeed,width:e.output.width,billboard:e.output.billboard??!1});break}default:console.error("Failed to create particly system body: "+JSON.stringify(e))}const H=new we(D);H.parent=v,H.setRate(V),H._space=e.output.space;const U=await Promise.all(e.initializers.filter(e=>!1!==e.enabled).filter(e=>null!=ee[e.type]).map(async e=>{const t=ee[e.type],a=await z(e.params??{});return le(t,e.params??{},a,T)}));U.push(F,new X),H.addInitializers(U);const J=await Promise.all(e.behaviours.filter(e=>!1!==e.enabled).filter(e=>null!=$[e.type]).map(async e=>{const t=$[e.type];for(const[a,r]of Object.entries(e.params))t.parameters&&null!=t.parameters[a]&&"curve"===t.parameters[a].type&&r.type!==L.Curve&&(r.type=L.Curve);const a=await z(e.params??{},r,p);return oe(t,e.params??{},a,T)}).sort((e,t)=>e instanceof ae?1:0));J.push(new ge);for(const e of J)e instanceof ae&&(e.physics=x);H.addBehaviours(J);for(const a of e.children??[]){const e=await pe(a,t,r,p,v,x,P,T,D),s=new EmitterPool(()=>{const t=e.clone();return t.onExpired=()=>{const e=H.childEmitters.findIndex(e=>e.id===t.id);-1!=e&&H.childEmitters.splice(e,1),null!=t.parentParticle&&(n.delete(t.parentParticle.id),t.parentParticle=null),s.release(t)},t}),i=H.eventDispatcher,n=new Map;H.bindEmitterEvent=!0,i.addEventListener("PARTICLE_DEAD",e=>{const t=n.get(e.id);null!=t&&(H.detachChildEmitterFromParticle(t,e),n.delete(e.id))});let o="PARTICLE_CREATED";if("spawnEvent"in a)switch(a.spawnEvent){case"collision":o="PARTICLE_COLLISION";break;case"start":o="PARTICLE_CREATED"}i.addEventListener(o,e=>{const t=s.get();t.age=0,t.totalEmitTimes=-1,t.particles.length=0,t.currentEmitTime=0,t.cID=0,t.eventDispatcher.removeAllEventListeners(),H.childEmitters.push(t),n.set(e.id,t),t.parentParticle=e,t.system=H.system,t.emit()})}return H}const ue=(new i.TextureLoader).load("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJkSURBVHjaxJeJbusgEEW94S1L//83X18M2MSuLd2pbqc4wZGqRLrKBsyZhQHny7Jk73xVL8xpVhWrcmiB5lX+6GJ5YgQ2owbAm8oIwH1VgKZUmGcRqKGGPgtEQQAzGR8hQ59fAmhJHSAagigJ4E7GPWRXOYC6owAd1JM6wDQPADyMWUqZRMqmAojHp1Vn6EQQEgUNMJLnUjMyJsM49wygBkAPw9dVFwXRkncCIIW3GRgoTQUZn6HxCMAFEFd8TwEQ78X4rHbILoAUmeT+RFG4UhQ6MiIAE4W/UsYFjuVjAIa2nIY4q1R0GFtQWG3E84lqw2GO2QOoCKBVu0BAPgDSU0eUDjjQenNkV/AW/pWChhpMTelo1a64AOKM30vk18GzTHXCNtI/Knz3DFBgsUqBGIjTInXRY1yA9xkVoqW5tVq3pDR9A0hfF5BSARmVnh7RMDCaIdcNgbPBkgzn1Bu+SfIEFSpSBmkxyrMicb0fAEuCZrWnN89veA/4XcakrPcjBWzkTuLjlbfTQPOlBhz+HwkqqPXmPQDdrQItxE1moGof1S74j/8txk8EHhTQrAE8qlwfqS5yukm1x/rAJ9Jiaa6nyATqD78aUVBhFo8b1V4DdTXdCW+IxA1zB4JhiOhZMEWO1HqnvdoHZ4FAMIhV9REF8FiUm0jsYPEJx/Fm/N8OhH90HI9YRHesWbXXZwAShU8qThe7H8YAuJmw5yOd989uRINKRTJAhoF8jbqrHKfeCYdIISZfSq26bk/K+yO3YvfKrVgiwQBHnwt8ynPB25+M8hceTt/ybPhnryJ78+tLgAEAuCFyiQgQB30AAAAASUVORK5CYII=");async function he(e,t,a){const r=a.get(e.shader);if(null==r)return console.error("No shader exists with name "+e.shader),new i.Material;const s=new r.type,n=await V(e.shaderParams??{},r.type,t,{getTexture:e=>t.getTexture(e.id),getMaterial:e=>t.getMaterial(e.id),getMesh:e=>t.getMesh(e.id)},void 0,void 0,void 0,void 0,void 0,s);return Object.assign(s,n),s.build()}async function de(e,t,a,r,s,i={}){const n=e.shaderGraph;if("asset"!==n?.source||null==n.assetId)return console.warn(`Missing shader graph asset reference for ${e.type} VFX output`),null;const o=await a.getAsset(n.assetId),l=o?.shaderGraph;if(null==l)return console.warn(`Missing shader graph asset "${n.assetId}" for ${e.type} VFX output`),null;if(l.target!==t)return console.warn(`Shader graph "${o.name}" targets "${l.target}" but ${e.type} VFX output expects "${t}"`),null;try{const t=await F(e.shaderGraphParams??{},l,a,r,void 0,s.shaders),o=ce(l,{parameters:t,trailBillboard:i.trailBillboard});return o.userData.customShaderName=`shaderGraph:${n.assetId}`,fe(o,e),o}catch(e){return console.log("Shader graph VFX runtime error: "+e,e),null}}function me(e){return null!=e.materialSource?e.materialSource:"asset"===e.shaderGraph?.source?"shaderGraph":"shader"in e&&null!=e.shader?"shader":"mesh"!==e.type&&"shape"!==e.type||null==e.material?"default":"material"}function fe(e,t){null!=e&&("bloom"in t&&!0===t.bloom&&(e.userData.hasBloom=!0),"sprite"===t.type?(e.blending=Z[t.blendingMode]??i.NormalBlending,!0===t.lockY&&e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.LOCK_Y_AXIS="")):"decal"===t.type?(e.blending=Z[t.blendingMode]??i.NormalBlending,e.transparent=!0,e.side=i.BackSide,e.depthTest=!1,e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE="")):"shape"!==t.type&&"mesh"!==t.type||e instanceof i.ShaderMaterial&&(e.defines??(e.defines={}),e.defines.IS_PARTICLE=""))}function ye(e){const t=k(new d("instanceColor")).rgb;let a,r=k(new o("particleData")).x;if(e instanceof i.MeshStandardMaterial||e instanceof i.MeshLambertMaterial||e instanceof i.MeshBasicMaterial){let s=t.multiply(P(e.color));null!=e.map&&(s=s.multiply(C(e.map).sample(j.uv).rgb)),null!=e.alphaMap&&(r=r.multiply(C(e.alphaMap).sample(j.uv).r)),e instanceof i.MeshStandardMaterial?a=new c({color:T({color:s,emissive:P(e.emissive),emissiveIntensity:v(e.emissiveIntensity),roughness:e.roughness,metalness:e.metalness}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshLambertMaterial?a=new c({color:A({color:s}).rgb.rgba(r),emissive:P(e.emissive).multiplyScalar(e.emissiveIntensity),transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}):e instanceof i.MeshBasicMaterial&&(a=new c({color:s.rgb.rgba(r),emissive:s.rgb,transparent:e.transparent,opacity:r,alphaTest:e.alphaTest}))}else e instanceof c&&(a=e.clone(),a.defines.IS_PARTICLE="");return null!=a&&(!0===e.userData?.hasBloom&&null!=a&&(a.userData.hasBloom=!0),a.side=e.side,a.transparent=e.transparent),a??e}class ge extends t{initialize(e){e.body instanceof i.Object3D&&e.body.traverse(e=>{if(e instanceof i.Mesh){const t=e.material;t instanceof c&&(null!=t.uniforms[H]||null!=t.uniforms[U]||t.uniforms[J])}})}mutate(e,t,a){this.energize(e,t),e.target instanceof n&&e.target.traverse(t=>{if(t instanceof i.Mesh){const a=t.material;a instanceof c&&(null!=a.uniforms[H]&&(a.uniforms[H].value=this.energy),null!=a.uniforms[U]&&(a.uniforms[U].value=e.age),null!=a.uniforms[J]&&(a.uniforms[J].value=e.velocity))}})}}class we extends r{constructor(e){super(),this.transformRoot=e,this.childEmitters=[],this.bindEmitterEvent=!1,this.onExpired=()=>{}}clearParticlesRecursive(){let e=this.childEmitters.length;for(;e--;){const t=this.childEmitters[e];t.stopEmit(),t.clearParticlesRecursive(),t.onExpired()}this.childEmitters.length=0;let t=this.particles.length;for(;t--;){const e=this.particles[t];this.system?.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),null!=this.system?this.system.pool.expire(e.reset()):e.reset()}this.particles.length=0}detachChildEmitterFromParticle(e,t){this.copyPositionToChildSpace(e,t.position),e.parentParticle=null,e.stopEmit()}update(e){if(!this.isEmitting&&0===this.particles.length&&0===this.childEmitters.length)return;this.age+=e,(this.dead||this.age>=this.life)&&this.destroy(),this.isEmitting&&this.generate(e),this.integrate(e);let t=this.particles.length;for(;t--;){const e=this.particles[t];e.dead&&(this.system&&this.system.dispatch("PARTICLE_DEAD",e),this.bindEmitterEvent&&this.dispatch("PARTICLE_DEAD",e),this.system.pool.expire(e.reset()),this.particles.splice(t,1))}this.updateEmitterBehaviours(e),this.updateChildren(e),this.isEmitting||0!==this.particles.length||0!==this.childEmitters.length||this.onExpired()}updateChildren(e){for(const t of this.childEmitters)null!=t.parentParticle&&this.copyPositionToChildSpace(t,t.parentParticle.position),t.update(e)}copyPositionToChildSpace(e,t){const a=this._space??"world",r=e._space??"world";a!==r&&null!=this.transformRoot?(be.copy(t),"local"===a&&"world"===r?be.applyMatrix4(this.transformRoot.matrixWorld):"world"===a&&"local"===r&&(ve.copy(this.transformRoot.matrixWorld).invert(),be.applyMatrix4(ve)),e.position.copy(be)):e.position.copy(t)}clone(){const e=new we(this.transformRoot);return e.setRate(this.rate.clone()),e.behaviours=this.behaviours,e.initializers=this.initializers,e._space=this._space,e.body=this.body,e.parent=this.parent,e.system=this.system,e}setParentRecursive(e){this.system=e,this.childEmitters.forEach(t=>t.setParentRecursive(e))}}const be=new i.Vector3,ve=new i.Matrix4;export class EmitterPool{constructor(e){this.creator=e,this.instances=[]}get(){0==this.instances.length&&this.instances.push(this.creator());return this.instances.pop()}release(e){this.instances.push(e)}dispose(){this.instances.length=0}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as o}from"tslib";import i from"@dimforge/rapier3d-compat";import{takeUntil as e}from"rxjs";import*as s from"three";import{ArrowHelper as n,MathUtils as r,Vector3 as a}from"three";import{RootMotionClip as c}from"../../../../../gameplay/animation/root-motion.js";import{ActionInput as h,AxisInput as l,RotationInput as p}from"../../../../../gameplay/input/index.js";import{PhysicsSystem as m,RayTestResult as u}from"../../../../../gameplay/services/physics/physics-system.js";import{CapsuleCollisionShape as d}from"../../../../../scene/collision/collision-shape.js";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import{ActorComponent as g,Component as f}from"../../../component.js";import{CharacterMovementMode as M}from"./modes.js";import{inject as S}from"../../../../../gameplay/inject.js";import{Parameter as v}from"../../../../../shader/parameter.js";const w=new a,x=new a,A=1/30,b=131070;let I=class extends g{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}set normalNudgeFactor(t){this.cc.setNormalNudgeFactor(t)}get normalNudgeFactor(){return this.cc.normalNudgeFactor()}constructor(){super(),this.directionInput=new l,this.jumpInput=new h,this.sprintInput=new h,this.rotationInput=new p,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=r.degToRad(70),this.maxSlopeClimbAngle=r.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.normalizedDirection=!0,this.characterCollision=!1,this.allowRootMotionJumpCancel=!1,this.enabled=!0,this.velocity=new a,this.mode=M.walking,this.isSprinting=!1,this.pressedJump=!1,this.rayTestResult=new u,this.physicsSystem=S(m),this.resetRootMotion=!1,this.rootMotionOptions={},this.rotateToMovementDirection=!1,this.smoothRotation=!0,this.rotationSpeed=40,this.maxRotationSpeed=100,this.impulse=new a,this.impulseDamping=2;const t=this.cc=this.physicsSystem.getCharacterController(.1);t.enableSnapToGround(.1),t.enableAutostep(0,.1,!1)}onInit(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:y.kinematic,continousCollisionDetection:!1,friction:0,restitution:.5,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation);let o=this.rotationInput.rotation.y;const i=new a,n=new a,h=new a,l=new a,p=new a,m=new a,u=new a;let d=0,g=null;const f=new a,S=new a,v=new a,I=new a,R=new a,z=new a,C=new a,D=this.characterCollision?null:b;let E=this.rotateToMovementDirection;this.physicsSystem.beforeStep.pipe(e(this.disposed)).subscribe(e=>{if(this.checkGrounded(e),!this.enabled)return;if(S.set(0,0,0),null==this.rootMotionAction||this.rootMotionAction.isRunning()||this.clearRootMotionAction(this.rootMotionAction),null!=this.rootMotionAction&&this.rootMotionOptions.cancelWithJump&&this.jumpInput.activated&&(this.isGrounded||this.jumpInAir)){const t=this.rootMotionAction,o=this.rootMotionOptions.onJumpCancel;this.clearRootMotionAction(t),t.stop(),o?.()}if(null!=this.rootMotionAction){if(this.rootMotionAction.getClip()instanceof c){const t=this.rootMotionInterpolant;this.resetRootMotion&&(f.fromArray(t.evaluate(0)),this.resetRootMotion=!1),z.fromArray(t.evaluate(this.rootMotionAction.time)),S.subVectors(z,f),f.copy(z);(this.rootMotionRootBone??this.rootMotionAction.getRoot()).getWorldScale(R),S.multiply(R)}}e>A&&(e=A);const y=null!=this.rootMotionAction&&this.rootMotionAction.enabled,b=y&&0!==S.lengthSq();this.pressedJump=!y&&this.jumpInput.activated,this.isSprinting=!y&&this.sprintInput.activated;const H=E!==this.rotateToMovementDirection;let B=r.euclideanModulo(this.rotationInput.rotation.y-o+Math.PI,2*Math.PI)-Math.PI;H&&(this.actor.object.quaternion.setFromEuler(F.set(0,this.rotationInput.rotation.y,0)),E?this.actor.object.quaternion.setFromEuler(F.set(0,this.rotationInput.rotation.y,0)):(B=0,o=this.rotationInput.rotation.y),E=this.rotateToMovementDirection),h.copy(this.actor.position),l.set(-this.directionInput.vector.x,0,this.directionInput.vector.y).normalize();const N=!this.rotateToMovementDirection&&l.z<0?this.maxSpeedBackwards:(this.isSprinting?this.maxSpeedSprint:this.maxSpeed)*(this.normalizedDirection?1:Math.min(1,this.directionInput.vector.length()));if(u.set(0,0,0),y)o=this.rotationInput.rotation.y;else if(this.rotateToMovementDirection&&!y){if(l.lengthSq()>0&&this.mode!=M.falling){const t=this.smoothRotation,i=F.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,s=Math.atan2(l.x,l.z),n=.99*this.rotationInput.rotation.y+s;if(t){r.clamp(.5*l.dot(p)+.5,.001,1);const t=r.euclideanModulo(n-i+Math.PI,2*Math.PI)-Math.PI;let o=r.clamp(t*this.rotationSpeed*e,-this.maxRotationSpeed*e,this.maxRotationSpeed*e);Math.abs(o)>Math.abs(t)&&(o=t),this.actor.object.quaternion.setFromEuler(F.set(0,i+o,0))}else this.actor.object.quaternion.setFromEuler(F.set(0,n,0));p.lerp(l,e*this.rotationSpeed),o+=B,u.copy(this.actor.object.getWorldDirection(k).normalize())}}else b||(o+=B,this.actor.object.quaternion.multiply(q.setFromEuler(F.set(0,B,0))),l.lengthSq()>0&&u.copy(l).applyQuaternion(this.actor.object.quaternion).normalize());if(C.set(0,0,0),this.rayTestResult.hasHit&&null!=this.rayTestResult.actor&&this.physicsSystem.getLinearVelocity(this.rayTestResult.actor,C),this.mode===M.walking?(0!==u.lengthSq()?(d=Math.min(N,d),d=r.lerp(d,N,4*e)):d=0,m.copy(u).multiplyScalar(d),this.pressedJump&&(this.mode=M.falling,this.velocity.copy(m),this.velocity.y=this.jumpVelocity),m.y=e*this.getEffectiveGravity(),m.add(C)):this.mode===M.falling&&(this.pressedJump&&this.jumpInAir&&(this.mode=M.falling,this.velocity.copy(m),this.velocity.y=this.jumpVelocity),this.velocity.y+=e*this.getEffectiveGravity(),m.copy(this.velocity),m.addScaledVector(u,this.fallingMovementControl),this.fallingReorientation&&m.applyAxisAngle(new a(0,1,0),B)),b&&(v.copy(S).applyQuaternion(this.actor.quaternion),I.copy(v).divideScalar(e),this.mode===M.walking?(m.x=I.x+C.x,m.z=I.z+C.z):(m.x=I.x,m.z=I.z),l.lengthSq()>0)){const t=Math.sqrt(I.x*I.x+I.z*I.z);t>.4&&(d=t)}if(this.impulse.lengthSq()>.1){const t=Math.min(1,this.impulse.length()/5);m.x=r.lerp(m.x,this.impulse.x,t),m.z=r.lerp(m.z,this.impulse.z,t),m.y+=this.impulse.y;const o=Math.exp(-this.impulseDamping*e);this.impulse.x*=o,this.impulse.y>0?this.impulse.y+=e*this.getEffectiveGravity():this.impulse.y*=o,this.impulse.z*=o}else this.impulse.set(0,0,0);if(n.copy(m).normalize(),i.copy(m),m.length()>0||!this.isGrounded){if(w.copy(m).multiplyScalar(e),this.isGrounded&&this.mode===M.walking&&(this.rayTestResult.distance>t.offset()||(w.y=Math.max(0,C.y*e)),this.physicsSystem.getActorComputedMovement(this.actor,t,w,D),t.computedCollision(0,G),null!=G&&null!=G.normal1)){const o=(new s.Vector3).copy(G.normal1);Math.acos(o.dot(T))>t.maxSlopeClimbAngle()&&(w.y=.016*this.getEffectiveGravity()*.5)}x.copy(this.physicsSystem.getActorComputedMovement(this.actor,t,w,D))}else x.set(0,0,0);this.physicsSystem.setNextKinematicTranslation(this.actor,x);let O=function(t){if(t.numComputedCollisions()>0){const o=t.computedCollision(0);j.x=o.normal2.x,j.y=o.normal2.y,j.z=o.normal2.z;const i=j.angleTo(T);j.x=o.normal1.x,j.y=o.normal1.y,j.z=o.normal1.z;const e=j.angleTo(T);return!(i<100)&&e>t.minSlopeSlideAngle()}return!1}(t);this.isGrounded&&!O||this.mode!==M.falling&&(null==g?g=performance.now():performance.now()-g>100&&(this.mode=M.falling,this.velocity.copy(i))),this.isGrounded&&this.velocity.y<=0&&(this.mode,M.falling,this.mode=M.walking,this.velocity.y=0,g=null),this.mode,M.walking,this.horizontalSpeed=d})}applyImpulse(t){this.impulse.add(t)}debugDirection(){const t=new n(w,this.actor.position,1,65280);this.actor.object.parent.add(t),setTimeout(()=>{t.removeFromParent()},30);const o=new n(x,this.actor.position,1,16711680);this.actor.object.parent.add(o),setTimeout(()=>{o.removeFromParent()},30)}setRootMotionAction(t,o={}){const i=t?.getClip();if(i instanceof c){this.rootMotionAction=t,this.rootMotionOptions=o,this.resetRootMotion=!0;const e=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(e);const n=s.PropertyBinding.parseTrackName(i.motionTrack.name);this.rootMotionRootBone=this.actor.object.getObjectByName(n.nodeName)}}clearRootMotionAction(t){null!=t&&this.rootMotionAction!==t||(this.rootMotionAction=null,this.rootMotionOptions={},this.resetRootMotion=!1)}getWallDirection(t,o){const i=t.clone().negate().cross(T);return i.dot(o)<0?i.negate():i}moveTo(t){this.actor.position.copy(t),this.physicsSystem.updateActorTransform(this.actor)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}checkGrounded(t){this.colliderHeight,this.colliderRadius;D.y=-.05,this.physicsSystem.rayTest(R.addVectors(this.actor.position,C.set(0,this.offset,0)),z.addVectors(this.actor.position,D),this.rayTestResult,{excludeActor:this.actor,excludeTriggers:!0})}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}createCollisionShape(){const t=new d(this.colliderHeight,this.colliderRadius);return t.offset.y=this.colliderRadius+this.colliderHeight/2+this.offset,t.collisionGroup=b,t}step(t){}performMovement(t){}arrowHelper(t,o,i){const e=new n(t.clone().normalize(),o,1,i);this.actor.object.parent.add(e),setTimeout(()=>{e.removeFromParent()},30)}};t([v(),o("design:type",Number)],I.prototype,"colliderHeight",void 0),t([v(),o("design:type",Number)],I.prototype,"colliderRadius",void 0),I=t([f({inEditor:!1}),o("design:paramtypes",[])],I);export{I as CharacterMovementComponent};const T=new a(0,1,0),j=new a;const R=new a,z=new a,C=new a(0,1,0),D=new a(0,-.1,0),G=(new a(0,-1,0),new i.CharacterCollision),q=new s.Quaternion,F=new s.Euler,k=new s.Vector3;/*
|
|
1
|
+
import{__decorate as t,__metadata as o}from"tslib";import i from"@dimforge/rapier3d-simd-compat";import{takeUntil as e}from"rxjs";import*as s from"three";import{ArrowHelper as n,MathUtils as r,Vector3 as a}from"three";import{RootMotionClip as c}from"../../../../../gameplay/animation/root-motion.js";import{ActionInput as h,AxisInput as l,RotationInput as p}from"../../../../../gameplay/input/index.js";import{PhysicsSystem as m,RayTestResult as u}from"../../../../../gameplay/services/physics/physics-system.js";import{CapsuleCollisionShape as d}from"../../../../../scene/collision/collision-shape.js";import{PhysicsBodyType as y}from"../../../../services/physics/physics-system.js";import{ActorComponent as g,Component as f}from"../../../component.js";import{CharacterMovementMode as M}from"./modes.js";import{inject as S}from"../../../../../gameplay/inject.js";import{Parameter as v}from"../../../../../shader/parameter.js";const w=new a,x=new a,A=1/30,b=131070;let I=class extends g{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}set normalNudgeFactor(t){this.cc.setNormalNudgeFactor(t)}get normalNudgeFactor(){return this.cc.normalNudgeFactor()}constructor(){super(),this.directionInput=new l,this.jumpInput=new h,this.sprintInput=new h,this.rotationInput=new p,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=r.degToRad(70),this.maxSlopeClimbAngle=r.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.normalizedDirection=!0,this.characterCollision=!1,this.allowRootMotionJumpCancel=!1,this.enabled=!0,this.velocity=new a,this.mode=M.walking,this.isSprinting=!1,this.pressedJump=!1,this.rayTestResult=new u,this.physicsSystem=S(m),this.resetRootMotion=!1,this.rootMotionOptions={},this.rotateToMovementDirection=!1,this.smoothRotation=!0,this.rotationSpeed=40,this.maxRotationSpeed=100,this.impulse=new a,this.impulseDamping=2;const t=this.cc=this.physicsSystem.getCharacterController(.1);t.enableSnapToGround(.1),t.enableAutostep(0,.1,!1)}onInit(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:y.kinematic,continousCollisionDetection:!1,friction:0,restitution:.5,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation);let o=this.rotationInput.rotation.y;const i=new a,n=new a,h=new a,l=new a,p=new a,m=new a,u=new a;let d=0,g=null;const f=new a,S=new a,v=new a,I=new a,R=new a,z=new a,C=new a,D=this.characterCollision?null:b;let E=this.rotateToMovementDirection;this.physicsSystem.beforeStep.pipe(e(this.disposed)).subscribe(e=>{if(this.checkGrounded(e),!this.enabled)return;if(S.set(0,0,0),null==this.rootMotionAction||this.rootMotionAction.isRunning()||this.clearRootMotionAction(this.rootMotionAction),null!=this.rootMotionAction&&this.rootMotionOptions.cancelWithJump&&this.jumpInput.activated&&(this.isGrounded||this.jumpInAir)){const t=this.rootMotionAction,o=this.rootMotionOptions.onJumpCancel;this.clearRootMotionAction(t),t.stop(),o?.()}if(null!=this.rootMotionAction){if(this.rootMotionAction.getClip()instanceof c){const t=this.rootMotionInterpolant;this.resetRootMotion&&(f.fromArray(t.evaluate(0)),this.resetRootMotion=!1),z.fromArray(t.evaluate(this.rootMotionAction.time)),S.subVectors(z,f),f.copy(z);(this.rootMotionRootBone??this.rootMotionAction.getRoot()).getWorldScale(R),S.multiply(R)}}e>A&&(e=A);const y=null!=this.rootMotionAction&&this.rootMotionAction.enabled,b=y&&0!==S.lengthSq();this.pressedJump=!y&&this.jumpInput.activated,this.isSprinting=!y&&this.sprintInput.activated;const H=E!==this.rotateToMovementDirection;let B=r.euclideanModulo(this.rotationInput.rotation.y-o+Math.PI,2*Math.PI)-Math.PI;H&&(this.actor.object.quaternion.setFromEuler(F.set(0,this.rotationInput.rotation.y,0)),E?this.actor.object.quaternion.setFromEuler(F.set(0,this.rotationInput.rotation.y,0)):(B=0,o=this.rotationInput.rotation.y),E=this.rotateToMovementDirection),h.copy(this.actor.position),l.set(-this.directionInput.vector.x,0,this.directionInput.vector.y).normalize();const N=!this.rotateToMovementDirection&&l.z<0?this.maxSpeedBackwards:(this.isSprinting?this.maxSpeedSprint:this.maxSpeed)*(this.normalizedDirection?1:Math.min(1,this.directionInput.vector.length()));if(u.set(0,0,0),y)o=this.rotationInput.rotation.y;else if(this.rotateToMovementDirection&&!y){if(l.lengthSq()>0&&this.mode!=M.falling){const t=this.smoothRotation,i=F.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,s=Math.atan2(l.x,l.z),n=.99*this.rotationInput.rotation.y+s;if(t){r.clamp(.5*l.dot(p)+.5,.001,1);const t=r.euclideanModulo(n-i+Math.PI,2*Math.PI)-Math.PI;let o=r.clamp(t*this.rotationSpeed*e,-this.maxRotationSpeed*e,this.maxRotationSpeed*e);Math.abs(o)>Math.abs(t)&&(o=t),this.actor.object.quaternion.setFromEuler(F.set(0,i+o,0))}else this.actor.object.quaternion.setFromEuler(F.set(0,n,0));p.lerp(l,e*this.rotationSpeed),o+=B,u.copy(this.actor.object.getWorldDirection(k).normalize())}}else b||(o+=B,this.actor.object.quaternion.multiply(q.setFromEuler(F.set(0,B,0))),l.lengthSq()>0&&u.copy(l).applyQuaternion(this.actor.object.quaternion).normalize());if(C.set(0,0,0),this.rayTestResult.hasHit&&null!=this.rayTestResult.actor&&this.physicsSystem.getLinearVelocity(this.rayTestResult.actor,C),this.mode===M.walking?(0!==u.lengthSq()?(d=Math.min(N,d),d=r.lerp(d,N,4*e)):d=0,m.copy(u).multiplyScalar(d),this.pressedJump&&(this.mode=M.falling,this.velocity.copy(m),this.velocity.y=this.jumpVelocity),m.y=e*this.getEffectiveGravity(),m.add(C)):this.mode===M.falling&&(this.pressedJump&&this.jumpInAir&&(this.mode=M.falling,this.velocity.copy(m),this.velocity.y=this.jumpVelocity),this.velocity.y+=e*this.getEffectiveGravity(),m.copy(this.velocity),m.addScaledVector(u,this.fallingMovementControl),this.fallingReorientation&&m.applyAxisAngle(new a(0,1,0),B)),b&&(v.copy(S).applyQuaternion(this.actor.quaternion),I.copy(v).divideScalar(e),this.mode===M.walking?(m.x=I.x+C.x,m.z=I.z+C.z):(m.x=I.x,m.z=I.z),l.lengthSq()>0)){const t=Math.sqrt(I.x*I.x+I.z*I.z);t>.4&&(d=t)}if(this.impulse.lengthSq()>.1){const t=Math.min(1,this.impulse.length()/5);m.x=r.lerp(m.x,this.impulse.x,t),m.z=r.lerp(m.z,this.impulse.z,t),m.y+=this.impulse.y;const o=Math.exp(-this.impulseDamping*e);this.impulse.x*=o,this.impulse.y>0?this.impulse.y+=e*this.getEffectiveGravity():this.impulse.y*=o,this.impulse.z*=o}else this.impulse.set(0,0,0);if(n.copy(m).normalize(),i.copy(m),m.length()>0||!this.isGrounded){if(w.copy(m).multiplyScalar(e),this.isGrounded&&this.mode===M.walking&&(this.rayTestResult.distance>t.offset()||(w.y=Math.max(0,C.y*e)),this.physicsSystem.getActorComputedMovement(this.actor,t,w,D),t.computedCollision(0,G),null!=G&&null!=G.normal1)){const o=(new s.Vector3).copy(G.normal1);Math.acos(o.dot(T))>t.maxSlopeClimbAngle()&&(w.y=.016*this.getEffectiveGravity()*.5)}x.copy(this.physicsSystem.getActorComputedMovement(this.actor,t,w,D))}else x.set(0,0,0);this.physicsSystem.setNextKinematicTranslation(this.actor,x);let O=function(t){if(t.numComputedCollisions()>0){const o=t.computedCollision(0);j.x=o.normal2.x,j.y=o.normal2.y,j.z=o.normal2.z;const i=j.angleTo(T);j.x=o.normal1.x,j.y=o.normal1.y,j.z=o.normal1.z;const e=j.angleTo(T);return!(i<100)&&e>t.minSlopeSlideAngle()}return!1}(t);this.isGrounded&&!O||this.mode!==M.falling&&(null==g?g=performance.now():performance.now()-g>100&&(this.mode=M.falling,this.velocity.copy(i))),this.isGrounded&&this.velocity.y<=0&&(this.mode,M.falling,this.mode=M.walking,this.velocity.y=0,g=null),this.mode,M.walking,this.horizontalSpeed=d})}applyImpulse(t){this.impulse.add(t)}debugDirection(){const t=new n(w,this.actor.position,1,65280);this.actor.object.parent.add(t),setTimeout(()=>{t.removeFromParent()},30);const o=new n(x,this.actor.position,1,16711680);this.actor.object.parent.add(o),setTimeout(()=>{o.removeFromParent()},30)}setRootMotionAction(t,o={}){const i=t?.getClip();if(i instanceof c){this.rootMotionAction=t,this.rootMotionOptions=o,this.resetRootMotion=!0;const e=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(e);const n=s.PropertyBinding.parseTrackName(i.motionTrack.name);this.rootMotionRootBone=this.actor.object.getObjectByName(n.nodeName)}}clearRootMotionAction(t){null!=t&&this.rootMotionAction!==t||(this.rootMotionAction=null,this.rootMotionOptions={},this.resetRootMotion=!1)}getWallDirection(t,o){const i=t.clone().negate().cross(T);return i.dot(o)<0?i.negate():i}moveTo(t){this.actor.position.copy(t),this.physicsSystem.updateActorTransform(this.actor)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}checkGrounded(t){this.colliderHeight,this.colliderRadius;D.y=-.05,this.physicsSystem.rayTest(R.addVectors(this.actor.position,C.set(0,this.offset,0)),z.addVectors(this.actor.position,D),this.rayTestResult,{excludeActor:this.actor,excludeTriggers:!0})}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}createCollisionShape(){const t=new d(this.colliderHeight,this.colliderRadius);return t.offset.y=this.colliderRadius+this.colliderHeight/2+this.offset,t.collisionGroup=b,t}step(t){}performMovement(t){}arrowHelper(t,o,i){const e=new n(t.clone().normalize(),o,1,i);this.actor.object.parent.add(e),setTimeout(()=>{e.removeFromParent()},30)}};t([v(),o("design:type",Number)],I.prototype,"colliderHeight",void 0),t([v(),o("design:type",Number)],I.prototype,"colliderRadius",void 0),I=t([f({inEditor:!1}),o("design:paramtypes",[])],I);export{I as CharacterMovementComponent};const T=new a(0,1,0),j=new a;const R=new a,z=new a,C=new a(0,1,0),D=new a(0,-.1,0),G=(new a(0,-1,0),new i.CharacterCollision),q=new s.Quaternion,F=new s.Euler,k=new s.Vector3;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{Ball as n,Capsule as
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Ball as n,Capsule as s,Cone as o,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-simd-compat";import{init as p}from"@recast-navigation/core";import{DebugDrawer as u,getPositionsAndIndices as d}from"@recast-navigation/three";import{BehaviorSubject as m,Subject as f,debounceTime as w,filter as b,firstValueFrom as g,takeUntil as y}from"rxjs";import*as x from"three";import{BufferGeometryUtils as v,ConvexHull as M}from"three/examples/jsm/Addons.js";import{Actor as B,BaseActor as S,Parameter as z,PhysicsSystem as A,ViewController as k,World as C,attach as j,inject as F}from"../../";import{sleepDelay as I}from"../../../utils/async";import{hasSharedArrayBufferSupport as P,toSharedFloat32Array as V,toSharedUint32Array as G}from"../../../utils/buffer";import{DynamicTiledNavMesh as N}from"../../ai/dynamic-tiled-navmesh";import{TriggerVolumeMesh as H}from"./components/volume-editor-component";var D;!function(e){e[e.none=0]="none",e[e.starting=1]="starting",e[e.started=2]="started"}(D||(D={}));let E=D.none,T=new m(!1);export async function safeRecastInit(){return E===D.none?(E=D.starting,p().then(()=>{T.next(!0),E=D.started})):g(T.pipe(b(e=>e)))}new x.Box3(new x.Vector3(-100,-100,-100),new x.Vector3(100,100,100));const R=navigator.hardwareConcurrency??1;let U=!1,q=class extends S{constructor(){super(...arguments),this.physics=F(A),this.view=F(k),this.world=F(C),this.editorVisualisation=j(H),this.debug=!0,this.refreshMs=4e3,this.tileSize=50,this.walkableClimb=.3,this.walkableSlopeAngle=45,this.walkableHeight=2,this.cellSize=.2,this.bounds=new x.Box3}async onInit(){U||(await safeRecastInit(),U=!0),setTimeout(()=>{this.init()},10),this.recreateInterval=setInterval(()=>{if("_hology_transform_group"===this.object.parent?.name)return;$.setFromCenterAndSize(this.position,this.object.scale).equals(this.bounds)||(this.disposed.next(!0),this.disposed=new f,this.init())},2e3)}onEndPlay(){clearInterval(this.recreateInterval)}init(){this.bounds.setFromCenterAndSize(this.position,this.object.scale);const e=this.bounds.max.x-this.bounds.min.x,t=this.bounds.max.z-this.bounds.min.z,n=Math.max(1,Math.min(e,t)),s=Math.min(400,Math.max(50,Math.ceil(n/2))),o=Math.max(this.cellSize,.01),i={tileSize:Math.max(32,Math.floor(s/o)),walkableClimb:this.walkableClimb/o,walkableSlopeAngle:this.walkableSlopeAngle,walkableRadius:2,walkableHeight:this.walkableHeight/o,detailSampleDist:1,minRegionArea:6,mergeRegionArea:400,cs:o,ch:o,maxSimplificationError:1.3,maxEdgeLen:200},r=new N({navMeshBounds:this.bounds,recastConfig:i,maxTiles:1024,workers:R,cacheId:"nav"+this.object.userData?.src?.id});this.navMesh=r.navMesh;const a=this.tileSize*i.cs*2,l=performance.now(),c=new Map,h=new u;h.userData.isDebugDrawer=!0;r.navMesh;const p=this.bounds,m=()=>{const e=this.view.getCamera().getWorldPosition(new x.Vector3),t=new x.Box3((new x.Vector3).copy(e).subScalar(a),(new x.Vector3).copy(e).addScalar(a)),n=[],s=this.physics.world.bodies;if(null==s)return[];const o=new x.Box3;for(const e of s.getAll())for(let s=0,i=e.numColliders();s<i;s++){const i=e.collider(s);if(i.isSensor()||null!=i.parent().userData&&!0===i.parent().userData.ignoreForNavMesh)continue;const r=e.handle+","+s,a=c.get(r)?.mesh,l=a??L(i);if(X(i,l),null!=l){o.copy(l.geometry.boundingBox),o.min.add(l.position),o.max.add(l.position);const e=o.intersectsBox(t)||!0,s=o.intersectsBox(this.bounds);c.set(r,{pos:i.translation(),mesh:l}),e&&s&&n.push(l)}}return n},f=new x.Box3,b=new Map,g=new Map;let v=!0,M=performance.now(),B=!1;const S=function(e,t){let n=!1;return(async()=>{for(;!n;)await e(),await I(t)})(),()=>{n=!0}}(async()=>{if(B)return;const e=new x.Box3,t=m();for(const n of t){const t=b.get(n);!0!==t?.equals(n.position)&&(null!=t&&e.expandByPoint(t),e.expandByObject(n),b.set(n,n.position.clone()))}e.min.subScalar(50),e.max.addScalar(50);const n=r.getTilesForBounds(e);n.length>500&&console.warn("Too many tiles to update. Consider increasing tile size");const s=n.slice(0,500);if(0!=s.length){const n=[];for(const s of t)f.setFromObject(s),f.intersectsBox(e)&&n.push(s);let[o,i]=d(n);i=function(e,t,n){const s=new x.Vector3,o=[];for(let i=0;i<t.length;i+=3){let r=!0;for(let o=0;o<3;o++){const a=3*t[i+o];if(s.fromArray(e,a),!n.containsPoint(s)){r=!1;break}}r&&o.push(t[i],t[i+1],t[i+2])}return new Uint32Array(o)}(o,i,p),P&&(o=V(o),i=G(i));const a=v;v=!1,await Promise.all(s.map(e=>(M=performance.now(),r.buildTile(o,i,e,a).then(()=>{const t=e[0]+","+e[1];g.set(t,(g.get(t)??0)+1),this.debug})))).then(()=>{this.debug,B=!1})}else B=!1},this.refreshMs??1e4);this.disposed.subscribe(()=>S()),r.onNavMeshUpdate.pipe(y(this.disposed),w(200)).subscribe(()=>{h.clear(),h.drawNavMesh(r.navMesh)}),console.log("Create navmesh with debug",this.debug),this.debug&&(this.object.rotation.set(0,0,0),this.object.updateMatrix(),this.object.updateMatrixWorld(),this.object.parent.add(h)),this.disposed.subscribe(()=>{r?.destroy(),h.removeFromParent(),h.dispose()});const z=performance.now()-l;z>1e3&&console.warn(`NavMesh update took ${z} ms. Consider changing tileSize or other parameter that may affect performance`)}};e([z(),t("design:type",Boolean)],q.prototype,"debug",void 0),e([z(),t("design:type",Number)],q.prototype,"walkableClimb",void 0),e([z({range:[0,89]}),t("design:type",Number)],q.prototype,"walkableSlopeAngle",void 0),e([z(),t("design:type",Number)],q.prototype,"walkableHeight",void 0),e([z({range:[.01,10]}),t("design:type",Number)],q.prototype,"cellSize",void 0),q=e([B()],q);export default q;const O=new Map,W=new WeakMap;function _(e){if(e.shape instanceof l)return function(e){const t=e.shape;if(t.type!==c.HeightField)throw new Error("The provided collider is not a height field.");let n=!1;const s=t,o=s.heights,i=s.nrows,r=s.ncols,a=s.scale.x,l=s.scale.z,h=s.scale.y,p=i+1,u=new x.PlaneGeometry(l,a,r,i);u.rotateX(-Math.PI/2);const d=u.attributes.position.array;let m=0;for(let e=0;e<p;e++)for(let t=0;t<p;t++)d[m+1]=o[t*p+e]*h,m+=3,0!=d[m+1]&&(n=!0);if(!n){const e=new x.PlaneGeometry(a,l,2,2);return e.rotateX(-Math.PI/2),e}return u}(e);if(e.shape instanceof n)return new x.SphereGeometry(e.shape.radius);if(e.shape instanceof r){const t=e.shape.halfExtents;return new x.BoxGeometry(2*t.x,2*t.y,2*t.z)}if(e.shape instanceof i){const t=function(e){const t=W.get(e);if(void 0!==t)return t;const n=new Uint32Array(e.buffer,e.byteOffset,e.byteLength>>>2);let s=2166136261;for(let e=0;e<n.length;e++)s=Math.imul(s^n[e],16777619)>>>0;return W.set(e,s),s}(e.shape.vertices);let n=O.get(t);return n||(n=function(e){const t=[];for(let n=0;n<e.length;n+=3)t.push(new x.Vector3(e[n],e[n+1],e[n+2]));const n=(new M).setFromPoints(t),s=[];n.faces.forEach(e=>{const t=e.edge.head().point,n=e.edge.next.head().point,o=e.edge.next.next.head().point;s.push(t.x,t.y,t.z),s.push(n.x,n.y,n.z),s.push(o.x,o.y,o.z)});const o=new x.BufferGeometry;return o.setAttribute("position",new x.Float32BufferAttribute(s,3)),o}(e.shape.vertices),O.set(t,n)),n}if(e.shape instanceof h){const t=e.shape.vertices,n=e.shape.indices;let s=new x.BufferGeometry;return s.setAttribute("position",new x.Float32BufferAttribute(t,3)),null!=n?s.setIndex(new x.Uint16BufferAttribute(n,1)):s=v.mergeVertices(s),s.computeVertexNormals(),s}if(e.shape instanceof a){const t=e.shape.halfHeight,n=e.shape.radius;return new x.CylinderGeometry(n,n,2*t)}if(e.shape instanceof o){const t=e.shape.halfHeight,n=e.shape.radius;return new x.ConeGeometry(n,2*t)}if(e.shape instanceof s){const t=e.shape.halfHeight,n=e.shape.radius;return new x.CapsuleGeometry(n,2*t)}return console.warn("Unsupported shape",e.shape.type,e),null}function L(e){const t=_(e);if(null==t)return null;const n=J,s=new x.Mesh(t,n);return s.geometry.computeBoundingBox(),s.geometry.scale(1.01,1.01,1.01),s}function X(e,t){const n=e.translation(),s=e.rotation();t.position.set(n.x,n.y,n.z),t.quaternion.set(s.x,s.y,s.z,s.w)}const $=new x.Box3,J=new x.MeshBasicMaterial({wireframe:!1,color:16711680,side:x.FrontSide});/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -4,7 +4,7 @@ import { BaseActor } from "../../actors/actor";
|
|
|
4
4
|
import { AbstractType } from "../../../utils/type";
|
|
5
5
|
import { CollisionShape } from "../../../index.js";
|
|
6
6
|
import { PhysicsBodyType } from "./physics-system";
|
|
7
|
-
import * as RAPIER from "@dimforge/rapier3d-compat";
|
|
7
|
+
import * as RAPIER from "@dimforge/rapier3d-simd-compat";
|
|
8
8
|
export type ActorPhysicsOptions = {
|
|
9
9
|
isTrigger: boolean;
|
|
10
10
|
mass: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as RAPIER from "@dimforge/rapier3d-compat";
|
|
1
|
+
import * as RAPIER from "@dimforge/rapier3d-simd-compat";
|
|
2
2
|
import { Observable, Subject } from "rxjs";
|
|
3
3
|
import * as THREE from "three";
|
|
4
4
|
import { ColorRepresentation, Object3D, Quaternion, Vector3 } from "three";
|
|
@@ -598,6 +598,7 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
598
598
|
* @returns The ShapeCastResult containing hit information if a collision occurred, or indicating no hit otherwise.
|
|
599
599
|
*/
|
|
600
600
|
castActorShape(actor: BaseActor, direction: Vector3, distance: number, result?: ShapeCastResult, collisionFilter?: InteractionGroups): ShapeCastResult;
|
|
601
|
+
private _isStopped;
|
|
601
602
|
/**
|
|
602
603
|
* Stops the physics simulation and cleans up resources.
|
|
603
604
|
*/
|