@hology/core 0.0.252 → 0.0.253
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/effects/sequence/sequencer.js +1 -1
- package/dist/gameplay/actors/actor.d.ts +9 -0
- package/dist/gameplay/actors/actor.js +1 -1
- package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +2 -0
- package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
- package/dist/gameplay/actors/controller/actor-controller.d.ts +21 -0
- package/dist/gameplay/actors/controller/actor-controller.js +1 -1
- package/dist/gameplay/actors/controller/game-state.d.ts +8 -0
- package/dist/gameplay/actors/controller/game-state.js +4 -0
- package/dist/gameplay/actors/index.d.ts +1 -0
- package/dist/gameplay/actors/index.js +1 -1
- package/dist/gameplay/game-mode.d.ts +34 -0
- package/dist/gameplay/game-mode.js +4 -0
- package/dist/gameplay/index.d.ts +7 -1
- package/dist/gameplay/index.js +1 -1
- package/dist/gameplay/initiate.d.ts +175 -85
- package/dist/gameplay/initiate.js +1 -1
- package/dist/gameplay/net/browser/index.d.ts +4 -1
- package/dist/gameplay/net/browser/index.js +1 -1
- package/dist/gameplay/net/index.d.ts +3 -0
- package/dist/gameplay/net/index.js +1 -1
- package/dist/gameplay/net/net-connection.d.ts +4 -0
- package/dist/gameplay/net/net-session.d.ts +3 -0
- package/dist/gameplay/net/player-session.d.ts +39 -0
- package/dist/gameplay/net/player-session.js +4 -0
- package/dist/gameplay/net/service/net-decorator.js +1 -1
- package/dist/gameplay/net/service/net-serializer.js +1 -1
- package/dist/gameplay/net/service/net-service.d.ts +42 -0
- package/dist/gameplay/net/service/net-service.js +1 -1
- package/dist/gameplay/network-travel-coordinator.d.ts +27 -0
- package/dist/gameplay/network-travel-coordinator.js +4 -0
- package/dist/gameplay/player-lifecycle-coordinator.d.ts +29 -0
- package/dist/gameplay/player-lifecycle-coordinator.js +4 -0
- package/dist/gameplay/rendering-host.d.ts +40 -0
- package/dist/gameplay/rendering-host.js +4 -0
- package/dist/gameplay/services/physics/physics-system.js +1 -1
- package/dist/gameplay/services/render.d.ts +1 -1
- package/dist/gameplay/services/render.js +1 -1
- package/dist/gameplay/services/scene-transition.d.ts +19 -0
- package/dist/gameplay/services/scene-transition.js +4 -0
- package/dist/gameplay/services/world.d.ts +16 -6
- package/dist/gameplay/services/world.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/rendering/graphics-runtime.d.ts +8 -0
- package/dist/rendering/graphics-runtime.js +4 -0
- package/dist/rendering/intersection-observer.d.ts +5 -0
- package/dist/rendering/intersection-observer.js +4 -0
- package/dist/rendering/webgpu-experimental-backend.d.ts +12 -1
- package/dist/rendering/webgpu-experimental-backend.js +1 -1
- package/dist/rendering.d.ts +18 -3
- package/dist/rendering.js +1 -1
- package/dist/scene/bootstrap.d.ts +2 -0
- package/dist/scene/bootstrap.js +1 -1
- package/dist/scene/custom-param-runtime-types.js +1 -1
- package/dist/scene/materializer.d.ts +3 -1
- package/dist/scene/materializer.js +1 -1
- package/dist/scene/model.d.ts +2 -1
- package/dist/scene/model.js +1 -1
- package/dist/scene/objects/prefab.d.ts +3 -0
- package/dist/scene/objects/prefab.js +1 -1
- package/dist/scene/scene-ref.d.ts +18 -0
- package/dist/scene/scene-ref.js +4 -0
- package/dist/shader/parameter.d.ts +2 -1
- package/dist/test/graphics-runtime.test.d.ts +2 -0
- package/dist/test/graphics-runtime.test.js +4 -0
- package/dist/test/intersection-observer.test.d.ts +2 -0
- package/dist/test/intersection-observer.test.js +4 -0
- package/dist/test/net-player-registry.test.d.ts +2 -0
- package/dist/test/net-player-registry.test.js +4 -0
- package/dist/test/net-serializer.test.d.ts +2 -0
- package/dist/test/net-serializer.test.js +4 -0
- package/dist/test/player-controller.test.d.ts +2 -0
- package/dist/test/player-controller.test.js +4 -0
- package/dist/test/rendering-host.test.d.ts +2 -0
- package/dist/test/rendering-host.test.js +4 -0
- package/dist/test/world-lifecycle.test.js +1 -1
- package/dist/test/world-prefab-spawn.test.js +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e}from"tslib";import{delay as t,interval as n,Subject as r,takeUntil as s,tap as o}from"rxjs";import{Euler as i,Vector3 as c}from"three";import{Service as a}from"typedi";import{$actorOptions as l,BaseActor as d,getActorClassById as p}from"../../actors/actor.js";import{ActorComponent as u}from"../../actors/component.js";import{$actorComponents as f}from"../../actors/internal/component-init.js";import{inject as h}from"../../inject.js";import{World as g}from"../../services/world.js";import{NetMode as y}from"../net-session.js";import{NetRole as w}from"./net-actor-role.js";import{DecodeResult as m,NetSerializer as v}from"./net-serializer.js";import{isSignalLike as A}from"./net-utils.js";import{ReplOn as b}from"./replication.js";import{getRpcMethodId as R,getRpcMethodName as _,RunsOn as S}from"./rpc.js";import{ActorController as U,BasePlayerController as M}from"../../actors/controller/actor-controller.js";import{makePropertyReplicated as C}from"./net-decorator.js";var P;!function(e){e[e.rpc=1]="rpc",e[e.prop=2]="prop",e[e.spawn=3]="spawn",e[e.removeActor=4]="removeActor",e[e.rpcComponent=5]="rpcComponent",e[e.propComponent=6]="propComponent",e[e.rpcBinary=21]="rpcBinary",e[e.rpcComponentBinary=25]="rpcComponentBinary",e[e.actorReady=7]="actorReady",e[e.propSnapshot=8]="propSnapshot",e[e.serverTime=100]="serverTime"}(P||(P={}));var $;!function(e){e[e.actor=0]="actor",e[e.component=1]="component"}($||($={}));let L=class{constructor(){this.actorConnection=new Map,this.destroyed=new r,this.world=h(g),this.serializer=h(v),this.serverTimeOffset=0,this.actorPreSpawnMessageBuffer=new Map,this.actorRefMissingMessageQueue=new Map,this.netStartupActorSpawnQueue=new Map,this.spawningActorNetIds=new Set,this.nextNetId=1,this.shouldReplicateMap=new Map,this.replicatedActors=new Map,this.replicatedProperties=new Map,this.replicatedPropertyRegistry=new Map}get mode(){return this.session?.mode??y.none}get isClient(){return this.mode===y.client}get isServer(){return this.mode<y.client}get isDedicatedServer(){return this.mode===y.dedicatedServer}start(){if(this.stop(),this.destroyed=new r,this.isServer)for(const e of this.session.clients)this.sendServerTime(e);n(15).pipe(s(this.destroyed)).subscribe(()=>{this.processMessages()}),this.world.actorAdded.pipe(s(this.destroyed),o(e=>{this.configureMaterializedActorRole(e),this.isServer?this.defineNetId(e):this.processQueuedNetStartupActorSpawns(e)}),t(8)).subscribe(e=>{this.shouldReplicate(e)&&(C(e,"owner",this,!0,b.all),this.sendActorSpawn(e))}),this.world.actorRemoved.pipe(s(this.destroyed),t(10)).subscribe(e=>{this.sendActorRemove(e),this.replicatedActors.delete(e),this.replicatedProperties.delete(e),this.replicatedPropertyRegistry.delete(e),this.actorPreSpawnMessageBuffer.delete(e)}),this.session.playerJoined.pipe(s(this.destroyed)).subscribe(e=>{this.sendServerTime(e),this.isServer&&this.replicatedActors.size>0&&this.spawnOnLateClient(e)})}stop(){this.destroyed.next(null),this.destroyed.complete()}configureMaterializedActorRole(e){null!=e.__netSceneId&&this.mode!==y.none&&(this.shouldReplicate(e)?e.netRole=this.isServer?w.authority:w.simulatedProxy:this.isServer||(e.netRole=w.none))}shouldReplicate(e){const t=this.shouldReplicateMap.get(e);if(null==t){const t=e.constructor[l],n=!0===t?.replicate;return this.shouldReplicateMap.set(e,n),n}return!0===t}setReplicate(e,t){this.shouldReplicateMap.set(e,t)}isRelevant(e,t){const n=this.getRelevancyOptions(e);return!(!0===n?.ownerOnly)||this.resolveActorConnection(e)?.id===t.id}getRelevancyOptions(e){return e.constructor[l].relevancy}spawnOnLateClient(e){const t=[e];for(const e of this.replicatedActors.keys())this.sendActorSpawn(e,t)}async processMessages(){const e=this.session.hasMessage();for(let t=0;t<e;t++){const e=this.session.readMessage();null!=e&&await this.processMessage(e)}}async processMessage(e){try{switch(new DataView(e.buffer).getUint8(0)){case P.rpc:case P.rpcComponent:case P.rpcBinary:case P.rpcComponentBinary:this.processRpc(e.from,e.buffer);break;case P.prop:case P.propComponent:this.processProp(e.from,e.buffer);break;case P.propSnapshot:this.processPropSnapshot(e.from,e.buffer);break;case P.spawn:await this.processSpawn(e.from,e.buffer);break;case P.removeActor:this.processRemoveActor(e.from,e.buffer);break;case P.serverTime:this.processServerTime(e.from,e.buffer);break;case P.actorReady:this.processActorReady(e.from,e.buffer)}}catch(e){console.error("Failed to process message",e)}}processServerTime(e,t){if(this.isServer||this.session.server?.id!==e.id)return;const n=this.parseServerTime(t);this.serverTimeOffset=Date.now()-n}getActorRefMissingMessageQueue(e){let t=this.actorRefMissingMessageQueue.get(e);return null==t&&(t=[],this.actorRefMissingMessageQueue.set(e,t)),t}processRpc(e,t){let n=0;const r=new DataView(t),s=r.getUint8(n);n+=1;const o=r.getUint32(n,!0);n+=4;const i=r.getUint8(n);n+=1;const c=s===P.rpcBinary||s===P.rpcComponentBinary;let a,l,d="";if(c){const e=r.getUint32(n,!0);n+=4,l=new Uint8Array(t,n,e),n+=e}else{const e=r.getUint16(n,!0);n+=2,d=O(t,n,e),n+=e;try{a=this.serializer.decode(d,F)}catch(e){return void console.warn("Failed to parse RPC args JSON",d,e)}}if(!c&&F.error){if(null!=F.missingActorId){const n=this.getActorRefMissingMessageQueue(F.missingActorId);console.debug(`Missing referenced actor ${F.missingActorId}. Queueing message for later`),n.push({from:e,buffer:t})}else console.log("Unknown decode error",d);return}const p=this.world.actors.find(e=>e.__netid===o);if(null==p){return this.getActorRefMissingMessageQueue(o).push({from:e,buffer:t}),void console.debug(`Missing actor ${o}. Queueing message for later`)}let u;if(s===P.rpcComponent||s===P.rpcComponentBinary){const e=r.getUint8(n),t=p[f];if(null!=t&&(u=t.find(t=>t.__netid===e)),null==u)return void console.error(`RPC failed: Failed to find component with netid ${e} on actor with netid ${o}`)}if(this.isServer){if(!this.session.clients.some(t=>t.id==e.id))return void console.warn("Received RCP from non client");const t=this.resolveActorConnection(p);if(null==t)return void console.error("Received server RPC for actor without owner which can't be processed");if(t.id!==e.id)return void console.warn(`Received RPC for actor net id ${p.__netid} from connection ${e.id}, but this connection is not the owner. Can't process.`)}else{if(!(this.session.server?.id===e.id))return void console.warn("Received RCP from non server which is not allowed")}const h=u??p,g=_(h,i);if(null!=g)if("function"==typeof h[g])if(c)h[g](l);else{if(F.requiresAssetLookups)return this.serializer.decodeAssets(a).then(e=>{h[g](...e)}).catch(e=>{console.warn(`Failed to decode asset references for RPC '${g}' on actor net id ${p.__netid}`,e)});h[g](...a)}else console.error(`RPC function '${g}' not found on actor net id ${p.__netid}`+(null!=u?` and component net id ${u.__netid}`:""));else console.error(`RPC method id ${i} not found on actor net id ${p.__netid}`+(null!=u?` and component net id ${u.__netid}`:""))}processProp(e,t){if(this.session.server?.id!==e.id)return void console.warn(`Received property replication from non-server connection (id: ${e.id}), ignoring.`);let n=0;const r=new DataView(t),s=r.getUint8(n);n+=1;const o=r.getUint32(n,!0);n+=4;const i=r.getUint8(n);n+=1;let c="";for(let e=0;e<i;e++)c+=String.fromCharCode(r.getUint8(n+e));n+=i;const a=r.getUint16(n,!0);n+=2;const l=t.slice(n,n+a);n+=a;const d=this.world.actors.find(e=>e.__netid===o);if(!d){return this.getActorRefMissingMessageQueue(o).push({from:e,buffer:t}),void console.error("Failed to process property replication. No actor found with id",o,c)}let p;if(s===P.propComponent){const e=r.getUint8(n),t=d[f];if(null!=t&&(p=t.find(t=>t.__netid===e)),null==p)return void console.error(`Failed to find component with netid ${e} on actor with netid ${o}`)}const u=p??d;try{const n=this.decodeReplicatedValue(l);if(F.error){if(null!=F.missingActorId){let n=this.getActorRefMissingMessageQueue(F.missingActorId);console.debug(`Missing referenced actor ${F.missingActorId}. Queueing message for later`),n.push({from:e,buffer:t})}return}if(F.requiresAssetLookups)return this.serializer.decodeAssets(n).then(e=>{this.applyReplicatedProperty(u,c,e),this.callRepNotify(u,c)}).catch(e=>{console.warn(`Failed to decode asset references for replicated property '${c}' on actor id ${o}`,e)});this.applyReplicatedProperty(u,c,n),this.callRepNotify(u,c)}catch(e){console.warn(`Failed to decode replicated property '${c}' on actor id ${o}`,e)}}processPropSnapshot(e,t){if(this.session.server?.id!==e.id)return void console.warn(`Received property snapshot from non-server connection (id: ${e.id}), ignoring.`);let n=0;const r=new DataView(t);n+=1;const s=r.getUint32(n,!0);n+=4;const o=this.world.actors.find(e=>e.__netid===s);if(null==o){return this.getActorRefMissingMessageQueue(s).push({from:e,buffer:t}),void console.debug(`Missing actor ${s}. Queueing property snapshot for later`)}const i=r.getUint16(n,!0);n+=2;const c=[];for(let a=0;a<i;a++){const i=r.getUint8(n);n+=1;let a=o;if(i===$.component){const e=r.getUint8(n);n+=1;const t=o[f];if(a=t?.find(t=>t.__netid===e),null==a)return void console.error(`Failed to process property snapshot. No component found with netid ${e} on actor with netid ${s}`)}else if(i!==$.actor)return void console.error(`Failed to process property snapshot. Unknown target kind ${i}`);const l=r.getUint8(n);n+=1;let d="";for(let e=0;e<l;e++)d+=String.fromCharCode(r.getUint8(n+e));n+=l;const p=r.getUint32(n,!0);n+=4;const u=t.slice(n,n+p);n+=p;try{const n=this.decodeReplicatedValue(u);if(F.error){if(null!=F.missingActorId){this.getActorRefMissingMessageQueue(F.missingActorId).push({from:e,buffer:t}),console.debug(`Missing referenced actor ${F.missingActorId}. Queueing property snapshot for later`)}else console.warn(`Unknown decode error in property snapshot for actor ${s}`);return}c.push({target:a,property:d,value:n,requiresAssetLookups:F.requiresAssetLookups})}catch(e){return void console.warn(`Failed to decode replicated property snapshot entry '${d}' on actor id ${s}`,e)}}if(c.some(e=>e.requiresAssetLookups))return Promise.all(c.map(async e=>{e.requiresAssetLookups&&(e.value=await this.serializer.decodeAssets(e.value))})).then(()=>{this.applyReplicatedProperties(c)}).catch(e=>{console.warn(`Failed to decode asset references for property snapshot on actor id ${s}`,e)});this.applyReplicatedProperties(c)}applyReplicatedProperties(e){for(const t of e)this.applyReplicatedProperty(t.target,t.property,t.value);for(const t of e)this.callRepNotify(t.target,t.property)}async processSpawn(e,t){if(this.isServer)return;const n=new DataView(t);let r=0;r+=1;const s=n.getUint32(r,!0);r+=4;const o=n.getUint8(r);r+=1;let i="";for(let e=0;e<o;e++)i+=String.fromCharCode(n.getUint8(r+e));r+=o,Q.set(n.getFloat32(r,!0),n.getFloat32(r+4,!0),n.getFloat32(r+8,!0)),r+=12,B.set(n.getFloat32(r,!0),n.getFloat32(r+4,!0),n.getFloat32(r+8,!0)),r+=12;const c=n.getUint8(r);r+=1;const a=n.getUint32(r);r+=4;const l=this.readOptionalSceneId(t,r);console.log("Spawning "+i);const d=p(i);if(!d)return void console.error(`Failed to spawn actor: unknown actor type '${i}'`);const u=this.world.actors.find(e=>e.__netid===s);if(null!=u)return void this.applySpawnNetInfo(u,s,c,a);if(this.spawningActorNetIds.has(s))return void console.log("Actor was already spawned",null!=u);const f=this.findMaterializedNetStartupActor(l,i,s);if(null!=f)return this.applySpawnNetInfo(f,s,c,a),this.processQueuedActorMessages(s),void this.sendActorReady(f);if(null==l){this.spawningActorNetIds.add(s);try{const e=await this.world.spawnActorWithNetInfo(d,s,c,a,Q,B);this.processQueuedActorMessages(s),this.sendActorReady(e)}catch(e){return void console.error("Spawning replicated actor on client failed",e)}finally{this.spawningActorNetIds.delete(s)}}else this.getNetStartupActorSpawnQueue(l).push({from:e,buffer:t})}readOptionalSceneId(e,t){if(t+2>e.byteLength)return;const n=new DataView(e).getUint16(t,!0);return t+=2,0===n||t+n>e.byteLength?void 0:O(e,t,n)}findMaterializedNetStartupActor(e,t,n){if(null!=e)return this.world.actors.find(r=>{if(r.__netSceneId!==e)return!1;if(null!=r.__netid&&r.__netid!==n)return!1;return(r.constructor.__actorId??r.constructor.name)===t})}applySpawnNetInfo(e,t,n,r){if(e.__netid=t,e.netRole=n,0===r)e.owner=void 0;else{const t=this.world.actors.find(e=>e.__netid===r);null!=t&&(e.owner=t)}e instanceof M&&(e.isLocallyControlled=n===w.autonomousProxy)}getNetStartupActorSpawnQueue(e){let t=this.netStartupActorSpawnQueue.get(e);return null==t&&(t=[],this.netStartupActorSpawnQueue.set(e,t)),t}processQueuedNetStartupActorSpawns(e){if(null==e.__netSceneId)return;const t=this.netStartupActorSpawnQueue.get(e.__netSceneId);if(null!=t){this.netStartupActorSpawnQueue.delete(e.__netSceneId);for(const e of t)this.processMessage(e)}}processQueuedActorMessages(e){const t=this.actorRefMissingMessageQueue.get(e);if(null!=t){console.log(`Processing queued messages for actor ${e}`),this.actorRefMissingMessageQueue.delete(e);for(const e of t)this.processMessage(e)}}sendActorReady(e){if(this.mode===y.none)return;if(!e||null==e.__netid)return void console.warn("sendActorReady: actor or actor.__netid is undefined");if(this.isServer)return;const t=new ArrayBuffer(5),n=new DataView(t);let r=0;n.setUint8(r,P.actorReady),r+=1,n.setUint32(r,e.__netid,!0),this.session.server&&this.session.sendMessage(this.session.server,!0,t)}processActorReady(e,t){if(!this.isServer)return;const n=new DataView(t).getUint32(1,!0),r=this.world.actors.find(e=>e.__netid===n);if(!r)return void console.warn(`processActorReady: No actor found with net id ${n}`);const s=this.actorPreSpawnMessageBuffer.get(r),o=this.getConnectionKey(e),i=s?.get(o);if(null!=i){this.sendPropertySnapshot(r,e);const t=i.filter(e=>!this.isPropertyMessage(e.buffer));if(t.length>0){console.log(`Sending ${t.length} queued messages for actor ${r.__netid}`);for(const e of t)this.session.sendMessage(e.connection,e.reliable,e.buffer)}s.delete(o),0===s.size&&this.actorPreSpawnMessageBuffer.delete(r)}}sendRpc(e,t,n,r,s,o){if(this.mode==y.none)return;if(!this.shouldReplicate(n))return;const i=n.__netid;if(null==i)return void console.warn("No __netid defined on actor. Actor must be repliated for RPC");const c=this.resolveActorConnection(n),a=[];if(this.isServer)switch(e){case S.all:a.push(...this.session.clients.filter(e=>this.isRelevant(n,e)));break;case S.client:null!=c&&a.push(c);break;case S.notOwner:a.push(...this.session.clients.filter(e=>e.id!==c?.id&&this.isRelevant(n,e)));case S.server:}else switch(e){case S.all:case S.client:case S.notOwner:break;case S.server:a.push(this.session.server)}if(0==a.length)return;if(null!=o&&null==o.__netid)return void console.warn("No __netid defined on component. Component must be initialized for RPC",o);const l=null!=o,d=o??n,p=R(d,r);if(null==p)return void console.warn(`RPC function '${r}' is not registered on ${d.constructor?.name??"target"}`);const u=1===s.length?function(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if("undefined"!=typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return null}(s[0]):null;if(null!=u){let e=10+u.byteLength;l&&(e+=1);const r=new ArrayBuffer(e),s=new DataView(r);let c=0;s.setUint8(c,l?P.rpcComponentBinary:P.rpcBinary),c+=1,s.setUint32(c,i,!0),c+=4,s.setUint8(c,p),c+=1,s.setUint32(c,u.byteLength,!0),c+=4,D(r,c,u),c+=u.byteLength,l&&(s.setUint8(c,o.__netid),c+=1);for(const e of a)null!=e&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:r});return}const f=this.serializer.encode(s),h=I.encode(f);if(h.byteLength>65535)return void console.warn("RPC arguments are too large to send with the JSON RPC format",r);let g=8+h.byteLength;l&&(g+=1);const w=new ArrayBuffer(g),m=new DataView(w);let v=0;m.setUint8(v,l?P.rpcComponent:P.rpc),v+=1,m.setUint32(v,i,!0),v+=4,m.setUint8(v,p),v+=1,m.setUint16(v,h.byteLength,!0),v+=2,D(w,v,h),v+=h.byteLength,l&&(m.setUint8(v,o.__netid),v+=1);for(const e of a)null!=e&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:w})}sendWithQueue(e,t){if(this.shouldQueueMessageUntilActorReady(e,t.connection)){return void this.getPreSpawnMessageQueue(e,t.connection).push(t)}this.session.sendMessage(t.connection,t.reliable,t.buffer)}findQueuedActorsInData(e,t=[]){if("object"==typeof e){if(Array.isArray(e))for(const t of e)this.findQueuedActorsInData(t);if(e instanceof d){this.actorPreSpawnMessageBuffer.get(e)}}}handlePropertySet(e,t,n,r,s,o){if(this.mode==y.none)return;if(!this.isServer)return;if(!this.shouldReplicate(n))return;let i=this.replicatedProperties.get(n);null==i&&(i={},this.replicatedProperties.set(n,i));const c=this.serializer.encode(s),a=I.encode(c),l=a.buffer.slice(a.byteOffset,a.byteOffset+a.byteLength);i[this.getReplicatedPropertyKey(r,o)]={property:r,replOn:e,reliable:t,buffer:l,component:o},this.sendProperty(e,t,n,r,l,o)}sendProperty(e,t,n,r,s,o){if(!this.isServer)return;const i=[],c=this.resolveActorConnection(n);switch(e){case b.all:i.push(...this.session.clients);break;case b.owner:null!=c&&i.push(c);break;case b.notOwner:null==c?i.push(...this.session.clients):i.push(...this.session.clients.filter(e=>e.id!==c.id))}const a=null!=o&&null!=o.__netid;let l=6+r.length+2+s.byteLength;a&&(l+=1);const d=new ArrayBuffer(l),p=new DataView(d);let u=0;p.setUint8(u,a?P.propComponent:P.prop),u+=1,p.setUint32(u,n.__netid,!0),u+=4,p.setUint8(u,r.length),u+=1;for(let e=0;e<r.length;e++)p.setUint8(u++,r.charCodeAt(e));p.setUint16(u,s.byteLength,!0),u+=2,new Uint8Array(d,u,s.byteLength).set(new Uint8Array(s)),u+=s.byteLength,a&&(p.setUint8(u,o.__netid),u+=1);for(const e of i)null!=e&&this.isRelevant(n,e)&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:d})}defineNetId(e){null==e.__netid&&(e.__netid=this.nextNetId++)}registerReplicatedProperty(e,t,n,r,s,o){if(null==n||null==r||null==s)return;let i=this.replicatedPropertyRegistry.get(n);null==i&&(i=[],this.replicatedPropertyRegistry.set(n,i));const c=o??(s instanceof u?s:void 0),a=i.find(e=>e.target===s&&e.property===r);if(null!=a)return a.replOn=e,a.reliable=t,void(a.component=c);i.push({property:r,replOn:e,reliable:t,target:s,component:c})}sendActorSpawn(e,t=this.session.clients){if(!this.isServer)return;const n=t.filter(t=>this.isRelevant(e,t));this.defineNetId(e);const r=e.__netid;let s=e.constructor.__actorId??e.constructor.name;const o=I.encode(s);let i;null!=e.__netSceneId&&(i=I.encode(e.__netSceneId),i.byteLength>65535&&(console.warn(`Scene actor id is too long to replicate as a startup actor: ${e.__netSceneId}`),i=void 0));const c=i?.byteLength??0,a=6+o.length+12+12+1+4+2+c,l=new ArrayBuffer(a),d=new DataView(l);let p=0;d.setUint8(p,P.spawn),p+=1,d.setUint32(p,r,!0),p+=4,d.setUint8(p,o.length),p+=1,new Uint8Array(l).set(o,p),p+=o.length,d.setFloat32(p,e.position.x,!0),p+=4,d.setFloat32(p,e.position.y,!0),p+=4,d.setFloat32(p,e.position.z,!0),p+=4,d.setFloat32(p,e.rotation.x,!0),p+=4,d.setFloat32(p,e.rotation.y,!0),p+=4,d.setFloat32(p,e.rotation.z,!0),p+=4;let u=p;p+=1,d.setUint32(p,e.owner?.__netid??0),p+=4,d.setUint16(p,c,!0),p+=2,null!=i&&(D(l,p,i),p+=i.byteLength);let f=this.replicatedActors.get(e);null==f&&(f={spawnedAt:Date.now(),connections:[]},this.replicatedActors.set(e,f));for(const t of n){const n=l.slice(0),r=new DataView(n),s=this.resolveActorConnection(e)?.id===t.id?w.autonomousProxy:w.simulatedProxy;r.setUint8(u,s),this.getPreSpawnMessageQueue(e,t),this.session.sendMessage(t,!0,n),f.connections.some(e=>e.id===t.id)||f.connections.push(t)}}sendActorRemove(e){if(!this.isServer)return;const t=new ArrayBuffer(5),n=new DataView(t);let r=0;n.setUint8(r,P.removeActor),r+=1,n.setUint32(r,e.__netid,!0);for(const e of this.session.clients)this.session.sendMessage(e,!0,t)}processRemoveActor(e,t){if(this.isServer||this.session.server?.id!==e.id)return;const n=new DataView(t).getUint32(1,!0),r=this.world.actors.find(e=>e.__netid===n);r&&(this.world.removeActor(r),this.replicatedActors?.delete?.(r),this.replicatedProperties?.delete?.(r))}setOwningConnection(e,t){this.actorConnection.set(e.id,t)}getOwningConnection(e){return this.actorConnection.get(e.id)}getActorsByOwningConnection(e){const t=[];return this.actorConnection.forEach((n,r)=>{if(n.id===e.id){const e=this.world.actors.find(e=>e.id===r);null!=e&&t.push(e)}}),t}resolveActorConnection(e){let t;for(;null==t&&null!=e;)t=this.actorConnection.get(e.id),null==t&&(e=e.owner);return t}isLocallyControlled(e){let t=e;for(;null!=t;){if(t.netRole===w.autonomousProxy)return!0;if(t instanceof U)return t.isLocallyControlled;t=e.owner}return!1}isLocalOwner(e){return this.isLocallyControlled(e)}sendServerTime(e){const t=new ArrayBuffer(9),n=new DataView(t);n.setUint8(0,P.serverTime),n.setBigUint64(1,BigInt(Date.now()),!0),this.session.sendMessage(e,!0,t)}parseServerTime(e){const t=new DataView(e).getBigUint64(1,!0);return Number(t)}getConnectionKey(e){return e.id.toString()}getPreSpawnMessageQueue(e,t){let n=this.actorPreSpawnMessageBuffer.get(e);null==n&&(n=new Map,this.actorPreSpawnMessageBuffer.set(e,n));const r=this.getConnectionKey(t);let s=n.get(r);return null==s&&(s=[],n.set(r,s)),s}shouldQueueMessageUntilActorReady(e,t){const n=this.actorPreSpawnMessageBuffer.get(e);return!!n?.has(this.getConnectionKey(t))||this.isServer&&!this.replicatedActors.has(e)&&this.shouldReplicate(e)}isPropertyMessage(e){const t=new DataView(e).getUint8(0);return t===P.prop||t===P.propComponent}getReplicatedPropertyKey(e,t){return null!=t?.__netid?`component:${t.__netid}:${e}`:`actor:${e}`}sendPropertySnapshot(e,t){const n=this.buildPropertySnapshotEntries(e,t);if(0===n.length)return;const r=this.createPropertySnapshotBuffer(e,n);this.session.sendMessage(t,!0,r)}buildPropertySnapshotEntries(e,t){if(!this.isRelevant(e,t))return[];const n=this.replicatedPropertyRegistry.get(e);if(null==n)return[];const r=[];for(const s of n){if(!this.shouldReplicatePropertyToConnection(e,s.replOn,t))continue;if(null!=s.component&&null==s.component.__netid)continue;const n=this.readReplicatedPropertyValue(s),o=this.serializer.encode(n),i=I.encode(o),c=i.buffer.slice(i.byteOffset,i.byteOffset+i.byteLength);r.push({property:s.property,component:s.component,buffer:c})}return r}shouldReplicatePropertyToConnection(e,t,n){const r=this.resolveActorConnection(e);switch(t){case b.all:return!0;case b.owner:return r?.id===n.id;case b.notOwner:return null==r||r.id!==n.id}}readReplicatedPropertyValue(e){const t=e.target[e.property];return A(t)?t.value:t}createPropertySnapshotBuffer(e,t){let n=7;const r=t.map(e=>I.encode(e.property));for(let e=0;e<t.length;e++){const s=t[e];n+=1,null!=s.component&&(n+=1),n+=1+r[e].byteLength+4+s.buffer.byteLength}const s=new ArrayBuffer(n),o=new DataView(s);let i=0;o.setUint8(i,P.propSnapshot),i+=1,o.setUint32(i,e.__netid,!0),i+=4,o.setUint16(i,t.length,!0),i+=2;for(let e=0;e<t.length;e++){const n=t[e],c=r[e],a=null!=n.component;o.setUint8(i,a?$.component:$.actor),i+=1,a&&(o.setUint8(i,n.component.__netid),i+=1),o.setUint8(i,c.byteLength),i+=1,new Uint8Array(s,i,c.byteLength).set(c),i+=c.byteLength,o.setUint32(i,n.buffer.byteLength,!0),i+=4,new Uint8Array(s,i,n.buffer.byteLength).set(new Uint8Array(n.buffer)),i+=n.buffer.byteLength}return s}decodeReplicatedValue(e){let t;if(null!=N)t=N.decode(e);else{t="";const n=new Uint8Array(e);for(let e=0;e<n.length;e++)t+=String.fromCharCode(n[e])}return this.serializer.decode(t,F)}applyReplicatedProperty(e,t,n){A(e[t])?e[t].value=n:e[t]=n}callRepNotify(e,t){const n=e[`onRep_${t}`];"function"==typeof n&&n.call(e)}};L=e([a()],L);export{L as NetService};const Q=new c,B=new i,I=new TextEncoder,N="undefined"!=typeof TextDecoder?new TextDecoder:void 0;function O(e,t,n){const r=new Uint8Array(e,t,n);if(null!=N)return N.decode(r);let s="";for(let e=0;e<r.length;e++)s+=String.fromCharCode(r[e]);return s}function D(e,t,n){new Uint8Array(e,t,n.byteLength).set(n)}const F=new m;/*
|
|
1
|
+
import{__decorate as e}from"tslib";import{delay as t,interval as n,Subject as s,takeUntil as r,tap as o}from"rxjs";import{Euler as i,Vector3 as a}from"three";import{Service as c}from"typedi";import{$actorOptions as l,BaseActor as d,getActorClassById as p}from"../../actors/actor.js";import{ActorComponent as h}from"../../actors/component.js";import{$actorComponents as u}from"../../actors/internal/component-init.js";import{inject as f}from"../../inject.js";import{World as g}from"../../services/world.js";import{NetMode as y}from"../net-session.js";import{NetPlayerRegistry as w}from"../player-session.js";import{NetRole as m}from"./net-actor-role.js";import{DecodeResult as v,NetSerializer as S}from"./net-serializer.js";import{isSignalLike as A}from"./net-utils.js";import{ReplOn as b}from"./replication.js";import{getRpcMethodId as R,getRpcMethodName as _,RunsOn as C}from"./rpc.js";import{ActorController as M,BasePlayerController as U,BasePlayerState as P}from"../../actors/controller/actor-controller.js";import{BaseGameState as T}from"../../actors/controller/game-state.js";import{makePropertyReplicated as I}from"./net-decorator.js";var B;!function(e){e[e.rpc=1]="rpc",e[e.prop=2]="prop",e[e.spawn=3]="spawn",e[e.removeActor=4]="removeActor",e[e.rpcComponent=5]="rpcComponent",e[e.propComponent=6]="propComponent",e[e.rpcBinary=21]="rpcBinary",e[e.rpcComponentBinary=25]="rpcComponentBinary",e[e.actorReady=7]="actorReady",e[e.propSnapshot=8]="propSnapshot",e[e.serverTime=100]="serverTime",e[e.sceneTravelBegin=101]="sceneTravelBegin",e[e.sceneTravelReady=102]="sceneTravelReady",e[e.sceneTravelComplete=103]="sceneTravelComplete"}(B||(B={}));var $;!function(e){e[e.actor=0]="actor",e[e.component=1]="component"}($||($={}));let L=class{constructor(){this.players=new w,this.suspendedReplicationConnections=new Set,this.sceneTravelBeginSubject=new s,this.sceneTravelReadySubject=new s,this.sceneTravelCompleteSubject=new s,this.sceneTravelBegin$=this.sceneTravelBeginSubject.asObservable(),this.sceneTravelReady$=this.sceneTravelReadySubject.asObservable(),this.sceneTravelComplete$=this.sceneTravelCompleteSubject.asObservable(),this.actorConnection=new Map,this.destroyed=new s,this.world=f(g),this.serializer=f(S),this.serverTimeOffset=0,this.actorPreSpawnMessageBuffer=new Map,this.actorRefMissingMessageQueue=new Map,this.netStartupActorSpawnQueue=new Map,this.spawningActorNetIds=new Set,this.nextNetId=1,this.shouldReplicateMap=new Map,this.replicatedActors=new Map,this.replicatedProperties=new Map,this.replicatedPropertyRegistry=new Map}get pendingSceneTravel(){return this.activeSceneTravel}get gameState(){return this.registeredGameState}setGameState(e){if(null!=this.registeredGameState&&this.registeredGameState!==e)throw new Error(`A game state is already registered as ${this.registeredGameState.constructor.name}`);this.registeredGameState=e}get mode(){return this.session?.mode??y.none}get isClient(){return this.mode===y.client}get isServer(){return this.mode<y.client}get isDedicatedServer(){return this.mode===y.dedicatedServer}start(){if(this.stop(),this.destroyed=new s,this.players.start(this.session),this.isServer)for(const e of this.session.clients)this.sendServerTime(e);n(15).pipe(r(this.destroyed)).subscribe(()=>{this.processMessages()}),this.world.actorAdded.pipe(r(this.destroyed),o(e=>{this.configureMaterializedActorRole(e),this.isServer?this.defineNetId(e):this.processQueuedNetStartupActorSpawns(e),e instanceof U?(I(e,"playerId",this,!0,b.all),I(e,"playerState",this,!0,b.all),I(e,"pawn",this,!0,b.all)):e instanceof P?(I(e,"playerId",this,!0,b.all),I(e,"displayName",this,!0,b.all),I(e,"connected",this,!0,b.all)):e instanceof T&&I(e,"playerStates",this,!0,b.all)}),t(8)).subscribe(e=>{this.shouldReplicate(e)&&(I(e,"owner",this,!0,b.all),this.sendActorSpawn(e))}),this.world.actorRemoved.pipe(r(this.destroyed),t(10)).subscribe(e=>{this.sendActorRemove(e),e===this.registeredGameState&&(this.registeredGameState=void 0),this.actorConnection.delete(e.id),this.replicatedActors.delete(e),this.replicatedProperties.delete(e),this.replicatedPropertyRegistry.delete(e),this.actorPreSpawnMessageBuffer.delete(e)}),this.session.playerJoined.pipe(r(this.destroyed)).subscribe(e=>{null==this.activeSceneTravel?(this.sendServerTime(e),this.isServer&&this.replicatedActors.size>0&&this.spawnOnLateClient(e)):this.suspendAndSendSceneTravel(e,this.activeSceneTravel)})}stop(){this.destroyed.next(null),this.destroyed.complete(),this.players.stop(),this.suspendedReplicationConnections.clear(),this.activeSceneTravel=void 0}configureMaterializedActorRole(e){null!=e.__netSceneId&&this.mode!==y.none&&(this.shouldReplicate(e)?e.netRole=this.isServer?m.authority:m.simulatedProxy:this.isServer||(e.netRole=m.none))}shouldReplicate(e){const t=this.shouldReplicateMap.get(e);if(null==t){const t=e.constructor[l],n=!0===t?.replicate;return this.shouldReplicateMap.set(e,n),n}return!0===t}setReplicate(e,t){this.shouldReplicateMap.set(e,t)}isRelevant(e,t){const n=this.getRelevancyOptions(e);return!(!0===n?.ownerOnly)||this.resolveActorConnection(e)?.id===t.id}getRelevancyOptions(e){return e.constructor[l].relevancy}spawnOnLateClient(e){const t=[e];for(const e of this.replicatedActors.keys())this.sendActorSpawn(e,t)}async processMessages(){const e=this.session.hasMessage();for(let t=0;t<e;t++){const e=this.session.readMessage();null!=e&&await this.processMessage(e)}}async processMessage(e){try{switch(new DataView(e.buffer).getUint8(0)){case B.rpc:case B.rpcComponent:case B.rpcBinary:case B.rpcComponentBinary:this.processRpc(e.from,e.buffer);break;case B.prop:case B.propComponent:this.processProp(e.from,e.buffer);break;case B.propSnapshot:this.processPropSnapshot(e.from,e.buffer);break;case B.spawn:await this.processSpawn(e.from,e.buffer);break;case B.removeActor:this.processRemoveActor(e.from,e.buffer);break;case B.serverTime:this.processServerTime(e.from,e.buffer);break;case B.actorReady:this.processActorReady(e.from,e.buffer);break;case B.sceneTravelBegin:this.processSceneTravelBegin(e.from,e.buffer);break;case B.sceneTravelReady:this.processSceneTravelReady(e.from,e.buffer);break;case B.sceneTravelComplete:this.processSceneTravelComplete(e.from,e.buffer)}}catch(e){console.error("Failed to process message",e)}}processServerTime(e,t){if(this.isServer||this.session.server?.id!==e.id)return;const n=this.parseServerTime(t);this.serverTimeOffset=Date.now()-n}getActorRefMissingMessageQueue(e){let t=this.actorRefMissingMessageQueue.get(e);return null==t&&(t=[],this.actorRefMissingMessageQueue.set(e,t)),t}processRpc(e,t){let n=0;const s=new DataView(t),r=s.getUint8(n);n+=1;const o=s.getUint32(n,!0);n+=4;const i=s.getUint8(n);n+=1;const a=r===B.rpcBinary||r===B.rpcComponentBinary;let c,l,d="";if(a){const e=s.getUint32(n,!0);n+=4,l=new Uint8Array(t,n,e),n+=e}else{const e=s.getUint16(n,!0);n+=2,d=j(t,n,e),n+=e;try{c=this.serializer.decode(d,V)}catch(e){return void console.warn("Failed to parse RPC args JSON",d,e)}}if(!a&&V.error){if(null!=V.missingActorId){const n=this.getActorRefMissingMessageQueue(V.missingActorId);console.debug(`Missing referenced actor ${V.missingActorId}. Queueing message for later`),n.push({from:e,buffer:t})}else console.log("Unknown decode error",d);return}const p=this.world.actors.find(e=>e.__netid===o);if(null==p){return this.getActorRefMissingMessageQueue(o).push({from:e,buffer:t}),void console.debug(`Missing actor ${o}. Queueing message for later`)}let h;if(r===B.rpcComponent||r===B.rpcComponentBinary){const e=s.getUint8(n),t=p[u];if(null!=t&&(h=t.find(t=>t.__netid===e)),null==h)return void console.error(`RPC failed: Failed to find component with netid ${e} on actor with netid ${o}`)}if(this.isServer){if(!this.session.clients.some(t=>t.id==e.id))return void console.warn("Received RCP from non client");const t=this.resolveActorConnection(p);if(null==t)return void console.error("Received server RPC for actor without owner which can't be processed");if(t.id!==e.id)return void console.warn(`Received RPC for actor net id ${p.__netid} from connection ${e.id}, but this connection is not the owner. Can't process.`)}else{if(!(this.session.server?.id===e.id))return void console.warn("Received RCP from non server which is not allowed")}const f=h??p,g=_(f,i);if(null!=g)if("function"==typeof f[g])if(a)f[g](l);else{if(V.requiresAssetLookups)return this.serializer.decodeAssets(c).then(e=>{f[g](...e)}).catch(e=>{console.warn(`Failed to decode asset references for RPC '${g}' on actor net id ${p.__netid}`,e)});f[g](...c)}else console.error(`RPC function '${g}' not found on actor net id ${p.__netid}`+(null!=h?` and component net id ${h.__netid}`:""));else console.error(`RPC method id ${i} not found on actor net id ${p.__netid}`+(null!=h?` and component net id ${h.__netid}`:""))}processProp(e,t){if(this.session.server?.id!==e.id)return void console.warn(`Received property replication from non-server connection (id: ${e.id}), ignoring.`);let n=0;const s=new DataView(t),r=s.getUint8(n);n+=1;const o=s.getUint32(n,!0);n+=4;const i=s.getUint8(n);n+=1;let a="";for(let e=0;e<i;e++)a+=String.fromCharCode(s.getUint8(n+e));n+=i;const c=s.getUint16(n,!0);n+=2;const l=t.slice(n,n+c);n+=c;const d=this.world.actors.find(e=>e.__netid===o);if(!d){return this.getActorRefMissingMessageQueue(o).push({from:e,buffer:t}),void console.error("Failed to process property replication. No actor found with id",o,a)}let p;if(r===B.propComponent){const e=s.getUint8(n),t=d[u];if(null!=t&&(p=t.find(t=>t.__netid===e)),null==p)return void console.error(`Failed to find component with netid ${e} on actor with netid ${o}`)}const h=p??d;try{const n=this.decodeReplicatedValue(l);if(V.error){if(null!=V.missingActorId){let n=this.getActorRefMissingMessageQueue(V.missingActorId);console.debug(`Missing referenced actor ${V.missingActorId}. Queueing message for later`),n.push({from:e,buffer:t})}return}if(V.requiresAssetLookups)return this.serializer.decodeAssets(n).then(e=>{this.applyReplicatedProperty(h,a,e),this.callRepNotify(h,a)}).catch(e=>{console.warn(`Failed to decode asset references for replicated property '${a}' on actor id ${o}`,e)});this.applyReplicatedProperty(h,a,n),this.callRepNotify(h,a)}catch(e){console.warn(`Failed to decode replicated property '${a}' on actor id ${o}`,e)}}processPropSnapshot(e,t){if(this.session.server?.id!==e.id)return void console.warn(`Received property snapshot from non-server connection (id: ${e.id}), ignoring.`);let n=0;const s=new DataView(t);n+=1;const r=s.getUint32(n,!0);n+=4;const o=this.world.actors.find(e=>e.__netid===r);if(null==o){return this.getActorRefMissingMessageQueue(r).push({from:e,buffer:t}),void console.debug(`Missing actor ${r}. Queueing property snapshot for later`)}const i=s.getUint16(n,!0);n+=2;const a=[];for(let c=0;c<i;c++){const i=s.getUint8(n);n+=1;let c=o;if(i===$.component){const e=s.getUint8(n);n+=1;const t=o[u];if(c=t?.find(t=>t.__netid===e),null==c)return void console.error(`Failed to process property snapshot. No component found with netid ${e} on actor with netid ${r}`)}else if(i!==$.actor)return void console.error(`Failed to process property snapshot. Unknown target kind ${i}`);const l=s.getUint8(n);n+=1;let d="";for(let e=0;e<l;e++)d+=String.fromCharCode(s.getUint8(n+e));n+=l;const p=s.getUint32(n,!0);n+=4;const h=t.slice(n,n+p);n+=p;try{const n=this.decodeReplicatedValue(h);if(V.error){if(null!=V.missingActorId){this.getActorRefMissingMessageQueue(V.missingActorId).push({from:e,buffer:t}),console.debug(`Missing referenced actor ${V.missingActorId}. Queueing property snapshot for later`)}else console.warn(`Unknown decode error in property snapshot for actor ${r}`);return}a.push({target:c,property:d,value:n,requiresAssetLookups:V.requiresAssetLookups})}catch(e){return void console.warn(`Failed to decode replicated property snapshot entry '${d}' on actor id ${r}`,e)}}if(a.some(e=>e.requiresAssetLookups))return Promise.all(a.map(async e=>{e.requiresAssetLookups&&(e.value=await this.serializer.decodeAssets(e.value))})).then(()=>{this.applyReplicatedProperties(a)}).catch(e=>{console.warn(`Failed to decode asset references for property snapshot on actor id ${r}`,e)});this.applyReplicatedProperties(a)}applyReplicatedProperties(e){for(const t of e)this.applyReplicatedProperty(t.target,t.property,t.value);for(const t of e)this.callRepNotify(t.target,t.property)}async processSpawn(e,t){if(this.isServer)return;const n=new DataView(t);let s=0;s+=1;const r=n.getUint32(s,!0);s+=4;const o=n.getUint8(s);s+=1;let i="";for(let e=0;e<o;e++)i+=String.fromCharCode(n.getUint8(s+e));s+=o,Q.set(n.getFloat32(s,!0),n.getFloat32(s+4,!0),n.getFloat32(s+8,!0)),s+=12,O.set(n.getFloat32(s,!0),n.getFloat32(s+4,!0),n.getFloat32(s+8,!0)),s+=12;const a=n.getUint8(s);s+=1;const c=n.getUint32(s);s+=4;const l=this.readOptionalSceneId(t,s);console.log("Spawning "+i);const d=p(i);if(!d)return void console.error(`Failed to spawn actor: unknown actor type '${i}'`);const h=this.world.actors.find(e=>e.__netid===r);if(null!=h)return this.applySpawnNetInfo(h,r,a,c),h instanceof T&&this.setGameState(h),this.processQueuedActorMessages(r),void this.sendActorReady(h);if(this.spawningActorNetIds.has(r))return void console.log("Actor was already spawned",null!=h);const u=this.findMaterializedNetStartupActor(l,i,r);if(null!=u)return this.applySpawnNetInfo(u,r,a,c),u instanceof T&&this.setGameState(u),this.processQueuedActorMessages(r),void this.sendActorReady(u);if(null==l){this.spawningActorNetIds.add(r);try{const e=await this.world.spawnActorWithNetInfo(d,r,a,c,Q,O);e instanceof T&&this.setGameState(e),this.processQueuedActorMessages(r),this.sendActorReady(e)}catch(e){return void console.error("Spawning replicated actor on client failed",e)}finally{this.spawningActorNetIds.delete(r)}}else this.getNetStartupActorSpawnQueue(l).push({from:e,buffer:t})}readOptionalSceneId(e,t){if(t+2>e.byteLength)return;const n=new DataView(e).getUint16(t,!0);return t+=2,0===n||t+n>e.byteLength?void 0:j(e,t,n)}findMaterializedNetStartupActor(e,t,n){if(null!=e)return this.world.actors.find(s=>{if(s.__netSceneId!==e)return!1;if(null!=s.__netid&&s.__netid!==n)return!1;return(s.constructor.__actorId??s.constructor.name)===t})}applySpawnNetInfo(e,t,n,s){if(e.__netid=t,e.netRole=n,0===s)e.owner=void 0;else{const t=this.world.actors.find(e=>e.__netid===s);null!=t&&(e.owner=t)}e instanceof U&&e.setLocallyControlled(n===m.autonomousProxy)}getNetStartupActorSpawnQueue(e){let t=this.netStartupActorSpawnQueue.get(e);return null==t&&(t=[],this.netStartupActorSpawnQueue.set(e,t)),t}processQueuedNetStartupActorSpawns(e){if(null==e.__netSceneId)return;const t=this.netStartupActorSpawnQueue.get(e.__netSceneId);if(null!=t){this.netStartupActorSpawnQueue.delete(e.__netSceneId);for(const e of t)this.processMessage(e)}}processQueuedActorMessages(e){const t=this.actorRefMissingMessageQueue.get(e);if(null!=t){console.log(`Processing queued messages for actor ${e}`),this.actorRefMissingMessageQueue.delete(e);for(const e of t)this.processMessage(e)}}sendActorReady(e){if(this.mode===y.none)return;if(!e||null==e.__netid)return void console.warn("sendActorReady: actor or actor.__netid is undefined");if(this.isServer)return;const t=new ArrayBuffer(5),n=new DataView(t);let s=0;n.setUint8(s,B.actorReady),s+=1,n.setUint32(s,e.__netid,!0),this.session.server&&this.session.sendMessage(this.session.server,!0,t)}processActorReady(e,t){if(!this.isServer)return;const n=new DataView(t).getUint32(1,!0),s=this.world.actors.find(e=>e.__netid===n);if(!s)return void console.warn(`processActorReady: No actor found with net id ${n}`);const r=this.actorPreSpawnMessageBuffer.get(s),o=this.getConnectionKey(e),i=r?.get(o);if(null!=i){this.sendPropertySnapshot(s,e);const t=i.filter(e=>!this.isPropertyMessage(e.buffer));if(t.length>0){console.log(`Sending ${t.length} queued messages for actor ${s.__netid}`);for(const e of t)this.sendMessage(e.connection,e.reliable,e.buffer)}r.delete(o),0===r.size&&this.actorPreSpawnMessageBuffer.delete(s)}}sendRpc(e,t,n,s,r,o){if(this.mode==y.none)return;if(!this.shouldReplicate(n))return;const i=n.__netid;if(null==i)return void console.warn("No __netid defined on actor. Actor must be repliated for RPC");const a=this.resolveActorConnection(n),c=[];if(this.isServer)switch(e){case C.all:c.push(...this.session.clients.filter(e=>this.isRelevant(n,e)));break;case C.client:null!=a&&c.push(a);break;case C.notOwner:c.push(...this.session.clients.filter(e=>e.id!==a?.id&&this.isRelevant(n,e)));case C.server:}else switch(e){case C.all:case C.client:case C.notOwner:break;case C.server:c.push(this.session.server)}if(0==c.length)return;if(null!=o&&null==o.__netid)return void console.warn("No __netid defined on component. Component must be initialized for RPC",o);const l=null!=o,d=o??n,p=R(d,s);if(null==p)return void console.warn(`RPC function '${s}' is not registered on ${d.constructor?.name??"target"}`);const h=1===r.length?function(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if("undefined"!=typeof SharedArrayBuffer&&e instanceof SharedArrayBuffer)return new Uint8Array(e);if(ArrayBuffer.isView(e))return new Uint8Array(e.buffer,e.byteOffset,e.byteLength);return null}(r[0]):null;if(null!=h){let e=10+h.byteLength;l&&(e+=1);const s=new ArrayBuffer(e),r=new DataView(s);let a=0;r.setUint8(a,l?B.rpcComponentBinary:B.rpcBinary),a+=1,r.setUint32(a,i,!0),a+=4,r.setUint8(a,p),a+=1,r.setUint32(a,h.byteLength,!0),a+=4,k(s,a,h),a+=h.byteLength,l&&(r.setUint8(a,o.__netid),a+=1);for(const e of c)null!=e&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:s});return}const u=this.serializer.encode(r),f=N.encode(u);if(f.byteLength>65535)return void console.warn("RPC arguments are too large to send with the JSON RPC format",s);let g=8+f.byteLength;l&&(g+=1);const w=new ArrayBuffer(g),m=new DataView(w);let v=0;m.setUint8(v,l?B.rpcComponent:B.rpc),v+=1,m.setUint32(v,i,!0),v+=4,m.setUint8(v,p),v+=1,m.setUint16(v,f.byteLength,!0),v+=2,k(w,v,f),v+=f.byteLength,l&&(m.setUint8(v,o.__netid),v+=1);for(const e of c)null!=e&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:w})}sendWithQueue(e,t){if(this.shouldQueueMessageUntilActorReady(e,t.connection)){return void this.getPreSpawnMessageQueue(e,t.connection).push(t)}this.sendMessage(t.connection,t.reliable,t.buffer)}findQueuedActorsInData(e,t=[]){if("object"==typeof e){if(Array.isArray(e))for(const t of e)this.findQueuedActorsInData(t);if(e instanceof d){this.actorPreSpawnMessageBuffer.get(e)}}}handlePropertySet(e,t,n,s,r,o){if(this.mode==y.none)return;if(!this.isServer)return;if(!this.shouldReplicate(n))return;let i=this.replicatedProperties.get(n);null==i&&(i={},this.replicatedProperties.set(n,i));const a=this.serializer.encode(r),c=N.encode(a),l=c.buffer.slice(c.byteOffset,c.byteOffset+c.byteLength);i[this.getReplicatedPropertyKey(s,o)]={property:s,replOn:e,reliable:t,buffer:l,component:o},this.sendProperty(e,t,n,s,l,o)}sendProperty(e,t,n,s,r,o){if(!this.isServer)return;const i=[],a=this.resolveActorConnection(n);switch(e){case b.all:i.push(...this.session.clients);break;case b.owner:null!=a&&i.push(a);break;case b.notOwner:null==a?i.push(...this.session.clients):i.push(...this.session.clients.filter(e=>e.id!==a.id))}const c=null!=o&&null!=o.__netid;let l=6+s.length+2+r.byteLength;c&&(l+=1);const d=new ArrayBuffer(l),p=new DataView(d);let h=0;p.setUint8(h,c?B.propComponent:B.prop),h+=1,p.setUint32(h,n.__netid,!0),h+=4,p.setUint8(h,s.length),h+=1;for(let e=0;e<s.length;e++)p.setUint8(h++,s.charCodeAt(e));p.setUint16(h,r.byteLength,!0),h+=2,new Uint8Array(d,h,r.byteLength).set(new Uint8Array(r)),h+=r.byteLength,c&&(p.setUint8(h,o.__netid),h+=1);for(const e of i)null!=e&&this.isRelevant(n,e)&&this.sendWithQueue(n,{connection:e,reliable:t,buffer:d})}defineNetId(e){null==e.__netid&&(e.__netid=this.nextNetId++)}registerReplicatedProperty(e,t,n,s,r,o){if(null==n||null==s||null==r)return;let i=this.replicatedPropertyRegistry.get(n);null==i&&(i=[],this.replicatedPropertyRegistry.set(n,i));const a=o??(r instanceof h?r:void 0),c=i.find(e=>e.target===r&&e.property===s);if(null!=c)return c.replOn=e,c.reliable=t,void(c.component=a);i.push({property:s,replOn:e,reliable:t,target:r,component:a})}sendActorSpawn(e,t=this.session.clients){if(!this.isServer)return;const n=this.replicatedActors.get(e),s=t.filter(t=>!!this.isRelevant(e,t)&&!n?.connections.some(e=>e.id===t.id));if(0===s.length)return;this.defineNetId(e);const r=e.__netid;let o=e.constructor.__actorId??e.constructor.name;const i=N.encode(o);let a;null!=e.__netSceneId&&(a=N.encode(e.__netSceneId),a.byteLength>65535&&(console.warn(`Scene actor id is too long to replicate as a startup actor: ${e.__netSceneId}`),a=void 0));const c=a?.byteLength??0,l=6+i.length+12+12+1+4+2+c,d=new ArrayBuffer(l),p=new DataView(d);let h=0;p.setUint8(h,B.spawn),h+=1,p.setUint32(h,r,!0),h+=4,p.setUint8(h,i.length),h+=1,new Uint8Array(d).set(i,h),h+=i.length,p.setFloat32(h,e.position.x,!0),h+=4,p.setFloat32(h,e.position.y,!0),h+=4,p.setFloat32(h,e.position.z,!0),h+=4,p.setFloat32(h,e.rotation.x,!0),h+=4,p.setFloat32(h,e.rotation.y,!0),h+=4,p.setFloat32(h,e.rotation.z,!0),h+=4;let u=h;h+=1,p.setUint32(h,e.owner?.__netid??0),h+=4,p.setUint16(h,c,!0),h+=2,null!=a&&(k(d,h,a),h+=a.byteLength);let f=this.replicatedActors.get(e);null==f&&(f={spawnedAt:Date.now(),connections:[]},this.replicatedActors.set(e,f));for(const t of s){const n=d.slice(0),s=new DataView(n),r=this.resolveActorConnection(e)?.id===t.id?m.autonomousProxy:m.simulatedProxy;s.setUint8(u,r),this.getPreSpawnMessageQueue(e,t),this.sendMessage(t,!0,n),f.connections.some(e=>e.id===t.id)||f.connections.push(t)}}sendActorRemove(e){if(!this.isServer)return;const t=new ArrayBuffer(5),n=new DataView(t);let s=0;n.setUint8(s,B.removeActor),s+=1,n.setUint32(s,e.__netid,!0);for(const e of this.session.clients)this.sendMessage(e,!0,t)}processRemoveActor(e,t){if(this.isServer||this.session.server?.id!==e.id)return;const n=new DataView(t).getUint32(1,!0),s=this.world.actors.find(e=>e.__netid===n);s&&(this.world.removeActor(s),this.replicatedActors?.delete?.(s),this.replicatedProperties?.delete?.(s))}setOwningConnection(e,t){this.actorConnection.set(e.id,t),this.isServer&&this.world.actors.includes(e)&&this.shouldReplicate(e)&&!0===this.getRelevancyOptions(e)?.ownerOnly&&this.sendActorSpawn(e,[t])}clearOwningConnection(e){this.actorConnection.delete(e.id)}getOwningConnection(e){return this.actorConnection.get(e.id)}getActorsByOwningConnection(e){const t=[];return this.actorConnection.forEach((n,s)=>{if(n.id===e.id){const e=this.world.actors.find(e=>e.id===s);null!=e&&t.push(e)}}),t}resolveActorConnection(e){let t;for(;null==t&&null!=e;)t=this.actorConnection.get(e.id),null==t&&(e=e.owner);return t}isLocallyControlled(e){let t=e;for(;null!=t;){if(t.netRole===m.autonomousProxy)return!0;if(t instanceof M)return t.isLocallyControlled;t=t.owner}return!1}isLocalOwner(e){return this.isLocallyControlled(e)}beginSceneTravel(e,t){if(!this.isServer)throw new Error("Only authority can begin scene travel");const n={travelId:e,sceneName:t};this.activeSceneTravel=n;for(const e of this.session.clients)this.suspendAndSendSceneTravel(e,n)}sendSceneTravelReady(e,t){if(!this.isClient||null==this.session.server)return;const n=this.createSceneTravelMessage(B.sceneTravelReady,{travelId:e,sceneName:t});this.session.sendMessage(this.session.server,!0,n)}completeSceneTravel(e,t){if(!this.isServer)throw new Error("Only authority can complete scene travel");const n=this.createSceneTravelMessage(B.sceneTravelComplete,{travelId:e,sceneName:t});for(const e of this.session.clients)this.resetReplicationState(e),this.suspendedReplicationConnections.delete(this.getConnectionKey(e)),this.spawnOnLateClient(e),this.session.sendMessage(e,!0,n);this.activeSceneTravel=void 0}suspendAndSendSceneTravel(e,t){this.suspendedReplicationConnections.add(this.getConnectionKey(e));const n=this.createSceneTravelMessage(B.sceneTravelBegin,t);this.session.sendMessage(e,!0,n)}processSceneTravelBegin(e,t){if(!this.isClient||this.session.server?.id!==e.id)return;const n=this.parseSceneTravelMessage(t);this.activeSceneTravel=n,this.sceneTravelBeginSubject.next(n)}processSceneTravelReady(e,t){if(!this.isServer||!this.session.clients.some(t=>t.id===e.id))return;const n=this.parseSceneTravelMessage(t);this.sceneTravelReadySubject.next({travelId:n.travelId,connection:e})}processSceneTravelComplete(e,t){if(!this.isClient||this.session.server?.id!==e.id)return;const n=this.parseSceneTravelMessage(t);this.activeSceneTravel=void 0,this.sceneTravelCompleteSubject.next(n)}createSceneTravelMessage(e,t){const n=N.encode(JSON.stringify(t)),s=new ArrayBuffer(1+n.byteLength);return new DataView(s).setUint8(0,e),k(s,1,n),s}parseSceneTravelMessage(e){const t=e.slice(1),n=null!=D?D.decode(t):String.fromCharCode(...new Uint8Array(t));return JSON.parse(n)}sendMessage(e,t,n){this.isServer&&this.suspendedReplicationConnections.has(this.getConnectionKey(e))||this.session.sendMessage(e,t,n)}sendServerTime(e){const t=new ArrayBuffer(9),n=new DataView(t);n.setUint8(0,B.serverTime),n.setBigUint64(1,BigInt(Date.now()),!0),this.sendMessage(e,!0,t)}parseServerTime(e){const t=new DataView(e).getBigUint64(1,!0);return Number(t)}getConnectionKey(e){return e.id.toString()}resetReplicationState(e){const t=this.getConnectionKey(e);for(const[n,s]of this.replicatedActors){for(let t=s.connections.length-1;t>=0;t--)s.connections[t].id===e.id&&s.connections.splice(t,1);const r=this.actorPreSpawnMessageBuffer.get(n);r?.delete(t),0===r?.size&&this.actorPreSpawnMessageBuffer.delete(n)}}getPreSpawnMessageQueue(e,t){let n=this.actorPreSpawnMessageBuffer.get(e);null==n&&(n=new Map,this.actorPreSpawnMessageBuffer.set(e,n));const s=this.getConnectionKey(t);let r=n.get(s);return null==r&&(r=[],n.set(s,r)),r}shouldQueueMessageUntilActorReady(e,t){const n=this.actorPreSpawnMessageBuffer.get(e);return!!n?.has(this.getConnectionKey(t))||this.isServer&&!this.replicatedActors.has(e)&&this.shouldReplicate(e)}isPropertyMessage(e){const t=new DataView(e).getUint8(0);return t===B.prop||t===B.propComponent}getReplicatedPropertyKey(e,t){return null!=t?.__netid?`component:${t.__netid}:${e}`:`actor:${e}`}sendPropertySnapshot(e,t){const n=this.buildPropertySnapshotEntries(e,t);if(0===n.length)return;const s=this.createPropertySnapshotBuffer(e,n);this.sendMessage(t,!0,s)}buildPropertySnapshotEntries(e,t){if(!this.isRelevant(e,t))return[];const n=this.replicatedPropertyRegistry.get(e);if(null==n)return[];const s=[];for(const r of n){if(!this.shouldReplicatePropertyToConnection(e,r.replOn,t))continue;if(null!=r.component&&null==r.component.__netid)continue;const n=this.readReplicatedPropertyValue(r),o=this.serializer.encode(n),i=N.encode(o),a=i.buffer.slice(i.byteOffset,i.byteOffset+i.byteLength);s.push({property:r.property,component:r.component,buffer:a})}return s}shouldReplicatePropertyToConnection(e,t,n){const s=this.resolveActorConnection(e);switch(t){case b.all:return!0;case b.owner:return s?.id===n.id;case b.notOwner:return null==s||s.id!==n.id}}readReplicatedPropertyValue(e){const t=e.target[e.property];return A(t)?t.value:t}createPropertySnapshotBuffer(e,t){let n=7;const s=t.map(e=>N.encode(e.property));for(let e=0;e<t.length;e++){const r=t[e];n+=1,null!=r.component&&(n+=1),n+=1+s[e].byteLength+4+r.buffer.byteLength}const r=new ArrayBuffer(n),o=new DataView(r);let i=0;o.setUint8(i,B.propSnapshot),i+=1,o.setUint32(i,e.__netid,!0),i+=4,o.setUint16(i,t.length,!0),i+=2;for(let e=0;e<t.length;e++){const n=t[e],a=s[e],c=null!=n.component;o.setUint8(i,c?$.component:$.actor),i+=1,c&&(o.setUint8(i,n.component.__netid),i+=1),o.setUint8(i,a.byteLength),i+=1,new Uint8Array(r,i,a.byteLength).set(a),i+=a.byteLength,o.setUint32(i,n.buffer.byteLength,!0),i+=4,new Uint8Array(r,i,n.buffer.byteLength).set(new Uint8Array(n.buffer)),i+=n.buffer.byteLength}return r}decodeReplicatedValue(e){let t;if(null!=D)t=D.decode(e);else{t="";const n=new Uint8Array(e);for(let e=0;e<n.length;e++)t+=String.fromCharCode(n[e])}return this.serializer.decode(t,V)}applyReplicatedProperty(e,t,n){A(e[t])?e[t].value=n:e[t]=n,this.synchronizeReplicatedPlayerActor(e)}synchronizeReplicatedPlayerActor(e){if(e instanceof U&&null!=e.playerId){const t=this.players.get(e.playerId);if(null==t)return;return this.players.attachController(e.playerId,e),void e.setLocallyControlled(null!=t.localPlayerIndex)}if(e instanceof P&&null!=e.playerId){null!=this.players.get(e.playerId)&&this.players.attachPlayerState(e.playerId,e)}}callRepNotify(e,t){const n=e[`onRep_${t}`];"function"==typeof n&&n.call(e)}};L=e([c()],L);export{L as NetService};const Q=new a,O=new i,N=new TextEncoder,D="undefined"!=typeof TextDecoder?new TextDecoder:void 0;function j(e,t,n){const s=new Uint8Array(e,t,n);if(null!=D)return D.decode(s);let r="";for(let e=0;e<s.length;e++)r+=String.fromCharCode(s[e]);return r}function k(e,t,n){new Uint8Array(e,t,n.byteLength).set(n)}const V=new v;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { GameMode } from './game-mode.js';
|
|
2
|
+
/** Coordinates server-authoritative, full-session scene travel. */
|
|
3
|
+
export declare class NetworkTravelCoordinator {
|
|
4
|
+
private readonly net;
|
|
5
|
+
private readonly scenes;
|
|
6
|
+
private readonly world;
|
|
7
|
+
private readonly subscriptions;
|
|
8
|
+
private gameMode?;
|
|
9
|
+
private pending?;
|
|
10
|
+
private clientTravel?;
|
|
11
|
+
/** Starts listening for travel protocol messages on authority and clients. */
|
|
12
|
+
start(gameMode: GameMode): void;
|
|
13
|
+
/** Stops protocol handling. It does not cancel an in-progress local scene load. */
|
|
14
|
+
stop(): void;
|
|
15
|
+
/** Moves the authority and every connected client to the same destination scene. */
|
|
16
|
+
travelAll(sceneName: string): Promise<void>;
|
|
17
|
+
private waitForClients;
|
|
18
|
+
private waitForPendingClients;
|
|
19
|
+
private markClientReady;
|
|
20
|
+
private addTravellingClient;
|
|
21
|
+
private handleClientTravel;
|
|
22
|
+
private handleClientTravelComplete;
|
|
23
|
+
private releaseControlledActors;
|
|
24
|
+
private restartPlayers;
|
|
25
|
+
private requireGameMode;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=network-travel-coordinator.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as e}from"tslib";import{Service as t}from"typedi";import{randomUUID as s}from"../utils/uuid.js";import{BasePlayerController as n}from"./actors/controller/actor-controller.js";import{inject as i}from"./inject.js";import{NetMode as o}from"./net/net-session.js";import{NetService as r}from"./net/service/net-service.js";import{SceneTransitionService as a}from"./services/scene-transition.js";import{World as l}from"./services/world.js";let c=class{constructor(){this.net=i(r),this.scenes=i(a),this.world=i(l),this.subscriptions=[]}start(e){if(this.stop(),this.gameMode=e,this.subscriptions.push(this.net.sceneTravelBegin$.subscribe(e=>{this.clientTravel=this.handleClientTravel(e).catch(t=>{console.error(`Failed to load scene ${JSON.stringify(e.sceneName)} for network travel`,t)})}),this.net.sceneTravelReady$.subscribe(e=>this.markClientReady(e.travelId,e.connection.id.toString())),this.net.sceneTravelComplete$.subscribe(e=>this.handleClientTravelComplete(e))),null!=this.net.session&&this.subscriptions.push(this.net.session.playerLeft.subscribe(e=>this.markClientReady(this.pending?.travelId,e.id.toString())),this.net.session.playerJoined.subscribe(e=>this.addTravellingClient(e.id.toString()))),this.net.isClient&&null!=this.net.pendingSceneTravel){const e=this.net.pendingSceneTravel;this.clientTravel=this.handleClientTravel(e).catch(t=>{console.error(`Failed to load scene ${JSON.stringify(e.sceneName)} for network travel`,t)})}}stop(){for(const e of this.subscriptions)e.unsubscribe();this.subscriptions.length=0,this.gameMode=void 0,this.pending=void 0}async travelAll(e){if(!this.net.isServer)throw new Error("Only authority can initiate full-session scene travel");if(null!=this.pending)throw new Error("A network scene transition is already in progress");const t=this.requireGameMode(),n=e.trim();if(0===n.length)throw new Error("A destination scene name is required");const i=s();for(const e of this.net.players.values)"disconnected"!==e.status&&(e.status="travelling");if(await t.onTravelStarted(n),this.net.mode!==o.none){const e=this.waitForClients(i,n);this.net.beginSceneTravel(i,n),await e}this.releaseControlledActors(),await this.scenes.transitionTo(n),await this.waitForPendingClients(),await this.restartPlayers(t),this.net.mode!==o.none&&this.net.completeSceneTravel(i,n),this.pending=void 0,await t.onTravelCompleted(n)}waitForClients(e,t){const s=new Set(this.net.session?.clients.map(e=>e.id.toString())??[]);return this.pending={travelId:e,sceneName:t,expectedConnections:s,readyConnections:new Set},0===s.size?Promise.resolve():new Promise(e=>{this.pending.resolve=e})}waitForPendingClients(){const e=this.pending;return null==e||e.readyConnections.size===e.expectedConnections.size?Promise.resolve():new Promise(t=>{e.resolve=t})}markClientReady(e,t){const s=this.pending;if(null!=s&&e===s.travelId&&s.expectedConnections.has(t)&&(s.readyConnections.add(t),s.readyConnections.size===s.expectedConnections.size)){const e=s.resolve;s.resolve=void 0,e?.()}}addTravellingClient(e){this.pending?.expectedConnections.add(e)}async handleClientTravel(e){if(this.net.isClient){for(const e of this.net.players.values)e.status="travelling";await(this.gameMode?.onTravelStarted(e.sceneName)),this.releaseControlledActors(),await this.scenes.transitionTo(e.sceneName),this.net.sendSceneTravelReady(e.travelId,e.sceneName)}}handleClientTravelComplete(e){if(this.net.isClient){for(const e of this.net.players.values)"disconnected"!==e.status&&(e.status="active");this.gameMode?.onTravelCompleted(e.sceneName)}}releaseControlledActors(){for(const e of[...this.world.actors]){if(!(e instanceof n)||null==e.pawn)continue;const t=e.pawn;e.unpossess(),this.world.actors.includes(t)&&this.world.removeActor(t)}}async restartPlayers(e){for(const t of this.net.players.values){if("disconnected"===t.status||null==t.controller)continue;const s=await e.spawnDefaultPawn(t,t.controller);null!=s&&t.controller.possess(s),t.status="active"}}requireGameMode(){if(null==this.gameMode)throw new Error("NetworkTravelCoordinator must be started with a GameMode");return this.gameMode}};c=e([t()],c);export{c as NetworkTravelCoordinator};/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { GameMode } from './game-mode.js';
|
|
2
|
+
/** Runs an optional GameMode against the authoritative network player registry. */
|
|
3
|
+
export declare class PlayerLifecycleCoordinator {
|
|
4
|
+
private readonly net;
|
|
5
|
+
private readonly subscriptions;
|
|
6
|
+
private readonly playerOperations;
|
|
7
|
+
private gameMode?;
|
|
8
|
+
/** The authority-side policy currently receiving player lifecycle events. */
|
|
9
|
+
get activeGameMode(): GameMode | undefined;
|
|
10
|
+
/** Installs a policy and begins processing existing and newly joined players. */
|
|
11
|
+
start(gameMode: GameMode): Promise<void>;
|
|
12
|
+
/** Stops routing events, drains in-flight work, and releases the active policy. */
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
private activatePlayer;
|
|
15
|
+
private deactivatePlayer;
|
|
16
|
+
/**
|
|
17
|
+
* Starts lifecycle work from a synchronous registry event without leaving an
|
|
18
|
+
* unhandled promise. Work is serialized per stable player ID, and failures
|
|
19
|
+
* are reported through the active game mode's error policy.
|
|
20
|
+
*/
|
|
21
|
+
private schedulePlayerOperation;
|
|
22
|
+
/**
|
|
23
|
+
* Chains operations for one player so a slow join, disconnect, and reconnect
|
|
24
|
+
* cannot mutate that player's actors concurrently. Different players remain
|
|
25
|
+
* independent and may be processed in parallel.
|
|
26
|
+
*/
|
|
27
|
+
private runPlayerOperation;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=player-lifecycle-coordinator.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as t}from"tslib";import{Service as e}from"typedi";import{inject as a}from"./inject.js";import{NetService as s}from"./net/service/net-service.js";let i=class{constructor(){this.net=a(s),this.subscriptions=[],this.playerOperations=new Map}get activeGameMode(){return this.gameMode}async start(t){if(await this.stop(),!this.net.isServer)return;this.gameMode=t;const e=this.net.players.values;this.subscriptions.push(this.net.players.playerJoined$.subscribe(e=>{this.schedulePlayerOperation(t,e,()=>this.activatePlayer(t,e))}),this.net.players.playerLeft$.subscribe(e=>{this.schedulePlayerOperation(t,e,()=>this.deactivatePlayer(t,e))}));try{if(null==this.net.gameState){const e=await t.createGameState();if(null!=e&&!this.net.shouldReplicate(e))throw new Error(`${e.constructor.name} must use @Actor({ replicate: true }) to be a game state`);null!=e&&this.net.setGameState(e)}await t.onStart();for(const a of e)await this.runPlayerOperation(a,()=>this.activatePlayer(t,a))}catch(t){throw await this.stop(),t}}async stop(){for(const t of this.subscriptions)t.unsubscribe();this.subscriptions.length=0,await Promise.allSettled(this.playerOperations.values());const t=this.gameMode;this.gameMode=void 0,null!=t&&await t.onStop()}async activatePlayer(t,e){if("disconnected"===e.status)return;let a=e.playerState;if(null==a){a=await t.createPlayerState(e),this.net.players.attachPlayerState(e.info.id,a);const s=this.net.gameState;null==s||s.playerStates.includes(a)||(s.playerStates=[...s.playerStates,a])}a.connected=!0;let s=e.controller;if(null==s?(s=await t.createPlayerController(e),this.net.players.attachController(e.info.id,s)):this.net.players.setStatus(e.info.id,"active"),null!=e.connection&&this.net.setOwningConnection(s,e.connection),null==s.pawn){const a=await t.spawnDefaultPawn(e,s);null!=a&&s.possess(a)}await t.onPlayerReady(e)}async deactivatePlayer(t,e){"disconnected"===e.status&&await t.onPlayerLeaving(e)}schedulePlayerOperation(t,e,a){this.runPlayerOperation(e,a).catch(a=>t.onPlayerLifecycleError(e,a))}runPlayerOperation(t,e){const a=(this.playerOperations.get(t.info.id)??Promise.resolve()).catch(()=>{}).then(e);return this.playerOperations.set(t.info.id,a),a.finally(()=>{this.playerOperations.get(t.info.id)===a&&this.playerOperations.delete(t.info.id)}).catch(()=>{}),a}};i=t([e()],i);export{i as PlayerLifecycleCoordinator};/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { RenderingView, WebGpuPresentationExtensionContext } from '../rendering.js';
|
|
2
|
+
export type RenderingHostStageContext = WebGpuPresentationExtensionContext & {
|
|
3
|
+
readonly deltaTime: number;
|
|
4
|
+
readonly elapsedTime: number;
|
|
5
|
+
readonly targetView: GPUTextureView;
|
|
6
|
+
readonly targetFormat: GPUTextureFormat;
|
|
7
|
+
};
|
|
8
|
+
export type RenderingViewFactory = () => RenderingView;
|
|
9
|
+
/**
|
|
10
|
+
* Application-lifetime coordinator for RenderingViews targeting one surface.
|
|
11
|
+
* Views own scene/camera/post-processing state; the host owns which view presents
|
|
12
|
+
* and records persistent overlays after upscaling at presentation resolution.
|
|
13
|
+
*/
|
|
14
|
+
export declare class RenderingHost {
|
|
15
|
+
readonly applicationView: RenderingView;
|
|
16
|
+
private readonly ownsApplicationView;
|
|
17
|
+
private readonly viewFactory;
|
|
18
|
+
private readonly views;
|
|
19
|
+
private readonly frameDelta;
|
|
20
|
+
private readonly stages;
|
|
21
|
+
private readonly stageDisposers;
|
|
22
|
+
private nextStageId;
|
|
23
|
+
private stopped;
|
|
24
|
+
private frameCallback;
|
|
25
|
+
private _activeView;
|
|
26
|
+
constructor(applicationView: RenderingView, ownsApplicationView: boolean, viewFactory: RenderingViewFactory);
|
|
27
|
+
get activeView(): RenderingView;
|
|
28
|
+
get device(): GPUDevice;
|
|
29
|
+
get graphicsRuntime(): import("../rendering.js").GraphicsRuntime;
|
|
30
|
+
createView(): RenderingView;
|
|
31
|
+
start(onFrame: (deltaTime: number) => void): void;
|
|
32
|
+
activate(view: RenderingView): void;
|
|
33
|
+
releaseView(view: RenderingView): void;
|
|
34
|
+
registerStage(callback: (context: RenderingHostStageContext) => void): () => void;
|
|
35
|
+
shutdown(): void;
|
|
36
|
+
private installStages;
|
|
37
|
+
private installStage;
|
|
38
|
+
private removeStages;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=rendering-host.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export class RenderingHost{constructor(e,t,s){this.applicationView=e,this.ownsApplicationView=t,this.viewFactory=s,this.views=new Set,this.frameDelta=new Map,this.stages=new Map,this.stageDisposers=new Map,this.nextStageId=0,this.stopped=!1,this.frameCallback=()=>{},this._activeView=e,this.views.add(e)}get activeView(){return this._activeView}get device(){return this._activeView.webGpuDevice}get graphicsRuntime(){return this.applicationView.sharedGraphicsRuntime}createView(){if(this.stopped)throw new Error("RenderingHost has been shut down");const e=this.viewFactory();if(this.views.has(e))throw new Error("RenderingViewFactory must return a new view");return e.suspendPresentation(),this.views.add(e),this.installStages(e),e}start(e){this.frameCallback=e,this.activate(this.applicationView)}activate(e){if(!this.views.has(e))throw new Error("RenderingView is not owned by this host");this._activeView!==e&&this._activeView.suspendPresentation(),this._activeView=e,this.installStages(e),e.activatePresentation(),e.loop(t=>{this.frameDelta.set(e,t),this.frameCallback(t)})}releaseView(e){if(e===this.applicationView)throw new Error("Cannot release the application view");this.views.delete(e)&&(this.removeStages(e),this.frameDelta.delete(e),e.stop())}registerStage(e){const t=++this.nextStageId;this.stages.set(t,e);for(const s of this.views)this.installStage(s,t,e);return()=>{this.stages.delete(t);for(const e of this.stageDisposers.values())e.get(t)?.(),e.delete(t)}}shutdown(){if(!this.stopped){this.stopped=!0;for(const e of this.views)this.removeStages(e),e!==this.applicationView||this.ownsApplicationView?e.stop():e.suspendPresentation();this.views.clear(),this.frameDelta.clear()}}installStages(e){for(const[t,s]of this.stages)this.installStage(e,t,s)}installStage(e,t,s){let i=this.stageDisposers.get(e);if(null==i&&(i=new Map,this.stageDisposers.set(e,i)),i.has(t))return;const a=this;i.set(t,e.registerWebGpuPresentationExtension(t=>{const i=t;i.deltaTime=a.frameDelta.get(e)??0,i.elapsedTime=e.simulationTime,s(i)}))}removeStages(e){const t=this.stageDisposers.get(e);if(null!=t){for(const e of t.values())e();this.stageDisposers.delete(e)}}}/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-simd-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-simd-compat";import{BehaviorSubject as o,distinctUntilChanged as n,filter as r,map as a,Subject as l,takeUntil as c}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as p,Group as y,LineSegments as g,Matrix4 as m,Object3D as b,Quaternion as f,Raycaster as w,Scene as x,Vector3 as v}from"three";import*as B from"three/examples/jsm/utils/BufferGeometryUtils.js";import{Service as D}from"typedi";import{ActorComponent as S,Component as A}from"../../../gameplay/actors/component.js";import{inject as C}from"../../../gameplay/inject.js";import{BoxCollisionShape as R,CapsuleCollisionShape as M,ConeCollisionShape as E,ConvexPolyhedronCollisionShape as T,CylinderCollisionShape as z,PhysicalShapeMesh as P,PlaneCollisionShape as F,SphereCollisionShape as I,toInstancedCollisionShape as _,TrimeshCollisionShape as N}from"../../../scene/collision/collision-shape.js";import{AssetMeshInstance as W}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as j}from"../../../scene/landscape/landscape.js";import{calculateEffectiveScale as L}from"../../../utils/three/traverse.js";import{ViewController as k}from"../render.js";import{World as O}from"../world.js";import{AbstractPhysicsSystem as V}from"./abstract-physics-system.js";import{NetRole as U}from"../../net/index.js";export{ActorComponent,attach,Attach,Component}from"../../actors/component.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.hitNormal=new v}}export class ShapeCastResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.normal=new v}reset(){this.actor=void 0,this.hasHit=!1,this.distance=0,this.hitPoint.set(0,0,0),this.normal.set(0,0,0)}}ShapeCastResult.shared=new ShapeCastResult;export var PhysicsBodyType;!function(t){t[t.dynamic=1]="dynamic",t[t.static=2]="static",t[t.kinematic=4]="kinematic",t[t.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));const G=new v,K=new v,X=new f,q=new f,H=new f;let Q=class extends V{set showDebug(t){this.shouldRenderDebug=t,t||this.clearRayDebugArrows(),this.debugMesh&&(this.debugMesh.visible=t),this.staticDebugMesh&&(this.staticDebugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(){super(),this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.colliders=new Map,this.rayDebugArrowPool=[],this.activeRayDebugArrows=[],this.nonFixedBodies=new Set,this.collisionEvents=new l,this.beforeStep=new l,this.afterStep=new l,this.shouldRenderDebug=!1,this.viewController=C(k),this.shapeCacheBox=new Map,this.shapeCacheBall=new Map,this.staticDebugNeedsUpdate=!0,this.invalidateStaticDebug=()=>{this.staticDebugNeedsUpdate=!0},this.handleCollisionEvent=(t,e,i)=>{this.collisionEvents.next({handle1:t,handle2:e,started:i}),this.collisionEvents.next({handle1:e,handle2:t,started:i})},this._raycaster=new w,this._reusableResult=new RayTestResult,this._raytestDiff=new v,this._raytestDirection=new v,this.controlledActors=new Set,this._isStopped=!1,this.ready=this.setup()}getBallShape(t){let e=this.shapeCacheBall.get(t);return null==e&&(e=new this.rapier.Ball(t),this.shapeCacheBall.set(t,e)),e}getBoxShape(t,e,i){const s=t+1e6*e+1e12*i;let o=this.shapeCacheBox.get(s);return null==o&&(o=new this.rapier.Cuboid(t,e,i),this.shapeCacheBox.set(s,o)),o}hasBoxIntersection(t){const e=t.getCenter(G),i=t.getSize(K),s=this.getBoxShape(i.x/2,i.y/2,i.z/2);return null!=this.world.intersectionWithShape(e,X,s)}hasSphereIntersection(t){const e=this.getBallShape(t.radius);return null!=this.world.intersectionWithShape(t.center,X,e)}findActorsInRadius(t,e,i){const s=this.getBallShape(e),o=[];for(const[e,n]of this.bodyActors)if(null==i||n instanceof i)for(let i=0,r=e.numColliders();i<r;i++){e.collider(i).intersectsShape(s,t,X)&&o.push(n)}return o}createDebugMesh(){const t=new g(new p,new d.LineBasicMaterial({color:255}));return t.frustumCulled=!1,t}updateDebugMesh(t,e){const i=t.geometry,s=i.getAttribute("position");if(null==s||s.array.length<e.length){null!=s&&i.dispose();const t=new Float32Array(e.length);t.set(e);const o=new u(t,3);o.setUsage(d.DynamicDrawUsage),i.setAttribute("position",o)}else e.length>0&&(s.array.set(e),s.clearUpdateRanges(),s.addUpdateRange(0,e.length),s.needsUpdate=!0);i.setDrawRange(0,e.length/3)}async start(){return await this.ready,this.handleTick(),this.handleCollisionEvents(),this.ready}handleCollisionEvents(){this.collisionSub=this.collisionEvents.subscribe(t=>{const e=this.colliders.get(t.handle1);if(null==e)return;const i=this.world.getCollider(t.handle2);if(null==i||null==i.parent())return;const s=this.bodyActors.get(i.parent());null!=s&&(t.started?e.onBeginOverlapActor.next({actor:s}):e.onEndOverlapActor.next({actor:s}))})}renderDebug(){if(null==this.scene)return;if(null==this.staticDebugMesh&&(this.staticDebugMesh=this.createDebugMesh(),this.staticDebugMesh.visible=this.shouldRenderDebug,this.staticDebugMesh.raycast=function(){},this.scene.add(this.staticDebugMesh)),null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.scene.add(this.debugMesh)),this.staticDebugNeedsUpdate){const t=this.world.debugRender(s.ONLY_FIXED);this.updateDebugMesh(this.staticDebugMesh,t.vertices),this.staticDebugNeedsUpdate=!1}const t=this.world.debugRender(s.EXCLUDE_FIXED);this.updateDebugMesh(this.debugMesh,t.vertices)}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await pt(),this.eventQueue=new this.rapier.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe(t=>{if(!this._isStopped){t=Math.min(.04,t),this.beforeStep.next(t),this.updatePhysics(t),this.showDebug&&this.renderDebug(),this.releaseExpiredRayDebugArrows();for(const t of this.nonFixedBodies){let e,i=this.staticMeshes.get(t);if(null==i){if(e=this.bodyActors.get(t),e?.netRole===U.simulatedProxy)continue;i=e?.object}null!=i&&i.parent instanceof x&&(t.translation(i.position),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(e?.id))&&t.rotation(i.quaternion),i.matrixWorldNeedsUpdate=!0)}this.afterStep.next(t)}})}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){this._isStopped||(this.world.timestep=t,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents(this.handleCollisionEvent))}rayTestFromCamera(t,e,i){this._raycaster.setFromCamera(ct,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(t).add(s);return this.rayTest(s,o,e,i)}rayTest(t,e,i,o){null==i&&(i=this._reusableResult);const n=this._raytestDiff,r=this._raytestDirection;n.subVectors(e,t);const a=n.length();if(0===a)return console.warn("Ray test called with to and from being equal"),i;r.copy(n).multiplyScalar(1/a),null==Bt&&(Bt=new this.rapier.Ray(new this.rapier.Vector3(0,0,0),new this.rapier.Vector3(0,1,0))),yt(Bt.origin,t),yt(Bt.dir,r);const l=this.world.castRayAndGetNormal(Bt,a,!1,o?.excludeTriggers?s.EXCLUDE_SENSORS:void 0,o?.collisionFilter,void 0,null!=o?.excludeActor?this.actorBodies.get(o.excludeActor.id):void 0);if(i.hasHit=null!=l,i.actor=void 0,i.hasHit&&(i._internal=l,mt(i.hitNormal,l.normal),i.hitPoint.copy(t).addScaledVector(r,l.timeOfImpact),i.distance=l.timeOfImpact,!1!==o?.resolveActor)){const t=l.collider.parent();i.actor=null!=t?this.bodyActors.get(t):null}return this.showDebug&&!1!==o?.debug&&null!=this.scene&&this.drawRayDebugArrow(r,t,a,o?.debugColor,o?.debugLifetime),i}drawRayDebugArrow(t,e,i,s=255,o=200){let n=this.rayDebugArrowPool.pop();null==n?n=new h(t,e,i,s,.2,.1):(n.setDirection(t),n.position.copy(e),n.setLength(i,.2,.1),n.setColor(s)),n.userData.physicsRayDebugExpiresAt=performance.now()+o,this.activeRayDebugArrows.push(n),this.scene.add(n)}releaseExpiredRayDebugArrows(){if(0===this.activeRayDebugArrows.length)return;const t=performance.now();let e=0;for(let i=0;i<this.activeRayDebugArrows.length;i++){const s=this.activeRayDebugArrows[i];s.userData.physicsRayDebugExpiresAt<=t?(s.removeFromParent(),this.rayDebugArrowPool.push(s)):this.activeRayDebugArrows[e++]=s}this.activeRayDebugArrows.length=e}clearRayDebugArrows(){for(const t of this.activeRayDebugArrows)t.removeFromParent(),this.rayDebugArrowPool.push(t);this.activeRayDebugArrows.length=0}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return Z.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(t){this.addRecursively(t);for(const t of this.staticBodies.values())bt(t,t=>t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS))}addRecursively(t){if(this.removeSceneObject(t),!function(t){if(null!=t.userData?.src){const e=t.userData?.src;return"actor"===e.type}return!1}(t))if(t instanceof P&&null!=t.collisionShape){const e=this.createStaticBody(t,[t.collisionShape],t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else if(t instanceof W){const e=!1!==t.userData?.src?.collisionDetection;if(t.children[0]&&(t.children[0].instanceMatrix&&e||t.children[0].isBatchedMesh))this.createForInstancedMesh(t.children[0],t.collisionShapes);else if(e&&t.children.length>0){const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}0===t.children.length&&(t.matrixAutoUpdate=!1,t.matrixWorldAutoUpdate=!1)}else t instanceof j?this.addLandscapeGroup(t):(t instanceof y||t instanceof x)&&t.children.forEach(t=>this.addRecursively(t))}createForInstancedMesh(t,e){const i=new m;if(t instanceof d.BatchedMesh){const e=t._instanceInfo??t._drawInfo,s=new Map,o=t.userData.collisionMatrices;for(let n=0;n<e.length;n++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[n])continue;const e=t.userData.collisionShapes;let r=e?.[n];if(null==r&&null==e&&t.parent instanceof W&&(r=t.parent.collisionShapes),null==r)continue;const a=o?.[n];let l=r;null==a&&(l=s.get(r),null==l&&(l=this.instancedShapeReset(r),s.set(r,l)));const c=new b;c.matrix.identity(),null!=a?i.copy(a):t.getMatrixAt(n,i),c.applyMatrix4(i);this.createStaticBody(c,l)}}else{const s=this.instancedShapeReset(e);for(let e=0;e<t.count;e++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[e])continue;const o=new b;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*e),o.applyMatrix4(i);this.createStaticBody(o,s)}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>_(t))}getCharacterController(t){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i,o=null){const n=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const r=n.collider(0);e.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,o,void 0);const a=e.computedMovement();return mt(ft,a),ft}setActorCapsuleCollider(t,e,i,s){const o=this.actorBodies.get(t.id),n=o?.collider(0);if(null==o||null==n)return!1;const r=t.object?.getWorldScale(vt)??et,a=Math.max(0,e*Math.abs(r.y)),l=Math.max(.001,i*Math.max(Math.abs(r.x),Math.abs(r.z)));return n.setHalfHeight(a/2),n.setRadius(l),ot.set(0,s,0).multiply(r),yt(it,ot),n.setTranslationWrtParent(it),o.recomputeMassPropertiesFromColliders(),o.isFixed()&&this.invalidateStaticDebug(),!0}hasActorCapsuleIntersection(t,e,i,o,n,r=null){const a=this.actorBodies.get(t.id),l=t.object?.getWorldScale(vt)??et,c=Math.max(0,i*Math.abs(l.y)),d=Math.max(.001,o*Math.max(Math.abs(l.x),Math.abs(l.z))),h=new this.rapier.Capsule(c/2,d),u=t.object?.getWorldQuaternion(H)??X;ot.set(0,n,0).multiply(l).applyQuaternion(u).add(e);return null!=this.world.intersectionWithShape(ot,u,h,s.EXCLUDE_SENSORS,r??void 0,void 0,a,xt)}createCollider(t,e){const i=this.addShape(e?.body,t),s=new PhysicsCollider(i,this.world,this.invalidateStaticDebug);return this.colliders.set(i.handle,s),(null==e||e.body.isFixed())&&this.invalidateStaticDebug(),s.disposed.subscribe(()=>{this.colliders.delete(i.handle)}),s}createBody(t=PhysicsBodyType.dynamic,e={}){const i=(()=>{switch(t){case PhysicsBodyType.dynamic:return this.rapier.RigidBodyDesc.dynamic();case PhysicsBodyType.static:return this.rapier.RigidBodyDesc.fixed();case PhysicsBodyType.kinematic:return this.rapier.RigidBodyDesc.kinematicPositionBased();case PhysicsBodyType.kinematicVelocityBased:return this.rapier.RigidBodyDesc.kinematicVelocityBased();default:return this.rapier.RigidBodyDesc.dynamic()}})();e.position&&i.setTranslation(e.position.x,e.position.y,e.position.z),e.rotation&&i.setRotation({x:e.rotation.x,y:e.rotation.y,z:e.rotation.z,w:e.rotation.w}),"boolean"==typeof e.canSleep&&i.setCanSleep(e.canSleep),"boolean"==typeof e.ccdEnabled&&i.setCcdEnabled(e.ccdEnabled),"number"==typeof e.gravityScale&&i.setGravityScale(e.gravityScale),"number"==typeof e.mass&&i.setAdditionalMass(e.mass),void 0!==e.userData&&(i.userData=e.userData);const s=this.world.createRigidBody(i);return s.isFixed()?this.invalidateStaticDebug():this.nonFixedBodies.add(s),new PhysicsBody(s,this.world,this.invalidateStaticDebug)}createJoint(t,e,i){let s,o;switch(i.type){case"fixed":s=this.rapier.JointData.fixed(i.anchor1,i.frame1,i.anchor2,i.frame2);break;case"spherical":s=this.rapier.JointData.spherical(i.anchor1,i.anchor2);break;case"revolute":s=this.rapier.JointData.revolute(i.anchor1,i.anchor2,i.axis),null!=i.limits&&(o=i.limits)}const n=this.world.createImpulseJoint(s,t.body,e.body,!0);if(null!=o){n.setLimits(o[0],o[1])}return n.setContactsEnabled(i.contactsEnabled??!1),new PhysicsJoint(n,this.world)}getCharacterComputedMovement(t,e,i,o=null){const n=t.collider;e.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,o,void 0);const r=e.computedMovement();return mt(ft,r),ft}setNextKinematicTranslation(t,e){const i=this.actorBodies.get(t.id),s=i.translation(it);s.x+=e.x,s.y+=e.y,s.z+=e.z,i?.setNextKinematicTranslation(s)}setNextKinematicPosition(t,e){this.actorBodies.get(t.id).setNextKinematicTranslation(e)}setNextKinematicRotation(t,e){this.actorBodies.get(t.id).setNextKinematicRotation(e)}setNextKinematicTransform(t){!function(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setNextKinematicTranslation(dt(i)),t.setNextKinematicRotation(ht(s))}(this.actorBodies.get(t.id),t.object)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setAngvel(it,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setLinvel(it,!0)}getLinearVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.linvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}getAngularVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.angvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}setLinearDamping(t,e){const i=this.actorBodies.get(t.id);i?.setLinearDamping(e)}getLienarDamping(t){const e=this.actorBodies.get(t.id);return e?.linearDamping()??0}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}getAngularDamping(t){const e=this.actorBodies.get(t.id);e?.angularDamping()}setPosition(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(dt(e),!1)}getPosition(t,e=new v){const i=this.actorBodies.get(t.id);i&&i.translation(e)}setRotation(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(ht(e),!1)}getRotation(t,e=new f){const i=this.actorBodies.get(t.id);i&&function(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}(e,i.rotation())}lockTranslations(t,e){const i=this.actorBodies.get(t.id);i?.lockTranslations(e,!1)}lockRotations(t,e){const i=this.actorBodies.get(t.id);i?.lockRotations(e,!1)}setEnabledTranslations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledTranslations(e,i,s,!1)}setEnabledRotations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledRotations(e,i,s,!1)}addLandscapeGroup(t){this.invalidateStaticDebug();const e=t.userData.src,s=e.landscape.heightMaps;for(const n of t.sections){this.staticBodies.has(n)&&this.world.removeRigidBody(this.staticBodies.get(n));var o=n.getWorldPosition(new v);if(e.landscape.holes&&e.landscape.holes.some(t=>t.m===n.name&&0!==t.w[0])){const t=n.geometry.clone(),i=n.scale,s=n.geometry.getAttribute("hole"),r=new Float32Array(t.getAttribute("position").array);for(let t=0;t<r.length;t+=3)r[t]*=i.x,r[t+1]*=i.y,r[t+2]*=i.z;const a=t.index;for(let t=0;t<a.count;t+=3){const e=s.getX(a.getX(t)),i=s.getX(a.getY(t)),o=s.getX(a.getZ(t));(e>.5||i>.5||o>.5)&&(a.setX(t,0),a.setY(t,0),a.setZ(t,0))}const l=this.rapier.ColliderDesc.trimesh(r,new Uint32Array(t.getIndex().array));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);yt(e,o),t.setTranslation(e,!1),this.world.createCollider(l,t),this.staticBodies.set(n,t)}continue}const t=e.landscape.options.density+1,r=e.landscape.options.sectionSize,a=new Array(t);for(let e=0;e<t;e++)a[e]=new Array(t).fill(0);const l=s.find(t=>t.x===n.x&&t.y==n.y);if(null!=l)for(const e of l.points){if(null==a[e.i%t])continue;const i=t-1-Math.floor(e.i/t);i in a[e.i%t]?a[e.i%t][i]=e.y/r:console.warn("wrong index",{points:a,point:e,i:e.i%t,k:i,heightMap:l})}const c=e.landscape.options.density,d=a.flatMap(t=>t.reverse()),h=i.ColliderDesc.heightfield(c,c,new Float32Array(d),new this.rapier.Vector3(r,r,r));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);yt(e,o),t.setTranslation(e,!1),this.world.createCollider(h,t),this.staticBodies.set(n,t)}}}setEnabled(t,e){const i=this.actorBodies.get(t.id);i?.setEnabled(e),i?.isFixed()&&this.invalidateStaticDebug()}addActor(t,e,i={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const s=t.object;let o;switch(i.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:o=this.rapier.RigidBodyDesc.dynamic(),o.mass=i.mass??1;break;case PhysicsBodyType.kinematic:o=this.rapier.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:o=this.rapier.RigidBodyDesc.kinematicVelocityBased();break;default:o=i.isTrigger?this.rapier.RigidBodyDesc.kinematicVelocityBased():this.rapier.RigidBodyDesc.fixed()}const n=this.world.createRigidBody(o);n.enableCcd(1==i.continousCollisionDetection);for(const t of e){const e=this.addShape(n,t,s);wt.set(e,!i.isTrigger)}return i.type!==PhysicsBodyType.static&&this.nonFixedBodies.add(n),bt(n,t=>{null!=i.isTrigger&&(t.setSensor(i.isTrigger),t.setActiveCollisionTypes(this.rapier.ActiveCollisionTypes.ALL),t.setActiveEvents(this.rapier.ActiveEvents.COLLISION_EVENTS)),null!=i.friction&&t.setFriction(i.friction),null!=i.density&&t.setDensity(i.density),null!=i.mass&&t.setMass(i.mass),null!=i.restitution&&t.setRestitution(i.restitution)}),Y(n,s),!0===i.ignoreForNavMesh&&(n.userData={ignoreForNavMesh:!0}),this.actorBodies.set(t.id,n),this.bodyActors.set(n,t),n.isFixed()&&this.invalidateStaticDebug(),new PhysicsBody(n,this.world,this.invalidateStaticDebug)}applyTorque(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addTorque(it,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyTorqueImpulse(it,!0)}resetForces(t){const e=this.actorBodies.get(t.id);e?.resetForces(!1)}resetTorques(t){const e=this.actorBodies.get(t.id);e?.resetTorques(!1)}applyForce(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addForce(it,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyImpulse(it,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);yt(it,e),null==i?s?.addForce(it,!0):(yt(st,i),s?.addForceAtPoint(it,st,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);yt(it,e),null==i?s.applyImpulse(it,!0):(yt(st,i),s.applyImpulseAtPoint(it,st,!0))}applyRadialImpulse(t,e,i){return e<=0||0===i?0:this.applyImpulseToBodiesInRadius(t,e,(t,s,o)=>{o<=1e-6?s.set(0,1,0):s.multiplyScalar(1/o),s.multiplyScalar(i*Math.max(0,1-o/e)),yt(it,s),t.applyImpulse(it,!0)})}applyDirectionalImpulse(t,e,i,s,o){if(i<=0||0===o||e.lengthSq()<=1e-12)return 0;nt.copy(e).normalize();const n=Math.cos(Math.max(0,Math.min(Math.PI,s)));return this.applyImpulseToBodiesInRadius(t,i,(t,e,i)=>{if(i>1e-6&&e.multiplyScalar(1/i).dot(nt)<n)return!1;it.x=nt.x*o,it.y=nt.y*o,it.z=nt.z*o,t.applyImpulse(it,!0)})}applyImpulseToBodiesInRadius(t,e,i){const o=at,n=lt;o.clear(),n.length=0;let r=0;this.world.intersectionsWithShape(t,X,this.getBallShape(e),t=>{const e=t.parent();return null==e||o.has(e.handle)||(o.add(e.handle),n.push(e)),!0},s.ONLY_DYNAMIC|s.EXCLUDE_SENSORS);for(const e of n)mt(rt,e.worldCom()),rt.sub(t),!1!==i(e,rt,rt.length())&&r++;return o.clear(),n.length=0,r}removeActor(t){if(null==t)return;this.controlledActors.delete(t.id);const e=this.actorBodies.get(t.id);null!=e&&(e.isFixed()&&this.invalidateStaticDebug(),this.bodyActors.delete(e),this.world.removeRigidBody(e),this.nonFixedBodies.delete(e)),this.actorBodies.delete(t.id)}removeRemoved(t){if(null==t)return;const e=new Set;t.traverse(t=>{e.add(t.uuid)});for(const[t,i]of this.staticBodies.entries())e.has(t.uuid)&&this.world.getRigidBody(i.handle)&&(this.invalidateStaticDebug(),this.staticBodies.delete(t),this.world.removeRigidBody(i),this.nonFixedBodies.delete(i))}removeSceneObject(t){if(t instanceof j){for(const e of t.sections)this.removeSceneObject(e);return}let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&(this.invalidateStaticDebug(),this.world.removeRigidBody(e),this.nonFixedBodies.delete(e)),this.staticBodies.delete(t)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(({started:t})=>t===i),a(({handle1:t,handle2:e,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(t)?.parent()),a2:this.bodyActors.get(this.world.getCollider(e)?.parent()),started:i})),r(({a1:i,a2:s})=>null!=i&&null!=s&&i.id===t.id&&e(i,s)),a(({a2:t})=>t))}onBeginContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onEndContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>!t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onHasContactChanged(t){const e=new Set,i=new o(!1);return this.onBeginContact(t).subscribe(t=>{e.add(t),i.next(e.size>0)}),this.onEndContact(t).subscribe(t=>{e.delete(t),i.next(e.size>0)}),i.pipe(n())}onBeginOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!0)}onEndOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!1)}onBeginOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!0)}onEndOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!1)}onBeginOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!0)}onEndOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!1)}onCollisionWithActor(t,e){return this.onBeginOverlapWithActor(t,e)}onCollisionWithActorType(t,e){return this.onBeginOverlapWithActorType(t,e)}updateActorTransform(t){const e=this.actorBodies.get(t.id);null!=e&&(Y(e,t.object),e.isFixed()&&this.invalidateStaticDebug())}flushModifiedBodyPositionsToColliders(){this.world.propagateModifiedBodyPositionsToColliders()}setupWorld(){const t=new this.rapier.World({x:0,y:-9.81,z:0});this.world=t,this.invalidateStaticDebug()}sphereCast(t,e,i,o,n=ShapeCastResult.shared,r){n.reset();const a=this.getBallShape(e);it.x=i.x,it.y=i.y,it.z=i.z;const l=r?.excludeActor?this.actorBodies.get(r.excludeActor.id):null,c=this.world.castShape(t,X,it,a,.01,o,!0,r?.excludeTriggers?s.EXCLUDE_SENSORS:void 0,r?.collisionFilter??void 0,null,l);if(null!=c){mt(n.hitPoint,c.witness1),n.normal.set(c.normal1.x,c.normal1.y,c.normal1.z),n.distance=c.time_of_impact,n.hasHit=!0;const t=c.collider.parent();if(t){const e=this.bodyActors.get(t);e&&(n.actor=e)}}return n}castActorShape(t,e,i,s=ShapeCastResult.shared,o=void 0){s.reset();const n=this.actorBodies.get(t.id);if(n&&n.numColliders()>0){for(let t=0;t<n.numColliders();t++){const r=n.collider(t);let a=r.shape,l=r.translation(),c=r.rotation(),d=e,h=i;const u=this.world.castShape(l,c,d,a,.01,h,!0,null,o,null,n,void 0);if(null!=u){u.collider;const t=r;return mt(s.hitPoint,u.witness1),St(t.rotation(),u.normal1,s.normal,q),s.distance=u.time_of_impact,s.actor=this.bodyActors.get(u.collider.parent()),s.hasHit=!0,s}}return s}return console.warn("Actor is not added to the physics system"),s}stop(){if(!this._isStopped){this._isStopped=!0,this.bodyActors.clear(),this.actorBodies.clear(),this.staticBodies.clear(),this.staticMeshes.clear(),this.colliders.clear(),this.fixedupdateSub?.unsubscribe(),this.collisionSub?.unsubscribe(),this.world?.bodies.forEach(t=>{this.world.removeRigidBody(t),this.nonFixedBodies.delete(t)});try{this.eventQueue?.free()}catch(t){console.warn("Error when freeing physics event queue",t)}try{this.world?.free(),this.world=void 0}catch(t){console.warn("Error while freeing physics world",t)}this.clearRayDebugArrows();for(const t of this.rayDebugArrowPool)t.dispose();this.rayDebugArrowPool.length=0}}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed(),n=this.world.createRigidBody(o);s?.type===PhysicsBodyType.dynamic&&this.nonFixedBodies.add(n);let r=0;for(const i of e){if(r>128){console.warn("Too many collision shapes for object",t);break}if(r++,null==i){console.warn("Collision shape is missing for object",t);continue}const o=this.addShape(n,i,t);null!=o&&(null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/e.length),null!=s?.restitution&&o.setRestitution(s.restitution))}return Y(n,t),n.userData=t.uuid,n.isFixed()&&this.invalidateStaticDebug(),n}addShape(t=void 0,e,i){const s=i?.getWorldScale(vt)??et,o=this.createShape(e,s);if(null==o)return void console.error("Failed to create physics shape. This can happen if the geometry is degenerate or zero-scaled.",{shapeInfo:e,object:i});this.applyShapeSettings(o,e);const n=e.offset.clone().multiply(s);yt(o.translation,n);const r=(new f).setFromEuler(e.rotation);gt(o.rotation,r),null!=t&&t.numColliders()>128&&console.warn(`Rigid body has many colliders (${t.numColliders()}). Consider using a Trimesh if this is static geometry.`,t);try{return this.world.createCollider(o,t)}catch(t){return void console.error("Failed to create collider",t)}}applyShapeSettings(t,e){null!=e.collisionGroup&&t.setCollisionGroups(e.collisionGroup),t.friction=e.friction??.1,null!=e.restitution&&(t.restitution=e.restitution),null!=e.density&&(t.density=e.density,t.massPropsMode=i.MassPropsMode.Density),null!=e.mass&&(t.mass=e.mass,t.massPropsMode=i.MassPropsMode.Mass)}createShape(t,e){if(t instanceof R)return this.rapier.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof M){return this.rapier.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof N){const i=null!=t.geometry.getIndex()?t.geometry:B.mergeVertices(t.geometry),s=extractFloat32Array(i.getAttribute("position"));for(let t=0;t<s.length;t+=3)s[t]*=e.x,s[t+1]*=e.y,s[t+2]*=e.z;const o=i.getIndex();return null==o?(console.error("Trimesh collision shape is missing an index buffer.",t),null):this.rapier.ColliderDesc.trimesh(s,new Uint32Array(o.array))}if(t instanceof T){let i,s;t.mesh instanceof d.Mesh?i=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?i=t.mesh:console.log("Unknownd shape",{shapeInfo:t}),t.mesh instanceof d.Mesh&&(s=L(t.mesh));const o=`${i.uuid}|${s?.x??1},${s?.y??1},${s?.z??1}|${e.x},${e.y},${e.z}`,n=tt.get(o);if(void 0!==n)return n;const r=extractFloat32Array(i.getAttribute("position"));if(null!=s)for(let t=0;t<r.length;t+=3)r[t]*=s.x,r[t+1]*=s.y,r[t+2]*=s.z;for(let t=0;t<r.length;t+=3)r[t]*=e.x,r[t+1]*=e.y,r[t+2]*=e.z;const a=this.rapier.ColliderDesc.convexHull(r);return null==a&&console.error("Failed to compute convex hull. Points may be coplanar or too few.",{count:r.length/3}),tt.set(o,a),a}if(t instanceof I){const i=2*e.x-e.y-e.z;return Math.abs(i)>.01?this.createShape(new T(new d.SphereGeometry(t.radius).scale(e.x,e.y,e.z)),new v(1,1,1)):this.rapier.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z))}return t instanceof z?this.rapier.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof E?this.rapier.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof F?this.rapier.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.001):(console.error("Unsupported shape",t),this.rapier.ColliderDesc.cuboid(1,1,1))}createCharacterCollision(){return new this.rapier.CharacterCollision}};Q=t([D(),e("design:paramtypes",[])],Q);export{Q as PhysicsSystem};const J=new v,$=new d.Quaternion;function Y(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setTranslation(dt(i),!1),t.setRotation(ht(s),!1)}const Z=new v,tt=new Map,et=new v(1,1,1),it=new i.Vector3(0,0,0),st=new i.Vector3(0,0,0),ot=new v,nt=new v,rt=new v,at=new Set,lt=[],ct=new d.Vector2;function dt(t){return yt(it,t),it}function ht(t){return gt(q,t),q}let ut=null;const pt=async()=>(null==ut&&(ut=(async()=>{let t=await import("@dimforge/rapier3d-simd-compat");return await t.init(),t})()),ut);function yt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function gt(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function mt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function bt(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const ft=new v,wt=new WeakMap,xt=t=>wt.get(t)??!0,vt=new v;let Bt,Dt=class extends S{constructor(){super(...arguments),this._active=!0,this.physics=C(Q),this.world=C(O)}set active(t){this._active=t,t?(this.world.scene.remove(this.actor.object),this.physics.setEnabled(this.actor,t)):(this.world.scene.add(this.actor.object),this.physics.setEnabled(this.actor,t))}get active(){return this._active}};Dt=t([A()],Dt);export function extractFloat32Array(t){const e=t.itemSize,i=t.count,s=new Float32Array(i*e);for(let o=0;o<i;o++)for(let i=0;i<e;i++)s[o*e+i]=t.getComponent(o,i);return s}function St(t,e,i,s){return s.set(t.x,t.y,t.z,t.w),i.set(e.x,e.y,e.z),i.applyQuaternion(s),i}export class PhysicsCollider{constructor(t,e,i){this.collider=t,this.world=e,this.invalidateStaticDebug=i,this.disposed=new l,this.onBeginOverlapActor=new l,this.onEndOverlapActor=new l}dispose(){const t=this.collider.parent();(null==t||t.isFixed())&&this.invalidateStaticDebug?.(),this.world.removeCollider(this.collider,!1),this.disposed.next(!0),this.disposed.complete(),this.onBeginOverlapActor.complete(),this.onEndOverlapActor.complete()}set mass(t){this.collider.setMass(t)}get mass(){return this.collider.mass()}set friction(t){this.collider.setFriction(t)}get friction(){return this.collider.friction()}set restitution(t){this.collider.setRestitution(t)}get restitution(){return this.collider.restitution()}set density(t){this.collider.setDensity(t)}get density(){return this.collider.density()}set isTrigger(t){this.collider.setSensor(t)}get isTrigger(){return this.collider.isSensor()}set collisionGroups(t){this.collider.setCollisionGroups(t)}get collisionGroups(){return this.collider.collisionGroups()}set enabled(t){this.collider.setEnabled(t);const e=this.collider.parent();(null==e||e.isFixed())&&this.invalidateStaticDebug?.()}get enabled(){return this.collider.isEnabled()}}export class PhysicsBody{constructor(t,e,i){this.invalidateStaticDebug=i,this.body=t,this.world=e}dispose(){this.body.isFixed()&&this.invalidateStaticDebug?.(),this.world.removeRigidBody(this.body)}setEnabled(t){this.body.setEnabled(t),this.body.isFixed()&&this.invalidateStaticDebug?.()}isEnabled(){return this.body.isEnabled()}getPosition(t){return this.body.translation(t)}setPosition(t){this.body.setTranslation({x:t.x,y:t.y,z:t.z},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getRotation(t){const e=this.body.rotation();return t.set(e.x,e.y,e.z,e.w),t}setRotation(t){this.body.setRotation({x:t.x,y:t.y,z:t.z,w:t.w},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getLinearVelocity(t){const e=this.body.linvel();return t.set(e.x,e.y,e.z),t}setLinearVelocity(t){this.body.setLinvel({x:t.x,y:t.y,z:t.z},!0)}getAngularVelocity(t){const e=this.body.angvel();return t.set(e.x,e.y,e.z),t}setAngularVelocity(t){this.body.setAngvel({x:t.x,y:t.y,z:t.z},!0)}setLinearDamping(t){this.body.setLinearDamping(t)}setAngularDamping(t){this.body.setAngularDamping(t)}applyImpulse(t,e=!0){this.body.applyImpulse({x:t.x,y:t.y,z:t.z},e)}applyTorqueImpulse(t,e=!0){this.body.applyTorqueImpulse({x:t.x,y:t.y,z:t.z},e)}setNextKinematicPosition(t){this.body.setNextKinematicTranslation(t)}setNextKinematicRotation(t){this.body.setNextKinematicRotation(t)}setType(t){const e=this.body.isFixed();this.body.setBodyType(function(t){switch(t){case PhysicsBodyType.dynamic:return i.RigidBodyType.Dynamic;case PhysicsBodyType.static:return i.RigidBodyType.Fixed;case PhysicsBodyType.kinematic:return i.RigidBodyType.KinematicPositionBased;case PhysicsBodyType.kinematicVelocityBased:return i.RigidBodyType.KinematicVelocityBased}}(t),t!==PhysicsBodyType.static),(e||this.body.isFixed())&&this.invalidateStaticDebug?.()}setGravityScale(t){this.body.setGravityScale(t,!1)}getGravityScale(){return this.body.gravityScale()}isDynamic(){return this.body.isDynamic()}isKinematic(){return this.body.isKinematic()}isStatic(){return this.body.isFixed()}sleep(){this.body.sleep()}wakeUp(){this.body.wakeUp()}}export class PhysicsJoint{constructor(t,e){this.joint=t,this.world=e}dispose(){this.joint.isValid()&&this.world.removeImpulseJoint(this.joint,!0)}setContactsEnabled(t){this.joint.setContactsEnabled(t)}get contactsEnabled(){return this.joint.contactsEnabled()}}/*
|
|
1
|
+
import{__decorate as t,__metadata as e}from"tslib";import*as i from"@dimforge/rapier3d-simd-compat";import{QueryFilterFlags as s}from"@dimforge/rapier3d-simd-compat";import{BehaviorSubject as o,distinctUntilChanged as n,filter as r,map as a,Subject as l,takeUntil as c}from"rxjs";import*as d from"three";import{ArrowHelper as h,BufferAttribute as u,BufferGeometry as p,Group as y,LineSegments as g,Matrix4 as m,Object3D as b,Quaternion as f,Raycaster as w,Scene as x,Vector3 as v}from"three";import*as B from"three/examples/jsm/utils/BufferGeometryUtils.js";import{Service as D}from"typedi";import{ActorComponent as S,Component as A}from"../../../gameplay/actors/component.js";import{inject as C}from"../../../gameplay/inject.js";import{BoxCollisionShape as R,CapsuleCollisionShape as M,ConeCollisionShape as E,ConvexPolyhedronCollisionShape as T,CylinderCollisionShape as z,PhysicalShapeMesh as P,PlaneCollisionShape as F,SphereCollisionShape as I,toInstancedCollisionShape as _,TrimeshCollisionShape as N}from"../../../scene/collision/collision-shape.js";import{AssetMeshInstance as W}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as j}from"../../../scene/landscape/landscape.js";import{calculateEffectiveScale as L}from"../../../utils/three/traverse.js";import{ViewController as k}from"../render.js";import{World as O}from"../world.js";import{AbstractPhysicsSystem as V}from"./abstract-physics-system.js";import{NetRole as U}from"../../net/index.js";export{ActorComponent,attach,Attach,Component}from"../../actors/component.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.hitNormal=new v}}export class ShapeCastResult{constructor(){this.hasHit=!1,this.hitPoint=new v,this.normal=new v}reset(){this.actor=void 0,this.hasHit=!1,this.distance=0,this.hitPoint.set(0,0,0),this.normal.set(0,0,0)}}ShapeCastResult.shared=new ShapeCastResult;export var PhysicsBodyType;!function(t){t[t.dynamic=1]="dynamic",t[t.static=2]="static",t[t.kinematic=4]="kinematic",t[t.kinematicVelocityBased=8]="kinematicVelocityBased"}(PhysicsBodyType||(PhysicsBodyType={}));const G=new v,K=new v,X=new f,q=new f,H=new f;let Q=class extends V{set showDebug(t){this.shouldRenderDebug=t,t||this.clearRayDebugArrows(),this.debugMesh&&(this.debugMesh.visible=t),this.staticDebugMesh&&(this.staticDebugMesh.visible=t)}get showDebug(){return this.shouldRenderDebug}constructor(){super(),this.staticMeshes=new Map,this.staticBodies=new Map,this.actorBodies=new Map,this.bodyActors=new Map,this.colliders=new Map,this.rayDebugArrowPool=[],this.activeRayDebugArrows=[],this.nonFixedBodies=new Set,this.collisionEvents=new l,this.beforeStep=new l,this.afterStep=new l,this.shouldRenderDebug=!1,this.viewController=C(k),this.shapeCacheBox=new Map,this.shapeCacheBall=new Map,this.staticDebugNeedsUpdate=!0,this.invalidateStaticDebug=()=>{this.staticDebugNeedsUpdate=!0},this.handleCollisionEvent=(t,e,i)=>{this.collisionEvents.next({handle1:t,handle2:e,started:i}),this.collisionEvents.next({handle1:e,handle2:t,started:i})},this._raycaster=new w,this._reusableResult=new RayTestResult,this._raytestDiff=new v,this._raytestDirection=new v,this.controlledActors=new Set,this._isStopped=!1,this.ready=this.setup()}getBallShape(t){let e=this.shapeCacheBall.get(t);return null==e&&(e=new this.rapier.Ball(t),this.shapeCacheBall.set(t,e)),e}getBoxShape(t,e,i){const s=t+1e6*e+1e12*i;let o=this.shapeCacheBox.get(s);return null==o&&(o=new this.rapier.Cuboid(t,e,i),this.shapeCacheBox.set(s,o)),o}hasBoxIntersection(t){const e=t.getCenter(G),i=t.getSize(K),s=this.getBoxShape(i.x/2,i.y/2,i.z/2);return null!=this.world.intersectionWithShape(e,X,s)}hasSphereIntersection(t){const e=this.getBallShape(t.radius);return null!=this.world.intersectionWithShape(t.center,X,e)}findActorsInRadius(t,e,i){const s=this.getBallShape(e),o=[];for(const[e,n]of this.bodyActors)if(null==i||n instanceof i)for(let i=0,r=e.numColliders();i<r;i++){e.collider(i).intersectsShape(s,t,X)&&o.push(n)}return o}createDebugMesh(){const t=new g(new p,new d.LineBasicMaterial({color:255}));return t.frustumCulled=!1,t}updateDebugMesh(t,e){const i=t.geometry,s=i.getAttribute("position");if(null==s||s.array.length<e.length){null!=s&&i.dispose();const t=new Float32Array(e.length);t.set(e);const o=new u(t,3);o.setUsage(d.DynamicDrawUsage),i.setAttribute("position",o)}else e.length>0&&(s.array.set(e),s.clearUpdateRanges(),s.addUpdateRange(0,e.length),s.needsUpdate=!0);i.setDrawRange(0,e.length/3)}async start(){return await this.ready,this.handleTick(),this.handleCollisionEvents(),this.ready}handleCollisionEvents(){this.collisionSub=this.collisionEvents.subscribe(t=>{const e=this.colliders.get(t.handle1);if(null==e)return;const i=this.world.getCollider(t.handle2);if(null==i||null==i.parent())return;const s=this.bodyActors.get(i.parent());null!=s&&(t.started?e.onBeginOverlapActor.next({actor:s}):e.onEndOverlapActor.next({actor:s}))})}renderDebug(){if(null==this.scene)return;if(null==this.staticDebugMesh&&(this.staticDebugMesh=this.createDebugMesh(),this.staticDebugMesh.visible=this.shouldRenderDebug,this.staticDebugMesh.raycast=function(){},this.scene.add(this.staticDebugMesh)),null==this.debugMesh&&(this.debugMesh=this.createDebugMesh(),this.debugMesh.visible=this.shouldRenderDebug,this.debugMesh.raycast=function(){},this.scene.add(this.debugMesh)),this.staticDebugNeedsUpdate){const t=this.world.debugRender(s.ONLY_FIXED);this.updateDebugMesh(this.staticDebugMesh,t.vertices),this.staticDebugNeedsUpdate=!1}const t=this.world.debugRender(s.EXCLUDE_FIXED);this.updateDebugMesh(this.debugMesh,t.vertices)}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await pt(),this.eventQueue=new this.rapier.EventQueue(!0),this.setupWorld()}handleTick(){this.fixedupdateSub=this.viewController.onUpdate().subscribe(t=>{if(!this._isStopped){t=Math.min(.04,t),this.beforeStep.next(t),this.updatePhysics(t),this.showDebug&&this.renderDebug(),this.releaseExpiredRayDebugArrows();for(const t of this.nonFixedBodies){let e,i=this.staticMeshes.get(t);if(null==i){if(e=this.bodyActors.get(t),e?.netRole===U.simulatedProxy)continue;i=e?.object}null!=i&&i.parent instanceof x&&(t.translation(i.position),(t.isDynamic()||t.isKinematic()&&!this.controlledActors.has(e?.id))&&t.rotation(i.quaternion),i.matrixWorldNeedsUpdate=!0)}this.afterStep.next(t)}})}_updateWorld(){this.world.timestep=0,this.world.step()}updatePhysics(t){this._isStopped||(this.world.timestep=t,this.world.step(this.eventQueue),this.eventQueue.drainCollisionEvents(this.handleCollisionEvent))}rayTestFromCamera(t,e,i){this._raycaster.setFromCamera(ct,this.viewController.getCamera());const s=this._raycaster.ray.origin,o=this._raycaster.ray.direction.multiplyScalar(t).add(s);return this.rayTest(s,o,e,i)}rayTest(t,e,i,o){null==i&&(i=this._reusableResult);const n=this._raytestDiff,r=this._raytestDirection;n.subVectors(e,t);const a=n.length();if(0===a)return console.warn("Ray test called with to and from being equal"),i;r.copy(n).multiplyScalar(1/a),null==Bt&&(Bt=new this.rapier.Ray(new this.rapier.Vector3(0,0,0),new this.rapier.Vector3(0,1,0))),yt(Bt.origin,t),yt(Bt.dir,r);const l=this.world.castRayAndGetNormal(Bt,a,!1,o?.excludeTriggers?s.EXCLUDE_SENSORS:void 0,o?.collisionFilter,void 0,null!=o?.excludeActor?this.actorBodies.get(o.excludeActor.id):void 0);if(i.hasHit=null!=l,i.actor=void 0,i.hasHit&&(i._internal=l,mt(i.hitNormal,l.normal),i.hitPoint.copy(t).addScaledVector(r,l.timeOfImpact),i.distance=l.timeOfImpact,!1!==o?.resolveActor)){const t=l.collider.parent();i.actor=null!=t?this.bodyActors.get(t):null}return this.showDebug&&!1!==o?.debug&&null!=this.scene&&this.drawRayDebugArrow(r,t,a,o?.debugColor,o?.debugLifetime),i}drawRayDebugArrow(t,e,i,s=255,o=200){let n=this.rayDebugArrowPool.pop();null==n?n=new h(t,e,i,s,.2,.1):(n.setDirection(t),n.position.copy(e),n.setLength(i,.2,.1),n.setColor(s)),n.userData.physicsRayDebugExpiresAt=performance.now()+o,this.activeRayDebugArrows.push(n),this.scene.add(n)}releaseExpiredRayDebugArrows(){if(0===this.activeRayDebugArrows.length)return;const t=performance.now();let e=0;for(let i=0;i<this.activeRayDebugArrows.length;i++){const s=this.activeRayDebugArrows[i];s.userData.physicsRayDebugExpiresAt<=t?(s.removeFromParent(),this.rayDebugArrowPool.push(s)):this.activeRayDebugArrows[e++]=s}this.activeRayDebugArrows.length=e}clearRayDebugArrows(){for(const t of this.activeRayDebugArrows)t.removeFromParent(),this.rayDebugArrowPool.push(t);this.activeRayDebugArrows.length=0}setGravity(t,e,i){this.world.gravity.x=t,this.world.gravity.y=e,this.world.gravity.z=i}getGravity(){return Z.set(this.world.gravity.x,this.world.gravity.y,this.world.gravity.z)}addFromScene(t){this.addRecursively(t);for(const t of this.staticBodies.values())bt(t,t=>t.setActiveEvents(i.ActiveEvents.COLLISION_EVENTS))}addRecursively(t){if(this.removeSceneObject(t),!function(t){if(null!=t.userData?.src){const e=t.userData?.src;return"actor"===e.type}return!1}(t))if(t instanceof P&&null!=t.collisionShape){const e=this.createStaticBody(t,[t.collisionShape],t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}else if(t instanceof W){const e=!1!==t.userData?.src?.collisionDetection;if(t.children[0]&&(t.children[0].instanceMatrix&&e||t.children[0].isBatchedMesh))this.createForInstancedMesh(t.children[0],t.collisionShapes);else if(e&&t.children.length>0){const e=this.createStaticBody(t,t.collisionShapes,t.physics);this.staticMeshes.set(e,t),this.staticBodies.set(t,e)}0===t.children.length&&(t.matrixAutoUpdate=!1,t.matrixWorldAutoUpdate=!1)}else t instanceof j?this.addLandscapeGroup(t):(t instanceof y||t instanceof x)&&t.children.forEach(t=>this.addRecursively(t))}createForInstancedMesh(t,e){const i=new m;if(t instanceof d.BatchedMesh){const e=t._instanceInfo??t._drawInfo,s=new Map,o=t.userData.collisionMatrices;for(let n=0;n<e.length;n++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[n])continue;const e=t.userData.collisionShapes;let r=e?.[n];if(null==r&&null==e&&t.parent instanceof W&&(r=t.parent.collisionShapes),null==r)continue;const a=o?.[n];let l=r;null==a&&(l=s.get(r),null==l&&(l=this.instancedShapeReset(r),s.set(r,l)));const c=new b;c.matrix.identity(),null!=a?i.copy(a):t.getMatrixAt(n,i),c.applyMatrix4(i);this.createStaticBody(c,l)}}else{const s=this.instancedShapeReset(e);for(let e=0;e<t.count;e++){if(null!=t.userData.hasCollision&&!t.userData.hasCollision[e])continue;const o=new b;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*e),o.applyMatrix4(i);this.createStaticBody(o,s)}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>_(t))}getCharacterController(t){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i,o=null){const n=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const r=n.collider(0);e.computeColliderMovement(r,i,s.EXCLUDE_SENSORS,o,void 0);const a=e.computedMovement();return mt(ft,a),ft}setActorCapsuleCollider(t,e,i,s){const o=this.actorBodies.get(t.id),n=o?.collider(0);if(null==o||null==n)return!1;const r=t.object?.getWorldScale(vt)??et,a=Math.max(0,e*Math.abs(r.y)),l=Math.max(.001,i*Math.max(Math.abs(r.x),Math.abs(r.z)));return n.setHalfHeight(a/2),n.setRadius(l),ot.set(0,s,0).multiply(r),yt(it,ot),n.setTranslationWrtParent(it),o.recomputeMassPropertiesFromColliders(),o.isFixed()&&this.invalidateStaticDebug(),!0}hasActorCapsuleIntersection(t,e,i,o,n,r=null){const a=this.actorBodies.get(t.id),l=t.object?.getWorldScale(vt)??et,c=Math.max(0,i*Math.abs(l.y)),d=Math.max(.001,o*Math.max(Math.abs(l.x),Math.abs(l.z))),h=new this.rapier.Capsule(c/2,d),u=t.object?.getWorldQuaternion(H)??X;ot.set(0,n,0).multiply(l).applyQuaternion(u).add(e);return null!=this.world.intersectionWithShape(ot,u,h,s.EXCLUDE_SENSORS,r??void 0,void 0,a,xt)}createCollider(t,e){const i=this.addShape(e?.body,t),s=new PhysicsCollider(i,this.world,this.invalidateStaticDebug);return this.colliders.set(i.handle,s),(null==e||e.body.isFixed())&&this.invalidateStaticDebug(),s.disposed.subscribe(()=>{this.colliders.delete(i.handle)}),s}createBody(t=PhysicsBodyType.dynamic,e={}){const i=(()=>{switch(t){case PhysicsBodyType.dynamic:return this.rapier.RigidBodyDesc.dynamic();case PhysicsBodyType.static:return this.rapier.RigidBodyDesc.fixed();case PhysicsBodyType.kinematic:return this.rapier.RigidBodyDesc.kinematicPositionBased();case PhysicsBodyType.kinematicVelocityBased:return this.rapier.RigidBodyDesc.kinematicVelocityBased();default:return this.rapier.RigidBodyDesc.dynamic()}})();e.position&&i.setTranslation(e.position.x,e.position.y,e.position.z),e.rotation&&i.setRotation({x:e.rotation.x,y:e.rotation.y,z:e.rotation.z,w:e.rotation.w}),"boolean"==typeof e.canSleep&&i.setCanSleep(e.canSleep),"boolean"==typeof e.ccdEnabled&&i.setCcdEnabled(e.ccdEnabled),"number"==typeof e.gravityScale&&i.setGravityScale(e.gravityScale),"number"==typeof e.mass&&i.setAdditionalMass(e.mass),void 0!==e.userData&&(i.userData=e.userData);const s=this.world.createRigidBody(i);return s.isFixed()?this.invalidateStaticDebug():this.nonFixedBodies.add(s),new PhysicsBody(s,this.world,this.invalidateStaticDebug)}createJoint(t,e,i){let s,o;switch(i.type){case"fixed":s=this.rapier.JointData.fixed(i.anchor1,i.frame1,i.anchor2,i.frame2);break;case"spherical":s=this.rapier.JointData.spherical(i.anchor1,i.anchor2);break;case"revolute":s=this.rapier.JointData.revolute(i.anchor1,i.anchor2,i.axis),null!=i.limits&&(o=i.limits)}const n=this.world.createImpulseJoint(s,t.body,e.body,!0);if(null!=o){n.setLimits(o[0],o[1])}return n.setContactsEnabled(i.contactsEnabled??!1),new PhysicsJoint(n,this.world)}getCharacterComputedMovement(t,e,i,o=null){const n=t.collider;e.computeColliderMovement(n,i,s.EXCLUDE_SENSORS,o,void 0);const r=e.computedMovement();return mt(ft,r),ft}setNextKinematicTranslation(t,e){const i=this.actorBodies.get(t.id),s=i.translation(it);s.x+=e.x,s.y+=e.y,s.z+=e.z,i?.setNextKinematicTranslation(s)}setNextKinematicPosition(t,e){this.actorBodies.get(t.id).setNextKinematicTranslation(e)}setNextKinematicRotation(t,e){this.actorBodies.get(t.id).setNextKinematicRotation(e)}setNextKinematicTransform(t){!function(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setNextKinematicTranslation(dt(i)),t.setNextKinematicRotation(ht(s))}(this.actorBodies.get(t.id),t.object)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setAngvel(it,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.setLinvel(it,!0)}getLinearVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.linvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}getAngularVelocity(t,e=new v){const i=this.actorBodies.get(t.id);if(null==i)return e.set(0,0,0);const s=i.angvel();return e.x=s.x,e.y=s.y,e.z=s.z,e}setLinearDamping(t,e){const i=this.actorBodies.get(t.id);i?.setLinearDamping(e)}getLienarDamping(t){const e=this.actorBodies.get(t.id);return e?.linearDamping()??0}setAngularDamping(t,e){const i=this.actorBodies.get(t.id);i?.setAngularDamping(e)}getAngularDamping(t){const e=this.actorBodies.get(t.id);e?.angularDamping()}setPosition(t,e){const i=this.actorBodies.get(t.id);i?.setTranslation(dt(e),!1)}getPosition(t,e=new v){const i=this.actorBodies.get(t.id);i&&i.translation(e)}setRotation(t,e){const i=this.actorBodies.get(t.id);i?.setRotation(ht(e),!1)}getRotation(t,e=new f){const i=this.actorBodies.get(t.id);i&&function(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}(e,i.rotation())}lockTranslations(t,e){const i=this.actorBodies.get(t.id);i?.lockTranslations(e,!1)}lockRotations(t,e){const i=this.actorBodies.get(t.id);i?.lockRotations(e,!1)}setEnabledTranslations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledTranslations(e,i,s,!1)}setEnabledRotations(t,e,i,s){const o=this.actorBodies.get(t.id);o?.setEnabledRotations(e,i,s,!1)}addLandscapeGroup(t){this.invalidateStaticDebug();const e=t.userData.src,s=e.landscape.heightMaps;for(const n of t.sections){this.staticBodies.has(n)&&this.world.removeRigidBody(this.staticBodies.get(n));var o=n.getWorldPosition(new v);if(e.landscape.holes&&e.landscape.holes.some(t=>t.m===n.name&&0!==t.w[0])){const t=n.geometry.clone(),i=n.scale,s=n.geometry.getAttribute("hole"),r=new Float32Array(t.getAttribute("position").array);for(let t=0;t<r.length;t+=3)r[t]*=i.x,r[t+1]*=i.y,r[t+2]*=i.z;const a=t.index;for(let t=0;t<a.count;t+=3){const e=s.getX(a.getX(t)),i=s.getX(a.getY(t)),o=s.getX(a.getZ(t));(e>.5||i>.5||o>.5)&&(a.setX(t,0),a.setY(t,0),a.setZ(t,0))}const l=this.rapier.ColliderDesc.trimesh(r,new Uint32Array(t.getIndex().array));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);yt(e,o),t.setTranslation(e,!1),this.world.createCollider(l,t),this.staticBodies.set(n,t)}continue}const t=e.landscape.options.density+1,r=e.landscape.options.sectionSize,a=new Array(t);for(let e=0;e<t;e++)a[e]=new Array(t).fill(0);const l=s.find(t=>t.x===n.x&&t.y==n.y);if(null!=l)for(const e of l.points){if(null==a[e.i%t])continue;const i=t-1-Math.floor(e.i/t);i in a[e.i%t]?a[e.i%t][i]=e.y/r:console.warn("wrong index",{points:a,point:e,i:e.i%t,k:i,heightMap:l})}const c=e.landscape.options.density,d=a.flatMap(t=>t.reverse()),h=i.ColliderDesc.heightfield(c,c,new Float32Array(d),new this.rapier.Vector3(r,r,r));if(!1!==e.collisionDetection){const t=this.world.createRigidBody(this.rapier.RigidBodyDesc.fixed()),e=new this.rapier.Vector3(0,0,0);yt(e,o),t.setTranslation(e,!1),this.world.createCollider(h,t),this.staticBodies.set(n,t)}}}setEnabled(t,e){const i=this.actorBodies.get(t.id);i?.setEnabled(e),i?.isFixed()&&this.invalidateStaticDebug()}addActor(t,e,i={}){if(0==e.length)return void console.error("No collision shapes were defined when adding actor to the physics system.");this.removeActor(t);const s=t.object;let o;switch(i.type??PhysicsBodyType.static){case PhysicsBodyType.dynamic:o=this.rapier.RigidBodyDesc.dynamic(),o.mass=i.mass??1;break;case PhysicsBodyType.kinematic:o=this.rapier.RigidBodyDesc.kinematicPositionBased();break;case PhysicsBodyType.kinematicVelocityBased:o=this.rapier.RigidBodyDesc.kinematicVelocityBased();break;default:o=i.isTrigger?this.rapier.RigidBodyDesc.kinematicVelocityBased():this.rapier.RigidBodyDesc.fixed()}const n=this.world.createRigidBody(o);n.enableCcd(1==i.continousCollisionDetection);for(const t of e){const e=this.addShape(n,t,s);wt.set(e,!i.isTrigger)}return i.type!==PhysicsBodyType.static&&this.nonFixedBodies.add(n),bt(n,t=>{null!=i.isTrigger&&(t.setSensor(i.isTrigger),t.setActiveCollisionTypes(this.rapier.ActiveCollisionTypes.ALL),t.setActiveEvents(this.rapier.ActiveEvents.COLLISION_EVENTS)),null!=i.friction&&t.setFriction(i.friction),null!=i.density&&t.setDensity(i.density),null!=i.mass&&t.setMass(i.mass),null!=i.restitution&&t.setRestitution(i.restitution)}),Y(n,s),!0===i.ignoreForNavMesh&&(n.userData={ignoreForNavMesh:!0}),this.actorBodies.set(t.id,n),this.bodyActors.set(n,t),n.isFixed()&&this.invalidateStaticDebug(),new PhysicsBody(n,this.world,this.invalidateStaticDebug)}applyTorque(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addTorque(it,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyTorqueImpulse(it,!0)}resetForces(t){const e=this.actorBodies.get(t.id);e?.resetForces(!1)}resetTorques(t){const e=this.actorBodies.get(t.id);e?.resetTorques(!1)}applyForce(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.addForce(it,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);it.x=e.x,it.y=e.y,it.z=e.z,i?.applyImpulse(it,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);yt(it,e),null==i?s?.addForce(it,!0):(yt(st,i),s?.addForceAtPoint(it,st,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);yt(it,e),null==i?s.applyImpulse(it,!0):(yt(st,i),s.applyImpulseAtPoint(it,st,!0))}applyRadialImpulse(t,e,i){return e<=0||0===i?0:this.applyImpulseToBodiesInRadius(t,e,(t,s,o)=>{o<=1e-6?s.set(0,1,0):s.multiplyScalar(1/o),s.multiplyScalar(i*Math.max(0,1-o/e)),yt(it,s),t.applyImpulse(it,!0)})}applyDirectionalImpulse(t,e,i,s,o){if(i<=0||0===o||e.lengthSq()<=1e-12)return 0;nt.copy(e).normalize();const n=Math.cos(Math.max(0,Math.min(Math.PI,s)));return this.applyImpulseToBodiesInRadius(t,i,(t,e,i)=>{if(i>1e-6&&e.multiplyScalar(1/i).dot(nt)<n)return!1;it.x=nt.x*o,it.y=nt.y*o,it.z=nt.z*o,t.applyImpulse(it,!0)})}applyImpulseToBodiesInRadius(t,e,i){const o=at,n=lt;o.clear(),n.length=0;let r=0;this.world.intersectionsWithShape(t,X,this.getBallShape(e),t=>{const e=t.parent();return null==e||o.has(e.handle)||(o.add(e.handle),n.push(e)),!0},s.ONLY_DYNAMIC|s.EXCLUDE_SENSORS);for(const e of n)mt(rt,e.worldCom()),rt.sub(t),!1!==i(e,rt,rt.length())&&r++;return o.clear(),n.length=0,r}removeActor(t){if(null==t)return;this.controlledActors.delete(t.id);const e=this.actorBodies.get(t.id);null!=e&&(e.isFixed()&&this.invalidateStaticDebug(),this.bodyActors.delete(e),this.world.removeRigidBody(e),this.nonFixedBodies.delete(e)),this.actorBodies.delete(t.id)}removeRemoved(t){if(null==t)return;const e=new Set;t.traverse(t=>{e.add(t.uuid)});for(const[t,i]of this.staticBodies.entries())e.has(t.uuid)&&this.world.getRigidBody(i.handle)&&(this.invalidateStaticDebug(),this.staticBodies.delete(t),this.world.removeRigidBody(i),this.nonFixedBodies.delete(i))}removeSceneObject(t){if(t instanceof j){for(const e of t.sections)this.removeSceneObject(e);return}let e=this.staticBodies.get(t);null!=e&&this.world.getRigidBody(e.handle)&&(this.invalidateStaticDebug(),this.world.removeRigidBody(e),this.nonFixedBodies.delete(e)),this.staticBodies.delete(t)}activateActorEvents(t){this.actorBodies.get(t.id)}_onCollisionWithActorEvent(t,e,i){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(({started:t})=>t===i),a(({handle1:t,handle2:e,started:i})=>({a1:this.bodyActors.get(this.world.getCollider(t)?.parent()),a2:this.bodyActors.get(this.world.getCollider(e)?.parent()),started:i})),r(({a1:i,a2:s})=>null!=i&&null!=s&&i.id===t.id&&e(i,s)),a(({a2:t})=>t))}onBeginContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onEndContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(c(t.disposed),r(t=>!t.started),r(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),a(t=>t.handle2))}onHasContactChanged(t){const e=new Set,i=new o(!1);return this.onBeginContact(t).subscribe(t=>{e.add(t),i.next(e.size>0)}),this.onEndContact(t).subscribe(t=>{e.delete(t),i.next(e.size>0)}),i.pipe(n())}onBeginOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!0)}onEndOverlap(t){return this._onCollisionWithActorEvent(t,()=>!0,!1)}onBeginOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!0)}onEndOverlapWithActorType(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>i instanceof e,!1)}onBeginOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!0)}onEndOverlapWithActor(t,e){return this._onCollisionWithActorEvent(t,(t,i)=>e.id===i.id,!1)}onCollisionWithActor(t,e){return this.onBeginOverlapWithActor(t,e)}onCollisionWithActorType(t,e){return this.onBeginOverlapWithActorType(t,e)}updateActorTransform(t){const e=this.actorBodies.get(t.id);null!=e&&(Y(e,t.object),e.isFixed()&&this.invalidateStaticDebug())}flushModifiedBodyPositionsToColliders(){this.world.propagateModifiedBodyPositionsToColliders()}setupWorld(){const t=new this.rapier.World({x:0,y:-9.81,z:0});this.world=t,this.invalidateStaticDebug()}sphereCast(t,e,i,o,n=ShapeCastResult.shared,r){n.reset();const a=this.getBallShape(e);it.x=i.x,it.y=i.y,it.z=i.z;const l=r?.excludeActor?this.actorBodies.get(r.excludeActor.id):null,c=this.world.castShape(t,X,it,a,.01,o,!0,r?.excludeTriggers?s.EXCLUDE_SENSORS:void 0,r?.collisionFilter??void 0,null,l);if(null!=c){mt(n.hitPoint,c.witness1),n.normal.set(c.normal1.x,c.normal1.y,c.normal1.z),n.distance=c.time_of_impact,n.hasHit=!0;const t=c.collider.parent();if(t){const e=this.bodyActors.get(t);e&&(n.actor=e)}}return n}castActorShape(t,e,i,s=ShapeCastResult.shared,o=void 0){s.reset();const n=this.actorBodies.get(t.id);if(n&&n.numColliders()>0){for(let t=0;t<n.numColliders();t++){const r=n.collider(t);let a=r.shape,l=r.translation(),c=r.rotation(),d=e,h=i;const u=this.world.castShape(l,c,d,a,.01,h,!0,null,o,null,n,void 0);if(null!=u){u.collider;const t=r;return mt(s.hitPoint,u.witness1),St(t.rotation(),u.normal1,s.normal,q),s.distance=u.time_of_impact,s.actor=this.bodyActors.get(u.collider.parent()),s.hasHit=!0,s}}return s}return console.warn("Actor is not added to the physics system"),s}stop(){if(!this._isStopped){this._isStopped=!0,this.bodyActors.clear(),this.actorBodies.clear(),this.staticBodies.clear(),this.staticMeshes.clear(),this.colliders.clear(),this.fixedupdateSub?.unsubscribe(),this.collisionSub?.unsubscribe(),this.world?.bodies.forEach(t=>{this.world.removeRigidBody(t),this.nonFixedBodies.delete(t)});try{this.eventQueue?.free()}catch(t){console.warn("Error when freeing physics event queue",t)}try{this.world?.free(),this.world=void 0}catch(t){console.warn("Error while freeing physics world",t)}this.clearRayDebugArrows();for(const t of this.rayDebugArrowPool)t.dispose();this.rayDebugArrowPool.length=0}}createStaticBody(t,e,s){const o=s?.type===PhysicsBodyType.dynamic?i.RigidBodyDesc.dynamic():i.RigidBodyDesc.fixed(),n=this.world.createRigidBody(o);s?.type===PhysicsBodyType.dynamic&&this.nonFixedBodies.add(n);let r=0;for(const i of e){if(r>128){console.warn("Too many collision shapes for object",t);break}if(r++,null==i){console.warn("Collision shape is missing for object",t);continue}const o=this.addShape(n,i,t);null!=o&&(null!=s?.friction&&o.setFriction(s.friction),null!=s?.density&&o.setDensity(s.density),null!=s?.mass&&o.setMass(s.mass/e.length),null!=s?.restitution&&o.setRestitution(s.restitution))}return Y(n,t),n.userData=t.uuid,n.isFixed()&&this.invalidateStaticDebug(),n}addShape(t=void 0,e,i){const s=i?.getWorldScale(vt)??et,o=this.createShape(e,s);if(null==o)return void console.error("Failed to create physics shape. This can happen if the geometry is degenerate or zero-scaled.",{shapeInfo:e,object:i});this.applyShapeSettings(o,e);const n=e.offset.clone().multiply(s);yt(o.translation,n);const r=(new f).setFromEuler(e.rotation);gt(o.rotation,r),null!=t&&t.numColliders()>128&&console.warn(`Rigid body has many colliders (${t.numColliders()}). Consider using a Trimesh if this is static geometry.`,t);try{return this.world.createCollider(o,t)}catch(t){return void console.error("Failed to create collider",t)}}applyShapeSettings(t,e){null!=e.collisionGroup&&t.setCollisionGroups(e.collisionGroup),t.friction=e.friction??.1,null!=e.restitution&&(t.restitution=e.restitution),null!=e.density&&(t.density=e.density,t.massPropsMode=i.MassPropsMode.Density),null!=e.mass&&(t.mass=e.mass,t.massPropsMode=i.MassPropsMode.Mass)}createShape(t,e){if(t instanceof R)return this.rapier.ColliderDesc.cuboid(t.dimensions.x*e.x/2,t.dimensions.y*e.y/2,t.dimensions.z*e.z/2);if(t instanceof M){return this.rapier.ColliderDesc.capsule(t.length/2*e.y,t.radius*Math.max(e.z,e.x))}if(t instanceof N){const i=null!=t.geometry.getIndex()?t.geometry:B.mergeVertices(t.geometry),s=extractFloat32Array(i.getAttribute("position"));for(let t=0;t<s.length;t+=3)s[t]*=e.x,s[t+1]*=e.y,s[t+2]*=e.z;const o=i.getIndex();return null==o?(console.error("Trimesh collision shape is missing an index buffer.",t),null):this.rapier.ColliderDesc.trimesh(s,new Uint32Array(o.array))}if(t instanceof T){let i,s;t.mesh instanceof d.Mesh?i=t.mesh.geometry:t.mesh instanceof d.BufferGeometry?i=t.mesh:console.log("Unknownd shape",{shapeInfo:t}),t.mesh instanceof d.Mesh&&(s=L(t.mesh));const o=`${i.uuid}|${s?.x??1},${s?.y??1},${s?.z??1}|${e.x},${e.y},${e.z}`,n=tt.get(o);if(void 0!==n)return n;const r=extractFloat32Array(i.getAttribute("position"));if(null!=s)for(let t=0;t<r.length;t+=3)r[t]*=s.x,r[t+1]*=s.y,r[t+2]*=s.z;for(let t=0;t<r.length;t+=3)r[t]*=e.x,r[t+1]*=e.y,r[t+2]*=e.z;const a=this.rapier.ColliderDesc.convexHull(r);return null==a&&console.error("Failed to compute convex hull. Points may be coplanar or too few.",{count:r.length/3}),tt.set(o,a),a}if(t instanceof I){const i=2*e.x-e.y-e.z;return Math.abs(i)>.01?this.createShape(new T(new d.SphereGeometry(t.radius).scale(e.x,e.y,e.z)),new v(1,1,1)):this.rapier.ColliderDesc.ball(t.radius*Math.max(e.x,e.y,e.z))}return t instanceof z?this.rapier.ColliderDesc.cylinder(t.height/2*e.y,t.radiusTop*Math.max(e.z,e.x)):t instanceof E?this.rapier.ColliderDesc.cone(t.height*e.y,t.radiusBottom/2*Math.max(e.z,e.x)):t instanceof F?this.rapier.ColliderDesc.cuboid(t.width/2*e.x,t.height/2*e.y,.001):(console.error("Unsupported shape",t),this.rapier.ColliderDesc.cuboid(1,1,1))}createCharacterCollision(){return new this.rapier.CharacterCollision}};Q=t([D(),e("design:paramtypes",[])],Q);export{Q as PhysicsSystem};const J=new v,$=new d.Quaternion;function Y(t,e){const i=e.getWorldPosition(J),s=e.getWorldQuaternion($);t.setTranslation(dt(i),!1),t.setRotation(ht(s),!1)}const Z=new v,tt=new Map,et=new v(1,1,1),it=new i.Vector3(0,0,0),st=new i.Vector3(0,0,0),ot=new v,nt=new v,rt=new v,at=new Set,lt=[],ct=new d.Vector2;function dt(t){return yt(it,t),it}function ht(t){return gt(q,t),q}let ut=null;const pt=async()=>(null==ut&&(ut=(async()=>{let t=await import("@dimforge/rapier3d-simd-compat");return await t.init(),t})()),ut);function yt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function gt(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function mt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function bt(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const ft=new v,wt=new WeakMap,xt=t=>wt.get(t)??!0,vt=new v;let Bt,Dt=class extends S{constructor(){super(...arguments),this._active=!0,this.physics=C(Q),this.world=C(O)}set active(t){this._active=t,t?(this.world.scene.remove(this.actor.object),this.physics.setEnabled(this.actor,t)):(this.world.scene.add(this.actor.object),this.physics.setEnabled(this.actor,t))}get active(){return this._active}};Dt=t([A()],Dt);export function extractFloat32Array(t){const e=t.itemSize,i=t.count,s=new Float32Array(i*e);for(let o=0;o<i;o++)for(let i=0;i<e;i++)s[o*e+i]=t.getComponent(o,i);return s}function St(t,e,i,s){return s.set(t.x,t.y,t.z,t.w),i.set(e.x,e.y,e.z),i.applyQuaternion(s),i}export class PhysicsCollider{constructor(t,e,i){this.collider=t,this.world=e,this.invalidateStaticDebug=i,this.disposed=new l,this.onBeginOverlapActor=new l,this.onEndOverlapActor=new l}dispose(){const t=this.collider.parent();(null==t||t.isFixed())&&this.invalidateStaticDebug?.(),this.world.removeCollider(this.collider,!1),this.disposed.next(!0),this.disposed.complete(),this.onBeginOverlapActor.complete(),this.onEndOverlapActor.complete()}set mass(t){this.collider.setMass(t)}get mass(){return this.collider.mass()}set friction(t){this.collider.setFriction(t)}get friction(){return this.collider.friction()}set restitution(t){this.collider.setRestitution(t)}get restitution(){return this.collider.restitution()}set density(t){this.collider.setDensity(t)}get density(){return this.collider.density()}set isTrigger(t){this.collider.setSensor(t)}get isTrigger(){return this.collider.isSensor()}set collisionGroups(t){this.collider.setCollisionGroups(t)}get collisionGroups(){return this.collider.collisionGroups()}set enabled(t){this.collider.setEnabled(t);const e=this.collider.parent();(null==e||e.isFixed())&&this.invalidateStaticDebug?.()}get enabled(){return this.collider.isEnabled()}}export class PhysicsBody{constructor(t,e,i){this.invalidateStaticDebug=i,this.body=t,this.world=e}dispose(){this.body.isFixed()&&this.invalidateStaticDebug?.(),this.world.removeRigidBody(this.body)}setEnabled(t){this.body.setEnabled(t),this.body.isFixed()&&this.invalidateStaticDebug?.()}isEnabled(){return this.body.isEnabled()}getPosition(t){return this.body.translation(t)}setPosition(t){this.body.setTranslation({x:t.x,y:t.y,z:t.z},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getRotation(t){const e=this.body.rotation();return t.set(e.x,e.y,e.z,e.w),t}setRotation(t){this.body.setRotation({x:t.x,y:t.y,z:t.z,w:t.w},!0),this.body.isFixed()&&this.invalidateStaticDebug?.()}getLinearVelocity(t){const e=this.body.linvel();return t.set(e.x,e.y,e.z),t}setLinearVelocity(t){this.body.setLinvel({x:t.x,y:t.y,z:t.z},!0)}getAngularVelocity(t){const e=this.body.angvel();return t.set(e.x,e.y,e.z),t}setAngularVelocity(t){this.body.setAngvel({x:t.x,y:t.y,z:t.z},!0)}setLinearDamping(t){this.body.setLinearDamping(t)}setAngularDamping(t){this.body.setAngularDamping(t)}applyImpulse(t,e=!0){this.body.applyImpulse({x:t.x,y:t.y,z:t.z},e)}applyTorqueImpulse(t,e=!0){this.body.applyTorqueImpulse({x:t.x,y:t.y,z:t.z},e)}setNextKinematicPosition(t){this.body.setNextKinematicTranslation(t)}setNextKinematicRotation(t){this.body.setNextKinematicRotation(t)}setType(t){const e=this.body.isFixed();this.body.setBodyType(function(t){switch(t){case PhysicsBodyType.dynamic:return i.RigidBodyType.Dynamic;case PhysicsBodyType.static:return i.RigidBodyType.Fixed;case PhysicsBodyType.kinematic:return i.RigidBodyType.KinematicPositionBased;case PhysicsBodyType.kinematicVelocityBased:return i.RigidBodyType.KinematicVelocityBased}}(t),t!==PhysicsBodyType.static),(e||this.body.isFixed())&&this.invalidateStaticDebug?.()}setGravityScale(t){this.body.setGravityScale(t,!1)}getGravityScale(){return this.body.gravityScale()}isDynamic(){return this.body.isDynamic()}isKinematic(){return this.body.isKinematic()}isStatic(){return this.body.isFixed()}sleep(){this.body.sleep()}wakeUp(){this.body.wakeUp()}}export class PhysicsJoint{constructor(t,e){this.joint=t,this.world=e}dispose(){this.joint.isValid()&&this.world.removeImpulseJoint(this.joint,!0)}setContactsEnabled(t){this.joint.setContactsEnabled(t)}get contactsEnabled(){return this.joint.contactsEnabled()}}/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -136,7 +136,7 @@ export declare class ViewController {
|
|
|
136
136
|
*/
|
|
137
137
|
setInterval(callback: () => void, intervalMs: number, owner?: BaseActor): number;
|
|
138
138
|
clearInterval(intervalId: number): void;
|
|
139
|
-
dispose(): void;
|
|
139
|
+
dispose(stopRenderingView?: boolean): void;
|
|
140
140
|
/**
|
|
141
141
|
* Creates a timer that emits once after the specified duration (in milliseconds),
|
|
142
142
|
* pausing when the view is paused and resuming when unpaused.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as u,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get webGpuDevice(){return this.view.webGpuDevice}get experimentalWebGpuDevice(){return this.webGpuDevice}registerWebGpuRenderGraphExtension(e){return this.view.registerWebGpuRenderGraphExtension(e)}registerExperimentalWebGpuRenderGraphExtension(e){return this.registerWebGpuRenderGraphExtension(e)}handleFrame(e){let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setProfilingEnabled(e){this.view.setProfilingEnabled(e)}getLastFrameProfile(){return this.view.getLastFrameProfile()}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(S)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){u(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),P.setFromEuler(x),e.quaternion.copy(k).multiply(P),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=g){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(){this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(v.setFromProjectionMatrix(p),!v.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,g=new o.Vector2,v=new o.Frustum,S=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),P=new o.Quaternion;/*
|
|
1
|
+
import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{RenderingView as r}from"../../rendering.js";import{BehaviorSubject as s,Subject as n,takeUntil as h}from"rxjs";import*as o from"three";import{GameTimeScheduler as m}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as u,sampleCameraShake as c}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let d=class{constructor(e){this.view=e,this.tick=new n,this.lateTick=new n,this.audioListener=new o.AudioListener,this.pausedChanged=new s(!1),this.mutedChanged=new s(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new m,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this.outlined=[],this.baseCamera=e.camera,this.sourceCamera=e.camera,e.onLoop(e=>{this.handleFrame(e)}),e.camera.add(this.audioListener),window.hology_view=this}get activeBackend(){return this.view.activeBackend}get requestedBackend(){return this.view.requestedBackend}get vfxBackendPreference(){return this.view.vfxBackendPreference}get webgpuVfxInstancesPerTemplate(){return this.view.webgpuVfxInstancesPerTemplate}get webgpuVfxTemplateMemoryBudgetBytes(){return this.view.webgpuVfxTemplateMemoryBudgetBytes}get webgpuVfxWorldMemoryBudgetBytes(){return this.view.webgpuVfxWorldMemoryBudgetBytes}get webgpuVfxColdTemplateSeconds(){return this.view.webgpuVfxColdTemplateSeconds}get webGpuDevice(){return this.view.webGpuDevice}get experimentalWebGpuDevice(){return this.webGpuDevice}registerWebGpuRenderGraphExtension(e){return this.view.registerWebGpuRenderGraphExtension(e)}registerExperimentalWebGpuRenderGraphExtension(e){return this.registerWebGpuRenderGraphExtension(e)}handleFrame(e){let t=this._timeScale,a=0;this._hitStopRemaining>0?(this._hitStopRemaining-=1e3*e,this._hitStopRemaining<=0&&(this._hitStopRemaining=0),t=0):a=e*this._timeScale,this.advanceGameplayCameraShakes(a),this.tick.next(a),this.scheduler.update(1e3*a),this.lateTick.next(a),this.view.simulationTimeScale=t,this.refreshCameraPresentation()}set timeScale(e){this._timeScale=Math.max(0,e)}get timeScale(){return this._timeScale}applyHitStop(e){this._hitStopRemaining=Math.max(this._hitStopRemaining,e)}set fpsCap(e){this.view.fpsCap=e}get fpsCap(){return this.view.fpsCap}set showStats(e){this.view.showStats=e}get showStats(){return this.view.showStats}setProfilingEnabled(e){this.view.setProfilingEnabled(e)}getLastFrameProfile(){return this.view.getLastFrameProfile()}setLightVolume(e){this.view.lightVolume=e}getLightVolume(){return this.view.lightVolume}addPostProcessVolume(e){this.view.addPostProcessVolume(e)}removePostProcessVolume(e){this.view.removePostProcessVolume(e)}addPostProcessEffect(e,t){return this.view.addPostProcessEffect(e,t)}onUpdate(e){return null==e?this.tick:this.tick.pipe(h(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(h(e.disposed))}setCamera(e){const t=e instanceof i?e:e.camera.instance;this.baseCamera=t,0===this.cameraOverrides.length&&(this.sourceCamera=t,this.refreshCameraPresentation())}getCamera(){return this.view.camera}getSourceCamera(){return this.sourceCamera}getBaseCamera(){return this.baseCamera}applyCameraShake(e){const t=function(e){return{duration:Math.max(0,e.duration??0),attack:e.attack??0,decay:e.decay??0,frequency:e.frequency??24,positionAmplitude:e.positionAmplitude?[...e.positionAmplitude]:[0,0,0],rotationAmplitude:e.rotationAmplitude?[...e.rotationAmplitude]:[0,0,0],seed:e.seed}}(e);if(t.duration<=0)return{release:()=>{}};const a={id:++this.cameraShakeId,request:t,elapsedTime:0,seedOverride:t.seed};this.gameplayCameraShakes.push(a),this.refreshCameraPresentation();let i=!1;return{release:()=>{i||(i=!0,this.releaseGameplayCameraShake(a.id))}}}setCameraShakeContribution(e,t,a,i,r){if(a.duration<=0)return void this.removeCameraShakeContribution(e,t);let s=this.cameraShakeContributions.get(e);s||(s=new Map,this.cameraShakeContributions.set(e,s));const n=s.get(t);n?(n.request=a,n.elapsedTime=Math.max(0,i),n.seedOverride=r):s.set(t,{key:t,request:a,elapsedTime:Math.max(0,i),seedOverride:r}),this.refreshCameraPresentation()}removeCameraShakeContribution(e,t){const a=this.cameraShakeContributions.get(e);a?.delete(t)&&(0===a.size&&this.cameraShakeContributions.delete(e),this.refreshCameraPresentation())}clearCameraShakeContributionsForOwner(e){this.cameraShakeContributions.delete(e)&&this.refreshCameraPresentation()}pushCameraOverride(e,t,a=0){const i={id:++this.cameraOverrideId,camera:e,owner:t,priority:a};this.cameraOverrides.push(i),this.applyTopCameraOverride();let r=!1;return{release:()=>{r||(r=!0,this.releaseCameraOverrideEntry(i))}}}releaseCameraOverridesForOwner(e){const t=this.cameraOverrides.filter(t=>t.owner!==e);t.length!==this.cameraOverrides.length&&(this.cameraOverrides=t,this.applyTopCameraOverride())}releaseCameraOverrideEntry(e){const t=this.cameraOverrides.indexOf(e);-1!==t&&(this.cameraOverrides.splice(t,1),this.applyTopCameraOverride())}applyTopCameraOverride(){const e=this.getTopCameraOverride();this.sourceCamera=e?.camera??this.baseCamera,this.refreshCameraPresentation()}getTopCameraOverride(){let e;for(const t of this.cameraOverrides)(!e||t.priority>e.priority||t.priority===e.priority&&t.id>e.id)&&(e=t);return e}applyRenderedCamera(e){this.view.camera!==e&&this.view.setCamera(e),e.add(this.audioListener)}releaseGameplayCameraShake(e){const t=this.gameplayCameraShakes.findIndex(t=>t.id===e);-1!==t&&(this.gameplayCameraShakes.splice(t,1),this.refreshCameraPresentation())}advanceGameplayCameraShakes(e){if(!(e<=0||0===this.gameplayCameraShakes.length))for(let t=this.gameplayCameraShakes.length-1;t>=0;t--){const a=this.gameplayCameraShakes[t];a.elapsedTime+=e,a.elapsedTime>a.request.duration&&this.gameplayCameraShakes.splice(t,1)}}refreshCameraPresentation(){if(!this.hasActiveCameraShake())return void this.applyRenderedCamera(this.sourceCamera);const e=this.ensurePresentationCamera();this.copyCameraState(this.sourceCamera,e),this.accumulateCameraShakeSamples(),this.applyCameraShakeSample(e),this.applyRenderedCamera(e)}hasActiveCameraShake(){if(this.gameplayCameraShakes.length>0)return!0;for(const e of this.cameraShakeContributions.values())if(e.size>0)return!0;return!1}ensurePresentationCamera(){return this.presentationCamera||(this.presentationCamera=new o.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(S)),t.quaternion.copy(e.getWorldQuaternion(w)),t.scale.copy(e.getWorldScale(f)),t.layers.mask=e.layers.mask,e instanceof o.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect,t.zoom=e.zoom,t.focus=e.focus,t.filmGauge=e.filmGauge,t.filmOffset=e.filmOffset,t.view=null==e.view?null:{enabled:e.view.enabled,fullWidth:e.view.fullWidth,fullHeight:e.view.fullHeight,offsetX:e.view.offsetX,offsetY:e.view.offsetY,width:e.view.width,height:e.view.height},t.updateProjectionMatrix()):(t.projectionMatrix.copy(e.projectionMatrix),t.projectionMatrixInverse.copy(e.projectionMatrixInverse))}accumulateCameraShakeSamples(){u(this.accumulatedCameraShakeSample);for(let e=0;e<this.gameplayCameraShakes.length;e++)this.accumulateCameraShakeEntry(this.gameplayCameraShakes[e]);for(const e of this.cameraShakeContributions.values())for(const t of e.values())this.accumulateCameraShakeEntry(t)}accumulateCameraShakeEntry(e){const t=c(e.request,e.elapsedTime,this.scratchCameraShakeSample,e.seedOverride);if(t)for(let e=0;e<3;e++)this.accumulatedCameraShakeSample.position[e]+=t.position[e],this.accumulatedCameraShakeSample.rotation[e]+=t.rotation[e]}applyCameraShakeSample(e){k.copy(e.quaternion),y.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),y.applyQuaternion(k),e.position.add(y),x.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),P.setFromEuler(x),e.quaternion.copy(k).multiply(P),e.updateMatrixWorld(!0)}setMuted(e){this._muted=e,this.applyAudioGain(),this.mutedChanged.next(e)}getMuted(){return this._muted}set masterVolume(e){this._masterVolume=Math.min(Math.max(e,0),1),this.applyAudioGain()}get masterVolume(){return this._masterVolume}set cameraShakeIntensity(e){this._cameraShakeIntensity=Math.min(Math.max(e,0),1),this.refreshCameraPresentation()}get cameraShakeIntensity(){return this._cameraShakeIntensity}applyAudioGain(){this.audioListener.gain.gain.setValueAtTime(this._muted?0:this._masterVolume,this.audioListener.context.currentTime)}setOutlined(e){this.outlined.length=0;const t=this.outlined;for(let a=0;a<e.length;a++)t[a]=e[a];this.view.setSelectedObjects(t),this.view.setEnableOutlines(e.length>0)}getOutlined(){return this.outlined}addOutlined(e){this.outlined.includes(e)||(this.outlined.push(e),this.view.setSelectedObjects(this.outlined),this.view.setEnableOutlines(!0))}removeOutlined(e){const t=this.outlined.indexOf(e);-1!==t&&(this.outlined.splice(t,1),this.view.setSelectedObjects(this.outlined))}setOutlineColor(e){this.view.outlinePass?.visibleEdgeColor.copy(e)}getOutlineColor(){return this.view.outlinePass?.visibleEdgeColor}setOutlineThickness(e){this.view.outlinePass.edgeThickness=e}getOutlineThickness(){return this.view.outlinePass.edgeThickness}get htmlElement(){return this.view.container}getViewportSize(e=g){return this.view.getClientSize(e)}get paused(){return this.view.paused}set paused(e){e!=this.paused&&(e?this.pauseRendering():this.unpauseRendering())}pauseRendering(){this.view.paused=!0,this.pausedChanged.next(this.view.paused),this.scheduler.pause()}unpauseRendering(){this.view.paused=!1,this.pausedChanged.next(this.view.paused),this.scheduler.resume()}setInterval(e,t,a){return this.scheduler.setInterval(e,t,a)}clearInterval(e){this.scheduler.clearInterval(e)}dispose(e=!0){e&&this.view.running&&this.view.stop(),this.scheduler.dispose(),this.cameraOverrides.length=0,this.gameplayCameraShakes.length=0,this.cameraShakeContributions.clear(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=C,a=this.getViewportSize()){const i=this.getCamera();return p.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof o.PerspectiveCamera&&(v.setFromProjectionMatrix(p),!v.containsPoint(e))?null:(t.copy(e),t.project(i),t.x=(t.x+1)/2*a.x,t.y=(1-t.y)/2*a.y,t)}};d=e([a(),t("design:paramtypes",[r])],d);export{d as ViewController};const p=new o.Matrix4,C=new o.Vector3,g=new o.Vector2,v=new o.Frustum,S=new o.Vector3,f=new o.Vector3,w=new o.Quaternion,k=new o.Quaternion,y=new o.Vector3,x=new o.Euler(0,0,0,"XYZ"),P=new o.Quaternion;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { World } from './world.js';
|
|
2
|
+
import { SceneRef } from '../../scene/scene-ref.js';
|
|
3
|
+
export type SceneTransitionRequest = {
|
|
4
|
+
scene: SceneRef;
|
|
5
|
+
/** Runs after destination actors and physics exist, but before gameplay resumes. */
|
|
6
|
+
afterLoad?: (world: World) => void | Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
export type SceneTransitionEvent = {
|
|
9
|
+
previousSceneName: string;
|
|
10
|
+
sceneName: string;
|
|
11
|
+
};
|
|
12
|
+
/** Injectable, session-scoped API for replacing the active scene in-place. */
|
|
13
|
+
export declare class SceneTransitionService {
|
|
14
|
+
private handler?;
|
|
15
|
+
private readonly transitionedSubject;
|
|
16
|
+
readonly transitioned$: import("rxjs").Observable<SceneTransitionEvent>;
|
|
17
|
+
transitionTo(request: SceneTransitionRequest | SceneRef | string): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=scene-transition.d.ts.map
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{__decorate as e}from"tslib";import{Subject as t}from"rxjs";import{SceneRef as i}from"../../scene/scene-ref.js";import{Service as s}from"../../gameplay/index.js";let n=class{constructor(){this.transitionedSubject=new t,this.transitioned$=this.transitionedSubject.asObservable()}bind(e){this.handler=e}transitionTo(e){return null==this.handler?Promise.reject(new Error("SceneTransitionService is not attached to an active game session")):this.handler("string"==typeof e?{scene:new i(e,e)}:e instanceof i?{scene:e}:e)}publish(e){this.transitionedSubject.next(e)}dispose(){this.handler=void 0,this.transitionedSubject.complete()}};n=e([s()],n);export{n as SceneTransitionService};/*
|
|
2
|
+
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
|
+
* See the LICENSE.md file for details.
|
|
4
|
+
*/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Constructable } from "typedi";
|
|
2
|
-
import { BaseActor } from '../actors/actor.js';
|
|
2
|
+
import { ActorLifetime, BaseActor } from '../actors/actor.js';
|
|
3
3
|
import { Euler, Scene, Vector3 } from 'three';
|
|
4
4
|
import { Observable } from 'rxjs';
|
|
5
5
|
import { RenderingView } from "../../rendering.js";
|
|
6
|
-
import { Prefab } from "../../scene/objects/prefab.js";
|
|
6
|
+
import { Prefab, PrefabOf } from "../../scene/objects/prefab.js";
|
|
7
7
|
import type { SceneMaterializer } from "../../scene/materializer.js";
|
|
8
8
|
import { PrefabInstance } from '../../scene/objects/prefab.js';
|
|
9
9
|
import { BasePlayerController } from "../actors/controller/actor-controller.js";
|
|
@@ -26,7 +26,13 @@ declare class DirectionalLightController {
|
|
|
26
26
|
get position(): Vector3;
|
|
27
27
|
}
|
|
28
28
|
export type ActorSpawnOptions = {
|
|
29
|
-
owner
|
|
29
|
+
owner?: BaseActor;
|
|
30
|
+
/** Overrides actor metadata. Runtime spawns default to scene lifetime. */
|
|
31
|
+
lifetime?: ActorLifetime;
|
|
32
|
+
};
|
|
33
|
+
export type PrefabSpawnOptions = {
|
|
34
|
+
/** Applies to the entire prefab, including its main actor and every child actor. */
|
|
35
|
+
lifetime?: ActorLifetime;
|
|
30
36
|
};
|
|
31
37
|
export declare class World {
|
|
32
38
|
private actorFactory;
|
|
@@ -36,13 +42,16 @@ export declare class World {
|
|
|
36
42
|
private assetsProvider;
|
|
37
43
|
private eventGraphAssets;
|
|
38
44
|
readonly actors: BaseActor[];
|
|
45
|
+
private readonly actorLifetimes;
|
|
46
|
+
private readonly actorPrefabInstances;
|
|
47
|
+
private readonly prefabInstances;
|
|
39
48
|
readonly actorAdded: Observable<BaseActor>;
|
|
40
49
|
readonly actorRemoved: Observable<BaseActor>;
|
|
41
50
|
scene: Scene;
|
|
42
51
|
readonly directionalLight: DirectionalLightController;
|
|
43
52
|
private readonly sceneEventGraphs;
|
|
44
53
|
private readonly sceneEventGraphSubscriptions;
|
|
45
|
-
spawnActor<T extends BaseActor>(type: Constructable<T>, position?: Vector3, rotation?: Euler, options?: ActorSpawnOptions): Promise<T>;
|
|
54
|
+
spawnActor<T extends BaseActor>(type: Constructable<T> | PrefabOf<T>, position?: Vector3, rotation?: Euler, options?: ActorSpawnOptions): Promise<T>;
|
|
46
55
|
/**
|
|
47
56
|
* Spawn the player controller to run locally.
|
|
48
57
|
* This is only called by the server and if it is not a dedicated server in
|
|
@@ -50,7 +59,7 @@ export declare class World {
|
|
|
50
59
|
* It sets isLocallyControlled to true
|
|
51
60
|
*/
|
|
52
61
|
spawnLocalPlayerController<T extends BasePlayerController>(type: Constructable<T>, position?: Vector3, rotation?: Euler): Promise<T>;
|
|
53
|
-
addActor(actor: BaseActor, position?: Vector3, rotation?: Euler): void;
|
|
62
|
+
addActor(actor: BaseActor, position?: Vector3, rotation?: Euler, lifetime?: ActorLifetime): void;
|
|
54
63
|
/**
|
|
55
64
|
* Materialize and compile visual effects before gameplay exposes the action
|
|
56
65
|
* that uses them. Call this at a loading boundary rather than on first use.
|
|
@@ -59,13 +68,14 @@ export declare class World {
|
|
|
59
68
|
removeActor(actor: BaseActor): void;
|
|
60
69
|
findActorByType<T extends BaseActor>(type: Constructable<T>, name?: string): T;
|
|
61
70
|
findActorsByType<T extends BaseActor>(type: Constructable<T>, name?: string): T[];
|
|
71
|
+
getActorLifetime(actor: BaseActor): ActorLifetime;
|
|
62
72
|
/** Starts event graphs owned by prefabs that were materialized with the scene. */
|
|
63
73
|
startSceneEventGraphs(materializer: SceneMaterializer): Promise<void>;
|
|
64
74
|
/** Stops scene-owned graphs before their actors or materializer are disposed. */
|
|
65
75
|
stopSceneEventGraphs(): void;
|
|
66
76
|
private activateSceneEventGraph;
|
|
67
77
|
private deactivateSceneEventGraph;
|
|
68
|
-
spawnPrefab(prefab: Prefab, position?: Vector3, rotation?: Euler): Promise<PrefabInstance>;
|
|
78
|
+
spawnPrefab(prefab: Prefab, position?: Vector3, rotation?: Euler, options?: PrefabSpawnOptions): Promise<PrefabInstance>;
|
|
69
79
|
removePrefab(instance: PrefabInstance): void;
|
|
70
80
|
}
|
|
71
81
|
export {};
|