@hology/core 0.0.214 → 0.0.216
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/project-config.d.ts +1 -0
- package/dist/effects/sequence/sequence-action.d.ts +4 -0
- package/dist/effects/sequence/sequence-actor.js +1 -1
- package/dist/effects/sequence/sequence-animation-retiming.d.ts +2 -1
- package/dist/effects/sequence/sequence-animation-retiming.js +1 -1
- package/dist/effects/sequence/sequence-data.d.ts +6 -0
- package/dist/effects/sequence/sequence-data.js +1 -1
- package/dist/effects/sequence/sequence-player.d.ts +11 -0
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/effects/vfx/vfx-collision-behaviour.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement-like.d.ts +3 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +22 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-slide.d.ts +7 -0
- package/dist/gameplay/actors/builtin/components/character/character-slide.js +4 -0
- package/dist/gameplay/actors/builtin/components/character/modes.d.ts +2 -1
- package/dist/gameplay/actors/builtin/components/character/modes.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts +3 -1
- package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js +1 -1
- package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
- package/dist/gameplay/actors/camera/third-person-camera-component.d.ts +1 -0
- package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
- package/dist/gameplay/ai/behavior-tree/move.js +1 -1
- package/dist/gameplay/ai/dynamic-tiled-navmesh.d.ts +20 -2
- package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
- package/dist/gameplay/animation/animation-action.d.ts +3 -0
- package/dist/gameplay/animation/animation-action.js +4 -0
- package/dist/gameplay/services/physics/physics-system.d.ts +56 -3
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +10 -0
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/collision/collision-shape.d.ts +1 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/storage/storage.js +1 -1
- package/dist/shader/builtin/standard-shader.js +1 -1
- package/dist/shader/builtin/unlit-shader.js +1 -1
- package/dist/shader/decal-shader.d.ts +2 -2
- package/dist/shader/decal-shader.js +1 -1
- package/dist/shader/shader.d.ts +2 -1
- package/dist/shader/shader.js +1 -1
- package/dist/shader/sprite-shader.d.ts +2 -2
- package/dist/shader/sprite-shader.js +1 -1
- package/dist/shader/trail-shader.d.ts +2 -2
- package/dist/shader/trail-shader.js +1 -1
- package/dist/test/asset-resource-loader-texture-array.test.d.ts +2 -0
- package/dist/test/asset-resource-loader-texture-array.test.js +4 -0
- package/dist/test/character-animation-transition.test.d.ts +2 -0
- package/dist/test/character-animation-transition.test.js +4 -0
- package/dist/test/character-slide.test.d.ts +2 -0
- package/dist/test/character-slide.test.js +4 -0
- package/dist/test/navmesh-worker-pool.test.d.ts +2 -0
- package/dist/test/navmesh-worker-pool.test.js +4 -0
- package/dist/test/net-character-movement.test.js +1 -1
- package/dist/test/sequence-animation-retiming.test.js +1 -1
- package/dist/test/sequence-root-motion-axis-mask.test.d.ts +2 -0
- package/dist/test/sequence-root-motion-axis-mask.test.js +4 -0
- package/package.json +2 -2
- 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{RootMotionClip as i}from"../../../../animation/root-motion.js";import{inject as s}from"../../../../inject.js";import{ViewController as r}from"../../../../services/render.js";import{AnimationMixer as n,Bone as l,Object3D as a,LoopOnce as h,Raycaster as c,Vector3 as d,SkinnedMesh as p,Skeleton as u,Quaternion as f,Matrix4 as g,MathUtils as y,ArrowHelper as m,Group as k}from"three";import{getCharacterMovementLike as S}from"./character-movement-like.js";import{CCDIKSolver as w}from"three/addons/animation/CCDIKSolver.js";import{World as b}from"../../../../services/world.js";import{PhysicsSystem as L,RayTestResult as v}from"../../../../services/physics/physics-system.js";import{ArrayMap as I}from"../../../../../utils/collections.js";import{getAnimationClipRigId as B,getAnimationRigChainBoneNames as P,getAnimationRigDataFromObject as x,getAnimationRigIdFromObject as R,setAnimationClipRigId as D}from"../../../../animation/retarget.js";const F=new d(0,-1,0),A=new d(0,1,0),M=new d(1,1,1),T=new f,W=new d,O=new d,V=new d,C=new d,E=new d,q=new f,H=new f,z=new f,N=new f,U=new g,j=new g,G=new d(1,0,0),Q=new d(0,1,0),$=new d(0,0,1);function _(){return{point:new d,normal:new d,hasNormal:!1}}const K=["mixamorigHips","Hips","hips","Pelvis","pelvis"],Y={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},J={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},X=["left","right"];let Z=class extends e{constructor(){super(...arguments),this.viewController=s(r),this.poseProcessors=new I,this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.externalControlActive=!1,this.world=s(b),this.physicsSystem=s(L),this.footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkAutoContactOffset=!1,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikLegState={left:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1},right:{targetPosition:new d,normal:new d(0,1,0),forward:new d(0,0,1),pitch:0,contactOffset:0,planted:!0,lastFootWorldPos:new d,hasLastFootSample:!1,weight:0,top:!1}},this.ikWarnedMissingBones=!1,this.raycaster=new c,this.raycastIntersections=[],this.footIkRayTo=new d,this.footIkRayTestResult=new v,this.footIkRayTestOptions={excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:_(),toe:_(),heel:_(),side:_()},this.footIkAxesScratch={up:new d,forward:new d,right:new d},this.footIkSampleAxesScratch={forward:new d,right:new d},this.footIkScratch={footWorldPos:new d,centerRayStart:new d,toeRayStart:new d,heelRayStart:new d,sideRayStart:new d,desiredTargetPos:new d,desiredNormal:new d,desiredForward:new d,debugRayEndA:new d,debugRayEndB:new d,debugRayEndC:new d,debugRayEndD:new d,debugRayEndE:new d,debugRayEndF:new d},this.ikPreSolve={left:{upper:new f,lower:new f,foot:new f},right:{upper:new f,lower:new f,foot:new f}},this.getFullBodyClip=it(t=>t.uuid,t=>tt(this.fullBodyMask,t)),this.getUpperBodyClip=it(t=>t.uuid,t=>tt(this.upperBodyMask,t))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=S(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,F),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(F,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&&(rt(t,e)||rt(e,t))}isFootIkDebugObject(t){let e=t;for(;null!=e;){if(!0===e.userData?.footIkDebug)return!0;e=e.parent}return!1}isSkinnedMeshObject(t){let e=t;for(;null!=e;){if(e instanceof p||!0===e.isSkinnedMesh)return!0;e=e.parent}return!1}getRootMotionAction(){if(this.fullBodyAction.getClip()instanceof i)return this.fullBodyAction}getFullBodyAction(){return this.fullBodyAction}setup(t,e,o){null!=e&&(this.upperBodyMask=et(e),this.fullBodyMask=function(t,e){const o=new Set(et(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof l||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(st(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new n(t),this.animationRigId=R(t),this.animationRigData=x(t),this.ikRoot=t,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority: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))}}runPoseProcessors(t,e){if(0===this.poseProcessors.size||null==this.mixer||!this.poseProcessors.present(t))return;const o=this.mixer.getRoot();if(!(o instanceof a))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){null!=this.mixer&&(this.externalControlActive||(this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),this.fullBodyAction&&this.fullBodyAction.loop===h&&this.fullBodyAction.getClip().duration-2*(this.overrideFadeTime??this.fadeTime)<this.fullBodyTimer&&(this.currentFullBodyPriority=-1,this.overrideFadeTime=null),null!=this.characterMovement&&(this.movementSpeed=this.characterMovement.horizontalSpeed),this.updateStateMachines(t),this.syncMovementSpeed(this.fullBodyAction),this.upperBodyOverride||this.syncMovementSpeed(this.upperBodyAction),this.runPoseProcessors("beforeMixer",t),this.mixer.update(t),this.runPoseProcessors("afterMixer",t),this.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)))}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=P(this.animationRigData,"leftLeg"),r=P(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,Y,s),a=this.resolveLegBoneRefs(i,this.rightLegIkBones,J,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.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(W)),this.ikLegState.right.targetPosition.copy(a.foot.getWorldPosition(W)),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=!0,this.ikLegState.right.planted=!0,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(W)),this.ikLegState.right.lastFootWorldPos.copy(a.foot.getWorldPosition(W)),this.ikLegState.left.hasLastFootSample=!0,this.ikLegState.right.hasLastFootSample=!0;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??st(t);if(null==p)return;let f=i.getBoneByName("_IKTargetLeftFoot"),y=i.getBoneByName("_IKTargetRightFoot"),m=!1;if(null==f&&(f=new l,f.name="_IKTargetLeftFoot",p.add(f),m=!0),null==y&&(y=new l,y.name="_IKTargetRightFoot",p.add(y),m=!0),this.setBoneWorldPosition(f,n.foot.getWorldPosition(W)),this.setBoneWorldPosition(y,a.foot.getWorldPosition(W)),m||i.bones.indexOf(f)<0||i.bones.indexOf(y)<0){const t=i.bones.slice(),e=i.boneInverses.map(t=>t.clone());t.indexOf(f)<0&&(t.push(f),e.push((new g).copy(f.matrixWorld).invert())),t.indexOf(y)<0&&(t.push(y),e.push((new g).copy(y.matrixWorld).invert())),o.bind(new u(t,e),o.bindMatrix)}this.ikTargetBones={left:f,right:y};const k=o.skeleton.bones,S={target:k.indexOf(f),effector:k.indexOf(n.foot),links:[{index:k.indexOf(n.lower)},{index:k.indexOf(n.upper)}],iteration:8},b={target:k.indexOf(y),effector:k.indexOf(a.foot),links:[{index:k.indexOf(a.lower)},{index:k.indexOf(a.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||b.target<0||b.effector<0||b.links.some(t=>t.index<0))return console.warn("[CharacterAnimationComponent] Foot IK disabled: failed to resolve IK indexes in skeleton."),void(this.ikSolver=null);this.ikSolver=new w(o,[S,b])}findFirstSkinnedMesh(t){let e;return t.traverse(t=>{null==e&&(t instanceof p||!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,...K].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(W),o=t.lower.getWorldPosition(O),i=t.foot.getWorldPosition(V),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(o.worldToLocal(W.copy(e))),t.quaternion.copy(T),t.scale.copy(M),t.updateMatrixWorld(!0)}syncFootIkDebug(){this.footIkDebug&&null!=this.ikRoot?(null!=this.ikDebugRoot&&null!=this.ikDebugLegs||(this.ikDebugRoot=new k,this.ikDebugRoot.name="FootIKDebug",this.ikDebugRoot.userData.footIkDebug=!0,this.ikDebugLegs={left:this.createDebugLeg("LeftFootIK",53503),right:this.createDebugLeg("RightFootIK",16755200)},this.ikDebugRoot.add(this.ikDebugLegs.left.root,this.ikDebugLegs.right.root),this.world.scene.add(this.ikDebugRoot)),this.ikDebugRoot.visible=!0):null!=this.ikDebugRoot&&(this.ikDebugRoot.visible=!1)}disposeFootIkDebug(){null!=this.ikDebugRoot&&(this.ikDebugRoot.removeFromParent(),this.ikDebugRoot.clear()),this.ikDebugRoot=null,this.ikDebugLegs=null}createDebugLeg(t,e){const o=new k;o.name=t,o.userData.footIkDebug=!0;const i=this.createDebugArrow(e),s=this.createDebugArrow(e),r=this.createDebugArrow(e),n=this.createDebugArrow(e),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new m(A,new d,.001,t);return e.userData.footIkDebug=!0,e.traverse(t=>{t.userData.footIkDebug=!0,t.raycast=()=>{}}),e.visible=!1,e}setDebugArrow(t,e,o){W.subVectors(o,e);const i=W.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(W.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.resetFootIkState(),void this.resetDebugVisibility();this.ikRoot.updateWorldMatrix(!0,!0);const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of X){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=e.foot.getWorldPosition(W);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,this.footIkAutoContactOffset?o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance):o.contactOffset=this.footIkFootOffset+this.footIkExtraClearance,o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of X){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=e.upper.getWorldPosition(W),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=y.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=y.lerp(this.ikPelvisOffsetY,o,i);const s=this.ikPelvisBone.getWorldPosition(O),r=V.copy(s).addScaledVector(A,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(this.ikPelvisBone.parent.worldToLocal(r)),this.ikPelvisBone.updateMatrixWorld(!0)}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance;if(!this.footIkAutoContactOffset)return i;const s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o),a=o.getWorldPosition(O),h=V.copy(n.upLocal).applyQuaternion(o.getWorldQuaternion(q)).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=U.copy(t.boneInverses[i]).invert(),n=j.copy(r).multiply(s),d=W.setFromMatrixPosition(n),p=C.copy(d).applyMatrix4(o.matrixWorld).sub(a);c=Math.min(c,p.dot(h))}),Math.max(i,-c+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=t.upper.getWorldPosition(W),i=t.foot.getWorldPosition(O),s=o.distanceTo(i);return e.total<=1e-6?1:y.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=C.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(A),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=e.getWorldPosition(r.footWorldPos),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(A,this.footIkRayStartHeight),p=r.toeRayStart.copy(d).addScaledVector(c.forward,this.footIkForwardSampleDistance),u=r.heelRayStart.copy(d).addScaledVector(c.forward,-this.footIkForwardSampleDistance),f=r.sideRayStart.copy(d).addScaledVector(c.right,this.footIkSideSampleDistance),g=this.getFirstGroundHit(d,n.center),m=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let L=0,v=0,I=this.footIkWeightOutSpeed;const B=null!=g||null!=m||null!=k;let P=l.y;null!=g?P=g.point.y:null!=m&&null!=k?P=.5*(m.point.y+k.point.y):null!=m?P=m.point.y:null!=k&&(P=k.point.y);const x=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],D=null!=x&&null!=R?this.computeLegExtensionRatio(x,R):1,F=Math.max(0,l.y-P,l.y-o.targetPosition.y),M=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,B,a,D,F);M?this.computeDesiredGroundNormal(c,g,m,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,m,k,b),L=this.computeDesiredPitchAngle(m,k,c.forward),v=1,I=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const T=1-Math.exp(-this.footIkPositionLerpSpeed*s),W=1-Math.exp(-I*s);o.normal.lerp(w,T).normalize(),o.forward.lerp(b,T).normalize(),o.pitch=y.lerp(o.pitch,L,T),o.weight=y.lerp(o.weight,v,W),o.planted=M&&v>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:m,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=h.getWorldPosition(l.footWorldPos),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(A,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),m=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(m,a.heel),L=this.getFirstGroundHit(k,a.side),v=l.desiredTargetPos.copy(c),I=l.desiredNormal.set(0,1,0),B=l.desiredForward.copy(u.forward);let P=0,x=0,R=this.footIkWeightOutSpeed;const D=null!=S||null!=w||null!=b;let F=c.y;null!=S?F=S.point.y:null!=w&&null!=b?F=.5*(w.point.y+b.point.y):null!=w?F=w.point.y:null!=b&&(F=b.point.y);const M=this.computeLegExtensionRatio(e,o),T=Math.max(0,c.y-F,c.y-s.targetPosition.y),W=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,D,d,M,T);if(W){if(v.copy(c),this.computeDesiredGroundNormal(u,S,w,b,L,I)){this.computeDesiredFootForward(u.forward,u.right,I,w,b,B),P=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(P))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);v.y=F+e+t,s.top&&(v.y-=this.ikPelvisOffsetY/2),x=1,R=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,I,null,null,B),v.copy(c),v.y+=this.footIkFootOffset;this.clampDesiredFootTarget(e,o,c,v);const O=1-Math.exp(-this.footIkPositionLerpSpeed*n),V=1-Math.exp(-R*n);s.targetPosition.lerp(v,O),s.normal.lerp(I,O).normalize(),s.forward.lerp(B,O).normalize(),s.pitch=y.lerp(s.pitch,P,O),s.weight=y.lerp(s.weight,x,V),s.planted=W&&x>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:m,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:L,desiredNormal:I,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(F,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(F,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(F,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(F,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new d,right:new d},n=this.actor.object.getWorldDirection(C);n.addScaledVector(A,-n.dot(A)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(A,-s.forward.dot(A)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=E.crossVectors(A,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,C);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=O.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=V.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(A),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(A)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.actor.object.getWorldDirection(C)),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=C.copy(this.actor.object.getWorldDirection(C));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=O.subVectors(t.point,e.point),s=Math.abs(i.dot(o));if(s<1e-5)return 0;const r=t.point.y-e.point.y,n=y.degToRad(this.footIkMaxSlopeAngleDeg);return y.clamp(-Math.atan2(r,s),-n,n)}applySimpleFootPitch(t,e,o){if(null==e.parent||o.weight<=.001)return;const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o.pitch*o.weight;if(Math.abs(s)<=1e-5)return;const r=this.resolveLocalPitchSign(i),n=q.copy(e.quaternion),l=H.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=z.setFromAxisAngle(t.rightLocal,.15);return V.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=O.subVectors(i,o),r=s.dot(A),n=V.copy(s).addScaledVector(A,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=y.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(A,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(W).clone(),c=O.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(W).clone(),s=e.lower.getWorldPosition(O).clone(),r=e.foot.getWorldPosition(V).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new d).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,p=n+l-1e-4,u=y.clamp(h,c,p),f=a.multiplyScalar(1/h),g=(new d).subVectors(s,i).normalize(),m=(new d).subVectors(r,s).normalize(),k=(new d).crossVectors(g,m);k.lengthSq()<1e-8&&(k.copy(this.actor.object.getWorldDirection(W).cross(A)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),L=(new d).copy(i).addScaledVector(f,S);let v=(new d).crossVectors(k,f);v.lengthSq()<1e-8&&(v=(new d).crossVectors(f,A),v.lengthSq()<1e-8&&(v=new d(1,0,0))),v.normalize();const I=(new d).copy(L).addScaledVector(v,b),B=(new d).copy(L).addScaledVector(v,-b),P=(new d).subVectors(s,L).dot(v)>=0?I:B;this.rotateBoneToward(e.upper,i,s,P),e.upper.updateMatrixWorld(!0);const x=e.lower.getWorldPosition(O),R=e.foot.getWorldPosition(V);this.rotateBoneToward(e.lower,x,R,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,P,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new d).subVectors(o,e),r=(new d).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new f).setFromUnitVectors(s,r),l=t.getWorldQuaternion(q),a=H.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=t.parent.getWorldQuaternion(z),c=N.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=t.getWorldQuaternion(q),o=this.actor.object.getWorldDirection(W);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:G.clone(),world:G.clone().applyQuaternion(e)},{local:Q.clone(),world:Q.clone().applyQuaternion(e)},{local:$.clone(),world:$.clone().applyQuaternion(e)}];i.push({local:G.clone().multiplyScalar(-1),world:G.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:Q.clone().multiplyScalar(-1),world:Q.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:$.clone().multiplyScalar(-1),world:$.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(A);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new d,forward:new d,right:new d},r=e.getWorldQuaternion(q);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}clampSlopeNormal(t){const e=y.clamp(t.dot(A),-1,1),o=Math.acos(e),i=y.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(A,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){q.copy(t.quaternion),t.quaternion.copy(e).slerp(q,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=W.copy(o.normal).normalize(),n=O.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=V.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(C.crossVectors(l,r)).normalize(),U.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),q.setFromRotationMatrix(U),j.makeBasis(l,r,n),H.setFromRotationMatrix(j);const a=z.copy(H).multiply(N.copy(q).invert()),h=e.parent.getWorldQuaternion(N),c=H.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,y.clamp(d,0,1))}getMixer(){return this.mixer}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,null==this.fullBodyAction||this.fullBodyAction.isRunning()||(this.fullBodyAction=null),null==this.upperBodyAction||this.upperBodyAction.isRunning()||(this.upperBodyAction=null),this.fullBodyTimer=0}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={}){ot(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 o.setLoop(h,1),o.clampWhenFinished=!0,o.timeScale=e.timeScale??1,o.reset(),o.play(),this.fullBodyAction=o,this.externalControlActive=!0,o}syncMovementSpeed(t){if(null!=t){const e=t.getClip();if(e instanceof i&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof a&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){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={}){ot(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}assertClipRigCompatible(t){const e=B(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!nt.has(o)){if(nt.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 i=o?.fadeTime??this.fadeTime;if(null!=t&&t.getClip().uuid===e.uuid)return!t.isRunning()&&!1===o.loop&&t.clampWhenFinished||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(h,1),t.clampWhenFinished=!0)),t;if(t&&t.isRunning()){const s=t,r=this.mixer.clipAction(e);r.reset(),null!=o.offset&&(r.time=o.offset),r.play(),r.enabled=!0,r.setEffectiveTimeScale(1),r.weight=1,s.crossFadeTo(r,i,!0),t=r}else(t=this.mixer.clipAction(e)).reset(),null!=o.offset&&(t.time=o.offset),t.enabled=!0,t.weight=1,t.setEffectiveWeight(1),t.setEffectiveTimeScale(1),t.play();return!1===o.loop&&(t.setLoop(h,1),t.clampWhenFinished=!0),t}};Z=t([o({inEditor:!0})],Z);export{Z as CharacterAnimationComponent};function tt(t,e){if(null==t)return e;const o=e.clone();D(o,B(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 et(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof l)}function ot(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function it(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 st(t){let e;return t.traverse(t=>{(t instanceof l||t.isBone)&&null==e&&(e=t)}),e}function rt(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const nt=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 l,Bone as a,Object3D as h,LoopOnce as c,Raycaster as d,Vector3 as p,SkinnedMesh as u,Skeleton as f,Quaternion as g,Matrix4 as y,MathUtils as m,ArrowHelper as k,Group as S}from"three";import{getCharacterMovementLike as w}from"./character-movement-like.js";import{CCDIKSolver as b}from"three/addons/animation/CCDIKSolver.js";import{World as L}from"../../../../services/world.js";import{PhysicsSystem as v,RayTestResult as I}from"../../../../services/physics/physics-system.js";import{ArrayMap as B}from"../../../../../utils/collections.js";import{getAnimationClipRigId as P,getAnimationRigChainBoneNames as x,getAnimationRigDataFromObject as R,getAnimationRigIdFromObject as D,setAnimationClipRigId as F}from"../../../../animation/retarget.js";const A=new p(0,-1,0),M=new p(0,1,0),T=new p(1,1,1),W=new g,O=new p,V=new p,C=new p,E=new p,q=new p,H=new g,z=new g,N=new g,U=new g,j=new y,G=new y,Q=new p(1,0,0),$=new p(0,1,0),_=new p(0,0,1);function K(){return{point:new p,normal:new p,hasNormal:!1}}const Y=["mixamorigHips","Hips","hips","Pelvis","pelvis"],J={upper:["LeftUpLeg","leftUpLeg","left_up_leg"],lower:["LeftLeg","leftLeg","left_leg"],foot:["LeftFoot","leftFoot","left_foot"]},X={upper:["RightUpLeg","rightUpLeg","right_up_leg"],lower:["RightLeg","rightLeg","right_leg"],foot:["RightFoot","rightFoot","right_foot"]},Z=["left","right"];let tt=class extends e{constructor(){super(...arguments),this.viewController=r(n),this.poseProcessors=new B,this.stateMachines=[],this.upperStateMachines=[],this.fadeTime=.2,this.movementSpeed=null,this.upperBodyTimer=0,this.upperBodyOverride=!1,this.fullBodyTimer=0,this.currentFullBodyPriority=-1,this.currentUpperBodyPriority=-1,this.externalControlActive=!1,this.world=r(L),this.physicsSystem=r(v),this.footIkEnabled=!1,this.footIkMoving=!1,this.footIkRayStartHeight=.5,this.footIkRayLength=1.5,this.footIkRaycastMode="physics",this.footIkFootOffset=.08,this.footIkAutoContactOffset=!1,this.footIkPositionLerpSpeed=28,this.footIkRotationLerpSpeed=14,this.footIkWeightInSpeed=34,this.footIkWeightOutSpeed=30,this.footIkMaxSlopeAngleDeg=40,this.footIkForwardSampleDistance=.14,this.footIkSideSampleDistance=.08,this.footIkMaxHorizontalOffset=.22,this.footIkMaxVerticalOffsetDown=.75,this.footIkMaxVerticalOffsetUp=.2,this.footIkPelvisEnabled=!0,this.footIkPelvisBone="mixamorigHips",this.footIkPelvisLerpSpeed=24,this.footIkPelvisMaxOffsetDown=.4,this.footIkPelvisMaxOffsetUp=.08,this.footIkRequireGrounded=!0,this.footIkSimpleTiltOnly=!1,this.footIkDebug=!1,this.footIkDebugNormalLength=.25,this.footIkDebugAxisLength=.2,this.footIkExtraClearance=.01,this.footIkPlantReleaseUpSpeed=.08,this.footIkPlantReleaseExtension=.9,this.footIkPlantAttachExtension=.96,this.footIkPlantReleaseLift=.055,this.footIkPlantAttachLift=.02,this.leftLegIkBones={upperLeg:"mixamorigLeftUpLeg",lowerLeg:"mixamorigLeftLeg",foot:"mixamorigLeftFoot"},this.rightLegIkBones={upperLeg:"mixamorigRightUpLeg",lowerLeg:"mixamorigRightLeg",foot:"mixamorigRightFoot"},this.ikPelvisOffsetY=0,this.ikLegState={left:{targetPosition:new 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:{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 I,this.footIkRayTestOptions={debug:!1,excludeTriggers:!0,resolveActor:!1,collisionFilter:-2},this.footIkHits={center:K(),toe:K(),heel:K(),side:K()},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},right:{upper:new g,lower:new g,foot:new g}},this.getFullBodyClip=st(t=>t.uuid,t=>et(this.fullBodyMask,t)),this.getUpperBodyClip=st(t=>t.uuid,t=>et(this.upperBodyMask,t))}onInit(){this.viewController.onUpdate(this.actor).subscribe(t=>this.updateInternal(t)),this.characterMovement=w(this.actor),this.footIkRayTestOptions.excludeActor=this.actor}onEndPlay(){this.disposeFootIkDebug()}raycastDownFirstValid(t,e,o){const i=this.world.scene;this.raycaster.set(t,A),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(A,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&&(nt(t,e)||nt(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}setup(t,e,o){null!=e&&(this.upperBodyMask=ot(e),this.fullBodyMask=function(t,e){const o=new Set(ot(e).map(t=>t.uuid)),i=[];return t.traverse(t=>{(t instanceof a||t.isBone)&&!o.has(t.uuid)&&i.push(t)}),i}(rt(t),e)),null!=this.mixer&&this.mixer.stopAllAction(),this.mixer=new l(t),this.animationRigId=D(t),this.animationRigData=R(t),this.ikRoot=t,this.disposeFootIkDebug(),this.initializeFootIk(t,o),this.syncFootIkDebug()}updateStateMachines(t){this.stateMachines.forEach(e=>{e.step(t);const o=e.current.clip;null!=o&&this.play(o,{priority: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))}}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){null!=this.mixer&&(this.externalControlActive||(this.upperBodyTimer+=t*(this.upperBodyAction?.timeScale??1),this.fullBodyTimer+=t*(this.fullBodyAction?.timeScale??1),this.upperBodyAction&&this.upperBodyOverride&&this.upperBodyAction.getClip().duration-2*(this.overrideFadeTimeUpper??this.fadeTime)<this.upperBodyTimer&&(this.upperBodyOverride=!1,null!=this.fullBodyClip&&this.transition(this.upperBodyAction,this.getUpperBodyClip(this.fullBodyClip)),this.upperBodyAction=null,this.overrideFadeTimeUpper=null),this.fullBodyAction&&this.fullBodyAction.loop===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),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.runPoseProcessors("beforeIk",t),this.updateFootIk(t),this.runPoseProcessors("afterIk",t)))}initializeFootIk(t,e){if(this.ikSolver=null,this.ikSkinnedMesh=null,this.ikBoneRefs=null,this.ikLegLengths=null,this.ikPelvisBone=null,this.ikPelvisOffsetY=0,this.ikFootAxes=null,this.ikTargetBones=null,this.ikWarnedMissingBones=!1,this.ikLegState.left.weight=0,this.ikLegState.right.weight=0,!this.footIkEnabled)return;const o=this.findFirstSkinnedMesh(t);if(null==o||null==o.skeleton)return;this.ikSkinnedMesh=o,t.updateWorldMatrix(!0,!0);const i=o.skeleton,s=x(this.animationRigData,"leftLeg"),r=x(this.animationRigData,"rightLeg"),n=this.resolveLegBoneRefs(i,this.leftLegIkBones,J,s),l=this.resolveLegBoneRefs(i,this.rightLegIkBones,X,r);if(null==n||null==l)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:l},this.ikLegLengths={left:this.computeLegLengths(n),right:this.computeLegLengths(l)},this.ikFootAxes={left:this.detectFootAxisBasis(n.foot),right:this.detectFootAxisBasis(l.foot)};const h=this.animationRigData?.bones.find(t=>t.id===this.animationRigData?.pelvisBoneId)?.name;this.ikPelvisBone=this.resolvePelvisBone(i,n,l,h),this.ikLegState.left.targetPosition.copy(n.foot.getWorldPosition(O)),this.ikLegState.right.targetPosition.copy(l.foot.getWorldPosition(O)),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",l.foot),this.ikLegState.left.planted=!1,this.ikLegState.right.planted=!1,this.ikLegState.left.lastFootWorldPos.copy(n.foot.getWorldPosition(O)),this.ikLegState.right.lastFootWorldPos.copy(l.foot.getWorldPosition(O)),this.ikLegState.left.hasLastFootSample=!1,this.ikLegState.right.hasLastFootSample=!1;const c=this.resolveFootAxes("left",n.foot),d=this.resolveFootAxes("right",l.foot);this.ikLegState.left.forward.copy(c.forward),this.ikLegState.right.forward.copy(d.forward);const p=e??rt(t);if(null==p)return;let u=i.getBoneByName("_IKTargetLeftFoot"),g=i.getBoneByName("_IKTargetRightFoot"),m=!1;if(null==u&&(u=new a,u.name="_IKTargetLeftFoot",p.add(u),m=!0),null==g&&(g=new a,g.name="_IKTargetRightFoot",p.add(g),m=!0),this.setBoneWorldPosition(u,n.foot.getWorldPosition(O)),this.setBoneWorldPosition(g,l.foot.getWorldPosition(O)),m||i.bones.indexOf(u)<0||i.bones.indexOf(g)<0){const t=i.bones.slice(),e=i.boneInverses.map(t=>t.clone());t.indexOf(u)<0&&(t.push(u),e.push((new y).copy(u.matrixWorld).invert())),t.indexOf(g)<0&&(t.push(g),e.push((new y).copy(g.matrixWorld).invert())),o.bind(new f(t,e),o.bindMatrix)}this.ikTargetBones={left:u,right:g};const k=o.skeleton.bones,S={target:k.indexOf(u),effector:k.indexOf(n.foot),links:[{index:k.indexOf(n.lower)},{index:k.indexOf(n.upper)}],iteration:8},w={target:k.indexOf(g),effector:k.indexOf(l.foot),links:[{index:k.indexOf(l.lower)},{index:k.indexOf(l.upper)}],iteration:8};if(S.target<0||S.effector<0||S.links.some(t=>t.index<0)||w.target<0||w.effector<0||w.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 b(o,[S,w])}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,...Y].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 a||!0===r.isBone)||null!=r&&(r instanceof a||!0===r.isBone)?r:void 0}computeLegLengths(t){const e=t.upper.getWorldPosition(O),o=t.lower.getWorldPosition(V),i=t.foot.getWorldPosition(C),s=e.distanceTo(o),r=o.distanceTo(i);return{upper:s,lower:r,total:s+r}}setBoneWorldPosition(t,e){const o=t.parent;null==o?t.position.copy(e):t.position.copy(o.worldToLocal(O.copy(e))),t.quaternion.copy(W),t.scale.copy(T),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),l=this.createDebugArrow(65280),a=this.createDebugArrow(6750054),h=this.createDebugArrow(16711935),c=this.createDebugArrow(16776960),d=this.createDebugArrow(16737792);return o.add(i,s,r,n,l,a,h,c,d),{root:o,rayCenter:i,rayToe:s,rayHeel:r,raySide:n,hitNormal:l,footUp:a,footToTarget:h,solveUpper:c,solveLower:d}}createDebugArrow(t){const e=new k(M,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){O.subVectors(o,e);const i=O.length();i<1e-6?t.visible=!1:(t.visible=!0,t.position.copy(e),t.setDirection(O.multiplyScalar(1/i)),t.setLength(i,Math.min(.08,.25*i),Math.min(.05,.2*i)))}resetDebugVisibility(){null!=this.ikDebugLegs&&(this.ikDebugLegs.left.rayCenter.visible=!1,this.ikDebugLegs.left.rayToe.visible=!1,this.ikDebugLegs.left.rayHeel.visible=!1,this.ikDebugLegs.left.raySide.visible=!1,this.ikDebugLegs.left.hitNormal.visible=!1,this.ikDebugLegs.left.footUp.visible=!1,this.ikDebugLegs.left.footToTarget.visible=!1,this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.rayCenter.visible=!1,this.ikDebugLegs.right.rayToe.visible=!1,this.ikDebugLegs.right.rayHeel.visible=!1,this.ikDebugLegs.right.raySide.visible=!1,this.ikDebugLegs.right.hitNormal.visible=!1,this.ikDebugLegs.right.footUp.visible=!1,this.ikDebugLegs.right.footToTarget.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1)}updateFootIk(t){if(this.syncFootIkDebug(),!this.footIkEnabled||null==this.ikBoneRefs||null==this.ikRoot)return void this.resetDebugVisibility();if(!this.footIkMoving&&(this.movementSpeed??0)>.01)return this.resetFootIkState(),void this.resetDebugVisibility();this.ikRoot.updateWorldMatrix(!0,!0);const e=this.characterMovement?.isGrounded??!0;return this.footIkSimpleTiltOnly?(this.updatePelvisOffset(t,!1),this.updateLegTiltSimple("left",this.ikBoneRefs.left.foot,this.ikLegState.left,e,t),void this.updateLegTiltSimple("right",this.ikBoneRefs.right.foot,this.ikLegState.right,e,t)):null==this.ikLegLengths||null==this.ikTargetBones||null==this.ikSkinnedMesh||null==this.ikSolver?(this.updatePelvisOffset(t,!1),void this.resetDebugVisibility()):(this.updateLegIkTarget("left",this.ikBoneRefs.left,this.ikLegLengths.left,this.ikTargetBones.left,this.ikLegState.left,e,t),this.updateLegIkTarget("right",this.ikBoneRefs.right,this.ikLegLengths.right,this.ikTargetBones.right,this.ikLegState.right,e,t),this.updatePelvisOffset(t,!0),this.setBoneWorldPosition(this.ikTargetBones.left,this.ikLegState.left.targetPosition),this.setBoneWorldPosition(this.ikTargetBones.right,this.ikLegState.right.targetPosition),this.ikPreSolve.left.upper.copy(this.ikBoneRefs.left.upper.quaternion),this.ikPreSolve.left.lower.copy(this.ikBoneRefs.left.lower.quaternion),this.ikPreSolve.left.foot.copy(this.ikBoneRefs.left.foot.quaternion),this.ikPreSolve.right.upper.copy(this.ikBoneRefs.right.upper.quaternion),this.ikPreSolve.right.lower.copy(this.ikBoneRefs.right.lower.quaternion),this.ikPreSolve.right.foot.copy(this.ikBoneRefs.right.foot.quaternion),null!=this.ikDebugLegs&&(this.ikDebugLegs.left.solveUpper.visible=!1,this.ikDebugLegs.left.solveLower.visible=!1,this.ikDebugLegs.right.solveUpper.visible=!1,this.ikDebugLegs.right.solveLower.visible=!1),this.ikSolver.update(),this.blendLegAfterSolve(this.ikBoneRefs.left,this.ikPreSolve.left,this.ikLegState.left.weight),this.blendLegAfterSolve(this.ikBoneRefs.right,this.ikPreSolve.right,this.ikLegState.right.weight),this.applySimpleFootPitch("left",this.ikBoneRefs.left.foot,this.ikLegState.left),void this.applySimpleFootPitch("right",this.ikBoneRefs.right.foot,this.ikLegState.right))}resetFootIkState(){if(null!=this.ikBoneRefs){for(const t of Z){const e=this.ikBoneRefs[t],o=this.ikLegState[t],i=e.foot.getWorldPosition(O);o.targetPosition.copy(i),o.lastFootWorldPos.copy(i),o.hasLastFootSample=!0,o.weight=0,o.normal.set(0,1,0);const s=this.resolveFootAxes(t,e.foot,this.footIkAxesScratch);o.forward.copy(s.forward),o.pitch=0,this.footIkAutoContactOffset?o.contactOffset=Math.max(o.contactOffset,this.footIkFootOffset+this.footIkExtraClearance):o.contactOffset=this.footIkFootOffset+this.footIkExtraClearance,o.planted=!1}this.ikPelvisOffsetY=0}}updatePelvisOffset(t,e){if(null==this.ikPelvisBone)return;let o=0;if(e&&this.footIkPelvisEnabled&&null!=this.ikBoneRefs&&null!=this.ikLegLengths){this.ikLegState.left.top=!1,this.ikLegState.right.top=!1;for(const t of Z){const e=this.ikBoneRefs[t],i=this.ikLegLengths[t],s=this.ikLegState[t];if(!s.planted)continue;const r=e.upper.getWorldPosition(O),n=.998*i.total,l=this.computeRequiredPelvisDrop(r,s.targetPosition,n);if(l>0){const e="left"===t?"right":"left";this.ikLegState[e].top=!0}o=Math.min(o,-l)}o=m.clamp(o,-this.footIkPelvisMaxOffsetDown,this.footIkPelvisMaxOffsetUp)}const i=1-Math.exp(-this.footIkPelvisLerpSpeed*t);this.ikPelvisOffsetY=m.lerp(this.ikPelvisOffsetY,o,i);const s=this.ikPelvisBone.getWorldPosition(V),r=C.copy(s).addScaledVector(M,this.ikPelvisOffsetY);null==this.ikPelvisBone.parent?this.ikPelvisBone.position.copy(r):this.ikPelvisBone.position.copy(this.ikPelvisBone.parent.worldToLocal(r)),this.ikPelvisBone.updateMatrixWorld(!0)}computeFootVerticalSpeed(t,e,o){return!t.hasLastFootSample||o<=1e-6?0:(e.y-t.lastFootWorldPos.y)/o}updateFootSample(t,e){t.lastFootWorldPos.copy(e),t.hasLastFootSample=!0}estimateFootContactOffset(t,e,o){const i=this.footIkFootOffset+this.footIkExtraClearance;if(!this.footIkAutoContactOffset)return i;const s=t.bones.indexOf(o);if(s<0)return i;const r=t.boneInverses[s];if(null==r)return i;const n=this.ikFootAxes?.[e]??this.detectFootAxisBasis(o),l=o.getWorldPosition(V),h=C.copy(n.upLocal).applyQuaternion(o.getWorldQuaternion(H)).normalize();let c=0;return o.traverse(e=>{if(!(e instanceof a)||e===o)return;const i=t.bones.indexOf(e);if(i<0)return;const s=j.copy(t.boneInverses[i]).invert(),n=G.copy(r).multiply(s),d=O.setFromMatrixPosition(n),p=E.copy(d).applyMatrix4(o.matrixWorld).sub(l);c=Math.min(c,p.dot(h))}),Math.max(i,-c+this.footIkExtraClearance)}shouldPlantFoot(t,e,o,i,s,r){if(!e||!o)return!1;const n=this.footIkPlantReleaseExtension,l=this.footIkPlantAttachExtension,a=this.footIkPlantReleaseLift,h=this.footIkPlantAttachLift;return t.planted?!(i>this.footIkPlantReleaseUpSpeed&&(s<n||r>a)):s>=l&&r<=h||i<=0&&s>=n}computeLegExtensionRatio(t,e){const o=t.upper.getWorldPosition(O),i=t.foot.getWorldPosition(V),s=o.distanceTo(i);return e.total<=1e-6?1:m.clamp(s/e.total,0,1.2)}computeRequiredPelvisDrop(t,e,o){const i=E.subVectors(t,e),s=i.length();if(s<=o+1e-6)return 0;const r=i.dot(M),n=o*o-Math.max(s*s-r*r,0);if(n<=0)return s-o;const l=Math.sqrt(n),a=r-l,h=r+l;return a>=0?a:h>=0?h:0}updateLegTiltSimple(t,e,o,i,s){const r=this.footIkScratch,n=this.footIkHits,l=e.getWorldPosition(r.footWorldPos),a=this.computeFootVerticalSpeed(o,l,s),h=this.resolveFootAxes(t,e,this.footIkAxesScratch),c=this.resolveGroundSampleAxes(t,e,h,this.footIkSampleAxesScratch),d=r.centerRayStart.copy(l).addScaledVector(M,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),y=this.getFirstGroundHit(p,n.toe),k=this.getFirstGroundHit(u,n.heel),S=this.getFirstGroundHit(f,n.side),w=r.desiredNormal.set(0,1,0),b=r.desiredForward.copy(c.forward);let L=0,v=0,I=this.footIkWeightOutSpeed;const B=null!=g||null!=y||null!=k;let P=l.y;null!=g?P=g.point.y:null!=y&&null!=k?P=.5*(y.point.y+k.point.y):null!=y?P=y.point.y:null!=k&&(P=k.point.y);const x=this.ikBoneRefs?.[t],R=this.ikLegLengths?.[t],D=null!=x&&null!=R?this.computeLegExtensionRatio(x,R):1,F=Math.max(0,l.y-P,l.y-o.targetPosition.y),A=this.shouldPlantFoot(o,!this.footIkRequireGrounded||i,B,a,D,F);A?this.computeDesiredGroundNormal(c,g,y,k,S,w)&&(this.computeDesiredFootForward(c.forward,c.right,w,y,k,b),L=this.computeDesiredPitchAngle(y,k,c.forward),v=1,I=this.footIkWeightInSpeed):this.computeDesiredFootForward(c.forward,c.right,w,null,null,b);const T=1-Math.exp(-this.footIkPositionLerpSpeed*s),W=1-Math.exp(-I*s);o.normal.lerp(w,T).normalize(),o.forward.lerp(b,T).normalize(),o.pitch=m.lerp(o.pitch,L,T),o.weight=m.lerp(o.weight,v,W),o.planted=A&&v>.001,this.updateFootSample(o,l),this.applySimpleFootPitch(t,e,o),this.updateLegDebug(t,{footWorldPos:l,centerRayStart:d,toeRayStart:p,heelRayStart:u,sideRayStart:f,centerHit:g,toeHit:y,heelHit:k,sideHit:S,desiredNormal:o.normal,desiredTargetPos:r.footWorldPos,weight:o.weight})}updateLegIkTarget(t,e,o,i,s,r,n){const l=this.footIkScratch,a=this.footIkHits,h=e.foot,c=h.getWorldPosition(l.footWorldPos),d=this.computeFootVerticalSpeed(s,c,n),p=this.resolveFootAxes(t,h,this.footIkAxesScratch),u=this.resolveGroundSampleAxes(t,h,p,this.footIkSampleAxesScratch),f=l.centerRayStart.copy(c).addScaledVector(M,this.footIkRayStartHeight),g=l.toeRayStart.copy(f).addScaledVector(u.forward,this.footIkForwardSampleDistance),y=l.heelRayStart.copy(f).addScaledVector(u.forward,-this.footIkForwardSampleDistance),k=l.sideRayStart.copy(f).addScaledVector(u.right,this.footIkSideSampleDistance),S=this.getFirstGroundHit(f,a.center),w=this.getFirstGroundHit(g,a.toe),b=this.getFirstGroundHit(y,a.heel),L=this.getFirstGroundHit(k,a.side),v=l.desiredTargetPos.copy(c),I=l.desiredNormal.set(0,1,0),B=l.desiredForward.copy(u.forward);let P=0,x=0,R=this.footIkWeightOutSpeed;const D=null!=S||null!=w||null!=b;let F=c.y;null!=S?F=S.point.y:null!=w&&null!=b?F=.5*(w.point.y+b.point.y):null!=w?F=w.point.y:null!=b&&(F=b.point.y);const A=this.computeLegExtensionRatio(e,o),T=Math.max(0,c.y-F,c.y-s.targetPosition.y),W=this.shouldPlantFoot(s,!this.footIkRequireGrounded||r,D,d,A,T);if(W){if(v.copy(c),this.computeDesiredGroundNormal(u,S,w,b,L,I)){this.computeDesiredFootForward(u.forward,u.right,I,w,b,B),P=this.computeDesiredPitchAngle(w,b,u.forward);const t=Math.max(0,Math.sin(P))*this.footIkForwardSampleDistance*.45,e=Math.max(this.footIkFootOffset+this.footIkExtraClearance,s.contactOffset);v.y=F+e+t,s.top&&(v.y-=this.ikPelvisOffsetY/2),x=1,R=this.footIkWeightInSpeed}}else this.computeDesiredFootForward(u.forward,u.right,I,null,null,B),v.copy(c),v.y+=this.footIkFootOffset;this.clampDesiredFootTarget(e,o,c,v);const O=1-Math.exp(-this.footIkPositionLerpSpeed*n),V=1-Math.exp(-R*n);s.targetPosition.lerp(v,O),s.normal.lerp(I,O).normalize(),s.forward.lerp(B,O).normalize(),s.pitch=m.lerp(s.pitch,P,O),s.weight=m.lerp(s.weight,x,V),s.planted=W&&x>.001,this.updateFootSample(s,c),this.setBoneWorldPosition(i,s.targetPosition),this.updateLegDebug(t,{footWorldPos:c,centerRayStart:f,toeRayStart:g,heelRayStart:y,sideRayStart:k,centerHit:S,toeHit:w,heelHit:b,sideHit:L,desiredNormal:I,desiredTargetPos:s.targetPosition,weight:s.weight})}updateLegDebug(t,e){if(!this.footIkDebug||null==this.ikDebugLegs||null==this.ikBoneRefs)return;const o=this.ikDebugLegs[t],i=this.ikBoneRefs[t],s=this.resolveFootAxes(t,i.foot,this.footIkAxesScratch),r=this.footIkScratch,n=e.centerHit?.point??r.debugRayEndA.copy(e.centerRayStart).addScaledVector(A,this.footIkRayLength),l=e.toeHit?.point??r.debugRayEndB.copy(e.toeRayStart).addScaledVector(A,this.footIkRayLength),a=e.heelHit?.point??r.debugRayEndC.copy(e.heelRayStart).addScaledVector(A,this.footIkRayLength),h=e.sideHit?.point??r.debugRayEndD.copy(e.sideRayStart).addScaledVector(A,this.footIkRayLength);this.setDebugArrow(o.rayCenter,e.centerRayStart,n),this.setDebugArrow(o.rayToe,e.toeRayStart,l),this.setDebugArrow(o.rayHeel,e.heelRayStart,a),this.setDebugArrow(o.raySide,e.sideRayStart,h);const c=e.centerHit?.point??e.toeHit?.point??e.heelHit?.point??e.sideHit?.point??e.footWorldPos;this.setDebugArrow(o.hitNormal,c,r.debugRayEndE.copy(c).addScaledVector(e.desiredNormal,this.footIkDebugNormalLength)),this.setDebugArrow(o.footUp,e.footWorldPos,r.debugRayEndF.copy(e.footWorldPos).addScaledVector(s.up,this.footIkDebugAxisLength*(.15+e.weight))),this.setDebugArrow(o.footToTarget,e.footWorldPos,e.desiredTargetPos)}getFirstGroundHit(t,e){return"physics"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)?e:null:"physicsThenRender"===this.footIkRaycastMode?this.rayTestDown(t,this.footIkRayLength,e)||this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null:this.raycastDownFirstValid(t,this.footIkRayLength,e)?e:null}resolveGroundSampleAxes(t,e,o,i){const s=o??this.resolveFootAxes(t,e),r=i??{forward:new p,right:new p},n=this.actor.object.getWorldDirection(E);n.addScaledVector(M,-n.dot(M)),n.lengthSq()<1e-8&&n.copy(s.forward).addScaledVector(M,-s.forward.dot(M)),n.lengthSq()<1e-8&&n.set(0,0,1),n.normalize();const l=q.crossVectors(M,n);return l.lengthSq()<1e-8?l.copy(s.right):l.normalize(),l.dot(s.right)<0&&l.multiplyScalar(-1),r.forward.copy(n),r.right.copy(l),r}computeDesiredGroundNormal(t,e,o,i,s,r){const n=this.computeAverageHitNormal(e,o,i,s,E);let l=!1,a=0,h=0;if(null!=o&&null!=i){const e=V.subVectors(o.point,i.point).dot(t.forward);Math.abs(e)>1e-5&&(a=(o.point.y-i.point.y)/e,l=!0)}if(null!=s&&null!=e){const o=C.subVectors(s.point,e.point).dot(t.right);Math.abs(o)>1e-5&&(h=(s.point.y-e.point.y)/o,l=!0)}if(l&&(r.copy(M),r.addScaledVector(t.forward,-a),r.addScaledVector(t.right,-h),r.lengthSq()>1e-8?r.normalize():l=!1),l)null!=n&&r.dot(n)<0&&r.multiplyScalar(-1);else{if(null==n)return!1;r.copy(n),l=!0}return r.dot(M)<0&&r.multiplyScalar(-1),this.clampSlopeNormal(r),!0}computeAverageHitNormal(t,e,o,i,s){s.set(0,0,0);let r=0;return null!=t&&t.hasNormal&&(s.add(t.normal),r++),null!=e&&e.hasNormal&&(s.add(e.normal),r++),null!=o&&o.hasNormal&&(s.add(o.normal),r++),null!=i&&i.hasNormal&&(s.add(i.normal),r++),0===r||s.lengthSq()<1e-8?null:(s.multiplyScalar(1/r).normalize(),s)}computeDesiredFootForward(t,e,o,i,s,r){null!=i&&null!=s?r.subVectors(i.point,s.point):r.copy(t),r.addScaledVector(o,-r.dot(o)),r.lengthSq()<1e-8&&(r.copy(this.actor.object.getWorldDirection(E)),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=E.copy(this.actor.object.getWorldDirection(E));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=V.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=m.degToRad(this.footIkMaxSlopeAngleDeg);return m.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=H.copy(e.quaternion),l=z.setFromAxisAngle(i.rightLocal,s*r);e.quaternion.copy(n.multiply(l))}resolveLocalPitchSign(t){const e=N.setFromAxisAngle(t.rightLocal,.15);return C.copy(t.upLocal).applyQuaternion(e).sub(t.upLocal).dot(t.forwardLocal)>=0?1:-1}clampDesiredFootTarget(t,e,o,i){const s=V.subVectors(i,o),r=s.dot(M),n=C.copy(s).addScaledVector(M,-r),l=n.length();l>this.footIkMaxHorizontalOffset&&l>1e-6&&n.multiplyScalar(this.footIkMaxHorizontalOffset/l);const a=m.clamp(r,-this.footIkMaxVerticalOffsetDown,this.footIkMaxVerticalOffsetUp);if(i.copy(o),i.add(n),i.addScaledVector(M,a),this.footIkPelvisEnabled)return;const h=t.upper.getWorldPosition(O).clone(),c=V.subVectors(i,h),d=c.length(),p=.995*e.total;d>p&&d>1e-6&&i.copy(h).addScaledVector(c,p/d)}solveTwoBoneLeg(t,e,o){const i=e.upper.getWorldPosition(O).clone(),s=e.lower.getWorldPosition(V).clone(),r=e.foot.getWorldPosition(C).clone(),n=i.distanceTo(s),l=s.distanceTo(r);if(n<1e-5||l<1e-5)return;const a=(new p).subVectors(o,i),h=a.length();if(h<1e-5)return;const c=Math.abs(n-l)+1e-4,d=n+l-1e-4,u=m.clamp(h,c,d),f=a.multiplyScalar(1/h),g=(new p).subVectors(s,i).normalize(),y=(new p).subVectors(r,s).normalize(),k=(new p).crossVectors(g,y);k.lengthSq()<1e-8&&(k.copy(this.actor.object.getWorldDirection(O).cross(M)),k.lengthSq()<1e-8&&k.set(1,0,0)),k.normalize();const S=(u*u+n*n-l*l)/(2*u),w=Math.max(n*n-S*S,0),b=Math.sqrt(w),L=(new p).copy(i).addScaledVector(f,S);let v=(new p).crossVectors(k,f);v.lengthSq()<1e-8&&(v=(new p).crossVectors(f,M),v.lengthSq()<1e-8&&(v=new p(1,0,0))),v.normalize();const I=(new p).copy(L).addScaledVector(v,b),B=(new p).copy(L).addScaledVector(v,-b),P=(new p).subVectors(s,L).dot(v)>=0?I:B;this.rotateBoneToward(e.upper,i,s,P),e.upper.updateMatrixWorld(!0);const x=e.lower.getWorldPosition(V),R=e.foot.getWorldPosition(C);this.rotateBoneToward(e.lower,x,R,o),e.lower.updateMatrixWorld(!0),this.updateSolveDebug(t,i,P,o)}updateSolveDebug(t,e,o,i){if(!this.footIkDebug||null==this.ikDebugLegs)return;const s=this.ikDebugLegs[t];this.setDebugArrow(s.solveUpper,e,o),this.setDebugArrow(s.solveLower,o,i)}rotateBoneToward(t,e,o,i){const s=(new p).subVectors(o,e),r=(new p).subVectors(i,e);if(s.lengthSq()<1e-10||r.lengthSq()<1e-10)return;if(s.normalize(),r.normalize(),s.dot(r)>.9999)return;const n=(new g).setFromUnitVectors(s,r),l=t.getWorldQuaternion(H),a=z.copy(n).multiply(l);if(null==t.parent)return void t.quaternion.copy(a);const h=t.parent.getWorldQuaternion(N),c=U.copy(h).invert().multiply(a);t.quaternion.copy(c)}detectFootAxisBasis(t){const e=t.getWorldQuaternion(H),o=this.actor.object.getWorldDirection(O);o.lengthSq()<1e-6&&o.set(0,0,1),o.normalize();const i=[{local:Q.clone(),world:Q.clone().applyQuaternion(e)},{local:$.clone(),world:$.clone().applyQuaternion(e)},{local:_.clone(),world:_.clone().applyQuaternion(e)}];i.push({local:Q.clone().multiplyScalar(-1),world:Q.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:$.clone().multiplyScalar(-1),world:$.clone().multiplyScalar(-1).applyQuaternion(e)}),i.push({local:_.clone().multiplyScalar(-1),world:_.clone().multiplyScalar(-1).applyQuaternion(e)});let s=i[0],r=-1/0;for(const t of i){const e=t.world.dot(M);e>r&&(r=e,s=t)}let n=i[0],l=-1/0;for(const t of i){if(Math.abs(t.world.dot(s.world))>.6)continue;const e=Math.abs(t.world.dot(o));e>l&&(l=e,n=t)}n.world.dot(o)<0&&(n={local:n.local.clone().multiplyScalar(-1),world:n.world.clone().multiplyScalar(-1)});const a=s.local.clone().normalize(),h=n.local.clone().normalize(),c=a.clone().cross(h).normalize();return{upLocal:a,forwardLocal:c.clone().cross(a).normalize(),rightLocal:c}}resolveFootAxes(t,e,o){const i=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),s=o??{up:new p,forward:new p,right:new p},r=e.getWorldQuaternion(H);return s.up.copy(i.upLocal).applyQuaternion(r).normalize(),s.forward.copy(i.forwardLocal).applyQuaternion(r).normalize(),s.right.copy(i.rightLocal).applyQuaternion(r).normalize(),s}clampSlopeNormal(t){const e=m.clamp(t.dot(M),-1,1),o=Math.acos(e),i=m.degToRad(this.footIkMaxSlopeAngleDeg);if(o<=i||o<1e-5)return;const s=i/o;t.lerpVectors(M,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){H.copy(t.quaternion),t.quaternion.copy(e).slerp(H,o)}alignFootToGroundNormal(t,e,o,i){if(o.weight<=.001||null==e.parent)return;const s=this.ikFootAxes?.[t]??this.detectFootAxisBasis(e),r=O.copy(o.normal).normalize(),n=V.copy(o.forward);if(n.addScaledVector(r,-n.dot(r)),n.lengthSq()<1e-8){const o=this.resolveFootAxes(t,e);n.copy(o.forward).addScaledVector(r,-o.forward.dot(r))}if(n.lengthSq()<1e-8)return;n.normalize();const l=C.crossVectors(r,n);if(l.lengthSq()<1e-8)return;l.normalize(),n.copy(E.crossVectors(l,r)).normalize(),j.makeBasis(s.rightLocal,s.upLocal,s.forwardLocal),H.setFromRotationMatrix(j),G.makeBasis(l,r,n),z.setFromRotationMatrix(G);const a=N.copy(z).multiply(U.copy(H).invert()),h=e.parent.getWorldQuaternion(U),c=z.copy(h).invert().multiply(a),d=(1-Math.exp(-this.footIkRotationLerpSpeed*i))*o.weight;e.quaternion.slerp(c,m.clamp(d,0,1))}getMixer(){return this.mixer}beginExternalControl(){this.externalControlActive=!0}endExternalControl(){this.externalControlActive=!1}stopSequenceAnimation(){this.currentFullBodyPriority=-1,this.externalControlActive=!1,null==this.fullBodyAction||this.fullBodyAction.isRunning()||(this.fullBodyAction=null),null==this.upperBodyAction||this.upperBodyAction.isRunning()||(this.upperBodyAction=null),this.fullBodyTimer=0}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={}){it(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 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){if(null!=t){const e=t.getClip();if(e instanceof s&&e.fixedInPlace&&null!=this.movementSpeed){t.timeScale=e.duration/e.displacement*this.movementSpeed;const o=this.mixer.getRoot();o instanceof h&&(t.timeScale/=o.scale.x)}}}playStateMachine(t){this.stateMachines.push(t)}playUpperStateMachine(t){this.upperStateMachines.push(t)}removeStateMachine(t){const e=this.stateMachines.indexOf(t);e>=0&&this.stateMachines.splice(e,1)}removeUpperStateMachine(t){const e=this.upperStateMachines.indexOf(t);e>=0&&this.upperStateMachines.splice(e,1)}playUpper(t,e={}){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={}){it(null!=this.mixer,"Can't play animation before setup is called"),this.assertClipRigCompatible(t);const o=e.priority??1;o<this.currentFullBodyPriority||(this.currentFullBodyPriority=o,this.fullBodyTimer=0,this.upperBodyOverride||(this.upperBodyAction=this.transition(this.upperBodyAction,this.getUpperBodyClip(t),e),this.upperBodyAction.timeScale=e?.timeScale??1),this.fullBodyClip=t,this.fullBodyAction=this.transition(this.fullBodyAction,this.getFullBodyClip(t),e),this.fullBodyAction.timeScale=e?.timeScale??1,this.fullBodyAction.getClip().uuid==this.upperBodyAction.getClip().uuid&&this.upperBodyAction.syncWith(this.fullBodyAction),this.overrideFadeTime=e.fadeTime)}assertClipRigCompatible(t){const e=P(t);if(e===this.animationRigId||null==e&&null==this.animationRigId)return;const o=`${t.uuid}|${e??""}|${this.animationRigId??""}`;if(!lt.has(o)){if(lt.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||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;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,!0),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),t}};tt=t([o({inEditor:!0})],tt);export{tt as CharacterAnimationComponent};function et(t,e){if(null==t)return e;const o=e.clone();F(o,P(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 ot(t){return t.flatMap(t=>function(t){const e=[];return t.traverse(t=>{e.push(t)}),e}(t)).filter(t=>t instanceof a)}function it(t,e){if(!1===t||"function"==typeof t&&!1===t())throw new Error(e)}function st(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 rt(t){let e;return t.traverse(t=>{(t instanceof a||t.isBone)&&null==e&&(e=t)}),e}function nt(t,e){let o=e;for(;null!=o;){if(o===t)return!0;o=o.parent}return!1}const lt=new Set;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -17,6 +17,9 @@ export type CharacterMovementLike = {
|
|
|
17
17
|
allowRootMotionJumpCancel: boolean;
|
|
18
18
|
isGrounded: boolean;
|
|
19
19
|
isCrouching?: boolean;
|
|
20
|
+
isSliding?: boolean;
|
|
21
|
+
readonly slideDirection?: Vector3;
|
|
22
|
+
readonly slideSurfaceNormal?: Vector3;
|
|
20
23
|
applyImpulse(impulse: Vector3): void;
|
|
21
24
|
setRootMotionAction(action: AnimationAction, options?: RootMotionActionOptions): void;
|
|
22
25
|
readonly isDefaultCharacterMovementComponent?: boolean;
|
|
@@ -48,6 +48,15 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
|
48
48
|
maxSpeedBackwards: number;
|
|
49
49
|
maxSpeedSprint: number;
|
|
50
50
|
maxSpeedCrouch: number;
|
|
51
|
+
/** Enables crouch-press sliding without changing the existing steep-slope controller behavior. */
|
|
52
|
+
slideEnabled: boolean;
|
|
53
|
+
slideMinStartSpeed: number;
|
|
54
|
+
slideMinExitSpeed: number;
|
|
55
|
+
/** Flat-ground speed loss in world units per second squared. */
|
|
56
|
+
slideDeceleration: number;
|
|
57
|
+
slideGravityScale: number;
|
|
58
|
+
/** Maximum steering turn rate in radians per second. */
|
|
59
|
+
slideSteeringRate: number;
|
|
51
60
|
sprintStartBoostSpeed: number;
|
|
52
61
|
sprintStartBoostDamping: number;
|
|
53
62
|
jumpVelocity: number;
|
|
@@ -100,9 +109,14 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
|
100
109
|
private suppressUncrouchLift;
|
|
101
110
|
readonly velocity: THREE.Vector3;
|
|
102
111
|
readonly visualSmoothingOffset: THREE.Vector3;
|
|
112
|
+
/** Normalized world-space travel direction while sliding, otherwise zero. */
|
|
113
|
+
readonly slideDirection: THREE.Vector3;
|
|
114
|
+
/** Normalized world-space supporting surface normal while sliding, otherwise world up. */
|
|
115
|
+
readonly slideSurfaceNormal: THREE.Vector3;
|
|
103
116
|
mode: CharacterMovementMode;
|
|
104
117
|
isSprinting: boolean;
|
|
105
118
|
isCrouching: boolean;
|
|
119
|
+
isSliding: boolean;
|
|
106
120
|
pressedJump: boolean;
|
|
107
121
|
get autoStepMinWidth(): number;
|
|
108
122
|
set autoStepMinWidth(minWidth: number);
|
|
@@ -118,6 +132,7 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
|
118
132
|
get normalNudgeFactor(): number;
|
|
119
133
|
private readonly cc;
|
|
120
134
|
private readonly rayTestResult;
|
|
135
|
+
private readonly groundRayTestOptions;
|
|
121
136
|
private readonly physicsSystem;
|
|
122
137
|
private readonly netService;
|
|
123
138
|
private readonly state;
|
|
@@ -148,6 +163,9 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
|
148
163
|
private lastServerReceivedSequence;
|
|
149
164
|
private lastAutonomousMoveFlags;
|
|
150
165
|
private previousSprintInput;
|
|
166
|
+
private previousCrouchInput;
|
|
167
|
+
private crouchSuppressedUntilRelease;
|
|
168
|
+
private slideOnLandingRequested;
|
|
151
169
|
private initialized;
|
|
152
170
|
constructor();
|
|
153
171
|
onInit(): void;
|
|
@@ -190,6 +208,10 @@ export declare class CharacterMovementComponent extends ActorComponent {
|
|
|
190
208
|
private initializeStateFromActor;
|
|
191
209
|
private createCollisionShape;
|
|
192
210
|
private updateCrouchState;
|
|
211
|
+
private updateSlidingMode;
|
|
212
|
+
private tryUncrouch;
|
|
213
|
+
private resolveGroundNormal;
|
|
214
|
+
private isWalkableSlideSurface;
|
|
193
215
|
private setCrouching;
|
|
194
216
|
private canUncrouch;
|
|
195
217
|
private syncColliderShape;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import i from"@dimforge/rapier3d-simd-compat";import{takeUntil as o}from"rxjs";import*as s from"three";import{ArrowHelper as n,MathUtils as r,Quaternion as a,Vector3 as h}from"three";import{RootMotionClip as c}from"../../../../animation/root-motion.js";import{inject as l}from"../../../../inject.js";import{ActionInput as u,AxisInput as p,RotationInput as m}from"../../../../input/index.js";import{NetRole as d}from"../../../../net/service/net-actor-role.js";import{RunOnClient as v,RunOnNotOwner as y,RunOnServer as S}from"../../../../net/service/rpc-decorator.js";import{NetService as M}from"../../../../net/service/net-service.js";import{PhysicsSystem as g,RayTestResult as f}from"../../../../services/physics/physics-system.js";import{CapsuleCollisionShape as x}from"../../../../../scene/collision/collision-shape.js";import{Parameter as T}from"../../../../../shader/parameter.js";import{PhysicsBodyType as C}from"../../../../services/physics/physics-system.js";import{ActorComponent as w,Component as A}from"../../../component.js";import{CharacterMovementMode as R}from"./modes.js";import{DEFAULT_MAX_CLIENT_TIME_AHEAD as D,DEFAULT_LARGE_CORRECTION_THRESHOLD as q,DEFAULT_MAX_COMBINED_MOVE_DELTA_TIME as b,DEFAULT_MAX_MOVE_DELTA_TIME as k,DEFAULT_MAX_MOVES_PER_PACKET as P,DEFAULT_MAX_REPLAYED_MOVES as I,DEFAULT_MAX_SERVER_MOVES_PER_TICK as z,DEFAULT_MAX_SAVED_MOVES as j,DEFAULT_MAX_SERVER_MOVE_DELTA_TIME_SCALAR as Y,DEFAULT_MAX_SERVER_MOVE_TIME_BUDGET as F,DEFAULT_MAX_SUBSTEP_DELTA_TIME as G,DEFAULT_MOVE_SEND_INTERVAL as O,DEFAULT_SIMULATED_INTERPOLATION_DELAY as V,DEFAULT_SIMULATED_STATE_INTERVAL as X,DEFAULT_SMALL_CORRECTION_TOLERANCE as B,DEFAULT_TELEPORT_SNAP_THRESHOLD as N,MOVE_FLAG_CROUCH as H,MOVE_FLAG_JUMP as Z,MOVE_FLAG_ROOT_MOTION as U,MOVE_FLAG_SPRINT as L,MOVE_FLAG_SPRINT_START as E,SNAPSHOT_FLAG_CROUCHING as $,NetCharacterProxySmoother as Q,NetCharacterSavedMoveBuffer as W,accrueNetCharacterServerMoveTime as J,createNetCharacterMovementSnapshot as K,createNetCharacterServerMoveTimingState as _,consumeNetCharacterServerMoveTime as tt,decodeNetCharacterMoveBatch as et,decodeNetCharacterOwnerAck as it,decodeNetCharacterOwnerCorrection as ot,decodeNetCharacterSimulatedState as st,encodeNetCharacterMoveBatch as nt,encodeNetCharacterOwnerAck as rt,encodeNetCharacterOwnerCorrection as at,encodeNetCharacterSimulatedState as ht,validateNetCharacterMove as ct}from"./net-character-movement-protocol.js";import{NetMode as lt}from"../../../../net/net-session.js";export*from"./net-character-movement-protocol.js";const ut=131070,pt=new h(0,1,0),mt=new h,dt=new h,vt=new h,yt=new h,St=new h,Mt=new h,gt=new h,ft=new h,xt=new h,Tt=new h,Ct=new h,wt=new h,At=new h,Rt=new h,Dt=new h(0,1,0),qt=new h(0,-.05,0),bt=new h,kt=new a,Pt=new s.Euler,It=new h,zt=new h,jt=new h,Yt=new i.CharacterCollision;let Ft=class extends w{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}set normalNudgeFactor(t){this.cc.setNormalNudgeFactor(t)}get normalNudgeFactor(){return this.cc.normalNudgeFactor()}constructor(){super(),this.isDefaultCharacterMovementComponent=!0,this.directionInput=new p,this.jumpInput=new u,this.sprintInput=new u,this.crouchInput=new u,this.rotationInput=new m,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.maxSpeedCrouch=4,this.sprintStartBoostSpeed=0,this.sprintStartBoostDamping=6,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.groundAccelerationRate=4,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.crouchColliderHeight=1,this.crouchColliderRadius=null,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=r.degToRad(70),this.maxSlopeClimbAngle=r.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.normalizedDirection=!0,this.characterCollision=!1,this.allowRootMotionJumpCancel=!1,this.enabled=!0,this.rotateToMovementDirection=!1,this.smoothRotation=!0,this.rotationSpeed=40,this.maxRotationSpeed=100,this.impulseDamping=2,this.moveSendInterval=O,this.simulatedStateInterval=X,this.maxSavedMoves=j,this.maxReplayedMoves=I,this.maxServerMovesPerTick=z,this.maxMovesPerPacket=P,this.maxMoveDeltaTime=k,this.maxCombinedMoveDeltaTime=b,this.maxServerMoveDeltaTimeScalar=Y,this.maxClientTimeAhead=D,this.maxServerMoveTimeBudget=F,this.maxSubstepDeltaTime=G,this.fallGraceTime=.1,this.correctionToleranceSq=B*B,this.largeCorrectionThreshold=q,this.teleportSnapThreshold=N,this.listenServerSmoothing=!0,this.listenServerSmoothLocationTime=.04,this.listenServerMaxSmoothUpdateDistance=1,this.listenServerNoSmoothUpdateDistance=2.5,this.debugCorrections=!0,this.suppressUncrouchLift=!1,this.velocity=new h,this.visualSmoothingOffset=new h,this.mode=R.walking,this.isSprinting=!1,this.isCrouching=!1,this.pressedJump=!1,this.rayTestResult=new f,this.physicsSystem=l(g),this.netService=l(M),this.state={sequence:0,position:new h,velocity:new h,yaw:0,lookYaw:0,mode:R.walking,grounded:!1,currentSpeed:0,fallGraceTime:0,prevInputDirection:new h,prevRotateToMovementDirection:!1},this.movementModes=new Map,this.savedMoves=new W(j),this.serverMoveTiming=_(),this.serverMoveQueue=[],this.inputMoveScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0},this.authoritativeMoveScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0},this.movementModeContext={component:this,state:this.state,move:this.inputMoveScratch,deltaTime:0,rotatedDirection:dt,platformVelocity:yt,outVelocity:vt,rootMotionActive:!1,startedSprinting:!1},this.proxySmoother=new Q(V,N),this.proxySample=K(),this.pendingSnapshot=K(),this.impulse=new h,this.prevRootMotionPos=new h,this.rootMotionOptions={},this.resetRootMotion=!1,this.nextMoveSequence=0,this.clientMoveTime=0,this.lastSentClientMoveTime=0,this.moveSendAccumulator=0,this.simulatedStateAccumulator=0,this.proxyTime=0,this.lastServerProcessedSequence=0,this.lastServerReceivedSequence=0,this.lastAutonomousMoveFlags=0,this.previousSprintInput=!1,this.initialized=!1,this.cc=this.physicsSystem.getCharacterController(.1),this.cc.enableSnapToGround(.1),this.cc.enableAutostep(0,.1,!1),this.registerMovementMode(Gt),this.registerMovementMode(Ot)}onInit(){this.configureCharacterController(),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:C.kinematic,continousCollisionDetection:!1,friction:0,restitution:.5,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation),this.initializeStateFromActor(),this.initialized=!0,this.physicsSystem.beforeStep.pipe(o(this.disposed)).subscribe(t=>this.tick(t))}onLateUpdate(t){this.updateVisualSmoothing(t)}registerMovementMode(t){this.movementModes.set(t.mode,t)}applyImpulse(t){this.impulse.add(t)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}setRootMotionAction(t,e={}){const i=t?.getClip();if(i instanceof c){this.rootMotionAction=t,this.rootMotionOptions=e,this.resetRootMotion=!0;const o=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(o);const n=s.PropertyBinding.parseTrackName(i.motionTrack.name);this.rootMotionRootBone=this.actor.object.getObjectByName(n.nodeName)}}serverMove(t){const e=et(t);if(e.ok)for(const t of e.value.moves)ct(t,this.lastServerReceivedSequence,this.maxMoveDeltaTime)&&(this.lastServerReceivedSequence=t.sequence,this.serverMoveQueue.push(t))}clientMoveAck(t){const e=it(t);e.ok&&this.actor.netRole===d.autonomousProxy&&(this.savedMoves.ack(e.value.sequence),this.sprintPolicy?.ack?.(e.value.sequence,!1))}clientMoveCorrection(t){const e=ot(t);e.ok&&this.actor.netRole===d.autonomousProxy&&(this.debugCorrections&&(null==this.correctionDebug&&(this.correctionDebug=new Bt(Ht(this.actor.object))),this.correctionDebug.update(this.state.position,e.value.snapshot)),this.applyCorrection(e.value.snapshot))}simulatedState(t){const e=st(t);e.ok&&this.actor.netRole===d.simulatedProxy&&this.proxySmoother.push(e.value,this.proxyTime)}tick(t){if(!this.initialized)return;t=Math.min(.1,t);const e=this.actor.netRole,i=this.netService.mode;e!==d.simulatedProxy?this.enabled&&(e!==d.autonomousProxy?this.isRemoteControlledAuthority(i,e)?this.tickRemoteAuthority(t):this.tickAuthority(t,i):this.tickAutonomousProxy(t)):this.tickSimulatedProxy(t)}tickAutonomousProxy(t){const e=this.state.mode,i=this.lastAutonomousMoveFlags,o=this.createMoveFromInput(t,++this.nextMoveSequence,{quantizeClientTime:!0});this.performMove(o,Zt);const s=this.state.mode!==e||o.flags!==i;this.lastAutonomousMoveFlags=o.flags,this.savedMoves.capacity=this.maxSavedMoves,this.savedMoves.maxCombinedDeltaTime=Math.min(this.maxCombinedMoveDeltaTime,this.maxMoveDeltaTime),this.savedMoves.push(o),this.sendSavedMoves(t,s)}tickAuthority(t,e){const i=this.createMoveFromInput(t,++this.nextMoveSequence);this.performMove(i,Zt),e!==lt.none&&this.sendSimulatedState(t,!1)}tickRemoteAuthority(t){J(this.serverMoveTiming,t,this.maxServerMoveTimeBudget);let e=!1;const i=Number.isFinite(this.maxServerMovesPerTick)?Math.max(1,Math.floor(this.maxServerMovesPerTick)):this.serverMoveQueue.length,o=Math.min(this.serverMoveQueue.length,i),s=zt.copy(this.actor.position);let n=!1;for(let t=0;t<o;t++){const t=this.serverMoveQueue.shift();if(null==t)break;if(!ct(t,this.lastServerProcessedSequence,this.maxMoveDeltaTime)){console.log("Net: Invalid move",t),this.sendOwnerCorrection(!0),e=!0;continue}const i=tt(this.serverMoveTiming,t,{maxMoveDeltaTime:this.maxMoveDeltaTime,maxServerMoveDeltaTimeScalar:this.maxServerMoveDeltaTimeScalar,maxClientTimeAhead:this.maxClientTimeAhead});if(i<0){this.sendOwnerCorrection(!0),e=!0;continue}const o=Vt(t,this.authoritativeMoveScratch);o.dt=i,o.rootMotionX=0,o.rootMotionY=0,o.rootMotionZ=0,o.flags&=~U,this.performMove(o,{immediate:!0,savedRootMotion:!1}),n=!0,this.lastServerProcessedSequence=o.sequence;const s=Xt(this.state,t);if(s>this.correctionToleranceSq){console.log(`Net server: Correction error: ${Math.sqrt(s)}`);const o=this.state.position.x-t.clientX,n=this.state.position.y-t.clientY,r=this.state.position.z-t.clientZ;console.log(`diff x: ${o}, y: ${n}, z: ${r}`),console.log({sequence:t.sequence,moveDt:t.dt,serverMoveDeltaTime:i,flags:t.flags,mode:this.state.mode,grounded:this.state.grounded,fallGraceTime:this.state.fallGraceTime}),this.sendOwnerCorrection(s>this.largeCorrectionThreshold*this.largeCorrectionThreshold),e=!0}}0===this.lastServerProcessedSequence||e||(this.sprintPolicy?.ack?.(this.lastServerProcessedSequence,!1),this.clientMoveAck(rt(this.lastServerProcessedSequence))),n&&this.accumulateListenServerVisualSmoothing(s,this.actor.position),this.sendSimulatedState(t,!1)}tickSimulatedProxy(t){this.proxyTime+=t,this.proxySmoother.sample(this.proxyTime,this.proxySample)&&this.applySnapshot(this.proxySample,!0)}accumulateListenServerVisualSmoothing(t,e){if(!this.shouldSmoothListenServerRemoteAuthority())return void this.visualSmoothingOffset.set(0,0,0);jt.subVectors(t,e);const i=jt.lengthSq();i>1e-8&&(i>this.listenServerNoSmoothUpdateDistance*this.listenServerNoSmoothUpdateDistance?this.visualSmoothingOffset.set(0,0,0):(i>this.listenServerMaxSmoothUpdateDistance*this.listenServerMaxSmoothUpdateDistance&&jt.setLength(this.listenServerMaxSmoothUpdateDistance),this.visualSmoothingOffset.add(jt)))}updateVisualSmoothing(t){if(this.visualSmoothingOffset.lengthSq()<=1e-8)return void this.visualSmoothingOffset.set(0,0,0);if(!this.shouldSmoothListenServerRemoteAuthority())return void this.visualSmoothingOffset.set(0,0,0);const e=Math.max(.001,this.listenServerSmoothLocationTime);t<e?this.visualSmoothingOffset.multiplyScalar(1-t/e):this.visualSmoothingOffset.set(0,0,0),this.visualSmoothingOffset.lengthSq()<=1e-4&&this.visualSmoothingOffset.set(0,0,0)}shouldSmoothListenServerRemoteAuthority(){return this.listenServerSmoothing&&this.actor.netRole===d.authority&&this.netService.isServer&&!this.netService.isDedicatedServer&&this.isRemoteControlledAuthority()}createMoveFromInput(t,e,i={}){const o=r.clamp(t,.001,this.maxMoveDeltaTime);this.clientMoveTime+=o;let s=this.clientMoveTime,n=o;!0===i.quantizeClientTime&&(s=Math.max(this.lastSentClientMoveTime+.001,Math.round(1e3*this.clientMoveTime)/1e3),n=r.clamp(s-this.lastSentClientMoveTime,.001,this.maxMoveDeltaTime),this.lastSentClientMoveTime=s),this.sampleRootMotion(gt);const a=this.crouchInput.activated,h=!a&&this.sprintInput.activated,c=h&&!this.previousSprintInput;this.previousSprintInput=h;const l=(this.jumpInput.activated?Z:0)|(h?L:0)|(a?H:0)|(c?E:0)|(gt.lengthSq()>0?U:0),u=function(t,e){e.set(t.x,0,t.y),e.lengthSq()>1&&e.normalize();return e}(this.directionInput.vector,It),p=this.inputMoveScratch;return p.sequence=e>>>0,p.clientTime=s,p.dt=n,p.inputX=u.x,p.inputY=u.z,p.yaw=this.rotationInput.rotation.y,p.flags=l,p.clientX=this.state.position.x,p.clientY=this.state.position.y,p.clientZ=this.state.position.z,p.rootMotionX=gt.x,p.rootMotionY=gt.y,p.rootMotionZ=gt.z,p}performMove(t,e){const i=r.clamp(t.dt,.001,this.maxMoveDeltaTime),o=Math.max(1,Math.ceil(i/this.maxSubstepDeltaTime)),s=0!==(t.flags&L)&&0===(t.flags&H);this.sprintPolicy?.update?.(i,t.sequence,s),wt.set(e.savedRootMotion?t.rootMotionX:0,e.savedRootMotion?t.rootMotionY:0,e.savedRootMotion?t.rootMotionZ:0),e.savedRootMotion||this.sampleRootMotion(wt);let n=i;const a=i/o;for(let s=0;s<o;s++){const o=i>0?a/i:1;this.performSubstep(t,Math.min(a,n),wt,o,e.immediate,0===s),n-=a}t.clientX=this.state.position.x,t.clientY=this.state.position.y,t.clientZ=this.state.position.z,t.flags=wt.lengthSq()>0?t.flags|U:t.flags&~U,this.state.sequence=t.sequence,this.syncPublicState()}performSubstep(t,e,i,o,s,n){if(e<.001)return;this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded,this.updateCrouchState(t);const r=null!=this.rootMotionAction&&this.rootMotionAction.enabled,a=i.lengthSq()>0,h=!r&&0!==(t.flags&Z),c=r||a;this.pressedJump=h,this.isSprinting=!1,this.updateRotation(t,e,r,a),this.resolvePlatformVelocity(yt);const l=this.movementModeContext,u=this.movementModes.get(this.state.mode);if(null!=u){l.move=t,l.deltaTime=e,l.rootMotionActive=c,l.startedSprinting=n&&!c&&0===(t.flags&H)&&0!==(t.flags&E);const i=u.update(l);"number"==typeof i&&(this.state.mode=i)}else vt.set(0,0,0);if(a){ft.copy(i).multiplyScalar(o).applyQuaternion(this.actor.quaternion),xt.copy(ft).divideScalar(e),this.state.mode===R.walking?(vt.x=xt.x+yt.x,vt.z=xt.z+yt.z):(vt.x=xt.x,vt.z=xt.z);const t=Math.sqrt(xt.x*xt.x+xt.z*xt.z);t>.4&&(this.state.currentSpeed=t)}this.applyImpulseToVelocity(vt,e),this.state.mode===R.walking&&this.state.velocity.copy(vt),this.applyMovement(vt,e,s),this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded,this.updateModeAfterMove(vt,e)}updateRotation(t,e,i,o){mt.set(-t.inputX,0,t.inputY),mt.lengthSq()>1&&mt.normalize();const s=this.state.prevRotateToMovementDirection!==this.rotateToMovementDirection;let n=r.euclideanModulo(t.yaw-this.state.lookYaw+Math.PI,2*Math.PI)-Math.PI;if(s&&(this.actor.object.quaternion.setFromEuler(Pt.set(0,t.yaw,0)),this.state.prevRotateToMovementDirection||(n=0,this.state.lookYaw=t.yaw),this.state.prevRotateToMovementDirection=this.rotateToMovementDirection),dt.set(0,0,0),i)this.state.lookYaw=t.yaw;else if(this.rotateToMovementDirection){if(mt.lengthSq()>0&&this.state.mode!==R.falling){const i=Pt.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,o=Math.atan2(mt.x,mt.z),s=.99*t.yaw+o;if(this.smoothRotation){const t=r.euclideanModulo(s-i+Math.PI,2*Math.PI)-Math.PI;let o=r.clamp(t*this.rotationSpeed*e,-this.maxRotationSpeed*e,this.maxRotationSpeed*e);Math.abs(o)>Math.abs(t)&&(o=t),this.actor.object.quaternion.setFromEuler(Pt.set(0,i+o,0))}else this.actor.object.quaternion.setFromEuler(Pt.set(0,s,0));this.state.prevInputDirection.lerp(mt,e*this.rotationSpeed),this.state.lookYaw+=n,dt.copy(this.actor.object.getWorldDirection(It).normalize())}}else o||(this.state.lookYaw+=n,this.actor.object.quaternion.multiply(kt.setFromEuler(Pt.set(0,n,0))),mt.lengthSq()>0&&dt.copy(mt).applyQuaternion(this.actor.object.quaternion).normalize())}applyMovement(t,e,i){if(t.lengthSq()>0||!this.state.grounded){if(St.copy(t).multiplyScalar(e),this.state.grounded&&this.state.mode===R.walking&&(this.rayTestResult.distance<=this.cc.offset()&&(St.y=Math.max(0,yt.y*e)),this.physicsSystem.getActorComputedMovement(this.actor,this.cc,St,this.getCollisionGroup()),this.cc.computedCollision(0,Yt),null!=Yt.normal1)){const t=It.copy(Yt.normal1);Math.acos(r.clamp(t.dot(pt),-1,1))>this.cc.maxSlopeClimbAngle()&&(St.y=.016*this.getEffectiveGravity()*.5)}Mt.copy(this.physicsSystem.getActorComputedMovement(this.actor,this.cc,St,this.getCollisionGroup()))}else Mt.set(0,0,0);this.suppressUncrouchLift&&(this.suppressUncrouchLift=!1,this.state.grounded&&this.state.mode===R.walking&&St.y<=1e-6&&Mt.y>0&&(Mt.y=0)),this.state.position.add(Mt),i?(this.actor.position.copy(this.state.position),this.physicsSystem.updateActorTransform(this.actor),this.physicsSystem.flushModifiedBodyPositionsToColliders()):this.physicsSystem.setNextKinematicPosition(this.actor,this.state.position)}updateModeAfterMove(t,e){const i=function(t){if(0===t.numComputedCollisions())return!1;const e=t.computedCollision(0);bt.set(e.normal2.x,e.normal2.y,e.normal2.z);const i=bt.angleTo(pt);bt.set(e.normal1.x,e.normal1.y,e.normal1.z);const o=bt.angleTo(pt);if(i<100)return!1;return o>t.minSlopeSlideAngle()}(this.cc);!this.state.grounded||i?this.state.mode!==R.falling&&(this.state.fallGraceTime+=e,this.state.fallGraceTime>this.fallGraceTime+1e-6&&(this.state.mode=R.falling,this.state.velocity.copy(t))):this.state.velocity.y<=0&&(this.state.mode=R.walking,this.state.velocity.y=0,this.state.fallGraceTime=0)}applyImpulseToVelocity(t,e){if(this.impulse.lengthSq()<=.1)return void this.impulse.set(0,0,0);const i=Math.min(1,this.impulse.length()/5);t.x=r.lerp(t.x,this.impulse.x,i),t.z=r.lerp(t.z,this.impulse.z,i),t.y+=this.impulse.y;const o=Math.exp(-this.impulseDamping*e);this.impulse.x*=o,this.impulse.y>0?this.impulse.y+=e*this.getEffectiveGravity():this.impulse.y*=o,this.impulse.z*=o}sendSavedMoves(t,e=!1){if(this.moveSendAccumulator+=t,!e&&this.moveSendAccumulator<this.moveSendInterval)return;this.moveSendAccumulator=0;const i=this.savedMoves.getMovesForSend(this.maxMovesPerPacket);0!==i.length&&this.serverMove(nt(i))}sendOwnerCorrection(t){const e=this.toSnapshot(this.pendingSnapshot);t&&(e.horizontalSpeed=this.horizontalSpeed),this.sprintPolicy?.ack?.(e.sequence,!0),this.clientMoveCorrection(at(e))}sendSimulatedState(t,e){this.simulatedStateAccumulator+=t,!e&&this.simulatedStateAccumulator<this.simulatedStateInterval||(this.simulatedStateAccumulator=0,this.simulatedState(ht(this.toSnapshot(this.pendingSnapshot))))}applyCorrection(t){this.sprintPolicy?.restore?.(t.sequence),this.savedMoves.ack(t.sequence),this.sprintPolicy?.ack?.(t.sequence,!0),this.applySnapshot(t,!0),this.savedMoves.replayAfter(t.sequence,t=>(this.performMove(t,{immediate:!0,savedRootMotion:!0}),null),this.maxReplayedMoves)}applySnapshot(t,e){this.state.sequence=t.sequence,this.state.position.set(t.x,t.y,t.z),this.state.velocity.set(t.velocityX,t.velocityY,t.velocityZ),this.state.yaw=t.yaw,this.state.lookYaw=t.yaw,this.state.mode=t.mode,this.state.currentSpeed=t.horizontalSpeed,this.state.fallGraceTime=0,this.actor.position.copy(this.state.position),this.actor.object.quaternion.setFromEuler(Pt.set(0,t.yaw,0)),this.setCrouching(0!==(t.flags&$)),e&&(this.physicsSystem.updateActorTransform(this.actor),this.physicsSystem.flushModifiedBodyPositionsToColliders()),this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded,this.syncPublicState()}toSnapshot(t){return t.sequence=this.state.sequence,t.x=this.state.position.x,t.y=this.state.position.y,t.z=this.state.position.z,t.velocityX=this.state.velocity.x,t.velocityY=this.state.velocity.y,t.velocityZ=this.state.velocity.z,t.yaw=Pt.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,t.mode=this.state.mode,t.flags=this.isCrouching?$:0,t.horizontalSpeed=this.state.currentSpeed,t}syncPublicState(){this.velocity.copy(this.state.velocity),this.mode=this.state.mode,this.horizontalSpeed=this.state.currentSpeed}sampleRootMotion(t){if(t.set(0,0,0),null==this.rootMotionAction||this.rootMotionAction.isRunning()||this.clearRootMotionAction(this.rootMotionAction),null!=this.rootMotionAction&&this.rootMotionOptions.cancelWithJump&&this.jumpInput.activated&&(this.isGrounded||this.jumpInAir)){const e=this.rootMotionAction,i=this.rootMotionOptions.onJumpCancel;return this.clearRootMotionAction(e),e.stop(),i?.(),t}if(null==this.rootMotionAction)return t;if(!(this.rootMotionAction.getClip()instanceof c))return t;const e=this.rootMotionInterpolant;this.resetRootMotion&&(this.prevRootMotionPos.fromArray(e.evaluate(0)),this.resetRootMotion=!1),Ct.fromArray(e.evaluate(this.rootMotionAction.time)),t.subVectors(Ct,this.prevRootMotionPos),this.prevRootMotionPos.copy(Ct);return(this.rootMotionRootBone??this.rootMotionAction.getRoot()).getWorldScale(Tt),t.multiply(Tt),t}clearRootMotionAction(t){null!=t&&this.rootMotionAction!==t||(this.rootMotionAction=null,this.rootMotionOptions={},this.resetRootMotion=!1)}isRemoteControlledAuthority(t=this.netService.mode,e=this.actor.netRole){if(t===lt.none||e!==d.authority||t>=lt.client)return!1;return null!=this.netService.resolveActorConnection(this.actor)&&!this.netService.isLocalOwner(this.actor)}configureCharacterController(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding)}initializeStateFromActor(){this.state.position.copy(this.actor.position),this.state.velocity.set(0,0,0),this.state.yaw=this.actor.rotation.y,this.state.lookYaw=this.rotationInput.rotation.y,this.state.mode=this.mode,this.state.currentSpeed=this.horizontalSpeed,this.state.prevRotateToMovementDirection=this.rotateToMovementDirection}createCollisionShape(){const t=this.getColliderHeight(!1),e=this.getColliderRadius(!1),i=new x(t,e);return i.offset.y=this.getCapsuleOffsetY(t,e),i.collisionGroup=ut,i}updateCrouchState(t){0===(t.flags&H)?this.isCrouching&&this.canUncrouch()&&this.setCrouching(!1)&&(this.suppressUncrouchLift=!0,this.state.fallGraceTime=0):this.setCrouching(!0)}setCrouching(t){return this.isCrouching!==t&&(this.isCrouching=t,this.syncColliderShape(),!0)}canUncrouch(){const t=this.getColliderHeight(!1),e=this.getColliderRadius(!1);return!this.physicsSystem.hasActorCapsuleIntersection(this.actor,this.state.position,t,e,this.getCapsuleOffsetY(t,e),this.getCollisionGroup())}syncColliderShape(){const t=this.getColliderHeight(this.isCrouching),e=this.getColliderRadius(this.isCrouching);this.physicsSystem.setActorCapsuleCollider(this.actor,t,e,this.getCapsuleOffsetY(t,e))}getColliderHeight(t){const e=Number.isFinite(this.colliderHeight)?Math.max(0,this.colliderHeight):0;if(!t)return e;const i=Number.isFinite(this.crouchColliderHeight)?this.crouchColliderHeight:e;return r.clamp(i,0,e)}getColliderRadius(t){const e=Number.isFinite(this.colliderRadius)?Math.max(.001,this.colliderRadius):.001;if(!t)return e;const i=this.crouchColliderRadius??e,o=Number.isFinite(i)?i:e;return r.clamp(o,.001,e)}getCapsuleOffsetY(t,e){return e+t/2+this.offset}checkGrounded(t){qt.y=-Math.max(.05,this.cc.snapToGroundDistance()),this.physicsSystem.rayTest(At.addVectors(t,Dt.set(0,this.offset,0)),Rt.addVectors(t,qt),this.rayTestResult,{excludeActor:this.actor,excludeTriggers:!0})}resolvePlatformVelocity(t){return t.set(0,0,0),this.rayTestResult.hasHit&&null!=this.rayTestResult.actor&&this.physicsSystem.getLinearVelocity(this.rayTestResult.actor,t),t}getCollisionGroup(){return this.characterCollision?null:ut}};t([T(),e("design:type",Object)],Ft.prototype,"colliderHeight",void 0),t([T(),e("design:type",Object)],Ft.prototype,"colliderRadius",void 0),t([T(),e("design:type",Object)],Ft.prototype,"crouchColliderHeight",void 0),t([T(),e("design:type",Number)],Ft.prototype,"crouchColliderRadius",void 0),t([S(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Ft.prototype,"serverMove",null),t([v(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Ft.prototype,"clientMoveAck",null),t([v(!0),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Ft.prototype,"clientMoveCorrection",null),t([y(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Ft.prototype,"simulatedState",null),Ft=t([A({inEditor:!1}),e("design:paramtypes",[])],Ft);export{Ft as CharacterMovementComponent};const Gt={mode:R.walking,update(t){const e=t.component,i=t.move,o=t.state,s=t.rotatedDirection,n=Math.min(1,Math.sqrt(i.inputX*i.inputX+i.inputY*i.inputY)),r=!e.rotateToMovementDirection&&i.inputY<0,a=e.isCrouching,h=!t.rootMotionActive&&!a&&0===(i.flags&H)&&0!==(i.flags&L)&&!r&&0!==s.lengthSq()&&(e.sprintPolicy?.canSprint()??!0),c=(a?e.maxSpeedCrouch:r?e.maxSpeedBackwards:h?e.maxSpeedSprint:e.maxSpeed)*(e.normalizedDirection?1:n);if(0!==s.lengthSq()){e.isSprinting=h,h&&e.sprintPolicy?.commitSprint(t.deltaTime,i.sequence);let a=Math.min(c,o.currentSpeed),l=e.groundAccelerationRate;if(h&&t.startedSprinting&&e.sprintStartBoostSpeed>0){const t=e.normalizedDirection?1:n;a=Math.max(a,c+e.sprintStartBoostSpeed*t),l=e.sprintStartBoostDamping}else h&&!r&&e.sprintStartBoostSpeed>0&&o.currentSpeed>c&&(a=o.currentSpeed,l=e.sprintStartBoostDamping);o.currentSpeed=function(t,e,i,o){return e+(t-e)*Math.exp(-i*o)}(a,c,l,t.deltaTime),t.outVelocity.copy(s).multiplyScalar(function(t,e,i,o){const s=i*o;if(s<=1e-6)return t;return e+(t-e)*(1-Math.exp(-s))/s}(a,c,l,t.deltaTime))}else o.currentSpeed=0,t.outVelocity.set(0,0,0);if(0!==(i.flags&Z))return o.mode=R.falling,o.velocity.copy(t.outVelocity),o.velocity.y=e.jumpVelocity,R.falling;t.outVelocity.y=t.deltaTime*e.getEffectiveGravity(),t.outVelocity.add(t.platformVelocity)}},Ot={mode:R.falling,update(t){const e=t.component,i=t.state,o=t.move;0!==(o.flags&Z)&&e.jumpInAir&&(i.velocity.copy(t.outVelocity),i.velocity.y=e.jumpVelocity),i.velocity.y+=t.deltaTime*e.getEffectiveGravity(),t.outVelocity.copy(i.velocity),t.outVelocity.addScaledVector(t.rotatedDirection,e.fallingMovementControl),e.fallingReorientation&&t.outVelocity.applyAxisAngle(pt,r.euclideanModulo(o.yaw-i.lookYaw+Math.PI,2*Math.PI)-Math.PI)}};function Vt(t,e){return e.sequence=t.sequence,e.clientTime=t.clientTime,e.dt=t.dt,e.inputX=t.inputX,e.inputY=t.inputY,e.yaw=t.yaw,e.flags=t.flags,e.clientX=t.clientX,e.clientY=t.clientY,e.clientZ=t.clientZ,e.rootMotionX=t.rootMotionX,e.rootMotionY=t.rootMotionY,e.rootMotionZ=t.rootMotionZ,e}function Xt(t,e){const i=t.position.x-e.clientX,o=t.position.y-e.clientY,s=t.position.z-e.clientZ;return i*i+o*o+s*s}class Bt{constructor(t){this.scene=t,this.serverPosition=new h,this.direction=new h}update(t,e){const i=this.serverPosition.set(e.x,e.y,e.z),o=i.distanceTo(t);o>.1&&console.log(`Correction applied. Error: ${o.toFixed(3)}. Server position: (${i.x.toFixed(2)}, ${i.y.toFixed(2)}, ${i.z.toFixed(2)}), Client position: (${t.x.toFixed(2)}, ${t.y.toFixed(2)}, ${t.z.toFixed(2)})`);const s=this.direction.copy(i).sub(t).normalize();Nt.position.copy(t),Nt.setDirection(s),Nt.setLength(o);const n=Ht(this.scene);n.add(Nt),setTimeout(()=>{n.remove(Nt)},1e3)}}const Nt=new n(new h(0,1,0),new h,1,16711680);function Ht(t){return null==t.parent?t:Ht(t.parent)}const Zt={immediate:!1,savedRootMotion:!0};/*
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import i from"@dimforge/rapier3d-simd-compat";import{takeUntil as o}from"rxjs";import*as s from"three";import{ArrowHelper as n,MathUtils as r,Quaternion as a,Vector3 as h}from"three";import{RootMotionClip as l}from"../../../../animation/root-motion.js";import{inject as c}from"../../../../inject.js";import{ActionInput as u,AxisInput as d,RotationInput as p}from"../../../../input/index.js";import{NetRole as m}from"../../../../net/service/net-actor-role.js";import{RunOnClient as v,RunOnNotOwner as y,RunOnServer as S}from"../../../../net/service/rpc-decorator.js";import{NetService as g}from"../../../../net/service/net-service.js";import{PhysicsSystem as M,RayTestResult as f}from"../../../../services/physics/physics-system.js";import{CapsuleCollisionShape as x}from"../../../../../scene/collision/collision-shape.js";import{Parameter as T}from"../../../../../shader/parameter.js";import{PhysicsBodyType as C}from"../../../../services/physics/physics-system.js";import{ActorComponent as R,Component as w}from"../../../component.js";import{CharacterMovementMode as A}from"./modes.js";import{DEFAULT_MAX_CLIENT_TIME_AHEAD as q,DEFAULT_LARGE_CORRECTION_THRESHOLD as D,DEFAULT_MAX_COMBINED_MOVE_DELTA_TIME as b,DEFAULT_MAX_MOVE_DELTA_TIME as k,DEFAULT_MAX_MOVES_PER_PACKET as P,DEFAULT_MAX_REPLAYED_MOVES as I,DEFAULT_MAX_SERVER_MOVES_PER_TICK as z,DEFAULT_MAX_SAVED_MOVES as O,DEFAULT_MAX_SERVER_MOVE_DELTA_TIME_SCALAR as j,DEFAULT_MAX_SERVER_MOVE_TIME_BUDGET as G,DEFAULT_MAX_SUBSTEP_DELTA_TIME as Y,DEFAULT_MOVE_SEND_INTERVAL as F,DEFAULT_SIMULATED_INTERPOLATION_DELAY as N,DEFAULT_SIMULATED_STATE_INTERVAL as V,DEFAULT_SMALL_CORRECTION_TOLERANCE as U,DEFAULT_TELEPORT_SNAP_THRESHOLD as X,MOVE_FLAG_CROUCH as E,MOVE_FLAG_JUMP as L,MOVE_FLAG_ROOT_MOTION as B,MOVE_FLAG_SLIDE_START as H,MOVE_FLAG_SPRINT as Z,MOVE_FLAG_SPRINT_START as W,SNAPSHOT_FLAG_CROUCH_SUPPRESSED as $,SNAPSHOT_FLAG_CROUCHING as Q,NetCharacterProxySmoother as J,NetCharacterSavedMoveBuffer as K,accrueNetCharacterServerMoveTime as _,createNetCharacterMovementSnapshot as tt,createNetCharacterServerMoveTimingState as et,consumeNetCharacterServerMoveTime as it,decodeNetCharacterMoveBatch as ot,decodeNetCharacterOwnerAck as st,decodeNetCharacterOwnerCorrection as nt,decodeNetCharacterSimulatedState as rt,encodeNetCharacterMoveBatch as at,encodeNetCharacterOwnerAck as ht,encodeNetCharacterOwnerCorrection as lt,encodeNetCharacterSimulatedState as ct,validateNetCharacterMove as ut}from"./net-character-movement-protocol.js";import{NetMode as dt}from"../../../../net/net-session.js";import{setSlideJumpVelocity as pt,shouldContinueSlide as mt,shouldStartSlide as vt,updateSlideVelocity as yt,updateSlideVelocityFromDisplacement as St}from"./character-slide.js";export*from"./net-character-movement-protocol.js";const gt=131070,Mt=new h(0,1,0),ft=new h,xt=new h,Tt=new h,Ct=new h,Rt=new h,wt=new h,At=new h,qt=new h,Dt=new h,bt=new h,kt=new h,Pt=new h,It=new h,zt=new h,Ot=new h(0,1,0),jt=new h(0,-.05,0),Gt=new h,Yt=new a,Ft=new s.Euler,Nt=new h,Vt=new h,Ut=new h,Xt=new h,Et=new i.CharacterCollision;let Lt=class extends R{get autoStepMinWidth(){return this.cc.autostepMinWidth()}set autoStepMinWidth(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),t,this.cc.autostepIncludesDynamicBodies())}get autoStepDynamicObjects(){return this.cc.autostepIncludesDynamicBodies()}set autoStepDynamicObjects(t){this.cc.enableAutostep(this.cc.autostepMaxHeight(),this.cc.autostepMinWidth(),t)}get autoStepMaxHeight(){return this.cc.autostepMaxHeight()}set autoStepMaxHeight(t){this.cc.enableAutostep(t,this.cc.autostepMinWidth(),this.cc.autostepIncludesDynamicBodies())}get snapToGround(){return this.cc.snapToGroundDistance()}set snapToGround(t){this.cc.enableSnapToGround(t)}set offset(t){this.cc.setOffset(t)}get offset(){return this.cc.offset()}set normalNudgeFactor(t){this.cc.setNormalNudgeFactor(t)}get normalNudgeFactor(){return this.cc.normalNudgeFactor()}constructor(){super(),this.isDefaultCharacterMovementComponent=!0,this.directionInput=new d,this.jumpInput=new u,this.sprintInput=new u,this.crouchInput=new u,this.rotationInput=new p,this.horizontalSpeed=0,this.maxSpeed=8,this.maxSpeedBackwards=8,this.maxSpeedSprint=12,this.maxSpeedCrouch=4,this.slideEnabled=!1,this.slideMinStartSpeed=8,this.slideMinExitSpeed=4,this.slideDeceleration=3,this.slideGravityScale=1,this.slideSteeringRate=2,this.sprintStartBoostSpeed=0,this.sprintStartBoostDamping=6,this.jumpVelocity=7,this.fallingMovementControl=.5,this.fallingReorientation=!1,this.groundAccelerationRate=4,this.gravityOverride=null,this.colliderHeight=2,this.colliderRadius=.5,this.crouchColliderHeight=1,this.crouchColliderRadius=null,this.jumpInAir=!1,this.mass=50,this.allowSliding=!0,this.minSlopeSlideAngle=r.degToRad(70),this.maxSlopeClimbAngle=r.degToRad(70),this.applyImpulsesToDynamicBodies=!0,this.normalizedDirection=!0,this.characterCollision=!1,this.allowRootMotionJumpCancel=!1,this.enabled=!0,this.rotateToMovementDirection=!1,this.smoothRotation=!0,this.rotationSpeed=40,this.maxRotationSpeed=100,this.impulseDamping=2,this.moveSendInterval=F,this.simulatedStateInterval=V,this.maxSavedMoves=O,this.maxReplayedMoves=I,this.maxServerMovesPerTick=z,this.maxMovesPerPacket=P,this.maxMoveDeltaTime=k,this.maxCombinedMoveDeltaTime=b,this.maxServerMoveDeltaTimeScalar=j,this.maxClientTimeAhead=q,this.maxServerMoveTimeBudget=G,this.maxSubstepDeltaTime=Y,this.fallGraceTime=.1,this.correctionToleranceSq=U*U,this.largeCorrectionThreshold=D,this.teleportSnapThreshold=X,this.listenServerSmoothing=!0,this.listenServerSmoothLocationTime=.04,this.listenServerMaxSmoothUpdateDistance=1,this.listenServerNoSmoothUpdateDistance=2.5,this.debugCorrections=!0,this.suppressUncrouchLift=!1,this.velocity=new h,this.visualSmoothingOffset=new h,this.slideDirection=new h,this.slideSurfaceNormal=new h(0,1,0),this.mode=A.walking,this.isSprinting=!1,this.isCrouching=!1,this.isSliding=!1,this.pressedJump=!1,this.rayTestResult=new f,this.groundRayTestOptions={debug:!1,excludeTriggers:!0,excludeActor:void 0},this.physicsSystem=c(M),this.netService=c(g),this.state={sequence:0,position:new h,velocity:new h,yaw:0,lookYaw:0,mode:A.walking,grounded:!1,currentSpeed:0,fallGraceTime:0,prevInputDirection:new h,prevRotateToMovementDirection:!1},this.movementModes=new Map,this.savedMoves=new K(O),this.serverMoveTiming=et(),this.serverMoveQueue=[],this.inputMoveScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0},this.authoritativeMoveScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0},this.movementModeContext={component:this,state:this.state,move:this.inputMoveScratch,deltaTime:0,rotatedDirection:xt,platformVelocity:Ct,outVelocity:Tt,rootMotionActive:!1,startedSprinting:!1},this.proxySmoother=new J(N,X),this.proxySample=tt(),this.pendingSnapshot=tt(),this.impulse=new h,this.prevRootMotionPos=new h,this.rootMotionOptions={},this.resetRootMotion=!1,this.nextMoveSequence=0,this.clientMoveTime=0,this.lastSentClientMoveTime=0,this.moveSendAccumulator=0,this.simulatedStateAccumulator=0,this.proxyTime=0,this.lastServerProcessedSequence=0,this.lastServerReceivedSequence=0,this.lastAutonomousMoveFlags=0,this.previousSprintInput=!1,this.previousCrouchInput=!1,this.crouchSuppressedUntilRelease=!1,this.slideOnLandingRequested=!1,this.initialized=!1,this.cc=this.physicsSystem.getCharacterController(.1),this.cc.enableSnapToGround(.1),this.cc.enableAutostep(0,.1,!1),this.registerMovementMode(Bt),this.registerMovementMode(Ht),this.registerMovementMode({mode:A.sliding,update:t=>this.updateSlidingMode(t)})}onInit(){this.groundRayTestOptions.excludeActor=this.actor,this.configureCharacterController(),this.physicsSystem.addActor(this.actor,[this.createCollisionShape()],{mass:0,type:C.kinematic,continousCollisionDetection:!1,friction:0,restitution:.5,ignoreForNavMesh:!0}),this.rotationInput.rotation.copy(this.actor.rotation),this.initializeStateFromActor(),this.initialized=!0,this.physicsSystem.beforeStep.pipe(o(this.disposed)).subscribe(t=>this.tick(t))}onLateUpdate(t){this.updateVisualSmoothing(t)}registerMovementMode(t){this.movementModes.set(t.mode,t)}applyImpulse(t){this.impulse.add(t)}getEffectiveGravity(){return this.gravityOverride??this.physicsSystem.getGravity().y}get isGrounded(){return this.rayTestResult.hasHit||this.cc.computedGrounded()}setRootMotionAction(t,e={}){const i=t?.getClip();if(i instanceof l){this.rootMotionAction=t,this.rootMotionOptions=e,this.resetRootMotion=!0;const o=[];this.rootMotionInterpolant=i.motionTrack.InterpolantFactoryMethodSmooth(o);const n=s.PropertyBinding.parseTrackName(i.motionTrack.name);this.rootMotionRootBone=this.actor.object.getObjectByName(n.nodeName)}}serverMove(t){const e=ot(t);if(e.ok)for(const t of e.value.moves)ut(t,this.lastServerReceivedSequence,this.maxMoveDeltaTime)&&(this.lastServerReceivedSequence=t.sequence,this.serverMoveQueue.push(t))}clientMoveAck(t){const e=st(t);e.ok&&this.actor.netRole===m.autonomousProxy&&(this.savedMoves.ack(e.value.sequence),this.sprintPolicy?.ack?.(e.value.sequence,!1))}clientMoveCorrection(t){const e=nt(t);e.ok&&this.actor.netRole===m.autonomousProxy&&(this.debugCorrections&&(null==this.correctionDebug&&(this.correctionDebug=new Qt(Kt(this.actor.object))),this.correctionDebug.update(this.state.position,e.value.snapshot)),this.applyCorrection(e.value.snapshot))}simulatedState(t){const e=rt(t);e.ok&&this.actor.netRole===m.simulatedProxy&&this.proxySmoother.push(e.value,this.proxyTime)}tick(t){if(!this.initialized)return;t=Math.min(.1,t);const e=this.actor.netRole,i=this.netService.mode;e!==m.simulatedProxy?this.enabled&&(e!==m.autonomousProxy?this.isRemoteControlledAuthority(i,e)?this.tickRemoteAuthority(t):this.tickAuthority(t,i):this.tickAutonomousProxy(t)):this.tickSimulatedProxy(t)}tickAutonomousProxy(t){const e=this.state.mode,i=this.lastAutonomousMoveFlags,o=this.createMoveFromInput(t,++this.nextMoveSequence,{quantizeClientTime:!0});this.performMove(o,_t);const s=this.state.mode!==e||o.flags!==i;this.lastAutonomousMoveFlags=o.flags,this.savedMoves.capacity=this.maxSavedMoves,this.savedMoves.maxCombinedDeltaTime=Math.min(this.maxCombinedMoveDeltaTime,this.maxMoveDeltaTime),this.savedMoves.push(o),this.sendSavedMoves(t,s)}tickAuthority(t,e){const i=this.createMoveFromInput(t,++this.nextMoveSequence);this.performMove(i,_t),e!==dt.none&&this.sendSimulatedState(t,!1)}tickRemoteAuthority(t){_(this.serverMoveTiming,t,this.maxServerMoveTimeBudget);let e=!1;const i=Number.isFinite(this.maxServerMovesPerTick)?Math.max(1,Math.floor(this.maxServerMovesPerTick)):this.serverMoveQueue.length,o=Math.min(this.serverMoveQueue.length,i),s=Ut.copy(this.actor.position);let n=!1;for(let t=0;t<o;t++){const t=this.serverMoveQueue.shift();if(null==t)break;if(!ut(t,this.lastServerProcessedSequence,this.maxMoveDeltaTime)){console.log("Net: Invalid move",t),this.sendOwnerCorrection(!0),e=!0;continue}const i=it(this.serverMoveTiming,t,{maxMoveDeltaTime:this.maxMoveDeltaTime,maxServerMoveDeltaTimeScalar:this.maxServerMoveDeltaTimeScalar,maxClientTimeAhead:this.maxClientTimeAhead});if(i<0){this.sendOwnerCorrection(!0),e=!0;continue}const o=Wt(t,this.authoritativeMoveScratch);o.dt=i,o.rootMotionX=0,o.rootMotionY=0,o.rootMotionZ=0,o.flags&=~B,this.performMove(o,{immediate:!0,savedRootMotion:!1}),n=!0,this.lastServerProcessedSequence=o.sequence;const s=$t(this.state,t);if(s>this.correctionToleranceSq){console.log(`Net server: Correction error: ${Math.sqrt(s)}`);const o=this.state.position.x-t.clientX,n=this.state.position.y-t.clientY,r=this.state.position.z-t.clientZ;console.log(`diff x: ${o}, y: ${n}, z: ${r}`),console.log({sequence:t.sequence,moveDt:t.dt,serverMoveDeltaTime:i,flags:t.flags,mode:this.state.mode,grounded:this.state.grounded,fallGraceTime:this.state.fallGraceTime}),this.sendOwnerCorrection(s>this.largeCorrectionThreshold*this.largeCorrectionThreshold),e=!0}}0===this.lastServerProcessedSequence||e||(this.sprintPolicy?.ack?.(this.lastServerProcessedSequence,!1),this.clientMoveAck(ht(this.lastServerProcessedSequence))),n&&this.accumulateListenServerVisualSmoothing(s,this.actor.position),this.sendSimulatedState(t,!1)}tickSimulatedProxy(t){this.proxyTime+=t,this.proxySmoother.sample(this.proxyTime,this.proxySample)&&this.applySnapshot(this.proxySample,!0)}accumulateListenServerVisualSmoothing(t,e){if(!this.shouldSmoothListenServerRemoteAuthority())return void this.visualSmoothingOffset.set(0,0,0);Xt.subVectors(t,e);const i=Xt.lengthSq();i>1e-8&&(i>this.listenServerNoSmoothUpdateDistance*this.listenServerNoSmoothUpdateDistance?this.visualSmoothingOffset.set(0,0,0):(i>this.listenServerMaxSmoothUpdateDistance*this.listenServerMaxSmoothUpdateDistance&&Xt.setLength(this.listenServerMaxSmoothUpdateDistance),this.visualSmoothingOffset.add(Xt)))}updateVisualSmoothing(t){if(this.visualSmoothingOffset.lengthSq()<=1e-8)return void this.visualSmoothingOffset.set(0,0,0);if(!this.shouldSmoothListenServerRemoteAuthority())return void this.visualSmoothingOffset.set(0,0,0);const e=Math.max(.001,this.listenServerSmoothLocationTime);t<e?this.visualSmoothingOffset.multiplyScalar(1-t/e):this.visualSmoothingOffset.set(0,0,0),this.visualSmoothingOffset.lengthSq()<=1e-4&&this.visualSmoothingOffset.set(0,0,0)}shouldSmoothListenServerRemoteAuthority(){return this.listenServerSmoothing&&this.actor.netRole===m.authority&&this.netService.isServer&&!this.netService.isDedicatedServer&&this.isRemoteControlledAuthority()}createMoveFromInput(t,e,i={}){const o=r.clamp(t,.001,this.maxMoveDeltaTime);this.clientMoveTime+=o;let s=this.clientMoveTime,n=o;!0===i.quantizeClientTime&&(s=Math.max(this.lastSentClientMoveTime+.001,Math.round(1e3*this.clientMoveTime)/1e3),n=r.clamp(s-this.lastSentClientMoveTime,.001,this.maxMoveDeltaTime),this.lastSentClientMoveTime=s),this.sampleRootMotion(At);const a=this.crouchInput.activated,h=a&&!this.previousCrouchInput;this.previousCrouchInput=a;const l=!a&&this.sprintInput.activated,c=l&&!this.previousSprintInput;this.previousSprintInput=l;const u=(this.jumpInput.activated?L:0)|(l?Z:0)|(a?E:0)|(h&&this.slideEnabled?H:0)|(c?W:0)|(At.lengthSq()>0?B:0),d=function(t,e){e.set(t.x,0,t.y),e.lengthSq()>1&&e.normalize();return e}(this.directionInput.vector,Nt),p=this.inputMoveScratch;return p.sequence=e>>>0,p.clientTime=s,p.dt=n,p.inputX=d.x,p.inputY=d.z,p.yaw=this.rotationInput.rotation.y,p.flags=u,p.clientX=this.state.position.x,p.clientY=this.state.position.y,p.clientZ=this.state.position.z,p.rootMotionX=At.x,p.rootMotionY=At.y,p.rootMotionZ=At.z,p}performMove(t,e){const i=r.clamp(t.dt,.001,this.maxMoveDeltaTime),o=Math.max(1,Math.ceil(i/this.maxSubstepDeltaTime)),s=0!==(t.flags&Z)&&0===(t.flags&E);this.sprintPolicy?.update?.(i,t.sequence,s),Pt.set(e.savedRootMotion?t.rootMotionX:0,e.savedRootMotion?t.rootMotionY:0,e.savedRootMotion?t.rootMotionZ:0),e.savedRootMotion||this.sampleRootMotion(Pt);let n=i;const a=i/o;for(let s=0;s<o;s++){const o=i>0?a/i:1;this.performSubstep(t,Math.min(a,n),Pt,o,e.immediate,0===s),n-=a}t.clientX=this.state.position.x,t.clientY=this.state.position.y,t.clientZ=this.state.position.z,t.flags=Pt.lengthSq()>0?t.flags|B:t.flags&~B,this.state.sequence=t.sequence,this.syncPublicState()}performSubstep(t,e,i,o,s,n){if(e<.001)return;this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded;const r=null!=this.rootMotionAction&&this.rootMotionAction.enabled,a=i.lengthSq()>0,h=!r&&0!==(t.flags&L),l=r||a;this.updateCrouchState(t,n,l,h),this.pressedJump=h,this.isSprinting=!1,this.updateRotation(t,e,r,a),this.resolvePlatformVelocity(Ct);const c=this.movementModeContext,u=this.movementModes.get(this.state.mode);if(null!=u){c.move=t,c.deltaTime=e,c.rootMotionActive=l,c.startedSprinting=n&&!l&&0===(t.flags&E)&&0!==(t.flags&W);const i=u.update(c);"number"==typeof i&&(this.state.mode=i)}else Tt.set(0,0,0);if(a){qt.copy(i).multiplyScalar(o).applyQuaternion(this.actor.quaternion),Dt.copy(qt).divideScalar(e),this.state.mode===A.walking?(Tt.x=Dt.x+Ct.x,Tt.z=Dt.z+Ct.z):(Tt.x=Dt.x,Tt.z=Dt.z);const t=Math.sqrt(Dt.x*Dt.x+Dt.z*Dt.z);t>.4&&(this.state.currentSpeed=t)}this.applyImpulseToVelocity(Tt,e),this.state.mode===A.walking&&this.state.velocity.copy(Tt),this.applyMovement(Tt,e,s),this.state.mode===A.sliding&&(St(this.state.velocity,wt,Ct,this.slideSurfaceNormal,e),this.state.currentSpeed=Zt(this.state.velocity)),this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded,this.updateModeAfterMove(Tt,e),this.state.mode===A.sliding&&this.state.velocity.length()<Math.max(0,this.slideMinExitSpeed)&&(this.state.mode=A.walking)}updateRotation(t,e,i,o){ft.set(-t.inputX,0,t.inputY),ft.lengthSq()>1&&ft.normalize();const s=this.state.prevRotateToMovementDirection!==this.rotateToMovementDirection;let n=r.euclideanModulo(t.yaw-this.state.lookYaw+Math.PI,2*Math.PI)-Math.PI;if(s&&(this.actor.object.quaternion.setFromEuler(Ft.set(0,t.yaw,0)),this.state.prevRotateToMovementDirection||(n=0,this.state.lookYaw=t.yaw),this.state.prevRotateToMovementDirection=this.rotateToMovementDirection),xt.set(0,0,0),i)this.state.lookYaw=t.yaw;else if(this.rotateToMovementDirection){if(ft.lengthSq()>0&&this.state.mode!==A.falling){const i=Ft.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,o=Math.atan2(ft.x,ft.z),s=.99*t.yaw+o;if(this.smoothRotation){const t=r.euclideanModulo(s-i+Math.PI,2*Math.PI)-Math.PI;let o=r.clamp(t*this.rotationSpeed*e,-this.maxRotationSpeed*e,this.maxRotationSpeed*e);Math.abs(o)>Math.abs(t)&&(o=t),this.actor.object.quaternion.setFromEuler(Ft.set(0,i+o,0))}else this.actor.object.quaternion.setFromEuler(Ft.set(0,s,0));this.state.prevInputDirection.lerp(ft,e*this.rotationSpeed),this.state.lookYaw+=n,xt.copy(this.actor.object.getWorldDirection(Nt).normalize())}}else o||(this.state.lookYaw+=n,this.actor.object.quaternion.multiply(Yt.setFromEuler(Ft.set(0,n,0))),ft.lengthSq()>0&&xt.copy(ft).applyQuaternion(this.actor.object.quaternion).normalize())}applyMovement(t,e,i){if(t.lengthSq()>0||!this.state.grounded){if(Rt.copy(t).multiplyScalar(e),this.state.grounded&&((o=this.state.mode)===A.walking||o===A.sliding)&&(this.state.mode===A.walking&&this.rayTestResult.distance<=this.cc.offset()&&(Rt.y=Math.max(0,Ct.y*e)),this.physicsSystem.getActorComputedMovement(this.actor,this.cc,Rt,this.getCollisionGroup()),this.cc.computedCollision(0,Et),null!=Et.normal1)){const t=Nt.copy(Et.normal1);Math.acos(r.clamp(t.dot(Mt),-1,1))>this.cc.maxSlopeClimbAngle()&&(Rt.y=.016*this.getEffectiveGravity()*.5)}wt.copy(this.physicsSystem.getActorComputedMovement(this.actor,this.cc,Rt,this.getCollisionGroup()))}else wt.set(0,0,0);var o;this.suppressUncrouchLift&&(this.suppressUncrouchLift=!1,this.state.grounded&&this.state.mode===A.walking&&Rt.y<=1e-6&&wt.y>0&&(wt.y=0)),this.state.position.add(wt),i?(this.actor.position.copy(this.state.position),this.physicsSystem.updateActorTransform(this.actor),this.physicsSystem.flushModifiedBodyPositionsToColliders()):this.physicsSystem.setNextKinematicPosition(this.actor,this.state.position)}updateModeAfterMove(t,e){const i=function(t){if(0===t.numComputedCollisions())return!1;const e=t.computedCollision(0);Gt.set(e.normal2.x,e.normal2.y,e.normal2.z);const i=Gt.angleTo(Mt);Gt.set(e.normal1.x,e.normal1.y,e.normal1.z);const o=Gt.angleTo(Mt);if(i<100)return!1;return o>t.minSlopeSlideAngle()}(this.cc);!this.state.grounded||i?this.state.mode!==A.falling&&(this.state.fallGraceTime+=e,this.state.fallGraceTime>this.fallGraceTime+1e-6&&(this.state.mode=A.falling,this.state.velocity.copy(t))):this.state.velocity.y<=0&&(this.state.mode===A.falling&&(this.state.mode=A.walking),this.state.mode!==A.sliding&&(this.state.velocity.y=0),this.state.fallGraceTime=0)}applyImpulseToVelocity(t,e){if(this.impulse.lengthSq()<=.1)return void this.impulse.set(0,0,0);const i=Math.min(1,this.impulse.length()/5);t.x=r.lerp(t.x,this.impulse.x,i),t.z=r.lerp(t.z,this.impulse.z,i),t.y+=this.impulse.y;const o=Math.exp(-this.impulseDamping*e);this.impulse.x*=o,this.impulse.y>0?this.impulse.y+=e*this.getEffectiveGravity():this.impulse.y*=o,this.impulse.z*=o}sendSavedMoves(t,e=!1){if(this.moveSendAccumulator+=t,!e&&this.moveSendAccumulator<this.moveSendInterval)return;this.moveSendAccumulator=0;const i=this.savedMoves.getMovesForSend(this.maxMovesPerPacket);0!==i.length&&this.serverMove(at(i))}sendOwnerCorrection(t){const e=this.toSnapshot(this.pendingSnapshot);t&&(e.horizontalSpeed=this.horizontalSpeed),this.sprintPolicy?.ack?.(e.sequence,!0),this.clientMoveCorrection(lt(e))}sendSimulatedState(t,e){this.simulatedStateAccumulator+=t,!e&&this.simulatedStateAccumulator<this.simulatedStateInterval||(this.simulatedStateAccumulator=0,this.simulatedState(ct(this.toSnapshot(this.pendingSnapshot))))}applyCorrection(t){this.sprintPolicy?.restore?.(t.sequence),this.savedMoves.ack(t.sequence),this.sprintPolicy?.ack?.(t.sequence,!0),this.applySnapshot(t,!0),this.savedMoves.replayAfter(t.sequence,t=>(this.performMove(t,{immediate:!0,savedRootMotion:!0}),null),this.maxReplayedMoves)}applySnapshot(t,e){this.state.sequence=t.sequence,this.state.position.set(t.x,t.y,t.z),this.state.velocity.set(t.velocityX,t.velocityY,t.velocityZ),this.state.yaw=t.yaw,this.state.lookYaw=t.yaw,this.state.mode=t.mode,this.state.currentSpeed=t.horizontalSpeed,this.state.fallGraceTime=0,this.actor.position.copy(this.state.position),this.actor.object.quaternion.setFromEuler(Ft.set(0,t.yaw,0)),this.crouchSuppressedUntilRelease=0!==(t.flags&$),this.setCrouching(0!==(t.flags&Q)||t.mode===A.sliding),e&&(this.physicsSystem.updateActorTransform(this.actor),this.physicsSystem.flushModifiedBodyPositionsToColliders()),this.checkGrounded(this.state.position),this.state.grounded=this.isGrounded,this.syncPublicState()}toSnapshot(t){return t.sequence=this.state.sequence,t.x=this.state.position.x,t.y=this.state.position.y,t.z=this.state.position.z,t.velocityX=this.state.velocity.x,t.velocityY=this.state.velocity.y,t.velocityZ=this.state.velocity.z,t.yaw=Ft.setFromQuaternion(this.actor.object.quaternion,"YXZ").y,t.mode=this.state.mode,t.flags=(this.isCrouching?Q:0)|(this.crouchSuppressedUntilRelease?$:0),t.horizontalSpeed=this.state.currentSpeed,t}syncPublicState(){this.velocity.copy(this.state.velocity),this.mode=this.state.mode,this.horizontalSpeed=this.state.currentSpeed,this.isSliding=this.state.mode===A.sliding,this.isSliding?(this.resolveGroundNormal(this.slideSurfaceNormal),this.slideDirection.copy(this.state.velocity).projectOnPlane(this.slideSurfaceNormal),this.slideDirection.lengthSq()>1e-8?this.slideDirection.normalize():this.slideDirection.set(0,0,0)):(this.slideDirection.set(0,0,0),this.slideSurfaceNormal.copy(Mt))}sampleRootMotion(t){if(t.set(0,0,0),null==this.rootMotionAction||this.rootMotionAction.isRunning()||this.clearRootMotionAction(this.rootMotionAction),null!=this.rootMotionAction&&this.rootMotionOptions.cancelWithJump&&this.jumpInput.activated&&(this.isGrounded||this.jumpInAir)){const e=this.rootMotionAction,i=this.rootMotionOptions.onJumpCancel;return this.clearRootMotionAction(e),e.stop(),i?.(),t}if(null==this.rootMotionAction)return t;if(!(this.rootMotionAction.getClip()instanceof l))return t;const e=this.rootMotionInterpolant;this.resetRootMotion&&(this.prevRootMotionPos.fromArray(e.evaluate(0)),this.resetRootMotion=!1),kt.fromArray(e.evaluate(this.rootMotionAction.time)),t.subVectors(kt,this.prevRootMotionPos),this.prevRootMotionPos.copy(kt);return(this.rootMotionRootBone??this.rootMotionAction.getRoot()).getWorldScale(bt),t.multiply(bt),t}clearRootMotionAction(t){null!=t&&this.rootMotionAction!==t||(this.rootMotionAction=null,this.rootMotionOptions={},this.resetRootMotion=!1)}isRemoteControlledAuthority(t=this.netService.mode,e=this.actor.netRole){if(t===dt.none||e!==m.authority||t>=dt.client)return!1;return null!=this.netService.resolveActorConnection(this.actor)&&!this.netService.isLocalOwner(this.actor)}configureCharacterController(){const t=this.cc;t.setApplyImpulsesToDynamicBodies(this.applyImpulsesToDynamicBodies),t.setMinSlopeSlideAngle(this.minSlopeSlideAngle),t.setMaxSlopeClimbAngle(this.maxSlopeClimbAngle),t.setCharacterMass(this.mass),t.setSlideEnabled(this.allowSliding)}initializeStateFromActor(){this.state.position.copy(this.actor.position),this.state.velocity.set(0,0,0),this.state.yaw=this.actor.rotation.y,this.state.lookYaw=this.rotationInput.rotation.y,this.state.mode=this.mode,this.state.currentSpeed=this.horizontalSpeed,this.state.prevRotateToMovementDirection=this.rotateToMovementDirection}createCollisionShape(){const t=this.getColliderHeight(!1),e=this.getColliderRadius(!1),i=new x(t,e);return i.offset.y=this.getCapsuleOffsetY(t,e),i.collisionGroup=gt,i}updateCrouchState(t,e,i,o){if(!(0!==(t.flags&E)))return this.crouchSuppressedUntilRelease=!1,this.slideOnLandingRequested=!1,this.state.mode===A.sliding&&(this.state.mode=A.walking),void this.tryUncrouch();if(this.state.mode===A.sliding&&(!this.slideEnabled||i))return this.slideOnLandingRequested=!1,this.state.mode=A.walking,void(this.crouchSuppressedUntilRelease||this.setCrouching(!0));if(this.state.mode===A.sliding&&o)return this.crouchSuppressedUntilRelease=!0,this.slideOnLandingRequested=!1,void this.tryUncrouch();if(this.crouchSuppressedUntilRelease)return void(this.slideOnLandingRequested=!1);if(this.setCrouching(!0),!this.slideEnabled||i)return void(this.slideOnLandingRequested=!1);if(this.state.mode===A.falling)return void(this.slideOnLandingRequested=!0);this.resolveGroundNormal(Vt);const s=this.slideOnLandingRequested&&this.state.mode===A.walking&&this.state.grounded,n=e&&0!==(t.flags&H)||s;s&&(this.slideOnLandingRequested=!1);const r=Zt(this.state.velocity);this.state.mode===A.walking&&vt(this.slideEnabled,n,this.state.grounded,this.isWalkableSlideSurface(Vt),i,r,this.slideMinStartSpeed)&&(this.state.mode=A.sliding,this.slideSurfaceNormal.copy(Vt),this.state.velocity.projectOnPlane(this.slideSurfaceNormal),this.state.currentSpeed=Zt(this.state.velocity))}updateSlidingMode(t){const e=t.state,i=t.move;this.resolveGroundNormal(this.slideSurfaceNormal);const o=this.isWalkableSlideSurface(this.slideSurfaceNormal),s=e.velocity.length();if(!e.grounded||!o)return e.mode=A.falling,Ht.update(t),A.falling;if(this.slideEnabled&&0!==(i.flags&E)&&!t.rootMotionActive&&0!==(i.flags&L))return pt(t.outVelocity,e.velocity,this.jumpVelocity),e.velocity.copy(t.outVelocity),e.currentSpeed=Zt(e.velocity),A.falling;if(!mt(this.slideEnabled,0!==(i.flags&E),e.grounded,o,t.rootMotionActive,s,this.slideMinExitSpeed))return e.mode=A.walking,Bt.update(t),A.walking;const n=yt(e.velocity,e.velocity,this.slideSurfaceNormal,t.rotatedDirection,this.getEffectiveGravity(),t.deltaTime,this.slideDeceleration,this.slideGravityScale,this.slideSteeringRate);if(e.currentSpeed=Zt(e.velocity),n<Math.max(0,this.slideMinExitSpeed))return e.mode=A.walking,Bt.update(t),A.walking;t.outVelocity.copy(e.velocity).add(t.platformVelocity)}tryUncrouch(){this.isCrouching&&this.canUncrouch()&&this.setCrouching(!1)&&(this.suppressUncrouchLift=!0,this.state.fallGraceTime=0)}resolveGroundNormal(t){return!this.rayTestResult.hasHit||this.rayTestResult.hitNormal.lengthSq()<=1e-8?t.copy(Mt):(t.copy(this.rayTestResult.hitNormal).normalize(),t.dot(Mt)<0&&t.multiplyScalar(-1),t)}isWalkableSlideSurface(t){return t.dot(Mt)>=Math.cos(this.cc.maxSlopeClimbAngle())}setCrouching(t){return this.isCrouching!==t&&(this.isCrouching=t,this.syncColliderShape(),!0)}canUncrouch(){const t=this.getColliderHeight(!1),e=this.getColliderRadius(!1);return!this.physicsSystem.hasActorCapsuleIntersection(this.actor,this.state.position,t,e,this.getCapsuleOffsetY(t,e),this.getCollisionGroup())}syncColliderShape(){const t=this.getColliderHeight(this.isCrouching),e=this.getColliderRadius(this.isCrouching);this.physicsSystem.setActorCapsuleCollider(this.actor,t,e,this.getCapsuleOffsetY(t,e))}getColliderHeight(t){const e=Number.isFinite(this.colliderHeight)?Math.max(0,this.colliderHeight):0;if(!t)return e;const i=Number.isFinite(this.crouchColliderHeight)?this.crouchColliderHeight:e;return r.clamp(i,0,e)}getColliderRadius(t){const e=Number.isFinite(this.colliderRadius)?Math.max(.001,this.colliderRadius):.001;if(!t)return e;const i=this.crouchColliderRadius??e,o=Number.isFinite(i)?i:e;return r.clamp(o,.001,e)}getCapsuleOffsetY(t,e){return e+t/2+this.offset}checkGrounded(t){jt.y=-Math.max(.05,this.cc.snapToGroundDistance()),this.physicsSystem.rayTest(It.addVectors(t,Ot.set(0,this.offset,0)),zt.addVectors(t,jt),this.rayTestResult,this.groundRayTestOptions)}resolvePlatformVelocity(t){return t.set(0,0,0),this.rayTestResult.hasHit&&null!=this.rayTestResult.actor&&this.physicsSystem.getLinearVelocity(this.rayTestResult.actor,t),t}getCollisionGroup(){return this.characterCollision?null:gt}};t([T(),e("design:type",Object)],Lt.prototype,"colliderHeight",void 0),t([T(),e("design:type",Object)],Lt.prototype,"colliderRadius",void 0),t([T(),e("design:type",Object)],Lt.prototype,"crouchColliderHeight",void 0),t([T(),e("design:type",Number)],Lt.prototype,"crouchColliderRadius",void 0),t([S(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Lt.prototype,"serverMove",null),t([v(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Lt.prototype,"clientMoveAck",null),t([v(!0),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Lt.prototype,"clientMoveCorrection",null),t([y(!1),e("design:type",Function),e("design:paramtypes",[Uint8Array]),e("design:returntype",void 0)],Lt.prototype,"simulatedState",null),Lt=t([w({inEditor:!1}),e("design:paramtypes",[])],Lt);export{Lt as CharacterMovementComponent};const Bt={mode:A.walking,update(t){const e=t.component,i=t.move,o=t.state,s=t.rotatedDirection,n=Math.min(1,Math.sqrt(i.inputX*i.inputX+i.inputY*i.inputY)),r=!e.rotateToMovementDirection&&i.inputY<0,a=e.isCrouching,h=!t.rootMotionActive&&!a&&0===(i.flags&E)&&0!==(i.flags&Z)&&!r&&0!==s.lengthSq()&&(e.sprintPolicy?.canSprint()??!0),l=(a?e.maxSpeedCrouch:r?e.maxSpeedBackwards:h?e.maxSpeedSprint:e.maxSpeed)*(e.normalizedDirection?1:n);if(0!==s.lengthSq()){e.isSprinting=h,h&&e.sprintPolicy?.commitSprint(t.deltaTime,i.sequence);let a=Math.min(l,o.currentSpeed),c=e.groundAccelerationRate;if(h&&t.startedSprinting&&e.sprintStartBoostSpeed>0){const t=e.normalizedDirection?1:n;a=Math.max(a,l+e.sprintStartBoostSpeed*t),c=e.sprintStartBoostDamping}else h&&!r&&e.sprintStartBoostSpeed>0&&o.currentSpeed>l&&(a=o.currentSpeed,c=e.sprintStartBoostDamping);o.currentSpeed=function(t,e,i,o){return e+(t-e)*Math.exp(-i*o)}(a,l,c,t.deltaTime),t.outVelocity.copy(s).multiplyScalar(function(t,e,i,o){const s=i*o;if(s<=1e-6)return t;return e+(t-e)*(1-Math.exp(-s))/s}(a,l,c,t.deltaTime))}else o.currentSpeed=0,t.outVelocity.set(0,0,0);if(0!==(i.flags&L))return o.mode=A.falling,o.velocity.copy(t.outVelocity),o.velocity.y=e.jumpVelocity,A.falling;t.outVelocity.y=t.deltaTime*e.getEffectiveGravity(),t.outVelocity.add(t.platformVelocity)}},Ht={mode:A.falling,update(t){const e=t.component,i=t.state,o=t.move;0!==(o.flags&L)&&e.jumpInAir&&(i.velocity.copy(t.outVelocity),i.velocity.y=e.jumpVelocity),i.velocity.y+=t.deltaTime*e.getEffectiveGravity(),t.outVelocity.copy(i.velocity),t.outVelocity.addScaledVector(t.rotatedDirection,e.fallingMovementControl),e.fallingReorientation&&t.outVelocity.applyAxisAngle(Mt,r.euclideanModulo(o.yaw-i.lookYaw+Math.PI,2*Math.PI)-Math.PI)}};function Zt(t){return Math.sqrt(t.x*t.x+t.z*t.z)}function Wt(t,e){return e.sequence=t.sequence,e.clientTime=t.clientTime,e.dt=t.dt,e.inputX=t.inputX,e.inputY=t.inputY,e.yaw=t.yaw,e.flags=t.flags,e.clientX=t.clientX,e.clientY=t.clientY,e.clientZ=t.clientZ,e.rootMotionX=t.rootMotionX,e.rootMotionY=t.rootMotionY,e.rootMotionZ=t.rootMotionZ,e}function $t(t,e){const i=t.position.x-e.clientX,o=t.position.y-e.clientY,s=t.position.z-e.clientZ;return i*i+o*o+s*s}class Qt{constructor(t){this.scene=t,this.serverPosition=new h,this.direction=new h}update(t,e){const i=this.serverPosition.set(e.x,e.y,e.z),o=i.distanceTo(t);o>.1&&console.log(`Correction applied. Error: ${o.toFixed(3)}. Server position: (${i.x.toFixed(2)}, ${i.y.toFixed(2)}, ${i.z.toFixed(2)}), Client position: (${t.x.toFixed(2)}, ${t.y.toFixed(2)}, ${t.z.toFixed(2)})`);const s=this.direction.copy(i).sub(t).normalize();Jt.position.copy(t),Jt.setDirection(s),Jt.setLength(o);const n=Kt(this.scene);n.add(Jt),setTimeout(()=>{n.remove(Jt)},1e3)}}const Jt=new n(new h(0,1,0),new h,1,16711680);function Kt(t){return null==t.parent?t:Kt(t.parent)}const _t={immediate:!1,savedRootMotion:!0};/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
export declare function shouldStartSlide(enabled: boolean, startRequested: boolean, grounded: boolean, walkableSurface: boolean, rootMotionActive: boolean, speed: number, minStartSpeed: number): boolean;
|
|
3
|
+
export declare function shouldContinueSlide(enabled: boolean, inputHeld: boolean, grounded: boolean, walkableSurface: boolean, rootMotionActive: boolean, speed: number, minExitSpeed: number): boolean;
|
|
4
|
+
export declare function updateSlideVelocity(out: Vector3, velocity: Vector3, surfaceNormal: Vector3, steeringInput: Vector3, gravity: number, deltaTime: number, deceleration: number, gravityScale: number, steeringRate: number): number;
|
|
5
|
+
export declare function updateSlideVelocityFromDisplacement(out: Vector3, correctedDisplacement: Vector3, platformVelocity: Vector3, surfaceNormal: Vector3, deltaTime: number): number;
|
|
6
|
+
export declare function setSlideJumpVelocity(out: Vector3, slideVelocity: Vector3, jumpVelocity: number): Vector3;
|
|
7
|
+
//# sourceMappingURL=character-slide.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{Vector3 as t}from"three";const e=new t,n=new t,o=new t,a=new t,r=1e-8;export function shouldStartSlide(t,e,n,o,a,r,l){return t&&e&&n&&o&&!a&&r>=Math.max(0,l)}export function shouldContinueSlide(t,e,n,o,a,r,l){return t&&e&&n&&o&&!a&&r>=Math.max(0,l)}export function updateSlideVelocity(t,l,c,i,p,u,m,s,h){t.copy(l).projectOnPlane(c);const x=Math.max(0,u);e.set(0,p,0).projectOnPlane(c).multiplyScalar(Math.max(0,s)),t.addScaledVector(e,x);let d=t.length();if(d<=r)return t.set(0,0,0),0;if(d=Math.max(0,d-Math.max(0,m)*x),d<=r)return t.set(0,0,0),0;if(n.copy(t).normalize(),o.copy(i).projectOnPlane(c),o.lengthSq()>r&&h>0){o.normalize();const t=Math.max(-1,Math.min(1,n.dot(o))),e=Math.acos(t);e>r&&(a.crossVectors(n,o),a.lengthSq()<=r?a.copy(c):a.normalize(),n.applyAxisAngle(a,Math.min(e,h*x)))}return t.copy(n).multiplyScalar(d),d}export function updateSlideVelocityFromDisplacement(t,e,n,o,a){return a<=r?(t.set(0,0,0),0):(t.copy(e).multiplyScalar(1/a).sub(n).projectOnPlane(o),t.length())}export function setSlideJumpVelocity(t,e,n){return t.set(e.x,n,e.z),t}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export var CharacterMovementMode;!function(
|
|
1
|
+
export var CharacterMovementMode;!function(i){i[i.walking=0]="walking",i[i.swimming=1]="swimming",i[i.falling=2]="falling",i[i.flying=3]="flying",i[i.sliding=4]="sliding"}(CharacterMovementMode||(CharacterMovementMode={}));/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CharacterMovementMode } from "./modes.js";
|
|
2
|
-
export declare const NET_CHARACTER_MOVEMENT_VERSION =
|
|
2
|
+
export declare const NET_CHARACTER_MOVEMENT_VERSION = 4;
|
|
3
3
|
export declare const MOVE_PACKET_KIND = 1;
|
|
4
4
|
export declare const OWNER_ACK_PACKET_KIND = 2;
|
|
5
5
|
export declare const OWNER_CORRECTION_PACKET_KIND = 3;
|
|
@@ -25,7 +25,9 @@ export declare const MOVE_FLAG_SPRINT: number;
|
|
|
25
25
|
export declare const MOVE_FLAG_ROOT_MOTION: number;
|
|
26
26
|
export declare const MOVE_FLAG_SPRINT_START: number;
|
|
27
27
|
export declare const MOVE_FLAG_CROUCH: number;
|
|
28
|
+
export declare const MOVE_FLAG_SLIDE_START: number;
|
|
28
29
|
export declare const SNAPSHOT_FLAG_CROUCHING: number;
|
|
30
|
+
export declare const SNAPSHOT_FLAG_CROUCH_SUPPRESSED: number;
|
|
29
31
|
export type NetCharacterMove = {
|
|
30
32
|
sequence: number;
|
|
31
33
|
clientTime: number;
|
package/dist/gameplay/actors/builtin/components/character/net-character-movement-protocol.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{MathUtils as t}from"three";import{CharacterMovementMode as e}from"./modes.js";export const NET_CHARACTER_MOVEMENT_VERSION=3;export const MOVE_PACKET_KIND=1;export const OWNER_ACK_PACKET_KIND=2;export const OWNER_CORRECTION_PACKET_KIND=3;export const SIMULATED_STATE_PACKET_KIND=4;export const DEFAULT_MOVE_SEND_INTERVAL=1/30;export const DEFAULT_SIMULATED_STATE_INTERVAL=.05;export const DEFAULT_MAX_SAVED_MOVES=128;export const DEFAULT_MAX_REPLAYED_MOVES=64;export const DEFAULT_MAX_SERVER_MOVES_PER_TICK=4;export const DEFAULT_MAX_MOVES_PER_PACKET=16;export const DEFAULT_MAX_MOVE_DELTA_TIME=1/15;export const DEFAULT_MAX_COMBINED_MOVE_DELTA_TIME=1/15;export const DEFAULT_MAX_SUBSTEP_DELTA_TIME=.017;export const DEFAULT_MAX_SERVER_MOVE_DELTA_TIME_SCALAR=1.75;export const DEFAULT_MAX_CLIENT_TIME_AHEAD=.1;export const DEFAULT_MAX_SERVER_MOVE_TIME_BUDGET=.25;export const DEFAULT_SMALL_CORRECTION_TOLERANCE=.08;export const DEFAULT_LARGE_CORRECTION_THRESHOLD=1;export const DEFAULT_TELEPORT_SNAP_THRESHOLD=5;export const DEFAULT_SIMULATED_INTERPOLATION_DELAY=.1;export const MOVE_FLAG_JUMP=1;export const MOVE_FLAG_SPRINT=2;export const MOVE_FLAG_ROOT_MOTION=4;export const MOVE_FLAG_SPRINT_START=8;export const MOVE_FLAG_CROUCH=16;export const SNAPSHOT_FLAG_CROUCHING=1;const n=.001;export class NetCharacterSavedMoveBuffer{constructor(t=128,e=.06666666666666667){this.capacity=t,this.maxCombinedDeltaTime=e,this.moves=[],this.freeMoves=[],this.sendScratch=[],this.replayScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0}}get length(){return this.moves.length+(null==this.pending?0:1)}push(e){if(null!=this.pending){if(function(e,o,i=.06666666666666667){if(i<0)return!1;if(s=e.sequence,r=o.sequence,(s>>>0)+1>>>0!=r>>>0)return!1;var s,r;if(e.flags!==o.flags||13&e.flags)return!1;const a=e.clientTime-e.dt,c=o.clientTime-o.dt,h=o.clientTime-a,u=i;if(h<=0||h>u+n)return!1;if(Math.abs(e.clientTime-c)>n)return!1;if(l(e.inputX)!==l(o.inputX)||l(e.inputY)!==l(o.inputY))return!1;return function(e,n){return Math.abs(t.euclideanModulo(n-e+Math.PI,2*Math.PI)-Math.PI)}(e.yaw,o.yaw)<=.001}(this.pending,e,this.maxCombinedDeltaTime))return void function(t,e){const n=t.clientTime-t.dt;t.sequence=e.sequence,t.clientTime=e.clientTime,t.dt=Math.max(.001,e.clientTime-n),t.inputX=e.inputX,t.inputY=e.inputY,t.yaw=e.yaw,t.flags=e.flags,t.clientX=e.clientX,t.clientY=e.clientY,t.clientZ=e.clientZ,t.rootMotionX+=e.rootMotionX,t.rootMotionY+=e.rootMotionY,t.rootMotionZ+=e.rootMotionZ}(this.pending,e);this.commitPending()}this.pending=this.acquireMove(e),this.trimToCapacity()}ack(t){let e=0;for(let n=0;n<this.moves.length;n++)isSequenceLessOrEqual(this.moves[n].sequence,t)&&(e=n+1);if(e>0){for(let t=0;t<e;t++)this.releaseMove(this.moves[t]);this.moves.splice(0,e)}null!=this.pending&&isSequenceLessOrEqual(this.pending.sequence,t)&&(this.releaseMove(this.pending),this.pending=void 0)}clear(){for(let t=0;t<this.moves.length;t++)this.releaseMove(this.moves[t]);this.moves.length=0,null!=this.pending&&this.releaseMove(this.pending),this.pending=void 0,this.sendScratch.length=0}getMovesForSend(t){if(this.commitPending(),this.sendScratch.length=0,t<=0||0===this.moves.length)return this.sendScratch;if(1===t||this.moves.length<=t){for(let e=1===t?this.moves.length-1:0;e<this.moves.length;e++)this.sendScratch.push(this.moves[e]);return this.sendScratch}this.sendScratch.push(this.moves[0]);const e=t-1;for(let t=Math.max(1,this.moves.length-e);t<this.moves.length;t++)this.sendScratch.push(this.moves[t]);return this.sendScratch}replayAfter(t,e,n=64){let o=0;for(let i=0;i<this.moves.length&&o<n;i++){const n=this.moves[i];isSequenceGreater(n.sequence,t)&&(e(s(n,this.replayScratch)),o++)}null!=this.pending&&isSequenceGreater(this.pending.sequence,t)&&o<n&&e(s(this.pending,this.replayScratch))}commitPending(){null!=this.pending&&(this.moves.push(this.pending),this.pending=void 0,this.trimToCapacity())}trimToCapacity(){const t=Math.max(1,Math.floor(this.capacity)),e=this.length-t;if(e>0){for(let t=0;t<e;t++)this.releaseMove(this.moves[t]);this.moves.splice(0,e)}}acquireMove(t){return s(t,this.freeMoves.pop()??{sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0})}releaseMove(t){this.freeMoves.length<Math.max(1,Math.floor(this.capacity))&&this.freeMoves.push(t)}}export class NetCharacterProxySmoother{constructor(t=.1,e=5,n=32){this.interpolationDelay=t,this.snapDistance=e,this.maxSnapshots=n,this.snapshots=[]}push(t,e){const n=function(t){return{...t}}(t);this.snapshots.push({time:e,snapshot:n}),this.snapshots.sort((t,e)=>t.time-e.time),this.snapshots.length>this.maxSnapshots&&this.snapshots.splice(0,this.snapshots.length-this.maxSnapshots)}reset(t,e=0){this.snapshots.length=0,null!=t&&this.push(t,e)}sample(e,n){if(0===this.snapshots.length)return!1;const o=e-this.interpolationDelay,i=this.snapshots[0],s=this.snapshots[this.snapshots.length-1];if(null==i||null==s)return!1;if(o<=i.time||1===this.snapshots.length)return r(i.snapshot,n),!0;if(o>=s.time)return r(s.snapshot,n),!0;for(let e=1;e<this.snapshots.length;e++){const i=this.snapshots[e-1],s=this.snapshots[e];if(null==i||null==s||o>s.time)continue;if(c(i.snapshot,s.snapshot)>this.snapDistance*this.snapDistance)return r(s.snapshot,n),!0;const l=s.time-i.time,h=l>0?t.clamp((o-i.time)/l,0,1):1;return a(i.snapshot,s.snapshot,h,n),!0}return r(s.snapshot,n),!0}}export function validateNetCharacterMove(t,e,n=.06666666666666667){return!!isSequenceGreater(t.sequence,e)&&(!(!Number.isFinite(t.clientTime)||t.clientTime<=0)&&(!(!Number.isFinite(t.dt)||t.dt<=0||t.dt>n)&&(!(!Number.isFinite(t.inputX)||!Number.isFinite(t.inputY))&&(!(t.inputX*t.inputX+t.inputY*t.inputY>1.0001)&&(!(!Number.isInteger(t.flags)||t.flags<0||-32&t.flags)&&(Number.isFinite(t.yaw)&&Number.isFinite(t.clientX)&&Number.isFinite(t.clientY)&&Number.isFinite(t.clientZ)))))))}export function encodeNetCharacterMoveBatch(e){const n=Math.min(65535,e.length),o=new Uint8Array(4+43*n),i=new DataView(o.buffer);let s=0;i.setUint8(s++,3),i.setUint8(s++,1),i.setUint16(s,n,!0),s+=2;for(let o=0;o<n;o++){const n=e[o];i.setUint32(s,n.sequence>>>0,!0),s+=4,i.setUint32(s,t.clamp(Math.round(1e3*n.clientTime),0,4294967295),!0),s+=4,i.setUint16(s,t.clamp(Math.round(1e3*n.dt),1,65535),!0),s+=2,i.setInt16(s,l(n.inputX),!0),s+=2,i.setInt16(s,l(n.inputY),!0),s+=2,i.setFloat32(s,n.yaw,!0),s+=4,i.setUint8(s++,255&n.flags),i.setFloat32(s,n.clientX,!0),s+=4,i.setFloat32(s,n.clientY,!0),s+=4,i.setFloat32(s,n.clientZ,!0),s+=4,i.setFloat32(s,n.rootMotionX,!0),s+=4,i.setFloat32(s,n.rootMotionY,!0),s+=4,i.setFloat32(s,n.rootMotionZ,!0),s+=4}return o}export function decodeNetCharacterMoveBatch(t){if(t.byteLength<4)return{ok:!1,reason:"malformed"};const e=u(t);let n=0;if(3!==e.getUint8(n++))return{ok:!1,reason:"unsupported-version"};if(1!==e.getUint8(n++))return{ok:!1,reason:"wrong-kind"};const o=e.getUint16(n,!0);if(n+=2,t.byteLength!==4+43*o)return{ok:!1,reason:"malformed"};const i=[];for(let t=0;t<o;t++){const t=e.getUint32(n,!0);n+=4;const o=e.getUint32(n,!0)/1e3;n+=4;const s=e.getUint16(n,!0)/1e3;n+=2;const r=h(e.getInt16(n,!0));n+=2;const a=h(e.getInt16(n,!0));n+=2;const c=e.getFloat32(n,!0);n+=4;const l=e.getUint8(n++),u=e.getFloat32(n,!0);n+=4;const p=e.getFloat32(n,!0);n+=4;const m=e.getFloat32(n,!0);n+=4;const g=e.getFloat32(n,!0);n+=4;const f=e.getFloat32(n,!0);n+=4;const M=e.getFloat32(n,!0);n+=4,i.push({sequence:t,clientTime:o,dt:s,inputX:r,inputY:a,yaw:c,flags:l,clientX:u,clientY:p,clientZ:m,rootMotionX:g,rootMotionY:f,rootMotionZ:M})}return{ok:!0,value:{moves:i}}}export function encodeNetCharacterOwnerAck(t){const e=new Uint8Array(6),n=new DataView(e.buffer);return n.setUint8(0,3),n.setUint8(1,2),n.setUint32(2,t>>>0,!0),e}export function decodeNetCharacterOwnerAck(t){if(6!==t.byteLength)return{ok:!1,reason:"malformed"};const e=u(t);return 3!==e.getUint8(0)?{ok:!1,reason:"unsupported-version"}:2!==e.getUint8(1)?{ok:!1,reason:"wrong-kind"}:{ok:!0,value:{sequence:e.getUint32(2,!0)}}}export function encodeNetCharacterOwnerCorrection(t){return o(3,t)}export function decodeNetCharacterOwnerCorrection(t){const e=i(t,3);return!1===e.ok?{ok:!1,reason:e.reason}:{ok:!0,value:{snapshot:e.value}}}export function encodeNetCharacterSimulatedState(t){return o(4,t)}export function decodeNetCharacterSimulatedState(t){return i(t,4)}export function replayNetCharacterSavedMoves(t,e,n,o=64){let i=t;const s=Math.min(o,e.length);for(let t=0;t<s;t++)i=n(i,e[t]);return i}export function createNetCharacterServerMoveTimingState(){return{lastClientTime:0,serverTimeBudget:0}}export function accrueNetCharacterServerMoveTime(t,e,n=.25){!Number.isFinite(e)||e<=0||(t.serverTimeBudget=Math.min(n,t.serverTimeBudget+e))}export function consumeNetCharacterServerMoveTime(t,e,n={}){if(!Number.isFinite(e.clientTime))return-1;const o=e.clientTime-t.lastClientTime;if(!Number.isFinite(o)||o<=0)return-1;const i=n.maxMoveDeltaTime??.06666666666666667,s=Math.max(1,n.maxServerMoveDeltaTimeScalar??1.75),r=n.maxClientTimeAhead??.1,a=Math.max(.001,i*s),c=Math.min(o,a),l=t.serverTimeBudget-c;return l<-r?-1:(t.serverTimeBudget=l,t.lastClientTime=e.clientTime,Math.max(.001,c))}export function createNetCharacterMovementSnapshot(t={}){return{sequence:0,x:0,y:0,z:0,velocityX:0,velocityY:0,velocityZ:0,yaw:0,mode:e.walking,flags:0,horizontalSpeed:0,...t}}export function isSequenceGreater(t,e){return t-e>>>0<2147483648&&t!==e}export function isSequenceLessOrEqual(t,e){return t===e||!isSequenceGreater(t,e)}function o(t,e){const n=new Uint8Array(41),o=new DataView(n.buffer);let i=0;return o.setUint8(i++,3),o.setUint8(i++,t),o.setUint32(i,e.sequence>>>0,!0),i+=4,o.setFloat32(i,e.x,!0),i+=4,o.setFloat32(i,e.y,!0),i+=4,o.setFloat32(i,e.z,!0),i+=4,o.setFloat32(i,e.velocityX,!0),i+=4,o.setFloat32(i,e.velocityY,!0),i+=4,o.setFloat32(i,e.velocityZ,!0),i+=4,o.setFloat32(i,e.yaw,!0),i+=4,o.setUint8(i++,e.mode),o.setUint8(i++,255&e.flags),o.setFloat32(i,e.horizontalSpeed,!0),n}function i(t,e){if(41!==t.byteLength)return{ok:!1,reason:"malformed"};const n=u(t);let o=0;if(3!==n.getUint8(o++))return{ok:!1,reason:"unsupported-version"};if(n.getUint8(o++)!==e)return{ok:!1,reason:"wrong-kind"};const i=n.getUint32(o,!0);o+=4;const s=n.getFloat32(o,!0);o+=4;const r=n.getFloat32(o,!0);o+=4;const a=n.getFloat32(o,!0);o+=4;const c=n.getFloat32(o,!0);o+=4;const l=n.getFloat32(o,!0);o+=4;const h=n.getFloat32(o,!0);o+=4;const p=n.getFloat32(o,!0);o+=4;return{ok:!0,value:{sequence:i,x:s,y:r,z:a,velocityX:c,velocityY:l,velocityZ:h,yaw:p,mode:n.getUint8(o++),flags:n.getUint8(o++),horizontalSpeed:n.getFloat32(o,!0)}}}function s(t,e){return e.sequence=t.sequence,e.clientTime=t.clientTime,e.dt=t.dt,e.inputX=t.inputX,e.inputY=t.inputY,e.yaw=t.yaw,e.flags=t.flags,e.clientX=t.clientX,e.clientY=t.clientY,e.clientZ=t.clientZ,e.rootMotionX=t.rootMotionX,e.rootMotionY=t.rootMotionY,e.rootMotionZ=t.rootMotionZ,e}function r(t,e){e.sequence=t.sequence,e.x=t.x,e.y=t.y,e.z=t.z,e.velocityX=t.velocityX,e.velocityY=t.velocityY,e.velocityZ=t.velocityZ,e.yaw=t.yaw,e.mode=t.mode,e.flags=t.flags,e.horizontalSpeed=t.horizontalSpeed}function a(e,n,o,i){i.sequence=n.sequence,i.x=t.lerp(e.x,n.x,o),i.y=t.lerp(e.y,n.y,o),i.z=t.lerp(e.z,n.z,o),i.velocityX=t.lerp(e.velocityX,n.velocityX,o),i.velocityY=t.lerp(e.velocityY,n.velocityY,o),i.velocityZ=t.lerp(e.velocityZ,n.velocityZ,o),i.yaw=e.yaw+(t.euclideanModulo(n.yaw-e.yaw+Math.PI,2*Math.PI)-Math.PI)*o,i.mode=o<1?e.mode:n.mode,i.flags=o<1?e.flags:n.flags,i.horizontalSpeed=t.lerp(e.horizontalSpeed,n.horizontalSpeed,o)}function c(t,e){const n=t.x-e.x,o=t.y-e.y,i=t.z-e.z;return n*n+o*o+i*i}function l(e){return t.clamp(Math.round(32767*t.clamp(e,-1,1)),-32767,32767)}function h(e){return t.clamp(e/32767,-1,1)}function u(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}/*
|
|
1
|
+
import{MathUtils as t}from"three";import{CharacterMovementMode as e}from"./modes.js";export const NET_CHARACTER_MOVEMENT_VERSION=4;export const MOVE_PACKET_KIND=1;export const OWNER_ACK_PACKET_KIND=2;export const OWNER_CORRECTION_PACKET_KIND=3;export const SIMULATED_STATE_PACKET_KIND=4;export const DEFAULT_MOVE_SEND_INTERVAL=1/30;export const DEFAULT_SIMULATED_STATE_INTERVAL=.05;export const DEFAULT_MAX_SAVED_MOVES=128;export const DEFAULT_MAX_REPLAYED_MOVES=64;export const DEFAULT_MAX_SERVER_MOVES_PER_TICK=4;export const DEFAULT_MAX_MOVES_PER_PACKET=16;export const DEFAULT_MAX_MOVE_DELTA_TIME=1/15;export const DEFAULT_MAX_COMBINED_MOVE_DELTA_TIME=1/15;export const DEFAULT_MAX_SUBSTEP_DELTA_TIME=.017;export const DEFAULT_MAX_SERVER_MOVE_DELTA_TIME_SCALAR=1.75;export const DEFAULT_MAX_CLIENT_TIME_AHEAD=.1;export const DEFAULT_MAX_SERVER_MOVE_TIME_BUDGET=.25;export const DEFAULT_SMALL_CORRECTION_TOLERANCE=.08;export const DEFAULT_LARGE_CORRECTION_THRESHOLD=1;export const DEFAULT_TELEPORT_SNAP_THRESHOLD=5;export const DEFAULT_SIMULATED_INTERPOLATION_DELAY=.1;export const MOVE_FLAG_JUMP=1;export const MOVE_FLAG_SPRINT=2;export const MOVE_FLAG_ROOT_MOTION=4;export const MOVE_FLAG_SPRINT_START=8;export const MOVE_FLAG_CROUCH=16;export const MOVE_FLAG_SLIDE_START=32;export const SNAPSHOT_FLAG_CROUCHING=1;export const SNAPSHOT_FLAG_CROUCH_SUPPRESSED=2;const n=.001;export class NetCharacterSavedMoveBuffer{constructor(t=128,e=.06666666666666667){this.capacity=t,this.maxCombinedDeltaTime=e,this.moves=[],this.freeMoves=[],this.sendScratch=[],this.replayScratch={sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0}}get length(){return this.moves.length+(null==this.pending?0:1)}push(e){if(null!=this.pending){if(function(e,o,i=.06666666666666667){if(i<0)return!1;if(s=e.sequence,r=o.sequence,(s>>>0)+1>>>0!=r>>>0)return!1;var s,r;if(e.flags!==o.flags||45&e.flags)return!1;const a=e.clientTime-e.dt,c=o.clientTime-o.dt,h=o.clientTime-a,u=i;if(h<=0||h>u+n)return!1;if(Math.abs(e.clientTime-c)>n)return!1;if(l(e.inputX)!==l(o.inputX)||l(e.inputY)!==l(o.inputY))return!1;return function(e,n){return Math.abs(t.euclideanModulo(n-e+Math.PI,2*Math.PI)-Math.PI)}(e.yaw,o.yaw)<=.001}(this.pending,e,this.maxCombinedDeltaTime))return void function(t,e){const n=t.clientTime-t.dt;t.sequence=e.sequence,t.clientTime=e.clientTime,t.dt=Math.max(.001,e.clientTime-n),t.inputX=e.inputX,t.inputY=e.inputY,t.yaw=e.yaw,t.flags=e.flags,t.clientX=e.clientX,t.clientY=e.clientY,t.clientZ=e.clientZ,t.rootMotionX+=e.rootMotionX,t.rootMotionY+=e.rootMotionY,t.rootMotionZ+=e.rootMotionZ}(this.pending,e);this.commitPending()}this.pending=this.acquireMove(e),this.trimToCapacity()}ack(t){let e=0;for(let n=0;n<this.moves.length;n++)isSequenceLessOrEqual(this.moves[n].sequence,t)&&(e=n+1);if(e>0){for(let t=0;t<e;t++)this.releaseMove(this.moves[t]);this.moves.splice(0,e)}null!=this.pending&&isSequenceLessOrEqual(this.pending.sequence,t)&&(this.releaseMove(this.pending),this.pending=void 0)}clear(){for(let t=0;t<this.moves.length;t++)this.releaseMove(this.moves[t]);this.moves.length=0,null!=this.pending&&this.releaseMove(this.pending),this.pending=void 0,this.sendScratch.length=0}getMovesForSend(t){if(this.commitPending(),this.sendScratch.length=0,t<=0||0===this.moves.length)return this.sendScratch;if(1===t||this.moves.length<=t){for(let e=1===t?this.moves.length-1:0;e<this.moves.length;e++)this.sendScratch.push(this.moves[e]);return this.sendScratch}this.sendScratch.push(this.moves[0]);const e=t-1;for(let t=Math.max(1,this.moves.length-e);t<this.moves.length;t++)this.sendScratch.push(this.moves[t]);return this.sendScratch}replayAfter(t,e,n=64){let o=0;for(let i=0;i<this.moves.length&&o<n;i++){const n=this.moves[i];isSequenceGreater(n.sequence,t)&&(e(s(n,this.replayScratch)),o++)}null!=this.pending&&isSequenceGreater(this.pending.sequence,t)&&o<n&&e(s(this.pending,this.replayScratch))}commitPending(){null!=this.pending&&(this.moves.push(this.pending),this.pending=void 0,this.trimToCapacity())}trimToCapacity(){const t=Math.max(1,Math.floor(this.capacity)),e=this.length-t;if(e>0){for(let t=0;t<e;t++)this.releaseMove(this.moves[t]);this.moves.splice(0,e)}}acquireMove(t){return s(t,this.freeMoves.pop()??{sequence:0,clientTime:0,dt:0,inputX:0,inputY:0,yaw:0,flags:0,clientX:0,clientY:0,clientZ:0,rootMotionX:0,rootMotionY:0,rootMotionZ:0})}releaseMove(t){this.freeMoves.length<Math.max(1,Math.floor(this.capacity))&&this.freeMoves.push(t)}}export class NetCharacterProxySmoother{constructor(t=.1,e=5,n=32){this.interpolationDelay=t,this.snapDistance=e,this.maxSnapshots=n,this.snapshots=[]}push(t,e){const n=function(t){return{...t}}(t);this.snapshots.push({time:e,snapshot:n}),this.snapshots.sort((t,e)=>t.time-e.time),this.snapshots.length>this.maxSnapshots&&this.snapshots.splice(0,this.snapshots.length-this.maxSnapshots)}reset(t,e=0){this.snapshots.length=0,null!=t&&this.push(t,e)}sample(e,n){if(0===this.snapshots.length)return!1;const o=e-this.interpolationDelay,i=this.snapshots[0],s=this.snapshots[this.snapshots.length-1];if(null==i||null==s)return!1;if(o<=i.time||1===this.snapshots.length)return r(i.snapshot,n),!0;if(o>=s.time)return r(s.snapshot,n),!0;for(let e=1;e<this.snapshots.length;e++){const i=this.snapshots[e-1],s=this.snapshots[e];if(null==i||null==s||o>s.time)continue;if(c(i.snapshot,s.snapshot)>this.snapDistance*this.snapDistance)return r(s.snapshot,n),!0;const l=s.time-i.time,h=l>0?t.clamp((o-i.time)/l,0,1):1;return a(i.snapshot,s.snapshot,h,n),!0}return r(s.snapshot,n),!0}}export function validateNetCharacterMove(t,e,n=.06666666666666667){return!!isSequenceGreater(t.sequence,e)&&(!(!Number.isFinite(t.clientTime)||t.clientTime<=0)&&(!(!Number.isFinite(t.dt)||t.dt<=0||t.dt>n)&&(!(!Number.isFinite(t.inputX)||!Number.isFinite(t.inputY))&&(!(t.inputX*t.inputX+t.inputY*t.inputY>1.0001)&&(!(!Number.isInteger(t.flags)||t.flags<0||-64&t.flags)&&(Number.isFinite(t.yaw)&&Number.isFinite(t.clientX)&&Number.isFinite(t.clientY)&&Number.isFinite(t.clientZ)))))))}export function encodeNetCharacterMoveBatch(e){const n=Math.min(65535,e.length),o=new Uint8Array(4+43*n),i=new DataView(o.buffer);let s=0;i.setUint8(s++,4),i.setUint8(s++,1),i.setUint16(s,n,!0),s+=2;for(let o=0;o<n;o++){const n=e[o];i.setUint32(s,n.sequence>>>0,!0),s+=4,i.setUint32(s,t.clamp(Math.round(1e3*n.clientTime),0,4294967295),!0),s+=4,i.setUint16(s,t.clamp(Math.round(1e3*n.dt),1,65535),!0),s+=2,i.setInt16(s,l(n.inputX),!0),s+=2,i.setInt16(s,l(n.inputY),!0),s+=2,i.setFloat32(s,n.yaw,!0),s+=4,i.setUint8(s++,255&n.flags),i.setFloat32(s,n.clientX,!0),s+=4,i.setFloat32(s,n.clientY,!0),s+=4,i.setFloat32(s,n.clientZ,!0),s+=4,i.setFloat32(s,n.rootMotionX,!0),s+=4,i.setFloat32(s,n.rootMotionY,!0),s+=4,i.setFloat32(s,n.rootMotionZ,!0),s+=4}return o}export function decodeNetCharacterMoveBatch(t){if(t.byteLength<4)return{ok:!1,reason:"malformed"};const e=u(t);let n=0;if(4!==e.getUint8(n++))return{ok:!1,reason:"unsupported-version"};if(1!==e.getUint8(n++))return{ok:!1,reason:"wrong-kind"};const o=e.getUint16(n,!0);if(n+=2,t.byteLength!==4+43*o)return{ok:!1,reason:"malformed"};const i=[];for(let t=0;t<o;t++){const t=e.getUint32(n,!0);n+=4;const o=e.getUint32(n,!0)/1e3;n+=4;const s=e.getUint16(n,!0)/1e3;n+=2;const r=h(e.getInt16(n,!0));n+=2;const a=h(e.getInt16(n,!0));n+=2;const c=e.getFloat32(n,!0);n+=4;const l=e.getUint8(n++),u=e.getFloat32(n,!0);n+=4;const p=e.getFloat32(n,!0);n+=4;const m=e.getFloat32(n,!0);n+=4;const g=e.getFloat32(n,!0);n+=4;const f=e.getFloat32(n,!0);n+=4;const M=e.getFloat32(n,!0);n+=4,i.push({sequence:t,clientTime:o,dt:s,inputX:r,inputY:a,yaw:c,flags:l,clientX:u,clientY:p,clientZ:m,rootMotionX:g,rootMotionY:f,rootMotionZ:M})}return{ok:!0,value:{moves:i}}}export function encodeNetCharacterOwnerAck(t){const e=new Uint8Array(6),n=new DataView(e.buffer);return n.setUint8(0,4),n.setUint8(1,2),n.setUint32(2,t>>>0,!0),e}export function decodeNetCharacterOwnerAck(t){if(6!==t.byteLength)return{ok:!1,reason:"malformed"};const e=u(t);return 4!==e.getUint8(0)?{ok:!1,reason:"unsupported-version"}:2!==e.getUint8(1)?{ok:!1,reason:"wrong-kind"}:{ok:!0,value:{sequence:e.getUint32(2,!0)}}}export function encodeNetCharacterOwnerCorrection(t){return o(3,t)}export function decodeNetCharacterOwnerCorrection(t){const e=i(t,3);return!1===e.ok?{ok:!1,reason:e.reason}:{ok:!0,value:{snapshot:e.value}}}export function encodeNetCharacterSimulatedState(t){return o(4,t)}export function decodeNetCharacterSimulatedState(t){return i(t,4)}export function replayNetCharacterSavedMoves(t,e,n,o=64){let i=t;const s=Math.min(o,e.length);for(let t=0;t<s;t++)i=n(i,e[t]);return i}export function createNetCharacterServerMoveTimingState(){return{lastClientTime:0,serverTimeBudget:0}}export function accrueNetCharacterServerMoveTime(t,e,n=.25){!Number.isFinite(e)||e<=0||(t.serverTimeBudget=Math.min(n,t.serverTimeBudget+e))}export function consumeNetCharacterServerMoveTime(t,e,n={}){if(!Number.isFinite(e.clientTime))return-1;const o=e.clientTime-t.lastClientTime;if(!Number.isFinite(o)||o<=0)return-1;const i=n.maxMoveDeltaTime??.06666666666666667,s=Math.max(1,n.maxServerMoveDeltaTimeScalar??1.75),r=n.maxClientTimeAhead??.1,a=Math.max(.001,i*s),c=Math.min(o,a),l=t.serverTimeBudget-c;return l<-r?-1:(t.serverTimeBudget=l,t.lastClientTime=e.clientTime,Math.max(.001,c))}export function createNetCharacterMovementSnapshot(t={}){return{sequence:0,x:0,y:0,z:0,velocityX:0,velocityY:0,velocityZ:0,yaw:0,mode:e.walking,flags:0,horizontalSpeed:0,...t}}export function isSequenceGreater(t,e){return t-e>>>0<2147483648&&t!==e}export function isSequenceLessOrEqual(t,e){return t===e||!isSequenceGreater(t,e)}function o(t,e){const n=new Uint8Array(41),o=new DataView(n.buffer);let i=0;return o.setUint8(i++,4),o.setUint8(i++,t),o.setUint32(i,e.sequence>>>0,!0),i+=4,o.setFloat32(i,e.x,!0),i+=4,o.setFloat32(i,e.y,!0),i+=4,o.setFloat32(i,e.z,!0),i+=4,o.setFloat32(i,e.velocityX,!0),i+=4,o.setFloat32(i,e.velocityY,!0),i+=4,o.setFloat32(i,e.velocityZ,!0),i+=4,o.setFloat32(i,e.yaw,!0),i+=4,o.setUint8(i++,e.mode),o.setUint8(i++,255&e.flags),o.setFloat32(i,e.horizontalSpeed,!0),n}function i(t,e){if(41!==t.byteLength)return{ok:!1,reason:"malformed"};const n=u(t);let o=0;if(4!==n.getUint8(o++))return{ok:!1,reason:"unsupported-version"};if(n.getUint8(o++)!==e)return{ok:!1,reason:"wrong-kind"};const i=n.getUint32(o,!0);o+=4;const s=n.getFloat32(o,!0);o+=4;const r=n.getFloat32(o,!0);o+=4;const a=n.getFloat32(o,!0);o+=4;const c=n.getFloat32(o,!0);o+=4;const l=n.getFloat32(o,!0);o+=4;const h=n.getFloat32(o,!0);o+=4;const p=n.getFloat32(o,!0);o+=4;return{ok:!0,value:{sequence:i,x:s,y:r,z:a,velocityX:c,velocityY:l,velocityZ:h,yaw:p,mode:n.getUint8(o++),flags:n.getUint8(o++),horizontalSpeed:n.getFloat32(o,!0)}}}function s(t,e){return e.sequence=t.sequence,e.clientTime=t.clientTime,e.dt=t.dt,e.inputX=t.inputX,e.inputY=t.inputY,e.yaw=t.yaw,e.flags=t.flags,e.clientX=t.clientX,e.clientY=t.clientY,e.clientZ=t.clientZ,e.rootMotionX=t.rootMotionX,e.rootMotionY=t.rootMotionY,e.rootMotionZ=t.rootMotionZ,e}function r(t,e){e.sequence=t.sequence,e.x=t.x,e.y=t.y,e.z=t.z,e.velocityX=t.velocityX,e.velocityY=t.velocityY,e.velocityZ=t.velocityZ,e.yaw=t.yaw,e.mode=t.mode,e.flags=t.flags,e.horizontalSpeed=t.horizontalSpeed}function a(e,n,o,i){i.sequence=n.sequence,i.x=t.lerp(e.x,n.x,o),i.y=t.lerp(e.y,n.y,o),i.z=t.lerp(e.z,n.z,o),i.velocityX=t.lerp(e.velocityX,n.velocityX,o),i.velocityY=t.lerp(e.velocityY,n.velocityY,o),i.velocityZ=t.lerp(e.velocityZ,n.velocityZ,o),i.yaw=e.yaw+(t.euclideanModulo(n.yaw-e.yaw+Math.PI,2*Math.PI)-Math.PI)*o,i.mode=o<1?e.mode:n.mode,i.flags=o<1?e.flags:n.flags,i.horizontalSpeed=t.lerp(e.horizontalSpeed,n.horizontalSpeed,o)}function c(t,e){const n=t.x-e.x,o=t.y-e.y,i=t.z-e.z;return n*n+o*o+i*i}function l(e){return t.clamp(Math.round(32767*t.clamp(e,-1,1)),-32767,32767)}function h(e){return t.clamp(e/32767,-1,1)}function u(t){return new DataView(t.buffer,t.byteOffset,t.byteLength)}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{Ball as n,Capsule as s,Cone as o,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-simd-compat";import{init as p}from"@recast-navigation/core";import{DebugDrawer as u,getPositionsAndIndices as d}from"@recast-navigation/three";import{BehaviorSubject as m,Subject as f,debounceTime as w,filter as b,firstValueFrom as g,takeUntil as y}from"rxjs";import*as x from"three";import{BufferGeometryUtils as v,ConvexHull as M}from"three/examples/jsm/Addons.js";import{Actor as B,BaseActor as S,Parameter as z,PhysicsSystem as A,ViewController as k,World as C,attach as j,inject as P}from"../../";import{sleepDelay as F}from"../../../utils/async";import{hasSharedArrayBufferSupport as I,toSharedFloat32Array as D,toSharedUint32Array as V}from"../../../utils/buffer";import{DynamicTiledNavMesh as G}from"../../ai/dynamic-tiled-navmesh";import{TriggerVolumeMesh as
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Ball as n,Capsule as s,Cone as o,ConvexPolyhedron as i,Cuboid as r,Cylinder as a,Heightfield as l,ShapeType as c,TriMesh as h}from"@dimforge/rapier3d-simd-compat";import{init as p}from"@recast-navigation/core";import{DebugDrawer as u,getPositionsAndIndices as d}from"@recast-navigation/three";import{BehaviorSubject as m,Subject as f,debounceTime as w,filter as b,firstValueFrom as g,takeUntil as y}from"rxjs";import*as x from"three";import{BufferGeometryUtils as v,ConvexHull as M}from"three/examples/jsm/Addons.js";import{Actor as B,BaseActor as S,Parameter as z,PhysicsSystem as A,ViewController as k,World as C,attach as j,inject as P}from"../../";import{sleepDelay as F}from"../../../utils/async";import{hasSharedArrayBufferSupport as I,toSharedFloat32Array as D,toSharedUint32Array as V}from"../../../utils/buffer";import{DynamicTiledNavMesh as G,MAX_NAV_MESH_WORKERS as N}from"../../ai/dynamic-tiled-navmesh";import{TriggerVolumeMesh as H}from"./components/volume-editor-component";var E;!function(e){e[e.none=0]="none",e[e.starting=1]="starting",e[e.started=2]="started"}(E||(E={}));let T=E.none,R=new m(!1);export async function safeRecastInit(){return T===E.none?(T=E.starting,p().then(()=>{R.next(!0),T=E.started})):g(R.pipe(b(e=>e)))}new x.Box3(new x.Vector3(-100,-100,-100),new x.Vector3(100,100,100));const U=Math.max(1,Math.min(N,(navigator.hardwareConcurrency??2)-1));let q=!1,O=class extends S{constructor(){super(...arguments),this.physics=P(A),this.view=P(k),this.world=P(C),this.editorVisualisation=j(H),this.debug=!0,this.refreshMs=4e3,this.tileSize=50,this.walkableClimb=.3,this.walkableSlopeAngle=45,this.walkableHeight=2,this.cellSize=.2,this.bounds=new x.Box3}async onInit(){q||(await safeRecastInit(),q=!0),setTimeout(()=>{this.init()},10),this.recreateInterval=setInterval(()=>{if("_hology_transform_group"===this.object.parent?.name)return;J.setFromCenterAndSize(this.position,this.object.scale).equals(this.bounds)||(this.disposed.next(!0),this.disposed=new f,this.init())},2e3)}onEndPlay(){clearInterval(this.recreateInterval)}applySceneParameters(e,t){return!(null==this.debugDrawer||!t.has("debug")||"boolean"!=typeof e.debug)&&(this.debugDrawer.visible=e.debug,!0)}init(){this.bounds.setFromCenterAndSize(this.position,this.object.scale);const e=this.bounds.max.x-this.bounds.min.x,t=this.bounds.max.z-this.bounds.min.z,n=Math.max(1,Math.min(e,t)),s=Math.min(400,Math.max(50,Math.ceil(n/2))),o=Math.max(this.cellSize,.01),i={tileSize:Math.max(32,Math.floor(s/o)),walkableClimb:this.walkableClimb/o,walkableSlopeAngle:this.walkableSlopeAngle,walkableRadius:2,walkableHeight:this.walkableHeight/o,detailSampleDist:1,minRegionArea:6,mergeRegionArea:400,cs:o,ch:o,maxSimplificationError:1.3,maxEdgeLen:200},r=new G({navMeshBounds:this.bounds,recastConfig:i,maxTiles:1024,workers:U,cacheId:"nav"+this.object.userData?.src?.id});this.navMesh=r.navMesh;const a=this.tileSize*i.cs*2,l=performance.now(),c=new Map,h=new u;h.userData.isDebugDrawer=!0,this.debugDrawer=h;r.navMesh;const p=this.bounds,m=()=>{const e=this.view.getCamera().getWorldPosition(new x.Vector3),t=new x.Box3((new x.Vector3).copy(e).subScalar(a),(new x.Vector3).copy(e).addScalar(a)),n=[],s=this.physics.world.bodies;if(null==s)return[];const o=new x.Box3;for(const e of s.getAll())for(let s=0,i=e.numColliders();s<i;s++){const i=e.collider(s);if(i.isSensor()||null!=i.parent().userData&&!0===i.parent().userData.ignoreForNavMesh)continue;const r=e.handle+","+s,a=c.get(r)?.mesh,l=a??X(i);if($(i,l),null!=l){o.copy(l.geometry.boundingBox),o.min.add(l.position),o.max.add(l.position);const e=o.intersectsBox(t)||!0,s=o.intersectsBox(this.bounds);c.set(r,{pos:i.translation(),mesh:l}),e&&s&&n.push(l)}}return n},f=new x.Box3,b=new Map,g=new Map;let v=!0,M=performance.now(),B=!1;const S=function(e,t){let n=!1;return(async()=>{for(;!n;)await e(),await F(t)})(),()=>{n=!0}}(async()=>{if(B)return;const e=new x.Box3,t=m();for(const n of t){const t=b.get(n);!0!==t?.equals(n.position)&&(null!=t&&e.expandByPoint(t),e.expandByObject(n),b.set(n,n.position.clone()))}e.min.subScalar(50),e.max.addScalar(50);const n=r.getTilesForBounds(e);n.length>500&&console.warn("Too many tiles to update. Consider increasing tile size");const s=n.slice(0,500);if(0!=s.length){const n=[];for(const s of t)f.setFromObject(s),f.intersectsBox(e)&&n.push(s);let[o,i]=d(n);i=function(e,t,n){const s=new x.Vector3,o=[];for(let i=0;i<t.length;i+=3){let r=!0;for(let o=0;o<3;o++){const a=3*t[i+o];if(s.fromArray(e,a),!n.containsPoint(s)){r=!1;break}}r&&o.push(t[i],t[i+1],t[i+2])}return new Uint32Array(o)}(o,i,p),I&&(o=D(o),i=V(i));const a=v;v=!1,await Promise.all(s.map(e=>(M=performance.now(),r.buildTile(o,i,e,a).then(()=>{const t=e[0]+","+e[1];g.set(t,(g.get(t)??0)+1),this.debug})))).then(()=>{this.debug,B=!1})}else B=!1},this.refreshMs??1e4);this.disposed.subscribe(()=>S()),r.onNavMeshUpdate.pipe(y(this.disposed),w(200)).subscribe(()=>{h.clear(),h.drawNavMesh(r.navMesh)}),console.log("Create navmesh with debug",this.debug),this.debug&&(this.object.rotation.set(0,0,0),this.object.updateMatrix(),this.object.updateMatrixWorld(),this.object.parent.add(h)),this.disposed.subscribe(()=>{r?.destroy(),h.removeFromParent(),h.dispose()});const z=performance.now()-l;z>1e3&&console.warn(`NavMesh update took ${z} ms. Consider changing tileSize or other parameter that may affect performance`)}};e([z(),t("design:type",Boolean)],O.prototype,"debug",void 0),e([z(),t("design:type",Number)],O.prototype,"walkableClimb",void 0),e([z({range:[0,89]}),t("design:type",Number)],O.prototype,"walkableSlopeAngle",void 0),e([z(),t("design:type",Number)],O.prototype,"walkableHeight",void 0),e([z({range:[.01,10]}),t("design:type",Number)],O.prototype,"cellSize",void 0),O=e([B()],O);export default O;const W=new Map,_=new WeakMap;function L(e){if(e.shape instanceof l)return function(e){const t=e.shape;if(t.type!==c.HeightField)throw new Error("The provided collider is not a height field.");let n=!1;const s=t,o=s.heights,i=s.nrows,r=s.ncols,a=s.scale.x,l=s.scale.z,h=s.scale.y,p=i+1,u=new x.PlaneGeometry(l,a,r,i);u.rotateX(-Math.PI/2);const d=u.attributes.position.array;let m=0;for(let e=0;e<p;e++)for(let t=0;t<p;t++)d[m+1]=o[t*p+e]*h,m+=3,0!=d[m+1]&&(n=!0);if(!n){const e=new x.PlaneGeometry(a,l,2,2);return e.rotateX(-Math.PI/2),e}return u}(e);if(e.shape instanceof n)return new x.SphereGeometry(e.shape.radius);if(e.shape instanceof r){const t=e.shape.halfExtents;return new x.BoxGeometry(2*t.x,2*t.y,2*t.z)}if(e.shape instanceof i){const t=function(e){const t=_.get(e);if(void 0!==t)return t;const n=new Uint32Array(e.buffer,e.byteOffset,e.byteLength>>>2);let s=2166136261;for(let e=0;e<n.length;e++)s=Math.imul(s^n[e],16777619)>>>0;return _.set(e,s),s}(e.shape.vertices);let n=W.get(t);return n||(n=function(e){const t=[];for(let n=0;n<e.length;n+=3)t.push(new x.Vector3(e[n],e[n+1],e[n+2]));const n=(new M).setFromPoints(t),s=[];n.faces.forEach(e=>{const t=e.edge.head().point,n=e.edge.next.head().point,o=e.edge.next.next.head().point;s.push(t.x,t.y,t.z),s.push(n.x,n.y,n.z),s.push(o.x,o.y,o.z)});const o=new x.BufferGeometry;return o.setAttribute("position",new x.Float32BufferAttribute(s,3)),o}(e.shape.vertices),W.set(t,n)),n}if(e.shape instanceof h){const t=e.shape.vertices,n=e.shape.indices;let s=new x.BufferGeometry;return s.setAttribute("position",new x.Float32BufferAttribute(t,3)),null!=n?s.setIndex(new x.Uint16BufferAttribute(n,1)):s=v.mergeVertices(s),s.computeVertexNormals(),s}if(e.shape instanceof a){const t=e.shape.halfHeight,n=e.shape.radius;return new x.CylinderGeometry(n,n,2*t)}if(e.shape instanceof o){const t=e.shape.halfHeight,n=e.shape.radius;return new x.ConeGeometry(n,2*t)}if(e.shape instanceof s){const t=e.shape.halfHeight,n=e.shape.radius;return new x.CapsuleGeometry(n,2*t)}return console.warn("Unsupported shape",e.shape.type,e),null}function X(e){const t=L(e);if(null==t)return null;const n=K,s=new x.Mesh(t,n);return s.geometry.computeBoundingBox(),s.geometry.scale(1.01,1.01,1.01),s}function $(e,t){const n=e.translation(),s=e.rotation();t.position.set(n.x,n.y,n.z),t.quaternion.set(s.x,s.y,s.z,s.w)}const J=new x.Box3,K=new x.MeshBasicMaterial({wireframe:!1,color:16711680,side:x.FrontSide});/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|