@hology/core 0.0.271 → 0.0.273

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.
Files changed (40) hide show
  1. package/dist/effects/vfx/gpu-sprite-compiler.js +1 -1
  2. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  3. package/dist/effects/vfx/gpu-vfx-world-service.js +1 -1
  4. package/dist/effects/vfx/rates.d.ts +2 -0
  5. package/dist/effects/vfx/rates.js +1 -1
  6. package/dist/effects/vfx/vfx-actor.d.ts +2 -1
  7. package/dist/effects/vfx/vfx-actor.js +1 -1
  8. package/dist/effects/vfx/vfx-asset.d.ts +10 -1
  9. package/dist/effects/vfx/vfx-backend-partition.d.ts +8 -0
  10. package/dist/effects/vfx/vfx-backend-partition.js +4 -0
  11. package/dist/effects/vfx/vfx-materializer.js +1 -1
  12. package/dist/effects/vfx/vfx-render-preparation.js +1 -1
  13. package/dist/effects/vfx/vfx-renderers.d.ts +27 -2
  14. package/dist/effects/vfx/vfx-renderers.js +1 -1
  15. package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +2 -0
  16. package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
  17. package/dist/gameplay/initiate.js +1 -1
  18. package/dist/scene/asset-resource-loader.d.ts +5 -1
  19. package/dist/scene/asset-resource-loader.js +1 -1
  20. package/dist/scene/materializer.d.ts +1 -1
  21. package/dist/scene/materializer.js +1 -1
  22. package/dist/scene/model.d.ts +4 -0
  23. package/dist/scene/native-texture.d.ts +13 -0
  24. package/dist/scene/native-texture.js +4 -0
  25. package/dist/shader-nodes/particle-parameter.d.ts +4 -0
  26. package/dist/shader-nodes/particle-parameter.js +4 -0
  27. package/dist/test/asset-resource-loader-texture-array.test.js +1 -1
  28. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  29. package/dist/test/gpu-sprite-pipeline-cache.test.js +1 -1
  30. package/dist/test/native-texture.test.d.ts +2 -0
  31. package/dist/test/native-texture.test.js +4 -0
  32. package/dist/test/shader-graph.test.js +1 -1
  33. package/dist/test/vfx-backend-partition.test.d.ts +2 -0
  34. package/dist/test/vfx-backend-partition.test.js +4 -0
  35. package/dist/test/vfx-playback-transform.test.js +1 -1
  36. package/dist/test/vfx-render-preparation.test.js +1 -1
  37. package/dist/utils/mesh.d.ts +1 -1
  38. package/dist/utils/mesh.js +1 -1
  39. package/package.json +1 -1
  40. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{canCrossFadeFromAnimationAction as i}from"../../../../animation/animation-action.js";import{RootMotionClip as s}from"../../../../animation/root-motion.js";import{inject as r}from"../../../../inject.js";import{ViewController as n}from"../../../../services/render.js";import{AnimationMixer as a,Bone as l,Object3D as h,LoopOnce as c,Raycaster as d,Vector3 as p,SkinnedMesh as u,Skeleton as f,Quaternion as g,Matrix4 as m,MathUtils as k,ArrowHelper as y,Group as S}from"three";import{getCharacterMovementLike as I}from"./character-movement-like.js";import{CCDIKSolver as P}from"three/addons/animation/CCDIKSolver.js";import{World as w}from"../../../../services/world.js";import{PhysicsSystem as v,RayTestResult as b}from"../../../../services/physics/physics-system.js";import{ArrayMap as x}from"../../../../../utils/collections.js";import{getAnimationClipRigId as L,getAnimationRigChainBoneNames as B,getAnimationRigDataFromObject as R,getAnimationRigIdFromObject as F,setAnimationClipRigId as A}from"../../../../animation/retarget.js";import{FootContactAnchor as D,getAnimationFootContacts as C,isFootInContact as M,setAnimationFootContacts as T}from"../../../../animation/foot-contact.js";const W=new p(0,-1,0),O=new p(0,1,0),q=new p(1,1,1),U=new g,V=new p,E=new p,H=new p,N=new p,z=new p,j=new g,Q=new g,G=new g,_=new g,$=new m,K=new m,Y=new p(1,0,0),J=new p(0,1,0),X=new p(0,0,1);function Z(){return{point:new p,normal:new p,hasNormal:!1}}const tt=["mixamorigHips","Hips","hips","Pelvis","pelvis"],et={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},ot={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},it=["left","right"];let st=class extends e{constructor(){super(...arguments),this.viewController=r(n),this.poseProcessors=new x,this.transitionProcessors=[],this.managedActions=[],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.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.externalControlActive=!1,this.world=r(w),this.physicsSystem=r(v),this._footIkEnabled=!1,this.footIkMoving=!1,this.footIkLocomotionEnabled=!1,this.footIkLocomotionActive=!0,this.footIkMaxPlantTurnAngleDeg=35,this.footIkMaxPlantDrift=.18,this.footIkMaxPlantPelvisDrop=.12,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.ikPelvisDescendantStack=[],this.ikWorldUpdateNodes=[],this.footIkStateReset=!0,this.footIkUsingContacts=!1,this.footIkLastRootPosition=new p,this.footIkHasRootSample=!1,this.ikPreSolvePelvisPosition=new p,this.footIkPoseApplied=!1,this.footIkAnimationPoseCaptured=!1,this.footIkContactTransitionTime=0,this.footIkTransitionLeftContact=!1,this.footIkTransitionRightContact=!1,this.ikLegState={left:{anchor:new D,contactRequested:!1,targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1},right:{anchor:new D,contactRequested:!1,targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new d,this.raycastIntersections=[],this.footIkRayTo=new p,this.footIkRayTestResult=new b,this.footIkRayTestOptions={debug:!1,excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:Z(),toe:Z(),heel:Z(),side:Z()},this.footIkAxesScratch={up:new p,forward:new p,right:new p},this.footIkSampleAxesScratch={forward:new p,right:new p},this.footIkScratch={footWorldPos:new p,centerRayStart:new p,toeRayStart:new p,heelRayStart:new p,sideRayStart:new p,desiredTargetPos:new p,desiredNormal:new p,desiredForward:new p,debugRayEndA:new p,debugRayEndB:new p,debugRayEndC:new p,debugRayEndD:new p,debugRayEndE:new p,debugRayEndF:new p},this.ikPreSolve={left:{upper:new g,lower:new g,foot:new g,footWorld:new g},right:{upper:new g,lower:new g,foot:new g,footWorld:new g}},this.ikSolveScratch={hip:new p,knee:new p,foot:new p,direction:new p,animatedDirection:new p,pole:new p,kneeTarget:new p,target:new p,currentDirection:new p,desiredDirection:new p,rotation:new g},this.getFullBodyClip=lt(t=>t.uuid,t=>rt(this.fullBodyMask,t)),this.getUpperBodyClip=lt(t=>t.uuid,t=>rt(this.upperBodyMask,t))}get isSequenceControlled(){return this.externalControlActive||this.sequenceAnimationControlled||this.sequenceAnimationReleasePending}get hasUpperBodyOverride(){return this.upperBodyOverride}get footIkEnabled(){return this._footIkEnabled}set footIkEnabled(t){this._footIkEnabled!==t&&(this.restoreFootIkPose(),this._footIkEnabled=t,null!=this.ikRoot&&(this.disposeFootIkDebug(),this.initializeFootIk(this.ikRoot,this.ikRootBone),this.syncFootIkDebug()))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=I(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.restoreFootIkPose(),this.resetFootIkContacts(),this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,W),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(W,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&&(ct(t,e)||ct(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 u||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof s)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}getFullBodySourceClip(){const t=this.fullBodyClip;return null!=t&&this.fullBodyAction?.getClip()===this.getFullBodyClip(t)?t:void 0}setup(t,e,o){this.restoreFootIkPose(),null!=e&&(this.upperBodyMask=nt(e),this.fullBodyMask=function(t,e){const o=new Set(nt(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof l||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(ht(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new a(t),this.managedActions.length=0,this.animationRigId=F(t),this.animationRigData=R(t),this.ikRoot=t,this.ikRootBone=o,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:e.current.options.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:e.current.options.priority??0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}addPoseProcessor(t){const e={id:t.id,phase:t.phase??"afterMixer",order:t.order??0,update:t.update};this.removePoseProcessor(e.id);const o=this.poseProcessors.get(e.phase);let i=o.findIndex(t=>t.order>e.order);return-1===i&&(i=o.length),o.splice(i,0,e),()=>{const t=o.indexOf(e);-1!==t&&(o.splice(t,1),0===o.length&&this.poseProcessors.delete(e.phase))}}removePoseProcessor(t){for(const[e,o]of this.poseProcessors.entries()){const i=o.findIndex(e=>e.id===t);if(-1!==i)return o.splice(i,1),void(0===o.length&&this.poseProcessors.delete(e))}}addTransitionProcessor(t){const e=this.transitionProcessors.findIndex(e=>e.id===t.id);return e>=0&&this.transitionProcessors.splice(e,1),this.transitionProcessors.push(t),()=>{const e=this.transitionProcessors.indexOf(t);e>=0&&this.transitionProcessors.splice(e,1)}}preparePoseTransition(t,e,o){if(0===this.transitionProcessors.length)return!1;const i=this.fullBodyAction,s=this.getFullBodySourceClip();if(null==i||null==s||i.getClip().uuid===e.uuid||this.isSequenceControlled||o.sequenceControlled||this.upperBodyOverride)return!1;const r=this.transitionContext??(this.transitionContext={});r.animation=this,r.source=i,r.sourceClip=s,r.targetClip=t,r.targetPoseClip=e,r.targetTimeScale=this.getPlaybackTimeScale(e,o.timeScale??1),r.options=o;for(const t of this.transitionProcessors)if(t.prepare(r))return!0;return!1}runPoseProcessors(t,e){if(0===this.poseProcessors.size||null==this.mixer||!this.poseProcessors.present(t))return;const o=this.mixer.getRoot();if(!(o instanceof h))return;const i=this.poseProcessorContext??(this.poseProcessorContext={deltaTime:e,phase:t,animation:this,mixer:this.mixer,root:o});i.deltaTime=e,i.phase=t,i.mixer=this.mixer,i.root=o;const s=this.poseProcessors.get(t);for(let t=0;t<s.length;t++)s[t].update(i)}updateInternal(t){if(null==this.mixer)return;if(this.externalControlActive)return;this.restoreFootIkPose(),this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1);let e=!1;this.sequenceAnimationReleasePending&&(this.sequenceAnimationReleaseFrames>0?(e=!0,this.sequenceAnimationReleaseFrames--):(this.sequenceAnimationReleasePending=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationControlled=!1,this.overrideFadeTime=null,this.fullBodyTimer=0)),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.sequenceAnimationControlled&&!this.sequenceAnimationReleasePending&&this.fullBodyAction&&this.fullBodyAction.loop===c&&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),e||this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.captureFootIkAnimationPose(),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)}initializeFootIk(t,e){if(this.resetFootIkContacts(),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.ikWorldUpdateNodes.length=0,this.footIkStateReset=!0,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=B(this.animationRigData,"leftLeg"),r=B(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,et,s),a=this.resolveLegBoneRefs(i,this.rightLegIkBones,ot,r);if(null==n||null==a)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:n,right:a},this.ikLegLengths={left:this.computeLegLengths(n),right:this.computeLegLengths(a)},this.ikFootAxes={left:this.detectFootAxisBasis(n.foot),right:this.detectFootAxisBasis(a.foot)};const h=this.animationRigData?.bones.find(t=>t.id===this.animationRigData?.pelvisBoneId)?.name;this.ikPelvisBone=this.resolvePelvisBone(i,n,a,h),this.rebuildFootIkWorldUpdateNodes(),this.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(V)),this.ikLegState.right.targetPosition.copy(a.foot.getWorldPosition(V)),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",n.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",a.foot),this.ikLegState.left.planted=!1,this.ikLegState.right.planted=!1,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(V)),this.ikLegState.right.lastFootWorldPos.copy(a.foot.getWorldPosition(V)),this.ikLegState.left.hasLastFootSample=!1,this.ikLegState.right.hasLastFootSample=!1;const c=this.resolveFootAxes("left",n.foot),d=this.resolveFootAxes("right",a.foot);this.ikLegState.left.forward.copy(c.forward),this.ikLegState.right.forward.copy(d.forward);const p=e??ht(t);if(null==p)return;let u=i.getBoneByName("_IKTargetLeftFoot"),g=i.getBoneByName("_IKTargetRightFoot"),k=!1;if(null==u&&(u=new l,u.name="_IKTargetLeftFoot",p.add(u),k=!0),null==g&&(g=new l,g.name="_IKTargetRightFoot",p.add(g),k=!0),this.setBoneWorldPosition(u,n.foot.getWorldPosition(V)),this.setBoneWorldPosition(g,a.foot.getWorldPosition(V)),k||i.bones.indexOf(u)<0||i.bones.indexOf(g)<0){const e=i.bones.slice(),o=i.boneInverses.map(t=>t.clone());e.indexOf(u)<0&&(e.push(u),o.push((new m).copy(u.matrixWorld).invert())),e.indexOf(g)<0&&(e.push(g),o.push((new m).copy(g.matrixWorld).invert()));const s=new f(e,o);t.traverse(t=>{const e=t;!0===e.isSkinnedMesh&&e.skeleton===i&&e.bind(s,e.bindMatrix)})}this.ikTargetBones={left:u,right:g},this.rebuildFootIkWorldUpdateNodes();const y=o.skeleton.bones,S={target:y.indexOf(u),effector:y.indexOf(n.foot),links:[{index:y.indexOf(n.lower)},{index:y.indexOf(n.upper)}],iteration:8},I={target:y.indexOf(g),effector:y.indexOf(a.foot),links:[{index:y.indexOf(a.lower)},{index:y.indexOf(a.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||I.target<0||I.effector<0||I.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 P(o,[S,I])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof u||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o,i=[]){const s=this.findBoneByNames(t,[i[0],e.upperLeg,...o.upper].filter(t=>null!=t)),r=this.findBoneByNames(t,[i.at(-2),e.lowerLeg,...o.lower].filter(t=>null!=t)),n=this.findBoneByNames(t,[i.at(-1),e.foot,...o.foot].filter(t=>null!=t));if(null!=s&&null!=r&&null!=n)return{upper:s,lower:r,foot:n}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o,i){const s=this.findBoneByNames(t,[i,this.footIkPelvisBone,...tt].filter(t=>null!=t));if(null!=s)return s;const r=e.upper.parent,n=o.upper.parent;return null!=r&&r===n&&(r instanceof l||!0===r.isBone)||null!=r&&(r instanceof l||!0===r.isBone)?r:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(V),o=t.lower.getWorldPosition(E),i=t.foot.getWorldPosition(H),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(V.copy(e).applyMatrix4($.copy(o.matrixWorld).invert())),t.quaternion.copy(U),t.scale.copy(q),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new S,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 S;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),a=this.createDebugArrow(65280),l=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,a,l,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:a,footUp:l,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new y(O,new p,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){V.subVectors(o,e);const i=V.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(V.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.footIkUsingContacts=!1,this.footIkLocomotionEnabled){const e=this.fullBodyAction,o=e?.getClip(),i=C(o);if(!this.footIkLocomotionActive||this.isSequenceControlled||null==i||null==e||e.getEffectiveWeight()<.65||!Number.isFinite(t)||t<0)return this.resetFootIkContacts(),void this.resetDebugVisibility();(this.footIkContactClip!==o||t>.2)&&(this.resetFootIkContacts(),this.footIkContactClip=o);const s=this.actor.object.getWorldPosition(V),r=(this.movementSpeed??0)*Math.max(0,t);this.footIkHasRootSample&&this.footIkLastRootPosition.distanceToSquared(s)>(1+r)**2&&(this.resetFootIkContacts(),this.footIkContactClip=o),this.footIkLastRootPosition.copy(s),this.footIkHasRootSample=!0,this.footIkUsingContacts=!0;const n=e.loop!==c;this.footIkContactTransitionTime=Math.max(0,this.footIkContactTransitionTime-t),this.ikLegState.left.contactRequested=this.footIkContactTransitionTime>0?this.footIkTransitionLeftContact:M(i.left,e.time,o.duration,n),this.ikLegState.right.contactRequested=this.footIkContactTransitionTime>0?this.footIkTransitionRightContact:M(i.right,e.time,o.duration,n)}if(!this.footIkUsingContacts&&!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.footIkStateReset||(this.syncFootIkWorldMatrices(),this.resetFootIkState(),this.footIkStateReset=!0),void this.resetDebugVisibility();this.syncFootIkWorldMatrices(),this.footIkStateReset=!1;const e=this.characterMovement?.isGrounded??!0;if(this.footIkSimpleTiltOnly)return 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);if(null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver)return this.updatePelvisOffset(t,!1),void this.resetDebugVisibility();if(this.footIkUsingContacts&&null!=this.ikPelvisBone&&this.ikPreSolvePelvisPosition.copy(this.ikPelvisBone.position),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.footIkUsingContacts&&!this.footIkAnimationPoseCaptured&&this.getCurrentWorldQuaternion(this.ikBoneRefs.left.foot,this.ikPreSolve.left.footWorld),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),this.footIkUsingContacts&&!this.footIkAnimationPoseCaptured&&this.getCurrentWorldQuaternion(this.ikBoneRefs.right.foot,this.ikPreSolve.right.footWorld),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.footIkUsingContacts?(this.ikLegState.left.weight>.001&&this.solveTwoBoneLeg("left",this.ikBoneRefs.left,this.ikLegState.left.targetPosition),this.ikLegState.right.weight>.001&&this.solveTwoBoneLeg("right",this.ikBoneRefs.right,this.ikLegState.right.targetPosition)):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.footIkUsingContacts){this.syncFootIkWorldMatrices();for(const t of it){const e=this.ikBoneRefs[t].foot,o=this.getCurrentWorldQuaternion(e.parent,j);e.quaternion.copy(o.invert().multiply(this.ikPreSolve[t].footWorld))}this.footIkPoseApplied=!0}this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right)}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of it){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=V.setFromMatrixPosition(e.foot.matrixWorld);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,o.anchor.reset()}this.ikPelvisOffsetY=0}}resetFootIkContacts(){for(const t of it){const e=this.ikLegState[t];e.anchor.reset(),e.contactRequested=!1,e.planted=!1,e.weight=0,e.hasLastFootSample=!1}this.footIkContactClip=void 0,this.footIkHasRootSample=!1,this.ikPelvisOffsetY=0,this.footIkContactTransitionTime=0}preserveFootIkContacts(t,e){this.footIkEnabled&&this.footIkLocomotionEnabled&&e>0&&(this.footIkContactClip=t,this.footIkTransitionLeftContact=this.ikLegState.left.anchor.locked,this.footIkTransitionRightContact=this.ikLegState.right.anchor.locked,this.footIkContactTransitionTime=e)}restoreFootIkPose(){if(this.footIkPoseApplied&&null!=this.ikBoneRefs){for(const t of it){const e=this.ikBoneRefs[t],o=this.ikPreSolve[t];e.upper.quaternion.copy(o.upper),e.lower.quaternion.copy(o.lower),e.foot.quaternion.copy(o.foot)}this.ikPelvisBone?.position.copy(this.ikPreSolvePelvisPosition),this.footIkPoseApplied=!1}}captureFootIkAnimationPose(){this.footIkAnimationPoseCaptured=!1,this.footIkEnabled&&this.footIkLocomotionEnabled&&this.footIkLocomotionActive&&!this.isSequenceControlled&&null!=this.ikBoneRefs&&null!=C(this.fullBodyAction?.getClip())&&(this.syncFootIkWorldMatrices(),this.getCurrentWorldQuaternion(this.ikBoneRefs.left.foot,this.ikPreSolve.left.footWorld),this.getCurrentWorldQuaternion(this.ikBoneRefs.right.foot,this.ikPreSolve.right.footWorld),this.footIkAnimationPoseCaptured=!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 it){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=V.setFromMatrixPosition(e.upper.matrixWorld),n=.998*i.total,a=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(a>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-a)}const t=this.footIkUsingContacts?Math.min(this.footIkPelvisMaxOffsetDown,this.footIkMaxPlantPelvisDrop):this.footIkPelvisMaxOffsetDown;o=k.clamp(o,-t,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=k.lerp(this.ikPelvisOffsetY,o,i);const s=E.setFromMatrixPosition(this.ikPelvisBone.matrixWorld),r=H.copy(s).addScaledVector(O,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(r.applyMatrix4($.copy(this.ikPelvisBone.parent.matrixWorld).invert())),this.updatePelvisWorldTranslation(s)}updatePelvisWorldTranslation(t){const e=this.ikPelvisBone;if(null==e)return;e.updateMatrix(),null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix),e.matrixWorldNeedsUpdate=!1;const o=e.matrixWorld.elements,i=o[12]-t.x,s=o[13]-t.y,r=o[14]-t.z;if(0===i&&0===s&&0===r)return;const n=this.ikPelvisDescendantStack;n.length=0;for(let t=0;t<e.children.length;t++)n.push(e.children[t]);for(;n.length>0;){const t=n.pop(),e=t.matrixWorld.elements;e[12]+=i,e[13]+=s,e[14]+=r,t.matrixWorldNeedsUpdate=!1;for(let e=0;e<t.children.length;e++)n.push(t.children[e])}}rebuildFootIkWorldUpdateNodes(){const t=this.ikRoot,e=this.ikBoneRefs;if(null==t||null==e)return void(this.ikWorldUpdateNodes.length=0);const o=new Set,i=[this.ikPelvisBone,e.left.upper,e.left.lower,e.left.foot,e.right.upper,e.right.lower,e.right.foot,this.ikTargetBones?.left,this.ikTargetBones?.right];for(const e of i){let i=e;for(;null!=i&&(o.add(i),i!==t);)i=i.parent??void 0}this.ikWorldUpdateNodes.length=0,t.traverse(t=>{o.has(t)&&this.ikWorldUpdateNodes.push(t)})}syncFootIkWorldMatrices(){const t=this.ikRoot;if(null!=t){t.updateWorldMatrix(!0,!1);for(const e of this.ikWorldUpdateNodes)e!==t&&(e.matrixAutoUpdate&&e.updateMatrix(),e.matrixWorldAutoUpdate&&(null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix)),e.matrixWorldNeedsUpdate=!1)}}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(E),h=H.copy(n.upLocal).applyQuaternion(this.getCurrentWorldQuaternion(o,j)).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=$.copy(t.boneInverses[i]).invert(),n=K.copy(r).multiply(s),d=V.setFromMatrixPosition(n),p=N.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;if(this.footIkUsingContacts)return t.contactRequested;const n=this.footIkPlantReleaseExtension,a=this.footIkPlantAttachExtension,l=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>l)):s>=a&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=V.setFromMatrixPosition(t.upper.matrixWorld),i=E.setFromMatrixPosition(t.foot.matrixWorld),s=o.distanceTo(i);return e.total<=1e-6?1:k.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=N.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(O),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const a=Math.sqrt(n),l=r-a,h=r+a;return l>=0?l:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,a=r.footWorldPos.setFromMatrixPosition(e.matrixWorld),l=this.computeFootVerticalSpeed(o,a,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(a).addScaledVector(O,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),y=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),I=r.desiredNormal.set(0,1,0),P=r.desiredForward.copy(c.forward);let w=0,v=0,b=this.footIkWeightOutSpeed;const x=null!=g||null!=m||null!=y;let L=a.y;null!=g?L=g.point.y:null!=m&&null!=y?L=.5*(m.point.y+y.point.y):null!=m?L=m.point.y:null!=y&&(L=y.point.y);const B=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],F=null!=B&&null!=R?this.computeLegExtensionRatio(B,R):1,A=Math.max(0,a.y-L,a.y-o.targetPosition.y),D=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,x,l,F,A);D?this.computeDesiredGroundNormal(c,g,m,y,S,I)&&(this.computeDesiredFootForward(c.forward,c.right,I,m,y,P),w=this.computeDesiredPitchAngle(m,y,c.forward),v=1,b=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,I,null,null,P);const C=1-Math.exp(-this.footIkPositionLerpSpeed*s),M=1-Math.exp(-b*s);o.normal.lerp(I,C).normalize(),o.forward.lerp(P,C).normalize(),o.pitch=k.lerp(o.pitch,w,C),o.weight=k.lerp(o.weight,v,M),o.planted=D&&v>.001,this.updateFootSample(o,a),this.applySimpleFootPitch(t,e,o),this.footIkDebug&&this.updateLegDebug(t,{footWorldPos:a,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:y,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const a=this.footIkScratch,l=this.footIkHits,h=e.foot,c=a.footWorldPos.setFromMatrixPosition(h.matrixWorld);if(this.footIkUsingContacts&&!s.contactRequested)return s.anchor.reset(),s.planted=!1,s.weight*=Math.exp(-this.footIkWeightOutSpeed*n),s.pitch*=Math.exp(-this.footIkRotationLerpSpeed*n),s.weight<=.001?s.targetPosition.copy(c):s.targetPosition.lerp(c,1-Math.exp(-this.footIkPositionLerpSpeed*n)),this.clampDesiredFootTarget(e,o,c,s.targetPosition),this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),void(null!=this.ikDebugLegs&&(this.ikDebugLegs[t].root.visible=!1));const d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=this.footIkUsingContacts&&s.anchor.locked&&s.contactRequested?s.anchor.position:c,g=a.centerRayStart.copy(f).addScaledVector(O,this.footIkRayStartHeight),m=a.toeRayStart.copy(g).addScaledVector(u.forward,this.footIkForwardSampleDistance),y=a.heelRayStart.copy(g).addScaledVector(u.forward,-this.footIkForwardSampleDistance),S=a.sideRayStart.copy(g).addScaledVector(u.right,this.footIkSideSampleDistance),I=this.getFirstGroundHit(g,l.center),P=this.getFirstGroundHit(m,l.toe),w=this.getFirstGroundHit(y,l.heel),v=this.getFirstGroundHit(S,l.side),b=a.desiredTargetPos.copy(c),x=a.desiredNormal.set(0,1,0),L=a.desiredForward.copy(u.forward);let B=0,R=0,F=this.footIkWeightOutSpeed;const A=null!=I||null!=P||null!=w;let D=c.y;null!=I?D=I.point.y:null!=P&&null!=w?D=.5*(P.point.y+w.point.y):null!=P?D=P.point.y:null!=w&&(D=w.point.y);const C=this.computeLegExtensionRatio(e,o),M=Math.max(0,c.y-D,c.y-s.targetPosition.y),T=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,A,d,C,M);if(T){if(b.copy(c),this.computeDesiredGroundNormal(u,I,P,w,v,x)){this.computeDesiredFootForward(u.forward,u.right,x,P,w,L),B=this.computeDesiredPitchAngle(P,w,u.forward);const t=Math.max(0,Math.sin(B))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);b.y=D+e+t,s.top&&!this.footIkUsingContacts&&(b.y-=this.ikPelvisOffsetY/2),R=1,F=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,x,null,null,L),b.copy(c),this.footIkUsingContacts||(b.y+=this.footIkFootOffset);if(this.footIkUsingContacts){const t=z.setFromMatrixPosition(e.upper.matrixWorld),i=this.footIkPelvisEnabled?Math.min(this.footIkMaxPlantPelvisDrop,this.footIkPelvisMaxOffsetDown):0;s.anchor.locked&&Math.abs(b.y-s.anchor.position.y)>.08&&s.anchor.release();s.anchor.update(s.contactRequested,(!this.footIkRequireGrounded||r)&&null!=I&&R>0,c,b,u.forward,t,.995*o.total,i,Math.min(this.footIkMaxPlantDrift,this.footIkMaxHorizontalOffset),k.degToRad(this.footIkMaxPlantTurnAngleDeg))?b.copy(s.anchor.position):(b.copy(c),R=0,F=this.footIkWeightOutSpeed)}const W=1-Math.exp(-this.footIkPositionLerpSpeed*n),q=1-Math.exp(-F*n);this.footIkUsingContacts&&s.anchor.locked?s.targetPosition.copy(b):s.targetPosition.lerp(b,W),this.clampDesiredFootTarget(e,o,c,s.targetPosition),s.normal.lerp(x,W).normalize(),s.forward.lerp(L,W).normalize(),s.pitch=k.lerp(s.pitch,B,W),s.weight=k.lerp(s.weight,R,q),s.planted=T&&R>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.footIkDebug&&this.updateLegDebug(t,{footWorldPos:c,centerRayStart:g,toeRayStart:m,heelRayStart:y,sideRayStart:S,centerHit:I,toeHit:P,heelHit:w,sideHit:v,desiredNormal:x,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(W,this.footIkRayLength),a=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(W,this.footIkRayLength),l=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(W,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(W,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,a),this.setDebugArrow(o.rayHeel,e.heelRayStart,l),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 p,right:new p},n=this.getCurrentWorldDirection(this.actor.object,N);n.addScaledVector(O,-n.dot(O)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(O,-s.forward.dot(O)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const a=z.crossVectors(O,n);return a.lengthSq()<1e-8?a.copy(s.right):a.normalize(),a.dot(s.right)<0&&a.multiplyScalar(-1),r.forward.copy(n),r.right.copy(a),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,N);let a=!1,l=0,h=0;if(null!=o&&null!=i){const e=E.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(l=(o.point.y-i.point.y)/e,a=!0)}if(null!=s&&null!=e){const o=H.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,a=!0)}if(a&&(r.copy(O),r.addScaledVector(t.forward,-l),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():a=!1),a)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),a=!0}return r.dot(O)<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.getCurrentWorldDirection(this.actor.object,N)),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=N.copy(this.getCurrentWorldDirection(this.actor.object,N));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=E.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=k.degToRad(this.footIkMaxSlopeAngleDeg);return k.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=j.copy(e.quaternion),a=Q.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(a))}resolveLocalPitchSign(t){const e=G.setFromAxisAngle(t.rightLocal,.15);return H.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=E.subVectors(i,o),r=s.dot(O),n=H.copy(s).addScaledVector(O,-r),a=n.length();a>this.footIkMaxHorizontalOffset&&a>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/a);const l=k.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(O,l),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(V).clone(),c=E.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=this.ikSolveScratch,s=i.hip.setFromMatrixPosition(e.upper.matrixWorld),r=i.knee.setFromMatrixPosition(e.lower.matrixWorld),n=i.foot.setFromMatrixPosition(e.foot.matrixWorld),a=s.distanceTo(r),l=r.distanceTo(n);if(a<1e-5||l<1e-5)return;const h=i.direction.subVectors(o,s),c=h.length();if(c<1e-5)return;const d=Math.abs(a-l)+1e-5,p=a+l-1e-5,u=k.clamp(c,d,p),f=h.multiplyScalar(1/c),g=i.animatedDirection.subVectors(n,s).normalize(),m=i.pole.subVectors(r,s);m.addScaledVector(g,-m.dot(g)),m.lengthSq()<a*a*1e-4&&(this.getCurrentWorldDirection(this.actor.object,m),m.addScaledVector(g,-m.dot(g)),m.lengthSq()<1e-8&&(Math.abs(g.x)<.9?m.set(1,0,0):m.set(0,1,0),m.addScaledVector(g,-m.dot(g)))),m.normalize(),i.rotation.setFromUnitVectors(g,f),m.applyQuaternion(i.rotation);const y=(u*u+a*a-l*l)/(2*u),S=Math.max(a*a-y*y,0),I=Math.sqrt(S),P=i.kneeTarget.copy(s).addScaledVector(f,y).addScaledVector(m,I),w=i.target.copy(s).addScaledVector(f,u);this.rotateBoneToward(e.upper,s,r,P),e.upper.updateMatrixWorld(!0);const v=r.setFromMatrixPosition(e.lower.matrixWorld),b=n.setFromMatrixPosition(e.foot.matrixWorld);this.rotateBoneToward(e.lower,v,b,w),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,s,P,w)}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=this.ikSolveScratch.currentDirection.subVectors(o,e),r=this.ikSolveScratch.desiredDirection.subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>1-1e-10)return;const n=this.ikSolveScratch.rotation.setFromUnitVectors(s,r),a=this.getCurrentWorldQuaternion(t,j),l=Q.copy(n).multiply(a);if(null==t.parent)return void t.quaternion.copy(l);const h=this.getCurrentWorldQuaternion(t.parent,G),c=_.copy(h).invert().multiply(l);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=this.getCurrentWorldQuaternion(t,j),o=this.getCurrentWorldDirection(this.actor.object,V);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:Y.clone(),world:Y.clone().applyQuaternion(e)},{local:J.clone(),world:J.clone().applyQuaternion(e)},{local:X.clone(),world:X.clone().applyQuaternion(e)}];i.push({local:Y.clone().multiplyScalar(-1),world:Y.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:J.clone().multiplyScalar(-1),world:J.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:X.clone().multiplyScalar(-1),world:X.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(O);e>r&&(r=e,s=t)}let n=i[0],a=-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>a&&(a=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const l=s.local.clone().normalize(),h=n.local.clone().normalize(),c=l.clone().cross(h).normalize();return{upLocal:l,forwardLocal:c.clone().cross(l).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new p,forward:new p,right:new p},r=this.getCurrentWorldQuaternion(e,j);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}getCurrentWorldQuaternion(t,e){return t.matrixWorld.decompose(z,e,N),e}getCurrentWorldDirection(t,e){const o=t.matrixWorld.elements;return e.set(o[8],o[9],o[10]).normalize()}clampSlopeNormal(t){const e=k.clamp(t.dot(O),-1,1),o=Math.acos(e),i=k.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(O,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){j.copy(t.quaternion),t.quaternion.copy(e).slerp(j,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=V.copy(o.normal).normalize(),n=E.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 a=H.crossVectors(r,n);if(a.lengthSq()<1e-8)return;a.normalize(),n.copy(N.crossVectors(a,r)).normalize(),$.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),j.setFromRotationMatrix($),K.makeBasis(a,r,n),Q.setFromRotationMatrix(K);const l=G.copy(Q).multiply(_.copy(j).invert()),h=this.getCurrentWorldQuaternion(e.parent,_),c=Q.copy(h).invert().multiply(l),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,k.clamp(d,0,1))}getMixer(){return this.mixer}evaluateExternalPose(t=0){null!=this.mixer&&(this.restoreFootIkPose(),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.captureFootIkAnimationPose(),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t))}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null,this.fullBodyTimer=0}requestSequenceAnimationRelease(){this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationReleasePending=!0,this.sequenceAnimationReleaseFrames=1,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null}cancelRootMotionAction(t){null!=t&&this.fullBodyAction!==t||(this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyAction?.stop(),this.fullBodyAction=null,this.fullBodyTimer=0)}beginExternalAnimationControl(t,e={}){at(null!=this.mixer,"Can't begin external control before setup is called"),this.assertClipRigCompatible(t),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return this.managedActions.indexOf(o)<0&&this.managedActions.push(o),o.setLoop(c,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){null!=t&&(t.timeScale=this.getPlaybackTimeScale(t.getClip(),t.timeScale))}getPlaybackTimeScale(t,e){if(!(t instanceof s&&t.fixedInPlace&&null!=this.movementSpeed))return e;const o=this.mixer.getRoot(),i=o instanceof h?o.scale.x:1;return t.duration/t.displacement*this.movementSpeed/i}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={}){this.assertClipRigCompatible(t);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={}){at(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;if(o<this.currentFullBodyPriority)return;this.currentFullBodyPriority=o,this.fullBodyTimer=0,e.sequenceControlled&&(this.sequenceAnimationControlled=!0,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0);const i=this.getFullBodyClip(t);if(this.preparePoseTransition(t,i,e)){for(const t of this.managedActions)t.stop();this.managedActions.length=0,this.fullBodyAction=null,this.upperBodyAction=null}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,i,e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime}assertClipRigCompatible(t){const e=L(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!dt.has(o)){if(dt.add(o),null==e||null==this.animationRigId)return void console.warn(`Animation clip "${t.name}" or its character has no rig assigned. Playing without rig compatibility validation for legacy compatibility.`);console.warn(`Animation clip "${t.name}" targets rig ${e??"no rig"}, but this character uses rig ${this.animationRigId??"no rig"}. Generate and assign a retargeted clip for the character rig.`)}}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={}){const s=o?.fadeTime??this.fadeTime;if(null!=t&&t.getClip().uuid===e.uuid)return t.isRunning()||!1!==o.loop||!t.clampWhenFinished||o.sequenceControlled?(t.isRunning()||(t.reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play(),!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0)),t):t;if(i(t)){const i=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,i.crossFadeTo(r,s,!1),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play();return!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0),this.managedActions.indexOf(t)<0&&this.managedActions.push(t),t}};st=t([o({inEditor:!0})],st);export{st as CharacterAnimationComponent};function rt(t,e){if(null==t)return e;const o=e.clone();A(o,L(e)),T(o,C(e));const i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function nt(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof l)}function at(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function lt(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 ht(t){let e;return t.traverse(t=>{(t instanceof l||t.isBone)&&null==e&&(e=t)}),e}function ct(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const dt=new Set;/*
1
+ import{__decorate as t}from"tslib";import{ActorComponent as e,Component as o}from"../../../component.js";import{canCrossFadeFromAnimationAction as i}from"../../../../animation/animation-action.js";import{RootMotionClip as s}from"../../../../animation/root-motion.js";import{inject as r}from"../../../../inject.js";import{ViewController as n}from"../../../../services/render.js";import{AnimationMixer as a,Bone as l,Object3D as h,LoopOnce as c,Raycaster as d,Vector3 as p,SkinnedMesh as u,Skeleton as f,Quaternion as g,Matrix4 as m,MathUtils as k,ArrowHelper as y,Group as S}from"three";import{getCharacterMovementLike as I}from"./character-movement-like.js";import{CCDIKSolver as P}from"three/addons/animation/CCDIKSolver.js";import{World as w}from"../../../../services/world.js";import{PhysicsSystem as v,RayTestResult as b}from"../../../../services/physics/physics-system.js";import{ArrayMap as x}from"../../../../../utils/collections.js";import{getAnimationClipRigId as L,getAnimationRigChainBoneNames as B,getAnimationRigDataFromObject as R,getAnimationRigIdFromObject as F,setAnimationClipRigId as A}from"../../../../animation/retarget.js";import{FootContactAnchor as D,getAnimationFootContacts as C,isFootInContact as M,setAnimationFootContacts as T}from"../../../../animation/foot-contact.js";const W=new p(0,-1,0),O=new p(0,1,0),q=new p(1,1,1),U=new g,V=new p,E=new p,H=new p,N=new p,z=new p,j=new g,Q=new g,G=new g,_=new g,$=new m,K=new m,Y=new p(1,0,0),J=new p(0,1,0),X=new p(0,0,1);function Z(){return{point:new p,normal:new p,hasNormal:!1}}const tt=["mixamorigHips","Hips","hips","Pelvis","pelvis"],et={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},ot={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},it=["left","right"];let st=class extends e{constructor(){super(...arguments),this.viewController=r(n),this.poseProcessors=new x,this.transitionProcessors=[],this.managedActions=[],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.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.externalControlActive=!1,this.world=r(w),this.physicsSystem=r(v),this._footIkEnabled=!1,this.footIkMoving=!1,this.footIkLocomotionEnabled=!1,this.footIkLocomotionActive=!0,this.footIkMaxPlantTurnAngleDeg=35,this.footIkMaxPlantDrift=.18,this.footIkMaxPlantPelvisDrop=.12,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.ikPelvisDescendantStack=[],this.ikWorldUpdateNodes=[],this.footIkStateReset=!0,this.footIkUsingContacts=!1,this.footIkLastRootPosition=new p,this.footIkHasRootSample=!1,this.ikPreSolvePelvisPosition=new p,this.footIkPoseApplied=!1,this.footIkAnimationPoseCaptured=!1,this.footIkContactTransitionTime=0,this.footIkTransitionLeftContact=!1,this.footIkTransitionRightContact=!1,this.ikLegState={left:{anchor:new D,contactRequested:!1,targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1},right:{anchor:new D,contactRequested:!1,targetPosition:new p,normal:new p(0,1,0),forward:new p(0,0,1),pitch:0,contactOffset:0,planted:!1,lastFootWorldPos:new p,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new d,this.raycastIntersections=[],this.footIkRayTo=new p,this.footIkRayTestResult=new b,this.footIkRayTestOptions={debug:!1,excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:Z(),toe:Z(),heel:Z(),side:Z()},this.footIkAxesScratch={up:new p,forward:new p,right:new p},this.footIkSampleAxesScratch={forward:new p,right:new p},this.footIkScratch={footWorldPos:new p,centerRayStart:new p,toeRayStart:new p,heelRayStart:new p,sideRayStart:new p,desiredTargetPos:new p,desiredNormal:new p,desiredForward:new p,debugRayEndA:new p,debugRayEndB:new p,debugRayEndC:new p,debugRayEndD:new p,debugRayEndE:new p,debugRayEndF:new p},this.ikPreSolve={left:{upper:new g,lower:new g,foot:new g,footWorld:new g},right:{upper:new g,lower:new g,foot:new g,footWorld:new g}},this.ikSolveScratch={hip:new p,knee:new p,foot:new p,direction:new p,animatedDirection:new p,pole:new p,kneeTarget:new p,target:new p,currentDirection:new p,desiredDirection:new p,rotation:new g},this.getFullBodyClip=lt(t=>t.uuid,t=>rt(this.fullBodyMask,t)),this.getUpperBodyClip=lt(t=>t.uuid,t=>rt(this.upperBodyMask,t))}get isSequenceControlled(){return this.externalControlActive||this.sequenceAnimationControlled||this.sequenceAnimationReleasePending}get hasUpperBodyOverride(){return this.upperBodyOverride}get footIkEnabled(){return this._footIkEnabled}set footIkEnabled(t){this._footIkEnabled!==t&&(this.restoreFootIkPose(),this._footIkEnabled=t,null!=this.ikRoot&&(this.disposeFootIkDebug(),this.initializeFootIk(this.ikRoot,this.ikRootBone),this.syncFootIkDebug()))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=I(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.restoreFootIkPose(),this.resetFootIkContacts(),this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,W),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(W,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&&(ct(t,e)||ct(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 u||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof s)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}getFullBodySourceClip(){const t=this.fullBodyClip;return null!=t&&this.fullBodyAction?.getClip()===this.getFullBodyClip(t)?t:void 0}setup(t,e,o){this.restoreFootIkPose(),null!=e&&(this.upperBodyMask=nt(e),this.fullBodyMask=function(t,e){const o=new Set(nt(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof l||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(ht(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new a(t),this.managedActions.length=0,this.animationRigId=F(t),this.animationRigData=R(t),this.ikRoot=t,this.ikRootBone=o,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:e.current.options.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:e.current.options.priority??0,loop:e.current.options.loop??!0}):this.play(this.fullBodyClip)})}addPoseProcessor(t){const e={id:t.id,phase:t.phase??"afterMixer",order:t.order??0,update:t.update};this.removePoseProcessor(e.id);const o=this.poseProcessors.get(e.phase);let i=o.findIndex(t=>t.order>e.order);return-1===i&&(i=o.length),o.splice(i,0,e),()=>{const t=o.indexOf(e);-1!==t&&(o.splice(t,1),0===o.length&&this.poseProcessors.delete(e.phase))}}removePoseProcessor(t){for(const[e,o]of this.poseProcessors.entries()){const i=o.findIndex(e=>e.id===t);if(-1!==i)return o.splice(i,1),void(0===o.length&&this.poseProcessors.delete(e))}}addTransitionProcessor(t){const e=this.transitionProcessors.findIndex(e=>e.id===t.id);return e>=0&&this.transitionProcessors.splice(e,1),this.transitionProcessors.push(t),()=>{const e=this.transitionProcessors.indexOf(t);e>=0&&this.transitionProcessors.splice(e,1)}}preparePoseTransition(t,e,o){if(0===this.transitionProcessors.length)return!1;const i=this.fullBodyAction,s=this.getFullBodySourceClip();if(null==i||null==s||i.getClip().uuid===e.uuid||this.isSequenceControlled||o.sequenceControlled||this.upperBodyOverride)return!1;const r=this.transitionContext??(this.transitionContext={});r.animation=this,r.source=i,r.sourceClip=s,r.targetClip=t,r.targetPoseClip=e,r.targetTimeScale=this.getPlaybackTimeScale(e,o.timeScale??1),r.options=o;for(const t of this.transitionProcessors)if(t.prepare(r))return!0;return!1}runPoseProcessors(t,e){if(0===this.poseProcessors.size||null==this.mixer||!this.poseProcessors.present(t))return;const o=this.mixer.getRoot();if(!(o instanceof h))return;const i=this.poseProcessorContext??(this.poseProcessorContext={deltaTime:e,phase:t,animation:this,mixer:this.mixer,root:o});i.deltaTime=e,i.phase=t,i.mixer=this.mixer,i.root=o;const s=this.poseProcessors.get(t);for(let t=0;t<s.length;t++)s[t].update(i)}updateInternal(t){if(null==this.mixer)return;if(this.externalControlActive)return;this.restoreFootIkPose(),this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1);let e=!1;this.sequenceAnimationReleasePending&&(this.sequenceAnimationReleaseFrames>0?(e=!0,this.sequenceAnimationReleaseFrames--):(this.sequenceAnimationReleasePending=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationControlled=!1,this.overrideFadeTime=null,this.fullBodyTimer=0)),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.sequenceAnimationControlled&&!this.sequenceAnimationReleasePending&&this.fullBodyAction&&this.fullBodyAction.loop===c&&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),e||this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.captureFootIkAnimationPose(),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)}initializeFootIk(t,e){if(this.resetFootIkContacts(),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.ikWorldUpdateNodes.length=0,this.footIkStateReset=!0,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=B(this.animationRigData,"leftLeg"),r=B(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,et,s),a=this.resolveLegBoneRefs(i,this.rightLegIkBones,ot,r);if(null==n||null==a)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:n,right:a},this.ikLegLengths={left:this.computeLegLengths(n),right:this.computeLegLengths(a)},this.ikFootAxes={left:this.detectFootAxisBasis(n.foot),right:this.detectFootAxisBasis(a.foot)};const h=this.animationRigData?.bones.find(t=>t.id===this.animationRigData?.pelvisBoneId)?.name;this.ikPelvisBone=this.resolvePelvisBone(i,n,a,h),this.rebuildFootIkWorldUpdateNodes(),this.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(V)),this.ikLegState.right.targetPosition.copy(a.foot.getWorldPosition(V)),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",n.foot),this.ikLegState.right.contactOffset=this.estimateFootContactOffset(i,"right",a.foot),this.ikLegState.left.planted=!1,this.ikLegState.right.planted=!1,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(V)),this.ikLegState.right.lastFootWorldPos.copy(a.foot.getWorldPosition(V)),this.ikLegState.left.hasLastFootSample=!1,this.ikLegState.right.hasLastFootSample=!1;const c=this.resolveFootAxes("left",n.foot),d=this.resolveFootAxes("right",a.foot);this.ikLegState.left.forward.copy(c.forward),this.ikLegState.right.forward.copy(d.forward);const p=e??ht(t);if(null==p)return;let u=i.getBoneByName("_IKTargetLeftFoot"),g=i.getBoneByName("_IKTargetRightFoot"),k=!1;if(null==u&&(u=new l,u.name="_IKTargetLeftFoot",p.add(u),k=!0),null==g&&(g=new l,g.name="_IKTargetRightFoot",p.add(g),k=!0),this.setBoneWorldPosition(u,n.foot.getWorldPosition(V)),this.setBoneWorldPosition(g,a.foot.getWorldPosition(V)),k||i.bones.indexOf(u)<0||i.bones.indexOf(g)<0){const e=i.bones.slice(),o=i.boneInverses.map(t=>t.clone());e.indexOf(u)<0&&(e.push(u),o.push((new m).copy(u.matrixWorld).invert())),e.indexOf(g)<0&&(e.push(g),o.push((new m).copy(g.matrixWorld).invert()));const s=new f(e,o);t.traverse(t=>{const e=t;!0===e.isSkinnedMesh&&e.skeleton===i&&e.bind(s,e.bindMatrix)})}this.ikTargetBones={left:u,right:g},this.rebuildFootIkWorldUpdateNodes();const y=o.skeleton.bones,S={target:y.indexOf(u),effector:y.indexOf(n.foot),links:[{index:y.indexOf(n.lower)},{index:y.indexOf(n.upper)}],iteration:8},I={target:y.indexOf(g),effector:y.indexOf(a.foot),links:[{index:y.indexOf(a.lower)},{index:y.indexOf(a.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||I.target<0||I.effector<0||I.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 P(o,[S,I])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof u||!0===t.isSkinnedMesh)&&(e=t)}),e}resolveLegBoneRefs(t,e,o,i=[]){const s=this.findBoneByNames(t,[i[0],e.upperLeg,...o.upper].filter(t=>null!=t)),r=this.findBoneByNames(t,[i.at(-2),e.lowerLeg,...o.lower].filter(t=>null!=t)),n=this.findBoneByNames(t,[i.at(-1),e.foot,...o.foot].filter(t=>null!=t));if(null!=s&&null!=r&&null!=n)return{upper:s,lower:r,foot:n}}findBoneByNames(t,e){for(const o of e){const e=t.getBoneByName(o);if(null!=e)return e}}resolvePelvisBone(t,e,o,i){const s=this.findBoneByNames(t,[i,this.footIkPelvisBone,...tt].filter(t=>null!=t));if(null!=s)return s;const r=e.upper.parent,n=o.upper.parent;return null!=r&&r===n&&(r instanceof l||!0===r.isBone)||null!=r&&(r instanceof l||!0===r.isBone)?r:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(V),o=t.lower.getWorldPosition(E),i=t.foot.getWorldPosition(H),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(V.copy(e).applyMatrix4($.copy(o.matrixWorld).invert())),t.quaternion.copy(U),t.scale.copy(q),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new S,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 S;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),a=this.createDebugArrow(65280),l=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,a,l,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:a,footUp:l,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new y(O,new p,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){V.subVectors(o,e);const i=V.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(V.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.footIkUsingContacts=!1,this.footIkLocomotionEnabled){const e=this.fullBodyAction,o=e?.getClip(),i=C(o);if(!this.footIkLocomotionActive||this.isSequenceControlled||null==i||null==e||e.getEffectiveWeight()<.65||!Number.isFinite(t)||t<0)return this.resetFootIkContacts(),void this.resetDebugVisibility();(this.footIkContactClip!==o||t>.2)&&(this.resetFootIkContacts(),this.footIkContactClip=o);const s=this.actor.object.getWorldPosition(V),r=(this.movementSpeed??0)*Math.max(0,t);this.footIkHasRootSample&&this.footIkLastRootPosition.distanceToSquared(s)>(1+r)**2&&(this.resetFootIkContacts(),this.footIkContactClip=o),this.footIkLastRootPosition.copy(s),this.footIkHasRootSample=!0,this.footIkUsingContacts=!0;const n=e.loop!==c;this.footIkContactTransitionTime=Math.max(0,this.footIkContactTransitionTime-t),this.ikLegState.left.contactRequested=this.footIkContactTransitionTime>0?this.footIkTransitionLeftContact:M(i.left,e.time,o.duration,n),this.ikLegState.right.contactRequested=this.footIkContactTransitionTime>0?this.footIkTransitionRightContact:M(i.right,e.time,o.duration,n)}if(!this.footIkUsingContacts&&!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.footIkStateReset||(this.syncFootIkWorldMatrices(),this.resetFootIkState(),this.footIkStateReset=!0),void this.resetDebugVisibility();this.syncFootIkWorldMatrices(),this.footIkStateReset=!1;const e=this.characterMovement?.isGrounded??!0;if(this.footIkSimpleTiltOnly)return 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);if(null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver)return this.updatePelvisOffset(t,!1),void this.resetDebugVisibility();if(this.footIkUsingContacts&&null!=this.ikPelvisBone&&this.ikPreSolvePelvisPosition.copy(this.ikPelvisBone.position),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.footIkUsingContacts&&!this.footIkAnimationPoseCaptured&&this.getCurrentWorldQuaternion(this.ikBoneRefs.left.foot,this.ikPreSolve.left.footWorld),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),this.footIkUsingContacts&&!this.footIkAnimationPoseCaptured&&this.getCurrentWorldQuaternion(this.ikBoneRefs.right.foot,this.ikPreSolve.right.footWorld),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.footIkUsingContacts?(this.ikLegState.left.weight>.001&&this.solveTwoBoneLeg("left",this.ikBoneRefs.left,this.ikLegState.left.targetPosition),this.ikLegState.right.weight>.001&&this.solveTwoBoneLeg("right",this.ikBoneRefs.right,this.ikLegState.right.targetPosition)):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.footIkUsingContacts){this.syncFootIkWorldMatrices();for(const t of it){const e=this.ikBoneRefs[t].foot,o=this.getCurrentWorldQuaternion(e.parent,j);e.quaternion.copy(o.invert().multiply(this.ikPreSolve[t].footWorld))}this.footIkPoseApplied=!0}this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right)}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of it){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=V.setFromMatrixPosition(e.foot.matrixWorld);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,o.anchor.reset()}this.ikPelvisOffsetY=0}}resetFootIkContacts(){for(const t of it){const e=this.ikLegState[t];e.anchor.reset(),e.contactRequested=!1,e.planted=!1,e.weight=0,e.hasLastFootSample=!1}this.footIkContactClip=void 0,this.footIkHasRootSample=!1,this.ikPelvisOffsetY=0,this.footIkContactTransitionTime=0}preserveFootIkContacts(t,e){this.footIkEnabled&&this.footIkLocomotionEnabled&&e>0&&(this.footIkContactClip=t,this.footIkTransitionLeftContact=this.ikLegState.left.anchor.locked,this.footIkTransitionRightContact=this.ikLegState.right.anchor.locked,this.footIkContactTransitionTime=e)}restoreFootIkPose(){if(this.footIkPoseApplied&&null!=this.ikBoneRefs){for(const t of it){const e=this.ikBoneRefs[t],o=this.ikPreSolve[t];e.upper.quaternion.copy(o.upper),e.lower.quaternion.copy(o.lower),e.foot.quaternion.copy(o.foot)}this.ikPelvisBone?.position.copy(this.ikPreSolvePelvisPosition),this.footIkPoseApplied=!1}}captureFootIkAnimationPose(){this.footIkAnimationPoseCaptured=!1,this.footIkEnabled&&this.footIkLocomotionEnabled&&this.footIkLocomotionActive&&!this.isSequenceControlled&&null!=this.ikBoneRefs&&null!=C(this.fullBodyAction?.getClip())&&(this.syncFootIkWorldMatrices(),this.getCurrentWorldQuaternion(this.ikBoneRefs.left.foot,this.ikPreSolve.left.footWorld),this.getCurrentWorldQuaternion(this.ikBoneRefs.right.foot,this.ikPreSolve.right.footWorld),this.footIkAnimationPoseCaptured=!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 it){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=V.setFromMatrixPosition(e.upper.matrixWorld),n=.998*i.total,a=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(a>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-a)}const t=this.footIkUsingContacts?Math.min(this.footIkPelvisMaxOffsetDown,this.footIkMaxPlantPelvisDrop):this.footIkPelvisMaxOffsetDown;o=k.clamp(o,-t,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=k.lerp(this.ikPelvisOffsetY,o,i);const s=E.setFromMatrixPosition(this.ikPelvisBone.matrixWorld),r=H.copy(s).addScaledVector(O,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(r.applyMatrix4($.copy(this.ikPelvisBone.parent.matrixWorld).invert())),this.updatePelvisWorldTranslation(s)}updatePelvisWorldTranslation(t){const e=this.ikPelvisBone;if(null==e)return;e.updateMatrix(),null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix),e.matrixWorldNeedsUpdate=!1;const o=e.matrixWorld.elements,i=o[12]-t.x,s=o[13]-t.y,r=o[14]-t.z;if(0===i&&0===s&&0===r)return;const n=this.ikPelvisDescendantStack;n.length=0;for(let t=0;t<e.children.length;t++)n.push(e.children[t]);for(;n.length>0;){const t=n.pop(),e=t.matrixWorld.elements;e[12]+=i,e[13]+=s,e[14]+=r,t.matrixWorldNeedsUpdate=!1;for(let e=0;e<t.children.length;e++)n.push(t.children[e])}}rebuildFootIkWorldUpdateNodes(){const t=this.ikRoot,e=this.ikBoneRefs;if(null==t||null==e)return void(this.ikWorldUpdateNodes.length=0);const o=new Set,i=[this.ikPelvisBone,e.left.upper,e.left.lower,e.left.foot,e.right.upper,e.right.lower,e.right.foot,this.ikTargetBones?.left,this.ikTargetBones?.right];for(const e of i){let i=e;for(;null!=i&&(o.add(i),i!==t);)i=i.parent??void 0}this.ikWorldUpdateNodes.length=0,t.traverse(t=>{o.has(t)&&this.ikWorldUpdateNodes.push(t)})}syncFootIkWorldMatrices(){const t=this.ikRoot;if(null!=t){t.updateWorldMatrix(!0,!1);for(const e of this.ikWorldUpdateNodes)e!==t&&(e.matrixAutoUpdate&&e.updateMatrix(),e.matrixWorldAutoUpdate&&(null==e.parent?e.matrixWorld.copy(e.matrix):e.matrixWorld.multiplyMatrices(e.parent.matrixWorld,e.matrix)),e.matrixWorldNeedsUpdate=!1)}}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(E),h=H.copy(n.upLocal).applyQuaternion(this.getCurrentWorldQuaternion(o,j)).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=$.copy(t.boneInverses[i]).invert(),n=K.copy(r).multiply(s),d=V.setFromMatrixPosition(n),p=N.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;if(this.footIkUsingContacts)return t.contactRequested;const n=this.footIkPlantReleaseExtension,a=this.footIkPlantAttachExtension,l=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>l)):s>=a&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=V.setFromMatrixPosition(t.upper.matrixWorld),i=E.setFromMatrixPosition(t.foot.matrixWorld),s=o.distanceTo(i);return e.total<=1e-6?1:k.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=N.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(O),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const a=Math.sqrt(n),l=r-a,h=r+a;return l>=0?l:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,a=r.footWorldPos.setFromMatrixPosition(e.matrixWorld),l=this.computeFootVerticalSpeed(o,a,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(a).addScaledVector(O,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),y=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),I=r.desiredNormal.set(0,1,0),P=r.desiredForward.copy(c.forward);let w=0,v=0,b=this.footIkWeightOutSpeed;const x=null!=g||null!=m||null!=y;let L=a.y;null!=g?L=g.point.y:null!=m&&null!=y?L=.5*(m.point.y+y.point.y):null!=m?L=m.point.y:null!=y&&(L=y.point.y);const B=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],F=null!=B&&null!=R?this.computeLegExtensionRatio(B,R):1,A=Math.max(0,a.y-L,a.y-o.targetPosition.y),D=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,x,l,F,A);D?this.computeDesiredGroundNormal(c,g,m,y,S,I)&&(this.computeDesiredFootForward(c.forward,c.right,I,m,y,P),w=this.computeDesiredPitchAngle(m,y,c.forward),v=1,b=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,I,null,null,P);const C=1-Math.exp(-this.footIkPositionLerpSpeed*s),M=1-Math.exp(-b*s);o.normal.lerp(I,C).normalize(),o.forward.lerp(P,C).normalize(),o.pitch=k.lerp(o.pitch,w,C),o.weight=k.lerp(o.weight,v,M),o.planted=D&&v>.001,this.updateFootSample(o,a),this.applySimpleFootPitch(t,e,o),this.footIkDebug&&this.updateLegDebug(t,{footWorldPos:a,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:y,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const a=this.footIkScratch,l=this.footIkHits,h=e.foot,c=a.footWorldPos.setFromMatrixPosition(h.matrixWorld);if(this.footIkUsingContacts&&!s.contactRequested)return s.anchor.reset(),s.planted=!1,s.weight*=Math.exp(-this.footIkWeightOutSpeed*n),s.pitch*=Math.exp(-this.footIkRotationLerpSpeed*n),s.weight<=.001?s.targetPosition.copy(c):s.targetPosition.lerp(c,1-Math.exp(-this.footIkPositionLerpSpeed*n)),this.clampDesiredFootTarget(e,o,c,s.targetPosition),this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),void(null!=this.ikDebugLegs&&(this.ikDebugLegs[t].root.visible=!1));const d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=this.footIkUsingContacts&&s.anchor.locked&&s.contactRequested?s.anchor.position:c,g=a.centerRayStart.copy(f).addScaledVector(O,this.footIkRayStartHeight),m=a.toeRayStart.copy(g).addScaledVector(u.forward,this.footIkForwardSampleDistance),y=a.heelRayStart.copy(g).addScaledVector(u.forward,-this.footIkForwardSampleDistance),S=a.sideRayStart.copy(g).addScaledVector(u.right,this.footIkSideSampleDistance),I=this.getFirstGroundHit(g,l.center),P=this.getFirstGroundHit(m,l.toe),w=this.getFirstGroundHit(y,l.heel),v=this.getFirstGroundHit(S,l.side),b=a.desiredTargetPos.copy(c),x=a.desiredNormal.set(0,1,0),L=a.desiredForward.copy(u.forward);let B=0,R=0,F=this.footIkWeightOutSpeed;const A=null!=I||null!=P||null!=w;let D=c.y;null!=I?D=I.point.y:null!=P&&null!=w?D=.5*(P.point.y+w.point.y):null!=P?D=P.point.y:null!=w&&(D=w.point.y);const C=this.computeLegExtensionRatio(e,o),M=Math.max(0,c.y-D,c.y-s.targetPosition.y),T=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,A,d,C,M);if(T){if(b.copy(c),this.computeDesiredGroundNormal(u,I,P,w,v,x)){this.computeDesiredFootForward(u.forward,u.right,x,P,w,L),B=this.computeDesiredPitchAngle(P,w,u.forward);const t=Math.max(0,Math.sin(B))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);b.y=D+e+t,s.top&&!this.footIkUsingContacts&&(b.y-=this.ikPelvisOffsetY/2),R=1,F=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,x,null,null,L),b.copy(c),this.footIkUsingContacts||(b.y+=this.footIkFootOffset);if(this.footIkUsingContacts){const t=z.setFromMatrixPosition(e.upper.matrixWorld),i=this.footIkPelvisEnabled?Math.min(this.footIkMaxPlantPelvisDrop,this.footIkPelvisMaxOffsetDown):0;s.anchor.locked&&Math.abs(b.y-s.anchor.position.y)>.08&&s.anchor.release();s.anchor.update(s.contactRequested,(!this.footIkRequireGrounded||r)&&null!=I&&R>0,c,b,u.forward,t,.995*o.total,i,Math.min(this.footIkMaxPlantDrift,this.footIkMaxHorizontalOffset),k.degToRad(this.footIkMaxPlantTurnAngleDeg))?b.copy(s.anchor.position):(b.copy(c),R=0,F=this.footIkWeightOutSpeed)}const W=1-Math.exp(-this.footIkPositionLerpSpeed*n),q=1-Math.exp(-F*n);this.footIkUsingContacts&&s.anchor.locked?s.targetPosition.copy(b):s.targetPosition.lerp(b,W),this.clampDesiredFootTarget(e,o,c,s.targetPosition),s.normal.lerp(x,W).normalize(),s.forward.lerp(L,W).normalize(),s.pitch=k.lerp(s.pitch,B,W),s.weight=k.lerp(s.weight,R,q),s.planted=T&&R>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.footIkDebug&&this.updateLegDebug(t,{footWorldPos:c,centerRayStart:g,toeRayStart:m,heelRayStart:y,sideRayStart:S,centerHit:I,toeHit:P,heelHit:w,sideHit:v,desiredNormal:x,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(W,this.footIkRayLength),a=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(W,this.footIkRayLength),l=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(W,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(W,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,a),this.setDebugArrow(o.rayHeel,e.heelRayStart,l),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 p,right:new p},n=this.getCurrentWorldDirection(this.actor.object,N);n.addScaledVector(O,-n.dot(O)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(O,-s.forward.dot(O)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const a=z.crossVectors(O,n);return a.lengthSq()<1e-8?a.copy(s.right):a.normalize(),a.dot(s.right)<0&&a.multiplyScalar(-1),r.forward.copy(n),r.right.copy(a),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,N);let a=!1,l=0,h=0;if(null!=o&&null!=i){const e=E.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(l=(o.point.y-i.point.y)/e,a=!0)}if(null!=s&&null!=e){const o=H.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,a=!0)}if(a&&(r.copy(O),r.addScaledVector(t.forward,-l),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():a=!1),a)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),a=!0}return r.dot(O)<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.getCurrentWorldDirection(this.actor.object,N)),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=N.copy(this.getCurrentWorldDirection(this.actor.object,N));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=E.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=k.degToRad(this.footIkMaxSlopeAngleDeg);return k.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=j.copy(e.quaternion),a=Q.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(a))}resolveLocalPitchSign(t){const e=G.setFromAxisAngle(t.rightLocal,.15);return H.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=E.subVectors(i,o),r=s.dot(O),n=H.copy(s).addScaledVector(O,-r),a=n.length();a>this.footIkMaxHorizontalOffset&&a>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/a);const l=k.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(O,l),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(V).clone(),c=E.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=this.ikSolveScratch,s=i.hip.setFromMatrixPosition(e.upper.matrixWorld),r=i.knee.setFromMatrixPosition(e.lower.matrixWorld),n=i.foot.setFromMatrixPosition(e.foot.matrixWorld),a=s.distanceTo(r),l=r.distanceTo(n);if(a<1e-5||l<1e-5)return;const h=i.direction.subVectors(o,s),c=h.length();if(c<1e-5)return;const d=Math.abs(a-l)+1e-5,p=a+l-1e-5,u=k.clamp(c,d,p),f=h.multiplyScalar(1/c),g=i.animatedDirection.subVectors(n,s).normalize(),m=i.pole.subVectors(r,s);m.addScaledVector(g,-m.dot(g)),m.lengthSq()<a*a*1e-4&&(this.getCurrentWorldDirection(this.actor.object,m),m.addScaledVector(g,-m.dot(g)),m.lengthSq()<1e-8&&(Math.abs(g.x)<.9?m.set(1,0,0):m.set(0,1,0),m.addScaledVector(g,-m.dot(g)))),m.normalize(),i.rotation.setFromUnitVectors(g,f),m.applyQuaternion(i.rotation);const y=(u*u+a*a-l*l)/(2*u),S=Math.max(a*a-y*y,0),I=Math.sqrt(S),P=i.kneeTarget.copy(s).addScaledVector(f,y).addScaledVector(m,I),w=i.target.copy(s).addScaledVector(f,u);this.rotateBoneToward(e.upper,s,r,P),e.upper.updateMatrixWorld(!0);const v=r.setFromMatrixPosition(e.lower.matrixWorld),b=n.setFromMatrixPosition(e.foot.matrixWorld);this.rotateBoneToward(e.lower,v,b,w),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,s,P,w)}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=this.ikSolveScratch.currentDirection.subVectors(o,e),r=this.ikSolveScratch.desiredDirection.subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>1-1e-10)return;const n=this.ikSolveScratch.rotation.setFromUnitVectors(s,r),a=this.getCurrentWorldQuaternion(t,j),l=Q.copy(n).multiply(a);if(null==t.parent)return void t.quaternion.copy(l);const h=this.getCurrentWorldQuaternion(t.parent,G),c=_.copy(h).invert().multiply(l);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=this.getCurrentWorldQuaternion(t,j),o=this.getCurrentWorldDirection(this.actor.object,V);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:Y.clone(),world:Y.clone().applyQuaternion(e)},{local:J.clone(),world:J.clone().applyQuaternion(e)},{local:X.clone(),world:X.clone().applyQuaternion(e)}];i.push({local:Y.clone().multiplyScalar(-1),world:Y.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:J.clone().multiplyScalar(-1),world:J.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:X.clone().multiplyScalar(-1),world:X.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(O);e>r&&(r=e,s=t)}let n=i[0],a=-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>a&&(a=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const l=s.local.clone().normalize(),h=n.local.clone().normalize(),c=l.clone().cross(h).normalize();return{upLocal:l,forwardLocal:c.clone().cross(l).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new p,forward:new p,right:new p},r=this.getCurrentWorldQuaternion(e,j);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}getCurrentWorldQuaternion(t,e){return t.matrixWorld.decompose(z,e,N),e}getCurrentWorldDirection(t,e){const o=t.matrixWorld.elements;return e.set(o[8],o[9],o[10]).normalize()}clampSlopeNormal(t){const e=k.clamp(t.dot(O),-1,1),o=Math.acos(e),i=k.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(O,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){j.copy(t.quaternion),t.quaternion.copy(e).slerp(j,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=V.copy(o.normal).normalize(),n=E.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 a=H.crossVectors(r,n);if(a.lengthSq()<1e-8)return;a.normalize(),n.copy(N.crossVectors(a,r)).normalize(),$.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),j.setFromRotationMatrix($),K.makeBasis(a,r,n),Q.setFromRotationMatrix(K);const l=G.copy(Q).multiply(_.copy(j).invert()),h=this.getCurrentWorldQuaternion(e.parent,_),c=Q.copy(h).invert().multiply(l),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,k.clamp(d,0,1))}getMixer(){return this.mixer}evaluateExternalPose(t=0){null!=this.mixer&&(this.restoreFootIkPose(),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.captureFootIkAnimationPose(),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t))}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null,this.fullBodyTimer=0}requestSequenceAnimationRelease(){this.externalControlActive=!1,this.sequenceAnimationControlled=!1,this.currentFullBodyPriority=-1,this.sequenceAnimationReleasePending=!0,this.sequenceAnimationReleaseFrames=1,this.upperBodyOverride=!1,this.overrideFadeTimeUpper=null}cancelRootMotionAction(t){null!=t&&this.fullBodyAction!==t||(this.currentFullBodyPriority=-1,this.externalControlActive=!1,this.fullBodyAction?.stop(),this.fullBodyAction=null,this.fullBodyTimer=0)}beginExternalAnimationControl(t,e={}){at(null!=this.mixer,"Can't begin external control before setup is called"),this.assertClipRigCompatible(t),this.mixer.stopAllAction(),this.currentFullBodyPriority=99,this.fullBodyTimer=0;const o=this.mixer.clipAction(t);return this.managedActions.indexOf(o)<0&&this.managedActions.push(o),o.setLoop(c,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){null!=t&&(t.timeScale=this.getPlaybackTimeScale(t.getClip(),t.timeScale))}getPlaybackTimeScale(t,e){if(!(t instanceof s&&t.fixedInPlace&&null!=this.movementSpeed))return e;const o=this.mixer.getRoot(),i=o instanceof h?o.scale.x:1;return t.duration/t.displacement*this.movementSpeed/i}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={}){this.assertClipRigCompatible(t);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)}cancelUpper(t){this.upperBodyOverride&&this.upperBodyAction?.getClip()===this.getUpperBodyClip(t)&&(this.upperBodyOverride=!1,this.currentUpperBodyPriority=-1,null!=this.fullBodyClip?this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)):(this.upperBodyAction?.stop(),this.upperBodyAction=null),this.overrideFadeTimeUpper=null)}play(t,e={}){at(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;if(o<this.currentFullBodyPriority)return;this.currentFullBodyPriority=o,this.fullBodyTimer=0,e.sequenceControlled&&(this.sequenceAnimationControlled=!0,this.sequenceAnimationReleasePending=!1,this.sequenceAnimationReleaseFrames=0);const i=this.getFullBodyClip(t);if(this.preparePoseTransition(t,i,e)){for(const t of this.managedActions)t.stop();this.managedActions.length=0,this.fullBodyAction=null,this.upperBodyAction=null}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,i,e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime}assertClipRigCompatible(t){const e=L(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!dt.has(o)){if(dt.add(o),null==e||null==this.animationRigId)return void console.warn(`Animation clip "${t.name}" or its character has no rig assigned. Playing without rig compatibility validation for legacy compatibility.`);console.warn(`Animation clip "${t.name}" targets rig ${e??"no rig"}, but this character uses rig ${this.animationRigId??"no rig"}. Generate and assign a retargeted clip for the character rig.`)}}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={}){const s=o?.fadeTime??this.fadeTime;if(null!=t&&t.getClip().uuid===e.uuid)return t.isRunning()||!1!==o.loop||!t.clampWhenFinished||o.sequenceControlled?(t.isRunning()||(t.reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play(),!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0)),t):t;if(i(t)){const i=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,i.crossFadeTo(r,s,!1),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play();return!1===o.loop&&(t.setLoop(c,1),t.clampWhenFinished=!0),this.managedActions.indexOf(t)<0&&this.managedActions.push(t),t}};st=t([o({inEditor:!0})],st);export{st as CharacterAnimationComponent};function rt(t,e){if(null==t)return e;const o=e.clone();A(o,L(e)),T(o,C(e));const i=new Set(t.map(t=>t.name));return o.tracks=o.tracks.filter(t=>i.has(t.name.split(".")[0])),o}function nt(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof l)}function at(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function lt(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 ht(t){let e;return t.traverse(t=>{(t instanceof l||t.isBone)&&null==e&&(e=t)}),e}function ct(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const dt=new Set;/*
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{setWebGpuPipelineLoading as e}from"../rendering/webgpu-runtime-bridge.js";import t from"typedi";import{BehaviorSubject as i,Subject as n}from"rxjs";import{loadScene as s}from"../scene/bootstrap.js";import{ActorFactory as r}from"./actors/factory.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{SceneDataService as a}from"../scene/scene-data-service.js";import{World as c}from"./services/world.js";import{ViewController as l}from"./services/render.js";import{RenderingView as p,GraphicsRuntime as h}from"../rendering.js";import{PhysicsSystem as d}from"./services/physics/physics-system.js";import{MeshComponent as m}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as u}from"./actors/builtin/components/index.js";import{InputService as g}from"./input/index.js";import{RuntimeAssetsService as w}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as f}from"../scene/asset-resource-loader.js";import{AssetLoader as y}from"./services/asset-loader.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{AssetsProvider as S}from"../scene/assets-provider.js";import{ShaderProvider as b}from"./services/shader-provider.js";import{PointerEvents as j}from"./services/pointer-events.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";import{NetMode as A}from"./net/net-session.js";import{GameStateContext as V}from"./game-state-context.js";import{PlayerSessions as P}from"./player-sessions.js";import{polyfillClient as N}from"./polyfill.js";import{withInjectionContext as C}from"./inject.js";import{RenderingHost as R}from"./rendering-host.js";import{SceneTransitionService as z}from"./services/scene-transition.js";import{SceneRef as G}from"../scene/scene-ref.js";import{ActorPersistence as H}from"./services/actor-persistence.js";let x=0;export function initiateApplication(e,i){const n="function"==typeof e?e:void 0,s=i??e;var r;N(),"element"in s&&null!=s.element&&(r=s.element,Object.assign(r.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"}));const o=s.renderingHost??(null!=s.renderingView?new R(s.renderingView,!1,("renderingViewFactory"in s?s.renderingViewFactory:void 0)??(()=>new p(s.renderingView.container,s.renderingView.options))):function(e,t,i){const n=new h,s=()=>function(e,t,i,n){return new p(e,{graphicsRuntime:n,backend:t?.backend??"webgpu",enableXR:!0===i?.enabled,maxPixelRatio:t?.maxPixelRatio,resolutionScale:t?.resolutionScale,dynamicResolution:t?.dynamicResolution,upscaling:t?.upscaling,webgpuPostProcessing:t?.webgpuPostProcessing,webgpuDirectionalShadows:t?.webgpuDirectionalShadows,webgpuVfx:t?.webgpuVfx??"auto",msaa:t?.msaa,fpsCap:t?.fpsCap,depthPrepass:{enabled:!0===t?.depthPrepass?.enabled},bloom:{enabled:!1!==t?.bloom?.enabled},reflection:{enabled:!1!==t?.reflection?.enabled},occlusionCulling:{enabled:!1!==t?.occlusionCulling?.enabled},shadows:{enabled:t?.shadows?.enabled??!0,autoUpdate:t?.shadows?.autoUpdate??!0,cascadeUpdateIntervals:[22,40,60,120]}})}(e,t,i,n);return new R(s(),!0,s)}(s.element,s.rendering,s.xr)),a=t.of("hology-application-"+ ++x),c=new HologyApplicationRuntime(s,a,o,n??s.defaultGameClass);return c.startInitialization(),c}export function initiateGame(e,t){const{sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o,...a}=t,c=initiateApplication(e,a),l=c.ready.then(()=>c.loadGame({sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o}));return new HologyRuntime(c,l)}export class GameInstance{onPreload(){}onStart(){}onUnload(){return this.onShutdown()}onShutdown(){}}export class HologyApplicationRuntime{constructor(e,t,s,r){this.config=e,this.applicationContainer=t,this.renderingHost=s,this.defaultGameClass=r,this.stateSubject=new i({type:"initializing"}),this.state=this.stateSubject.asObservable(),this.shutdownSubject=new n,this.shutdownStarted=this.shutdownSubject.asObservable(),this.transitionTail=Promise.resolve(),this.initializationPromise=Promise.resolve(),this.transitionIntent=0,this.shutdownFlag=!1,this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t})}get renderingView(){return this.renderingHost.activeView}get currentState(){return this.stateSubject.value}startInitialization(){this.initializationPromise=this.initialize()}async initialize(){try{if(this.registerApplicationServices(),await this.renderingHost.applicationView.compileAsync(),this.shutdownFlag)return void this.rejectReady(k());const e=this.getApplicationService(g);this.renderingHost.start(t=>e.update(t),t=>e.sampleGamepadButtons(t)),this.setState({type:"menu"}),this.resolveReady()}catch(e){this.setState({type:"error",operation:"initialize",error:e}),this.rejectReady(e)}}loadGame(e,t){const i="function"==typeof e?e:this.defaultGameClass,n=t??e;if(null==i)return Promise.reject(new Error("loadGame() requires a game class because no default was configured"));const s=++this.transitionIntent;return this.enqueue(async()=>(await this.ready,this.assertRunning(),this.checkIntent(s),null!=this.session&&await this.disposeSession(this.session,!0),this.checkIntent(s),this.performLoad(i,n,s)))}unloadGame(){const e=++this.transitionIntent;return this.enqueue(async()=>{if(await this.ready,!this.shutdownFlag&&e===this.transitionIntent){try{null!=this.session&&await this.disposeSession(this.session,!0)}catch(t){throw this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"error",operation:"unload",error:t}),t}this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"menu"})}})}transitionScene(e){const t="string"==typeof e?{scene:new G(e,e)}:e instanceof G?{scene:e}:e,i=this.transitionIntent;return this.enqueue(async()=>{await this.ready,this.assertRunning(),this.checkIntent(i);const e=this.session;if(null==e)throw new Error("transitionScene() requires an active game session");try{return await this.performSceneTransition(e,t,i),e}catch(e){throw F(e)||this.shutdownFlag||i!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}})}async shutdown(){this.shutdownFlag||(this.shutdownFlag=!0,++this.transitionIntent,this.shutdownSubject.next(),this.shutdownSubject.complete(),await this.initializationPromise.catch(()=>{}),await this.transitionTail.catch(()=>{}),null!=this.session&&await this.disposeSession(this.session,!1),this.getApplicationService(g).stop(),this.getOptionalApplicationService(j)?.stop(),this.getApplicationService(f).disposeAll(),this.getApplicationService(w).dispose(),this.getApplicationService(l).dispose(!1),this.renderingHost.shutdown(),t.reset(this.applicationContainer.id),this.setState({type:"stopped"}),this.stateSubject.complete())}getWorld(){return this.session?.world}getGameInstance(){return this.session?.gameInstance}getApplicationService(e){return this.applicationContainer.get(e)}getSessionService(e){return this.session?.container.get(e)}getService(e){return null!=this.session?this.session.container.get(e):this.applicationContainer.get(e)}registerRenderStage(e){return this.renderingHost.registerStage(e)}registerApplicationServices(){const e=new l(this.renderingView);this.applicationContainer.set(p,this.renderingHost.applicationView),this.applicationContainer.set(l,e);const t=new v(this.config.runtimeDataUrl),i=new w(t),n=new f;n.setDataDir(this.config.dataDir),n.setDirectFileLoading(!0===this.config.directAssetFileLoading),"webgpu"===this.renderingHost.applicationView.requestedBackend?n.initKtx2ForWebGpu():n.initKtx2(this.renderingHost.applicationView.renderer);const s=Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t}));this.applicationContainer.set(v,t),this.applicationContainer.set(S,i),this.applicationContainer.set(w,i),this.applicationContainer.set(f,n),this.applicationContainer.set(y,new y(n,i,s)),this.applicationContainer.set(b,new b(s));const r=C(this.applicationContainer,e=>e.get(g));this.applicationContainer.set(g,r)}async performLoad(i,n,r){if(null!=n.persistence&&null!=n.multi?.session&&n.multi.session.mode!==A.none)throw new Error("Actor persistence currently supports single-player sessions only");const a=this.createSession(n);this.session=a;try{this.loading(n.sceneName,"physics",.08),await Promise.all([a.physics.start(),a.renderingView.initializeBackend()]),await e(a.renderingView.webGpuDevice,!0,"loading: "+n.sceneName),this.checkIntent(r),this.loading(n.sceneName,"runtime-data",.2),await this.getApplicationService(v).preloadData(),this.checkIntent(r),this.loading(n.sceneName,"scene",.42);const c=await s(a.renderingView,n.sceneName,this.config.dataDir,this.config.shaders,this.config.actors,a.components,a.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:n.detailTier,nodeMode:n.multi?.session.mode??A.none,persistence:a.world.persistence});if(a.materializer.dispose(),a.materializer=c.materializer,a.sceneRoots=c.sceneRoots,a.container.set(o,c.materializer),a.world.materializer=c.materializer,a.world.scene=c.scene,a.physics.scene=c.scene,this.checkIntent(r),null!=n.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=C(a.container,t=>t.get(e));t.session=n.multi.session,t.start(),a.stopPlayers=()=>t.stop()}if(t.import([m]),await this.restoreSceneActors(a,c.materializer,c.actors,r),a.physics.addFromScene(c.scene),await a.world.startSceneEventGraphs(c.materializer),this.checkIntent(r),a.gameInstance=C(a.container,e=>(e.set({id:i,type:i}),e.get(i))),this.loading(n.sceneName,"game-preload",.58),a.gameInstance instanceof GameInstance&&await a.gameInstance.onPreload(),this.checkIntent(r),this.loading(n.sceneName,"shaders",.7),await a.renderingView.compileAsync(),this.checkIntent(r),this.loading(n.sceneName,"textures",.82),await a.renderingView.initTexturesAsync(),this.checkIntent(r),"webgpu"===a.renderingView.activeBackend){this.loading(n.sceneName,"vfx-warmup",.94);const e=C(a.container,e=>e.get(I).beginPipelineWarmup());try{const e=performance.now();console.info("[Hology GPU VFX warmup] Rendering loading frame",n.sceneName),a.renderingView.render(0),console.info("[Hology GPU VFX warmup] Render returned; waiting for GPU queue",{sceneName:n.sceneName,renderMs:performance.now()-e}),await(a.renderingView.webGpuDevice?.queue.onSubmittedWorkDone()),console.info("[Hology GPU VFX warmup] GPU queue completed",{sceneName:n.sceneName,totalMs:performance.now()-e})}finally{e()}}return this.checkIntent(r),await e(a.renderingView.webGpuDevice,!1,"playing: "+n.sceneName),a.gameInstance instanceof GameInstance&&await a.gameInstance.onStart(),this.checkIntent(r),a.viewController.paused=!1,this.renderingHost.activate(a.renderingView),this.setState({type:"playing",sceneName:n.sceneName}),a}catch(e){throw await this.disposeSession(a,!1),F(e)||this.shutdownFlag||r!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}}createSession(e){const i=t.of("hology-session-"+ ++x);this.copyApplicationServices(i);const n=this.renderingHost.createView(),s=new l(n);s.paused=!0,i.set(p,n),i.set(l,s);const h={...u,...this.config.components??{}},m=new H;null!=e.persistence&&m.configure(e.persistence),i.set(H,m);const g=new r(i,{inEditor:!1});g.classes=this.config.actors,i.set(r,g);const y=new o(n.scene,new a,this.getApplicationService(w),this.getApplicationService(f),n,Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t})),Object.entries(this.config.actors).map(([e,t])=>({name:e,type:t})),g,Object.entries(h).map(([e,t])=>({name:e,type:t})));y.inEditor=!1,y.netMode=e.multi?.session.mode??A.none,i.set(o,y);const v=C(i,e=>e.get(c));m.enabled&&(v.persistence=m),v.scene=n.scene,i.set(c,v);const S=C(i,e=>e.get(d));i.set(d,S);const b=new z;b.bind(async e=>{await this.transitionScene(e)}),i.set(z,b);const j=C(i,e=>e.get(P));i.set(P,j);const I=C(i,e=>e.get(V));return i.set(V,I),null==e.multi?.session&&j.startStandalone(e.localPlayer??{id:"local-player",displayName:"Player"}),{sceneName:e.sceneName,detailTier:e.detailTier,container:i,renderingView:n,viewController:s,actorFactory:g,materializer:y,world:v,physics:S,components:h,sceneTransition:b,sceneRoots:[],netMode:e.multi?.session.mode??A.none,stopPlayers:null==e.multi?.session?()=>{j.stop(),I.stop()}:void 0}}async performSceneTransition(t,i,n){if(t.netMode!==A.none)throw new Error("In-session scene transitions are not yet supported for network sessions");const r=i.scene.id.trim();if(0===r.length)throw new Error("A destination scene id is required");await e(t.renderingView.webGpuDevice,!0,"transition: "+r);const a=t.sceneName,c=t.viewController.paused;t.viewController.paused=!0,this.renderingHost.activate(this.renderingHost.applicationView),t.world.persistence?.captureAll(),this.setState({type:"unloading",sceneName:a}),t.world.stopSceneEventGraphs();const l=t.world.removeSceneLifetimeActors(t.sceneRoots);for(const e of t.sceneRoots)t.physics.removeRemoved(e),e.removeFromParent();t.sceneRoots=[],t.materializer.dispose(l),this.checkIntent(n),this.loading(r,"scene",.42);const p=await s(t.renderingView,r,this.config.dataDir,this.config.shaders,this.config.actors,t.components,t.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:t.detailTier,nodeMode:t.netMode,persistence:t.world.persistence});this.checkIntent(n),t.materializer=p.materializer,t.sceneRoots=p.sceneRoots,t.sceneName=r,t.container.set(o,p.materializer),t.world.materializer=p.materializer,await this.restoreSceneActors(t,p.materializer,p.actors,n),t.physics.addFromScene(p.scene),await t.world.startSceneEventGraphs(p.materializer),await(i.afterLoad?.(t.world)),this.checkIntent(n),this.loading(r,"shaders",.7),await t.renderingView.compileAsync(),this.checkIntent(n),this.loading(r,"textures",.82),await t.renderingView.initTexturesAsync(),this.checkIntent(n),await e(t.renderingView.webGpuDevice,!1,"playing: "+r),t.sceneTransition.publish({previousSceneName:a,sceneName:r}),t.viewController.paused=c,this.renderingHost.activate(t.renderingView),this.setState({type:"playing",sceneName:r})}async restoreSceneActors(e,t,i,n){if(null==e.world.persistence){for(const t of i)e.world.addActor(t);return}const s=i.filter(t=>!e.world.actors.includes(t));for(const t of s)e.world.addActor(t,void 0,void 0,void 0,!0);const r=t.registerPersistentActors();await e.world.persistence.restore(r,()=>this.checkIntent(n)),this.checkIntent(n);for(const t of s)e.world.beginActorPlay(t)}copyApplicationServices(e){const t=[g,S,w,v,f,y,b];for(const i of t)e.set(i,this.applicationContainer.get(i))}async disposeSession(e,i){if(e.disposed)return;let n;e.disposed=!0,i&&this.setState({type:"unloading",sceneName:e.sceneName});try{e.viewController.paused=!0,e.world.persistence?.captureAll(),e.stopPlayers?.(),e.sceneTransition.dispose(),e.world.stopSceneEventGraphs(),e.gameInstance instanceof GameInstance&&await e.gameInstance.onUnload()}catch(e){n=e}finally{for(const t of[...e.world.actors])e.world.removeActor(t);e.physics.stop(),e.materializer.dispose(),this.renderingHost.activeView===e.renderingView&&this.renderingHost.activate(this.renderingHost.applicationView),e.viewController.dispose(!1),this.renderingHost.releaseView(e.renderingView),t.reset(e.container.id),this.session===e&&(this.session=void 0)}if(null!=n)throw n}enqueue(e){const t=this.transitionTail.then(e,e);return this.transitionTail=t.catch(()=>{}),t}checkIntent(e){if(this.assertRunning(),e!==this.transitionIntent)throw k()}assertRunning(){if(this.shutdownFlag)throw new Error("Hology application has been shut down")}loading(e,t,i){this.setState({type:"loading",sceneName:e,stage:t,progress:i})}setState(e){const t=this.renderingHost.applicationView;"loading"===e.type?t.stopAnimationLoop():"menu"!==e.type&&("error"!==e.type||"initialize"===e.operation)||this.renderingHost.activeView!==t||t.running||this.renderingHost.activate(t),this.stateSubject.next(e)}getOptionalApplicationService(e){return this.applicationContainer.has(e)?this.applicationContainer.get(e):void 0}}export class HologyRuntime{constructor(e,t){this.application=e,this.ready=t.then(()=>!0),this.shutdownStarted=e.shutdownStarted}get status(){return"playing"===this.application.currentState.type?5:"stopped"===this.application.currentState.type||"error"===this.application.currentState.type?10:0}get gameInstance(){return this.application.getGameInstance()}get isShutdown(){return"stopped"===this.application.currentState.type}getWorld(){return this.application.getWorld()}getService(e){return this.application.getService(e)}shutdown(){return this.application.shutdown()}}function k(){return new DOMException("Superseded by a newer game transition","AbortError")}function F(e){return e instanceof DOMException&&"AbortError"===e.name}/*
1
+ import{setWebGpuPipelineLoading as e}from"../rendering/webgpu-runtime-bridge.js";import t from"typedi";import{BehaviorSubject as i,Subject as n}from"rxjs";import{loadScene as s}from"../scene/bootstrap.js";import{ActorFactory as r}from"./actors/factory.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{SceneDataService as a}from"../scene/scene-data-service.js";import{World as c}from"./services/world.js";import{ViewController as l}from"./services/render.js";import{RenderingView as p,GraphicsRuntime as h}from"../rendering.js";import{PhysicsSystem as d}from"./services/physics/physics-system.js";import{MeshComponent as m}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as u}from"./actors/builtin/components/index.js";import{InputService as g}from"./input/index.js";import{RuntimeAssetsService as w}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as f}from"../scene/asset-resource-loader.js";import{AssetLoader as y}from"./services/asset-loader.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{AssetsProvider as S}from"../scene/assets-provider.js";import{ShaderProvider as b}from"./services/shader-provider.js";import{PointerEvents as j}from"./services/pointer-events.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";import{NetMode as A}from"./net/net-session.js";import{GameStateContext as V}from"./game-state-context.js";import{PlayerSessions as P}from"./player-sessions.js";import{polyfillClient as N}from"./polyfill.js";import{withInjectionContext as C}from"./inject.js";import{RenderingHost as G}from"./rendering-host.js";import{SceneTransitionService as H}from"./services/scene-transition.js";import{SceneRef as R}from"../scene/scene-ref.js";import{ActorPersistence as z}from"./services/actor-persistence.js";let x=0;export function initiateApplication(e,i){const n="function"==typeof e?e:void 0,s=i??e;var r;N(),"element"in s&&null!=s.element&&(r=s.element,Object.assign(r.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"}));const o=s.renderingHost??(null!=s.renderingView?new G(s.renderingView,!1,("renderingViewFactory"in s?s.renderingViewFactory:void 0)??(()=>new p(s.renderingView.container,s.renderingView.options))):function(e,t,i){const n=new h,s=()=>function(e,t,i,n){return new p(e,{graphicsRuntime:n,backend:t?.backend??"webgpu",enableXR:!0===i?.enabled,maxPixelRatio:t?.maxPixelRatio,resolutionScale:t?.resolutionScale,dynamicResolution:t?.dynamicResolution,upscaling:t?.upscaling,webgpuPostProcessing:t?.webgpuPostProcessing,webgpuDirectionalShadows:t?.webgpuDirectionalShadows,webgpuVfx:t?.webgpuVfx??"auto",msaa:t?.msaa,fpsCap:t?.fpsCap,depthPrepass:{enabled:!0===t?.depthPrepass?.enabled},bloom:{enabled:!1!==t?.bloom?.enabled},reflection:{enabled:!1!==t?.reflection?.enabled},occlusionCulling:{enabled:!1!==t?.occlusionCulling?.enabled},shadows:{enabled:t?.shadows?.enabled??!0,autoUpdate:t?.shadows?.autoUpdate??!0,cascadeUpdateIntervals:[22,40,60,120]}})}(e,t,i,n);return new G(s(),!0,s)}(s.element,s.rendering,s.xr)),a=t.of("hology-application-"+ ++x),c=new HologyApplicationRuntime(s,a,o,n??s.defaultGameClass);return c.startInitialization(),c}export function initiateGame(e,t){const{sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o,...a}=t,c=initiateApplication(e,a),l=c.ready.then(()=>c.loadGame({sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o}));return new HologyRuntime(c,l)}export class GameInstance{onPreload(){}onStart(){}onUnload(){return this.onShutdown()}onShutdown(){}}export class HologyApplicationRuntime{constructor(e,t,s,r){this.config=e,this.applicationContainer=t,this.renderingHost=s,this.defaultGameClass=r,this.stateSubject=new i({type:"initializing"}),this.state=this.stateSubject.asObservable(),this.shutdownSubject=new n,this.shutdownStarted=this.shutdownSubject.asObservable(),this.transitionTail=Promise.resolve(),this.initializationPromise=Promise.resolve(),this.transitionIntent=0,this.shutdownFlag=!1,this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t})}get renderingView(){return this.renderingHost.activeView}get currentState(){return this.stateSubject.value}startInitialization(){this.initializationPromise=this.initialize()}async initialize(){try{if(this.registerApplicationServices(),await this.renderingHost.applicationView.compileAsync(),this.shutdownFlag)return void this.rejectReady(k());const e=this.getApplicationService(g);this.renderingHost.start(t=>e.update(t),t=>e.sampleGamepadButtons(t)),this.setState({type:"menu"}),this.resolveReady()}catch(e){this.setState({type:"error",operation:"initialize",error:e}),this.rejectReady(e)}}loadGame(e,t){const i="function"==typeof e?e:this.defaultGameClass,n=t??e;if(null==i)return Promise.reject(new Error("loadGame() requires a game class because no default was configured"));const s=++this.transitionIntent;return this.enqueue(async()=>(await this.ready,this.assertRunning(),this.checkIntent(s),null!=this.session&&await this.disposeSession(this.session,!0),this.checkIntent(s),this.performLoad(i,n,s)))}unloadGame(){const e=++this.transitionIntent;return this.enqueue(async()=>{if(await this.ready,!this.shutdownFlag&&e===this.transitionIntent){try{null!=this.session&&await this.disposeSession(this.session,!0)}catch(t){throw this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"error",operation:"unload",error:t}),t}this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"menu"})}})}transitionScene(e){const t="string"==typeof e?{scene:new R(e,e)}:e instanceof R?{scene:e}:e,i=this.transitionIntent;return this.enqueue(async()=>{await this.ready,this.assertRunning(),this.checkIntent(i);const e=this.session;if(null==e)throw new Error("transitionScene() requires an active game session");try{return await this.performSceneTransition(e,t,i),e}catch(e){throw F(e)||this.shutdownFlag||i!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}})}async shutdown(){this.shutdownFlag||(this.shutdownFlag=!0,++this.transitionIntent,this.shutdownSubject.next(),this.shutdownSubject.complete(),await this.initializationPromise.catch(()=>{}),await this.transitionTail.catch(()=>{}),null!=this.session&&await this.disposeSession(this.session,!1),this.getApplicationService(g).stop(),this.getOptionalApplicationService(j)?.stop(),this.getApplicationService(f).disposeAll(),this.getApplicationService(w).dispose(),this.getApplicationService(l).dispose(!1),this.renderingHost.shutdown(),t.reset(this.applicationContainer.id),this.setState({type:"stopped"}),this.stateSubject.complete())}getWorld(){return this.session?.world}getGameInstance(){return this.session?.gameInstance}getApplicationService(e){return this.applicationContainer.get(e)}getSessionService(e){return this.session?.container.get(e)}getService(e){return null!=this.session?this.session.container.get(e):this.applicationContainer.get(e)}registerRenderStage(e){return this.renderingHost.registerStage(e)}registerApplicationServices(){const e=new l(this.renderingView);this.applicationContainer.set(p,this.renderingHost.applicationView),this.applicationContainer.set(l,e);const t=new v(this.config.runtimeDataUrl),i=new w(t),n=new f;n.setDataDir(this.config.dataDir),n.setDirectFileLoading(!0===this.config.directAssetFileLoading),"webgpu"===this.renderingHost.applicationView.requestedBackend?n.initKtx2ForWebGpu(this.renderingHost.applicationView.webGpuDevice??void 0):n.initKtx2(this.renderingHost.applicationView.renderer);const s=Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t}));this.applicationContainer.set(v,t),this.applicationContainer.set(S,i),this.applicationContainer.set(w,i),this.applicationContainer.set(f,n),this.applicationContainer.set(y,new y(n,i,s)),this.applicationContainer.set(b,new b(s));const r=C(this.applicationContainer,e=>e.get(g));this.applicationContainer.set(g,r)}async performLoad(i,n,r){if(null!=n.persistence&&null!=n.multi?.session&&n.multi.session.mode!==A.none)throw new Error("Actor persistence currently supports single-player sessions only");const a=this.createSession(n);this.session=a;try{this.loading(n.sceneName,"physics",.08),await Promise.all([a.physics.start(),a.renderingView.initializeBackend()]),await e(a.renderingView.webGpuDevice,!0,"loading: "+n.sceneName),this.checkIntent(r),this.loading(n.sceneName,"runtime-data",.2),await this.getApplicationService(v).preloadData(),this.checkIntent(r),this.loading(n.sceneName,"scene",.42);const c=await s(a.renderingView,n.sceneName,this.config.dataDir,this.config.shaders,this.config.actors,a.components,a.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:n.detailTier,nodeMode:n.multi?.session.mode??A.none,persistence:a.world.persistence});if(a.materializer.dispose(),a.materializer=c.materializer,a.sceneRoots=c.sceneRoots,a.container.set(o,c.materializer),a.world.materializer=c.materializer,a.world.scene=c.scene,a.physics.scene=c.scene,this.checkIntent(r),null!=n.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=C(a.container,t=>t.get(e));t.session=n.multi.session,t.start(),a.stopPlayers=()=>t.stop()}if(t.import([m]),await this.restoreSceneActors(a,c.materializer,c.actors,r),a.physics.addFromScene(c.scene),await a.world.startSceneEventGraphs(c.materializer),this.checkIntent(r),a.gameInstance=C(a.container,e=>(e.set({id:i,type:i}),e.get(i))),this.loading(n.sceneName,"game-preload",.58),a.gameInstance instanceof GameInstance&&await a.gameInstance.onPreload(),this.checkIntent(r),this.loading(n.sceneName,"shaders",.7),await a.renderingView.compileAsync(),this.checkIntent(r),this.loading(n.sceneName,"textures",.82),await a.renderingView.initTexturesAsync(),this.checkIntent(r),"webgpu"===a.renderingView.activeBackend){this.loading(n.sceneName,"vfx-warmup",.94);const e=C(a.container,e=>e.get(I).beginPipelineWarmup());try{const e=performance.now();console.info("[Hology GPU VFX warmup] Rendering loading frame",n.sceneName),a.renderingView.render(0),console.info("[Hology GPU VFX warmup] Render returned; waiting for GPU queue",{sceneName:n.sceneName,renderMs:performance.now()-e}),await(a.renderingView.webGpuDevice?.queue.onSubmittedWorkDone()),console.info("[Hology GPU VFX warmup] GPU queue completed",{sceneName:n.sceneName,totalMs:performance.now()-e})}finally{e()}}return this.checkIntent(r),await e(a.renderingView.webGpuDevice,!1,"playing: "+n.sceneName),a.gameInstance instanceof GameInstance&&await a.gameInstance.onStart(),this.checkIntent(r),a.viewController.paused=!1,this.renderingHost.activate(a.renderingView),this.setState({type:"playing",sceneName:n.sceneName}),a}catch(e){throw await this.disposeSession(a,!1),F(e)||this.shutdownFlag||r!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}}createSession(e){const i=t.of("hology-session-"+ ++x);this.copyApplicationServices(i);const n=this.renderingHost.createView(),s=new l(n);s.paused=!0,i.set(p,n),i.set(l,s);const h={...u,...this.config.components??{}},m=new z;null!=e.persistence&&m.configure(e.persistence),i.set(z,m);const g=new r(i,{inEditor:!1});g.classes=this.config.actors,i.set(r,g);const y=new o(n.scene,new a,this.getApplicationService(w),this.getApplicationService(f),n,Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t})),Object.entries(this.config.actors).map(([e,t])=>({name:e,type:t})),g,Object.entries(h).map(([e,t])=>({name:e,type:t})));y.inEditor=!1,y.netMode=e.multi?.session.mode??A.none,i.set(o,y);const v=C(i,e=>e.get(c));m.enabled&&(v.persistence=m),v.scene=n.scene,i.set(c,v);const S=C(i,e=>e.get(d));i.set(d,S);const b=new H;b.bind(async e=>{await this.transitionScene(e)}),i.set(H,b);const j=C(i,e=>e.get(P));i.set(P,j);const I=C(i,e=>e.get(V));return i.set(V,I),null==e.multi?.session&&j.startStandalone(e.localPlayer??{id:"local-player",displayName:"Player"}),{sceneName:e.sceneName,detailTier:e.detailTier,container:i,renderingView:n,viewController:s,actorFactory:g,materializer:y,world:v,physics:S,components:h,sceneTransition:b,sceneRoots:[],netMode:e.multi?.session.mode??A.none,stopPlayers:null==e.multi?.session?()=>{j.stop(),I.stop()}:void 0}}async performSceneTransition(t,i,n){if(t.netMode!==A.none)throw new Error("In-session scene transitions are not yet supported for network sessions");const r=i.scene.id.trim();if(0===r.length)throw new Error("A destination scene id is required");await e(t.renderingView.webGpuDevice,!0,"transition: "+r);const a=t.sceneName,c=t.viewController.paused;t.viewController.paused=!0,this.renderingHost.activate(this.renderingHost.applicationView),t.world.persistence?.captureAll(),this.setState({type:"unloading",sceneName:a}),t.world.stopSceneEventGraphs();const l=t.world.removeSceneLifetimeActors(t.sceneRoots);for(const e of t.sceneRoots)t.physics.removeRemoved(e),e.removeFromParent();t.sceneRoots=[],t.materializer.dispose(l),this.checkIntent(n),this.loading(r,"scene",.42);const p=await s(t.renderingView,r,this.config.dataDir,this.config.shaders,this.config.actors,t.components,t.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:t.detailTier,nodeMode:t.netMode,persistence:t.world.persistence});this.checkIntent(n),t.materializer=p.materializer,t.sceneRoots=p.sceneRoots,t.sceneName=r,t.container.set(o,p.materializer),t.world.materializer=p.materializer,await this.restoreSceneActors(t,p.materializer,p.actors,n),t.physics.addFromScene(p.scene),await t.world.startSceneEventGraphs(p.materializer),await(i.afterLoad?.(t.world)),this.checkIntent(n),this.loading(r,"shaders",.7),await t.renderingView.compileAsync(),this.checkIntent(n),this.loading(r,"textures",.82),await t.renderingView.initTexturesAsync(),this.checkIntent(n),await e(t.renderingView.webGpuDevice,!1,"playing: "+r),t.sceneTransition.publish({previousSceneName:a,sceneName:r}),t.viewController.paused=c,this.renderingHost.activate(t.renderingView),this.setState({type:"playing",sceneName:r})}async restoreSceneActors(e,t,i,n){if(null==e.world.persistence){for(const t of i)e.world.addActor(t);return}const s=i.filter(t=>!e.world.actors.includes(t));for(const t of s)e.world.addActor(t,void 0,void 0,void 0,!0);const r=t.registerPersistentActors();await e.world.persistence.restore(r,()=>this.checkIntent(n)),this.checkIntent(n);for(const t of s)e.world.beginActorPlay(t)}copyApplicationServices(e){const t=[g,S,w,v,f,y,b];for(const i of t)e.set(i,this.applicationContainer.get(i))}async disposeSession(e,i){if(e.disposed)return;let n;e.disposed=!0,i&&this.setState({type:"unloading",sceneName:e.sceneName});try{e.viewController.paused=!0,e.world.persistence?.captureAll(),e.stopPlayers?.(),e.sceneTransition.dispose(),e.world.stopSceneEventGraphs(),e.gameInstance instanceof GameInstance&&await e.gameInstance.onUnload()}catch(e){n=e}finally{for(const t of[...e.world.actors])e.world.removeActor(t);e.physics.stop(),e.materializer.dispose(),this.renderingHost.activeView===e.renderingView&&this.renderingHost.activate(this.renderingHost.applicationView),e.viewController.dispose(!1),this.renderingHost.releaseView(e.renderingView),t.reset(e.container.id),this.session===e&&(this.session=void 0)}if(null!=n)throw n}enqueue(e){const t=this.transitionTail.then(e,e);return this.transitionTail=t.catch(()=>{}),t}checkIntent(e){if(this.assertRunning(),e!==this.transitionIntent)throw k()}assertRunning(){if(this.shutdownFlag)throw new Error("Hology application has been shut down")}loading(e,t,i){this.setState({type:"loading",sceneName:e,stage:t,progress:i})}setState(e){const t=this.renderingHost.applicationView;"loading"===e.type?t.stopAnimationLoop():"menu"!==e.type&&("error"!==e.type||"initialize"===e.operation)||this.renderingHost.activeView!==t||t.running||this.renderingHost.activate(t),this.stateSubject.next(e)}getOptionalApplicationService(e){return this.applicationContainer.has(e)?this.applicationContainer.get(e):void 0}}export class HologyRuntime{constructor(e,t){this.application=e,this.ready=t.then(()=>!0),this.shutdownStarted=e.shutdownStarted}get status(){return"playing"===this.application.currentState.type?5:"stopped"===this.application.currentState.type||"error"===this.application.currentState.type?10:0}get gameInstance(){return this.application.getGameInstance()}get isShutdown(){return"stopped"===this.application.currentState.type}getWorld(){return this.application.getWorld()}getService(e){return this.application.getService(e)}shutdown(){return this.application.shutdown()}}function k(){return new DOMException("Superseded by a newer game transition","AbortError")}function F(e){return e instanceof DOMException&&"AbortError"===e.name}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -19,6 +19,9 @@ export declare class AssetResourceLoader {
19
19
  private hdrLoader;
20
20
  private ktx2Loader;
21
21
  private ktx2Ready;
22
+ private nativeTextureLoader;
23
+ private nativeBcSupported;
24
+ private nativeAstcSupported;
22
25
  private _textureLoader;
23
26
  private audioLoader;
24
27
  private initialisedKtx2;
@@ -41,7 +44,7 @@ export declare class AssetResourceLoader {
41
44
  decodeImageBitmap(url: string): Promise<ImageBitmap> | undefined;
42
45
  private configureKtx2;
43
46
  initKtx2(renderer: THREE.WebGLRenderer): void;
44
- initKtx2ForWebGpu(): void;
47
+ initKtx2ForWebGpu(device?: GPUDevice): void;
45
48
  setDataDir(path: string): void;
46
49
  private getUri;
47
50
  private _texturePromises;
@@ -61,6 +64,7 @@ export declare class AssetResourceLoader {
61
64
  texture: Texture | null;
62
65
  layerIndex: number | null;
63
66
  }>;
67
+ private loadKtx2Texture;
64
68
  private loadTextureArray;
65
69
  private applyTextureArraySettings;
66
70
  private _getTextureLoader;
@@ -1,4 +1,4 @@
1
- import{createAuthoredCollisionShapes as e}from"./collision/authored-colliders.js";import{parseAnimationClips as t}from"./animation-binary.js";import{AudioLoader as r,BufferGeometry as a,Group as i,LoadingManager as s,Mesh as n,Object3D as o,Texture as l,TextureLoader as c,Vector3 as h}from"three";import{MTLLoader as u,OBJLoader as m,LUTCubeLoader as d}from"three-stdlib";import{cloneMesh as p,mergeCompatibleSkinnedMeshes as f}from"../utils/mesh.js";import{pathJoin as g}from"../utils/files.js";import{Subject as y,firstValueFrom as w}from"rxjs";import{importCollisionShapes as x,isCollisionMesh as M}from"./collision/collision-shape-import.js";import*as b from"three";import{iterateMaterials as A}from"../utils/materials.js";import{applyMaterial as L,getConvertedFbxToGlbAssignedMaterialTextureFlipY as S}from"./materializer.js";import{BufferGeometryUtils as _,DRACOLoader as v,EXRLoader as T,FBXLoader as R,GLTFLoader as C,KTX2Loader as B,TGALoader as F,UltraHDRLoader as P}from"three/examples/jsm/Addons.js";import{disposeScene as I}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as K,setAnimationClipRigId as k}from"../gameplay/animation/retarget.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new b.DataTexture(e,1,1,b.RGBAFormat);t.needsUpdate=!0})();const D=new v;D.setDecoderConfig({type:"js"}),D.setDecoderPath("/assets/draco/");const j=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new C(this.loadingManager).setDRACOLoader(D),this.fbxLoader=new R(this.loadingManager),this.objLoader=new m(this.loadingManager),this.textureLoader=new c(this.loadingManager),this.tgaLoader=new F(this.loadingManager),this.exrLoader=new T(this.loadingManager),this.cubeLoader=new d(this.loadingManager),this.hdrLoader=new P(this.loadingManager),this.ktx2Loader=new B(this.loadingManager),this.ktx2Ready=Promise.resolve(),this._textureLoader=new b.ImageBitmapLoader(this.loadingManager),this.audioLoader=new r(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new y,this.ready=w(this.makeReady),this.directFileLoading=!1,this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTexturePromisesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.clipsRequests=new Set,this.timeToLoadClips=0,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}setDirectFileLoading(e){this.directFileLoading=e}setImageBitmapDecoder(e){this.imageBitmapDecoder=e}decodeImageBitmap(e){return this.imageBitmapDecoder?.(e)}configureKtx2(){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.setWorkerLimit(6)}initKtx2(e){this.configureKtx2(),this.ktx2Loader.detectSupport(e)}initKtx2ForWebGpu(){this.configureKtx2(),this.ktx2Ready=Promise.resolve(navigator.gpu?.requestAdapter({powerPreference:"high-performance"})??null).then(e=>{this.ktx2Loader.detectSupport({isWebGPURenderer:!0,hasFeature:t=>!0===e?.features.has(t)})})}setDataDir(e){this.basePath=g(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){if(e.startsWith("asset://"))return e;const t=function(e){return W.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?g(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(g("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,e.fileKey.toLowerCase().endsWith(".ktx2")&&await this.ktx2Ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=E(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==$(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=$(e.texture?.wrapS)):t.wrapT!==$(e.texture?.wrapT)&&(t.wrapT=$(e.texture?.wrapT),t.needsUpdate=!0)}const r=N(O(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{const t=this._getTextureLoader(e.fileKey),r=null!=this.imageBitmapDecoder&&/\.(png|jpe?g)$/i.test(e.fileKey),a=r||this.directFileLoading&&t===this.textureLoader,i=this.getUri(e.fileKey),s=r?this.imageBitmapDecoder(i).catch(t=>(console.warn(`Worker image decode failed for ${e.name}; falling back to ImageBitmapLoader`,t),this._textureLoader.loadAsync(i))):(a?this._textureLoader:t).loadAsync(i);await s.then(t=>(a&&((t=new l(t)).needsUpdate=!0),t.texture3D?t=t.texture3D:(t.wrapS=$(e.texture?.wrapS),t.wrapT=$(e.texture?.wrapT),t.flipY=E(t,e),t.colorSpace=N(O(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};let a=this._arrayTexturesByFileKey.get(t);if(null==a){let e=this._arrayTexturePromisesByFileKey.get(t);null==e&&(e=this.loadTextureArray(t).finally(()=>{this._arrayTexturePromisesByFileKey.delete(t)}),this._arrayTexturePromisesByFileKey.set(t,e)),a=await e}return this.applyTextureArraySettings(t,a,e),{texture:a,layerIndex:r}}async loadTextureArray(e){const t=this._getTextureLoader(e);let r=await t.loadAsync(this.getUri(e));return r instanceof l||(r=r.texture3D),this._arrayTexturesByFileKey.set(e,r),this._retrievedTextures.push(r),r}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:$(e.texture?.wrapS),wrapT:$(e.texture?.wrapT)}}(r),i=this._arrayTextureSettingsByFileKey.get(e);if(null!=i&&(n=a,(s=i).wrapS!==n.wrapS||s.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var s,n;null==i&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),U(e.fileKey)),null!=e.materialLib&&U(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new i,animations:[]};if(!j.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new i,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new i,animations:[]}}const a=this.cache.get(r),s=a.scene,o=a.animations;if(!1===t?.clone)return{scene:s,animations:o};const l=this.computeCollisionShapes(e,s),c=(e.mesh?.secondaryMotion?.regions.length??0)>0;!0!==t?.mergeGeomtries||c||this.optimizeDrawGroups(s);const h=p(s);h.traverse(e=>{e instanceof n&&e.material instanceof Array&&(e.material=e.material.slice())});const u=new AssetMeshInstance;u.add(h),u.collisionShapes=l,u.animations=o,u.userData.assetId=e.id,u.userData.secondaryMotion=e.mesh?.secondaryMotion,function(e){const t=e.children.length>0?e.children:[e];for(let e=0;e<t.length;e++)r(t[e],"",e);function r(e,t,a){const i=e instanceof n?"Mesh":"Group",s=`${t}/${e.name?.trim()?.length>0?e.name:i}[${a}]`;e.userData.secondaryMotionMeshPath=s;for(let t=0;t<e.children.length;t++)r(e.children[t],s,t)}}(u);const m=e.mesh?.animationRigId??e.anim?.rigId;if(u.userData.animationRigId=m,h.userData.animationRigId=m,null!=m&&null!=this.animationRigProvider){const e=await this.animationRigProvider(m);u.userData.animationRig=e,h.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&u.quaternion.copy(K(e))}const d=e.receiveShadow??!1,f=e.castShadow??!1;if(h.traverse(e=>{e.castShadow=f,e.receiveShadow=d}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&u.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await L(u,t,r,void 0,{textureFlipY:S(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:u,animations:o}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const r=e.anim.clip,a=e.fileKey,i=a+"|"+r;if(this._animationCache.has(i))return this._animationCache.get(i);if(this._animationPromises.has(i))return this._animationPromises.get(i);this.clipsRequests.add(e.id);const s=(async()=>{try{const s=("anim"===e.fileFormat?t(await new b.FileLoader(this.loadingManager).setResponseType("arraybuffer").loadAsync(this.getUri(a))):(await this.getMesh(e,{mergeGeomtries:!1,clone:!1})).animations).find(e=>e.name===r);return null!=s&&(k(s,e.anim?.rigId),this._animationCache.set(i,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(i),1e3)}})();return this._animationPromises.set(i,s),s}computeCollisionShapes(t,r){if(!0!==t.collisionDetection)return[];const a=t.id+"|"+(t.mesh?.collisions?.shapeType??"")+"|"+(t.mesh?.rescale??1)+"|"+JSON.stringify(t.mesh?.colliders??[]);if(!this.collisionShapeCache.has(a)){const i=t.mesh?.colliders??[],s=i.length>0?e(i,t.mesh?.rescale):x(r,t);this.collisionShapeCache.set(a,s)}return this.collisionShapeCache.get(a)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(t=>(t.scene.traverse(t=>{if(t instanceof n&&t.geometry instanceof a){const r=removeInvalidFaces(t.geometry);r>0&&console.warn(`Removed ${r} invalid face${1===r?"":"s"} from ${e.name}/${t.name||"unnamed mesh"}`)}t instanceof n&&t.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(V):e.material=V(t)}(t),M(t)?t.visible=!1:t instanceof n&&t.geometry instanceof a&&(t.geometry.hasAttribute("normal")||t.geometry.computeVertexNormals())}),this._retrievedMeshes.push(t.scene),t.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{X.test(e.name)&&(r=!0)}),!r)return t;const a=[],i=[t];for(;i.length>0;){const e=i.shift(),t=e.name.match(X);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}i.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,t.scene),function(e){const t=Y;Y.length=0,e.traverse(e=>{(e instanceof b.Camera||e instanceof b.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(t.scene),t.scene.userData.assetId=e.id,t))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const t=[];e.traverse(e=>{e instanceof n&&!(e instanceof b.SkinnedMesh)&&e.geometry instanceof a&&Array.isArray(e.material)&&!M(e)&&t.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:r,geometry:a,materialArray:i,parent:s}of t){r.removeFromParent();for(let t=0;t<i.length;t++){const o=i[t],l=a.groups.filter(e=>e.materialIndex===t);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&_.mergeGroups(c);const h=new n(c,o);h.copy(r,!1),h.geometry=c,h.material=o,s?s.add(h):e.add(h)}a.dispose()}f(e,M);let r=!0,i=0,s=0;if(e.traverse(e=>{if(e instanceof n&&e.geometry instanceof a&&!M(e)){i++;const t=Object.keys(e.geometry.attributes).length;t!==s&&0!==s&&(r=!1),s=t}else(e instanceof b.SkinnedMesh||e instanceof b.Bone)&&(r=!1)}),i>1&&r){const t=new Map;e.traverse(r=>{if(r instanceof n&&r.geometry instanceof a&&!M(r)){if(Array.isArray(r.material))return;r.updateWorldMatrix(!0,!0);const a=r.material?.uuid||"default";t.has(a)||t.set(a,{material:r.material,geometries:[],objects:[]});const i=t.get(a),s=e.matrixWorld.clone().invert().multiply(r.matrixWorld);i.geometries.push(r.geometry.clone().applyMatrix4(s)),i.objects.push(r)}});for(const e of t.values())for(const t of e.objects)t.removeFromParent();for(const r of t.values()){let t,a=r.geometries;if(a.some(e=>null!=e.index)&&(a=a.map(e=>{if(null!=e.index)return e;const t=e.getAttribute("position");if(null==t)return e;const r=t.count>65535?new Uint32Array(t.count):new Uint16Array(t.count);for(let e=0;e<r.length;e++)r[e]=e;return e.setIndex(new b.BufferAttribute(r,1)),e})),t=1===r.geometries.length?a[0]:z(a)?_.mergeGeometries(a,!0):null,null!=t)t.groups.length>1&&_.mergeGroups(t),e.add(new n(t,r.material));else for(const t of a)e.add(new n(t,r.material))}}e.traverse(e=>{if(e instanceof n&&e.geometry instanceof a&&!M(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&_.mergeGroups(t)}})}extractGeometryGroups(e,t){const r=e.index;if(!r){const r=new a;let i=0;for(const e of t)i+=e.count;if(0===i)return r;for(const a in e.attributes){const s=e.attributes[a],n=s.itemSize,o=s.array,l=new(0,o.constructor)(i*n);let c=0;for(const e of t){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new b.BufferAttribute(l,n,s.normalized);r.setAttribute(a,h)}return r.groups=[{start:0,count:i,materialIndex:0}],r}const i=[];for(const e of t)for(let t=0;t<e.count;t++){const a=r.getX(e.start+t);i.push(a)}if(0===i.length)return new a;const s=new Map,n=[];let o=0;for(const e of i)s.has(e)||(s.set(e,o),o++),n.push(s.get(e));if(0===n.length||0===s.size)return new a;const l=new a;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,i=r.array,n=new(0,i.constructor)(s.size*a);for(const[e,t]of s)for(let r=0;r<a;r++)n[t*a+r]=i[e*a+r];const o=new b.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new b.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(t=>{const r=!0===e.originalFileKey?.toLowerCase().endsWith(".fbx")&&1===t.scene.children.length?t.scene.children[0]:t.scene;return r!==t.scene&&t.scene.remove(r),{scene:r,animations:t.animations}});case"fbx":if(this.directFileLoading){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load FBX ${t}: ${e.status}`);const r=await e.arrayBuffer(),a=this.fbxLoader.parse(r,b.LoaderUtils.extractUrlBase(t));return{scene:a,animations:a.animations}}return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new u;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>(G(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>I(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const W=new Map;function U(e){W.set(e,(W.get(e)??0)+1)}function z(e){if(e.length<2)return!0;const t=e[0],r=Object.keys(t.attributes).sort(),a=Object.keys(t.morphAttributes).sort();return e.slice(1).every(e=>{if(null==e.index!=(null==t.index))return!1;if(e.morphTargetsRelative!==t.morphTargetsRelative)return!1;const i=Object.keys(e.attributes).sort(),s=Object.keys(e.morphAttributes).sort();if(i.join("|")!==r.join("|"))return!1;if(s.join("|")!==a.join("|"))return!1;for(const a of r){const r=t.getAttribute(a),i=e.getAttribute(a);if(r.itemSize!==i.itemSize||r.normalized!==i.normalized||r.array.constructor!==i.array.constructor)return!1}for(const r of a){const a=t.morphAttributes[r],i=e.morphAttributes[r];if(a.length!==i.length)return!1;for(let e=0;e<a.length;e++)if(a[e].itemSize!==i[e].itemSize||a[e].normalized!==i[e].normalized||a[e].array.constructor!==i[e].array.constructor)return!1}return!0})}function G(e){if(e instanceof n)for(const t of A(e.material))t instanceof b.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach(G)}export class AssetMeshInstance extends o{}export{createAuthoredCollisionShapes}from"./collision/authored-colliders.js";export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function $(e){switch(e){case"clamp":return b.ClampToEdgeWrapping;case"repeat":return b.RepeatWrapping;case"mirror":return b.MirroredRepeatWrapping}return b.RepeatWrapping}function E(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function O(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(q.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function N(e){return"linear"===e?b.LinearSRGBColorSpace:b.SRGBColorSpace}const q=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new b.Matrix4;const Y=[];const X=/_LOD(\d+)/;export function removeInvalidFaces(e){const t=e.getAttribute("position");if(null==t||t.itemSize<3)return 0;const r=e.index,a=r?.count??t.count,i=Math.floor(a/3),s=[],n=new Uint32Array(i+1),o=new h,l=new h,c=new h;let u=0;for(let e=0;e<i;e++){const a=3*e,i=r?.getX(a)??a,h=r?.getX(a+1)??a+1,m=r?.getX(a+2)??a+2;let d=Number.isInteger(i)&&Number.isInteger(h)&&Number.isInteger(m)&&i>=0&&h>=0&&m>=0&&i<t.count&&h<t.count&&m<t.count;if(d){o.fromBufferAttribute(t,i),l.fromBufferAttribute(t,h).sub(o),c.fromBufferAttribute(t,m).sub(o);const e=Math.max(l.lengthSq(),c.lengthSq(),l.distanceToSquared(c)),r=l.cross(c).lengthSq();d=Number.isFinite(e)&&Number.isFinite(r)&&e>0&&r>Number.EPSILON*e*e}d?s.push(i,h,m):u++,n[e+1]=s.length}if(0===u)return 0;if(e.setIndex(s),e.groups.length>0){const t=e.groups.slice();e.clearGroups();for(const r of t){const t=Math.max(0,Math.ceil(r.start/3)),a=Math.min(i,Math.floor((r.start+r.count)/3));if(a<=t)continue;const s=n[t],o=n[a]-s;o>0&&e.addGroup(s,o,r.materialIndex)}}const m=Math.max(0,Math.ceil(e.drawRange.start/3)),d=Number.isFinite(e.drawRange.count)?Math.min(i,Math.floor((e.drawRange.start+e.drawRange.count)/3)):i,p=Math.min(m,i),f=Math.min(i,Math.max(p,d)),g=n[p];return e.setDrawRange(g,n[f]-g),u}function V(e){let t=e instanceof b.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof b.MeshLambertMaterial||e instanceof b.MeshPhongMaterial||e instanceof b.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new b.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return e}/*
1
+ import{createAuthoredCollisionShapes as e}from"./collision/authored-colliders.js";import{parseAnimationClips as t}from"./animation-binary.js";import{AudioLoader as r,BufferGeometry as a,Group as i,LoadingManager as s,Mesh as n,Object3D as o,Texture as l,TextureLoader as c,Vector3 as h}from"three";import{MTLLoader as u,OBJLoader as m,LUTCubeLoader as d}from"three-stdlib";import{cloneMesh as p,mergeCompatibleSkinnedMeshes as f}from"../utils/mesh.js";import{pathJoin as g}from"../utils/files.js";import{Subject as y,firstValueFrom as w}from"rxjs";import{importCollisionShapes as x,isCollisionMesh as M}from"./collision/collision-shape-import.js";import*as b from"three";import{iterateMaterials as A}from"../utils/materials.js";import{applyMaterial as L,getConvertedFbxToGlbAssignedMaterialTextureFlipY as v}from"./materializer.js";import{BufferGeometryUtils as S,DRACOLoader as _,EXRLoader as T,FBXLoader as R,GLTFLoader as K,KTX2Loader as B,TGALoader as F,UltraHDRLoader as C}from"three/examples/jsm/Addons.js";import{disposeScene as P}from"../utils/three/cleanup.js";import{resolveAnimationRigBasisRotation as I,setAnimationClipRigId as k}from"../gameplay/animation/retarget.js";import{parseNativeTexture as D,selectNativeTexture as j}from"./native-texture.js";(()=>{const e=new Uint8Array([255,0,0,255]),t=new b.DataTexture(e,1,1,b.RGBAFormat);t.needsUpdate=!0})();const W=new _;W.setDecoderConfig({type:"js"}),W.setDecoderPath("/assets/draco/");const U=["glb","gltf","fbx","obj"];export class AssetResourceLoader{onError(e){console.error(e)}constructor(){this.cache=new Map,this.textureCache=new Map,this.loadingManager=new s,this.glbLoader=new K(this.loadingManager).setDRACOLoader(W),this.fbxLoader=new R(this.loadingManager),this.objLoader=new m(this.loadingManager),this.textureLoader=new c(this.loadingManager),this.tgaLoader=new F(this.loadingManager),this.exrLoader=new T(this.loadingManager),this.cubeLoader=new d(this.loadingManager),this.hdrLoader=new C(this.loadingManager),this.ktx2Loader=new B(this.loadingManager),this.ktx2Ready=Promise.resolve(),this.nativeTextureLoader=new b.FileLoader(this.loadingManager).setResponseType("arraybuffer"),this.nativeBcSupported=!1,this.nativeAstcSupported=!1,this._textureLoader=new b.ImageBitmapLoader(this.loadingManager),this.audioLoader=new r(this.loadingManager),this.initialisedKtx2=!1,this._retrievedMeshes=[],this._retrievedTextures=[],this.makeReady=new y,this.ready=w(this.makeReady),this.directFileLoading=!1,this._texturePromises=new Map,this._arrayTexturesByFileKey=new Map,this._arrayTexturePromisesByFileKey=new Map,this._arrayTextureSettingsByFileKey=new Map,this._animationPromises=new Map,this._animationCache=new Map,this.asyncMeshResults=new Map,this.asyncAudioResults=new Map,this.clipsRequests=new Set,this.timeToLoadClips=0,this.collisionShapeCache=new Map,this.optimizedMeshes=new Set}setDirectFileLoading(e){this.directFileLoading=e}setImageBitmapDecoder(e){this.imageBitmapDecoder=e}decodeImageBitmap(e){return this.imageBitmapDecoder?.(e)}configureKtx2(){this.initialisedKtx2=!0;null!=getElectronArg("windowId")||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?this.ktx2Loader.setTranscoderPath("/assets/basis/"):this.ktx2Loader.setTranscoderPath(new URL("../assets/basis/",import.meta.url).href),this.ktx2Loader.setWorkerLimit(6)}initKtx2(e){this.configureKtx2(),this.ktx2Loader.detectSupport(e),this.nativeBcSupported=e.extensions.has("EXT_texture_compression_bptc"),this.nativeAstcSupported=e.extensions.has("WEBGL_compressed_texture_astc")}initKtx2ForWebGpu(e){this.configureKtx2(),this.ktx2Ready=Promise.resolve(e??navigator.gpu?.requestAdapter({powerPreference:"high-performance"})??null).then(e=>{this.nativeBcSupported=!0===e?.features.has("texture-compression-bc"),this.nativeAstcSupported=!0===e?.features.has("texture-compression-astc"),this.ktx2Loader.detectSupport({isWebGPURenderer:!0,hasFeature:t=>!0===e?.features.has(t)})})}setDataDir(e){this.basePath=g(e,"asset-resources"),this.makeReady.next(!0)}getUri(e){if(e.startsWith("asset://"))return e;const t=function(e){return G.get(e)}(e),r=getElectronArg("windowId");return null!=r||import.meta.url.includes(".vite")||import.meta.url.includes("hology/packages/core")?g(this.basePath,e)+(null!=r?`?windowId=${r}${null!=t?`&v=${t}`:""}`:""):new URL(g("..",this.basePath,e),import.meta.url).href}async getTexture(e){if(!e||!e.fileKey)return null;if("png"===e.fileFormat||e.fileFormat,this._texturePromises.has(e.id))return this._texturePromises.get(e.id);const t=this._getTexture(e).finally(()=>{this._texturePromises.delete(e.id)});return this._texturePromises.set(e.id,t),t}async _getTexture(e){if(null==e||null==e.fileKey)return null;if(await this.ready,e.fileKey.toLowerCase().endsWith(".ktx2")&&await this.ktx2Ready,this.textureCache.has(e.id)){const t=this.textureCache.get(e.id);if(null!=e.texture){const r=N(t,e);t.flipY!==r?(t.needsUpdate=!0,t.flipY=r):t.wrapS!==O(e.texture?.wrapS)?(t.needsUpdate=!0,t.wrapS=O(e.texture?.wrapS)):t.wrapT!==O(e.texture?.wrapT)&&(t.wrapT=O(e.texture?.wrapT),t.needsUpdate=!0)}const r=X(q(e));t.colorSpace!==r&&(t.colorSpace=r,t.needsUpdate=!0)}else try{const t=this._getTextureLoader(e.fileKey),r=null!=this.imageBitmapDecoder&&/\.(png|jpe?g)$/i.test(e.fileKey),a=r||this.directFileLoading&&t===this.textureLoader,i=this.getUri(e.fileKey),s=r?this.imageBitmapDecoder(i).catch(t=>(console.warn(`Worker image decode failed for ${e.name}; falling back to ImageBitmapLoader`,t),this._textureLoader.loadAsync(i))):e.texture?.nativeFileKeys&&t===this.ktx2Loader?this.loadKtx2Texture(e.fileKey,e.texture.nativeFileKeys):(a?this._textureLoader:t).loadAsync(i);await s.then(t=>(a&&((t=new l(t)).needsUpdate=!0),t.texture3D?t=t.texture3D:(t.wrapS=O(e.texture?.wrapS),t.wrapT=O(e.texture?.wrapT),t.flipY=N(t,e),t.colorSpace=X(q(e))),this.textureCache.set(e.id,t),this._retrievedTextures.push(t),t))}catch(t){return console.warn("Failed to load texture "+e.name,t),null}const t=this.textureCache.get(e.id);return null!=t&&(t.userData.assetId=e.id),t}async getTextureArray(e){const t=e.texture?.textureArrayFileKey,r=e.texture?.textureArrayLayer;if(!t||null==r)return{texture:null,layerIndex:null};let a=this._arrayTexturesByFileKey.get(t);if(null==a){let r=this._arrayTexturePromisesByFileKey.get(t);null==r&&(r=this.loadTextureArray(t,e.texture?.nativeArrayFileKeys).finally(()=>{this._arrayTexturePromisesByFileKey.delete(t)}),this._arrayTexturePromisesByFileKey.set(t,r)),a=await r}return this.applyTextureArraySettings(t,a,e),{texture:a,layerIndex:r}}async loadKtx2Texture(e,t){await this.ktx2Ready;const r=j(t,this.nativeBcSupported,this.nativeAstcSupported);if(r)try{const e=await this.nativeTextureLoader.loadAsync(this.getUri(r.fileKey));return D(e,r.format)}catch(e){console.warn(`Failed to load native texture ${r.fileKey}; using portable KTX2`,e)}return this._getTextureLoader(e).loadAsync(this.getUri(e))}async loadTextureArray(e,t){let r=await this.loadKtx2Texture(e,t);return r instanceof l||(r=r.texture3D),this._arrayTexturesByFileKey.set(e,r),this._retrievedTextures.push(r),r}applyTextureArraySettings(e,t,r){const a=function(e){return{wrapS:O(e.texture?.wrapS),wrapT:O(e.texture?.wrapT)}}(r),i=this._arrayTextureSettingsByFileKey.get(e);if(null!=i&&(n=a,(s=i).wrapS!==n.wrapS||s.wrapT!==n.wrapT))return void console.warn(`Texture array ${e} is used with incompatible texture settings. Texture arrays share wrapping; rebuild arrays so incompatible textures are grouped separately.`);var s,n;null==i&&this._arrayTextureSettingsByFileKey.set(e,a);let o=!1;t.wrapS!==a.wrapS&&(t.wrapS=a.wrapS,o=!0),t.wrapT!==a.wrapT&&(t.wrapT=a.wrapT,o=!0),!1!==t.flipY&&(t.flipY=!1,o=!0),o&&(t.needsUpdate=!0)}_getTextureLoader(e){return e?.toLowerCase().endsWith(".tga")?this.tgaLoader:e?.toLowerCase().endsWith(".ktx2")?this.ktx2Loader:e?.toLowerCase().endsWith(".exr")?this.exrLoader:e?.toLowerCase().endsWith(".cube")?this.cubeLoader:this.textureLoader}clearCache(e){this.clearCacheByAsset(e)}clearCacheByAsset(e){null!=e&&(this.clearCacheById(e.id),null!=e.fileKey&&(Array.from(this.cache.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.cache.delete(t)}),Array.from(this.asyncMeshResults.keys()).forEach(t=>{t.startsWith(e.fileKey)&&this.asyncMeshResults.delete(t)}),Array.from(this._animationCache.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationCache.delete(t)}),Array.from(this._animationPromises.keys()).forEach(t=>{t.startsWith(e.fileKey+"|")&&this._animationPromises.delete(t)}),z(e.fileKey)),null!=e.materialLib&&z(e.materialLib))}clearCacheById(e){const t=Array.from(this.cache.values()).find(t=>t.scene.userData.assetId===e);t&&Array.from(this.cache.keys()).forEach(e=>{this.cache.get(e)===t&&this.cache.delete(e)}),this.textureCache.delete(e),this._texturePromises.delete(e),Array.from(this.collisionShapeCache.keys()).forEach(t=>{t.startsWith(e+"|")&&this.collisionShapeCache.delete(t)})}async getMesh(e,t){if(await this.ready,null==e)return console.error("No asset was provided"),{scene:new i,animations:[]};if(!U.includes(e.fileFormat?.toLowerCase()))return console.error("Unsupported mesh file format "+e.fileFormat,e),{scene:new i,animations:[]};const r=e.fileKey+(!0===t?.mergeGeomtries?"1":"0");if(!this.cache.has(r))try{this.asyncMeshResults.has(r)||this.asyncMeshResults.set(r,this.loadMesh(e).finally(()=>this.asyncMeshResults.delete(r))),this.cache.set(r,await this.asyncMeshResults.get(r))}catch(e){return this.onError(e),{scene:new i,animations:[]}}const a=this.cache.get(r),s=a.scene,o=a.animations;if(!1===t?.clone)return{scene:s,animations:o};const l=this.computeCollisionShapes(e,s),c=(e.mesh?.secondaryMotion?.regions.length??0)>0;!0!==t?.mergeGeomtries||c||this.optimizeDrawGroups(s);const h=p(s);h.traverse(e=>{e instanceof n&&e.material instanceof Array&&(e.material=e.material.slice())});const u=new AssetMeshInstance;u.add(h),u.collisionShapes=l,u.animations=o,u.userData.assetId=e.id,u.userData.secondaryMotion=e.mesh?.secondaryMotion,function(e){const t=e.children.length>0?e.children:[e];for(let e=0;e<t.length;e++)r(t[e],"",e);function r(e,t,a){const i=e instanceof n?"Mesh":"Group",s=`${t}/${e.name?.trim()?.length>0?e.name:i}[${a}]`;e.userData.secondaryMotionMeshPath=s;for(let t=0;t<e.children.length;t++)r(e.children[t],s,t)}}(u);const m=e.mesh?.animationRigId??e.anim?.rigId;if(u.userData.animationRigId=m,h.userData.animationRigId=m,null!=m&&null!=this.animationRigProvider){const e=await this.animationRigProvider(m);u.userData.animationRig=e,h.userData.animationRig=e,null!=e&&!1!==t?.applyRigBasis&&u.quaternion.copy(I(e))}const d=e.receiveShadow??!1,f=e.castShadow??!1;if(h.traverse(e=>{e.castShadow=f,e.receiveShadow=d}),!0===t?.rescale&&"number"==typeof e.mesh?.rescale&&u.scale.setScalar(e.mesh?.rescale),!0===t?.applyMaterials){const r=t?.materialResolver??this.materialProvider;if(null!=r)for(const t of e.materialAssignments??[])await L(u,t,r,void 0,{textureFlipY:v(e)});else console.warn(`applyMaterials was set to true for ${e.name} but no material resolver was provided.`)}return{scene:u,animations:o}}async getAudio(e){await this.ready;const t=e.fileKey;if(this.asyncAudioResults.has(t))return await this.asyncAudioResults.get(t);const r=this.audioLoader.loadAsync(this.getUri(e.fileKey)).finally(()=>{setTimeout(()=>{this.asyncAudioResults.delete(t)},1e3)});return this.asyncAudioResults.set(t,r),r}async getAnimationClip(e){if(null==e||null==e.fileKey||null==e.anim?.clip)return console.warn("Asset or animation clip name is not defined",e),null;const r=e.anim.clip,a=e.fileKey,i=a+"|"+r;if(this._animationCache.has(i))return this._animationCache.get(i);if(this._animationPromises.has(i))return this._animationPromises.get(i);this.clipsRequests.add(e.id);const s=(async()=>{try{const s=("anim"===e.fileFormat?t(await new b.FileLoader(this.loadingManager).setResponseType("arraybuffer").loadAsync(this.getUri(a))):(await this.getMesh(e,{mergeGeomtries:!1,clone:!1})).animations).find(e=>e.name===r);return null!=s&&(k(s,e.anim?.rigId),this._animationCache.set(i,s)),s}catch(e){return this.onError(e),null}finally{setTimeout(()=>this._animationPromises.delete(i),1e3)}})();return this._animationPromises.set(i,s),s}computeCollisionShapes(t,r){if(!0!==t.collisionDetection)return[];const a=t.id+"|"+(t.mesh?.collisions?.shapeType??"")+"|"+(t.mesh?.rescale??1)+"|"+JSON.stringify(t.mesh?.colliders??[]);if(!this.collisionShapeCache.has(a)){const i=t.mesh?.colliders??[],s=i.length>0?e(i,t.mesh?.rescale):x(r,t);this.collisionShapeCache.set(a,s)}return this.collisionShapeCache.get(a)}async loadMesh(e){return await this.ready,await this.loadByAsset(e).then(t=>(t.scene.traverse(t=>{if(t instanceof n&&t.geometry instanceof a){const r=removeInvalidFaces(t.geometry);r>0&&console.warn(`Removed ${r} invalid face${1===r?"":"s"} from ${e.name}/${t.name||"unnamed mesh"}`)}t instanceof n&&t.material&&function(e){let t=e.material;if(null==t)return;Array.isArray(t)?e.material=t.map(H):e.material=H(t)}(t),M(t)?t.visible=!1:t instanceof n&&t.geometry instanceof a&&(t.geometry.hasAttribute("normal")||t.geometry.computeVertexNormals())}),this._retrievedMeshes.push(t.scene),t.scene=function(e,t){let r=!1;if(t.traverseVisible(e=>{J.test(e.name)&&(r=!0)}),!r)return t;const a=[],i=[t];for(;i.length>0;){const e=i.shift(),t=e.name.match(J);if(null!=t){const r=parseInt(t[1]);if(0!==r){console.warn(`Skipping LOD level ${r} for now as LOD is not fully supported`),a.push(e);continue}}i.push(...e.children)}for(const e of a)e.removeFromParent();return t}(0,t.scene),function(e){const t=V;V.length=0,e.traverse(e=>{(e instanceof b.Camera||e instanceof b.Light)&&t.push(e)}),t.forEach(e=>e.removeFromParent())}(t.scene),t.scene.userData.assetId=e.id,t))}optimizeDrawGroups(e){if(this.optimizedMeshes.has(e.uuid))return;this.optimizedMeshes.add(e.uuid),e.updateWorldMatrix(!0,!0);const t=[];e.traverse(e=>{e instanceof n&&!(e instanceof b.SkinnedMesh)&&e.geometry instanceof a&&Array.isArray(e.material)&&!M(e)&&t.push({mesh:e,geometry:e.geometry,materialArray:e.material,parent:e.parent})});for(const{mesh:r,geometry:a,materialArray:i,parent:s}of t){r.removeFromParent();for(let t=0;t<i.length;t++){const o=i[t],l=a.groups.filter(e=>e.materialIndex===t);if(0===l.length)continue;const c=this.extractGeometryGroups(a,l);c.groups.length>1&&S.mergeGroups(c);const h=new n(c,o);h.copy(r,!1),h.geometry=c,h.material=o,s?s.add(h):e.add(h)}a.dispose()}f(e,M);let r=!0,i=0,s=0;if(e.traverse(e=>{if(e instanceof n&&e.geometry instanceof a&&!M(e)){i++;const t=Object.keys(e.geometry.attributes).length;t!==s&&0!==s&&(r=!1),s=t}else(e instanceof b.SkinnedMesh||e instanceof b.Bone)&&(r=!1)}),i>1&&r){const t=new Map;e.traverse(r=>{if(r instanceof n&&r.geometry instanceof a&&!M(r)){if(Array.isArray(r.material))return;r.updateWorldMatrix(!0,!0);const a=r.material?.uuid||"default";t.has(a)||t.set(a,{material:r.material,geometries:[],objects:[]});const i=t.get(a),s=e.matrixWorld.clone().invert().multiply(r.matrixWorld);i.geometries.push(r.geometry.clone().applyMatrix4(s)),i.objects.push(r)}});for(const e of t.values())for(const t of e.objects)t.removeFromParent();for(const r of t.values()){let t,a=r.geometries;if(a.some(e=>null!=e.index)&&(a=a.map(e=>{if(null!=e.index)return e;const t=e.getAttribute("position");if(null==t)return e;const r=t.count>65535?new Uint32Array(t.count):new Uint16Array(t.count);for(let e=0;e<r.length;e++)r[e]=e;return e.setIndex(new b.BufferAttribute(r,1)),e})),t=1===r.geometries.length?a[0]:E(a)?S.mergeGeometries(a,!0):null,null!=t)t.groups.length>1&&S.mergeGroups(t),e.add(new n(t,r.material));else for(const t of a)e.add(new n(t,r.material))}}e.traverse(e=>{if(e instanceof n&&e.geometry instanceof a&&!M(e)){const t=e.geometry;!Array.isArray(e.material)&&t.groups.length>1&&S.mergeGroups(t)}})}extractGeometryGroups(e,t){const r=e.index;if(!r){const r=new a;let i=0;for(const e of t)i+=e.count;if(0===i)return r;for(const a in e.attributes){const s=e.attributes[a],n=s.itemSize,o=s.array,l=new(0,o.constructor)(i*n);let c=0;for(const e of t){const t=e.start*n,r=e.count*n;for(let e=0;e<r;e++)l[c+e]=o[t+e];c+=r}const h=new b.BufferAttribute(l,n,s.normalized);r.setAttribute(a,h)}return r.groups=[{start:0,count:i,materialIndex:0}],r}const i=[];for(const e of t)for(let t=0;t<e.count;t++){const a=r.getX(e.start+t);i.push(a)}if(0===i.length)return new a;const s=new Map,n=[];let o=0;for(const e of i)s.has(e)||(s.set(e,o),o++),n.push(s.get(e));if(0===n.length||0===s.size)return new a;const l=new a;for(const t in e.attributes){const r=e.attributes[t],a=r.itemSize,i=r.array,n=new(0,i.constructor)(s.size*a);for(const[e,t]of s)for(let r=0;r<a;r++)n[t*a+r]=i[e*a+r];const o=new b.BufferAttribute(n,a,r.normalized);l.setAttribute(t,o)}const c=new((n.length>0?Math.max(...n):0)>65535?Uint32Array:Uint16Array)(n.length);for(let e=0;e<n.length;e++)c[e]=n[e];return l.setIndex(new b.BufferAttribute(c,1)),l.groups=[{start:0,count:n.length,materialIndex:0}],l}async loadByAsset(e){this.fbxLoader;const t=this.getUri(e.fileKey);switch(e.fileFormat){case"glb":case"gltf":return this.glbLoader.loadAsync(t).then(t=>{const r=!0===e.originalFileKey?.toLowerCase().endsWith(".fbx")&&1===t.scene.children.length?t.scene.children[0]:t.scene;return r!==t.scene&&t.scene.remove(r),{scene:r,animations:t.animations}});case"fbx":if(this.directFileLoading){const e=await fetch(t);if(!e.ok)throw new Error(`Failed to load FBX ${t}: ${e.status}`);const r=await e.arrayBuffer(),a=this.fbxLoader.parse(r,b.LoaderUtils.extractUrlBase(t));return{scene:a,animations:a.animations}}return this.fbxLoader.loadAsync(t).then(e=>({scene:e,animations:e.animations}));case"obj":if(null!=e.materialLib){const t=new u;t.materialOptions={normalizeRGB:!1};const r=await t.loadAsync(this.getUri(e.materialLib));this.objLoader.setMaterials(r)}return this.objLoader.loadAsync(t).then(e=>($(e),e)).then(e=>({scene:e,animations:e.animations}))}}disposeAll(){this.cache.clear(),this._retrievedMeshes.forEach(e=>P(e)),this._retrievedTextures.forEach(e=>e.dispose()),this._retrievedMeshes.length=0,this._retrievedTextures.length=0}}const G=new Map;function z(e){G.set(e,(G.get(e)??0)+1)}function E(e){if(e.length<2)return!0;const t=e[0],r=Object.keys(t.attributes).sort(),a=Object.keys(t.morphAttributes).sort();return e.slice(1).every(e=>{if(null==e.index!=(null==t.index))return!1;if(e.morphTargetsRelative!==t.morphTargetsRelative)return!1;const i=Object.keys(e.attributes).sort(),s=Object.keys(e.morphAttributes).sort();if(i.join("|")!==r.join("|"))return!1;if(s.join("|")!==a.join("|"))return!1;for(const a of r){const r=t.getAttribute(a),i=e.getAttribute(a);if(r.itemSize!==i.itemSize||r.normalized!==i.normalized||r.array.constructor!==i.array.constructor)return!1}for(const r of a){const a=t.morphAttributes[r],i=e.morphAttributes[r];if(a.length!==i.length)return!1;for(let e=0;e<a.length;e++)if(a[e].itemSize!==i[e].itemSize||a[e].normalized!==i[e].normalized||a[e].array.constructor!==i[e].array.constructor)return!1}return!0})}function $(e){if(e instanceof n)for(const t of A(e.material))t instanceof b.MeshPhongMaterial&&!t.color.isLinear&&(t.color.isLinear=!0);e.children?.forEach($)}export class AssetMeshInstance extends o{}export{createAuthoredCollisionShapes}from"./collision/authored-colliders.js";export function getElectronArg(e){const t=`--${e}=`,r=window.process?.argv.find(e=>e.startsWith(t));return r?.substring(t.length)}function O(e){switch(e){case"clamp":return b.ClampToEdgeWrapping;case"repeat":return b.RepeatWrapping;case"mirror":return b.MirroredRepeatWrapping}return b.RepeatWrapping}function N(e,t){const r=e;return!0!==r.isCompressedTexture&&!0!==r.isCompressedArrayTexture&&(t.texture?.flipY??!0)}function q(e){return e.texture?.colorSpace??function(e){if("exr"===e.fileFormat||e.fileKey?.toLowerCase().endsWith(".exr"))return"linear";const t=`${e.name} ${e.fileKey??""}`.toLowerCase();if(Y.some(e=>t.includes(e)))return"linear";return"srgb"}(e)}function X(e){return"linear"===e?b.LinearSRGBColorSpace:b.SRGBColorSpace}const Y=["_normal","_nrm","_nor","_norm","_roughness","_rough","_metalness","_metallic","_metal","_ao","_ambient","_occlusion","_mask","_height","_disp","_displacement","_bump","_opacity"];new b.Matrix4;const V=[];const J=/_LOD(\d+)/;export function removeInvalidFaces(e){const t=e.getAttribute("position");if(null==t||t.itemSize<3)return 0;const r=e.index,a=r?.count??t.count,i=Math.floor(a/3),s=[],n=new Uint32Array(i+1),o=new h,l=new h,c=new h;let u=0;for(let e=0;e<i;e++){const a=3*e,i=r?.getX(a)??a,h=r?.getX(a+1)??a+1,m=r?.getX(a+2)??a+2;let d=Number.isInteger(i)&&Number.isInteger(h)&&Number.isInteger(m)&&i>=0&&h>=0&&m>=0&&i<t.count&&h<t.count&&m<t.count;if(d){o.fromBufferAttribute(t,i),l.fromBufferAttribute(t,h).sub(o),c.fromBufferAttribute(t,m).sub(o);const e=Math.max(l.lengthSq(),c.lengthSq(),l.distanceToSquared(c)),r=l.cross(c).lengthSq();d=Number.isFinite(e)&&Number.isFinite(r)&&e>0&&r>Number.EPSILON*e*e}d?s.push(i,h,m):u++,n[e+1]=s.length}if(0===u)return 0;if(e.setIndex(s),e.groups.length>0){const t=e.groups.slice();e.clearGroups();for(const r of t){const t=Math.max(0,Math.ceil(r.start/3)),a=Math.min(i,Math.floor((r.start+r.count)/3));if(a<=t)continue;const s=n[t],o=n[a]-s;o>0&&e.addGroup(s,o,r.materialIndex)}}const m=Math.max(0,Math.ceil(e.drawRange.start/3)),d=Number.isFinite(e.drawRange.count)?Math.min(i,Math.floor((e.drawRange.start+e.drawRange.count)/3)):i,p=Math.min(m,i),f=Math.min(i,Math.max(p,d)),g=n[p];return e.setDrawRange(g,n[f]-g),u}function H(e){let t=e instanceof b.MeshPhysicalMaterial&&0===e.sheen&&0===e.anisotropy;if("MeshLambertMaterial"===e.type||"MeshPhongMaterial"===e.type||t){let t={};(e instanceof b.MeshLambertMaterial||e instanceof b.MeshPhongMaterial||e instanceof b.MeshPhysicalMaterial)&&(t.color=e.color,t.map=e.map,t.bumpMap=e.bumpMap,t.bumpScale=e.bumpScale,t.lightMap=e.lightMap,t.lightMapIntensity=e.lightMapIntensity,t.aoMap=e.aoMap,t.aoMapIntensity=e.aoMapIntensity,t.emissiveMap=e.emissiveMap,t.alphaMap=e.alphaMap,t.envMap=e.envMap,t.envMapRotation=e.envMapRotation,t.wireframe=e.wireframe,t.wireframeLinewidth=e.wireframeLinewidth,t.fog=e.fog,t.opacity=e.opacity,t.transparent=e.transparent,t.side=e.side,t.depthTest=e.depthTest,t.depthWrite=e.depthWrite,t.alphaTest=e.alphaTest,t.displacementMap=e.displacementMap,t.displacementScale=e.displacementScale,t.displacementBias=e.displacementBias);const r=new b.MeshStandardMaterial(t);return r.userData={...e.userData??{}},r.name=e.name,r}return e}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -653,7 +653,7 @@ export declare function _materialFromAsset(key: string, asset: Asset, renderingV
653
653
  export declare function prepareCustomParamsFromShaderGraph(graph: ShaderGraphDocument, previous?: Record<string, CustomParamValue>): Record<string, CustomParamValue>;
654
654
  export declare function prepareShaderGraphParameters(paramsSource: {
655
655
  [key: string]: CustomParamValue;
656
- }, graph: ShaderGraphDocument, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, renderingView?: RenderingView, shaders?: ShaderImpl[]): Promise<{
656
+ }, graph: ShaderGraphDocument, assetsService: AssetsProvider, assetManagerService: AssetResourceLoader, renderingView?: RenderingView, shaders?: ShaderImpl[], stableParticleAnimation?: boolean): Promise<{
657
657
  [key: string]: unknown;
658
658
  }>;
659
659
  export declare function prepareClassParameters(paramsSource: {