@hology/core 0.0.213 → 0.0.215
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/initializsers.d.ts +4 -0
- package/dist/effects/vfx/initializsers.js +1 -1
- package/dist/effects/vfx/vfx-collision-behaviour.js +1 -1
- package/dist/effects/vfx/vfx-materializer.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +6 -0
- 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/actors/component.d.ts +6 -0
- 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/animation/retarget.js +1 -1
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/services/physics/physics-system.d.ts +56 -3
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/world.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +2 -0
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/assets-provider.d.ts +1 -0
- package/dist/scene/assets-provider.js +1 -1
- package/dist/scene/collision/collision-shape.d.ts +1 -1
- package/dist/scene/materializer.d.ts +8 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/runtime-asset-service.d.ts +7 -1
- package/dist/scene/runtime-asset-service.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/animation-retarget.test.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/prefab-instance-params.test.js +1 -1
- package/dist/test/runtime-asset-service.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/dist/test/vfx-world-space-emitter-rotation.test.d.ts +2 -0
- package/dist/test/vfx-world-space-emitter-rotation.test.js +4 -0
- package/dist/test/world-prefab-spawn.test.js +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
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
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import{ActorComponent as o,Component as i}from"../component.js";import{Vector3 as s,MathUtils as n,PerspectiveCamera as h,Object3D as r}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as c,RestrictedRotationInput as d}from"../../input/index.js";import{PhysicsSystem as m}from"../../services/physics/physics-system.js";import{Parameter as p}from"../../../shader/parameter.js";import{World as l}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as f}from"@hology/nebula";const v=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let k=class extends o{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(m),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.5,this.far=500,this.viewAngle=v?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new h(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new d(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new c(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(l),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default")},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&this.canvas.requestPointerLock&&(this.canvas.requestPointerLock({unadjustedMovement:!0}),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t),this.collision&&this.checkForCollision(t);let e=this.zoomInput.value,o=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=n.lerp(this.smoothedRotX,o,s),this.smoothedRotY=n.lerp(this.smoothedRotY,i,s),o=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=n.lerp(this.smoothZoom,e,.4*s),e=this.smoothZoom}else this.smoothedRotX=o,this.smoothedRotY=i;const s=n.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*e,this.minDistance)),h=Math.cos(o)*s,r=this.fixedBehind?0:i;this.offset.x=Math.sin(-r)*h,this.offset.y=Math.sin(o)*s+
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import{ActorComponent as o,Component as i}from"../component.js";import{Vector3 as s,MathUtils as n,PerspectiveCamera as h,Object3D as r}from"three";import{ViewController as a}from"../../services/render.js";import{DecimalInput as c,RestrictedRotationInput as d}from"../../input/index.js";import{PhysicsSystem as m}from"../../services/physics/physics-system.js";import{Parameter as p}from"../../../shader/parameter.js";import{World as l}from"../../services/world.js";import{inject as u}from"../../inject.js";import{ease as f}from"@hology/nebula";const v=void 0!==window&&/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);let k=class extends o{constructor(){super(),this.viewController=u(a),this.physicsSystem=u(m),this.aspect=this.viewController.htmlElement.clientWidth/this.viewController.htmlElement.clientHeight,this.near=.5,this.far=500,this.viewAngle=v?30:45,this.collision=!0,this.collisionSphereRadius=.25,this.smoothCamera=!1,this.smoothSpeed=10,this.teleportSnapDistance=5,this.camera=new h(this.viewAngle,this.aspect,this.near,this.far),this.distance=9,this.minDistance=1.5,this.maxDistance=this.distance,this.height=3,this.offsetX=-1,this.offsetY=2,this.offsetZ=1.5,this.autoActivate=!0,this.bounceBackSpeed=3,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.rotationInput=new d(-Math.PI/4,Math.PI/2-.7),this.zoomInput=new c(1,0,1),this.offset=new s,this.lookAtOffset=new s(this.offsetX,0,this.offsetZ),this.fixedBehind=!0,this.world=u(l),this.activated=!1,this.isMouseLocked=!1,this.prevFixedBehind=!1,this.blendDurationLeft=0,this.pointerEventsRegistered=!1,this.canvas=null,this.pointerLockInactivatedAt=null,this.onMouseDown=t=>{this.isMouseLocked||"mouse"!==t.pointerType||this.hideCursor()},this.onKeyDown=t=>{"Escape"===t.key&&this.showCursor()},this.onPointerLockChange=()=>{this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.isMouseLocked||(this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default")},this.prevLookAt=new s,this.smoothedLookAt=new s,this.previousTargetLookAt=new s,this.hasSmoothedLookAt=!1,this.smoothedRotX=0,this.smoothedRotY=0,this.smoothZoom=0}async onInit(){this.prevFixedBehind=this.fixedBehind,this.world.scene.add(this.camera),this.rotationInput.rotation.copy(this.actor.rotation),this.smoothedRotX=this.rotationInput.rotation.x,this.smoothedRotY=this.rotationInput.rotation.y,this.restrictedDistance=Math.max(this.distance,this.maxDistance),this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.smoothZoom=this.zoomInput.value,this.autoActivate&&this.activate(),this.disposed.subscribe(()=>{this.unregisterPointerEvents()})}activate(){this.activated=!0,this.hasSmoothedLookAt=!1,this.viewController.setCamera(this.camera),this.isMouseLocked=null!=document.pointerLockElement||null!=document.mozPointerLockElement,this.registerPointerEvents()}deactivate(){this.activated=!1,this.isMouseLocked=!1,this.unregisterPointerEvents()}registerPointerEvents(){if(this.pointerEventsRegistered||null==document.body.requestPointerLock)return;const t=this.element;t.addEventListener("pointerdown",this.onMouseDown),t.addEventListener("keydown",this.onKeyDown),document.addEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!0}unregisterPointerEvents(){if(!this.pointerEventsRegistered)return;const t=this.element;t.removeEventListener("pointerdown",this.onMouseDown),t.removeEventListener("keydown",this.onKeyDown),document.removeEventListener("pointerlockchange",this.onPointerLockChange,!1),this.pointerEventsRegistered=!1}onLateUpdate(t){this.activated&&this.setFromRotation(t)}get element(){return this.viewController.htmlElement}hideCursor(){null!=this.pointerLockInactivatedAt&&performance.now()-this.pointerLockInactivatedAt<1600||(this.element.style.cursor="none",null==this.canvas&&(this.canvas=this.element.getElementsByTagName("canvas")[0]),this.canvas&&this.canvas.requestPointerLock&&(this.canvas.requestPointerLock({unadjustedMovement:!0}),this.isMouseLocked=!0))}showCursor(){this.pointerLockInactivatedAt=performance.now(),this.element.style.cursor="default",null==document.pointerLockElement&&null==document.mozPointerLockElement||window.document.exitPointerLock(),this.isMouseLocked=!1}setFromRotation(t){this.lookAtOffset.set(this.offsetX,0,this.offsetZ),this.fixedBehind!==this.prevFixedBehind?(this.blendDurationLeft=1,this.prevFixedBehind=this.fixedBehind):this.blendDurationLeft>0&&(this.blendDurationLeft-=t),this.collision&&this.checkForCollision(t);let e=this.zoomInput.value,o=this.rotationInput.rotation.x,i=this.rotationInput.rotation.y;if(this.smoothCamera){const s=1-Math.exp(-this.smoothSpeed*t*2);this.smoothedRotX=n.lerp(this.smoothedRotX,o,s),this.smoothedRotY=n.lerp(this.smoothedRotY,i,s),o=this.smoothedRotX,i=this.smoothedRotY,this.smoothZoom=n.lerp(this.smoothZoom,e,.4*s),e=this.smoothZoom}else this.smoothedRotX=o,this.smoothedRotY=i;const s=n.clamp(Math.min(this.restrictedDistance,this.distance),Math.min(this.minDistance,this.restrictedDistance),Math.max(this.distance*e,this.minDistance)),h=Math.cos(o)*s,r=this.fixedBehind?0:i;this.offset.x=Math.sin(-r)*h,this.offset.y=Math.sin(o)*s+this.offsetY,this.offset.z=Math.cos(-r)*-h,this.fixedBehind&&this.offset.add(this.lookAtOffset),this.updateCameraPosition(t)}checkForCollision(t){const e=this.getLookAtPosition(),o=this.camera.getWorldPosition(w),i=A.subVectors(o,e),s=i.length();if(s<.001)return;i.divideScalar(s);const h=this.physicsSystem.sphereCast(e,this.collisionSphereRadius,i,this.distance,void 0,{excludeActor:this.actor,excludeTriggers:!0,collisionFilter:-2});if(h.hasHit){const e=Math.max(this.minDistance,h.distance-.05);e<this.restrictedDistance?this.restrictedDistance=e:this.restrictedDistance=n.lerp(this.restrictedDistance,e,n.clamp(this.bounceBackSpeed*t,0,1))}else this.restrictedDistance=n.lerp(this.restrictedDistance,this.distance,n.clamp(this.bounceBackSpeed*t,0,1))}getLookAtPosition(){const t=y;return t.set(0,0,0),t.y=this.height,this.fixedBehind&&t.add(this.lookAtOffset),t.applyMatrix4(this.actor.object.matrixWorld),t}updateCameraPosition(t){this.actor.object.updateWorldMatrix(!0,!1),this.fixedBehind?(L.position.set(this.offset.x,this.offset.y,this.offset.z),L.rotation.set(0,0,0),L.scale.set(1,1,1),L.applyMatrix4(this.actor.object.matrix)):L.position.copy(this.actor.position).add(this.offset);const e=f.easeInOutCubic(1-this.blendDurationLeft);if(this.blendDurationLeft>0){const t=this.getLookAtPosition();this.prevLookAt.lerp(t,e),this.camera.lookAt(this.prevLookAt),this.camera.position.lerp(L.position,e),this.smoothedLookAt.copy(this.prevLookAt),this.previousTargetLookAt.copy(t),this.hasSmoothedLookAt=!0}else{const e=this.getLookAtPosition();if(this.smoothCamera){const o=1-Math.exp(-this.smoothSpeed*t),i=Math.max(0,this.teleportSnapDistance);!this.hasSmoothedLookAt||this.previousTargetLookAt.distanceToSquared(e)>i*i?this.smoothedLookAt.copy(e):this.smoothedLookAt.lerp(e,o)}else this.smoothedLookAt.copy(e);this.previousTargetLookAt.copy(e),this.hasSmoothedLookAt=!0,g.subVectors(L.position,e),this.camera.position.copy(this.smoothedLookAt).add(g),this.camera.lookAt(this.smoothedLookAt),this.prevLookAt.copy(this.smoothedLookAt)}}};t([p(),e("design:type",Number)],k.prototype,"near",void 0),t([p(),e("design:type",Number)],k.prototype,"far",void 0),t([p(),e("design:type",Number)],k.prototype,"viewAngle",void 0),t([p(),e("design:type",Boolean)],k.prototype,"collision",void 0),t([p(),e("design:type",Number)],k.prototype,"collisionSphereRadius",void 0),t([p(),e("design:type",Boolean)],k.prototype,"smoothCamera",void 0),t([p(),e("design:type",Number)],k.prototype,"smoothSpeed",void 0),t([p(),e("design:type",Number)],k.prototype,"teleportSnapDistance",void 0),k=t([i(),e("design:paramtypes",[])],k);export{k as ThirdPersonCameraComponent};const L=new r,y=new s,g=new s,A=new s,w=(new s,new s);export class ThirdPartyCameraComponent extends k{}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -7,6 +7,12 @@ export declare abstract class ActorComponent<ActorType extends BaseActor = BaseA
|
|
|
7
7
|
onInit(): Promise<void> | void;
|
|
8
8
|
onBeginPlay(): void;
|
|
9
9
|
onEndPlay(): void;
|
|
10
|
+
/**
|
|
11
|
+
* Applies saved authoring parameter changes without recreating the owning
|
|
12
|
+
* actor. Return true only when every supplied change was applied. Returning
|
|
13
|
+
* false means unsupported and must leave the component unchanged.
|
|
14
|
+
*/
|
|
15
|
+
applySceneParameters(parameters: Record<string, unknown>, changedParameters: ReadonlySet<string>): boolean | Promise<boolean>;
|
|
10
16
|
/**
|
|
11
17
|
* Code that has to run before every rendered frame. This will run after the
|
|
12
18
|
* actor's onInit method has run.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{Vector3 as t}from"three";import{LeafNode as e,NodeState as o}from"./bt";
|
|
1
|
+
import{Vector3 as t}from"three";import{LeafNode as e,NodeState as o}from"./bt";export class CharacterMoveToNode extends e{constructor(t,e){super(),this.navigation=t,this.movement=e,this.distanceFrom=.5}tick(t){const e=this.movement.actor.object.position,i=null!=this.target?this.target():null;if(null==i)return this.movement.directionInput.vector.set(0,0),o.FAILURE;if(e.distanceTo(i)<this.distanceFrom)return this.movement.directionInput.vector.set(0,0),o.SUCCESS;const{success:r,path:s}=this.navigation.findPath(e,i);if(!r||s.length<2)return o.FAILURE;const c=s[1],a=n.subVectors(c,e);return a.y=0,a.normalize(),this.movement.rotationInput.rotation.y=Math.atan2(a.x,a.z),this.movement.directionInput.togglePositiveY(!0),o.RUNNING}}const n=new t;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { NavMesh, RecastConfig, Vector3Tuple } from 'recast-navigation';
|
|
2
2
|
import * as THREE from 'three';
|
|
3
|
+
import { BuildTileMeshProps } from './build-tile.js';
|
|
3
4
|
import { Subject } from 'rxjs';
|
|
4
5
|
export type DynamicTiledNavMeshProps = {
|
|
5
6
|
navMeshBounds: THREE.Box3;
|
|
@@ -8,6 +9,23 @@ export type DynamicTiledNavMeshProps = {
|
|
|
8
9
|
workers: number;
|
|
9
10
|
cacheId: string;
|
|
10
11
|
};
|
|
12
|
+
export declare const MAX_NAV_MESH_WORKERS = 4;
|
|
13
|
+
type NavMeshWorkerResult = {
|
|
14
|
+
tileX: number;
|
|
15
|
+
tileY: number;
|
|
16
|
+
navMeshData: Uint8Array;
|
|
17
|
+
};
|
|
18
|
+
export declare class NavMeshWorkerPool {
|
|
19
|
+
private workerFactory;
|
|
20
|
+
private slots;
|
|
21
|
+
private queue;
|
|
22
|
+
private workerLimit;
|
|
23
|
+
constructor(workerFactory?: () => Worker);
|
|
24
|
+
schedule(owner: object, data: BuildTileMeshProps, transfer: Transferable[] | undefined, onResult: (event: MessageEvent<NavMeshWorkerResult>) => void, requestedWorkers: number): void;
|
|
25
|
+
cancel(owner: object): void;
|
|
26
|
+
private drain;
|
|
27
|
+
private createSlot;
|
|
28
|
+
}
|
|
11
29
|
export declare class DynamicTiledNavMesh {
|
|
12
30
|
navMesh: NavMesh;
|
|
13
31
|
navMeshVersion: number;
|
|
@@ -20,9 +38,8 @@ export declare class DynamicTiledNavMesh {
|
|
|
20
38
|
tileHeight: number;
|
|
21
39
|
tcs: number;
|
|
22
40
|
recastConfig: RecastConfig;
|
|
23
|
-
workers: InstanceType<any>[];
|
|
24
|
-
workerRoundRobin: number;
|
|
25
41
|
private cacheId;
|
|
42
|
+
private workerLimit;
|
|
26
43
|
constructor(props: DynamicTiledNavMeshProps);
|
|
27
44
|
private onResult;
|
|
28
45
|
buildTile(positions: Float32Array, indices: Uint32Array, [tileX, tileY]: [x: number, y: number], useTileCache?: boolean): Promise<unknown>;
|
|
@@ -31,4 +48,5 @@ export declare class DynamicTiledNavMesh {
|
|
|
31
48
|
getTilesForBounds(bounds: THREE.Box3): [x: number, y: number][];
|
|
32
49
|
destroy(): void;
|
|
33
50
|
}
|
|
51
|
+
export {};
|
|
34
52
|
//# sourceMappingURL=dynamic-tiled-navmesh.d.ts.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{NavMesh as t,NavMeshParams as
|
|
1
|
+
import{NavMesh as t,NavMeshParams as e,Raw as s,UnsignedCharArray as i,recastConfigDefaults as o,statusToReadableString as n}from"recast-navigation";import{buildConfig as r,buildTile as a}from"./build-tile.js";import{Subject as h}from"rxjs";import{hasWorkerBuilder as l,createWorker as c}from"../../worker/index.js";import{hasSharedArrayBufferSupport as d}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export class NavMeshWorkerPool{constructor(t=c){this.workerFactory=t,this.slots=[],this.queue=[],this.workerLimit=0}schedule(t,e,s,i,o){this.workerLimit=Math.max(this.workerLimit,Math.min(4,Math.max(1,o))),this.queue.push({owner:t,data:e,transfer:s,onResult:i,cancelled:!1}),this.drain()}cancel(t){this.queue=this.queue.filter(e=>e.owner!==t);for(const e of this.slots)e.job?.owner===t&&(e.job.cancelled=!0)}drain(){for(;this.queue.length>0;){let t=this.slots.find(t=>null==t.job);if(null==t){if(this.slots.length>=this.workerLimit)return;t=this.createSlot(),this.slots.push(t)}const e=this.queue.shift();t.job=e,t.worker.postMessage(e.data,e.transfer)}}createSlot(){const t={worker:this.workerFactory()};return t.worker.onmessage=e=>{const s=t.job;t.job=void 0;try{null==s||s.cancelled||s.onResult(e)}finally{this.drain()}},t.worker.onerror=e=>{t.job=void 0,t.worker.terminate();const s=this.slots.indexOf(t);s>=0&&this.slots.splice(s,1),console.error("Navmesh worker failed",e),this.drain()},t}}const u=new NavMeshWorkerPool;export class DynamicTiledNavMesh{constructor(s){this.navMeshVersion=0,this.onNavMeshUpdate=new h;const i=s.navMeshBounds.min,n=s.navMeshBounds.max,a=[i.toArray(),n.toArray()],l=s.navMeshBounds.min;this.navMeshBoundsMin=i,this.navMeshBoundsMax=n,this.navMeshBounds=a,this.navMeshOrigin=l,this.cacheId=s.cacheId,this.workerLimit=Math.min(4,Math.max(0,s.workers));const c={...o,...s.recastConfig};this.recastConfig=c;const d=new t,{tileWidth:u,tileHeight:M,tcs:f,maxPolysPerTile:m}=r({recastConfig:c,navMeshBounds:a});this.tileWidth=u,this.tileHeight=M,this.tcs=f;const v=e.create({orig:l,tileWidth:c.tileSize*c.cs,tileHeight:c.tileSize*c.cs,maxTiles:s.maxTiles,maxPolys:m});d.initTiled(v),this.navMesh=d}onResult(t){const{tileX:e,tileY:o,navMeshData:r}=t.data,a=new i;a.copy(r),this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0));const h=this.navMesh.addTile(a,s.Module.DT_TILE_FREE_DATA,0);s.Detour.statusFailed(h.status)&&(console.error(s.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${n(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[s,i],o=!0){const n=d&&t.buffer instanceof window.SharedArrayBuffer,r=n?t:new Float32Array(t),h=n?e:new Uint32Array(e),c={tileX:s,tileY:i,tileBoundsMin:[this.navMeshBoundsMin.x+s*this.tcs,this.navMeshBoundsMin.y,this.navMeshBoundsMin.z+i*this.tcs],tileBoundsMax:[this.navMeshBoundsMax.x+(s+1)*this.tcs,this.navMeshBoundsMax.y,this.navMeshBoundsMax.z+(i+1)*this.tcs],recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:r,indices:h};return this.workerLimit>0&&l()?(u.schedule(this,c,n?void 0:[r.buffer,h.buffer],t=>this.onResult(t),this.workerLimit),Promise.resolve()):new Promise(t=>{requestIdleCallback(()=>{const e=this.cacheId+JSON.stringify({tileX:c.tileX,tileY:c.tileY});if(o){const s=localStorage.getItem(e);if(null!=s){const e=f(s);return this.onResult({data:{tileX:c.tileX,tileY:c.tileY,navMeshData:e}}),void t({})}}else localStorage.removeItem(e);const s=a(c);if(!s.success||!s.data)return;const i=s.data.toTypedArray();localStorage.setItem(e,M(i)),this.onResult({data:{tileX:c.tileX,tileY:c.tileY,navMeshData:i}}),t(s)})})}buildAllTiles(t,e){const{tileWidth:s,tileHeight:i}=this;for(let o=0;o<i;o++)for(let i=0;i<s;i++)this.buildTile(t,e,[i,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){const e=this.getTileForWorldPosition(t.min),s=this.getTileForWorldPosition(t.max),i=[];for(let t=e[1];t<=s[1];t++)for(let o=e[0];o<=s[0];o++)i.push([o,t]);return i}destroy(){u.cancel(this),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}const M=function(t){return btoa(String.fromCharCode(...t))},f=function(t){if(!t)return null;const e=atob(t),s=e.length,i=new Uint8Array(s);for(let t=0;t<s;t++)i[t]=e.charCodeAt(t);return i};/*
|
|
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{AnimationClip as e,AnimationMixer as n,Bone as t,LoopOnce as o,Matrix4 as r,Quaternion as i,QuaternionKeyframeTrack as a,Skeleton as s,SkinnedMesh as l,Vector3 as u,VectorKeyframeTrack as c}from"three";import*as d from"three/addons/utils/SkeletonUtils.js";export const ANIMATION_RETARGET_GENERATOR_VERSION=9;export function resolveAnimationRigBasisRotation(e){const n=e.basisPreset??"yUp";let t;t="custom"===n&&null!=e.basisRotation?(new i).fromArray(e.basisRotation).normalize():"yUp"===n?new i:"unrealZUp"===n?(new i).setFromAxisAngle(new u(1,0,0),-Math.PI/2):detectAnimationRigBasisRotation(e);const o=(e.basisYawDegrees??0)*Math.PI/180;return(new i).setFromAxisAngle(new u(0,1,0),o).multiply(t).normalize()}export function detectAnimationRigBasisRotation(e){const n=x(e,{}),t=e.bones.findIndex(n=>n.id===e.pelvisBoneId),o=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),r=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);let a=new u;if(o>=0&&r.length>0){const e=r.reduce((e,t)=>e.add(n.worldPositions[t]),new u).multiplyScalar(1/r.length);a.copy(n.worldPositions[o]).sub(e)}else t>=0&&o>=0&&a.copy(n.worldPositions[o]).sub(n.worldPositions[t]);if(a.lengthSq()<1e-8)return new i;a.normalize();const s=[new u(Math.sign(a.x)||1,0,0),new u(0,Math.sign(a.y)||1,0),new u(0,0,Math.sign(a.z)||1)].sort((e,n)=>Math.abs(n.dot(a))-Math.abs(e.dot(a)))[0];return(new i).setFromUnitVectors(s,new u(0,1,0))}export function extractAnimationRigs(e){const n=[],o=new Set,r=new Set;e.updateMatrixWorld(!0),e.traverse(e=>{if($(e)){for(const n of e.skeleton.bones)r.add(n);o.has(e.skeleton)||(o.add(e.skeleton),n.push({name:e.name,mesh:e,skeleton:e.skeleton}))}}),e.traverse(e=>{if(!(e instanceof t)||e.parent instanceof t)return;const o=[];e.traverse(e=>{e instanceof t&&!r.has(e)&&o.push(e)}),0!==o.length&&n.push({name:e.name,skeleton:new s(o)})});const i=new Map;for(const e of n){const n=f(e.skeleton),t=m(e.skeleton);i.set(n,Math.min(i.get(n)??Number.POSITIVE_INFINITY,t))}const a=[],l=[],u=[];for(const{name:e,mesh:t,skeleton:o}of n){const n=m(o);if(n>(i.get(f(o))??n))continue;const r=g(t,o),s=a.findIndex(e=>e.topologyFingerprint===r.topologyFingerprint&&e.bindPoseFingerprint===r.bindPoseFingerprint);s>=0?n<u[s]&&(a[s]=r,l[s]=e,u[s]=n):(a.push(r),l.push(e),u.push(n))}return{rigs:a,skinnedMeshNames:l}}export function areAnimationRigsCompatible(e,n){return e.topologyFingerprint===n.topologyFingerprint&&e.bindPoseFingerprint===n.bindPoseFingerprint}export function validateAnimationRig(e){const n=[],t=new Set(e.bones.map(e=>e.id)),o=new Map;for(const n of e.bones)o.set(n.name,(o.get(n.name)??0)+1);const r=[...o].filter(([,e])=>e>1).map(([e])=>e);r.length>0&&n.push({severity:"error",code:"duplicate-bone-names",message:`Bone names must be unique for animation tracks. Duplicates: ${r.join(", ")}`});for(const o of e.chains)t.has(o.startBoneId)&&t.has(o.endBoneId)?0===v(e,o).length&&n.push({severity:"error",code:"invalid-chain-hierarchy",message:`Chain "${o.name}" does not follow a parent-to-child hierarchy.`}):n.push({severity:"error",code:"invalid-chain-bone",message:`Chain "${o.name}" references a missing start or end bone.`});return null!=e.retargetRootBoneId&&t.has(e.retargetRootBoneId)||n.push({severity:"error",code:"missing-retarget-root",message:"Select a valid retarget root bone."}),null!=e.pelvisBoneId&&t.has(e.pelvisBoneId)||n.push({severity:"warning",code:"missing-pelvis",message:"Select a pelvis bone for reliable root-motion and height scaling."}),n}export function validateAnimationRetargeter(e,n,t){const o=[...validateAnimationRig(n).map(e=>({...e,message:`Source rig: ${e.message}`})),...validateAnimationRig(t).map(e=>({...e,message:`Target rig: ${e.message}`}))];e.sourceRigFingerprint?.topology===n.topologyFingerprint&&e.sourceRigFingerprint?.bindPose===n.bindPoseFingerprint||o.push({severity:"error",code:"source-rig-changed",message:"The source rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."}),e.targetRigFingerprint?.topology===t.topologyFingerprint&&e.targetRigFingerprint?.bindPose===t.bindPoseFingerprint||o.push({severity:"error",code:"target-rig-changed",message:"The target rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."});for(const r of e.chainMappings)!1!==r.enabled&&(n.chains.some(e=>e.id===r.sourceChainId)||o.push({severity:"error",code:"missing-source-chain",message:`Mapped source chain "${r.sourceChainId}" no longer exists.`}),t.chains.some(e=>e.id===r.targetChainId)||o.push({severity:"error",code:"missing-target-chain",message:`Mapped target chain "${r.targetChainId}" no longer exists.`}));return o}export function createDefaultAnimationRetargeter(e,n,t,o){const r=new Map(o.chains.map(e=>[e.role,e])),i=t.chains.flatMap(e=>{const n=r.get(e.role);return null==n?[]:[{sourceChainId:e.id,targetChainId:n.id,enabled:!0,rotationMode:"interpolated",translationMode:"root"===e.role?"scaled":"none"}]});return{version:1,solverVersion:9,sourceRigId:e,targetRigId:n,sourceRigFingerprint:{topology:t.topologyFingerprint,bindPose:t.bindPoseFingerprint},targetRigFingerprint:{topology:o.topologyFingerprint,bindPose:o.bindPoseFingerprint},sourcePoseId:t.defaultPoseId,targetPoseId:o.defaultPoseId,chainMappings:i,rootSettings:{scaleTranslation:!0,translationAxes:[!0,!0,!0],translationAxisMap:[1,2,3],scaleMultiplier:1},bakeSettings:{framesPerSecond:60},generatedOutputs:{}}}export function createAutoAlignedRetargetPose(e,n,t,o="auto-aligned",r="Auto Aligned"){const a=P(e,t.sourcePoseId),s=P(n,t.targetPoseId),l={...s?.rotationOffsets??{}},u=R(e,a?.rotationOffsets??{}),c=h(e,n,t),d=new Map(e.bones.map((e,n)=>[e.name,n]));new Map(n.bones.map((e,n)=>[e.name,n]));let p=R(n,l);for(let e=0;e<n.bones.length;e++){const t=n.bones[e],o=c[t.name],r=null==o?null:d.get(o);if(null==r)continue;const a=n.bones.map((e,n)=>({bone:e,index:n})).filter(n=>n.bone.parentIndex===e&&null!=c[n.bone.name]);if(1!==a.length)continue;const s=a[0],g=c[s.bone.name],m=null==g?null:d.get(g);if(null==m)continue;const f=u.worldPositions[m].clone().sub(u.worldPositions[r]),h=p.worldPositions[s.index].clone().sub(p.worldPositions[e]);if(f.lengthSq()<1e-8||h.lengthSq()<1e-8)continue;f.normalize(),h.normalize();const w=(new i).setFromUnitVectors(h,f).multiply(p.worldQuaternions[e]),b=(t.parentIndex>=0?p.worldQuaternions[t.parentIndex].clone().invert():new i).multiply(w);l[t.id]=(new i).fromArray(t.quaternion).invert().multiply(b).normalize().toArray(),p=R(n,l)}return{id:o,name:r,rotationOffsets:l,rootOffset:null==s?.rootOffset?void 0:[...s.rootOffset]}}export function bakeRetargetedAnimationClip(r){const p=validateAnimationRetargeter(r.retargeter,r.sourceRig,r.targetRig).filter(e=>"error"===e.severity);if(p.length>0)throw new Error(p.map(e=>e.message).join(" "));const g=S(r.sourceObject,r.sourceRig),m=S(r.targetObject,r.targetRig);if(null==g)throw new Error("The source model does not contain a skinned mesh.");if(null==m)throw new Error("The target model does not contain a skinned mesh.");r.sourceObject.updateMatrixWorld(!0);const f=F(r.sourceRig,r.sourceRig.retargetRootBoneId)??g.skeleton.bones[0]?.name;if(null==f)throw new Error("The source rig has no retarget root.");const w=g.skeleton.getBoneByName(f),b=w?.parent?.getWorldQuaternion(new i)??new i,y=function(e){const n=new l;n.name="RetargetSourceRig";const o=e.bones.map(e=>{const n=new t;return n.name=e.name,n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale),n});for(let t=0;t<o.length;t++){const r=e.bones[t].parentIndex;r>=0?o[r].add(o[t]):n.add(o[t])}return n.bind(new s(o)),n}(r.sourceRig),I=y,x=d.clone(r.targetObject);I.quaternion.copy(resolveAnimationRigBasisRotation(r.sourceRig)).multiply(b),x.quaternion.premultiply(resolveAnimationRigBasisRotation(r.targetRig)),I.updateMatrixWorld(!0),x.updateMatrixWorld(!0);const R=S(x,r.targetRig);if(null==R)throw new Error("Failed to clone the target skeleton.");A(y,r.sourceRig,P(r.sourceRig,r.retargeter.sourcePoseId)),A(R,r.targetRig,P(r.targetRig,r.retargeter.targetPoseId));const v=h(r.sourceRig,r.targetRig,r.retargeter),$=function(t,r,s,l,u,c,d){const p=P(s,u.sourcePoseId),g=P(l,u.targetPoseId),m=new Map(t.skeleton.bones.map(e=>[e.name,e]));A(t,s,p),A(r,l,g);const f=new Map;for(const e of t.skeleton.bones)f.set(e.name,e.getWorldQuaternion(new i));const h=new Map,w=new Map;for(const e of r.skeleton.bones)h.set(e.name,e.getWorldQuaternion(new i)),w.set(e.name,{position:e.position.clone(),quaternion:e.quaternion.clone(),scale:e.scale.clone()});const b=r.skeleton.bones.flatMap(e=>{const n=d[e.name],t=null==n?null:m.get(n),o=null==n?null:f.get(n),r=h.get(e.name);return null==t||null==o||null==r?[]:[{targetBone:e,sourceBone:t,sourceReference:o,targetReference:r,times:[],values:[],previous:null}]}),y=Math.max(60,u.bakeSettings.framesPerSecond),I=Math.max(1,Math.ceil(c.duration*y)),x=I+1,R=new n(t),v=R.clipAction(c);v.setLoop(o,1),v.clampWhenFinished=!0,v.play();const k=new i,F=new i,S=new i,$=new i,O=new i;for(let e=0;e<x;e++){const n=c.duration*e/I;M(t,s),R.setTime(n),B(t,s,p),t.updateMatrixWorld(!0);for(const e of r.skeleton.bones){const n=w.get(e.name);null!=n&&(e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.scale.copy(n.scale))}r.updateMatrixWorld(!0);for(const e of b)e.sourceBone.getWorldQuaternion(F),k.copy(F).multiply($.copy(e.sourceReference).invert()),S.copy(k).multiply(e.targetReference),null!=e.targetBone.parent?(e.targetBone.parent.getWorldQuaternion($).invert(),O.copy($).multiply(S)):O.copy(S),O.normalize(),null!=e.previous&&e.previous.dot(O)<0&&O.set(-O.x,-O.y,-O.z,-O.w),e.targetBone.quaternion.copy(O),e.targetBone.updateMatrixWorld(!0),e.times.push(n),e.values.push(O.x,O.y,O.z,O.w),e.previous??(e.previous=new i),e.previous.copy(O)}return R.stopAllAction(),R.uncacheRoot(t),new e(c.name,c.duration,b.map(e=>new a(`.bones[${e.targetBone.name}].quaternion`,e.times,e.values)))}(y,R,r.sourceRig,r.targetRig,r.retargeter,r.clip,v),O=F(r.targetRig,r.targetRig.retargetRootBoneId);return null!=O&&function(e,n,t,o,r,a,s,l,d){const p=e.tracks.find(e=>e instanceof c&&z(e.name,t)),g=F(r,r.pelvisBoneId),m=F(a,a.pelvisBoneId),f=null==g||g===t?void 0:e.tracks.find(e=>e instanceof c&&z(e.name,g));if(null==p&&null==f)return;const h=k(r),w=k(a),b=s.rootSettings.scaleTranslation&&h>0?w/h*s.rootSettings.scaleMultiplier:s.rootSettings.scaleMultiplier,y=Math.max(60,s.bakeSettings.framesPerSecond),I=Math.max(2,Math.ceil(e.duration*y)+1),x=new Float32Array(I),R=p?.createInterpolant(),v=null==R?null:Float32Array.from(R.evaluate(0)),M=f?.createInterpolant();A(l,r,P(r,s.sourcePoseId)),A(d,a,P(a,s.targetPoseId));const B=l.skeleton.getBoneByName(t),S=d.skeleton.getBoneByName(o),$=B?.parent?.getWorldQuaternion(new i)??new i,O=(S?.parent?.getWorldQuaternion(new i)??new i).invert(),q=null==g?void 0:l.skeleton.getBoneByName(g),C=null==m?void 0:d.skeleton.getBoneByName(m),N=q?.parent?.getWorldQuaternion(new i)??new i,W=(C?.parent?.getWorldQuaternion(new i)??new i).invert(),T=P(a,s.targetPoseId)?.rootOffset??[0,0,0],Q=a.bones.find(e=>e.name===o),E=(Q?.position??[0,0,0]).map((e,n)=>e+T[n]),j=null==m?void 0:a.bones.find(e=>e.name===m),D=m===o?E:j?.position??[0,0,0],L=null!=p||null!=f&&m===o?new Float32Array(3*I):null,_=null!=f&&null!=m&&m!==o?new Float32Array(3*I):null,U=new u,G=new u,H=new u,V=new u,Y=(e,n,t)=>{G.copy(e).applyQuaternion(n),H.set(0,0,0);for(let e=0;e<3;e++)if(s.rootSettings.translationAxes[e]){const n=s.rootSettings.translationAxisMap?.[e]??e+1,t=Math.max(0,Math.min(2,Math.abs(n)-1));H.setComponent(e,G.getComponent(t)*Math.sign(n||1))}return V.copy(H).applyQuaternion(t).multiplyScalar(b)};for(let n=0;n<I;n++){const t=Math.min(e.duration,n/y);if(x[n]=t,null!=L&&(L.set(E,3*n),null!=R&&null!=v)){const e=R.evaluate(t);U.set(e[0]-v[0],e[1]-v[1],e[2]-v[2]);const o=Y(U,$,O);L[3*n]+=o.x,L[3*n+1]+=o.y,L[3*n+2]+=o.z}if(null!=M&&null!=q&&null!=m){const e=M.evaluate(t);U.set(e[0]-q.position.x,e[1]-q.position.y,e[2]-q.position.z);const r=m===o,i=Y(U,N,r?O:W),a=r?L:_;null!=a&&(r||a.set(D,3*n),a[3*n]+=i.x,a[3*n+1]+=i.y,a[3*n+2]+=i.z)}}const Z=new Set([null==L?null:o,null==_?null:m].filter(e=>null!=e));n.tracks=n.tracks.filter(e=>!(e instanceof c&&[...Z].some(n=>z(e.name,n)))),null!=L&&n.tracks.push(new c(`.bones[${o}].position`,x,L));null!=_&&null!=m&&n.tracks.push(new c(`.bones[${m}].position`,x,_))}(r.clip,$,f,O,r.sourceRig,r.targetRig,r.retargeter,y,R),$.name=r.clip.name,$.optimize(),$}export function getAnimationRigIdFromObject(e){if(null==e)return;let n=e.userData?.animationRigId;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRigId)}),n}export function getAnimationRigDataFromObject(e){if(null==e)return;let n=e.userData?.animationRig;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRig)}),n}export function getAnimationRigChainBoneNames(e,n){if(null==e)return[];const t=e.chains.find(e=>e.role===n);return null==t?[]:v(e,t).map(e=>e.name)}export function getAnimationClipBoneNames(e){const n=new Set;for(const t of e.tracks){const e=t.name.match(/\.bones\[([^\]]+)\]\./);if(null!=e?.[1]){n.add(e[1]);continue}const o=t.name.lastIndexOf(".");o>0&&n.add(t.name.slice(0,o))}return[...n]}export function isAnimationClipCompatibleWithRig(e,n){const t=new Set(n.bones.map(e=>e.name));return getAnimationClipBoneNames(e).some(e=>t.has(e))}export function getAnimationClipRigId(e){return null==e?void 0:Q.get(e)}export function setAnimationClipRigId(e,n){null==n?Q.delete(e):Q.set(e,n)}export function findGeneratedAnimationOutput(e,n,t){for(const o of e){const r=o.animationRetargeter;if("animationRetargeter"===o.type&&r?.targetRigId===t&&null!=r.generatedOutputs[n]){const t=r.generatedOutputs[n];return e.find(e=>e.id===t)}}}export function resolveAnimationClipAssetForTarget(e,n,t){if(null==t||e.anim?.rigId===t)return e;if(null==e.anim?.rigId){const n=`${e.id}|${t}`;return p.has(n)||(p.add(n),console.warn(`Animation clip "${e.name}" (${e.id}) has no rig assigned, while the target uses rig ${t}. Playing the legacy source clip without rig compatibility validation.`)),e}const o=findGeneratedAnimationOutput(n,e.id,t);if(null==o)throw new Error(`Animation clip "${e.name}" (${e.id}) targets rig ${e.anim?.rigId??"unassigned"}, but the bound sequence actor uses rig ${t}. Generate this source/target output in an Animation Retargeter before playback.`);if(o.anim?.rigId!==t)throw new Error(`Generated animation clip "${o.name}" (${o.id}) is indexed for rig ${t}, but its clip metadata targets ${o.anim?.rigId??"no rig"}. Regenerate the output.`);return o}const p=new Set;function g(e,n){const o=new Map(n.bones.map((e,n)=>[e,n])),a=new Set(n.bones.filter(e=>function(e,n,o){const r=e.parent;if(!(r instanceof t&&r.name===e.name&&o.has(r)))return!1;if(e.position.lengthSq()>1e-12||Math.abs(e.quaternion.x)>1e-6||Math.abs(e.quaternion.y)>1e-6||Math.abs(e.quaternion.z)>1e-6||Math.abs(Math.abs(e.quaternion.w)-1)>1e-6||e.scale.distanceTo(new u(1,1,1))>1e-6)return!1;const i=n.boneInverses[o.get(e)],a=n.boneInverses[o.get(r)];return null!=i&&null!=a&&(s=i,l=a,s.elements.every((e,n)=>Math.abs(e-l.elements[n])<=1e-6));var s,l}(e,n,o))),s=n.bones.filter(e=>!a.has(e)),l=new Map(s.map((e,n)=>[e,n])),c=[];for(let e=0;e<s.length;e++){const a=s[e],d=o.get(a)??e;let p=a.parent;for(;p instanceof t&&!l.has(p);)p=p.parent;const g=p instanceof t?l.get(p)??-1:-1,m=a.name||`bone_${e}`,f=g<0?m:`${c[g].id}/${m}`,h=new u,w=new i,b=new u;a.matrix.decompose(h,w,b),c.push({id:f,name:m,parentIndex:g,position:h.toArray(),quaternion:w.toArray(),scale:b.toArray(),inverseBindMatrix:(n.boneInverses[d]??new r).toArray()})}const d=T(c.map(e=>[e.name,e.parentIndex])),p=T(c.map(e=>[e.name,e.parentIndex,...W(e.position),...W(e.quaternion),...W(e.scale),...W(e.inverseBindMatrix)])),g=function(e){const n=[{role:"spine",start:["spine"],end:["chest","spine2","spine_02","spine3"]},{role:"neck",start:["neck"],end:["head"]},{role:"leftArm",side:"left",start:["upperarm","arm"],end:["hand","wrist"]},{role:"rightArm",side:"right",start:["upperarm","arm"],end:["hand","wrist"]},{role:"leftLeg",side:"left",start:["upleg","thigh","upperleg"],end:["foot","ankle"]},{role:"rightLeg",side:"right",start:["upleg","thigh","upperleg"],end:["foot","ankle"]}],t=[];for(const o of n){const n=o.side?q(e,o.side,o.start):O(e,o.start),r=o.side?q(e,o.side,o.end):O(e,o.end);null!=n&&null!=r&&t.push({id:o.role,name:N(o.role),role:o.role,startBoneId:n.id,endBoneId:r.id})}return t}(c),m=O(c,["root","armature"]),f=O(c,["hips","hip","pelvis"]),h=q(c,"left",["hand","wrist"]),w=q(c,"right",["hand","wrist"]);return{version:1,basisPreset:"auto",basisYawDegrees:0,skinnedMeshName:e?.name||void 0,bones:c,topologyFingerprint:d,bindPoseFingerprint:p,retargetRootBoneId:m?.id??f?.id??c[0]?.id,pelvisBoneId:f?.id,leftHandBoneId:h?.id,rightHandBoneId:w?.id,chains:g,poses:[{id:"default",name:"Default",rotationOffsets:{}}],defaultPoseId:"default"}}function m(e){const n=new Set(e.bones);return e.bones.filter(e=>e.parent instanceof t&&!n.has(e.parent)).length}function f(e){return[...new Set(e.bones.map(e=>e.name))].sort().join("\n")}function h(e,n,t){const o={};for(const r of t.chainMappings){if(!1===r.enabled)continue;const t=e.chains.find(e=>e.id===r.sourceChainId),i=n.chains.find(e=>e.id===r.targetChainId);if(null==t||null==i)continue;const a=v(e,t),s=v(n,i);if(0!==a.length&&0!==s.length)for(let e=0;e<s.length;e++){const n=1===s.length?0:e/(s.length-1),t=Math.round(n*(a.length-1));o[s[e].name]=a[t].name}}return w(o,e,n,"retargetRootBoneId"),w(o,e,n,"pelvisBoneId"),w(o,e,n,"leftHandBoneId"),w(o,e,n,"rightHandBoneId"),b(o,e,n,"leftHandBoneId"),b(o,e,n,"rightHandBoneId"),o}function w(e,n,t,o){const r=F(n,n[o]),i=F(t,t[o]);null!=r&&null!=i&&(e[i]=r)}function b(e,n,t,o){const r=n.bones.findIndex(e=>e.id===n[o]),i=t.bones.findIndex(e=>e.id===t[o]);if(r<0||i<0)return;const a=new Map;for(const e of y(n,r)){const n=I(e.name);null!=n&&a.set(n,e)}for(const n of y(t,i)){const t=I(n.name),o=null==t?null:a.get(t);null!=o&&(e[n.name]=o.name)}}function y(e,n){return e.bones.filter((t,o)=>{let r=e.bones[o].parentIndex;for(;r>=0;){if(r===n)return!0;r=e.bones[r].parentIndex}return!1})}function I(e){const n=e.toLowerCase();if(n.includes("base"))return null;const t=["thumb","index","middle","ring","pinky"].find(e=>n.includes(e));if(null==t)return null;const o=n.slice(n.indexOf(t)+t.length),r=o.match(/\d+/)?.[0];return null==r?null:`${t}:${Number(r)}`}function x(e,n){const t=[],o=[],a=[];for(let s=0;s<e.bones.length;s++){const l=e.bones[s],c=(new i).fromArray(l.quaternion),d=n[l.id];null!=d&&c.multiply((new i).fromArray(d)).normalize();const p=(new r).compose((new u).fromArray(l.position),c,(new u).fromArray(l.scale));l.parentIndex>=0&&p.premultiply(t[l.parentIndex]),t.push(p),o.push((new u).setFromMatrixPosition(p)),a.push((new i).setFromRotationMatrix(p))}return{worldPositions:o,worldQuaternions:a}}function R(e,n){const t=x(e,n),o=resolveAnimationRigBasisRotation(e);for(const e of t.worldPositions)e.applyQuaternion(o);for(const e of t.worldQuaternions)e.premultiply(o);return t}function v(e,n){const t=e.bones.findIndex(e=>e.id===n.startBoneId),o=e.bones.findIndex(e=>e.id===n.endBoneId);if(t<0||o<0)return[];const r=[];let i=o;for(;i>=0;){if(r.push(e.bones[i]),i===t)return r.reverse();i=e.bones[i].parentIndex}return[]}function A(e,n,t){M(e,n),B(e,n,t),e.updateMatrixWorld(!0)}function M(e,n){const t=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const e of n.bones){const n=t.get(e.name);null!=n&&(n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale))}}function B(e,n,t){if(null==t)return;const o=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const[e,r]of Object.entries(t.rotationOffsets)){const t=n.bones.find(n=>n.id===e),a=null==t?void 0:o.get(t.name);null!=a&&a.quaternion.multiply((new i).fromArray(r)).normalize()}const r=F(n,n.retargetRootBoneId),a=null==r?void 0:o.get(r);null!=a&&null!=t.rootOffset&&a.position.add((new u).fromArray(t.rootOffset))}function k(e){const n=e.bones.map(()=>new r),t=e.bones.map(()=>new u);for(let o=0;o<e.bones.length;o++){const r=e.bones[o];n[o].compose((new u).fromArray(r.position),(new i).fromArray(r.quaternion),(new u).fromArray(r.scale)),r.parentIndex>=0&&n[o].premultiply(n[r.parentIndex]),t[o].setFromMatrixPosition(n[o])}const o=e.bones.findIndex(n=>n.id===e.pelvisBoneId),a=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),s=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);if(o>=0&&a>=0&&s.length>0){const e=t[o].distanceTo(t[a]),n=Math.max(...s.map(e=>t[o].distanceTo(t[e])));if(e+n>1e-4)return e+n}let l=0;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++)l=Math.max(l,t[e].distanceTo(t[n]));return Math.max(1e-4,l)}function P(e,n){return e.poses.find(e=>e.id===n)}function F(e,n){return null==n?void 0:e.bones.find(e=>e.id===n)?.name}function S(e,n){const t=[];if(e.traverse(e=>{$(e)&&t.push(e)}),null==n)return t[0];const o=null==n.skinnedMeshName?void 0:t.find(e=>e.name===n.skinnedMeshName);if(null!=o)return o;const r=t.map(e=>({candidate:e,rig:g(e,e.skeleton)}));return r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint&&e.rig.bindPoseFingerprint===n.bindPoseFingerprint)?.candidate??r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint)?.candidate??t[0]}function $(e){return e instanceof l||!0===e.isSkinnedMesh}function O(e,n){return e.find(e=>n.some(n=>C(e.name)===C(n)))??e.find(e=>n.some(n=>C(e.name).includes(C(n))))}function q(e,n,t){const o="left"===n?["left","_l",".l"]:["right","_r",".r"];return e.find(e=>{const n=e.name.toLowerCase(),r=C(n);return o.some(e=>n.includes(e))&&t.some(e=>r.includes(C(e)))})}function C(e){return e.toLowerCase().replace(/^mixamorig[:_]?/,"").replace(/^bip0*1[_:]?/,"").replace(/[^a-z0-9]/g,"")}function N(e){return e.replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,e=>e.toUpperCase())}function W(e){return e.map(e=>Math.round(1e5*e)/1e5)}function T(e){const n=JSON.stringify(e);let t=2166136261;for(let e=0;e<n.length;e++)t^=n.charCodeAt(e),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function z(e,n){return e===`${n}.position`||e===`.bones[${n}].position`||e.endsWith(`[${n}].position`)}const Q=new WeakMap;/*
|
|
1
|
+
import{AnimationClip as e,AnimationMixer as n,Bone as t,LoopOnce as o,Matrix4 as r,Quaternion as i,QuaternionKeyframeTrack as a,Skeleton as s,SkinnedMesh as l,Vector3 as u,VectorKeyframeTrack as c}from"three";import*as d from"three/addons/utils/SkeletonUtils.js";export const ANIMATION_RETARGET_GENERATOR_VERSION=9;export function resolveAnimationRigBasisRotation(e){const n=e.basisPreset??"yUp";let t;t="custom"===n&&null!=e.basisRotation?(new i).fromArray(e.basisRotation).normalize():"yUp"===n?new i:"unrealZUp"===n?(new i).setFromAxisAngle(new u(1,0,0),-Math.PI/2):detectAnimationRigBasisRotation(e);const o=(e.basisYawDegrees??0)*Math.PI/180;return(new i).setFromAxisAngle(new u(0,1,0),o).multiply(t).normalize()}export function detectAnimationRigBasisRotation(e){const n=R(e,{}),t=e.bones.findIndex(n=>n.id===e.pelvisBoneId),o=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),r=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);let a=new u;if(o>=0&&r.length>0){const e=r.reduce((e,t)=>e.add(n.worldPositions[t]),new u).multiplyScalar(1/r.length);a.copy(n.worldPositions[o]).sub(e)}else t>=0&&o>=0&&a.copy(n.worldPositions[o]).sub(n.worldPositions[t]);if(a.lengthSq()<1e-8)return new i;a.normalize();const s=[new u(Math.sign(a.x)||1,0,0),new u(0,Math.sign(a.y)||1,0),new u(0,0,Math.sign(a.z)||1)].sort((e,n)=>Math.abs(n.dot(a))-Math.abs(e.dot(a)))[0];return(new i).setFromUnitVectors(s,new u(0,1,0))}export function extractAnimationRigs(e){const n=[],o=new Set,r=new Set;e.updateMatrixWorld(!0),e.traverse(e=>{if(O(e)){for(const n of e.skeleton.bones)r.add(n);o.has(e.skeleton)||(o.add(e.skeleton),n.push({name:e.name,mesh:e,skeleton:e.skeleton}))}}),e.traverse(e=>{if(!(e instanceof t)||e.parent instanceof t)return;const o=[];e.traverse(e=>{e instanceof t&&!r.has(e)&&o.push(e)}),0!==o.length&&n.push({name:e.name,skeleton:new s(o)})});const i=new Map;for(const e of n){const n=f(e.skeleton),t=m(e.skeleton);i.set(n,Math.min(i.get(n)??Number.POSITIVE_INFINITY,t))}const a=[],l=[],u=[];for(const{name:e,mesh:t,skeleton:o}of n){const n=m(o);if(n>(i.get(f(o))??n))continue;const r=g(t,o),s=a.findIndex(e=>e.topologyFingerprint===r.topologyFingerprint&&e.bindPoseFingerprint===r.bindPoseFingerprint);s>=0?n<u[s]&&(a[s]=r,l[s]=e,u[s]=n):(a.push(r),l.push(e),u.push(n))}return{rigs:a,skinnedMeshNames:l}}export function areAnimationRigsCompatible(e,n){return e.topologyFingerprint===n.topologyFingerprint&&e.bindPoseFingerprint===n.bindPoseFingerprint}export function validateAnimationRig(e){const n=[],t=new Set(e.bones.map(e=>e.id)),o=new Map;for(const n of e.bones)o.set(n.name,(o.get(n.name)??0)+1);const r=[...o].filter(([,e])=>e>1).map(([e])=>e);r.length>0&&n.push({severity:"error",code:"duplicate-bone-names",message:`Bone names must be unique for animation tracks. Duplicates: ${r.join(", ")}`});for(const o of e.chains)t.has(o.startBoneId)&&t.has(o.endBoneId)?0===v(e,o).length&&n.push({severity:"error",code:"invalid-chain-hierarchy",message:`Chain "${o.name}" does not follow a parent-to-child hierarchy.`}):n.push({severity:"error",code:"invalid-chain-bone",message:`Chain "${o.name}" references a missing start or end bone.`});return null!=e.retargetRootBoneId&&t.has(e.retargetRootBoneId)||n.push({severity:"error",code:"missing-retarget-root",message:"Select a valid retarget root bone."}),null!=e.pelvisBoneId&&t.has(e.pelvisBoneId)||n.push({severity:"warning",code:"missing-pelvis",message:"Select a pelvis bone for reliable root-motion and height scaling."}),n}export function validateAnimationRetargeter(e,n,t){const o=[...validateAnimationRig(n).map(e=>({...e,message:`Source rig: ${e.message}`})),...validateAnimationRig(t).map(e=>({...e,message:`Target rig: ${e.message}`}))];e.sourceRigFingerprint?.topology===n.topologyFingerprint&&e.sourceRigFingerprint?.bindPose===n.bindPoseFingerprint||o.push({severity:"error",code:"source-rig-changed",message:"The source rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."}),e.targetRigFingerprint?.topology===t.topologyFingerprint&&e.targetRigFingerprint?.bindPose===t.bindPoseFingerprint||o.push({severity:"error",code:"target-rig-changed",message:"The target rig hierarchy or bind pose changed. Review mappings and explicitly accept the new fingerprints."});for(const r of e.chainMappings)!1!==r.enabled&&(n.chains.some(e=>e.id===r.sourceChainId)||o.push({severity:"error",code:"missing-source-chain",message:`Mapped source chain "${r.sourceChainId}" no longer exists.`}),t.chains.some(e=>e.id===r.targetChainId)||o.push({severity:"error",code:"missing-target-chain",message:`Mapped target chain "${r.targetChainId}" no longer exists.`}));return o}export function createDefaultAnimationRetargeter(e,n,t,o){const r=new Map(o.chains.map(e=>[e.role,e])),i=t.chains.flatMap(e=>{const n=r.get(e.role);return null==n?[]:[{sourceChainId:e.id,targetChainId:n.id,enabled:!0,rotationMode:"interpolated",translationMode:"root"===e.role?"scaled":"none"}]});return{version:1,solverVersion:9,sourceRigId:e,targetRigId:n,sourceRigFingerprint:{topology:t.topologyFingerprint,bindPose:t.bindPoseFingerprint},targetRigFingerprint:{topology:o.topologyFingerprint,bindPose:o.bindPoseFingerprint},sourcePoseId:t.defaultPoseId,targetPoseId:o.defaultPoseId,chainMappings:i,rootSettings:{scaleTranslation:!0,translationAxes:[!0,!0,!0],translationAxisMap:[1,2,3],scaleMultiplier:1},bakeSettings:{framesPerSecond:60},generatedOutputs:{}}}export function createAutoAlignedRetargetPose(e,n,t,o="auto-aligned",r="Auto Aligned"){const a=P(e,t.sourcePoseId),s=P(n,t.targetPoseId),l={...s?.rotationOffsets??{}},u=x(e,a?.rotationOffsets??{}),c=h(e,n,t),d=new Map(e.bones.map((e,n)=>[e.name,n]));new Map(n.bones.map((e,n)=>[e.name,n]));let p=x(n,l);for(let e=0;e<n.bones.length;e++){const t=n.bones[e],o=c[t.name],r=null==o?null:d.get(o);if(null==r)continue;const a=n.bones.map((e,n)=>({bone:e,index:n})).filter(n=>n.bone.parentIndex===e&&null!=c[n.bone.name]);if(1!==a.length)continue;const s=a[0],g=c[s.bone.name],m=null==g?null:d.get(g);if(null==m)continue;const f=u.worldPositions[m].clone().sub(u.worldPositions[r]),h=p.worldPositions[s.index].clone().sub(p.worldPositions[e]);if(f.lengthSq()<1e-8||h.lengthSq()<1e-8)continue;f.normalize(),h.normalize();const w=(new i).setFromUnitVectors(h,f).multiply(p.worldQuaternions[e]),b=p.parentWorldQuaternions[e].clone().invert().multiply(w);l[t.id]=(new i).fromArray(t.quaternion).invert().multiply(b).normalize().toArray(),p=x(n,l)}return{id:o,name:r,rotationOffsets:l,rootOffset:null==s?.rootOffset?void 0:[...s.rootOffset]}}export function bakeRetargetedAnimationClip(r){const p=validateAnimationRetargeter(r.retargeter,r.sourceRig,r.targetRig).filter(e=>"error"===e.severity);if(p.length>0)throw new Error(p.map(e=>e.message).join(" "));const g=S(r.sourceObject,r.sourceRig);if(null==S(r.targetObject,r.targetRig))throw new Error("The target model does not contain a skinned mesh.");r.sourceObject.updateMatrixWorld(!0);const m=F(r.sourceRig,r.sourceRig.retargetRootBoneId)??g?.skeleton.bones[0]?.name??r.sourceRig.bones.find(e=>e.parentIndex<0)?.name;if(null==m)throw new Error("The source rig has no retarget root.");const f=g?.skeleton.getBoneByName(m)??function(e,n,o){const r=[];if(e.traverse(e=>{e instanceof t&&e.name===o&&r.push(e)}),r.length<=1)return r[0];const i=new Set(n.bones.map(e=>e.name));return r.sort((e,n)=>$(n,i)-$(e,i))[0]}(r.sourceObject,r.sourceRig,m),w=f?.parent?.getWorldQuaternion(new i)??new i,b=function(e){const n=new l;n.name="RetargetSourceRig";const o=e.bones.map(e=>{const n=new t;return n.name=e.name,n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale),n});for(let t=0;t<o.length;t++){const r=e.bones[t].parentIndex;r>=0?o[r].add(o[t]):n.add(o[t])}return n.bind(new s(o)),n}(r.sourceRig),y=b,I=d.clone(r.targetObject);y.quaternion.copy(resolveAnimationRigBasisRotation(r.sourceRig)).multiply(w),I.quaternion.premultiply(resolveAnimationRigBasisRotation(r.targetRig)),y.updateMatrixWorld(!0),I.updateMatrixWorld(!0);const R=S(I,r.targetRig);if(null==R)throw new Error("Failed to clone the target skeleton.");A(b,r.sourceRig,P(r.sourceRig,r.retargeter.sourcePoseId)),A(R,r.targetRig,P(r.targetRig,r.retargeter.targetPoseId));const x=h(r.sourceRig,r.targetRig,r.retargeter),v=function(t,r,s,l,u,c,d){const p=P(s,u.sourcePoseId),g=P(l,u.targetPoseId),m=new Map(t.skeleton.bones.map(e=>[e.name,e]));A(t,s,p),A(r,l,g);const f=new Map;for(const e of t.skeleton.bones)f.set(e.name,e.getWorldQuaternion(new i));const h=new Map,w=new Map;for(const e of r.skeleton.bones)h.set(e.name,e.getWorldQuaternion(new i)),w.set(e.name,{position:e.position.clone(),quaternion:e.quaternion.clone(),scale:e.scale.clone()});const b=r.skeleton.bones.flatMap(e=>{const n=d[e.name],t=null==n?null:m.get(n),o=null==n?null:f.get(n),r=h.get(e.name);return null==t||null==o||null==r?[]:[{targetBone:e,sourceBone:t,sourceReference:o,targetReference:r,times:[],values:[],previous:null}]}),y=Math.max(60,u.bakeSettings.framesPerSecond),I=Math.max(1,Math.ceil(c.duration*y)),R=I+1,x=new n(t),v=x.clipAction(c);v.setLoop(o,1),v.clampWhenFinished=!0,v.play();const k=new i,F=new i,S=new i,$=new i,O=new i;for(let e=0;e<R;e++){const n=c.duration*e/I;M(t,s),x.setTime(n),B(t,s,p),t.updateMatrixWorld(!0);for(const e of r.skeleton.bones){const n=w.get(e.name);null!=n&&(e.position.copy(n.position),e.quaternion.copy(n.quaternion),e.scale.copy(n.scale))}r.updateMatrixWorld(!0);for(const e of b)e.sourceBone.getWorldQuaternion(F),k.copy(F).multiply($.copy(e.sourceReference).invert()),S.copy(k).multiply(e.targetReference),null!=e.targetBone.parent?(e.targetBone.parent.getWorldQuaternion($).invert(),O.copy($).multiply(S)):O.copy(S),O.normalize(),null!=e.previous&&e.previous.dot(O)<0&&O.set(-O.x,-O.y,-O.z,-O.w),e.targetBone.quaternion.copy(O),e.targetBone.updateMatrixWorld(!0),e.times.push(n),e.values.push(O.x,O.y,O.z,O.w),e.previous??(e.previous=new i),e.previous.copy(O)}return x.stopAllAction(),x.uncacheRoot(t),new e(c.name,c.duration,b.map(e=>new a(`.bones[${e.targetBone.name}].quaternion`,e.times,e.values)))}(b,R,r.sourceRig,r.targetRig,r.retargeter,r.clip,x),O=F(r.targetRig,r.targetRig.retargetRootBoneId);return null!=O&&function(e,n,t,o,r,a,s,l,d){const p=e.tracks.find(e=>e instanceof c&&Q(e.name,t)),g=F(r,r.pelvisBoneId),m=F(a,a.pelvisBoneId),f=null==g||g===t?void 0:e.tracks.find(e=>e instanceof c&&Q(e.name,g));if(null==p&&null==f)return;const h=k(r),w=k(a),b=s.rootSettings.scaleTranslation&&h>0?w/h*s.rootSettings.scaleMultiplier:s.rootSettings.scaleMultiplier,y=Math.max(60,s.bakeSettings.framesPerSecond),I=Math.max(2,Math.ceil(e.duration*y)+1),R=new Float32Array(I),x=p?.createInterpolant(),v=null==x?null:Float32Array.from(x.evaluate(0)),M=f?.createInterpolant();A(l,r,P(r,s.sourcePoseId)),A(d,a,P(a,s.targetPoseId));const B=l.skeleton.getBoneByName(t),S=d.skeleton.getBoneByName(o),$=B?.parent?.getWorldQuaternion(new i)??new i,O=(S?.parent?.getWorldQuaternion(new i)??new i).invert(),q=null==g?void 0:l.skeleton.getBoneByName(g),C=null==m?void 0:d.skeleton.getBoneByName(m),W=q?.parent?.getWorldQuaternion(new i)??new i,N=(C?.parent?.getWorldQuaternion(new i)??new i).invert(),z=P(a,s.targetPoseId)?.rootOffset??[0,0,0],T=a.bones.find(e=>e.name===o),j=(T?.position??[0,0,0]).map((e,n)=>e+z[n]),E=null==m?void 0:a.bones.find(e=>e.name===m),D=m===o?j:E?.position??[0,0,0],L=null!=p||null!=f&&m===o?new Float32Array(3*I):null,_=null!=f&&null!=m&&m!==o?new Float32Array(3*I):null,U=new u,G=new u,H=new u,V=new u,Y=(e,n,t)=>{G.copy(e).applyQuaternion(n),H.set(0,0,0);for(let e=0;e<3;e++)if(s.rootSettings.translationAxes[e]){const n=s.rootSettings.translationAxisMap?.[e]??e+1,t=Math.max(0,Math.min(2,Math.abs(n)-1));H.setComponent(e,G.getComponent(t)*Math.sign(n||1))}return V.copy(H).applyQuaternion(t).multiplyScalar(b)};for(let n=0;n<I;n++){const t=Math.min(e.duration,n/y);if(R[n]=t,null!=L&&(L.set(j,3*n),null!=x&&null!=v)){const e=x.evaluate(t);U.set(e[0]-v[0],e[1]-v[1],e[2]-v[2]);const o=Y(U,$,O);L[3*n]+=o.x,L[3*n+1]+=o.y,L[3*n+2]+=o.z}if(null!=M&&null!=q&&null!=m){const e=M.evaluate(t);U.set(e[0]-q.position.x,e[1]-q.position.y,e[2]-q.position.z);const r=m===o,i=Y(U,W,r?O:N),a=r?L:_;null!=a&&(r||a.set(D,3*n),a[3*n]+=i.x,a[3*n+1]+=i.y,a[3*n+2]+=i.z)}}const Z=new Set([null==L?null:o,null==_?null:m].filter(e=>null!=e));n.tracks=n.tracks.filter(e=>!(e instanceof c&&[...Z].some(n=>Q(e.name,n)))),null!=L&&n.tracks.push(new c(`.bones[${o}].position`,R,L));null!=_&&null!=m&&n.tracks.push(new c(`.bones[${m}].position`,R,_))}(r.clip,v,m,O,r.sourceRig,r.targetRig,r.retargeter,b,R),v.name=r.clip.name,v.optimize(),v}export function getAnimationRigIdFromObject(e){if(null==e)return;let n=e.userData?.animationRigId;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRigId)}),n}export function getAnimationRigDataFromObject(e){if(null==e)return;let n=e.userData?.animationRig;return null!=n||e.traverse(e=>{n??(n=e.userData?.animationRig)}),n}export function getAnimationRigChainBoneNames(e,n){if(null==e)return[];const t=e.chains.find(e=>e.role===n);return null==t?[]:v(e,t).map(e=>e.name)}export function getAnimationClipBoneNames(e){const n=new Set;for(const t of e.tracks){const e=t.name.match(/\.bones\[([^\]]+)\]\./);if(null!=e?.[1]){n.add(e[1]);continue}const o=t.name.lastIndexOf(".");o>0&&n.add(t.name.slice(0,o))}return[...n]}export function isAnimationClipCompatibleWithRig(e,n){const t=new Set(n.bones.map(e=>e.name));return getAnimationClipBoneNames(e).some(e=>t.has(e))}export function getAnimationClipRigId(e){return null==e?void 0:j.get(e)}export function setAnimationClipRigId(e,n){null==n?j.delete(e):j.set(e,n)}export function findGeneratedAnimationOutput(e,n,t){for(const o of e){const r=o.animationRetargeter;if("animationRetargeter"===o.type&&r?.targetRigId===t&&null!=r.generatedOutputs[n]){const t=r.generatedOutputs[n];return e.find(e=>e.id===t)}}}export function resolveAnimationClipAssetForTarget(e,n,t){if(null==t||e.anim?.rigId===t)return e;if(null==e.anim?.rigId){const n=`${e.id}|${t}`;return p.has(n)||(p.add(n),console.warn(`Animation clip "${e.name}" (${e.id}) has no rig assigned, while the target uses rig ${t}. Playing the legacy source clip without rig compatibility validation.`)),e}const o=findGeneratedAnimationOutput(n,e.id,t);if(null==o)throw new Error(`Animation clip "${e.name}" (${e.id}) targets rig ${e.anim?.rigId??"unassigned"}, but the bound sequence actor uses rig ${t}. Generate this source/target output in an Animation Retargeter before playback.`);if(o.anim?.rigId!==t)throw new Error(`Generated animation clip "${o.name}" (${o.id}) is indexed for rig ${t}, but its clip metadata targets ${o.anim?.rigId??"no rig"}. Regenerate the output.`);return o}const p=new Set;function g(e,n){const o=new Map(n.bones.map((e,n)=>[e,n])),a=new Set(n.bones.filter(e=>function(e,n,o){const r=e.parent;if(!(r instanceof t&&r.name===e.name&&o.has(r)))return!1;if(e.position.lengthSq()>1e-12||Math.abs(e.quaternion.x)>1e-6||Math.abs(e.quaternion.y)>1e-6||Math.abs(e.quaternion.z)>1e-6||Math.abs(Math.abs(e.quaternion.w)-1)>1e-6||e.scale.distanceTo(new u(1,1,1))>1e-6)return!1;const i=n.boneInverses[o.get(e)],a=n.boneInverses[o.get(r)];return null!=i&&null!=a&&(s=i,l=a,s.elements.every((e,n)=>Math.abs(e-l.elements[n])<=1e-6));var s,l}(e,n,o))),s=n.bones.filter(e=>!a.has(e)),l=new Map(s.map((e,n)=>[e,n])),c=[];for(let e=0;e<s.length;e++){const a=s[e],d=o.get(a)??e;let p=a.parent;for(;p instanceof t&&!l.has(p);)p=p.parent;const g=p instanceof t?l.get(p)??-1:-1,m=a.name||`bone_${e}`,f=g<0?m:`${c[g].id}/${m}`,h=new u,w=new i,b=new u;a.matrix.decompose(h,w,b),c.push({id:f,name:m,parentIndex:g,position:h.toArray(),quaternion:w.toArray(),scale:b.toArray(),inverseBindMatrix:(n.boneInverses[d]??new r).toArray()})}const d=T(c.map(e=>[e.name,e.parentIndex])),p=T(c.map(e=>[e.name,e.parentIndex,...z(e.position),...z(e.quaternion),...z(e.scale),...z(e.inverseBindMatrix)])),g=function(e){const n=[{role:"spine",start:["spine"],end:["chest","spine2","spine_02","spine3"]},{role:"neck",start:["neck"],end:["head"]},{role:"leftArm",side:"left",start:["upperarm","arm"],end:["hand","wrist"]},{role:"rightArm",side:"right",start:["upperarm","arm"],end:["hand","wrist"]},{role:"leftLeg",side:"left",start:["upleg","thigh","upperleg"],end:["foot","ankle"]},{role:"rightLeg",side:"right",start:["upleg","thigh","upperleg"],end:["foot","ankle"]}],t=[];for(const o of n){const n=o.side?C(e,o.side,o.start):q(e,o.start),r=o.side?C(e,o.side,o.end):q(e,o.end);null!=n&&null!=r&&t.push({id:o.role,name:N(o.role),role:o.role,startBoneId:n.id,endBoneId:r.id})}return t}(c),m=q(c,["root","armature"]),f=q(c,["hips","hip","pelvis"]),h=C(c,"left",["hand","wrist"]),w=C(c,"right",["hand","wrist"]);return{version:1,basisPreset:"auto",basisYawDegrees:0,skinnedMeshName:e?.name||void 0,bones:c,topologyFingerprint:d,bindPoseFingerprint:p,retargetRootBoneId:m?.id??f?.id??c[0]?.id,pelvisBoneId:f?.id,leftHandBoneId:h?.id,rightHandBoneId:w?.id,chains:g,poses:[{id:"default",name:"Default",rotationOffsets:{}}],defaultPoseId:"default"}}function m(e){const n=new Set(e.bones);return e.bones.filter(e=>e.parent instanceof t&&!n.has(e.parent)).length}function f(e){return[...new Set(e.bones.map(e=>e.name))].sort().join("\n")}function h(e,n,t){const o={};for(const r of t.chainMappings){if(!1===r.enabled)continue;const t=e.chains.find(e=>e.id===r.sourceChainId),i=n.chains.find(e=>e.id===r.targetChainId);if(null==t||null==i)continue;const a=v(e,t),s=v(n,i);if(0!==a.length&&0!==s.length)for(let e=0;e<s.length;e++){const n=1===s.length?0:e/(s.length-1),t=Math.round(n*(a.length-1));o[s[e].name]=a[t].name}}return w(o,e,n,"retargetRootBoneId"),w(o,e,n,"pelvisBoneId"),w(o,e,n,"leftHandBoneId"),w(o,e,n,"rightHandBoneId"),b(o,e,n,"leftHandBoneId"),b(o,e,n,"rightHandBoneId"),o}function w(e,n,t,o){const r=F(n,n[o]),i=F(t,t[o]);null!=r&&null!=i&&(e[i]=r)}function b(e,n,t,o){const r=n.bones.findIndex(e=>e.id===n[o]),i=t.bones.findIndex(e=>e.id===t[o]);if(r<0||i<0)return;const a=new Map;for(const e of y(n,r)){const n=I(e.name);null!=n&&a.set(n,e)}for(const n of y(t,i)){const t=I(n.name),o=null==t?null:a.get(t);null!=o&&(e[n.name]=o.name)}}function y(e,n){return e.bones.filter((t,o)=>{let r=e.bones[o].parentIndex;for(;r>=0;){if(r===n)return!0;r=e.bones[r].parentIndex}return!1})}function I(e){const n=e.toLowerCase();if(n.includes("base"))return null;const t=["thumb","index","middle","ring","pinky"].find(e=>n.includes(e));if(null==t)return null;const o=n.slice(n.indexOf(t)+t.length),r=o.match(/\d+/)?.[0];return null==r?null:`${t}:${Number(r)}`}function R(e,n){const t=[],o=[],a=[],s=[];for(let l=0;l<e.bones.length;l++){const c=e.bones[l],d=(new i).fromArray(c.quaternion),p=d.clone(),g=n[c.id];null!=g&&p.multiply((new i).fromArray(g)).normalize();const m=(new r).compose((new u).fromArray(c.position),p,(new u).fromArray(c.scale));let f;if(c.parentIndex>=0)f=t[c.parentIndex],m.premultiply(f);else{const e=(new r).compose((new u).fromArray(c.position),d,(new u).fromArray(c.scale));f=(new r).fromArray(c.inverseBindMatrix).invert().multiply(e.invert()),m.premultiply(f)}t.push(m),o.push((new u).setFromMatrixPosition(m)),a.push((new i).setFromRotationMatrix(m)),s.push((new i).setFromRotationMatrix(f))}return{worldPositions:o,worldQuaternions:a,parentWorldQuaternions:s}}function x(e,n){const t=R(e,n),o=resolveAnimationRigBasisRotation(e);for(const e of t.worldPositions)e.applyQuaternion(o);for(const e of t.worldQuaternions)e.premultiply(o);for(const e of t.parentWorldQuaternions)e.premultiply(o);return t}function v(e,n){const t=e.bones.findIndex(e=>e.id===n.startBoneId),o=e.bones.findIndex(e=>e.id===n.endBoneId);if(t<0||o<0)return[];const r=[];let i=o;for(;i>=0;){if(r.push(e.bones[i]),i===t)return r.reverse();i=e.bones[i].parentIndex}return[]}function A(e,n,t){M(e,n),B(e,n,t),e.updateMatrixWorld(!0)}function M(e,n){const t=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const e of n.bones){const n=t.get(e.name);null!=n&&(n.position.fromArray(e.position),n.quaternion.fromArray(e.quaternion),n.scale.fromArray(e.scale))}}function B(e,n,t){if(null==t)return;const o=new Map(e.skeleton.bones.map(e=>[e.name,e]));for(const[e,r]of Object.entries(t.rotationOffsets)){const t=n.bones.find(n=>n.id===e),a=null==t?void 0:o.get(t.name);null!=a&&a.quaternion.multiply((new i).fromArray(r)).normalize()}const r=F(n,n.retargetRootBoneId),a=null==r?void 0:o.get(r);null!=a&&null!=t.rootOffset&&a.position.add((new u).fromArray(t.rootOffset))}function k(e){const n=e.bones.map(()=>new r),t=e.bones.map(()=>new u);for(let o=0;o<e.bones.length;o++){const r=e.bones[o];n[o].compose((new u).fromArray(r.position),(new i).fromArray(r.quaternion),(new u).fromArray(r.scale)),r.parentIndex>=0&&n[o].premultiply(n[r.parentIndex]),t[o].setFromMatrixPosition(n[o])}const o=e.bones.findIndex(n=>n.id===e.pelvisBoneId),a=e.bones.findIndex(n=>n.id===e.chains.find(e=>"neck"===e.role)?.endBoneId),s=e.chains.filter(e=>"leftLeg"===e.role||"rightLeg"===e.role).map(n=>e.bones.findIndex(e=>e.id===n.endBoneId)).filter(e=>e>=0);if(o>=0&&a>=0&&s.length>0){const e=t[o].distanceTo(t[a]),n=Math.max(...s.map(e=>t[o].distanceTo(t[e])));if(e+n>1e-4)return e+n}let l=0;for(let e=0;e<t.length;e++)for(let n=e+1;n<t.length;n++)l=Math.max(l,t[e].distanceTo(t[n]));return Math.max(1e-4,l)}function P(e,n){return e.poses.find(e=>e.id===n)}function F(e,n){return null==n?void 0:e.bones.find(e=>e.id===n)?.name}function S(e,n){const t=[];if(e.traverse(e=>{O(e)&&t.push(e)}),null==n)return t[0];const o=null==n.skinnedMeshName?void 0:t.find(e=>e.name===n.skinnedMeshName);if(null!=o)return o;const r=t.map(e=>({candidate:e,rig:g(e,e.skeleton)}));return r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint&&e.rig.bindPoseFingerprint===n.bindPoseFingerprint)?.candidate??r.find(e=>e.rig.topologyFingerprint===n.topologyFingerprint)?.candidate??t[0]}function $(e,n){let o=0;return e.traverse(e=>{e instanceof t&&n.has(e.name)&&o++}),o}function O(e){return e instanceof l||!0===e.isSkinnedMesh}function q(e,n){return e.find(e=>n.some(n=>W(e.name)===W(n)))??e.find(e=>n.some(n=>W(e.name).includes(W(n))))}function C(e,n,t){const o="left"===n?["left","_l",".l"]:["right","_r",".r"];return e.find(e=>{const n=e.name.toLowerCase(),r=W(n);return o.some(e=>n.includes(e))&&t.some(e=>r.includes(W(e)))})}function W(e){return e.toLowerCase().replace(/^mixamorig[:_]?/,"").replace(/^bip0*1[_:]?/,"").replace(/[^a-z0-9]/g,"")}function N(e){return e.replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^./,e=>e.toUpperCase())}function z(e){return e.map(e=>Math.round(1e5*e)/1e5)}function T(e){const n=JSON.stringify(e);let t=2166136261;for(let e=0;e<n.length;e++)t^=n.charCodeAt(e),t=Math.imul(t,16777619);return(t>>>0).toString(16).padStart(8,"0")}function Q(e,n){return e===`${n}.position`||e===`.bones[${n}].position`||e.endsWith(`[${n}].position`)}const j=new WeakMap;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as s}from"./actors/factory.js";import{World as n}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as r}from"./services/render.js";import{RenderingView as i}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as m}from"./actors/internal/container-map.js";import{InputService as l}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as h}from"../scene/asset-resource-loader.js";import{AssetLoader as u}from"./services/asset-loader.js";import{polyfillClient as f}from"./polyfill.js";import{Subject as g}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{Scene as b}from"three";import{ShaderProvider as j}from"./services/shader-provider.js";import{SceneDataService as S}from"../scene/scene-data-service.js";import{NetMode as y}from"./net/net-session.js";import{AssetsProvider as x}from"../scene/assets-provider.js";export function initiateGame(g,I){if(f(),0!=I.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(r);const E=e.of("default"),R=new HologyRuntime(E),G=new s(E,{inEditor:!1});var P;G.classes=I.actors,e.set(s,G),P=I.element,Object.assign(P.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const D=new i(I.element,{enableXR:!0===I.xr?.enabled,maxPixelRatio:I.rendering?.maxPixelRatio,resolutionScale:I.rendering?.resolutionScale,dynamicResolution:I.rendering?.dynamicResolution,upscaling:I.rendering?.upscaling,msaa:I.rendering?.msaa,fpsCap:I.rendering?.fpsCap,depthPrepass:{enabled:!0===I.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==I?.rendering?.bloom?.enabled},reflection:{enabled:!1!==I?.rendering?.reflection?.enabled},shadows:{cascadeUpdateIntervals:[22,40,60,120]}});D.renderer.shadowMap.enabled=I.rendering?.shadows?.enabled??!0,D.renderer.shadowMap.autoUpdate=I.rendering?.shadows?.autoUpdate??!0,D.renderer.debug.checkShaderErrors=!1,e.set(i,D);const M=new r(D);e.set(r,M);const z=new v,A=new p(z),O=new h;O.setDataDir(I.dataDir),O.initKtx2(D.renderer);const C=Object.entries(I.shaders).map(([e,t])=>({name:e,type:t})),H=Object.entries(I.actors).map(([e,t])=>({name:e,type:t})),N={...d,...I.components??{}},T=Object.entries(N).map(([e,t])=>({name:e,type:t})),U=new j(C);e.set(j,U);const k=new u(O,A,C);e.set(x,A),e.set(h,O),e.set(u,k);const F=new b,W=new o(F,new S,A,O,D,C,H,G,T);W.inEditor=!1,W.netMode=I.multi?.session?.mode??y.none,e.set(o,W);const _=e.get(n);return e.set(n,_),_.materializer=W,(async()=>{const s=e.get(a);if(await s.start(),R.isShutdown)return;if(await z.preloadData(),R.isShutdown)return;if(_.scene=F,null!=I.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=E.get(e);t.session=I.multi.session,t.start(),R.shutdownStarted.subscribe(()=>t.stop())}const{scene:n,actors:o,materializer:r}=await t(D,I.sceneName,I.dataDir,I.shaders,I.actors,N,G,z,A,O,{detailTier:I.detailTier,nodeMode:I.multi?.session?.mode??y.none});_.scene=n,s.scene=_.scene;for(const e of F.children)_.scene.add(e);if(R.isShutdown)return void D.stop();e.import([c]);for(const e of o)_.addActor(e);s.addFromScene(n),await _.startSceneEventGraphs(r),console.log("Start compile shaders"),console.time("compile shaders"),await D.compileAsync(),console.timeEnd("compile shaders"),console.log("Finished compile shaders. Programs: ",D.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),D.initTextures(),console.timeEnd("init scene textures");const i=E.get(l);D.loop(e=>{i.update(e)}),R.status=5,R.shutdownStarted.subscribe(()=>{O.disposeAll()}),m.value=E,E.remove(g),E.set({id:g,type:g});const d=E.get(g);m.value=null,R.gameInstance=d,E.get(w).start(),d instanceof GameInstance&&await d.onStart(),R._resolver(!0)})(),R}export class GameInstance{onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new g,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(n)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(l).stop();const t=this.containerInstance.get(i);t?.stop();const s=this.getWorld();s.stopSceneEventGraphs();const n=this.containerInstance.get(r);n.setMuted(!0),n.dispose();for(const e of[...s.actors])s.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
|
|
1
|
+
import e from"typedi";import{loadScene as t}from"../scene/bootstrap.js";import{ActorFactory as s}from"./actors/factory.js";import{World as n}from"./services/world.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{ViewController as r}from"./services/render.js";import{RenderingView as i}from"../rendering.js";import{PhysicsSystem as a}from"./services/physics/physics-system.js";import{MeshComponent as c}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as d}from"./actors/builtin/components/index.js";import{activeContainerInstance as m}from"./actors/internal/container-map.js";import{InputService as l}from"./input/index.js";import{RuntimeAssetsService as p}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as h}from"../scene/asset-resource-loader.js";import{AssetLoader as u}from"./services/asset-loader.js";import{polyfillClient as f}from"./polyfill.js";import{Subject as g}from"rxjs";import{PointerEvents as w}from"./services/pointer-events.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{Scene as b}from"three";import{ShaderProvider as j}from"./services/shader-provider.js";import{SceneDataService as S}from"../scene/scene-data-service.js";import{NetMode as y}from"./net/net-session.js";import{AssetsProvider as x}from"../scene/assets-provider.js";export function initiateGame(g,I){if(f(),0!=I.element.childNodes.length)return console.error("Can not initialize the game with a non-empty html element"),null;e.has(r);const E=e.of("default"),R=new HologyRuntime(E),G=new s(E,{inEditor:!1});var P;G.classes=I.actors,e.set(s,G),P=I.element,Object.assign(P.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"});const D=new i(I.element,{enableXR:!0===I.xr?.enabled,maxPixelRatio:I.rendering?.maxPixelRatio,resolutionScale:I.rendering?.resolutionScale,dynamicResolution:I.rendering?.dynamicResolution,upscaling:I.rendering?.upscaling,msaa:I.rendering?.msaa,fpsCap:I.rendering?.fpsCap,depthPrepass:{enabled:!0===I.rendering?.depthPrepass?.enabled},bloom:{enabled:!1!==I?.rendering?.bloom?.enabled},reflection:{enabled:!1!==I?.rendering?.reflection?.enabled},shadows:{cascadeUpdateIntervals:[22,40,60,120]}});D.renderer.shadowMap.enabled=I.rendering?.shadows?.enabled??!0,D.renderer.shadowMap.autoUpdate=I.rendering?.shadows?.autoUpdate??!0,D.renderer.debug.checkShaderErrors=!1,e.set(i,D);const M=new r(D);e.set(r,M);const z=new v,A=new p(z),O=new h;O.setDataDir(I.dataDir),O.initKtx2(D.renderer);const C=Object.entries(I.shaders).map(([e,t])=>({name:e,type:t})),H=Object.entries(I.actors).map(([e,t])=>({name:e,type:t})),N={...d,...I.components??{}},T=Object.entries(N).map(([e,t])=>({name:e,type:t})),U=new j(C);e.set(j,U);const k=new u(O,A,C);e.set(x,A),e.set(h,O),e.set(u,k);const F=new b,W=new o(F,new S,A,O,D,C,H,G,T);W.inEditor=!1,W.netMode=I.multi?.session?.mode??y.none,e.set(o,W);const _=e.get(n);return e.set(n,_),_.materializer=W,(async()=>{const s=e.get(a);if(await s.start(),R.isShutdown)return;if(await z.preloadData(),R.isShutdown)return;if(_.scene=F,null!=I.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=E.get(e);t.session=I.multi.session,t.start(),R.shutdownStarted.subscribe(()=>t.stop())}const{scene:n,actors:o,materializer:r}=await t(D,I.sceneName,I.dataDir,I.shaders,I.actors,N,G,z,A,O,{detailTier:I.detailTier,nodeMode:I.multi?.session?.mode??y.none});_.scene=n,s.scene=_.scene;for(const e of F.children)_.scene.add(e);if(R.isShutdown)return void D.stop();e.import([c]);for(const e of o)_.addActor(e);s.addFromScene(n),await _.startSceneEventGraphs(r),console.log("Start compile shaders"),console.time("compile shaders"),await D.compileAsync(),console.timeEnd("compile shaders"),console.log("Finished compile shaders. Programs: ",D.renderer.info.programs?.length??0),console.log("Start init scene textures"),console.time("init scene textures"),D.initTextures(),console.timeEnd("init scene textures");const i=E.get(l);D.loop(e=>{i.update(e)}),R.status=5,R.shutdownStarted.subscribe(()=>{O.disposeAll()}),m.value=E,E.remove(g),E.set({id:g,type:g});const d=E.get(g);m.value=null,R.gameInstance=d,E.get(w).start(),d instanceof GameInstance&&await d.onStart(),R._resolver(!0)})(),R}export class GameInstance{onStart(){}onShutdown(){}}export function createHologyScene(){}export class HologyRuntime{constructor(e){this.containerInstance=e,this.status=0,this.isShutdown=!1,this.shutdownStarted=new g,this.ready=new Promise(e=>{this._resolver=e})}getWorld(){return this.containerInstance.get(n)}getService(e){return this.containerInstance.get(e)}shutdown(){this.isShutdown=!0;const e=this.shutdownStarted;e.next(),e.complete(),this.gameInstance instanceof GameInstance&&this.gameInstance.onShutdown(),this.containerInstance.get(l).stop();const t=this.containerInstance.get(i);t?.stop();const s=this.getWorld();s.stopSceneEventGraphs();const n=this.containerInstance.get(r);n.setMuted(!0),n.dispose();for(const e of[...s.actors])s.removeActor(e);this.containerInstance.get(a).stop(),this.containerInstance.get(o).dispose();const c=this.containerInstance.get(x);c instanceof p&&c.dispose(),this.containerInstance.get(w).stop(),this.containerInstance.reset(),this.shutdownStarted.complete()}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -2,7 +2,7 @@ import * as RAPIER from "@dimforge/rapier3d-simd-compat";
|
|
|
2
2
|
import { Observable, Subject } from "rxjs";
|
|
3
3
|
import * as THREE from "three";
|
|
4
4
|
import { ColorRepresentation, Object3D, Quaternion, Vector3 } from "three";
|
|
5
|
-
import { CollisionShape } from '../../../
|
|
5
|
+
import { CollisionShape } from '../../../scene/collision/collision-shape.js';
|
|
6
6
|
import { AbstractType, Type } from '../../../utils/type.js';
|
|
7
7
|
import { BaseActor } from '../../actors/actor.js';
|
|
8
8
|
import { ViewController } from '../render.js';
|
|
@@ -35,6 +35,11 @@ export declare class RayTestResult {
|
|
|
35
35
|
hitNormal: Vector3;
|
|
36
36
|
}
|
|
37
37
|
export interface RayTestOptions {
|
|
38
|
+
/**
|
|
39
|
+
* Whether to draw the ray while physics debug rendering is enabled.
|
|
40
|
+
* @default true
|
|
41
|
+
*/
|
|
42
|
+
debug?: boolean;
|
|
38
43
|
debugColor?: ColorRepresentation;
|
|
39
44
|
debugLifetime?: number;
|
|
40
45
|
collisionFilter?: InteractionGroups;
|
|
@@ -73,6 +78,26 @@ export declare enum PhysicsBodyType {
|
|
|
73
78
|
kinematic = 4,
|
|
74
79
|
kinematicVelocityBased = 8
|
|
75
80
|
}
|
|
81
|
+
export type PhysicsJointDescriptor = {
|
|
82
|
+
type: 'fixed';
|
|
83
|
+
anchor1: Vector3;
|
|
84
|
+
frame1: Quaternion;
|
|
85
|
+
anchor2: Vector3;
|
|
86
|
+
frame2: Quaternion;
|
|
87
|
+
contactsEnabled?: boolean;
|
|
88
|
+
} | {
|
|
89
|
+
type: 'spherical';
|
|
90
|
+
anchor1: Vector3;
|
|
91
|
+
anchor2: Vector3;
|
|
92
|
+
contactsEnabled?: boolean;
|
|
93
|
+
} | {
|
|
94
|
+
type: 'revolute';
|
|
95
|
+
anchor1: Vector3;
|
|
96
|
+
anchor2: Vector3;
|
|
97
|
+
axis: Vector3;
|
|
98
|
+
limits?: readonly [number, number];
|
|
99
|
+
contactsEnabled?: boolean;
|
|
100
|
+
};
|
|
76
101
|
/**
|
|
77
102
|
* A physics system implementation using the Rapier physics engine.
|
|
78
103
|
* Handles rigid body physics, collisions, and physics-based character movement.
|
|
@@ -89,6 +114,8 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
89
114
|
private eventQueue;
|
|
90
115
|
private fixedupdateSub;
|
|
91
116
|
private collisionSub;
|
|
117
|
+
private rayDebugArrowPool;
|
|
118
|
+
private activeRayDebugArrows;
|
|
92
119
|
private readonly collisionEvents;
|
|
93
120
|
readonly beforeStep: Subject<number>;
|
|
94
121
|
readonly afterStep: Subject<number>;
|
|
@@ -129,7 +156,11 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
129
156
|
*/
|
|
130
157
|
findActorsInRadius<T = BaseActor>(position: Vector3, radius: number, actorType?: Type<T>): T[];
|
|
131
158
|
private debugMesh;
|
|
159
|
+
private staticDebugMesh;
|
|
160
|
+
private staticDebugNeedsUpdate;
|
|
161
|
+
private invalidateStaticDebug;
|
|
132
162
|
private createDebugMesh;
|
|
163
|
+
private updateDebugMesh;
|
|
133
164
|
/**
|
|
134
165
|
* Initializes and starts the physics system.
|
|
135
166
|
* @returns A promise that resolves when the physics system is ready
|
|
@@ -184,6 +215,9 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
184
215
|
* @returns The result of the raycast test
|
|
185
216
|
*/
|
|
186
217
|
rayTest(from: Vector3, to: Vector3, result?: RayTestResult, options?: RayTestOptions): RayTestResult;
|
|
218
|
+
private drawRayDebugArrow;
|
|
219
|
+
private releaseExpiredRayDebugArrows;
|
|
220
|
+
private clearRayDebugArrows;
|
|
187
221
|
/**
|
|
188
222
|
* Sets the gravity vector for the physics world.
|
|
189
223
|
* @param x - Gravity force along X axis
|
|
@@ -274,6 +308,11 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
|
|
|
274
308
|
mass?: number;
|
|
275
309
|
userData?: any;
|
|
276
310
|
}): PhysicsBody;
|
|
311
|
+
/**
|
|
312
|
+
* Creates an impulse joint between two generic physics bodies.
|
|
313
|
+
* Joint anchors, axes, and frames are expressed in the local spaces of the bodies.
|
|
314
|
+
*/
|
|
315
|
+
createJoint(body1: PhysicsBody, body2: PhysicsBody, descriptor: PhysicsJointDescriptor): PhysicsJoint;
|
|
277
316
|
/**
|
|
278
317
|
* Computes the corrected movement vector for a collider using a kinematic character controller.
|
|
279
318
|
* This function uses the provided character controller to calculate the actual movement that can be performed
|
|
@@ -661,6 +700,7 @@ type ColliderCollisionEvent = {
|
|
|
661
700
|
actor: BaseActor;
|
|
662
701
|
};
|
|
663
702
|
export declare class PhysicsCollider {
|
|
703
|
+
private readonly invalidateStaticDebug?;
|
|
664
704
|
readonly disposed: Subject<true>;
|
|
665
705
|
readonly onBeginOverlapActor: Subject<ColliderCollisionEvent>;
|
|
666
706
|
readonly onEndOverlapActor: Subject<ColliderCollisionEvent>;
|
|
@@ -668,7 +708,7 @@ export declare class PhysicsCollider {
|
|
|
668
708
|
/** @internal */
|
|
669
709
|
collider: RAPIER.Collider,
|
|
670
710
|
/** @internal */
|
|
671
|
-
world: RAPIER.World);
|
|
711
|
+
world: RAPIER.World, invalidateStaticDebug?: () => void);
|
|
672
712
|
dispose(): void;
|
|
673
713
|
set mass(mass: number);
|
|
674
714
|
get mass(): number;
|
|
@@ -686,7 +726,8 @@ export declare class PhysicsCollider {
|
|
|
686
726
|
get enabled(): boolean;
|
|
687
727
|
}
|
|
688
728
|
export declare class PhysicsBody {
|
|
689
|
-
|
|
729
|
+
private readonly invalidateStaticDebug?;
|
|
730
|
+
constructor(body: RAPIER.RigidBody, world: RAPIER.World, invalidateStaticDebug?: () => void);
|
|
690
731
|
dispose(): void;
|
|
691
732
|
setEnabled(enabled: boolean): void;
|
|
692
733
|
isEnabled(): boolean;
|
|
@@ -698,6 +739,8 @@ export declare class PhysicsBody {
|
|
|
698
739
|
setLinearVelocity(vel: Vector3): void;
|
|
699
740
|
getAngularVelocity(target: Vector3): Vector3;
|
|
700
741
|
setAngularVelocity(vel: Vector3): void;
|
|
742
|
+
setLinearDamping(damping: number): void;
|
|
743
|
+
setAngularDamping(damping: number): void;
|
|
701
744
|
applyImpulse(impulse: Vector3, wakeUp?: boolean): void;
|
|
702
745
|
applyTorqueImpulse(torque: Vector3, wakeUp?: boolean): void;
|
|
703
746
|
setNextKinematicPosition(pos: Vector3): void;
|
|
@@ -718,4 +761,14 @@ export declare class PhysicsBody {
|
|
|
718
761
|
sleep(): void;
|
|
719
762
|
wakeUp(): void;
|
|
720
763
|
}
|
|
764
|
+
export declare class PhysicsJoint {
|
|
765
|
+
constructor(
|
|
766
|
+
/** @internal */
|
|
767
|
+
joint: RAPIER.ImpulseJoint,
|
|
768
|
+
/** @internal */
|
|
769
|
+
world: RAPIER.World);
|
|
770
|
+
dispose(): void;
|
|
771
|
+
setContactsEnabled(enabled: boolean): void;
|
|
772
|
+
get contactsEnabled(): boolean;
|
|
773
|
+
}
|
|
721
774
|
//# sourceMappingURL=physics-system.d.ts.map
|