@hology/core 0.0.196 → 0.0.198
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/effects/sequence/sequence-action.d.ts +8 -1
- package/dist/effects/sequence/sequence-actor.d.ts +14 -2
- package/dist/effects/sequence/sequence-actor.js +1 -1
- package/dist/effects/sequence/sequence-data.d.ts +98 -4
- package/dist/effects/sequence/sequence-data.js +1 -1
- package/dist/effects/sequence/sequence-definitions.d.ts +12 -8
- package/dist/effects/sequence/sequence-definitions.js +1 -1
- package/dist/effects/sequence/sequence-ops.js +1 -1
- package/dist/effects/sequence/sequence-player.d.ts +66 -2
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/sequence/sequence-value-lane.d.ts +1 -0
- package/dist/effects/sequence/sequence-value-lane.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/builtin/post-process-volume-actor.js +1 -1
- package/dist/gameplay/index.d.ts +1 -0
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.d.ts +1 -0
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/camera-shake.d.ts +28 -0
- package/dist/gameplay/services/camera-shake.js +4 -0
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/render.d.ts +47 -2
- package/dist/gameplay/services/render.js +1 -1
- package/dist/rendering/post-process-effect.d.ts +63 -0
- package/dist/rendering/post-process-effect.js +4 -0
- package/dist/rendering.d.ts +15 -1
- package/dist/rendering.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +3 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/collision/collision-shape-import.js +1 -1
- package/dist/scene/collision/collision-shape.js +1 -1
- package/dist/scene/materializer.d.ts +20 -2
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/scatter/surface-scatter-manager.d.ts +44 -0
- package/dist/scene/scatter/surface-scatter-manager.js +4 -0
- package/dist/scene/storage/storage.d.ts +2 -0
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/landscape-composite-shader.js +1 -1
- package/dist/shader/builtin/standard-shader.d.ts +2 -0
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/builtin/unlit-shader.d.ts +2 -1
- package/dist/shader/builtin/unlit-shader.js +1 -1
- package/dist/shader/index.d.ts +1 -0
- package/dist/shader/index.js +1 -1
- package/dist/shader/post-process-shader.d.ts +14 -0
- package/dist/shader/post-process-shader.js +4 -0
- package/dist/shader/uv-nodes.d.ts +4 -0
- package/dist/shader/uv-nodes.js +4 -0
- package/dist/shader-nodes/index.d.ts +1 -1
- package/dist/shader-nodes/index.js +1 -1
- package/dist/test/authored-collision-rescale.test.d.ts +2 -0
- package/dist/test/authored-collision-rescale.test.js +4 -0
- package/dist/test/camera-shake.test.d.ts +2 -0
- package/dist/test/camera-shake.test.js +4 -0
- package/dist/test/collision-shape-import.test.js +1 -1
- package/dist/test/post-process-effect.test.d.ts +2 -0
- package/dist/test/post-process-effect.test.js +4 -0
- package/dist/test/sequence-camera-control.test.d.ts +2 -0
- package/dist/test/sequence-camera-control.test.js +4 -0
- package/dist/test/sequence-property-parameters.test.d.ts +2 -0
- package/dist/test/sequence-property-parameters.test.js +4 -0
- package/dist/test/storage-case-collision.test.d.ts +2 -0
- package/dist/test/storage-case-collision.test.js +4 -0
- package/package.json +2 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{BehaviorSubject as t,Subject as e}from"rxjs";import*as i from"three";import{AnimationMixer as s,Euler as a,Object3D as n,Quaternion as o,Vector3 as r}from"three";import{VisualEffect as c}from"../../effects/vfx/vfx-param.js";import{BaseActor as l}from"../../gameplay/actors/actor.js";import u from"../../gameplay/actors/builtin/index.js";import{Prefab as d,PrefabOf as h}from"../../scene/objects/prefab.js";import{customParamValueNeedsAsyncResolution as p,deserializeCustomParamValue as f,deserializeCustomParamValueSync as m}from"../../scene/custom-param-deserialize.js";import{getAudioParameterDefinition as y}from"./audio-parameters.js";import{Sequence as g}from"./sequence-data.js";import{getSequenceSubTrackDefinition as v,getSequenceTrackDefinition as A}from"./sequence-definitions.js";import{applyInterpolation as b,evaluateCustomParamValueKeyframes as w,evaluateNumericKeyframes as C,findKeyframeSpan as S}from"./sequence-value-lane.js";import{buildRetimedAnimationClip as k,getAnimationClipRetimingSignature as T,isAnimationClipUsingRetiming as x}from"./sequence-animation-retiming.js";import{SkeletonUtils as P}from"three-stdlib";import{CharacterAnimationComponent as I,CharacterMovementComponent as q}from"../../gameplay/actors/index.js";import{RootMotionClip as B}from"../../gameplay/animation/root-motion.js";export var SequencePlaybackState;!function(t){t.Stopped="stopped",t.Playing="playing",t.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new t(SequencePlaybackState.Stopped),this._time=new t(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 e,this.onLoop=new e,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.sequenceCamera=null,this.originalCamera=null,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.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set,this.sequenceEventSyncResolvers={actor:t=>this.resolveSequenceEventActorReference(t)},this.sequenceEventAsyncResolvers={actor:t=>this.resolveSequenceEventActorReference(t),texture:t=>this.assetLoader?.getTextureByAssetId(t)??null,sampler2DNode:t=>this.assetLoader?.getTextureByAssetId(t)??null,object3D:async t=>{const e=await(this.assetLoader?.getModelByAssetId(t));return e?.scene??null},material:t=>this.assetLoader?.getMaterialByAssetId(t)??null,audioBuffer:t=>this.assetLoader?.getAudioByAssetId(t)??null,visualEffect:async t=>{if(!this.assetLoader||!this.actorFactory)return null;const e=await this.assetLoader.getAsset(t);return e?new c(this.actorFactory,e):null},prefab:async t=>{const e=await(this.assetLoader?.getPrefabById(t));return e?new d(e.asset):null},prefabActor:async t=>{const e=await(this.assetLoader?.getPrefabById(t));return e?new h(new d(e.asset)):null},sequence:t=>this.resolveSequenceEventSequence(t),animationClip:t=>this.resolveSequenceEventAnimationClip(t)},this.trackRuntimeEvaluators={object:(t,e,i)=>{e&&this.evaluateObjectTrack(t,e,i)},locator:(t,e,i)=>{e&&this.evaluateLocatorTrack(t,e,i)},camera:(t,e,i)=>this.evaluateCameraTrack(t,i),audio:(t,e,i)=>this.evaluateAudioTrack(t,i),vfx:(t,e,i)=>this.evaluateVfxTrack(t,i),spawn:(t,e,i)=>this.evaluateSpawnTrack(t,e,i),group:(t,e,i)=>{if("group"===t.type)for(const e of t.childTracks)this.evaluateTrack(e,i)}},this.subTrackRuntimeEvaluators={transform:(t,e,i)=>{const s=this.getPlayableObject(e);s&&this.evaluateTransformSubTrack(t,s,i)},animation:(t,e,i)=>this.evaluateAnimationSubTrack(t,e,i),visibility:(t,e,i)=>{const s=this.getPlayableObject(e);s&&this.evaluateVisibilitySubTrack(t,s,i)},parameter:(t,e,i)=>this.evaluateParameterSubTrack(t,e.target||null,i),event:(t,e,i)=>this.evaluateEventSubTrack(t,e.target||null,i)}}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(.01,t)}get loop(){return this._loop}set loop(t){this._loop=t}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(t){this._externalTimeControl=t}get inEditor(){return this._inEditor}set inEditor(t){this._inEditor=t,this.updateLocatorMarkerVisibility()}setWorld(t){this.world!==t&&(this.clearLocatorBindings(),this.world=t,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.clearRetimedAnimationClipCache(),this._state.next(SequencePlaybackState.Stopped),this.sequenceData&&this.initializeLocatorBindings())}setAudioListener(t){this.audioListener=t}setAssetLoader(t){if(this.assetLoader=t,this.sequenceData){const t=this.clearCounter;this.preloadSequenceResources(this.sequenceData,t)}}setActorFactory(t){this.actorFactory=t}setVfxService(t){this.vfxService=t}load(t){if(this.stop(),this.clearCounter++,this.clearLocatorBindings(),this.sequenceData=t,this._duration=t.duration,this._loop=t.loop,this._timescale=t.playbackRate,this.clearRetimedAnimationClipCache(),this.bindings.clear(),this.initializeLocatorBindings(),this.loopCount=0,this.assetLoader){const e=this.clearCounter;this.preloadSequenceResources(t,e)}}preloadSequenceResources(t,e){return Promise.all([this.preloadAudioBuffersForSequence(t,e),this.preloadAnimationClipsForSequence(t,e)]).then(()=>{})}getAudioAssetIdsForSequence(t){const e=new Set;for(const i of t.tracks){if("audio"!==i.type)continue;const t=i;for(const i of t.clips??[])i.audioAssetId&&e.add(i.audioAssetId)}return[...e]}async preloadAudioBuffersForSequence(t,e){if(!this.assetLoader)return;const i=this.getAudioAssetIdsForSequence(t);0!==i.length&&await Promise.all(i.map(async t=>{if(e!==this.clearCounter)return;if(this.audioBuffers.has(t))return;let i=this.loadingAudioBuffers.get(t);i||(i=this.assetLoader.getAudioByAssetId(t),this.loadingAudioBuffers.set(t,i));try{const s=await i;if(e!==this.clearCounter)return;this.audioBuffers.set(t,s)}catch(t){}finally{this.loadingAudioBuffers.get(t)===i&&this.loadingAudioBuffers.delete(t)}}))}getAnimationClipAssetIdsForSequence(t){const e=new Set;for(const i of L(t.tracks))if("subTracks"in i)for(const t of i.subTracks)if("animation"===t.type)for(const i of t.clips)i.animationClipAssetId&&e.add(i.animationClipAssetId);return[...e]}async preloadAnimationClipsForSequence(t,e){if(!this.assetLoader)return;const i=this.getAnimationClipAssetIdsForSequence(t);0!==i.length&&await Promise.all(i.map(async t=>{e===this.clearCounter&&await this.ensureAnimationClip(t)}))}bindRole(t,e){this.roleBindings.set(t,e),this.sequenceData&&this.resolveBindings()}bindObject(t,e){if(this.sequenceData)for(const i of this.sequenceData.tracks)"object"===i.type&&i.targetId===t&&this.createBinding(i,e)}getLocator(t){return this.getLocators(t)[0]??null}getLocators(t){const e=_(t);if(!e||!this.sequenceData)return[];const i=[];for(const t of L(this.sequenceData.tracks)){if("locator"!==t.type)continue;if(_(t.bindingId)!==e)continue;const s=this.bindings.get(t.id),a=s?this.getPlayableObject(s):null;a&&(a.updateWorldMatrix(!0,!1),i.push({trackId:t.id,name:t.name,bindingId:t.bindingId,position:a.getWorldPosition(new r),rotation:a.getWorldQuaternion(new o),scale:a.getWorldScale(new r)}))}return i}resolveBindings(){if(this.sequenceData)for(const t of this.sequenceData.tracks)this.resolveTrackBinding(t)}initializeLocatorBindings(){if(this.sequenceData)for(const t of L(this.sequenceData.tracks)){if("locator"!==t.type||this.bindings.has(t.id))continue;const e=new n;e.name=t.name||"Locator",e.userData.sequenceLocatorTrackId=t.id,this.world?.scene&&null==e.parent&&this.world.scene.add(e);const i=j(t.name);i.visible=this._inEditor,e.add(i),this.locatorMarkers.set(t.id,i),this.disableLocatorInteraction(e),this.createBinding(t,e)}}clearLocatorBindings(){for(const t of this.locatorMarkers.values())F(t);for(const t of this.bindings.values()){if("locator"!==t.track.type)continue;const e=this.getPlayableObject(t);e?.parent&&e.removeFromParent()}this.locatorMarkers.clear()}updateLocatorMarkerVisibility(){for(const t of this.locatorMarkers.values())t.visible=this._inEditor}disableLocatorInteraction(t){t.traverse(t=>{t.raycast=()=>{}})}resolveTrackBinding(t){if("object"===t.type){const e=t;e.role&&this.roleBindings.has(e.role)&&this.createBinding(t,this.roleBindings.get(e.role))}else if("spawn"===t.type){const e=t;e.role&&this.roleBindings.has(e.role)&&this.createBinding(t,this.roleBindings.get(e.role))}else if("group"===t.type)for(const e of t.childTracks)this.resolveTrackBinding(e)}createBinding(t,e){const i=e instanceof l?e.object:e,a={track:t,target:e,activeActions:new Map,originalTransform:{position:i.position.clone(),rotation:i.rotation.clone(),scale:i.scale.clone()},originalParent:i.parent};t.subTracks.some(t=>"animation"===t.type)&&(a.mixer=new s(i)),this.bindings.set(t.id,a)}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 t of this.audioByClip.values())t.pause()}pauseVfx(){for(const t of this.vfxActors.values())t.pause()}resumeVfx(){for(const[t,e]of this.vfxActors.entries())(this.activeVfxClips.has(t)||e.getParticleCount()>0)&&e.play()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear()}restart(){this.stop(),this.play()}seek(t){const e=Math.max(0,Math.min(t,this._duration));this._time.next(e),this.evaluate(e)}update(t){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const e of this.bindings.values())e.mixer&&e.mixer.update(t*this._timescale);for(const e of this.spawnedInstances.values())e.mixer&&e.mixer.update(t*this._timescale);return}const e=this._time.value+t*this._timescale;if(e>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();this.loopCount++,this._time.next(e%this._duration),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}else this._time.next(e);this.evaluate(this._time.value);for(const e of this.bindings.values())e.mixer&&e.mixer.update(t*this._timescale);for(const e of this.spawnedInstances.values())e.mixer&&e.mixer.update(t*this._timescale)}evaluate(t){if(this.sequenceData)for(const e of this.sequenceData.tracks){if(!e.muted&&("object"===e.type||"locator"===e.type||"spawn"===e.type||"vfx"===e.type)){const t=this.bindings.get(e.id);this.updateTrackParenting(e,t)}this.evaluateTrack(e,t)}}evaluateTrack(t,e){if(t.muted)return;const i=this.bindings.get(t.id);(0,this.trackRuntimeEvaluators[A(t.type).runtimeEvaluator])(t,i,e)}evaluateObjectTrack(t,e,i){this.evaluateSubTracks(t.subTracks,e,i)}evaluateLocatorTrack(t,e,i){this.evaluateSubTracks(t.subTracks,e,i)}evaluateSubTracks(t,e,i){for(const s of t){if(s.muted)continue;(0,this.subTrackRuntimeEvaluators[v(s.type).runtimeEvaluator])(s,e,i)}}evaluateTransformSubTrack(t,e,i){const s=t.keyframes;if(0===s.length)return;const{prev:a,next:n,t:o}=S(s,i);if(a)if(n&&a!==n){const i=b(o,a.interpolation);t.components.position&&a.position&&n.position&&e.position.lerpVectors(M.fromArray(a.position),E.fromArray(n.position),i),t.components.rotation&&a.rotation&&n.rotation&&(R.setFromEuler(D.fromArray([...a.rotation,"XYZ"])),V.setFromEuler($.fromArray([...n.rotation,"XYZ"])),e.quaternion.slerpQuaternions(R,V,i)),t.components.scale&&a.scale&&n.scale&&e.scale.lerpVectors(M.fromArray(a.scale),E.fromArray(n.scale),i)}else t.components.position&&a.position&&e.position.fromArray(a.position),t.components.rotation&&a.rotation&&e.rotation.fromArray([...a.rotation,"XYZ"]),t.components.scale&&a.scale&&e.scale.fromArray(a.scale)}evaluateAnimationSubTrack(t,e,s){if(!e.mixer||!e.activeActions)return;if(e.target instanceof l?e.target.object:e.target)for(const a of t.clips){const n=a.startTime+a.duration,o=s>=a.startTime&&s<n,r=`${t.id}-${a.id}`;let c=e.activeActions.get(r),u=!1;if(o){if(!c){u=!0;const t=a.animationClipAssetId;if(null==t)continue;const s=this.animationClips.get(t);if(null==s){this.ensureAnimationClip(t);continue}const n=this.prepareAnimationPlayback(t,s,a),o=e;let d=!1;if(e.target instanceof l){o.charAnimComponent||(o.charAnimComponent=e.target.getComponent(I)??void 0);const i=o.charAnimComponent;if(null!=i){const l=a.rootMotion?x(a)?this.getPlayableAnimationClip(t,s,a,!0):B.fromClip(n.clip,!1):n.clip;if(this._externalTimeControl)c=i.beginExternalAnimationControl(l,{timeScale:n.timeScale});else if(i.play(l,{inPlace:!a.rootMotion,loop:!1,priority:20,timeScale:n.timeScale,fadeTime:a.fadeInDuration??.2,offset:n.startOffset}),c=i.getFullBodyAction(),a.rootMotion){const t=e.target.getComponent(q);t&&t.setRootMotionAction(c)}e.activeActions.set(r,c),o.charAnimActionKeys||(o.charAnimActionKeys=new Set),o.charAnimActionKeys.add(r),d=!0}}d||(c=e.mixer.clipAction(n.clip),c.setLoop(i.LoopOnce,1),c.clampWhenFinished=!0,c.timeScale=n.timeScale,n.startOffset>0&&(c.time=n.startOffset),e.activeActions.set(r,c),c.play())}if(c){const t=e;if(this._externalTimeControl){t.charAnimComponent?.beginExternalControl();const i=this.getAnimationPlaybackLocalTime(a,s),n=Math.min(i,c.getClip().duration);(u||Math.abs(c.time-n)>.001)&&(c.time=n,c.paused=!1,c.play(),t.charAnimComponent?t.charAnimComponent.getMixer()?.update(0):e.mixer&&e.mixer.update(0))}else t.charAnimComponent?.endExternalControl()}}else if(c){e.activeActions.delete(r);const t=e;t.charAnimActionKeys?.has(r)?(t.charAnimActionKeys.delete(r),0===t.charAnimActionKeys.size&&t.charAnimComponent&&(t.charAnimComponent.stopSequenceAnimation(),t.charAnimComponent=void 0)):(c.stop(),this._externalTimeControl&&e.mixer&&e.mixer.update(0))}}}evaluateVisibilitySubTrack(t,e,i){const s=t.keyframes;if(0===s.length)return;let a=s[0];for(const t of s){if(!(t.time<=i))break;a=t}e.visible=a.visible}evaluatePropertySubTrack(t,e,i){w(t.keyframes,i)}evaluateParameterSubTrack(t,e,i){if("audioParameter"===t.type)return;const s=w(t.keyframes,i);s&&("property"!==t.type?this.applyResolvedMaterialValue(t,e,s):this.applyResolvedPropertyValue(t,e,s))}evaluateEventSubTrack(t,e,i){if(e instanceof l&&this._state.value===SequencePlaybackState.Playing)for(const s of t.events){const a=`${t.id}-${s.id}`;if(i>=s.time&&!this.firedEvents.has(a)){if(this.firedEvents.add(a),s.editorOnly&&!this._inEditor)continue;if(!s.functionName)continue;const t=e[s.functionName];"function"==typeof t?this.invokeSequenceEvent(e,s.functionName,t,s.arguments??[]):console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>i&&this.firedEvents.delete(a)}}evaluateCameraTrack(t,e){}evaluateAudioTrack(t,e){if(!this.assetLoader||!t.clips||0===t.clips.length)return;const i=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(t,e);t.volume;for(const a of t.clips){const n=a.startTime+a.duration,o=e>=a.startTime&&e<n,r=`${t.id}-${a.id}`;if(o){if(this.activeAudioClips.has(r)||this.activeAudioClips.add(r),i){const i=this.audioByClip.get(r);i&&i.isPlaying||this.tryStartAudioClip(t,a,r,e,s)}const n=this.audioByClip.get(r);n&&this.applyAudioParameters(n,t,a,r,e,s)}else this.activeAudioClips.has(r)&&(this.activeAudioClips.delete(r),this.lastAudioStartAttemptTime.delete(r),this.audioStartInFlight.delete(r),this.stopAudioClip(r))}}tryStartAudioClip(t,e,i,s,a){if(this.audioStartInFlight.has(i))return;const n=this.lastAudioStartAttemptTime.get(i);if(void 0!==n&&s-n<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(i,s);const o=this.playAudioClip(t,e,i,s,a).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(i)===o&&this.audioStartInFlight.delete(i)});this.audioStartInFlight.set(i,o)}applyAudioParameters(t,e,s,a,n,o){const r=o.volume??1,c=this.stringToRandom(a+e.id),l=s.volumeRandomization?(2*c-1)*s.volumeRandomization:0;let u=1;const d=n-s.startTime;d<s.fadeInDuration&&s.fadeInDuration>0?u=d/s.fadeInDuration:d>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(u=(s.duration-d)/s.fadeOutDuration);const h=Math.max(0,(e.volume??1)*r*(s.volume+l)*u);t.setVolume(h);let p=o.detune??0;if(s.pitchRandomization){p+=(2*this.stringToRandom(a+"_pitch")-1)*s.pitchRandomization}if(t.setDetune(p),t.hasPlaybackControl&&t.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,n=[],r=o.lowpass,c=o.highpass;let l=this.audioFilters.get(a);if(void 0!==r||void 0!==c)l||(l=s.createBiquadFilter(),this.audioFilters.set(a,l)),void 0!==r?(l.type="lowpass",l.frequency.value=r):void 0!==c&&(l.type="highpass",l.frequency.value=c),n.push(l);else if(l){try{l.disconnect()}catch{}this.audioFilters.delete(a)}const u=o.pan;if(!e.spatial&&t instanceof i.Audio&&void 0!==u&&"function"==typeof s.createStereoPanner){let t=this.audioPannerNodes.get(a);t||(t=s.createStereoPanner(),this.audioPannerNodes.set(a,t)),t.pan.value=u,n.push(t)}else{const t=this.audioPannerNodes.get(a);if(t){try{t.disconnect()}catch{}this.audioPannerNodes.delete(a)}}t.setFilters(n)}e.spatial&&t instanceof i.PositionalAudio?this.updatePositionalAudioTransform(t,e,s,o.spatialBlend):void 0!==o.pan&&this.audioListener}updatePositionalAudioTransform(t,e,s,a){let n=null,o=null;const r=s.attachedToTrackId||e.parent?.trackId,c=s.attachmentSocketName||e.parent?.socketName;if(r){const t=this.sequenceData?.tracks.find(t=>t.id===r);if(t){const e=this.getActiveObjectsForTrack(t);if(e.length>0){const t=e[0];if(n=M,o=R,t.getWorldPosition(n),t.getWorldQuaternion(o),c){const e=this.findSocket(t,c);e&&(e.getWorldPosition(n),e.getWorldQuaternion(o))}}}}if(n&&o){const e="number"==typeof a?i.MathUtils.clamp(a,0,1):1;if(e<1&&this.audioListener){const t=O;this.audioListener.getWorldPosition(t),n=n.clone().lerp(t,1-e)}t.position.copy(n),t.quaternion.copy(o),t.updateMatrixWorld()}}async playAudioClip(t,e,s,a,n){if(!this.assetLoader||!e.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(t){return void console.warn("Failed to resume audio context:",t)}this.stopAudioClip(s);const o=this.clearCounter;try{let a=this.audioBuffers.get(e.audioAssetId);if(!a){let t=this.loadingAudioBuffers.get(e.audioAssetId);t||(t=this.assetLoader.getAudioByAssetId(e.audioAssetId),this.loadingAudioBuffers.set(e.audioAssetId,t));try{a=await t,this.audioBuffers.set(e.audioAssetId,a)}finally{this.loadingAudioBuffers.delete(e.audioAssetId)}}if(o!==this.clearCounter)return;const r=this._time.value,c=e.startTime+e.duration;if(!(r>=e.startTime&&r<c))return;const l=Math.max(0,r-e.startTime),u=e.clipStartOffset+l*e.playbackRate;if(u>=a.duration||l>=e.duration)return;let d=this.audioByClip.get(s);const h=!0===t.spatial,p=d&&!0===d.isPositionalAudio;if(d&&h!==p&&(d.isPlaying&&d.stop(),d.disconnect(),this.audioByClip.delete(s),d=void 0),!d){if(h){const t=new i.PositionalAudio(this.audioListener);t.setRefDistance(10),t.setRolloffFactor(1),d=t}else d=new i.Audio(this.audioListener);this.world&&this.world.scene.add(d),this.audioByClip.set(s,d)}Math.min((e.duration-l)/e.playbackRate,(a.duration-u)/e.playbackRate);d.setLoopStart(e.clipStartOffset),d.setLoopEnd(Math.min(e.clipStartOffset+e.duration,a.duration)),d.setLoop(!0),d.setBuffer(a),this.applyAudioParameters(d,t,e,s,r,n),d.isPlaying||d.play()}catch(t){console.error(`Failed to play audio clip ${e.id}:`,t)}}stopAudioClip(t){const e=this.audioByClip.get(t);if(e){try{e.isPlaying&&e.stop()}catch(t){}e.parent&&e.parent.remove(e),this.audioByClip.delete(t)}const i=this.audioGainNodes.get(t);i&&(i.disconnect(),this.audioGainNodes.delete(t));const s=this.audioFilters.get(t);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(t)}const a=this.audioPannerNodes.get(t);if(a){try{a.disconnect()}catch{}this.audioPannerNodes.delete(t)}}stopAllAudio(){for(const t of this.audioByClip.keys())this.stopAudioClip(t);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(t,e){if(!this.vfxService||!this.world||!t.clips||0===t.clips.length)return;const i=new Set,s=new Map;for(const a of t.clips){const n=this.getVfxClipKey(t,a);s.set(n,a);const o=a.startTime+a.duration;e>=a.startTime&&e<o&&i.add(n)}const a=[];for(const e of this.activeVfxClips)e.startsWith(`${t.id}-`)&&(i.has(e)||a.push(e));for(const t of a)this.activeVfxClips.delete(t);for(const[a,n]of s.entries()){const s=this.vfxActors.get(a);i.has(a)&&!this.activeVfxClips.has(a)?(this.activeVfxClips.add(a),this.ensureVfxActor(t,n,a)):i.has(a)&&s?(this.updateVfxTransform(t,s,e),this._state.value===SequencePlaybackState.Playing&&s.play()):s&&this.applyInactiveVfxClipBehavior(n,s,e)}}getVfxClipKey(t,e){return`${t.id}-${e.id}-${e.vfxAssetId}`}applyInactiveVfxClipBehavior(t,e,i){const s=t.endBehavior??"finish";if("finish"===s)return void e.stop();if("kill"===s)return void e.applyClipEndBehavior(s);const a=t.startTime+t.duration,n=Math.max(i-a,0),o=Math.max(0,t.expireWithinSeconds??.25),r=Math.max(0,o-n);e.applyClipEndBehavior(s,r)}async ensureVfxActor(t,e,i){if(!this.vfxService||!e.vfxAssetId)return;if(this.vfxActors.has(i)){const t=this.vfxActors.get(i);return t.restart(),void t.play()}const s=this.clearCounter;try{const a=await this.vfxService.createFromAssetId(e.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(a));const{position:n,rotation:o,scale:r}=this.getVfxTransform(t,e.startTime);a.object.position.copy(n),a.object.rotation.copy(o),a.object.scale.copy(r),this.vfxActors.set(i,a),this._state.value===SequencePlaybackState.Playing&&a.play()}catch(t){console.error(`Failed to create VFX actor for clip ${e.id}:`,t)}}getVfxTransform(t,e){const i=new r,s=new a,n=new r(1,1,1),c=t.subTracks.find(t=>"transform"===t.type);if(c&&c.keyframes.length>0){const{prev:t,next:a,t:r}=S(c.keyframes,e);if(t&&(t.position&&i.fromArray(t.position),t.rotation&&s.fromArray([...t.rotation,"XYZ"]),t.scale&&n.fromArray(t.scale)),a&&t!==a&&t.time!==a.time){const e=b(r,t.interpolation);if(t.position&&a.position&&i.lerpVectors(M.fromArray(t.position),E.fromArray(a.position),e),t.rotation&&a.rotation){R.setFromEuler(D.fromArray([...t.rotation,"XYZ"])),V.setFromEuler($.fromArray([...a.rotation,"XYZ"]));const i=new o;i.slerpQuaternions(R,V,e),s.setFromQuaternion(i)}t.scale&&a.scale&&n.lerpVectors(M.fromArray(t.scale),E.fromArray(a.scale),e)}}else i.fromArray(t.position),s.fromArray([...t.rotation,"XYZ"]),n.fromArray(t.scale);return{position:i,rotation:s,scale:n}}updateVfxTransform(t,e,i){const{position:s,rotation:a,scale:n}=this.getVfxTransform(t,i);e.object.position.copy(s),e.object.rotation.copy(a),e.object.scale.copy(n)}resolveActorType(t){const e=this.actorFactory.classes[t];if(null!=e)return e;const i=u[t];return i||(console.warn(`Could not resolve actor type: ${t}`),null)}async spawnActorForClip(t,e,i,s){if(!this.world||!t.actorType)return null;const a=this.resolveActorType(t.actorType);if(!a)return null;try{return await this.world.spawnActor(a,i,s)}catch(e){return console.error(`Failed to spawn actor ${t.actorType}:`,e),null}}async spawnPrefabForClip(t,e,i,s){if(!this.world||!this.assetLoader||!t.prefabId)return null;try{const e=await this.assetLoader.getPrefabById(t.prefabId);if(!e)return null;return await this.world.spawnPrefab(e,i,s)}catch(e){return console.error(`Failed to spawn prefab ${t.prefabId}:`,e),null}}async spawnMeshForClip(t,e,i,s){if(!this.world||!this.assetLoader||!t.meshId)return null;try{const e=await this.assetLoader.getAsset(t.meshId),a=await this.assetLoader.getModelByAssetId(t.meshId),n=P.clone(a.scene);if(n.position.copy(i),n.rotation.copy(s),e){await this.assetLoader.applyMaterials(e,n);const t=e.mesh?.rescale;null!=t&&1!==t&&n.scale.multiplyScalar(t)}return this.world.scene.add(n),n}catch(e){return console.error(`Failed to spawn mesh ${t.meshId}:`,e),null}}despawnInstance(t){if(this.world)switch(t?.type){case"actor":this.world.removeActor(t.instance);break;case"prefab":this.world.removePrefab(t.instance);break;case"mesh":this.world.scene.remove(t.instance)}}despawnAll(){for(const t of this.spawnedInstances.values())this.despawnInstance(t);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(t,e,i){const s=new r,n=new a,o=t.subTracks.find(t=>"transform"===t.type);if(o&&o.keyframes.length>0){const{prev:t}=S(o.keyframes,i);t&&(t.position&&s.fromArray(t.position),t.rotation&&n.fromArray([...t.rotation,"XYZ"]))}else e.initialPosition&&s.fromArray(e.initialPosition),e.initialRotation&&n.fromArray([...e.initialRotation,"XYZ"]);return{position:s,rotation:n}}evaluateSpawnTrack(t,e,i){if(!t.clips||0===t.clips.length)return;const s=e||this.bindings.get(t.id);if(s&&s.target)for(const e of t.clips){const a=e.startTime+e.duration,n=i>=e.startTime&&i<a,o=`${t.id}-${e.id}`;if(n){this.activeClips.has(o)||(this.activeClips.add(o),this.spawnedInstances.set(o,{type:"proxy",target:s.target}));(s.target instanceof l?s.target.object:s.target)&&this.evaluateSubTracks(t.subTracks,s,i)}else this.activeClips.has(o)&&(this.activeClips.delete(o),this.spawnedInstances.delete(o))}else for(const e of t.clips){const s=e.startTime+e.duration,a=i>=e.startTime&&i<s,n=`${t.id}-${e.id}`,o=this.spawnedInstances.has(n),r=this.pendingSpawns.has(n);if(!a||o||r){if(a&&o){const e=this.spawnedInstances.get(n);e&&"proxy"!==e.type&&this.evaluateSubTracks(t.subTracks,e,i)}else if(!a&&o){const t=this.spawnedInstances.get(n);t&&(this.despawnInstance(t),this.spawnedInstances.delete(n),this.activeClips.delete(n))}}else{const{position:i,rotation:s}=this.getInitialTransform(t,e,e.startTime);this.pendingSpawns.add(n),this.spawnForClip(t,e,i,s,n)}}}getInstanceObject(t){switch(t.type){case"actor":return t.instance.object;case"prefab":return t.instance.mainActor?.object||t.instance.object;case"mesh":return t.instance;case"proxy":return t.target instanceof l?t.target.object:t.target;default:return null}}async spawnForClip(t,e,i,a,n){const o=this.clearCounter;let r=null;try{switch(t.spawnType){case"actor":const s=await this.spawnActorForClip(t,e,i,a);s&&(r={type:"actor",instance:s});break;case"prefab":const n=await this.spawnPrefabForClip(t,e,i,a);n&&(r={type:"prefab",instance:n});break;case"mesh":const o=await this.spawnMeshForClip(t,e,i,a);o&&(r={type:"mesh",instance:o})}if(o!==this.clearCounter)return void(r&&this.despawnInstance(r));const c=this._time.value,l=c>=e.startTime&&c<e.startTime+e.duration;if(r&&l){const e=this.getInstanceObject(r);"proxy"===r.type||("actor"===r.type?r.target=r.instance:"prefab"===r.type?r.target=r.instance.mainActor||r.instance.object:r.target=e);t.subTracks.some(t=>"animation"===t.type)&&e&&(r.mixer=new s(e),r.activeActions=new Map),this.spawnedInstances.set(n,r),this.activeClips.add(n)}else r&&this.despawnInstance(r)}finally{this.pendingSpawns.delete(n)}}getPlayableObject(t){return t.target instanceof l?t.target.object:t.target??null}applyResolvedPropertyValue(t,e,i){}applyResolvedMaterialValue(t,e,i){}async ensureAnimationClip(t){if(!this.assetLoader)return null;const e=this.animationClips.get(t);if(e)return e;const i=this.loadingAnimationClips.get(t);if(i)return i;const s=(async()=>{try{const e=await this.assetLoader.getAnimationClipByAssetId(t);return e&&this.animationClips.set(t,e),e}catch(e){return console.error(`Failed to load animation clip for asset ${t}:`,e),null}finally{this.loadingAnimationClips.get(t)===s&&this.loadingAnimationClips.delete(t)}})();return this.loadingAnimationClips.set(t,s),s}prepareAnimationPlayback(t,e,i){if(!x(i)){let t=e;return i.clipEndOffset>0&&(t=t.clone(),t.duration=Math.max(0,t.duration-i.clipEndOffset)),{clip:t,timeScale:i.playbackRate,startOffset:i.clipStartOffset}}return{clip:this.getPlayableAnimationClip(t,e,i,!1),timeScale:1,startOffset:0}}getPlayableAnimationClip(t,e,i,s){if(!x(i))return s?B.fromClip(e,!1):e;const a=`${i.id}:${s?"root":"base"}`,n=`${T(i)}|${s?"root":"base"}`,o=this.retimedAnimationClips.get(a);if(o&&o.assetId===t&&o.signature===n)return o.clip;const r=k(e,i),c=s?B.fromClip(r,!1):r;return this.retimedAnimationClips.set(a,{assetId:t,signature:n,clip:c}),c}getAnimationPlaybackLocalTime(t,e){const i=Math.max(0,e-t.startTime);return x(t)?i:i*t.playbackRate+t.clipStartOffset}clearRetimedAnimationClipCache(t){if(null!=t)for(const[e,i]of this.retimedAnimationClips.entries())i.assetId===t&&this.retimedAnimationClips.delete(e);else this.retimedAnimationClips.clear()}captureOriginalTransforms(){for(const t of this.bindings.values()){const e=t.target instanceof l?t.target.object:t.target;e&&(t.originalTransform={position:e.position.clone(),rotation:e.rotation.clone(),scale:e.scale.clone()})}}restoreOriginalTransforms(){for(const t of this.bindings.values())if(t.originalTransform){const e=t.target instanceof l?t.target.object:t.target;e&&(e.position.copy(t.originalTransform.position),e.rotation.copy(t.originalTransform.rotation),e.scale.copy(t.originalTransform.scale))}}stopAllAnimations(){for(const t of this.bindings.values()){for(const e of t.activeActions.values())e.stop();t.activeActions.clear(),t.mixer&&t.mixer.stopAllAction(),t.charAnimComponent&&(t.charAnimComponent.stopSequenceAnimation(),t.charAnimComponent=void 0),t.charAnimActionKeys?.clear()}}stopAllVfx(){for(const t of this.vfxActors.values())t.paused||t.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.clearLocatorBindings(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const t of this.vfxActors.values())this.world.removeActor(t);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.loadingAnimationClips.clear(),this.clearRetimedAnimationClipCache(),this.audioByClip.clear()}updateTrackParenting(t,e){const i=this.getActiveObjectsForTrack(t);if(0===i.length)return;let s=null;const a=t.parent?.trackId;if(a){const e=this.sequenceData?.tracks.find(t=>t.id===a);if(e){const i=this.getActiveObjectsForTrack(e);if(i.length>0&&(s=i[0],t.parent?.socketName)){const e=this.findSocket(s,t.parent.socketName);e&&(s=e)}}}for(const a of i)s?a.parent!==s&&(s.add(a),!e||"object"!==t.type&&"locator"!==t.type||(e.currentParent=s)):e?.currentParent&&e.currentParent===a.parent?this.restoreObjectParent(e,a):a.parent&&a.parent!==this.world?.scene&&"object"!==t.type&&"locator"!==t.type&&this.world?.scene.add(a)}findSocket(t,e){if(t.name===e)return t;if(t instanceof i.SkinnedMesh){const i=t.skeleton.bones.find(t=>t.name===e);if(i)return i}return t.getObjectByName(e)||null}getActiveObjectsForTrack(t){if("object"===t.type){const e=this.bindings.get(t.id);if(e&&e.target)return[e.target instanceof l?e.target.object:e.target]}else if("locator"===t.type){const e=this.bindings.get(t.id);if(e&&e.target instanceof n)return[e.target]}else{if("spawn"===t.type){const e=[];for(const[i,s]of this.spawnedInstances)if(i.startsWith(t.id+"-")&&this.activeClips.has(i)){const t=this.getInstanceObject(s);t&&e.push(t)}return e}if("vfx"===t.type){const e=[];for(const i of this.activeVfxClips)if(i.startsWith(t.id+"-")){const t=this.vfxActors.get(i);t&&e.push(t.object)}return e}}return[]}restoreObjectParent(t,e){t.originalParent?t.originalParent.add(e):this.world&&this.world.scene.add(e),t.currentParent=void 0}restoreOriginalParents(){for(const t of this.bindings.values())if(t.currentParent){const e=t.target instanceof l?t.target.object:t.target;e&&this.restoreObjectParent(t,e)}}evaluateAudioSubTracks(t,e){const i={};for(const s of t.subTracks)if("audioParameter"===s.type){const t=s,a=y(t.parameter),n=C(t.keyframes,e,{min:a.min,max:a.max});void 0!==n&&(i[t.parameter]=n)}return i}stringToRandom(t){let e=0;for(let i=0;i<t.length;i++){e=(e<<5)-e+t.charCodeAt(i),e&=e}const i=1e4*Math.sin(e);return i-Math.floor(i)}refreshAsset(t){this.assetLoader?.clearCacheById(t),this.animationClips.delete(t),this.loadingAnimationClips.delete(t),this.clearRetimedAnimationClipCache(t),this.vfxService?.clearPool(t);for(const[e,i]of this.vfxActors.entries())e.endsWith(`-${t}`)&&(this.world&&this.world.removeActor(i),this.vfxActors.delete(e),this.activeVfxClips.delete(e));for(const[e,i]of this.spawnedInstances.entries()){const s=e.split("-")[0],a=this.sequenceData?.tracks.find(t=>t.id===s);!a||a.prefabId!==t&&a.meshId!==t||(this.despawnInstance(i),this.spawnedInstances.delete(e),this.activeClips.delete(e))}}async invokeSequenceEvent(t,e,i,s){let a=!1;for(let t=0;t<s.length;t++)if(p(s[t])){a=!0;break}if(a)try{const e=new Array(s.length);for(let t=0;t<s.length;t++)e[t]=f(s[t],this.sequenceEventAsyncResolvers);const a=await Promise.all(e);await i.call(t,...a)}catch(t){console.error(`Failed to call sequence event ${e}:`,t)}else try{const e=new Array(s.length);for(let t=0;t<s.length;t++)e[t]=m(s[t],this.sequenceEventSyncResolvers);i.call(t,...e)}catch(t){console.error(`Failed to call sequence event ${e}:`,t)}}resolveSequenceEventActorReference(t){if(!this.world||null==t)return null;const e=t,i="object"==typeof e&&null!=e?.id?e.id:"string"==typeof e?e:null;if(null==i)return null;for(const t of this.world.actors){const e=t.object.userData.src??t.object.userData._src;if(e?.id===i)return t}return null}resolveSequenceEventSequence(t){return function(t){return"object"==typeof t&&null!=t&&"duration"in t&&"tracks"in t}(t)?new g(t):this.assetLoader&&"string"==typeof t?this.assetLoader.getSequenceById(t):null}async resolveSequenceEventAnimationClip(t){const e="string"==typeof t?t:"object"==typeof t&&null!=t?t.assetId??null:null;return null!=e&&this.assetLoader?this.assetLoader.getAnimationClipByAssetId(e):null}}function L(t){const e=[];for(const i of t)e.push(i),"group"===i.type&&e.push(...L(i.childTracks));return e}function _(t){if("string"!=typeof t)return null;const e=t.trim();return e.length>0?e:null}function j(t){const e=new i.Group;e.name=`SequenceLocatorMarker:${t}`,e.renderOrder=1e3;const s=new i.AxesHelper(.35);s.renderOrder=1e3;const a=Array.isArray(s.material)?s.material:[s.material];for(const t of a)t.depthTest=!1,t.transparent=!0,t.opacity=.9,t.toneMapped=!1;e.add(s);const n=function(t){if("undefined"==typeof document)return null;const e=document.createElement("canvas");e.width=256,e.height=64;const s=e.getContext("2d");if(!s)return null;s.clearRect(0,0,e.width,e.height),s.fillStyle="rgba(16, 18, 24, 0.78)",function(t,e,i,s,a,n){const o=e+s,r=i+a;t.beginPath(),t.moveTo(e+n,i),t.lineTo(o-n,i),t.quadraticCurveTo(o,i,o,i+n),t.lineTo(o,r-n),t.quadraticCurveTo(o,r,o-n,r),t.lineTo(e+n,r),t.quadraticCurveTo(e,r,e,r-n),t.lineTo(e,i+n),t.quadraticCurveTo(e,i,e+n,i),t.closePath()}(s,0,8,e.width,48,8),s.fill(),s.font="24px sans-serif",s.textAlign="center",s.textBaseline="middle",s.fillStyle="#f8fafc",s.fillText(t||"Locator",e.width/2,e.height/2);const a=new i.CanvasTexture(e);a.needsUpdate=!0;const n=new i.SpriteMaterial({map:a,transparent:!0,depthTest:!1});n.toneMapped=!1;const o=new i.Sprite(n);return o.scale.set(.9,.225,1),o}(t);return n&&(n.position.set(0,.45,0),n.renderOrder=1001,e.add(n)),e.traverse(t=>{t.raycast=()=>{}}),e}function F(t){t.traverse(t=>{const e=t.material;if(Array.isArray(e))for(const t of e)t?.dispose?.(),t?.map?.dispose?.();else e?.dispose?.(),e?.map?.dispose?.()})}const M=new r,E=new r,O=new r,R=new o,V=new o,D=new a,$=new a;/*
|
|
1
|
+
import{BehaviorSubject as e,Subject as t}from"rxjs";import*as a from"three";import{AnimationMixer as i,Color as s,Euler as r,Object3D as n,Quaternion as o,Vector2 as l,Vector3 as c,Vector4 as u}from"three";import{VisualEffect as h}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{Sequence as S}from"./sequence-data.js";import{getSequenceSubTrackDefinition as b,getSequenceTrackDefinition as w}from"./sequence-definitions.js";import{applyInterpolation as k,evaluateCustomParamValueKeyframes as T,evaluateNumericKeyframes as P,findKeyframeSpan as x}from"./sequence-value-lane.js";import{buildRetimedAnimationClip as B,getAnimationClipRetimingSignature as q,isAnimationClipUsingRetiming as I}from"./sequence-animation-retiming.js";import{SkeletonUtils as O}from"three-stdlib";import{CharacterAnimationComponent as M,CharacterMovementComponent as F}from"../../gameplay/actors/index.js";import{RootMotionClip as j}from"../../gameplay/animation/root-motion.js";import{hashCameraShakeSeed as _}from"../../gameplay/services/camera-shake.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.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.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 h(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),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 i=this.getPlayableObject(t);i&&this.evaluateTransformSubTrack(e,i,a)},animation:(e,t,a)=>this.evaluateAnimationSubTrack(e,t,a),visibility:(e,t,a)=>{const i=this.getPlayableObject(t);i&&this.evaluateVisibilitySubTrack(e,i,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.clearLocatorBindings(),this.clearSequenceCameras(),this.clearCameraShakeContributions(),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.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 i=await a;if(t!==this.clearCounter)return;this.audioBuffers.set(e,i)}catch(e){}finally{this.loadingAudioBuffers.get(e)===a&&this.loadingAudioBuffers.delete(e)}}))}getAnimationClipAssetIdsForSequence(e){const t=new Set;for(const a of $(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=W(e);if(!t||!this.sequenceData)return[];const a=[];for(const e of $(this.sequenceData.tracks)){if("locator"!==e.type)continue;if(W(e.bindingId)!==t)continue;const i=this.bindings.get(e.id),s=i?this.getPlayableObject(i):null;s&&(s.updateWorldMatrix(!0,!1),a.push({trackId:e.id,name:e.name,bindingId:e.bindingId,position:s.getWorldPosition(new c),rotation:s.getWorldQuaternion(new o),scale:s.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 $(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=N(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())X(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,s={track:e,target:t,activeActions:new Map,originalTransform:{position:a.position.clone(),rotation:a.rotation.clone(),scale:a.scale.clone()},originalParent:a.parent};e.subTracks.some(e=>"animation"===e.type)&&(s.mixer=new i(a)),this.bindings.set(e.id,s)}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()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions()}restart(){this.stop(),this.play()}seek(e){const t=Math.max(0,Math.min(e,this._duration));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.restoreAllPropertySnapshots(),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();this.loopCount++,this._time.next(t%this._duration),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();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()}}evaluateTrack(e,t){if(e.muted)return;const a=this.bindings.get(e.id);(0,this.trackRuntimeEvaluators[w(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=$(this.sequenceData.tracks).find(t=>t.id===e);return t?this.getActiveObjectsForTrack(t):[]}evaluateSubTracks(e,t,a){for(const i of e){if(i.muted)continue;(0,this.subTrackRuntimeEvaluators[b(i.type).runtimeEvaluator])(i,t,a)}}evaluateTransformSubTrack(e,t,a){const i=e.keyframes;if(0===i.length)return;const{prev:s,next:r,t:n}=x(i,a);if(s)if(r&&s!==r){const a=k(n,s.interpolation);e.components.position&&s.position&&r.position&&t.position.lerpVectors(Q.fromArray(s.position),Y.fromArray(r.position),a),e.components.rotation&&s.rotation&&r.rotation&&(z.setFromEuler(G.fromArray([...s.rotation,"XYZ"])),H.setFromEuler(U.fromArray([...r.rotation,"XYZ"])),t.quaternion.slerpQuaternions(z,H,a)),e.components.scale&&s.scale&&r.scale&&t.scale.lerpVectors(Q.fromArray(s.scale),Y.fromArray(r.scale),a)}else e.components.position&&s.position&&t.position.fromArray(s.position),e.components.rotation&&s.rotation&&t.rotation.fromArray([...s.rotation,"XYZ"]),e.components.scale&&s.scale&&t.scale.fromArray(s.scale)}evaluateAnimationSubTrack(e,t,i){if(!t.mixer||!t.activeActions)return;if(t.target instanceof p?t.target.object:t.target)for(const s of e.clips){const r=s.startTime+s.duration,n=i>=s.startTime&&i<r,o=`${e.id}-${s.id}`;let l=t.activeActions.get(o),c=!1;if(n){if(!l){c=!0;const e=s.animationClipAssetId;if(null==e)continue;const i=this.animationClips.get(e);if(null==i){this.ensureAnimationClip(e);continue}const r=this.prepareAnimationPlayback(e,i,s),n=t;let u=!1;if(t.target instanceof p){n.charAnimComponent||(n.charAnimComponent=t.target.getComponent(M)??void 0);const a=n.charAnimComponent;if(null!=a){const c=s.rootMotion?I(s)?this.getPlayableAnimationClip(e,i,s,!0):j.fromClip(r.clip,!1):r.clip;if(this._externalTimeControl)l=a.beginExternalAnimationControl(c,{timeScale:r.timeScale});else if(a.play(c,{inPlace:!s.rootMotion,loop:!1,priority:20,timeScale:r.timeScale,fadeTime:s.fadeInDuration??.2,offset:r.startOffset}),l=a.getFullBodyAction(),s.rootMotion){const e=t.target.getComponent(F);e&&e.setRootMotionAction(l)}t.activeActions.set(o,l),n.charAnimActionKeys||(n.charAnimActionKeys=new Set),n.charAnimActionKeys.add(o),u=!0}}u||(l=t.mixer.clipAction(r.clip),l.setLoop(a.LoopOnce,1),l.clampWhenFinished=!0,l.timeScale=r.timeScale,r.startOffset>0&&(l.time=r.startOffset),t.activeActions.set(o,l),l.play())}if(l){const e=t;if(this._externalTimeControl){e.charAnimComponent?.beginExternalControl();const a=this.getAnimationPlaybackLocalTime(s,i),r=Math.min(a,l.getClip().duration);(c||Math.abs(l.time-r)>.001)&&(l.time=r,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),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 i=e.keyframes;if(0===i.length)return;let s=i[0];for(const e of i){if(!(e.time<=a))break;s=e}t.visible=s.visible}evaluatePropertySubTrack(e,t,a){const i=T(e.keyframes,a,{min:e.range?.[0],max:e.range?.[1],stepOnly:L(e)});i&&this.applyResolvedPropertyValue(e,t,i)}evaluateParameterSubTrack(e,t,a){if("audioParameter"===e.type)return;const i=T(e.keyframes,a,"property"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:L(e)}:{});i&&("property"!==e.type?this.applyResolvedMaterialValue(e,t,i):this.applyResolvedPropertyValue(e,t,i))}evaluateEventSubTrack(e,t,a){if(t instanceof p&&this._state.value===SequencePlaybackState.Playing)for(const i of e.events){const s=`${e.id}-${i.id}`;if(a>=i.time&&!this.firedEvents.has(s)){if(this.firedEvents.add(s),i.editorOnly&&!this._inEditor)continue;if(!i.functionName)continue;const e=t[i.functionName];"function"==typeof e?this.invokeSequenceEvent(t,i.functionName,e,i.arguments??[]):console.warn(`Sequence event method '${i.functionName}' not found on actor`)}else i.time>a&&this.firedEvents.delete(s)}}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,i=a.id;this.nextCameraShakeClipKeys.add(i),this.viewController.setCameraShakeContribution(this,i,a,e,a.seed??_(a.id))}}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 i=e.cameraSettings??{fov:60,near:.1,far:1e3};t=new a.PerspectiveCamera(i.fov??60,this.getCurrentCameraAspect(),i.near??.1,i.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 $(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const i=a.clips??[];for(const s of i)this.isCameraClipActive(s,e)&&(t={track:a,clip:s,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,s)})}return t}findBlendOutCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of $(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const i=a.clips??[];for(const s of i){const i=Math.max(0,s.blendOutDuration??0);if(i<=0)continue;const r=this.getCameraClipEnd(s);e>=r&&e<r+i&&(t={track:a,clip:s,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,s)})}}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 i=Math.max(0,e.clip.blendInDuration??0),s=i<=0?1:this.evaluateCameraBlendAlpha((t-e.clip.startTime)/i,e.clip);s>=1?this.copyCameraState(e.camera,a):this.blendCameraState(this.ensureCameraBlendSource(),e.camera,a,s),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 i=this.getCameraClipEnd(e.clip),s=Math.max(0,e.clip.blendOutDuration??0),r=s<=0?1:this.evaluateCameraBlendAlpha((t-i)/s,e.clip);this.blendCameraState(this.ensureCameraBlendOutSource(),this.viewController.getBaseCamera(),a,r),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(Q)),t.quaternion.copy(e.getWorldQuaternion(z)),t.scale.copy(e.getWorldScale(Y)),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,i,s){e.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!1),i.position.lerpVectors(e.getWorldPosition(Q),t.getWorldPosition(Y),s),i.quaternion.slerpQuaternions(e.getWorldQuaternion(z),t.getWorldQuaternion(H),s),i.scale.lerpVectors(e.getWorldScale(Q),t.getWorldScale(Y),s),e instanceof a.PerspectiveCamera&&t instanceof a.PerspectiveCamera?(i.fov=e.fov+(t.fov-e.fov)*s,i.near=e.near+(t.near-e.near)*s,i.far=e.far+(t.far-e.far)*s,i.aspect=t.aspect):t instanceof a.PerspectiveCamera?(i.fov=t.fov,i.near=t.near,i.far=t.far,i.aspect=t.aspect):i.aspect=this.getCurrentCameraAspect(),i.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,i=this.evaluateAudioSubTracks(e,t);e.volume;for(const s of e.clips){const r=s.startTime+s.duration,n=t>=s.startTime&&t<r,o=`${e.id}-${s.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,s,o,t,i)}const r=this.audioByClip.get(o);r&&this.applyAudioParameters(r,e,s,o,t,i)}else this.activeAudioClips.has(o)&&(this.activeAudioClips.delete(o),this.lastAudioStartAttemptTime.delete(o),this.audioStartInFlight.delete(o),this.stopAudioClip(o))}}tryStartAudioClip(e,t,a,i,s){if(this.audioStartInFlight.has(a))return;const r=this.lastAudioStartAttemptTime.get(a);if(void 0!==r&&i-r<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(a,i);const n=this.playAudioClip(e,t,a,i,s).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(a)===n&&this.audioStartInFlight.delete(a)});this.audioStartInFlight.set(a,n)}applyAudioParameters(e,t,i,s,r,n){const o=n.volume??1,l=this.stringToRandom(s+t.id),c=i.volumeRandomization?(2*l-1)*i.volumeRandomization:0;let u=1;const h=r-i.startTime;h<i.fadeInDuration&&i.fadeInDuration>0?u=h/i.fadeInDuration:h>i.duration-i.fadeOutDuration&&i.fadeOutDuration>0&&(u=(i.duration-h)/i.fadeOutDuration);const p=Math.max(0,(t.volume??1)*o*(i.volume+c)*u);e.setVolume(p);let d=n.detune??0;if(i.pitchRandomization){d+=(2*this.stringToRandom(s+"_pitch")-1)*i.pitchRandomization}if(e.setDetune(d),e.hasPlaybackControl&&e.setPlaybackRate(i.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const i=this.audioListener.context,r=[],o=n.lowpass,l=n.highpass;let c=this.audioFilters.get(s);if(void 0!==o||void 0!==l)c||(c=i.createBiquadFilter(),this.audioFilters.set(s,c)),void 0!==o?(c.type="lowpass",c.frequency.value=o):void 0!==l&&(c.type="highpass",c.frequency.value=l),r.push(c);else if(c){try{c.disconnect()}catch{}this.audioFilters.delete(s)}const u=n.pan;if(!t.spatial&&e instanceof a.Audio&&void 0!==u&&"function"==typeof i.createStereoPanner){let e=this.audioPannerNodes.get(s);e||(e=i.createStereoPanner(),this.audioPannerNodes.set(s,e)),e.pan.value=u,r.push(e)}else{const e=this.audioPannerNodes.get(s);if(e){try{e.disconnect()}catch{}this.audioPannerNodes.delete(s)}}e.setFilters(r)}t.spatial&&e instanceof a.PositionalAudio?this.updatePositionalAudioTransform(e,t,i,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(e,t,i,s){let r=null,n=null;const o=i.attachedToTrackId||t.parent?.trackId,l=i.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(r=Q,n=z,e.getWorldPosition(r),e.getWorldQuaternion(n),l){const t=this.findSocket(e,l);t&&(t.getWorldPosition(r),t.getWorldQuaternion(n))}}}}if(r&&n){const t="number"==typeof s?a.MathUtils.clamp(s,0,1):1;if(t<1&&this.audioListener){const e=Z;this.audioListener.getWorldPosition(e),r=r.clone().lerp(e,1-t)}e.position.copy(r),e.quaternion.copy(n),e.updateMatrixWorld()}}async playAudioClip(e,t,i,s,r){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(i);const n=this.clearCounter;try{let s=this.audioBuffers.get(t.audioAssetId);if(!s){let e=this.loadingAudioBuffers.get(t.audioAssetId);e||(e=this.assetLoader.getAudioByAssetId(t.audioAssetId),this.loadingAudioBuffers.set(t.audioAssetId,e));try{s=await e,this.audioBuffers.set(t.audioAssetId,s)}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),u=t.clipStartOffset+c*t.playbackRate;if(u>=s.duration||c>=t.duration)return;let h=this.audioByClip.get(i);const p=!0===e.spatial,d=h&&!0===h.isPositionalAudio;if(h&&p!==d&&(h.isPlaying&&h.stop(),h.disconnect(),this.audioByClip.delete(i),h=void 0),!h){if(p){const e=new a.PositionalAudio(this.audioListener);e.setRefDistance(10),e.setRolloffFactor(1),h=e}else h=new a.Audio(this.audioListener);this.world&&this.world.scene.add(h),this.audioByClip.set(i,h)}Math.min((t.duration-c)/t.playbackRate,(s.duration-u)/t.playbackRate);h.setLoopStart(t.clipStartOffset),h.setLoopEnd(Math.min(t.clipStartOffset+t.duration,s.duration)),h.setLoop(!0),h.setBuffer(s),this.applyAudioParameters(h,e,t,i,o,r),h.isPlaying||h.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 i=this.audioFilters.get(e);if(i){try{i.disconnect()}catch{}this.audioFilters.delete(e)}const s=this.audioPannerNodes.get(e);if(s){try{s.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,i=new Map;for(const s of e.clips){const r=this.getVfxClipKey(e,s);i.set(r,s);const n=s.startTime+s.duration;t>=s.startTime&&t<n&&a.add(r)}const s=[];for(const t of this.activeVfxClips)t.startsWith(`${e.id}-`)&&(a.has(t)||s.push(t));for(const e of s)this.activeVfxClips.delete(e);for(const[s,r]of i.entries()){const i=this.vfxActors.get(s);a.has(s)&&!this.activeVfxClips.has(s)?(this.activeVfxClips.add(s),this.ensureVfxActor(e,r,s)):a.has(s)&&i?(this.updateVfxTransform(e,i,t),this._state.value===SequencePlaybackState.Playing&&i.play()):i&&this.applyInactiveVfxClipBehavior(r,i,t)}}getVfxClipKey(e,t){return`${e.id}-${t.id}-${t.vfxAssetId}`}applyInactiveVfxClipBehavior(e,t,a){const i=e.endBehavior??"finish";if("finish"===i)return void t.stop();if("kill"===i)return void t.applyClipEndBehavior(i);const s=e.startTime+e.duration,r=Math.max(a-s,0),n=Math.max(0,e.expireWithinSeconds??.25),o=Math.max(0,n-r);t.applyClipEndBehavior(i,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 i=this.clearCounter;try{const s=await this.vfxService.createFromAssetId(t.vfxAssetId,this.world.scene);if(i!==this.clearCounter)return void(this.world&&this.world.removeActor(s));const{position:r,rotation:n,scale:o}=this.getVfxTransform(e,t.startTime);s.object.position.copy(r),s.object.rotation.copy(n),s.object.scale.copy(o),this.vfxActors.set(a,s),this._state.value===SequencePlaybackState.Playing&&s.play()}catch(e){console.error(`Failed to create VFX actor for clip ${t.id}:`,e)}}getVfxTransform(e,t){const a=new c,i=new r,s=new c(1,1,1),n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,next:r,t:l}=x(n.keyframes,t);if(e&&(e.position&&a.fromArray(e.position),e.rotation&&i.fromArray([...e.rotation,"XYZ"]),e.scale&&s.fromArray(e.scale)),r&&e!==r&&e.time!==r.time){const t=k(l,e.interpolation);if(e.position&&r.position&&a.lerpVectors(Q.fromArray(e.position),Y.fromArray(r.position),t),e.rotation&&r.rotation){z.setFromEuler(G.fromArray([...e.rotation,"XYZ"])),H.setFromEuler(U.fromArray([...r.rotation,"XYZ"]));const a=new o;a.slerpQuaternions(z,H,t),i.setFromQuaternion(a)}e.scale&&r.scale&&s.lerpVectors(Q.fromArray(e.scale),Y.fromArray(r.scale),t)}}else a.fromArray(e.position),i.fromArray([...e.rotation,"XYZ"]),s.fromArray(e.scale);return{position:a,rotation:i,scale:s}}updateVfxTransform(e,t,a){const{position:i,rotation:s,scale:r}=this.getVfxTransform(e,a);t.object.position.copy(i),t.object.rotation.copy(s),t.object.scale.copy(r)}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,i){if(!this.world||!e.actorType)return null;const s=this.resolveActorType(e.actorType);if(!s)return null;try{return await this.world.spawnActor(s,a,i)}catch(t){return console.error(`Failed to spawn actor ${e.actorType}:`,t),null}}async spawnPrefabForClip(e,t,a,i){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,i)}catch(t){return console.error(`Failed to spawn prefab ${e.prefabId}:`,t),null}}async spawnMeshForClip(e,t,a,i){if(!this.world||!this.assetLoader||!e.meshId)return null;try{const t=await this.assetLoader.getAsset(e.meshId),s=await this.assetLoader.getModelByAssetId(e.meshId),r=O.clone(s.scene);if(r.position.copy(a),r.rotation.copy(i),t){await this.assetLoader.applyMaterials(t,r);const e=t.mesh?.rescale;null!=e&&1!==e&&r.scale.multiplyScalar(e)}return this.world.scene.add(r),r}catch(t){return console.error(`Failed to spawn mesh ${e.meshId}:`,t),null}}despawnInstance(e){if(this.restorePropertySnapshotsForInstance(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 i=new c,s=new r,n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e}=x(n.keyframes,a);e&&(e.position&&i.fromArray(e.position),e.rotation&&s.fromArray([...e.rotation,"XYZ"]))}else t.initialPosition&&i.fromArray(t.initialPosition),t.initialRotation&&s.fromArray([...t.initialRotation,"XYZ"]);return{position:i,rotation:s}}evaluateSpawnTrack(e,t,a){if(!e.clips||0===e.clips.length)return;const i=t||this.bindings.get(e.id);if(i&&i.target)for(const t of e.clips){const s=t.startTime+t.duration,r=a>=t.startTime&&a<s,n=`${e.id}-${t.id}`;if(r){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:i.target}));(i.target instanceof p?i.target.object:i.target)&&this.evaluateSubTracks(e.subTracks,i,a)}else this.activeClips.has(n)&&(this.restorePropertySnapshotsForTarget(i.target),this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const t of e.clips){const i=t.startTime+t.duration,s=a>=t.startTime&&a<i,r=`${e.id}-${t.id}`,n=this.spawnedInstances.has(r),o=this.pendingSpawns.has(r);if(!s||n||o){if(s&&n){const t=this.spawnedInstances.get(r);t&&"proxy"!==t.type&&this.evaluateSubTracks(e.subTracks,t,a)}else if(!s&&n){const e=this.spawnedInstances.get(r);e&&(this.despawnInstance(e),this.spawnedInstances.delete(r),this.activeClips.delete(r))}}else{const{position:a,rotation:i}=this.getInitialTransform(e,t,t.startTime);this.pendingSpawns.add(r),this.spawnForClip(e,t,a,i,r)}}}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,s,r){const n=this.clearCounter;let o=null;try{switch(e.spawnType){case"actor":const i=await this.spawnActorForClip(e,t,a,s);i&&(o={type:"actor",instance:i});break;case"prefab":const r=await this.spawnPrefabForClip(e,t,a,s);r&&(o={type:"prefab",instance:r});break;case"mesh":const n=await this.spawnMeshForClip(e,t,a,s);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 i(t),o.activeActions=new Map),this.spawnedInstances.set(r,o),this.activeClips.add(r)}else o&&this.despawnInstance(o)}finally{this.pendingSpawns.delete(r)}}getPlayableObject(e){return e.target instanceof p?e.target.object:e.target??null}applyResolvedPropertyValue(e,t,a){if(!t||!e.propertyPath)return;const i=this.getPropertyResolution(t,e);if(!i)return;const n=this.getPropertySnapshotKey(e);this.capturePropertySnapshot(t,n,i);const o=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 function(e,t){const a=R(t,2);if(!a)return{applied:!1};if(e instanceof l)return e.fromArray(a),{applied:!0,value:e};return{applied:!0,value:new l(a[0],a[1])}}(e,t.value);case y.Vector3:return function(e,t){const a=R(t,3);if(!a)return{applied:!1};if(e instanceof c)return e.fromArray(a),{applied:!0,value:e};return{applied:!0,value:new c(a[0],a[1],a[2])}}(e,t.value);case y.Vector4:return function(e,t){const a=R(t,4);if(!a)return{applied:!1};if(e instanceof u)return e.fromArray(a),{applied:!0,value:e};return{applied:!0,value:new u(a[0],a[1],a[2],a[3])}}(e,t.value);case y.Euler:return function(e,t){const a=R(t,3);if(!a)return{applied:!1};const i=Array.isArray(t)&&"string"==typeof t[3]?t[3]:"XYZ";if(e instanceof r)return e.set(a[0],a[1],a[2],i),{applied:!0,value:e};return{applied:!0,value:new r(a[0],a[1],a[2],i)}}(e,t.value);case y.Color:return function(e,t){if(e instanceof s)return V(e,t)?{applied:!0,value:e}:{applied:!1};const a=new s;return V(a,t)?{applied:!0,value:a}:{applied:!1}}(e,t.value);default:return{applied:!1}}}(i.owner[i.key],a);o.applied&&(i.owner[i.key]=o.value)}getPropertyResolution(e,t){const a=e,i=this.getPropertySnapshotKey(t);let s=this.propertyResolutionCache.get(a);if(s||(s=new Map,this.propertyResolutionCache.set(a,s)),s.has(i))return s.get(i)??null;const r=this.getPropertyPathSegments(t.propertyPath);if(0===r.length)return s.set(i,null),null;let n=e;for(let e=0;e<r.length-1;e++){if(!E(n))return s.set(i,null),null;n=n[r[e]]}if(!E(n))return s.set(i,null),null;const o={owner:n,key:r[r.length-1]};return s.set(i,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 i=e;let s=this.propertySnapshots.get(i);if(s||(s=new Map,this.propertySnapshots.set(i,s)),s.has(t))return;const r=a.owner[a.key];s.set(t,{resolution:a,hadOwnProperty:Object.prototype.hasOwnProperty.call(a.owner,a.key),value:r,valueSnapshot:D(r)})}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())K(e);this.propertySnapshots.delete(t),this.propertyResolutionCache.delete(t)}}restoreAllPropertySnapshots(){for(const e of Array.from(this.propertySnapshots.keys()))this.restorePropertySnapshotsForTarget(e)}applyResolvedMaterialValue(e,t,a){}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 i=(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)===i&&this.loadingAnimationClips.delete(e)}})();return this.loadingAnimationClips.set(e,i),i}prepareAnimationPlayback(e,t,a){if(!I(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,i){if(!I(a))return i?j.fromClip(t,!1):t;const s=`${a.id}:${i?"root":"base"}`,r=`${q(a)}|${i?"root":"base"}`,n=this.retimedAnimationClips.get(s);if(n&&n.assetId===e&&n.signature===r)return n.clip;const o=B(t,a),l=i?j.fromClip(o,!1):o;return this.retimedAnimationClips.set(s,{assetId:e,signature:r,clip:l}),l}getAnimationPlaybackLocalTime(e,t){const a=Math.max(0,t-e.startTime);return I(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 i=null;const s=e.parent?.trackId;if(s){const t=this.sequenceData?$(this.sequenceData.tracks).find(e=>e.id===s):void 0;if(t){const a=this.getActiveObjectsForTrack(t);if(a.length>0&&(i=a[0],e.parent?.socketName)){const t=this.findSocket(i,e.parent.socketName);t&&(i=t)}}}if(!i&&"camera"===e.type&&e.parentRole&&this.roleBindings.has(e.parentRole)){const t=this.roleBindings.get(e.parentRole);if(i=t instanceof p?t.object:t,e.parentRoleSocketName){const t=this.findSocket(i,e.parentRoleSocketName);t&&(i=t)}}for(const s of a)i?s.parent!==i&&(i.add(s),!t||"object"!==e.type&&"locator"!==e.type||(t.currentParent=i)):t?.currentParent&&t.currentParent===s.parent?this.restoreObjectParent(t,s):s.parent&&s.parent!==this.world?.scene&&"object"!==e.type&&"locator"!==e.type&&this.world?.scene.add(s)}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,i]of this.spawnedInstances)if(a.startsWith(e.id+"-")&&this.activeClips.has(a)){const e=this.getInstanceObject(i);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 i of e.subTracks)if("audioParameter"===i.type){const e=i,s=A(e.parameter),r=P(e.keyframes,t,{min:s.min,max:s.max});void 0!==r&&(a[e.parameter]=r)}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)}refreshAsset(e){this.assetLoader?.clearCacheById(e),this.animationClips.delete(e),this.loadingAnimationClips.delete(e),this.clearRetimedAnimationClipCache(e),this.vfxService?.clearPool(e);for(const[t,a]of this.vfxActors.entries())t.endsWith(`-${e}`)&&(this.world&&this.world.removeActor(a),this.vfxActors.delete(t),this.activeVfxClips.delete(t));for(const[t,a]of this.spawnedInstances.entries()){const i=t.split("-")[0],s=this.sequenceData?.tracks.find(e=>e.id===i);!s||s.prefabId!==e&&s.meshId!==e||(this.despawnInstance(a),this.spawnedInstances.delete(t),this.activeClips.delete(t))}}async invokeSequenceEvent(e,t,a,i){let s=!1;for(let e=0;e<i.length;e++)if(C(i[e])){s=!0;break}if(s)try{const t=new Array(i.length);for(let e=0;e<i.length;e++)t[e]=v(i[e],this.sequenceEventAsyncResolvers);const s=await Promise.all(t);await a.call(e,...s)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}else try{const t=new Array(i.length);for(let e=0;e<i.length;e++)t[e]=g(i[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 S(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 L(e){return e.options?.length>0||e.propertyType===y.Boolean||e.propertyType===y.String}function E(e){return"object"==typeof e&&null!=e||"function"==typeof e}function R(e,t){if(!Array.isArray(e)||e.length<t)return null;const a=new Array(t);for(let i=0;i<t;i++){if("number"!=typeof e[i])return null;a[i]=e[i]}return a}function V(e,t){return t instanceof s||"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 D(e){if(e instanceof l||e instanceof c||e instanceof u||e instanceof s||e instanceof r)return e.clone()}function K(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 u&&t instanceof u)return e.copy(t),!0;if(e instanceof s&&t instanceof s)return e.copy(t),!0;if(e instanceof r&&t instanceof r)return e.copy(t),!0}(e.value,e.valueSnapshot),t[a]=e.value):delete t[a]}function $(e){const t=[];for(const a of e)t.push(a),"group"===a.type&&t.push(...$(a.childTracks));return t}function W(e){if("string"!=typeof e)return null;const t=e.trim();return t.length>0?t:null}function N(e){const t=new a.Group;t.name=`SequenceLocatorMarker:${e}`,t.renderOrder=1e3;const i=new a.AxesHelper(.35);i.renderOrder=1e3;const s=Array.isArray(i.material)?i.material:[i.material];for(const e of s)e.depthTest=!1,e.transparent=!0,e.opacity=.9,e.toneMapped=!1;t.add(i);const r=function(e){if("undefined"==typeof document)return null;const t=document.createElement("canvas");t.width=256,t.height=64;const i=t.getContext("2d");if(!i)return null;i.clearRect(0,0,t.width,t.height),i.fillStyle="rgba(16, 18, 24, 0.78)",function(e,t,a,i,s,r){const n=t+i,o=a+s;e.beginPath(),e.moveTo(t+r,a),e.lineTo(n-r,a),e.quadraticCurveTo(n,a,n,a+r),e.lineTo(n,o-r),e.quadraticCurveTo(n,o,n-r,o),e.lineTo(t+r,o),e.quadraticCurveTo(t,o,t,o-r),e.lineTo(t,a+r),e.quadraticCurveTo(t,a,t+r,a),e.closePath()}(i,0,8,t.width,48,8),i.fill(),i.font="24px sans-serif",i.textAlign="center",i.textBaseline="middle",i.fillStyle="#f8fafc",i.fillText(e||"Locator",t.width/2,t.height/2);const s=new a.CanvasTexture(t);s.needsUpdate=!0;const r=new a.SpriteMaterial({map:s,transparent:!0,depthTest:!1});r.toneMapped=!1;const n=new a.Sprite(r);return n.scale.set(.9,.225,1),n}(e);return r&&(r.position.set(0,.45,0),r.renderOrder=1001,t.add(r)),t.traverse(e=>{e.raycast=()=>{}}),t}function X(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 Q=new c,Y=new c,Z=new c,z=new o,H=new o,G=new r,U=new r;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -11,6 +11,7 @@ export interface SequenceKeyframeSpan<T extends TimedSequenceItem> {
|
|
|
11
11
|
export interface NumericValueLaneOptions {
|
|
12
12
|
min?: number;
|
|
13
13
|
max?: number;
|
|
14
|
+
stepOnly?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export declare function sortTimedSequenceItems<T extends TimedSequenceItem>(items: readonly T[]): T[];
|
|
16
17
|
export declare function findKeyframeSpan<T extends TimedSequenceItem>(keyframes: readonly T[], time: number): SequenceKeyframeSpan<T>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{SerializedParamType as e}from"../../scene/model.js";export function sortTimedSequenceItems(e){return[...e].sort((e,t)=>e.time-t.time)}export function findKeyframeSpan(e,t){if(0===e.length)return{prev:null,next:null,t:0};let
|
|
1
|
+
import{SerializedParamType as e}from"../../scene/model.js";import{Color as t}from"three";export function sortTimedSequenceItems(e){return[...e].sort((e,t)=>e.time-t.time)}export function findKeyframeSpan(e,t){if(0===e.length)return{prev:null,next:null,t:0};let r=null,n=null;for(let u=0;u<e.length;u++)if(e[u].time<=t&&(r=e[u]),e[u].time>t&&!n){n=e[u];break}if(r||(r=e[0]),n||(n=e[e.length-1]),r===n||r.time===n.time)return{prev:r,next:r,t:0};return{prev:r,next:n,t:(t-r.time)/(n.time-r.time)}}export function applyInterpolation(e,t){switch(t){case"linear":case"catmullRom":default:return e;case"step":return 0;case"cubic":return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}}export function clampNumericValue(e,t={}){const r=t.min,n=t.max;let u=e;return"number"==typeof r&&(u=Math.max(r,u)),"number"==typeof n&&(u=Math.min(n,u)),u}export function evaluateNumericKeyframes(e,t,n={}){if(0===e.length)return;const{prev:u,next:l,t:a}=findKeyframeSpan(e,t);if(!u)return;const o=r(u.value);if("number"!=typeof o)return;let i=o;if(l&&l!==u){const e=r(l.value);"number"==typeof e&&(i="step"===u.interpolation?o:o+(e-o)*applyInterpolation(a,u.interpolation))}return clampNumericValue(i,n)}export function evaluateCustomParamValueKeyframes(t,r,f={}){if(0===t.length)return null;const{prev:c,next:m,t:s}=findKeyframeSpan(t,r);if(!c)return null;const y=c.value;if(!m||m===c)return n(y,f);if(!f.stepOnly&&"step"!==c.interpolation){const t=function(t,r,n,f){if(t?.type!==r?.type)return null;if(t.type===e.Number&&r.type===e.Number)return"number"!=typeof t.value||"number"!=typeof r.value?null:{type:e.Number,value:clampNumericValue(t.value+(r.value-t.value)*n,f)};const c=u(t.type);if(c>0){const u=l(t.value,c),o=l(r.value,c);if(!u||!o)return null;const i=new Array(c);for(let e=0;e<c;e++)i[e]=clampNumericValue(u[e]+(o[e]-u[e])*n,f);return t.type===e.Euler&&(i[3]=a(t.value)??a(r.value)??"XYZ"),{type:t.type,value:i}}if(t.type===e.Color){const u=function(e,t,r){try{return o(i,e),o(p,t),i.lerp(p,r),`#${i.getHexString()}`}catch{return null}}(t.value,r.value,n);return null==u?null:{type:e.Color,value:u}}return null}(y,m.value,applyInterpolation(s,c.interpolation),f);if(t)return t}return n(y,f)}function r(t){if(t?.type===e.Number)return"number"==typeof t.value?t.value:void 0}function n(t,r){if(t?.type===e.Number&&"number"==typeof t.value)return{...t,value:clampNumericValue(t.value,r)};const n=u(t?.type);if(n>0){const e=t.value;if(!Array.isArray(e))return t;const u=e.slice();for(let e=0;e<Math.min(n,u.length);e++)"number"==typeof u[e]&&(u[e]=clampNumericValue(u[e],r));return{...t,value:u}}return t}function u(t){switch(t){case e.Vector2:return 2;case e.Vector3:return 3;case e.Vector4:return 4;case e.Euler:return 3;default:return 0}}function l(e,t){if(!Array.isArray(e)||e.length<t)return null;const r=new Array(t);for(let n=0;n<t;n++){if("number"!=typeof e[n])return null;r[n]=e[n]}return r}function a(e){return Array.isArray(e)&&"string"==typeof e[3]?e[3]:void 0}function o(e,r){if(r instanceof t||"string"==typeof r||"number"==typeof r)e.set(r);else{if(!(Array.isArray(r)&&r.length>=3))throw new Error("Unsupported color value");e.setRGB(Number(r[0])||0,Number(r[1])||0,Number(r[2])||0)}}const i=new t,p=new t;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -45,6 +45,8 @@ export declare class CharacterAnimationComponent extends ActorComponent {
|
|
|
45
45
|
private footIkRaycastMode;
|
|
46
46
|
/** Base foot lift from hit surface to avoid z-fighting/penetration, in meters. */
|
|
47
47
|
footIkFootOffset: number;
|
|
48
|
+
/** If true, derives ankle-to-ground contact offset from the foot bone hierarchy. */
|
|
49
|
+
footIkAutoContactOffset: boolean;
|
|
48
50
|
/** Position smoothing speed for foot targets (higher = snappier). */
|
|
49
51
|
footIkPositionLerpSpeed: number;
|
|
50
52
|
/** Rotation smoothing speed for foot orientation. */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{RootMotionClip as i}from"../../../../animation/root-motion.js";import{inject as s}from"../../../../inject.js";import{ViewController as r}from"../../../../services/render.js";import{AnimationMixer as n,Bone as l,Object3D as a,LoopOnce as h,Raycaster as c,Vector3 as d,SkinnedMesh as p,Skeleton as u,Quaternion as f,Matrix4 as g,MathUtils as y,ArrowHelper as m,Group as k}from"three";import{CharacterMovementComponent as S}from"./character-movement.js";import{CCDIKSolver as w}from"three/addons/animation/CCDIKSolver.js";import{World as b}from"../../../../services/world.js";import{PhysicsSystem as L,RayTestResult as v}from"../../../../services/physics/physics-system.js";const I=new d(0,-1,0),B=new d(0,1,0),x=new d(1,1,1),D=new f,F=new d,P=new d,R=new d,A=new d,M=new d,T=new f,W=new f,O=new f,V=new f,C=new g,q=new g,H=new d(1,0,0),E=new d(0,1,0),N=new d(0,0,1);function U(){return{point:new d,normal:new d,hasNormal:!1}}const z=["mixamorigHips","Hips","hips","Pelvis","pelvis"],j={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},G={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},Q=["left","right"];let K=class extends e{constructor(){super(...arguments),this.viewController=s(r),this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.externalControlActive=!1,this.world=s(b),this.physicsSystem=s(L),this.footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikLegState={left:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1},right:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new c,this.raycastIntersections=[],this.footIkRayTo=new d,this.footIkRayTestResult=new v,this.footIkRayTestOptions={excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:U(),toe:U(),heel:U(),side:U()},this.footIkAxesScratch={up:new d,forward:new d,right:new d},this.footIkSampleAxesScratch={forward:new d,right:new d},this.footIkScratch={footWorldPos:new d,centerRayStart:new d,toeRayStart:new d,heelRayStart:new d,sideRayStart:new d,desiredTargetPos:new d,desiredNormal:new d,desiredForward:new d,debugRayEndA:new d,debugRayEndB:new d,debugRayEndC:new d,debugRayEndD:new d,debugRayEndE:new d,debugRayEndF:new d},this.ikPreSolve={left:{upper:new f,lower:new f,foot:new f},right:{upper:new f,lower:new f,foot:new f}},this.getFullBodyClip=J(t=>t.uuid,t=>_(this.fullBodyMask,t)),this.getUpperBodyClip=J(t=>t.uuid,t=>_(this.upperBodyMask,t))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=this.actor.getComponent(S),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,I),this.raycaster.near=0,this.raycaster.far=e,this.raycastIntersections.length=0,this.raycaster.intersectObject(i,!0,this.raycastIntersections);for(const t of this.raycastIntersections)if(!(this.isFootIkDebugObject(t.object)||this.isRelatedToActorHierarchy(t.object)||this.isSkinnedMeshObject(t.object)))return console.log(`Foot IK raycast hit: ${t.object.name}, distance=${t.distance.toFixed(2)}m`,t),o.point.copy(t.point),null!=t.face?(o.normal.copy(t.face.normal).transformDirection(t.object.matrixWorld).normalize(),o.hasNormal=!0):o.hasNormal=!1,this.raycastIntersections.length=0,!0;return this.raycastIntersections.length=0,!1}rayTestDown(t,e,o){const i=this.footIkRayTo.copy(t).addScaledVector(I,e),s=this.physicsSystem.rayTest(t,i,this.footIkRayTestResult,this.footIkRayTestOptions);return!!s.hasHit&&(o.point.copy(s.hitPoint),o.normal.copy(s.hitNormal),o.normal.lengthSq()>1e-8?(o.normal.normalize(),o.hasNormal=!0):o.hasNormal=!1,!0)}isRelatedToActorHierarchy(t){const e=this.actor?.object;return null!=e&&null!=t&&(Z(t,e)||Z(e,t))}isFootIkDebugObject(t){let e=t;for(;null!=e;){if(!0===e.userData?.footIkDebug)return!0;e=e.parent}return!1}isSkinnedMeshObject(t){let e=t;for(;null!=e;){if(e instanceof p||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof i)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}setup(t,e,o){null!=e&&(this.upperBodyMask=$(e),this.fullBodyMask=function(t,e){const o=new Set($(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof l||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(X(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new n(t),this.ikRoot=t,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority:0,loop:e.current.options.loop??!0})}),this.upperStateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o?this.playUpper(o,{priority:0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}updateInternal(t){null!=this.mixer&&(this.externalControlActive||(this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),this.fullBodyAction&&this.fullBodyAction.loop===h&&this.fullBodyAction.getClip().duration-2*(this.overrideFadeTime??this.fadeTime)<this.fullBodyTimer&&(this.currentFullBodyPriority=-1,this.overrideFadeTime=null),null!=this.characterMovement&&(this.movementSpeed=this.characterMovement.horizontalSpeed),this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.mixer.update(t),this.updateFootIk(t)))}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=this.resolveLegBoneRefs(i,this.leftLegIkBones,j),r=this.resolveLegBoneRefs(i,this.rightLegIkBones,G);if(null==s||null==r)return void(this.ikWarnedMissingBones||(this.ikWarnedMissingBones=!0,console.warn(`[CharacterAnimationComponent] Foot IK disabled: missing leg bones. Left=${this.leftLegIkBones.upperLeg}/${this.leftLegIkBones.lowerLeg}/${this.leftLegIkBones.foot}, Right=${this.rightLegIkBones.upperLeg}/${this.rightLegIkBones.lowerLeg}/${this.rightLegIkBones.foot}`)));this.ikBoneRefs={left:s,right:r},this.ikLegLengths={left:this.computeLegLengths(s),right:this.computeLegLengths(r)},this.ikFootAxes={left:this.detectFootAxisBasis(s.foot),right:this.detectFootAxisBasis(r.foot)},this.ikPelvisBone=this.resolvePelvisBone(i,s,r),this.ikLegState.left.targetPosition.copy(s.foot.getWorldPosition(F)),this.ikLegState.right.targetPosition.copy(r.foot.getWorldPosition(F)),this.ikLegState.left.normal.set(0,1,0),this.ikLegState.right.normal.set(0,1,0),this.ikLegState.left.pitch=0,this.ikLegState.right.pitch=0,this.ikLegState.left.contactOffset=this.estimateFootContactOffset(i,"left",s.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",r.foot),this.ikLegState.left.planted=!0,this.ikLegState.right.planted=!0,this.ikLegState.left.lastFootWorldPos.copy(s.foot.getWorldPosition(F)),this.ikLegState.right.lastFootWorldPos.copy(r.foot.getWorldPosition(F)),this.ikLegState.left.hasLastFootSample=!0,this.ikLegState.right.hasLastFootSample=!0;const n=this.resolveFootAxes("left",s.foot),a=this.resolveFootAxes("right",r.foot);this.ikLegState.left.forward.copy(n.forward),this.ikLegState.right.forward.copy(a.forward);const h=e??X(t);if(null==h)return;let c=i.getBoneByName("_IKTargetLeftFoot"),d=i.getBoneByName("_IKTargetRightFoot"),p=!1;if(null==c&&(c=new l,c.name="_IKTargetLeftFoot",h.add(c),p=!0),null==d&&(d=new l,d.name="_IKTargetRightFoot",h.add(d),p=!0),this.setBoneWorldPosition(c,s.foot.getWorldPosition(F)),this.setBoneWorldPosition(d,r.foot.getWorldPosition(F)),p||i.bones.indexOf(c)<0||i.bones.indexOf(d)<0){const t=i.bones.slice(),e=i.boneInverses.map(t=>t.clone());t.indexOf(c)<0&&(t.push(c),e.push((new g).copy(c.matrixWorld).invert())),t.indexOf(d)<0&&(t.push(d),e.push((new g).copy(d.matrixWorld).invert())),o.bind(new u(t,e),o.bindMatrix)}this.ikTargetBones={left:c,right:d};const f=o.skeleton.bones,y={target:f.indexOf(c),effector:f.indexOf(s.foot),links:[{index:f.indexOf(s.lower)},{index:f.indexOf(s.upper)}],iteration:8},m={target:f.indexOf(d),effector:f.indexOf(r.foot),links:[{index:f.indexOf(r.lower)},{index:f.indexOf(r.upper)}],iteration:8};if(y.target<0||y.effector<0||y.links.some(t=>t.index<0)||m.target<0||m.effector<0||m.links.some(t=>t.index<0))return console.warn("[CharacterAnimationComponent] Foot IK disabled: failed to resolve IK indexes in skeleton."),void(this.ikSolver=null);this.ikSolver=new w(o,[y,m])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof p||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o){const i=this.findBoneByNames(t,[e.upperLeg,...o.upper]),s=this.findBoneByNames(t,[e.lowerLeg,...o.lower]),r=this.findBoneByNames(t,[e.foot,...o.foot]);if(null!=i&&null!=s&&null!=r)return{upper:i,lower:s,foot:r}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o){const i=this.findBoneByNames(t,[this.footIkPelvisBone,...z]);if(null!=i)return i;const s=e.upper.parent,r=o.upper.parent;return null!=s&&s===r&&(s instanceof l||!0===s.isBone)||null!=s&&(s instanceof l||!0===s.isBone)?s:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(F),o=t.lower.getWorldPosition(P),i=t.foot.getWorldPosition(R),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(o.worldToLocal(F.copy(e))),t.quaternion.copy(D),t.scale.copy(x),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new k,this.ikDebugRoot.name="FootIKDebug",this.ikDebugRoot.userData.footIkDebug=!0,this.ikDebugLegs={left:this.createDebugLeg("LeftFootIK",53503),right:this.createDebugLeg("RightFootIK",16755200)},this.ikDebugRoot.add(this.ikDebugLegs.left.root,this.ikDebugLegs.right.root),this.world.scene.add(this.ikDebugRoot)),this.ikDebugRoot.visible=!0):null!=this.ikDebugRoot&&(this.ikDebugRoot.visible=!1)}disposeFootIkDebug(){null!=this.ikDebugRoot&&(this.ikDebugRoot.removeFromParent(),this.ikDebugRoot.clear()),this.ikDebugRoot=null,this.ikDebugLegs=null}createDebugLeg(t,e){const o=new k;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new m(B,new d,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){F.subVectors(o,e);const i=F.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(F.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.resetFootIkState(),void this.resetDebugVisibility();this.ikRoot.updateWorldMatrix(!0,!0);const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of Q){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=e.foot.getWorldPosition(F);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance),o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of Q){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=e.upper.getWorldPosition(F),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=y.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=y.lerp(this.ikPelvisOffsetY,o,i);const s=this.ikPelvisBone.getWorldPosition(P),r=R.copy(s).addScaledVector(B,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(this.ikPelvisBone.parent.worldToLocal(r)),this.ikPelvisBone.updateMatrixWorld(!0)}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance,s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o);let a=0;return o.traverse(e=>{if(!(e instanceof l)||e===o)return;const i=t.bones.indexOf(e);if(i<0)return;const s=C.copy(t.boneInverses[i]).invert(),h=q.copy(r).multiply(s),c=F.setFromMatrixPosition(h);a=Math.min(a,c.dot(n.upLocal))}),Math.max(i,-a+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=t.upper.getWorldPosition(F),i=t.foot.getWorldPosition(P),s=o.distanceTo(i);return e.total<=1e-6?1:y.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=A.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(B),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=e.getWorldPosition(r.footWorldPos),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(B,this.footIkRayStartHeight),p=r.toeRayStart.copy(d).addScaledVector(c.forward,this.footIkForwardSampleDistance),u=r.heelRayStart.copy(d).addScaledVector(c.forward,-this.footIkForwardSampleDistance),f=r.sideRayStart.copy(d).addScaledVector(c.right,this.footIkSideSampleDistance),g=this.getFirstGroundHit(d,n.center),m=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let L=0,v=0,I=this.footIkWeightOutSpeed;const x=null!=g||null!=m||null!=k;let D=l.y;null!=g?D=g.point.y:null!=m&&null!=k?D=.5*(m.point.y+k.point.y):null!=m?D=m.point.y:null!=k&&(D=k.point.y);const F=this.ikBoneRefs?.[t],P=this.ikLegLengths?.[t],R=null!=F&&null!=P?this.computeLegExtensionRatio(F,P):1,A=Math.max(0,l.y-D,l.y-o.targetPosition.y),M=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,x,a,R,A);M?this.computeDesiredGroundNormal(c,g,m,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,m,k,b),L=this.computeDesiredPitchAngle(m,k,c.forward),v=1,I=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const T=1-Math.exp(-this.footIkPositionLerpSpeed*s),W=1-Math.exp(-I*s);o.normal.lerp(w,T).normalize(),o.forward.lerp(b,T).normalize(),o.pitch=y.lerp(o.pitch,L,T),o.weight=y.lerp(o.weight,v,W),o.planted=M&&v>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=h.getWorldPosition(l.footWorldPos),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(B,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),m=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(m,a.heel),L=this.getFirstGroundHit(k,a.side),v=l.desiredTargetPos.copy(c),I=l.desiredNormal.set(0,1,0),x=l.desiredForward.copy(u.forward);let D=0,F=0,P=this.footIkWeightOutSpeed;const R=null!=S||null!=w||null!=b;let A=c.y;null!=S?A=S.point.y:null!=w&&null!=b?A=.5*(w.point.y+b.point.y):null!=w?A=w.point.y:null!=b&&(A=b.point.y);const M=this.computeLegExtensionRatio(e,o),T=Math.max(0,c.y-A,c.y-s.targetPosition.y),W=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,R,d,M,T);if(W){if(v.copy(c),this.computeDesiredGroundNormal(u,S,w,b,L,I)){this.computeDesiredFootForward(u.forward,u.right,I,w,b,x),D=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(D))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);v.y=A+e+t,s.top&&(v.y-=this.ikPelvisOffsetY/2),F=1,P=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,I,null,null,x),v.copy(c),v.y+=this.footIkFootOffset;this.clampDesiredFootTarget(e,o,c,v);const O=1-Math.exp(-this.footIkPositionLerpSpeed*n),V=1-Math.exp(-P*n);s.targetPosition.lerp(v,O),s.normal.lerp(I,O).normalize(),s.forward.lerp(x,O).normalize(),s.pitch=y.lerp(s.pitch,D,O),s.weight=y.lerp(s.weight,F,V),s.planted=W&&F>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:m,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:L,desiredNormal:I,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(I,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(I,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(I,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(I,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new d,right:new d},n=this.actor.object.getWorldDirection(A);n.addScaledVector(B,-n.dot(B)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(B,-s.forward.dot(B)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=M.crossVectors(B,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,A);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=P.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=R.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(B),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(B)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.actor.object.getWorldDirection(A)),r.addScaledVector(o,-r.dot(o))),r.lengthSq()<1e-8&&r.crossVectors(o,e),r.lengthSq()<1e-8&&r.set(0,0,1),r.normalize();const n=A.copy(this.actor.object.getWorldDirection(A));n.addScaledVector(o,-n.dot(o)),n.lengthSq()<1e-8&&(n.copy(t),n.addScaledVector(o,-n.dot(o))),n.lengthSq()>1e-8&&n.normalize(),r.dot(n)<0&&r.multiplyScalar(-1)}computeDesiredPitchAngle(t,e,o){if(null==t||null==e)return 0;const i=P.subVectors(t.point,e.point),s=Math.abs(i.dot(o));if(s<1e-5)return 0;const r=t.point.y-e.point.y,n=y.degToRad(this.footIkMaxSlopeAngleDeg);return y.clamp(-Math.atan2(r,s),-n,n)}applySimpleFootPitch(t,e,o){if(null==e.parent||o.weight<=.001)return;const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o.pitch*o.weight;if(Math.abs(s)<=1e-5)return;const r=this.resolveLocalPitchSign(i),n=T.copy(e.quaternion),l=W.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=O.setFromAxisAngle(t.rightLocal,.15);return R.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=P.subVectors(i,o),r=s.dot(B),n=R.copy(s).addScaledVector(B,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=y.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(B,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(F).clone(),c=P.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(F).clone(),s=e.lower.getWorldPosition(P).clone(),r=e.foot.getWorldPosition(R).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new d).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,p=n+l-1e-4,u=y.clamp(h,c,p),f=a.multiplyScalar(1/h),g=(new d).subVectors(s,i).normalize(),m=(new d).subVectors(r,s).normalize(),k=(new d).crossVectors(g,m);k.lengthSq()<1e-8&&(k.copy(this.actor.object.getWorldDirection(F).cross(B)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),L=(new d).copy(i).addScaledVector(f,S);let v=(new d).crossVectors(k,f);v.lengthSq()<1e-8&&(v=(new d).crossVectors(f,B),v.lengthSq()<1e-8&&(v=new d(1,0,0))),v.normalize();const I=(new d).copy(L).addScaledVector(v,b),x=(new d).copy(L).addScaledVector(v,-b),D=(new d).subVectors(s,L).dot(v)>=0?I:x;this.rotateBoneToward(e.upper,i,s,D),e.upper.updateMatrixWorld(!0);const A=e.lower.getWorldPosition(P),M=e.foot.getWorldPosition(R);this.rotateBoneToward(e.lower,A,M,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,D,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new d).subVectors(o,e),r=(new d).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new f).setFromUnitVectors(s,r),l=t.getWorldQuaternion(T),a=W.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=t.parent.getWorldQuaternion(O),c=V.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=t.getWorldQuaternion(T),o=this.actor.object.getWorldDirection(F);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:H.clone(),world:H.clone().applyQuaternion(e)},{local:E.clone(),world:E.clone().applyQuaternion(e)},{local:N.clone(),world:N.clone().applyQuaternion(e)}];i.push({local:H.clone().multiplyScalar(-1),world:H.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:E.clone().multiplyScalar(-1),world:E.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:N.clone().multiplyScalar(-1),world:N.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(B);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new d,forward:new d,right:new d},r=e.getWorldQuaternion(T);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}clampSlopeNormal(t){const e=y.clamp(t.dot(B),-1,1),o=Math.acos(e),i=y.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(B,t,s).normalize()}blendLegAfterSolve(t,e,o){if(!(o>=.999)){if(o<=.001)return t.upper.quaternion.copy(e.upper),t.lower.quaternion.copy(e.lower),void t.foot.quaternion.copy(e.foot);this.blendBoneQuaternion(t.upper,e.upper,o),this.blendBoneQuaternion(t.lower,e.lower,o),this.blendBoneQuaternion(t.foot,e.foot,o)}}blendBoneQuaternion(t,e,o){T.copy(t.quaternion),t.quaternion.copy(e).slerp(T,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=F.copy(o.normal).normalize(),n=P.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=R.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(A.crossVectors(l,r)).normalize(),C.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),T.setFromRotationMatrix(C),q.makeBasis(l,r,n),W.setFromRotationMatrix(q);const a=O.copy(W).multiply(V.copy(T).invert()),h=e.parent.getWorldQuaternion(V),c=W.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,y.clamp(d,0,1))}getMixer(){return this.mixer}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyTimer=0}beginExternalAnimationControl(t,e={}){Y(null!=this.mixer,"Can't begin external control before setup is called"),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return o.setLoop(h,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){if(null!=t){const e=t.getClip();if(e instanceof i&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof a&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){const o=e?.priority??1;o<this.currentUpperBodyPriority||(this.currentUpperBodyPriority=o,this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1,this.upperBodyTimer=0,this.upperBodyOverride=!0,this.overrideFadeTimeUpper=e.fadeTime)}play(t,e={}){Y(null!=this.mixer,"Can't play animation before setup is called");const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}onActionDone(t){return new Promise(e=>{const o=i=>{i.action===t&&(e(i.action),this.mixer.removeEventListener("finished",o))};this.mixer.addEventListener("finished",o)})}transition(t,e,o={}){if(null!=t&&t.getClip().uuid===e.uuid)return t;const i=o?.fadeTime??this.fadeTime;if(t){const s=t,r=this.mixer.clipAction(e);r.reset(),null!=o.offset&&(r.time=o.offset),r.play(),r.enabled=!0,r.setEffectiveTimeScale(1),r.weight=1,s.crossFadeTo(r,i,!0),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.fadeIn(i),t.play();return!1===o.loop&&(t.setLoop(h,1),t.clampWhenFinished=!0),t}};K=t([o({inEditor:!0})],K);export{K as CharacterAnimationComponent};function _(t,e){if(null==t)return e;const o=e.clone(),i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function $(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof l)}function Y(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function J(t,e){const o=new Map;return(i,...s)=>{const r=t(i);return o.has(r)||o.set(r,e(i,...s)),o.get(r)}}function X(t){let e;return t.traverse(t=>{(t instanceof l||t.isBone)&&null==e&&(e=t)}),e}function Z(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}/*
|
|
1
|
+
import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{RootMotionClip as i}from"../../../../animation/root-motion.js";import{inject as s}from"../../../../inject.js";import{ViewController as r}from"../../../../services/render.js";import{AnimationMixer as n,Bone as l,Object3D as a,LoopOnce as h,Raycaster as c,Vector3 as d,SkinnedMesh as p,Skeleton as u,Quaternion as f,Matrix4 as g,MathUtils as y,ArrowHelper as m,Group as k}from"three";import{CharacterMovementComponent as S}from"./character-movement.js";import{CCDIKSolver as w}from"three/addons/animation/CCDIKSolver.js";import{World as b}from"../../../../services/world.js";import{PhysicsSystem as L,RayTestResult as v}from"../../../../services/physics/physics-system.js";const I=new d(0,-1,0),B=new d(0,1,0),x=new d(1,1,1),D=new f,F=new d,P=new d,R=new d,A=new d,M=new d,T=new f,W=new f,O=new f,V=new f,C=new g,q=new g,H=new d(1,0,0),E=new d(0,1,0),z=new d(0,0,1);function N(){return{point:new d,normal:new d,hasNormal:!1}}const U=["mixamorigHips","Hips","hips","Pelvis","pelvis"],j={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},Q={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},G=["left","right"];let _=class extends e{constructor(){super(...arguments),this.viewController=s(r),this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.externalControlActive=!1,this.world=s(b),this.physicsSystem=s(L),this.footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkAutoContactOffset=!1,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikLegState={left:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1},right:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new c,this.raycastIntersections=[],this.footIkRayTo=new d,this.footIkRayTestResult=new v,this.footIkRayTestOptions={excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:N(),toe:N(),heel:N(),side:N()},this.footIkAxesScratch={up:new d,forward:new d,right:new d},this.footIkSampleAxesScratch={forward:new d,right:new d},this.footIkScratch={footWorldPos:new d,centerRayStart:new d,toeRayStart:new d,heelRayStart:new d,sideRayStart:new d,desiredTargetPos:new d,desiredNormal:new d,desiredForward:new d,debugRayEndA:new d,debugRayEndB:new d,debugRayEndC:new d,debugRayEndD:new d,debugRayEndE:new d,debugRayEndF:new d},this.ikPreSolve={left:{upper:new f,lower:new f,foot:new f},right:{upper:new f,lower:new f,foot:new f}},this.getFullBodyClip=J(t=>t.uuid,t=>K(this.fullBodyMask,t)),this.getUpperBodyClip=J(t=>t.uuid,t=>K(this.upperBodyMask,t))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=this.actor.getComponent(S),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,I),this.raycaster.near=0,this.raycaster.far=e,this.raycastIntersections.length=0,this.raycaster.intersectObject(i,!0,this.raycastIntersections);for(const t of this.raycastIntersections)if(!(this.isFootIkDebugObject(t.object)||this.isRelatedToActorHierarchy(t.object)||this.isSkinnedMeshObject(t.object)))return o.point.copy(t.point),null!=t.face?(o.normal.copy(t.face.normal).transformDirection(t.object.matrixWorld).normalize(),o.hasNormal=!0):o.hasNormal=!1,this.raycastIntersections.length=0,!0;return this.raycastIntersections.length=0,!1}rayTestDown(t,e,o){const i=this.footIkRayTo.copy(t).addScaledVector(I,e),s=this.physicsSystem.rayTest(t,i,this.footIkRayTestResult,this.footIkRayTestOptions);return!!s.hasHit&&(o.point.copy(s.hitPoint),o.normal.copy(s.hitNormal),o.normal.lengthSq()>1e-8?(o.normal.normalize(),o.hasNormal=!0):o.hasNormal=!1,!0)}isRelatedToActorHierarchy(t){const e=this.actor?.object;return null!=e&&null!=t&&(Z(t,e)||Z(e,t))}isFootIkDebugObject(t){let e=t;for(;null!=e;){if(!0===e.userData?.footIkDebug)return!0;e=e.parent}return!1}isSkinnedMeshObject(t){let e=t;for(;null!=e;){if(e instanceof p||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof i)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}setup(t,e,o){null!=e&&(this.upperBodyMask=Y(e),this.fullBodyMask=function(t,e){const o=new Set(Y(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof l||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(X(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new n(t),this.ikRoot=t,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority:0,loop:e.current.options.loop??!0})}),this.upperStateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o?this.playUpper(o,{priority:0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}updateInternal(t){null!=this.mixer&&(this.externalControlActive||(this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),this.fullBodyAction&&this.fullBodyAction.loop===h&&this.fullBodyAction.getClip().duration-2*(this.overrideFadeTime??this.fadeTime)<this.fullBodyTimer&&(this.currentFullBodyPriority=-1,this.overrideFadeTime=null),null!=this.characterMovement&&(this.movementSpeed=this.characterMovement.horizontalSpeed),this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.mixer.update(t),this.updateFootIk(t)))}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=this.resolveLegBoneRefs(i,this.leftLegIkBones,j),r=this.resolveLegBoneRefs(i,this.rightLegIkBones,Q);if(null==s||null==r)return void(this.ikWarnedMissingBones||(this.ikWarnedMissingBones=!0,console.warn(`[CharacterAnimationComponent] Foot IK disabled: missing leg bones. Left=${this.leftLegIkBones.upperLeg}/${this.leftLegIkBones.lowerLeg}/${this.leftLegIkBones.foot}, Right=${this.rightLegIkBones.upperLeg}/${this.rightLegIkBones.lowerLeg}/${this.rightLegIkBones.foot}`)));this.ikBoneRefs={left:s,right:r},this.ikLegLengths={left:this.computeLegLengths(s),right:this.computeLegLengths(r)},this.ikFootAxes={left:this.detectFootAxisBasis(s.foot),right:this.detectFootAxisBasis(r.foot)},this.ikPelvisBone=this.resolvePelvisBone(i,s,r),this.ikLegState.left.targetPosition.copy(s.foot.getWorldPosition(F)),this.ikLegState.right.targetPosition.copy(r.foot.getWorldPosition(F)),this.ikLegState.left.normal.set(0,1,0),this.ikLegState.right.normal.set(0,1,0),this.ikLegState.left.pitch=0,this.ikLegState.right.pitch=0,this.ikLegState.left.contactOffset=this.estimateFootContactOffset(i,"left",s.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",r.foot),this.ikLegState.left.planted=!0,this.ikLegState.right.planted=!0,this.ikLegState.left.lastFootWorldPos.copy(s.foot.getWorldPosition(F)),this.ikLegState.right.lastFootWorldPos.copy(r.foot.getWorldPosition(F)),this.ikLegState.left.hasLastFootSample=!0,this.ikLegState.right.hasLastFootSample=!0;const n=this.resolveFootAxes("left",s.foot),a=this.resolveFootAxes("right",r.foot);this.ikLegState.left.forward.copy(n.forward),this.ikLegState.right.forward.copy(a.forward);const h=e??X(t);if(null==h)return;let c=i.getBoneByName("_IKTargetLeftFoot"),d=i.getBoneByName("_IKTargetRightFoot"),p=!1;if(null==c&&(c=new l,c.name="_IKTargetLeftFoot",h.add(c),p=!0),null==d&&(d=new l,d.name="_IKTargetRightFoot",h.add(d),p=!0),this.setBoneWorldPosition(c,s.foot.getWorldPosition(F)),this.setBoneWorldPosition(d,r.foot.getWorldPosition(F)),p||i.bones.indexOf(c)<0||i.bones.indexOf(d)<0){const t=i.bones.slice(),e=i.boneInverses.map(t=>t.clone());t.indexOf(c)<0&&(t.push(c),e.push((new g).copy(c.matrixWorld).invert())),t.indexOf(d)<0&&(t.push(d),e.push((new g).copy(d.matrixWorld).invert())),o.bind(new u(t,e),o.bindMatrix)}this.ikTargetBones={left:c,right:d};const f=o.skeleton.bones,y={target:f.indexOf(c),effector:f.indexOf(s.foot),links:[{index:f.indexOf(s.lower)},{index:f.indexOf(s.upper)}],iteration:8},m={target:f.indexOf(d),effector:f.indexOf(r.foot),links:[{index:f.indexOf(r.lower)},{index:f.indexOf(r.upper)}],iteration:8};if(y.target<0||y.effector<0||y.links.some(t=>t.index<0)||m.target<0||m.effector<0||m.links.some(t=>t.index<0))return console.warn("[CharacterAnimationComponent] Foot IK disabled: failed to resolve IK indexes in skeleton."),void(this.ikSolver=null);this.ikSolver=new w(o,[y,m])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof p||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o){const i=this.findBoneByNames(t,[e.upperLeg,...o.upper]),s=this.findBoneByNames(t,[e.lowerLeg,...o.lower]),r=this.findBoneByNames(t,[e.foot,...o.foot]);if(null!=i&&null!=s&&null!=r)return{upper:i,lower:s,foot:r}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o){const i=this.findBoneByNames(t,[this.footIkPelvisBone,...U]);if(null!=i)return i;const s=e.upper.parent,r=o.upper.parent;return null!=s&&s===r&&(s instanceof l||!0===s.isBone)||null!=s&&(s instanceof l||!0===s.isBone)?s:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(F),o=t.lower.getWorldPosition(P),i=t.foot.getWorldPosition(R),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(o.worldToLocal(F.copy(e))),t.quaternion.copy(D),t.scale.copy(x),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new k,this.ikDebugRoot.name="FootIKDebug",this.ikDebugRoot.userData.footIkDebug=!0,this.ikDebugLegs={left:this.createDebugLeg("LeftFootIK",53503),right:this.createDebugLeg("RightFootIK",16755200)},this.ikDebugRoot.add(this.ikDebugLegs.left.root,this.ikDebugLegs.right.root),this.world.scene.add(this.ikDebugRoot)),this.ikDebugRoot.visible=!0):null!=this.ikDebugRoot&&(this.ikDebugRoot.visible=!1)}disposeFootIkDebug(){null!=this.ikDebugRoot&&(this.ikDebugRoot.removeFromParent(),this.ikDebugRoot.clear()),this.ikDebugRoot=null,this.ikDebugLegs=null}createDebugLeg(t,e){const o=new k;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new m(B,new d,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){F.subVectors(o,e);const i=F.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(F.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.resetFootIkState(),void this.resetDebugVisibility();this.ikRoot.updateWorldMatrix(!0,!0);const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of G){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=e.foot.getWorldPosition(F);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,this.footIkAutoContactOffset?o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance):o.contactOffset=this.footIkFootOffset+this.footIkExtraClearance,o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of G){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=e.upper.getWorldPosition(F),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=y.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=y.lerp(this.ikPelvisOffsetY,o,i);const s=this.ikPelvisBone.getWorldPosition(P),r=R.copy(s).addScaledVector(B,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(this.ikPelvisBone.parent.worldToLocal(r)),this.ikPelvisBone.updateMatrixWorld(!0)}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance;if(!this.footIkAutoContactOffset)return i;const s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o),a=o.getWorldPosition(P),h=R.copy(n.upLocal).applyQuaternion(o.getWorldQuaternion(T)).normalize();let c=0;return o.traverse(e=>{if(!(e instanceof l)||e===o)return;const i=t.bones.indexOf(e);if(i<0)return;const s=C.copy(t.boneInverses[i]).invert(),n=q.copy(r).multiply(s),d=F.setFromMatrixPosition(n),p=A.copy(d).applyMatrix4(o.matrixWorld).sub(a);c=Math.min(c,p.dot(h))}),Math.max(i,-c+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=t.upper.getWorldPosition(F),i=t.foot.getWorldPosition(P),s=o.distanceTo(i);return e.total<=1e-6?1:y.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=A.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(B),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=e.getWorldPosition(r.footWorldPos),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(B,this.footIkRayStartHeight),p=r.toeRayStart.copy(d).addScaledVector(c.forward,this.footIkForwardSampleDistance),u=r.heelRayStart.copy(d).addScaledVector(c.forward,-this.footIkForwardSampleDistance),f=r.sideRayStart.copy(d).addScaledVector(c.right,this.footIkSideSampleDistance),g=this.getFirstGroundHit(d,n.center),m=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let L=0,v=0,I=this.footIkWeightOutSpeed;const x=null!=g||null!=m||null!=k;let D=l.y;null!=g?D=g.point.y:null!=m&&null!=k?D=.5*(m.point.y+k.point.y):null!=m?D=m.point.y:null!=k&&(D=k.point.y);const F=this.ikBoneRefs?.[t],P=this.ikLegLengths?.[t],R=null!=F&&null!=P?this.computeLegExtensionRatio(F,P):1,A=Math.max(0,l.y-D,l.y-o.targetPosition.y),M=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,x,a,R,A);M?this.computeDesiredGroundNormal(c,g,m,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,m,k,b),L=this.computeDesiredPitchAngle(m,k,c.forward),v=1,I=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const T=1-Math.exp(-this.footIkPositionLerpSpeed*s),W=1-Math.exp(-I*s);o.normal.lerp(w,T).normalize(),o.forward.lerp(b,T).normalize(),o.pitch=y.lerp(o.pitch,L,T),o.weight=y.lerp(o.weight,v,W),o.planted=M&&v>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=h.getWorldPosition(l.footWorldPos),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(B,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),m=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(m,a.heel),L=this.getFirstGroundHit(k,a.side),v=l.desiredTargetPos.copy(c),I=l.desiredNormal.set(0,1,0),x=l.desiredForward.copy(u.forward);let D=0,F=0,P=this.footIkWeightOutSpeed;const R=null!=S||null!=w||null!=b;let A=c.y;null!=S?A=S.point.y:null!=w&&null!=b?A=.5*(w.point.y+b.point.y):null!=w?A=w.point.y:null!=b&&(A=b.point.y);const M=this.computeLegExtensionRatio(e,o),T=Math.max(0,c.y-A,c.y-s.targetPosition.y),W=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,R,d,M,T);if(W){if(v.copy(c),this.computeDesiredGroundNormal(u,S,w,b,L,I)){this.computeDesiredFootForward(u.forward,u.right,I,w,b,x),D=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(D))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);v.y=A+e+t,s.top&&(v.y-=this.ikPelvisOffsetY/2),F=1,P=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,I,null,null,x),v.copy(c),v.y+=this.footIkFootOffset;this.clampDesiredFootTarget(e,o,c,v);const O=1-Math.exp(-this.footIkPositionLerpSpeed*n),V=1-Math.exp(-P*n);s.targetPosition.lerp(v,O),s.normal.lerp(I,O).normalize(),s.forward.lerp(x,O).normalize(),s.pitch=y.lerp(s.pitch,D,O),s.weight=y.lerp(s.weight,F,V),s.planted=W&&F>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:m,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:L,desiredNormal:I,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(I,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(I,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(I,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(I,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new d,right:new d},n=this.actor.object.getWorldDirection(A);n.addScaledVector(B,-n.dot(B)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(B,-s.forward.dot(B)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=M.crossVectors(B,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,A);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=P.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=R.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(B),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(B)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.actor.object.getWorldDirection(A)),r.addScaledVector(o,-r.dot(o))),r.lengthSq()<1e-8&&r.crossVectors(o,e),r.lengthSq()<1e-8&&r.set(0,0,1),r.normalize();const n=A.copy(this.actor.object.getWorldDirection(A));n.addScaledVector(o,-n.dot(o)),n.lengthSq()<1e-8&&(n.copy(t),n.addScaledVector(o,-n.dot(o))),n.lengthSq()>1e-8&&n.normalize(),r.dot(n)<0&&r.multiplyScalar(-1)}computeDesiredPitchAngle(t,e,o){if(null==t||null==e)return 0;const i=P.subVectors(t.point,e.point),s=Math.abs(i.dot(o));if(s<1e-5)return 0;const r=t.point.y-e.point.y,n=y.degToRad(this.footIkMaxSlopeAngleDeg);return y.clamp(-Math.atan2(r,s),-n,n)}applySimpleFootPitch(t,e,o){if(null==e.parent||o.weight<=.001)return;const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o.pitch*o.weight;if(Math.abs(s)<=1e-5)return;const r=this.resolveLocalPitchSign(i),n=T.copy(e.quaternion),l=W.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=O.setFromAxisAngle(t.rightLocal,.15);return R.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=P.subVectors(i,o),r=s.dot(B),n=R.copy(s).addScaledVector(B,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=y.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(B,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(F).clone(),c=P.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(F).clone(),s=e.lower.getWorldPosition(P).clone(),r=e.foot.getWorldPosition(R).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new d).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,p=n+l-1e-4,u=y.clamp(h,c,p),f=a.multiplyScalar(1/h),g=(new d).subVectors(s,i).normalize(),m=(new d).subVectors(r,s).normalize(),k=(new d).crossVectors(g,m);k.lengthSq()<1e-8&&(k.copy(this.actor.object.getWorldDirection(F).cross(B)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),L=(new d).copy(i).addScaledVector(f,S);let v=(new d).crossVectors(k,f);v.lengthSq()<1e-8&&(v=(new d).crossVectors(f,B),v.lengthSq()<1e-8&&(v=new d(1,0,0))),v.normalize();const I=(new d).copy(L).addScaledVector(v,b),x=(new d).copy(L).addScaledVector(v,-b),D=(new d).subVectors(s,L).dot(v)>=0?I:x;this.rotateBoneToward(e.upper,i,s,D),e.upper.updateMatrixWorld(!0);const A=e.lower.getWorldPosition(P),M=e.foot.getWorldPosition(R);this.rotateBoneToward(e.lower,A,M,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,D,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new d).subVectors(o,e),r=(new d).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new f).setFromUnitVectors(s,r),l=t.getWorldQuaternion(T),a=W.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=t.parent.getWorldQuaternion(O),c=V.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=t.getWorldQuaternion(T),o=this.actor.object.getWorldDirection(F);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:H.clone(),world:H.clone().applyQuaternion(e)},{local:E.clone(),world:E.clone().applyQuaternion(e)},{local:z.clone(),world:z.clone().applyQuaternion(e)}];i.push({local:H.clone().multiplyScalar(-1),world:H.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:E.clone().multiplyScalar(-1),world:E.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:z.clone().multiplyScalar(-1),world:z.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(B);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new d,forward:new d,right:new d},r=e.getWorldQuaternion(T);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}clampSlopeNormal(t){const e=y.clamp(t.dot(B),-1,1),o=Math.acos(e),i=y.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(B,t,s).normalize()}blendLegAfterSolve(t,e,o){if(!(o>=.999)){if(o<=.001)return t.upper.quaternion.copy(e.upper),t.lower.quaternion.copy(e.lower),void t.foot.quaternion.copy(e.foot);this.blendBoneQuaternion(t.upper,e.upper,o),this.blendBoneQuaternion(t.lower,e.lower,o),this.blendBoneQuaternion(t.foot,e.foot,o)}}blendBoneQuaternion(t,e,o){T.copy(t.quaternion),t.quaternion.copy(e).slerp(T,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=F.copy(o.normal).normalize(),n=P.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=R.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(A.crossVectors(l,r)).normalize(),C.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),T.setFromRotationMatrix(C),q.makeBasis(l,r,n),W.setFromRotationMatrix(q);const a=O.copy(W).multiply(V.copy(T).invert()),h=e.parent.getWorldQuaternion(V),c=W.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,y.clamp(d,0,1))}getMixer(){return this.mixer}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyTimer=0}beginExternalAnimationControl(t,e={}){$(null!=this.mixer,"Can't begin external control before setup is called"),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return o.setLoop(h,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){if(null!=t){const e=t.getClip();if(e instanceof i&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof a&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){const o=e?.priority??1;o<this.currentUpperBodyPriority||(this.currentUpperBodyPriority=o,this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1,this.upperBodyTimer=0,this.upperBodyOverride=!0,this.overrideFadeTimeUpper=e.fadeTime)}play(t,e={}){$(null!=this.mixer,"Can't play animation before setup is called");const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}onActionDone(t){return new Promise(e=>{const o=i=>{i.action===t&&(e(i.action),this.mixer.removeEventListener("finished",o))};this.mixer.addEventListener("finished",o)})}transition(t,e,o={}){if(null!=t&&t.getClip().uuid===e.uuid)return t;const i=o?.fadeTime??this.fadeTime;if(t){const s=t,r=this.mixer.clipAction(e);r.reset(),null!=o.offset&&(r.time=o.offset),r.play(),r.enabled=!0,r.setEffectiveTimeScale(1),r.weight=1,s.crossFadeTo(r,i,!0),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.fadeIn(i),t.play();return!1===o.loop&&(t.setLoop(h,1),t.clampWhenFinished=!0),t}};_=t([o({inEditor:!0})],_);export{_ as CharacterAnimationComponent};function K(t,e){if(null==t)return e;const o=e.clone(),i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function Y(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof l)}function $(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function J(t,e){const o=new Map;return(i,...s)=>{const r=t(i);return o.has(r)||o.set(r,e(i,...s)),o.get(r)}}function X(t){let e;return t.traverse(t=>{(t instanceof l||t.isBone)&&null==e&&(e=t)}),e}function Z(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}/*
|
|
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 o,Cone as s,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-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
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Ball as n,Capsule as o,Cone as s,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-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)),o=Math.min(400,Math.max(50,Math.ceil(n/2))),s=Math.max(this.cellSize,.01),i={tileSize:Math.max(32,Math.floor(o/s)),walkableClimb:this.walkableClimb/s,walkableSlopeAngle:this.walkableSlopeAngle,walkableRadius:2,walkableHeight:this.walkableHeight/s,detailSampleDist:1,minRegionArea:6,mergeRegionArea:400,cs:s,ch:s,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=[],o=this.physics.world.bodies;if(null==o)return[];const s=new x.Box3;for(const e of o.getAll())for(let o=0,i=e.numColliders();o<i;o++){const i=e.collider(o);if(i.isSensor()||null!=i.parent().userData&&!0===i.parent().userData.ignoreForNavMesh)continue;const r=e.handle+","+o,a=c.get(r)?.mesh,l=a??L(i);if(X(i,l),null!=l){s.copy(l.geometry.boundingBox),s.min.add(l.position),s.max.add(l.position);const e=s.intersectsBox(t)||!0,o=s.intersectsBox(this.bounds);c.set(r,{pos:i.translation(),mesh:l}),e&&o&&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 o=n.slice(0,500);if(0!=o.length){const n=[];for(const o of t)f.setFromObject(o),f.intersectsBox(e)&&n.push(o);let[s,i]=d(n);i=function(e,t,n){const o=new x.Vector3,s=[];for(let i=0;i<t.length;i+=3){let r=!0;for(let s=0;s<3;s++){const a=3*t[i+s];if(o.fromArray(e,a),!n.containsPoint(o)){r=!1;break}}r&&s.push(t[i],t[i+1],t[i+2])}return new Uint32Array(s)}(s,i,p),P&&(s=V(s),i=G(i));const a=v;v=!1,await Promise.all(o.map(e=>(M=performance.now(),r.buildTile(s,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 o=t,s=o.heights,i=o.nrows,r=o.ncols,a=o.scale.x,l=o.scale.z,h=o.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]=s[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 o=2166136261;for(let e=0;e<n.length;e++)o=Math.imul(o^n[e],16777619)>>>0;return W.set(e,o),o}(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),o=[];n.faces.forEach(e=>{const t=e.edge.head().point,n=e.edge.next.head().point,s=e.edge.next.next.head().point;o.push(t.x,t.y,t.z),o.push(n.x,n.y,n.z),o.push(s.x,s.y,s.z)});const s=new x.BufferGeometry;return s.setAttribute("position",new x.Float32BufferAttribute(o,3)),s}(e.shape.vertices),O.set(t,n)),n}if(e.shape instanceof h){const t=e.shape.vertices,n=e.shape.indices;let o=new x.BufferGeometry;return o.setAttribute("position",new x.Float32BufferAttribute(t,3)),null!=n?o.setIndex(new x.Uint16BufferAttribute(n,1)):o=v.mergeVertices(o),o.computeVertexNormals(),o}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 s){const t=e.shape.halfHeight,n=e.shape.radius;return new x.ConeGeometry(n,2*t)}if(e.shape instanceof o){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,o=new x.Mesh(t,n);return o.geometry.computeBoundingBox(),o.geometry.scale(1.01,1.01,1.01),o}function X(e,t){const n=e.translation(),o=e.rotation();t.position.set(n.x,n.y,n.z),t.quaternion.set(o.x,o.y,o.z,o.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
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import{Actor as o,attach as i,BaseActor as p,Component as n,inject as r,Parameter as s}from"../..";import{Texture as a}from"three";import{tonemapMappings as d}from"../../../rendering/tone-mapping";import{OBB as l}from"three/examples/jsm/math/OBB.js";import{Vector3 as g}from"three";import*as u from"three";import{RenderingView as y}from"../../../rendering.js";import{TriggerVolumeMesh as h}from"./components/volume-editor-component.js";import{ActorComponent as m}from"../../actors/component.js";const b=[0,2],v=[-1,1];function f(t,e){return{optional:!0,type:g,group:t,label:e,range:b,precision:3,stepSize:.01,defaultValue:new g(1,1,1),editorInput:"colorGrade"}}function c(t,e){return{optional:!0,type:g,group:t,label:e,range:v,precision:3,stepSize:.01,defaultValue:new g(0,0,0),editorInput:"colorGrade"}}let w=class extends m{};t([s({options:d,optional:!0,group:"Tone Mapping",label:"Tone Mapping"}),e("design:type",Number)],w.prototype,"tonemapMapping",void 0),t([s({optional:!0,group:"Tone Mapping",label:"Tone Mapping Exposure",defaultValue:1}),e("design:type",Number)],w.prototype,"tonemapExposure",void 0),t([s({optional:!0}),e("design:type",a)],w.prototype,"envTexture",void 0),t([s({optional:!0,defaultValue:1}),e("design:type",Number)],w.prototype,"envIntensity",void 0),t([s({optional:!0,group:"Lens",defaultValue:0}),e("design:type",Number)],w.prototype,"vignetteIntensity",void 0),t([s({optional:!0,group:"Color Correction",defaultValue:new u.Color(16777215)}),e("design:type",u.Color)],w.prototype,"colorTint",void 0),t([s({optional:!0,group:"Color Correction",defaultValue:0}),e("design:type",Number)],w.prototype,"colorTintIntensity",void 0),t([s({optional:!0,group:"Depth of Field"}),e("design:type",Number)],w.prototype,"depthFocus",void 0),t([s({optional:!0,group:"Depth of Field"}),e("design:type",Number)],w.prototype,"depthAperture",void 0),t([s({optional:!0,group:"Depth of Field"}),e("design:type",Number)],w.prototype,"depthMaxBlur",void 0),t([s({optional:!0,range:[1e3,4e4],precision:.1,group:"White Balance",defaultValue:6500}),e("design:type",Number)],w.prototype,"temperature",void 0),t([s({optional:!0,range:[-1,1],group:"White Balance",defaultValue:0}),e("design:type",Number)],w.prototype,"temperatureTint",void 0),t([s(f("Global","Saturation")),e("design:type",g)],w.prototype,"globalSaturation",void 0),t([s(f("Global","Contrast")),e("design:type",g)],w.prototype,"globalContrast",void 0),t([s(f("Global","Gamma")),e("design:type",g)],w.prototype,"globalGamma",void 0),t([s(f("Global","Gain")),e("design:type",g)],w.prototype,"globalGain",void 0),t([s(c("Global","Offset")),e("design:type",g)],w.prototype,"globalOffset",void 0),t([s(f("Shadows","Saturation")),e("design:type",g)],w.prototype,"shadowsSaturation",void 0),t([s(f("Shadows","Contrast")),e("design:type",g)],w.prototype,"shadowsContrast",void 0),t([s(f("Shadows","Gamma")),e("design:type",g)],w.prototype,"shadowsGamma",void 0),t([s(f("Shadows","Gain")),e("design:type",g)],w.prototype,"shadowsGain",void 0),t([s(c("Shadows","Offset")),e("design:type",g)],w.prototype,"shadowsOffset",void 0),t([s({optional:!0,group:"Shadows",label:"Max",range:[0,1],precision:3,stepSize:.01,defaultValue:.09}),e("design:type",Number)],w.prototype,"shadowsMax",void 0),t([s(f("Midtones","Saturation")),e("design:type",g)],w.prototype,"midtonesSaturation",void 0),t([s(f("Midtones","Contrast")),e("design:type",g)],w.prototype,"midtonesContrast",void 0),t([s(f("Midtones","Gamma")),e("design:type",g)],w.prototype,"midtonesGamma",void 0),t([s(f("Midtones","Gain")),e("design:type",g)],w.prototype,"midtonesGain",void 0),t([s(c("Midtones","Offset")),e("design:type",g)],w.prototype,"midtonesOffset",void 0),t([s(f("Highlights","Saturation")),e("design:type",g)],w.prototype,"highlightsSaturation",void 0),t([s(f("Highlights","Contrast")),e("design:type",g)],w.prototype,"highlightsContrast",void 0),t([s(f("Highlights","Gamma")),e("design:type",g)],w.prototype,"highlightsGamma",void 0),t([s(f("Highlights","Gain")),e("design:type",g)],w.prototype,"highlightsGain",void 0),t([s(c("Highlights","Offset")),e("design:type",g)],w.prototype,"highlightsOffset",void 0),t([s({optional:!0,group:"Highlights",label:"Min",range:[0,1],precision:3,stepSize:.01,defaultValue:.5}),e("design:type",Number)],w.prototype,"highlightsMin",void 0),t([s({label:"LUT",optional:!0,group:"LUT"}),e("design:type",a)],w.prototype,"lut",void 0),t([s({label:"LUT Intensity",range:[0,1],optional:!0,group:"LUT",defaultValue:0}),e("design:type",Number)],w.prototype,"lutIntensity",void 0),w=t([n()],w);export{w as PostProcessSettings};let G=class extends p{constructor(){super(),this.settings=i(w),this.bounded=!1,this.priority=0,this.blendWeight=1,this.blendRadius=0,this.box=new l(void 0,new u.Vector3(.5,.5,.5)),this.view=r(y),this.editorView=i(h),this.disposed.subscribe(()=>{this.view.removePostProcessVolume(this)})}onInit(){this.view.addPostProcessVolume(this),this.editorView.visible=this.bounded}containsPoint(t){return!this.bounded||(this.resetBox(),this.box.containsPoint(t))}distanceToPoint(t){return this.bounded?(this.resetBox(),this.box.clampPoint(t,S),S.distanceTo(t)):0}resetBox(){const t=this.box;t.center.set(0,0,0),t.halfSize.set(.5,.5,.5),t.rotation.copy(x.rotation),t.applyMatrix4(this.object.matrixWorld)}};t([s(),e("design:type",Boolean)],G.prototype,"bounded",void 0),t([s({precision:0}),e("design:type",Number)],G.prototype,"priority",void 0),t([s({range:[0,1]}),e("design:type",Number)],G.prototype,"blendWeight",void 0),t([s(),e("design:type",Number)],G.prototype,"blendRadius",void 0),G=t([o(),e("design:paramtypes",[])],G);export{G as PostProcessVolume};const x=new l,S=new g;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
package/dist/gameplay/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { Actor, BaseActor } from './actors/actor.js';
|
|
|
8
8
|
export { Component, ActorComponent, type ComponentOptions, attach, Attach } from './actors/component.js';
|
|
9
9
|
export * from './services/world.js';
|
|
10
10
|
export * from './services/game-time-scheduler.js';
|
|
11
|
+
export * from './services/camera-shake.js';
|
|
11
12
|
export * from './services/render.js';
|
|
12
13
|
export * from './services/physics/physics-system.js';
|
|
13
14
|
export * from './animation/anim-sm.js';
|
package/dist/gameplay/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"reflect-metadata";export{Container as DIContainer}from"typedi";export*from"./initiate.js";export*from"./inject.js";export{Service,Inject}from"typedi";export{ActorFactory}from"./actors/factory.js";export{Actor,BaseActor}from"./actors/actor.js";export{Component,ActorComponent,attach,Attach}from"./actors/component.js";export*from"./services/world.js";export*from"./services/game-time-scheduler.js";export*from"./services/render.js";export*from"./services/physics/physics-system.js";export*from"./animation/anim-sm.js";export*from"./animation/root-motion.js";export*from"./services/asset-loader.js";export*from"./services/pointer-events.js";export{VisualEffect}from"../effects/vfx/vfx-param.js";export*from"../shader/parameter.js";export*from"./ai/index.js";export*from"../effects/vfx/index.js";export*from"./services/shader-provider.js";/*
|
|
1
|
+
import"reflect-metadata";export{Container as DIContainer}from"typedi";export*from"./initiate.js";export*from"./inject.js";export{Service,Inject}from"typedi";export{ActorFactory}from"./actors/factory.js";export{Actor,BaseActor}from"./actors/actor.js";export{Component,ActorComponent,attach,Attach}from"./actors/component.js";export*from"./services/world.js";export*from"./services/game-time-scheduler.js";export*from"./services/camera-shake.js";export*from"./services/render.js";export*from"./services/physics/physics-system.js";export*from"./animation/anim-sm.js";export*from"./animation/root-motion.js";export*from"./services/asset-loader.js";export*from"./services/pointer-events.js";export{VisualEffect}from"../effects/vfx/vfx-param.js";export*from"../shader/parameter.js";export*from"./ai/index.js";export*from"../effects/vfx/index.js";export*from"./services/shader-provider.js";/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|