@hology/core 0.0.270 → 0.0.272

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/effects/sequence/sequence-player.js +1 -1
  2. package/dist/effects/vfx/gpu-sprite-compiler.js +1 -1
  3. package/dist/effects/vfx/gpu-sprite-runtime.js +1 -1
  4. package/dist/effects/vfx/gpu-vfx-world-service.d.ts +2 -0
  5. package/dist/effects/vfx/gpu-vfx-world-service.js +1 -1
  6. package/dist/effects/vfx/vfx-actor.js +1 -1
  7. package/dist/effects/vfx/vfx-materializer.js +1 -1
  8. package/dist/effects/vfx/vfx-render-preparation.d.ts +3 -0
  9. package/dist/effects/vfx/vfx-render-preparation.js +1 -1
  10. package/dist/gameplay/actors/builtin/components/spline-component.d.ts +7 -39
  11. package/dist/gameplay/actors/builtin/components/spline-component.js +1 -1
  12. package/dist/gameplay/actors/builtin/navmesh-actor.d.ts +16 -2
  13. package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
  14. package/dist/gameplay/actors/builtin/water-spline-volume-actor.d.ts +2 -2
  15. package/dist/gameplay/actors/builtin/water-spline-volume-actor.js +1 -1
  16. package/dist/gameplay/ai/build-tile.js +1 -1
  17. package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
  18. package/dist/gameplay/ai/dynamic-tiled-navmesh.worker.js +1 -1
  19. package/dist/gameplay/ai/navigation.d.ts +2 -0
  20. package/dist/gameplay/ai/navigation.js +1 -1
  21. package/dist/gameplay/initiate.js +1 -1
  22. package/dist/gameplay/services/physics/physics-system.d.ts +1 -1
  23. package/dist/gameplay/services/physics/physics-system.js +1 -1
  24. package/dist/gameplay/services/render.js +1 -1
  25. package/dist/navigation/bake.d.ts +68 -0
  26. package/dist/navigation/bake.js +4 -0
  27. package/dist/navigation/cache.d.ts +11 -0
  28. package/dist/navigation/cache.js +4 -0
  29. package/dist/navigation/spline-data.d.ts +64 -0
  30. package/dist/navigation/spline-data.js +4 -0
  31. package/dist/navigation/water-spline-geometry.d.ts +23 -0
  32. package/dist/navigation/water-spline-geometry.js +4 -0
  33. package/dist/scene/asset-resource-loader.d.ts +7 -3
  34. package/dist/scene/asset-resource-loader.js +1 -1
  35. package/dist/scene/bootstrap.js +1 -1
  36. package/dist/scene/collision/authored-colliders.d.ts +4 -0
  37. package/dist/scene/collision/authored-colliders.js +4 -0
  38. package/dist/scene/collision/rapier-shape.d.ts +7 -0
  39. package/dist/scene/collision/rapier-shape.js +4 -0
  40. package/dist/scene/materializer.d.ts +4 -1
  41. package/dist/scene/materializer.js +1 -1
  42. package/dist/scene/model.d.ts +4 -0
  43. package/dist/scene/native-texture.d.ts +13 -0
  44. package/dist/scene/native-texture.js +4 -0
  45. package/dist/scene/objects/shapes.js +1 -1
  46. package/dist/scene/runtime-backend-service.d.ts +1 -0
  47. package/dist/scene/runtime-bundled-backend-service.d.ts +1 -0
  48. package/dist/scene/runtime-bundled-backend-service.js +1 -1
  49. package/dist/shader-nodes/particle-parameter.d.ts +4 -0
  50. package/dist/shader-nodes/particle-parameter.js +4 -0
  51. package/dist/test/asset-resource-loader-texture-array.test.js +1 -1
  52. package/dist/test/authored-collision-rescale.test.js +1 -1
  53. package/dist/test/gpu-sprite-compiler.test.js +1 -1
  54. package/dist/test/gpu-sprite-pipeline-cache.test.js +1 -1
  55. package/dist/test/gpu-vfx-preload.test.d.ts +2 -0
  56. package/dist/test/gpu-vfx-preload.test.js +4 -0
  57. package/dist/test/materializer-prefetch.test.js +1 -1
  58. package/dist/test/native-texture.test.d.ts +2 -0
  59. package/dist/test/native-texture.test.js +4 -0
  60. package/dist/test/navigation-bake-backend.test.d.ts +2 -0
  61. package/dist/test/navigation-bake-backend.test.js +4 -0
  62. package/dist/test/navigation-bake.test.d.ts +2 -0
  63. package/dist/test/navigation-bake.test.js +4 -0
  64. package/dist/test/sequence-vfx.test.js +1 -1
  65. package/dist/test/shader-graph.test.js +1 -1
  66. package/dist/test/vfx-render-preparation.test.js +1 -1
  67. package/package.json +6 -2
  68. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{NavMesh as t,NavMeshParams as e,Raw as i,UnsignedCharArray as s,recastConfigDefaults as o,statusToReadableString as r}from"recast-navigation";import*as n from"three";import{buildConfig as a,buildTile as h}from"./build-tile.js";import{Subject as l}from"rxjs";import{executeTask as d,hasWorkerBuilder as u}from"../../worker/index.js";import{hasSharedArrayBufferSupport as c}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export const getTileBounds=(t,e,i,s,o)=>[[t.x+i*o,t.y,t.z+s*o],[t.x+(i+1)*o,e.y,t.z+(s+1)*o]];export class DynamicTiledNavMesh{constructor(i){this.navMeshVersion=0,this.onNavMeshUpdate=new l,this.abortController=new AbortController;const s=i.navMeshBounds.min,r=i.navMeshBounds.max,n=[s.toArray(),r.toArray()],h=i.navMeshBounds.min;this.navMeshBoundsMin=s,this.navMeshBoundsMax=r,this.navMeshBounds=n,this.navMeshOrigin=h,this.cacheId=i.cacheId,this.workerLimit=Math.min(4,Math.max(0,i.workers));const d={...o,...i.recastConfig};this.recastConfig=d;const u=new t,{tileWidth:c,tileHeight:M,tcs:m,maxPolysPerTile:v}=a({recastConfig:d,navMeshBounds:n});this.tileWidth=c,this.tileHeight=M,this.tcs=m;const f=e.create({orig:h,tileWidth:d.tileSize*d.cs,tileHeight:d.tileSize*d.cs,maxTiles:i.maxTiles,maxPolys:v});u.initTiled(f),this.navMesh=u}onResult(t){if(t.data.error)return void console.error(t.data.error);const{tileX:e,tileY:o,navMeshData:n}=t.data;if(this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0)),null==n)return this.navMeshVersion++,void this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]]);const a=new s;a.copy(n);const h=this.navMesh.addTile(a,i.Module.DT_TILE_FREE_DATA,0);i.Detour.statusFailed(h.status)&&(console.error(i.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${r(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[i,s],o=!1,r=[]){const n=c&&t.buffer instanceof window.SharedArrayBuffer,a=n?t:new Float32Array(t),l=n?e:new Uint32Array(e),[v,f]=getTileBounds(this.navMeshBoundsMin,this.navMeshBoundsMax,i,s,this.tcs),g={tileX:i,tileY:s,tileBoundsMin:v,tileBoundsMax:f,recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:a,indices:l,areaModifiers:r};return this.workerLimit>0&&u()?d("navmesh.buildTile",g,{transfer:n?void 0:[a.buffer,l.buffer],signal:this.abortController.signal,priority:"background"}).then(t=>this.onResult({data:t})).catch(t=>{"AbortError"!==t?.name&&console.error("Navmesh worker failed",t)}):new Promise(t=>{(globalThis.requestIdleCallback??(t=>setTimeout(t,0)))(()=>{const e=this.cacheId+JSON.stringify({tileX:g.tileX,tileY:g.tileY,areaModifiers:g.areaModifiers});if(o){const i=localStorage.getItem(e);if(null!=i){const e=m(i);return this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:e}}),void t({})}}else localStorage.removeItem(e);const i=h(g);if(!i.success)return console.error("error"in i?i.error:"Unknown navmesh tile build error"),void t(i);if(!i.data)return localStorage.removeItem(e),this.onResult({data:{tileX:g.tileX,tileY:g.tileY}}),void t(i);const s=i.data.toTypedArray();localStorage.setItem(e,M(s)),this.onResult({data:{tileX:g.tileX,tileY:g.tileY,navMeshData:s}}),t(i)})})}buildAllTiles(t,e){const{tileWidth:i,tileHeight:s}=this;for(let o=0;o<s;o++)for(let s=0;s<i;s++)this.buildTile(t,e,[s,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){if(!t.intersectsBox(new n.Box3(this.navMeshBoundsMin,this.navMeshBoundsMax)))return[];const e=this.getTileForWorldPosition(t.min),i=this.getTileForWorldPosition(t.max);e[0]=Math.max(0,Math.min(this.tileWidth-1,e[0])),e[1]=Math.max(0,Math.min(this.tileHeight-1,e[1])),i[0]=Math.max(0,Math.min(this.tileWidth-1,i[0])),i[1]=Math.max(0,Math.min(this.tileHeight-1,i[1]));const s=[];for(let t=e[1];t<=i[1];t++)for(let o=e[0];o<=i[0];o++)s.push([o,t]);return s}destroy(){this.abortController.abort(),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}const M=function(t){return btoa(String.fromCharCode(...t))},m=function(t){if(!t)return null;const e=atob(t),i=e.length,s=new Uint8Array(i);for(let t=0;t<i;t++)s[t]=e.charCodeAt(t);return s};/*
1
+ import{NavMesh as t,NavMeshParams as e,Raw as i,UnsignedCharArray as s,recastConfigDefaults as o,statusToReadableString as r}from"recast-navigation";import*as n from"three";import{buildConfig as a,buildTile as h}from"./build-tile.js";import{Subject as l}from"rxjs";import{executeTask as d,hasWorkerBuilder as u}from"../../worker/index.js";import{hasSharedArrayBufferSupport as M}from"../../utils/buffer.js";export const MAX_NAV_MESH_WORKERS=4;export const getTileBounds=(t,e,i,s,o)=>[[t.x+i*o,t.y,t.z+s*o],[t.x+(i+1)*o,e.y,t.z+(s+1)*o]];export class DynamicTiledNavMesh{constructor(s){this.navMeshVersion=0,this.onNavMeshUpdate=new l,this.abortController=new AbortController;const r=s.navMeshBounds.min,n=s.navMeshBounds.max,h=[r.toArray(),n.toArray()],d=s.navMeshBounds.min;this.navMeshBoundsMin=r,this.navMeshBoundsMax=n,this.navMeshBounds=h,this.navMeshOrigin=d,this.cacheId=s.cacheId,this.workerLimit=Math.min(4,Math.max(0,s.workers));const u={...o,...s.recastConfig};this.recastConfig=u;const M=new t,c=a({recastConfig:u,navMeshBounds:h}),{tileWidth:v,tileHeight:m,tcs:f,maxPolysPerTile:x}=c;i.Module.destroy(c.config),this.tileWidth=v,this.tileHeight=m,this.tcs=f;const g=e.create({orig:d,tileWidth:u.tileSize*u.cs,tileHeight:u.tileSize*u.cs,maxTiles:s.maxTiles,maxPolys:x});M.initTiled(g),i.Module.destroy(g.raw),this.navMesh=M}onResult(t){if(t.data.error)return void console.error(t.data.error);const{tileX:e,tileY:o,navMeshData:n}=t.data;if(this.navMesh.removeTile(this.navMesh.getTileRefAt(e,o,0)),null==n)return this.navMeshVersion++,void this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]]);const a=new s;a.copy(n);const h=this.navMesh.addTile(a,i.Module.DT_TILE_FREE_DATA,0);i.Detour.statusFailed(h.status)&&(console.error(i.Module.RC_LOG_WARNING,`Failed to add tile to nav mesh\n\ttx: ${e}, ty: ${o},status: ${r(h.status)} (${h.status})`),a.destroy()),this.navMeshVersion++,this.onNavMeshUpdate.next([this.navMeshVersion,[e,o]])}buildTile(t,e,[s,o],r=!1,n=[]){const a=M&&t.buffer instanceof window.SharedArrayBuffer,l=a?t:new Float32Array(t),c=a?e:new Uint32Array(e),[v,m]=getTileBounds(this.navMeshBoundsMin,this.navMeshBoundsMax,s,o,this.tcs),f={tileX:s,tileY:o,tileBoundsMin:v,tileBoundsMax:m,recastConfig:this.recastConfig,navMeshBounds:this.navMeshBounds,keepIntermediates:!1,positions:l,indices:c,areaModifiers:n};return this.workerLimit>0&&u()?d("navmesh.buildTile",f,{transfer:a?void 0:[l.buffer,c.buffer],signal:this.abortController.signal,priority:"background"}).then(t=>this.onResult({data:t})).catch(t=>{"AbortError"!==t?.name&&console.error("Navmesh worker failed",t)}):new Promise(t=>{(globalThis.requestIdleCallback??(t=>setTimeout(t,0)))(()=>{if(this.abortController.signal.aborted)return void t(void 0);const e=h(f);if(i.Module.destroy(e.buildContext.raw),!e.success)return console.error("error"in e?e.error:"Unknown navmesh tile build error"),void t(e);if(!e.data)return this.onResult({data:{tileX:f.tileX,tileY:f.tileY}}),void t(e);const s=e.data.toTypedArray();e.data.destroy(),this.onResult({data:{tileX:f.tileX,tileY:f.tileY,navMeshData:s}}),t(e)})})}buildAllTiles(t,e){const{tileWidth:i,tileHeight:s}=this;for(let o=0;o<s;o++)for(let s=0;s<i;s++)this.buildTile(t,e,[s,o])}getTileForWorldPosition(t){return[Math.floor((t.x-this.navMeshBoundsMin.x)/this.tcs),Math.floor((t.z-this.navMeshBoundsMin.z)/this.tcs)]}getTilesForBounds(t){if(!t.intersectsBox(new n.Box3(this.navMeshBoundsMin,this.navMeshBoundsMax)))return[];const e=this.getTileForWorldPosition(t.min),i=this.getTileForWorldPosition(t.max);e[0]=Math.max(0,Math.min(this.tileWidth-1,e[0])),e[1]=Math.max(0,Math.min(this.tileHeight-1,e[1])),i[0]=Math.max(0,Math.min(this.tileWidth-1,i[0])),i[1]=Math.max(0,Math.min(this.tileHeight-1,i[1]));const s=[];for(let t=e[1];t<=i[1];t++)for(let o=e[0];o<=i[0];o++)s.push([o,t]);return s}destroy(){this.abortController.abort(),this.navMesh.destroy(),this.onNavMeshUpdate.complete()}}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{init as e}from"recast-navigation";import{buildTile as t}from"./build-tile.js";let r;export const navMeshTaskHandlers={"navmesh.buildTile":async a=>{r??(r=e()),await r;const i=t(a);if(!i.success){const e="error"in i?i.error:"Unknown navmesh tile build error";throw new Error(`NavMesh tile build failed (${a.tileX}, ${a.tileY}): ${e}`)}if(!i.data)return{payload:{tileX:a.tileX,tileY:a.tileY}};const l=i.data.toTypedArray();return i.data.destroy(),{payload:{tileX:a.tileX,tileY:a.tileY,navMeshData:l},transfer:[l.buffer]}}};/*
1
+ import{init as e,Raw as t}from"recast-navigation";import{buildTile as r}from"./build-tile.js";let a;export const navMeshTaskHandlers={"navmesh.buildTile":async i=>{a??(a=e()),await a;const l=r(i);if(t.Module.destroy(l.buildContext.raw),!l.success){const e="error"in l?l.error:"Unknown navmesh tile build error";throw new Error(`NavMesh tile build failed (${i.tileX}, ${i.tileY}): ${e}`)}if(!l.data)return{payload:{tileX:i.tileX,tileY:i.tileY}};const o=l.data.toTypedArray();return l.data.destroy(),{payload:{tileX:i.tileX,tileY:i.tileY,navMeshData:o},transfer:[o.buffer]}}};/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -24,10 +24,12 @@ export declare const NavigationQueryProfiles: Readonly<{
24
24
  export declare class Navigation {
25
25
  private navMeshActor;
26
26
  private query?;
27
+ private queryMesh?;
27
28
  private world;
28
29
  private filters;
29
30
  constructor();
30
31
  private getFilter;
32
+ private resetQuery;
31
33
  private ensureQuery;
32
34
  /**
33
35
  * Finds a path from a start point to an end point.
@@ -1,4 +1,4 @@
1
- import{__decorate as e,__metadata as t}from"tslib";import{NavMeshQuery as n,QueryFilter as s}from"recast-navigation";import{Vector3 as r}from"three";import{Service as i}from"typedi";import{inject as o}from"../inject.js";import{World as l}from"../services/world.js";import a,{safeRecastInit as u}from"../actors/builtin/navmesh-actor.js";import{NavigationArea as c,NavigationTraversalFlag as h}from"./navigation-areas.js";export const NavigationQueryProfiles=Object.freeze({Walker:Object.freeze({name:"Walker",includeFlags:h.Walk,excludeFlags:h.Swim}),Swimmer:Object.freeze({name:"Swimmer",includeFlags:h.Walk|h.Swim,excludeFlags:0,areaCosts:{[c.Water]:2}})});let d=class{constructor(){this.world=o(l),this.filters=new Map,u().then(()=>{const e=this.world.actors.find(e=>e instanceof a);null!=e&&(this.navMeshActor=e,this.query=null),this.world.actorAdded.subscribe(e=>{e instanceof a&&(this.navMeshActor=e,this.query=null)}),this.world.actorRemoved.subscribe(e=>{e instanceof a&&e.id===this.navMeshActor?.id&&(this.navMeshActor=null,this.query=null)})})}getFilter(e){let t=this.filters.get(e);if(null!=t)return t;t=new s,t.includeFlags=e.includeFlags,t.excludeFlags=e.excludeFlags;for(const[n,s]of Object.entries(e.areaCosts??{}))null!=s&&t.setAreaCost(Number(n),s);return this.filters.set(e,t),t}ensureQuery(){null==this.query&&null!=this.navMeshActor&&null!=this.navMeshActor.navMesh&&(this.query=new n(this.navMeshActor.navMesh))}findPath(e,t,n=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return y("NavMesh has not been generated yet"),f;const s=this.findClosestPoint(e,n);if(null==s)return y("Start point could not be found on NavMesh",e),f;const i=this.findClosestPoint(t,n);if(null==i)return y("End point could not be found on NavMesh",t),f;const{success:o,error:l,path:a}=this.query.computePath(s,i,{filter:this.getFilter(n)}),u=a.at(-1),c=null!=u&&function(e,t){const n=e.x-t.x,s=e.y-t.y,r=e.z-t.z;return n*n+s*s+r*r}(u,i)<=.01;return o&&c?{success:!0,path:a.map(e=>new r(e.x,e.y,e.z))}:(y("Failed to generate path",l),f)}findClosestPoint(e,t=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return y("NavMesh has not been generated yet"),null;const{success:n,point:s}=this.query.findClosestPoint(e,{filter:this.getFilter(t)});return n?new r(s.x,s.y,s.z):null}findRandomPoint(e=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return y("NavMesh has not been generated yet"),null;const t=this.query.findRandomPoint({filter:this.getFilter(e)});return{success:t.success,randomPoint:(new r).copy(t.randomPoint)}}findRandomPointAroundCircle(e,t,n=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return y("NavMesh has not been generated yet"),null;const s=this.query.findRandomPointAroundCircle(e,t,{filter:this.getFilter(n)});return{success:s.success,randomPoint:(new r).copy(s.randomPoint)}}};d=e([i(),t("design:paramtypes",[])],d);export{d as Navigation};const f={success:!1,path:[]};let m=new Set;function y(e,...t){m.has(e)||(m.add(e),setTimeout(()=>m.delete(e),2e3),console.warn(e,...t))}/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{NavMeshQuery as s,QueryFilter as r}from"recast-navigation";import{Vector3 as n}from"three";import{Service as i}from"typedi";import{inject as o}from"../inject.js";import{World as a}from"../services/world.js";import l,{safeRecastInit as u}from"../actors/builtin/navmesh-actor.js";import{NavigationArea as h,NavigationTraversalFlag as c}from"./navigation-areas.js";export const NavigationQueryProfiles=Object.freeze({Walker:Object.freeze({name:"Walker",includeFlags:c.Walk,excludeFlags:c.Swim}),Swimmer:Object.freeze({name:"Swimmer",includeFlags:c.Walk|c.Swim,excludeFlags:0,areaCosts:{[h.Water]:2}})});let d=class{constructor(){this.world=o(a),this.filters=new Map,u().then(()=>{const e=this.world.actors.find(e=>e instanceof l);null!=e&&(this.navMeshActor=e,this.resetQuery()),this.world.actorAdded.subscribe(e=>{e instanceof l&&(this.navMeshActor=e,this.resetQuery())}),this.world.actorRemoved.subscribe(e=>{e instanceof l&&e.id===this.navMeshActor?.id&&(this.navMeshActor=null,this.resetQuery())})})}getFilter(e){let t=this.filters.get(e);if(null!=t)return t;t=new r,t.includeFlags=e.includeFlags,t.excludeFlags=e.excludeFlags;for(const[s,r]of Object.entries(e.areaCosts??{}))null!=r&&t.setAreaCost(Number(s),r);return this.filters.set(e,t),t}resetQuery(){this.query?.destroy(),this.query=void 0,this.queryMesh=void 0}ensureQuery(){const e=this.navMeshActor?.navMesh;e!==this.queryMesh&&(this.query?.destroy(),this.query=void 0,this.queryMesh=e),null==this.query&&null!=this.navMeshActor&&null!=this.navMeshActor.navMesh&&(this.query=new s(this.navMeshActor.navMesh))}findPath(e,t,s=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return m("NavMesh has not been generated yet"),f;const r=this.findClosestPoint(e,s);if(null==r)return m("Start point could not be found on NavMesh",e),f;const i=this.findClosestPoint(t,s);if(null==i)return m("End point could not be found on NavMesh",t),f;const{success:o,error:a,path:l}=this.query.computePath(r,i,{filter:this.getFilter(s)}),u=l.at(-1),h=null!=u&&function(e,t){const s=e.x-t.x,r=e.y-t.y,n=e.z-t.z;return s*s+r*r+n*n}(u,i)<=.01;return o&&h?{success:!0,path:l.map(e=>new n(e.x,e.y,e.z))}:(m("Failed to generate path",a),f)}findClosestPoint(e,t=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return m("NavMesh has not been generated yet"),null;const{success:s,point:r}=this.query.findClosestPoint(e,{filter:this.getFilter(t)});return s?new n(r.x,r.y,r.z):null}findRandomPoint(e=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return m("NavMesh has not been generated yet"),null;const t=this.query.findRandomPoint({filter:this.getFilter(e)});return{success:t.success,randomPoint:(new n).copy(t.randomPoint)}}findRandomPointAroundCircle(e,t,s=NavigationQueryProfiles.Walker){if(this.ensureQuery(),null==this.query)return m("NavMesh has not been generated yet"),null;const r=this.query.findRandomPointAroundCircle(e,t,{filter:this.getFilter(s)});return{success:r.success,randomPoint:(new n).copy(r.randomPoint)}}};d=e([i(),t("design:paramtypes",[])],d);export{d as Navigation};const f={success:!1,path:[]};let y=new Set;function m(e,...t){y.has(e)||(y.add(e),setTimeout(()=>y.delete(e),2e3),console.warn(e,...t))}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -1,4 +1,4 @@
1
- import{setWebGpuPipelineLoading as e}from"../rendering/webgpu-runtime-bridge.js";import t from"typedi";import{BehaviorSubject as i,Subject as n}from"rxjs";import{loadScene as s}from"../scene/bootstrap.js";import{ActorFactory as r}from"./actors/factory.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{SceneDataService as a}from"../scene/scene-data-service.js";import{World as c}from"./services/world.js";import{ViewController as l}from"./services/render.js";import{RenderingView as p,GraphicsRuntime as h}from"../rendering.js";import{PhysicsSystem as d}from"./services/physics/physics-system.js";import{MeshComponent as m}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as u}from"./actors/builtin/components/index.js";import{InputService as g}from"./input/index.js";import{RuntimeAssetsService as w}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as f}from"../scene/asset-resource-loader.js";import{AssetLoader as y}from"./services/asset-loader.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{AssetsProvider as S}from"../scene/assets-provider.js";import{ShaderProvider as b}from"./services/shader-provider.js";import{PointerEvents as j}from"./services/pointer-events.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";import{NetMode as A}from"./net/net-session.js";import{GameStateContext as V}from"./game-state-context.js";import{PlayerSessions as P}from"./player-sessions.js";import{polyfillClient as N}from"./polyfill.js";import{withInjectionContext as C}from"./inject.js";import{RenderingHost as R}from"./rendering-host.js";import{SceneTransitionService as z}from"./services/scene-transition.js";import{SceneRef as G}from"../scene/scene-ref.js";import{ActorPersistence as H}from"./services/actor-persistence.js";let x=0;export function initiateApplication(e,i){const n="function"==typeof e?e:void 0,s=i??e;var r;N(),"element"in s&&null!=s.element&&(r=s.element,Object.assign(r.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"}));const o=s.renderingHost??(null!=s.renderingView?new R(s.renderingView,!1,("renderingViewFactory"in s?s.renderingViewFactory:void 0)??(()=>new p(s.renderingView.container,s.renderingView.options))):function(e,t,i){const n=new h,s=()=>function(e,t,i,n){return new p(e,{graphicsRuntime:n,backend:t?.backend??"webgpu",enableXR:!0===i?.enabled,maxPixelRatio:t?.maxPixelRatio,resolutionScale:t?.resolutionScale,dynamicResolution:t?.dynamicResolution,upscaling:t?.upscaling,webgpuPostProcessing:t?.webgpuPostProcessing,webgpuDirectionalShadows:t?.webgpuDirectionalShadows,webgpuVfx:t?.webgpuVfx??"auto",msaa:t?.msaa,fpsCap:t?.fpsCap,depthPrepass:{enabled:!0===t?.depthPrepass?.enabled},bloom:{enabled:!1!==t?.bloom?.enabled},reflection:{enabled:!1!==t?.reflection?.enabled},occlusionCulling:{enabled:!1!==t?.occlusionCulling?.enabled},shadows:{enabled:t?.shadows?.enabled??!0,autoUpdate:t?.shadows?.autoUpdate??!0,cascadeUpdateIntervals:[22,40,60,120]}})}(e,t,i,n);return new R(s(),!0,s)}(s.element,s.rendering,s.xr)),a=t.of("hology-application-"+ ++x),c=new HologyApplicationRuntime(s,a,o,n??s.defaultGameClass);return c.startInitialization(),c}export function initiateGame(e,t){const{sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o,...a}=t,c=initiateApplication(e,a),l=c.ready.then(()=>c.loadGame({sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o}));return new HologyRuntime(c,l)}export class GameInstance{onPreload(){}onStart(){}onUnload(){return this.onShutdown()}onShutdown(){}}export class HologyApplicationRuntime{constructor(e,t,s,r){this.config=e,this.applicationContainer=t,this.renderingHost=s,this.defaultGameClass=r,this.stateSubject=new i({type:"initializing"}),this.state=this.stateSubject.asObservable(),this.shutdownSubject=new n,this.shutdownStarted=this.shutdownSubject.asObservable(),this.transitionTail=Promise.resolve(),this.initializationPromise=Promise.resolve(),this.transitionIntent=0,this.shutdownFlag=!1,this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t})}get renderingView(){return this.renderingHost.activeView}get currentState(){return this.stateSubject.value}startInitialization(){this.initializationPromise=this.initialize()}async initialize(){try{if(this.registerApplicationServices(),await this.renderingHost.applicationView.compileAsync(),this.shutdownFlag)return void this.rejectReady(k());const e=this.getApplicationService(g);this.renderingHost.start(t=>e.update(t),t=>e.sampleGamepadButtons(t)),this.setState({type:"menu"}),this.resolveReady()}catch(e){this.setState({type:"error",operation:"initialize",error:e}),this.rejectReady(e)}}loadGame(e,t){const i="function"==typeof e?e:this.defaultGameClass,n=t??e;if(null==i)return Promise.reject(new Error("loadGame() requires a game class because no default was configured"));const s=++this.transitionIntent;return this.enqueue(async()=>(await this.ready,this.assertRunning(),this.checkIntent(s),null!=this.session&&await this.disposeSession(this.session,!0),this.checkIntent(s),this.performLoad(i,n,s)))}unloadGame(){const e=++this.transitionIntent;return this.enqueue(async()=>{if(await this.ready,!this.shutdownFlag&&e===this.transitionIntent){try{null!=this.session&&await this.disposeSession(this.session,!0)}catch(t){throw this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"error",operation:"unload",error:t}),t}this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"menu"})}})}transitionScene(e){const t="string"==typeof e?{scene:new G(e,e)}:e instanceof G?{scene:e}:e,i=this.transitionIntent;return this.enqueue(async()=>{await this.ready,this.assertRunning(),this.checkIntent(i);const e=this.session;if(null==e)throw new Error("transitionScene() requires an active game session");try{return await this.performSceneTransition(e,t,i),e}catch(e){throw F(e)||this.shutdownFlag||i!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}})}async shutdown(){this.shutdownFlag||(this.shutdownFlag=!0,++this.transitionIntent,this.shutdownSubject.next(),this.shutdownSubject.complete(),await this.initializationPromise.catch(()=>{}),await this.transitionTail.catch(()=>{}),null!=this.session&&await this.disposeSession(this.session,!1),this.getApplicationService(g).stop(),this.getOptionalApplicationService(j)?.stop(),this.getApplicationService(f).disposeAll(),this.getApplicationService(w).dispose(),this.getApplicationService(l).dispose(!1),this.renderingHost.shutdown(),t.reset(this.applicationContainer.id),this.setState({type:"stopped"}),this.stateSubject.complete())}getWorld(){return this.session?.world}getGameInstance(){return this.session?.gameInstance}getApplicationService(e){return this.applicationContainer.get(e)}getSessionService(e){return this.session?.container.get(e)}getService(e){return null!=this.session?this.session.container.get(e):this.applicationContainer.get(e)}registerRenderStage(e){return this.renderingHost.registerStage(e)}registerApplicationServices(){const e=new l(this.renderingView);this.applicationContainer.set(p,this.renderingHost.applicationView),this.applicationContainer.set(l,e);const t=new v(this.config.runtimeDataUrl),i=new w(t),n=new f;n.setDataDir(this.config.dataDir),n.setDirectFileLoading(!0===this.config.directAssetFileLoading),"webgpu"===this.renderingHost.applicationView.requestedBackend?n.initKtx2ForWebGpu():n.initKtx2(this.renderingHost.applicationView.renderer);const s=Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t}));this.applicationContainer.set(v,t),this.applicationContainer.set(S,i),this.applicationContainer.set(w,i),this.applicationContainer.set(f,n),this.applicationContainer.set(y,new y(n,i,s)),this.applicationContainer.set(b,new b(s));const r=C(this.applicationContainer,e=>e.get(g));this.applicationContainer.set(g,r)}async performLoad(i,n,r){if(null!=n.persistence&&null!=n.multi?.session&&n.multi.session.mode!==A.none)throw new Error("Actor persistence currently supports single-player sessions only");const a=this.createSession(n);this.session=a;try{this.loading(n.sceneName,"physics",.08),await Promise.all([a.physics.start(),a.renderingView.initializeBackend()]),await e(a.renderingView.webGpuDevice,!0,"loading: "+n.sceneName),this.checkIntent(r),this.loading(n.sceneName,"runtime-data",.2),await this.getApplicationService(v).preloadData(),this.checkIntent(r),this.loading(n.sceneName,"scene",.42);const c=await s(a.renderingView,n.sceneName,this.config.dataDir,this.config.shaders,this.config.actors,a.components,a.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:n.detailTier,nodeMode:n.multi?.session.mode??A.none,persistence:a.world.persistence});if(a.materializer.dispose(),a.materializer=c.materializer,a.sceneRoots=c.sceneRoots,a.container.set(o,c.materializer),a.world.materializer=c.materializer,a.world.scene=c.scene,a.physics.scene=c.scene,this.checkIntent(r),null!=n.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=C(a.container,t=>t.get(e));t.session=n.multi.session,t.start(),a.stopPlayers=()=>t.stop()}if(t.import([m]),await this.restoreSceneActors(a,c.materializer,c.actors,r),a.physics.addFromScene(c.scene),await a.world.startSceneEventGraphs(c.materializer),this.checkIntent(r),a.gameInstance=C(a.container,e=>(e.set({id:i,type:i}),e.get(i))),this.loading(n.sceneName,"game-preload",.58),a.gameInstance instanceof GameInstance&&await a.gameInstance.onPreload(),this.checkIntent(r),this.loading(n.sceneName,"shaders",.7),await a.renderingView.compileAsync(),this.checkIntent(r),this.loading(n.sceneName,"textures",.82),await a.renderingView.initTexturesAsync(),this.checkIntent(r),"webgpu"===a.renderingView.activeBackend){this.loading(n.sceneName,"vfx-warmup",.94);const e=C(a.container,e=>e.get(I).beginPipelineWarmup());try{const e=performance.now();console.info("[Hology GPU VFX warmup] Rendering loading frame",n.sceneName),a.renderingView.render(0),console.info("[Hology GPU VFX warmup] Render returned; waiting for GPU queue",{sceneName:n.sceneName,renderMs:performance.now()-e}),await(a.renderingView.webGpuDevice?.queue.onSubmittedWorkDone()),console.info("[Hology GPU VFX warmup] GPU queue completed",{sceneName:n.sceneName,totalMs:performance.now()-e})}finally{e()}}return this.checkIntent(r),await e(a.renderingView.webGpuDevice,!1,"playing: "+n.sceneName),a.gameInstance instanceof GameInstance&&await a.gameInstance.onStart(),this.checkIntent(r),a.viewController.paused=!1,this.renderingHost.activate(a.renderingView),this.setState({type:"playing",sceneName:n.sceneName}),a}catch(e){throw await this.disposeSession(a,!1),F(e)||this.shutdownFlag||r!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}}createSession(e){const i=t.of("hology-session-"+ ++x);this.copyApplicationServices(i);const n=this.renderingHost.createView(),s=new l(n);s.paused=!0,i.set(p,n),i.set(l,s);const h={...u,...this.config.components??{}},m=new H;null!=e.persistence&&m.configure(e.persistence),i.set(H,m);const g=new r(i,{inEditor:!1});g.classes=this.config.actors,i.set(r,g);const y=new o(n.scene,new a,this.getApplicationService(w),this.getApplicationService(f),n,Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t})),Object.entries(this.config.actors).map(([e,t])=>({name:e,type:t})),g,Object.entries(h).map(([e,t])=>({name:e,type:t})));y.inEditor=!1,y.netMode=e.multi?.session.mode??A.none,i.set(o,y);const v=C(i,e=>e.get(c));m.enabled&&(v.persistence=m),v.scene=n.scene,i.set(c,v);const S=C(i,e=>e.get(d));i.set(d,S);const b=new z;b.bind(async e=>{await this.transitionScene(e)}),i.set(z,b);const j=C(i,e=>e.get(P));i.set(P,j);const I=C(i,e=>e.get(V));return i.set(V,I),null==e.multi?.session&&j.startStandalone(e.localPlayer??{id:"local-player",displayName:"Player"}),{sceneName:e.sceneName,detailTier:e.detailTier,container:i,renderingView:n,viewController:s,actorFactory:g,materializer:y,world:v,physics:S,components:h,sceneTransition:b,sceneRoots:[],netMode:e.multi?.session.mode??A.none,stopPlayers:null==e.multi?.session?()=>{j.stop(),I.stop()}:void 0}}async performSceneTransition(t,i,n){if(t.netMode!==A.none)throw new Error("In-session scene transitions are not yet supported for network sessions");const r=i.scene.id.trim();if(0===r.length)throw new Error("A destination scene id is required");await e(t.renderingView.webGpuDevice,!0,"transition: "+r);const a=t.sceneName,c=t.viewController.paused;t.viewController.paused=!0,this.renderingHost.activate(this.renderingHost.applicationView),t.world.persistence?.captureAll(),this.setState({type:"unloading",sceneName:a}),t.world.stopSceneEventGraphs();const l=t.world.removeSceneLifetimeActors(t.sceneRoots);for(const e of t.sceneRoots)t.physics.removeRemoved(e),e.removeFromParent();t.sceneRoots=[],t.materializer.dispose(l),this.checkIntent(n),this.loading(r,"scene",.42);const p=await s(t.renderingView,r,this.config.dataDir,this.config.shaders,this.config.actors,t.components,t.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:t.detailTier,nodeMode:t.netMode,persistence:t.world.persistence});this.checkIntent(n),t.materializer=p.materializer,t.sceneRoots=p.sceneRoots,t.sceneName=r,t.container.set(o,p.materializer),t.world.materializer=p.materializer,await this.restoreSceneActors(t,p.materializer,p.actors,n),t.physics.addFromScene(p.scene),await t.world.startSceneEventGraphs(p.materializer),await(i.afterLoad?.(t.world)),this.checkIntent(n),this.loading(r,"shaders",.7),await t.renderingView.compileAsync(),this.checkIntent(n),this.loading(r,"textures",.82),await t.renderingView.initTexturesAsync(),this.checkIntent(n),await e(t.renderingView.webGpuDevice,!1,"playing: "+r),t.sceneTransition.publish({previousSceneName:a,sceneName:r}),t.viewController.paused=c,this.renderingHost.activate(t.renderingView),this.setState({type:"playing",sceneName:r})}async restoreSceneActors(e,t,i,n){if(null==e.world.persistence){for(const t of i)e.world.addActor(t);return}const s=i.filter(t=>!e.world.actors.includes(t));for(const t of s)e.world.addActor(t,void 0,void 0,void 0,!0);const r=t.registerPersistentActors();await e.world.persistence.restore(r,()=>this.checkIntent(n)),this.checkIntent(n);for(const t of s)e.world.beginActorPlay(t)}copyApplicationServices(e){const t=[g,S,w,v,f,y,b];for(const i of t)e.set(i,this.applicationContainer.get(i))}async disposeSession(e,i){if(e.disposed)return;let n;e.disposed=!0,i&&this.setState({type:"unloading",sceneName:e.sceneName});try{e.viewController.paused=!0,e.world.persistence?.captureAll(),e.stopPlayers?.(),e.sceneTransition.dispose(),e.world.stopSceneEventGraphs(),e.gameInstance instanceof GameInstance&&await e.gameInstance.onUnload()}catch(e){n=e}finally{for(const t of[...e.world.actors])e.world.removeActor(t);e.physics.stop(),e.materializer.dispose(),this.renderingHost.activeView===e.renderingView&&this.renderingHost.activate(this.renderingHost.applicationView),e.viewController.dispose(!1),this.renderingHost.releaseView(e.renderingView),t.reset(e.container.id),this.session===e&&(this.session=void 0)}if(null!=n)throw n}enqueue(e){const t=this.transitionTail.then(e,e);return this.transitionTail=t.catch(()=>{}),t}checkIntent(e){if(this.assertRunning(),e!==this.transitionIntent)throw k()}assertRunning(){if(this.shutdownFlag)throw new Error("Hology application has been shut down")}loading(e,t,i){this.setState({type:"loading",sceneName:e,stage:t,progress:i})}setState(e){const t=this.renderingHost.applicationView;"loading"===e.type?t.stopAnimationLoop():"menu"!==e.type&&("error"!==e.type||"initialize"===e.operation)||this.renderingHost.activeView!==t||t.running||this.renderingHost.activate(t),this.stateSubject.next(e)}getOptionalApplicationService(e){return this.applicationContainer.has(e)?this.applicationContainer.get(e):void 0}}export class HologyRuntime{constructor(e,t){this.application=e,this.ready=t.then(()=>!0),this.shutdownStarted=e.shutdownStarted}get status(){return"playing"===this.application.currentState.type?5:"stopped"===this.application.currentState.type||"error"===this.application.currentState.type?10:0}get gameInstance(){return this.application.getGameInstance()}get isShutdown(){return"stopped"===this.application.currentState.type}getWorld(){return this.application.getWorld()}getService(e){return this.application.getService(e)}shutdown(){return this.application.shutdown()}}function k(){return new DOMException("Superseded by a newer game transition","AbortError")}function F(e){return e instanceof DOMException&&"AbortError"===e.name}/*
1
+ import{setWebGpuPipelineLoading as e}from"../rendering/webgpu-runtime-bridge.js";import t from"typedi";import{BehaviorSubject as i,Subject as n}from"rxjs";import{loadScene as s}from"../scene/bootstrap.js";import{ActorFactory as r}from"./actors/factory.js";import{SceneMaterializer as o}from"../scene/materializer.js";import{SceneDataService as a}from"../scene/scene-data-service.js";import{World as c}from"./services/world.js";import{ViewController as l}from"./services/render.js";import{RenderingView as p,GraphicsRuntime as h}from"../rendering.js";import{PhysicsSystem as d}from"./services/physics/physics-system.js";import{MeshComponent as m}from"./actors/builtin/components/mesh-component.js";import{builtInComponents as u}from"./actors/builtin/components/index.js";import{InputService as g}from"./input/index.js";import{RuntimeAssetsService as w}from"../scene/runtime-asset-service.js";import{AssetResourceLoader as f}from"../scene/asset-resource-loader.js";import{AssetLoader as y}from"./services/asset-loader.js";import{RuntimeBundledBackendService as v}from"../scene/runtime-bundled-backend-service.js";import{AssetsProvider as S}from"../scene/assets-provider.js";import{ShaderProvider as b}from"./services/shader-provider.js";import{PointerEvents as j}from"./services/pointer-events.js";import{GpuVfxWorldService as I}from"../effects/vfx/gpu-vfx-world-service.js";import{NetMode as A}from"./net/net-session.js";import{GameStateContext as V}from"./game-state-context.js";import{PlayerSessions as P}from"./player-sessions.js";import{polyfillClient as N}from"./polyfill.js";import{withInjectionContext as C}from"./inject.js";import{RenderingHost as G}from"./rendering-host.js";import{SceneTransitionService as H}from"./services/scene-transition.js";import{SceneRef as R}from"../scene/scene-ref.js";import{ActorPersistence as z}from"./services/actor-persistence.js";let x=0;export function initiateApplication(e,i){const n="function"==typeof e?e:void 0,s=i??e;var r;N(),"element"in s&&null!=s.element&&(r=s.element,Object.assign(r.style,{position:"absolute",top:"0",left:"0",width:"100%",height:"100%",overflow:"hidden"}));const o=s.renderingHost??(null!=s.renderingView?new G(s.renderingView,!1,("renderingViewFactory"in s?s.renderingViewFactory:void 0)??(()=>new p(s.renderingView.container,s.renderingView.options))):function(e,t,i){const n=new h,s=()=>function(e,t,i,n){return new p(e,{graphicsRuntime:n,backend:t?.backend??"webgpu",enableXR:!0===i?.enabled,maxPixelRatio:t?.maxPixelRatio,resolutionScale:t?.resolutionScale,dynamicResolution:t?.dynamicResolution,upscaling:t?.upscaling,webgpuPostProcessing:t?.webgpuPostProcessing,webgpuDirectionalShadows:t?.webgpuDirectionalShadows,webgpuVfx:t?.webgpuVfx??"auto",msaa:t?.msaa,fpsCap:t?.fpsCap,depthPrepass:{enabled:!0===t?.depthPrepass?.enabled},bloom:{enabled:!1!==t?.bloom?.enabled},reflection:{enabled:!1!==t?.reflection?.enabled},occlusionCulling:{enabled:!1!==t?.occlusionCulling?.enabled},shadows:{enabled:t?.shadows?.enabled??!0,autoUpdate:t?.shadows?.autoUpdate??!0,cascadeUpdateIntervals:[22,40,60,120]}})}(e,t,i,n);return new G(s(),!0,s)}(s.element,s.rendering,s.xr)),a=t.of("hology-application-"+ ++x),c=new HologyApplicationRuntime(s,a,o,n??s.defaultGameClass);return c.startInitialization(),c}export function initiateGame(e,t){const{sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o,...a}=t,c=initiateApplication(e,a),l=c.ready.then(()=>c.loadGame({sceneName:i,detailTier:n,multi:s,localPlayer:r,persistence:o}));return new HologyRuntime(c,l)}export class GameInstance{onPreload(){}onStart(){}onUnload(){return this.onShutdown()}onShutdown(){}}export class HologyApplicationRuntime{constructor(e,t,s,r){this.config=e,this.applicationContainer=t,this.renderingHost=s,this.defaultGameClass=r,this.stateSubject=new i({type:"initializing"}),this.state=this.stateSubject.asObservable(),this.shutdownSubject=new n,this.shutdownStarted=this.shutdownSubject.asObservable(),this.transitionTail=Promise.resolve(),this.initializationPromise=Promise.resolve(),this.transitionIntent=0,this.shutdownFlag=!1,this.ready=new Promise((e,t)=>{this.resolveReady=e,this.rejectReady=t})}get renderingView(){return this.renderingHost.activeView}get currentState(){return this.stateSubject.value}startInitialization(){this.initializationPromise=this.initialize()}async initialize(){try{if(this.registerApplicationServices(),await this.renderingHost.applicationView.compileAsync(),this.shutdownFlag)return void this.rejectReady(k());const e=this.getApplicationService(g);this.renderingHost.start(t=>e.update(t),t=>e.sampleGamepadButtons(t)),this.setState({type:"menu"}),this.resolveReady()}catch(e){this.setState({type:"error",operation:"initialize",error:e}),this.rejectReady(e)}}loadGame(e,t){const i="function"==typeof e?e:this.defaultGameClass,n=t??e;if(null==i)return Promise.reject(new Error("loadGame() requires a game class because no default was configured"));const s=++this.transitionIntent;return this.enqueue(async()=>(await this.ready,this.assertRunning(),this.checkIntent(s),null!=this.session&&await this.disposeSession(this.session,!0),this.checkIntent(s),this.performLoad(i,n,s)))}unloadGame(){const e=++this.transitionIntent;return this.enqueue(async()=>{if(await this.ready,!this.shutdownFlag&&e===this.transitionIntent){try{null!=this.session&&await this.disposeSession(this.session,!0)}catch(t){throw this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"error",operation:"unload",error:t}),t}this.shutdownFlag||e!==this.transitionIntent||this.setState({type:"menu"})}})}transitionScene(e){const t="string"==typeof e?{scene:new R(e,e)}:e instanceof R?{scene:e}:e,i=this.transitionIntent;return this.enqueue(async()=>{await this.ready,this.assertRunning(),this.checkIntent(i);const e=this.session;if(null==e)throw new Error("transitionScene() requires an active game session");try{return await this.performSceneTransition(e,t,i),e}catch(e){throw F(e)||this.shutdownFlag||i!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}})}async shutdown(){this.shutdownFlag||(this.shutdownFlag=!0,++this.transitionIntent,this.shutdownSubject.next(),this.shutdownSubject.complete(),await this.initializationPromise.catch(()=>{}),await this.transitionTail.catch(()=>{}),null!=this.session&&await this.disposeSession(this.session,!1),this.getApplicationService(g).stop(),this.getOptionalApplicationService(j)?.stop(),this.getApplicationService(f).disposeAll(),this.getApplicationService(w).dispose(),this.getApplicationService(l).dispose(!1),this.renderingHost.shutdown(),t.reset(this.applicationContainer.id),this.setState({type:"stopped"}),this.stateSubject.complete())}getWorld(){return this.session?.world}getGameInstance(){return this.session?.gameInstance}getApplicationService(e){return this.applicationContainer.get(e)}getSessionService(e){return this.session?.container.get(e)}getService(e){return null!=this.session?this.session.container.get(e):this.applicationContainer.get(e)}registerRenderStage(e){return this.renderingHost.registerStage(e)}registerApplicationServices(){const e=new l(this.renderingView);this.applicationContainer.set(p,this.renderingHost.applicationView),this.applicationContainer.set(l,e);const t=new v(this.config.runtimeDataUrl),i=new w(t),n=new f;n.setDataDir(this.config.dataDir),n.setDirectFileLoading(!0===this.config.directAssetFileLoading),"webgpu"===this.renderingHost.applicationView.requestedBackend?n.initKtx2ForWebGpu(this.renderingHost.applicationView.webGpuDevice??void 0):n.initKtx2(this.renderingHost.applicationView.renderer);const s=Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t}));this.applicationContainer.set(v,t),this.applicationContainer.set(S,i),this.applicationContainer.set(w,i),this.applicationContainer.set(f,n),this.applicationContainer.set(y,new y(n,i,s)),this.applicationContainer.set(b,new b(s));const r=C(this.applicationContainer,e=>e.get(g));this.applicationContainer.set(g,r)}async performLoad(i,n,r){if(null!=n.persistence&&null!=n.multi?.session&&n.multi.session.mode!==A.none)throw new Error("Actor persistence currently supports single-player sessions only");const a=this.createSession(n);this.session=a;try{this.loading(n.sceneName,"physics",.08),await Promise.all([a.physics.start(),a.renderingView.initializeBackend()]),await e(a.renderingView.webGpuDevice,!0,"loading: "+n.sceneName),this.checkIntent(r),this.loading(n.sceneName,"runtime-data",.2),await this.getApplicationService(v).preloadData(),this.checkIntent(r),this.loading(n.sceneName,"scene",.42);const c=await s(a.renderingView,n.sceneName,this.config.dataDir,this.config.shaders,this.config.actors,a.components,a.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:n.detailTier,nodeMode:n.multi?.session.mode??A.none,persistence:a.world.persistence});if(a.materializer.dispose(),a.materializer=c.materializer,a.sceneRoots=c.sceneRoots,a.container.set(o,c.materializer),a.world.materializer=c.materializer,a.world.scene=c.scene,a.physics.scene=c.scene,this.checkIntent(r),null!=n.multi?.session){const{NetService:e}=await import("./net/service/net-service.js"),t=C(a.container,t=>t.get(e));t.session=n.multi.session,t.start(),a.stopPlayers=()=>t.stop()}if(t.import([m]),await this.restoreSceneActors(a,c.materializer,c.actors,r),a.physics.addFromScene(c.scene),await a.world.startSceneEventGraphs(c.materializer),this.checkIntent(r),a.gameInstance=C(a.container,e=>(e.set({id:i,type:i}),e.get(i))),this.loading(n.sceneName,"game-preload",.58),a.gameInstance instanceof GameInstance&&await a.gameInstance.onPreload(),this.checkIntent(r),this.loading(n.sceneName,"shaders",.7),await a.renderingView.compileAsync(),this.checkIntent(r),this.loading(n.sceneName,"textures",.82),await a.renderingView.initTexturesAsync(),this.checkIntent(r),"webgpu"===a.renderingView.activeBackend){this.loading(n.sceneName,"vfx-warmup",.94);const e=C(a.container,e=>e.get(I).beginPipelineWarmup());try{const e=performance.now();console.info("[Hology GPU VFX warmup] Rendering loading frame",n.sceneName),a.renderingView.render(0),console.info("[Hology GPU VFX warmup] Render returned; waiting for GPU queue",{sceneName:n.sceneName,renderMs:performance.now()-e}),await(a.renderingView.webGpuDevice?.queue.onSubmittedWorkDone()),console.info("[Hology GPU VFX warmup] GPU queue completed",{sceneName:n.sceneName,totalMs:performance.now()-e})}finally{e()}}return this.checkIntent(r),await e(a.renderingView.webGpuDevice,!1,"playing: "+n.sceneName),a.gameInstance instanceof GameInstance&&await a.gameInstance.onStart(),this.checkIntent(r),a.viewController.paused=!1,this.renderingHost.activate(a.renderingView),this.setState({type:"playing",sceneName:n.sceneName}),a}catch(e){throw await this.disposeSession(a,!1),F(e)||this.shutdownFlag||r!==this.transitionIntent||this.setState({type:"error",operation:"load",error:e}),e}}createSession(e){const i=t.of("hology-session-"+ ++x);this.copyApplicationServices(i);const n=this.renderingHost.createView(),s=new l(n);s.paused=!0,i.set(p,n),i.set(l,s);const h={...u,...this.config.components??{}},m=new z;null!=e.persistence&&m.configure(e.persistence),i.set(z,m);const g=new r(i,{inEditor:!1});g.classes=this.config.actors,i.set(r,g);const y=new o(n.scene,new a,this.getApplicationService(w),this.getApplicationService(f),n,Object.entries(this.config.shaders).map(([e,t])=>({name:e,type:t})),Object.entries(this.config.actors).map(([e,t])=>({name:e,type:t})),g,Object.entries(h).map(([e,t])=>({name:e,type:t})));y.inEditor=!1,y.netMode=e.multi?.session.mode??A.none,i.set(o,y);const v=C(i,e=>e.get(c));m.enabled&&(v.persistence=m),v.scene=n.scene,i.set(c,v);const S=C(i,e=>e.get(d));i.set(d,S);const b=new H;b.bind(async e=>{await this.transitionScene(e)}),i.set(H,b);const j=C(i,e=>e.get(P));i.set(P,j);const I=C(i,e=>e.get(V));return i.set(V,I),null==e.multi?.session&&j.startStandalone(e.localPlayer??{id:"local-player",displayName:"Player"}),{sceneName:e.sceneName,detailTier:e.detailTier,container:i,renderingView:n,viewController:s,actorFactory:g,materializer:y,world:v,physics:S,components:h,sceneTransition:b,sceneRoots:[],netMode:e.multi?.session.mode??A.none,stopPlayers:null==e.multi?.session?()=>{j.stop(),I.stop()}:void 0}}async performSceneTransition(t,i,n){if(t.netMode!==A.none)throw new Error("In-session scene transitions are not yet supported for network sessions");const r=i.scene.id.trim();if(0===r.length)throw new Error("A destination scene id is required");await e(t.renderingView.webGpuDevice,!0,"transition: "+r);const a=t.sceneName,c=t.viewController.paused;t.viewController.paused=!0,this.renderingHost.activate(this.renderingHost.applicationView),t.world.persistence?.captureAll(),this.setState({type:"unloading",sceneName:a}),t.world.stopSceneEventGraphs();const l=t.world.removeSceneLifetimeActors(t.sceneRoots);for(const e of t.sceneRoots)t.physics.removeRemoved(e),e.removeFromParent();t.sceneRoots=[],t.materializer.dispose(l),this.checkIntent(n),this.loading(r,"scene",.42);const p=await s(t.renderingView,r,this.config.dataDir,this.config.shaders,this.config.actors,t.components,t.actorFactory,this.getApplicationService(v),this.getApplicationService(w),this.getApplicationService(f),{detailTier:t.detailTier,nodeMode:t.netMode,persistence:t.world.persistence});this.checkIntent(n),t.materializer=p.materializer,t.sceneRoots=p.sceneRoots,t.sceneName=r,t.container.set(o,p.materializer),t.world.materializer=p.materializer,await this.restoreSceneActors(t,p.materializer,p.actors,n),t.physics.addFromScene(p.scene),await t.world.startSceneEventGraphs(p.materializer),await(i.afterLoad?.(t.world)),this.checkIntent(n),this.loading(r,"shaders",.7),await t.renderingView.compileAsync(),this.checkIntent(n),this.loading(r,"textures",.82),await t.renderingView.initTexturesAsync(),this.checkIntent(n),await e(t.renderingView.webGpuDevice,!1,"playing: "+r),t.sceneTransition.publish({previousSceneName:a,sceneName:r}),t.viewController.paused=c,this.renderingHost.activate(t.renderingView),this.setState({type:"playing",sceneName:r})}async restoreSceneActors(e,t,i,n){if(null==e.world.persistence){for(const t of i)e.world.addActor(t);return}const s=i.filter(t=>!e.world.actors.includes(t));for(const t of s)e.world.addActor(t,void 0,void 0,void 0,!0);const r=t.registerPersistentActors();await e.world.persistence.restore(r,()=>this.checkIntent(n)),this.checkIntent(n);for(const t of s)e.world.beginActorPlay(t)}copyApplicationServices(e){const t=[g,S,w,v,f,y,b];for(const i of t)e.set(i,this.applicationContainer.get(i))}async disposeSession(e,i){if(e.disposed)return;let n;e.disposed=!0,i&&this.setState({type:"unloading",sceneName:e.sceneName});try{e.viewController.paused=!0,e.world.persistence?.captureAll(),e.stopPlayers?.(),e.sceneTransition.dispose(),e.world.stopSceneEventGraphs(),e.gameInstance instanceof GameInstance&&await e.gameInstance.onUnload()}catch(e){n=e}finally{for(const t of[...e.world.actors])e.world.removeActor(t);e.physics.stop(),e.materializer.dispose(),this.renderingHost.activeView===e.renderingView&&this.renderingHost.activate(this.renderingHost.applicationView),e.viewController.dispose(!1),this.renderingHost.releaseView(e.renderingView),t.reset(e.container.id),this.session===e&&(this.session=void 0)}if(null!=n)throw n}enqueue(e){const t=this.transitionTail.then(e,e);return this.transitionTail=t.catch(()=>{}),t}checkIntent(e){if(this.assertRunning(),e!==this.transitionIntent)throw k()}assertRunning(){if(this.shutdownFlag)throw new Error("Hology application has been shut down")}loading(e,t,i){this.setState({type:"loading",sceneName:e,stage:t,progress:i})}setState(e){const t=this.renderingHost.applicationView;"loading"===e.type?t.stopAnimationLoop():"menu"!==e.type&&("error"!==e.type||"initialize"===e.operation)||this.renderingHost.activeView!==t||t.running||this.renderingHost.activate(t),this.stateSubject.next(e)}getOptionalApplicationService(e){return this.applicationContainer.has(e)?this.applicationContainer.get(e):void 0}}export class HologyRuntime{constructor(e,t){this.application=e,this.ready=t.then(()=>!0),this.shutdownStarted=e.shutdownStarted}get status(){return"playing"===this.application.currentState.type?5:"stopped"===this.application.currentState.type||"error"===this.application.currentState.type?10:0}get gameInstance(){return this.application.getGameInstance()}get isShutdown(){return"stopped"===this.application.currentState.type}getWorld(){return this.application.getWorld()}getService(e){return this.application.getService(e)}shutdown(){return this.application.shutdown()}}function k(){return new DOMException("Superseded by a newer game transition","AbortError")}function F(e){return e instanceof DOMException&&"AbortError"===e.name}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */
@@ -701,7 +701,7 @@ export declare class PhysicsSystem extends AbstractPhysicsSystem {
701
701
  * @param attr
702
702
  * @returns
703
703
  */
704
- export declare function extractFloat32Array(attr: THREE.BufferAttribute | THREE.InterleavedBufferAttribute): Float32Array;
704
+ export { extractFloat32Array } from '../../../scene/collision/rapier-shape.js';
705
705
  type ColliderCollisionEvent = {
706
706
  actor: BaseActor;
707
707
  };
@@ -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 j,TrimeshCollisionShape as _}from"../../../scene/collision/collision-shape.js";import{AssetMeshInstance as W}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as O}from"../../../scene/landscape/landscape.js";import{calculateEffectiveScale as N}from"../../../utils/three/traverse.js";import{ViewController as L}from"../render.js";import{World as k}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.colliderObjects=new WeakMap,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(L),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.lastEmptyPhysicsWorld=void 0,this.world.timestep=0,this.world.step()}updatePhysics(t){if(this._isStopped)return;this.world.timestep=t;const e=0===this.world.bodies.len()&&0===this.world.colliders.len();e&&this.lastEmptyPhysicsWorld===this.world||this.world.step(this.eventQueue),this.lastEmptyPhysicsWorld=e?this.world:void 0,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),i.hasHit=!1,i.actor=void 0,i.object=void 0,i.instanceId=void 0,i.batchId=void 0;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){const e=this.colliderObjects.get(l.collider);if(i.object=e?.object,i.instanceId=e?.instanceId,i.batchId=e?.batchId,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 O?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);const d=this.createStaticBody(c,l),h={object:t,batchId:n};bt(d,t=>this.colliderObjects.set(t,h))}}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);const n=this.createStaticBody(o,s),r={object:t,instanceId:e};bt(n,t=>this.colliderObjects.set(t,r))}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>j(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);const i=this.world.createCollider(l,t);this.colliderObjects.set(i,{object:n}),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);const i=this.world.createCollider(h,t);this.colliderObjects.set(i,{object:n}),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 O){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{const s=this.world.createCollider(o,t),n=i??(e instanceof T&&e.mesh instanceof b?e.mesh:void 0);return null!=n&&this.colliderObjects.set(s,{object:n}),s}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 _){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=N(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(k)}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{createRapierCollisionShape as i}from"../../../scene/collision/rapier-shape.js";import*as s from"@dimforge/rapier3d-simd-compat";import{QueryFilterFlags as o}from"@dimforge/rapier3d-simd-compat";import{BehaviorSubject as n,distinctUntilChanged as r,filter as a,map as l,Subject as c,takeUntil as d}from"rxjs";import*as h from"three";import{ArrowHelper as u,BufferAttribute as p,BufferGeometry as y,Group as g,LineSegments as m,Matrix4 as b,Object3D as w,Quaternion as f,Raycaster as v,Scene as x,Vector3 as B}from"three";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{ConvexPolyhedronCollisionShape as R,PhysicalShapeMesh as E,toInstancedCollisionShape as M}from"../../../scene/collision/collision-shape.js";import{AssetMeshInstance as T}from"../../../scene/asset-resource-loader.js";import{LandscapeGroup as P,LandscapeMesh as z}from"../../../scene/landscape/landscape.js";import{ViewController as F}from"../render.js";import{World as j}from"../world.js";import{AbstractPhysicsSystem as I}from"./abstract-physics-system.js";import{NetRole as _}from"../../net/index.js";export{ActorComponent,attach,Attach,Component}from"../../actors/component.js";export class RayTestResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.hitNormal=new B}}export class ShapeCastResult{constructor(){this.hasHit=!1,this.hitPoint=new B,this.normal=new B}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 N=new B,W=new B,O=new f,L=new f,k=new f;let V=class extends I{isLandscapeNavigationCollider(t){return this.colliderObjects.get(t)?.object instanceof z}forEachStaticActorNavigationCollider(t,e){const i=this.actorBodies.get(t.id);if(i?.isFixed()&&i.isEnabled()&&!0!==i.userData?.ignoreForNavMesh)for(let t=0;t<i.numColliders();t++){const s=i.collider(t);s.isEnabled()&&!s.isSensor()&&e(s)}}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.colliderObjects=new WeakMap,this.rayDebugArrowPool=[],this.activeRayDebugArrows=[],this.nonFixedBodies=new Set,this.collisionEvents=new c,this.beforeStep=new c,this.afterStep=new c,this.shouldRenderDebug=!1,this.viewController=C(F),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 v,this._reusableResult=new RayTestResult,this._raytestDiff=new B,this._raytestDirection=new B,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(N),i=t.getSize(W),s=this.getBoxShape(i.x/2,i.y/2,i.z/2);return null!=this.world.intersectionWithShape(e,O,s)}hasSphereIntersection(t){const e=this.getBallShape(t.radius);return null!=this.world.intersectionWithShape(t.center,O,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,O)&&o.push(n)}return o}createDebugMesh(){const t=new m(new y,new h.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 p(t,3);o.setUsage(h.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(o.ONLY_FIXED);this.updateDebugMesh(this.staticDebugMesh,t.vertices),this.staticDebugNeedsUpdate=!1}const t=this.world.debugRender(o.EXCLUDE_FIXED);this.updateDebugMesh(this.debugMesh,t.vertices)}async setup(){if(null!=this.rapier)throw new Error("Rapier is already estup");this.rapier=await nt(),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===_.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.lastEmptyPhysicsWorld=void 0,this.world.timestep=0,this.world.step()}updatePhysics(t){if(this._isStopped)return;this.world.timestep=t;const e=0===this.world.bodies.len()&&0===this.world.colliders.len();e&&this.lastEmptyPhysicsWorld===this.world||this.world.step(this.eventQueue),this.lastEmptyPhysicsWorld=e?this.world:void 0,this.eventQueue.drainCollisionEvents(this.handleCollisionEvent)}rayTestFromCamera(t,e,i){this._raycaster.setFromCamera(et,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,s){null==i&&(i=this._reusableResult),i.hasHit=!1,i.actor=void 0,i.object=void 0,i.instanceId=void 0,i.batchId=void 0;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==yt&&(yt=new this.rapier.Ray(new this.rapier.Vector3(0,0,0),new this.rapier.Vector3(0,1,0))),rt(yt.origin,t),rt(yt.dir,r);const l=this.world.castRayAndGetNormal(yt,a,!1,s?.excludeTriggers?o.EXCLUDE_SENSORS:void 0,s?.collisionFilter,void 0,null!=s?.excludeActor?this.actorBodies.get(s.excludeActor.id):void 0);if(i.hasHit=null!=l,i.actor=void 0,i.hasHit){const e=this.colliderObjects.get(l.collider);if(i.object=e?.object,i.instanceId=e?.instanceId,i.batchId=e?.batchId,i._internal=l,lt(i.hitNormal,l.normal),i.hitPoint.copy(t).addScaledVector(r,l.timeOfImpact),i.distance=l.timeOfImpact,!1!==s?.resolveActor){const t=l.collider.parent();i.actor=null!=t?this.bodyActors.get(t):null}}return this.showDebug&&!1!==s?.debug&&null!=this.scene&&this.drawRayDebugArrow(r,t,a,s?.debugColor,s?.debugLifetime),i}drawRayDebugArrow(t,e,i,s=255,o=200){let n=this.rayDebugArrowPool.pop();null==n?n=new u(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 X.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())ct(t,t=>t.setActiveEvents(s.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 E&&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 T){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 P?this.addLandscapeGroup(t):(t instanceof g||t instanceof x)&&t.children.forEach(t=>this.addRecursively(t))}createForInstancedMesh(t,e){const i=new b;if(t instanceof h.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 T&&(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 w;c.matrix.identity(),null!=a?i.copy(a):t.getMatrixAt(n,i),c.applyMatrix4(i);const d=this.createStaticBody(c,l),h={object:t,batchId:n};ct(d,t=>this.colliderObjects.set(t,h))}}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 w;o.matrix.identity(),i.fromArray(t.instanceMatrix.array,16*e),o.applyMatrix4(i);const n=this.createStaticBody(o,s),r={object:t,instanceId:e};ct(n,t=>this.colliderObjects.set(t,r))}}}instancedShapeReset(t){return t.filter(t=>null!=t).map(t=>M(t))}getCharacterController(t){return this.world?.createCharacterController(t)}getActorComputedMovement(t,e,i,s=null){const n=this.actorBodies.get(t.id);this.controlledActors.add(t.id);const r=n.collider(0);e.computeColliderMovement(r,i,o.EXCLUDE_SENSORS,s,void 0);const a=e.computedMovement();return lt(dt,a),dt}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(pt)??q,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),J.set(0,s,0).multiply(r),rt(H,J),n.setTranslationWrtParent(H),o.recomputeMassPropertiesFromColliders(),o.isFixed()&&this.invalidateStaticDebug(),!0}hasActorCapsuleIntersection(t,e,i,s,n,r=null){const a=this.actorBodies.get(t.id),l=t.object?.getWorldScale(pt)??q,c=Math.max(0,i*Math.abs(l.y)),d=Math.max(.001,s*Math.max(Math.abs(l.x),Math.abs(l.z))),h=new this.rapier.Capsule(c/2,d),u=t.object?.getWorldQuaternion(k)??O;J.set(0,n,0).multiply(l).applyQuaternion(u).add(e);return null!=this.world.intersectionWithShape(J,u,h,o.EXCLUDE_SENSORS,r??void 0,void 0,a,ut)}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,s=null){const n=t.collider;e.computeColliderMovement(n,i,o.EXCLUDE_SENSORS,s,void 0);const r=e.computedMovement();return lt(dt,r),dt}setNextKinematicTranslation(t,e){const i=this.actorBodies.get(t.id),s=i.translation(H);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(U),s=e.getWorldQuaternion(K);t.setNextKinematicTranslation(it(i)),t.setNextKinematicRotation(st(s))}(this.actorBodies.get(t.id),t.object)}setAngularVelocity(t,e){const i=this.actorBodies.get(t.id);H.x=e.x,H.y=e.y,H.z=e.z,i?.setAngvel(H,!0)}setLinearVelocity(t,e){const i=this.actorBodies.get(t.id);H.x=e.x,H.y=e.y,H.z=e.z,i?.setLinvel(H,!0)}getLinearVelocity(t,e=new B){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 B){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(it(e),!1)}getPosition(t,e=new B){const i=this.actorBodies.get(t.id);i&&i.translation(e)}setRotation(t,e){const i=this.actorBodies.get(t.id);i?.setRotation(st(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,i=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 B);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);rt(e,o),t.setTranslation(e,!1);const i=this.world.createCollider(l,t);this.colliderObjects.set(i,{object:n}),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=i.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=s.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);rt(e,o),t.setTranslation(e,!1);const i=this.world.createCollider(h,t);this.colliderObjects.set(i,{object:n}),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);ht.set(e,!i.isTrigger)}return i.type!==PhysicsBodyType.static&&this.nonFixedBodies.add(n),ct(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)}),G(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);H.x=e.x,H.y=e.y,H.z=e.z,i?.addTorque(H,!0)}applyTorqueImpulse(t,e){const i=this.actorBodies.get(t.id);H.x=e.x,H.y=e.y,H.z=e.z,i?.applyTorqueImpulse(H,!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);H.x=e.x,H.y=e.y,H.z=e.z,i?.addForce(H,!0)}applyImpulse(t,e){const i=this.actorBodies.get(t.id);H.x=e.x,H.y=e.y,H.z=e.z,i?.applyImpulse(H,!0)}applyLocalForce(t,e,i){const s=this.actorBodies.get(t.id);rt(H,e),null==i?s?.addForce(H,!0):(rt(Q,i),s?.addForceAtPoint(H,Q,!0))}applyLocalImpulse(t,e,i){const s=this.actorBodies.get(t.id);rt(H,e),null==i?s.applyImpulse(H,!0):(rt(Q,i),s.applyImpulseAtPoint(H,Q,!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)),rt(H,s),t.applyImpulse(H,!0)})}applyDirectionalImpulse(t,e,i,s,o){if(i<=0||0===o||e.lengthSq()<=1e-12)return 0;Y.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(Y)<n)return!1;H.x=Y.x*o,H.y=Y.y*o,H.z=Y.z*o,t.applyImpulse(H,!0)})}applyImpulseToBodiesInRadius(t,e,i){const s=$,n=tt;s.clear(),n.length=0;let r=0;this.world.intersectionsWithShape(t,O,this.getBallShape(e),t=>{const e=t.parent();return null==e||s.has(e.handle)||(s.add(e.handle),n.push(e)),!0},o.ONLY_DYNAMIC|o.EXCLUDE_SENSORS);for(const e of n)lt(Z,e.worldCom()),Z.sub(t),!1!==i(e,Z,Z.length())&&r++;return s.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 P){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(d(t.disposed),a(({started:t})=>t===i),l(({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})),a(({a1:i,a2:s})=>null!=i&&null!=s&&i.id===t.id&&e(i,s)),l(({a2:t})=>t))}onBeginContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(d(t.disposed),a(t=>t.started),a(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),l(t=>t.handle2))}onEndContact(t){return this.activateActorEvents(t),this.collisionEvents.pipe(d(t.disposed),a(t=>!t.started),a(({handle1:e})=>{const i=this.bodyActors.get(this.world.getCollider(e)?.parent());return null!=i&&i.id===t.id}),l(t=>t.handle2))}onHasContactChanged(t){const e=new Set,i=new n(!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(r())}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&&(G(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,s,n=ShapeCastResult.shared,r){n.reset();const a=this.getBallShape(e);H.x=i.x,H.y=i.y,H.z=i.z;const l=r?.excludeActor?this.actorBodies.get(r.excludeActor.id):null,c=this.world.castShape(t,O,H,a,.01,s,!0,r?.excludeTriggers?o.EXCLUDE_SENSORS:void 0,r?.collisionFilter??void 0,null,l);if(null!=c){lt(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 lt(s.hitPoint,u.witness1),mt(t.rotation(),u.normal1,s.normal,L),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,i){const o=i?.type===PhysicsBodyType.dynamic?s.RigidBodyDesc.dynamic():s.RigidBodyDesc.fixed(),n=this.world.createRigidBody(o);i?.type===PhysicsBodyType.dynamic&&this.nonFixedBodies.add(n);let r=0;for(const s of e){if(r>128){console.warn("Too many collision shapes for object",t);break}if(r++,null==s){console.warn("Collision shape is missing for object",t);continue}const o=this.addShape(n,s,t);null!=o&&(null!=i?.friction&&o.setFriction(i.friction),null!=i?.density&&o.setDensity(i.density),null!=i?.mass&&o.setMass(i.mass/e.length),null!=i?.restitution&&o.setRestitution(i.restitution))}return G(n,t),n.userData=t.uuid,n.isFixed()&&this.invalidateStaticDebug(),n}addShape(t=void 0,e,i){const s=i?.getWorldScale(pt)??q,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);rt(o.translation,n);const r=(new f).setFromEuler(e.rotation);at(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{const s=this.world.createCollider(o,t),n=i??(e instanceof R&&e.mesh instanceof w?e.mesh:void 0);return null!=n&&this.colliderObjects.set(s,{object:n}),s}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=s.MassPropsMode.Density),null!=e.mass&&(t.mass=e.mass,t.massPropsMode=s.MassPropsMode.Mass)}createShape(t,e){return i(this.rapier,t,e)}createCharacterCollision(){return new this.rapier.CharacterCollision}};V=t([D(),e("design:paramtypes",[])],V);export{V as PhysicsSystem};const U=new B,K=new h.Quaternion;function G(t,e){const i=e.getWorldPosition(U),s=e.getWorldQuaternion(K);t.setTranslation(it(i),!1),t.setRotation(st(s),!1)}const X=new B,q=new B(1,1,1),H=new s.Vector3(0,0,0),Q=new s.Vector3(0,0,0),J=new B,Y=new B,Z=new B,$=new Set,tt=[],et=new h.Vector2;function it(t){return rt(H,t),H}function st(t){return at(L,t),L}let ot=null;const nt=async()=>(null==ot&&(ot=(async()=>{let t=await import("@dimforge/rapier3d-simd-compat");return await t.init(),t})()),ot);function rt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function at(t,e){t.x=e.x,t.y=e.y,t.z=e.z,t.w=e.w}function lt(t,e){t.x=e.x,t.y=e.y,t.z=e.z}function ct(t,e){for(let i=0,s=t.numColliders();i<s;i++){e(t.collider(i))}}const dt=new B,ht=new WeakMap,ut=t=>ht.get(t)??!0,pt=new B;let yt,gt=class extends S{constructor(){super(...arguments),this._active=!0,this.physics=C(V),this.world=C(j)}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}};gt=t([A()],gt);export{extractFloat32Array}from"../../../scene/collision/rapier-shape.js";function mt(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 c,this.onBeginOverlapActor=new c,this.onEndOverlapActor=new c}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 s.RigidBodyType.Dynamic;case PhysicsBodyType.static:return s.RigidBodyType.Fixed;case PhysicsBodyType.kinematic:return s.RigidBodyType.KinematicPositionBased;case PhysicsBodyType.kinematicVelocityBased:return s.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
  */
@@ -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{FrameAudioListener as r}from"../../utils/three/frame-audio-listener.js";import{RenderingView as s}from"../../rendering.js";import{BehaviorSubject as n,Subject as h,takeUntil as o}from"rxjs";import*as m from"three";import{GameTimeScheduler as u}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as c,sampleCameraShake as d}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let p=class{constructor(e){this.view=e,this.tick=new h,this.lateTick=new h,this.audioListener=new r,this.pausedChanged=new n(!1),this.mutedChanged=new n(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new u,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this._updateFrameIndex=0,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)}get updateFrameIndex(){return this._updateFrameIndex}handleFrame(e){this._updateFrameIndex++;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}get time(){return performance.now()/1e3}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(o(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(o(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 m.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(f)),t.quaternion.copy(e.getWorldQuaternion(k)),t.scale.copy(e.getWorldScale(w)),t.layers.mask=e.layers.mask,e instanceof m.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(){c(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=d(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){y.copy(e.quaternion),x.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),x.applyQuaternion(y),e.position.add(x),P.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),b.setFromEuler(P),e.quaternion.copy(y).multiply(b),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=v){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.disposePoseUpdates(),this.audioListener.removeFromParent(),this.tick.complete(),this.lateTick.complete(),this.paused=!0}createTimer(e){return this.scheduler.createTimer(e)}getScreenPosition(e,t=g,a=this.getViewportSize()){const i=this.getCamera();return C.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof m.PerspectiveCamera&&(S.setFromProjectionMatrix(C),!S.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)}};p=e([a(),t("design:paramtypes",[s])],p);export{p as ViewController};const C=new m.Matrix4,g=new m.Vector3,v=new m.Vector2,S=new m.Frustum,f=new m.Vector3,w=new m.Vector3,k=new m.Quaternion,y=new m.Quaternion,x=new m.Vector3,P=new m.Euler(0,0,0,"XYZ"),b=new m.Quaternion;/*
1
+ import{__decorate as e,__metadata as t}from"tslib";import{Service as a}from"typedi";import{Camera as i}from"three";import{FrameAudioListener as r}from"../../utils/three/frame-audio-listener.js";import{RenderingView as s}from"../../rendering.js";import{BehaviorSubject as n,Subject as h,takeUntil as o}from"rxjs";import*as m from"three";import{GameTimeScheduler as u}from"./game-time-scheduler.js";import{createCameraShakeSample as l,resetCameraShakeSample as c,sampleCameraShake as d}from"./camera-shake.js";export{defaultPostProcessEffectStage,postProcessEffectStages}from"../../rendering/post-process-effect.js";let p=class{constructor(e){this.view=e,this.tick=new h,this.lateTick=new h,this.audioListener=new r,this.pausedChanged=new n(!1),this.mutedChanged=new n(!1),this._muted=!1,this._masterVolume=1,this._cameraShakeIntensity=1,this._timeScale=1,this._hitStopRemaining=0,this.scheduler=new u,this.cameraOverrideId=0,this.cameraOverrides=[],this.cameraShakeId=0,this.gameplayCameraShakes=[],this.cameraShakeContributions=new Map,this.presentationCamera=null,this.accumulatedCameraShakeSample=l(),this.scratchCameraShakeSample=l(),this._updateFrameIndex=0,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)}get updateFrameIndex(){return this._updateFrameIndex}handleFrame(e){this._updateFrameIndex++;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}get time(){return performance.now()/1e3}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(o(e.disposed))}onLateUpdate(e){return null==e?this.lateTick:this.lateTick.pipe(o(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 m.PerspectiveCamera,this.presentationCamera.name="View Controller Presentation Camera"),this.presentationCamera}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(f)),t.quaternion.copy(e.getWorldQuaternion(k)),t.scale.copy(e.getWorldScale(w)),t.layers.mask=e.layers.mask,e instanceof m.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(){c(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=d(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){y.copy(e.quaternion),x.set(this.accumulatedCameraShakeSample.position[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.position[2]*this._cameraShakeIntensity),x.applyQuaternion(y),e.position.add(x),P.set(this.accumulatedCameraShakeSample.rotation[0]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[1]*this._cameraShakeIntensity,this.accumulatedCameraShakeSample.rotation[2]*this._cameraShakeIntensity),b.setFromEuler(P),e.quaternion.copy(y).multiply(b),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),this.view.setEnableOutlines(this.outlined.length>0))}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=v){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.disposePoseUpdates(),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 g.multiplyMatrices(i.projectionMatrix,i.matrixWorldInverse),i instanceof m.PerspectiveCamera&&(S.setFromProjectionMatrix(g),!S.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)}};p=e([a(),t("design:paramtypes",[s])],p);export{p as ViewController};const g=new m.Matrix4,C=new m.Vector3,v=new m.Vector2,S=new m.Frustum,f=new m.Vector3,w=new m.Vector3,k=new m.Quaternion,y=new m.Quaternion,x=new m.Vector3,P=new m.Euler(0,0,0,"XYZ"),b=new m.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,68 @@
1
+ /** Renderer-independent navigation input extraction and Recast baking. Safe to import in Node. */
2
+ import * as RAPIER from '@dimforge/rapier3d-simd-compat';
3
+ import { Box3, BufferGeometry, Matrix4 } from 'three';
4
+ import { type RecastConfig } from 'recast-navigation';
5
+ import type { SceneObject } from '../scene/materializer.js';
6
+ import type { Asset } from '../scene/model.js';
7
+ import type { CollisionShape } from '../scene/collision/collision-shape.js';
8
+ import { type BuildTileMeshProps } from '../gameplay/ai/build-tile.js';
9
+ import { type NavigationAreaModifier } from '../gameplay/ai/navigation-areas.js';
10
+ export { importCollisionShapes } from '../scene/collision/collision-shape-import.js';
11
+ export { createAuthoredCollisionShapes } from '../scene/collision/authored-colliders.js';
12
+ export { decodeStorageValue, parseStorageJson } from '../scene/storage/packed-json.js';
13
+ export type { CollisionShape, Asset, SceneObject };
14
+ export declare const NAVIGATION_BAKE_VERSION = "navigation-1-recast-0.39.0";
15
+ export type NavigationGeometry = {
16
+ positions: Float32Array;
17
+ indices: Uint32Array;
18
+ };
19
+ export type NavigationBakeReference = {
20
+ file: string;
21
+ settings: string;
22
+ };
23
+ export type NavigationBakes = Record<string, NavigationBakeReference>;
24
+ export type NavigationVolume = {
25
+ id: string;
26
+ bounds: Box3;
27
+ config: RecastConfig;
28
+ settings: string;
29
+ };
30
+ export type NavigationSceneEntry = {
31
+ id: string;
32
+ source: SceneObject;
33
+ matrix: Matrix4;
34
+ };
35
+ export type NavigationContribution = {
36
+ geometry?: NavigationGeometry[];
37
+ modifiers?: NavigationAreaModifier[];
38
+ };
39
+ export type NavigationBakeOptions = {
40
+ objects: SceneObject[];
41
+ assets: Asset[];
42
+ /** Model loading is supplied by the host; no textures or renderer are required. */
43
+ loadCollisionShapes(asset: Asset): Promise<CollisionShape[]>;
44
+ /** Explicit headless counterpart for game actors which create static collision or areas. */
45
+ contribute?(entry: NavigationSceneEntry): Promise<NavigationContribution | undefined>;
46
+ };
47
+ export declare function navigationConfig(bounds: Box3, params: {
48
+ cellSize?: number;
49
+ walkableClimb?: number;
50
+ walkableSlopeAngle?: number;
51
+ walkableHeight?: number;
52
+ }): RecastConfig;
53
+ export declare function navigationSettings(bounds: Box3, config: RecastConfig): string;
54
+ export declare function navigationEntries(objects: SceneObject[], assets: Asset[]): NavigationSceneEntry[];
55
+ export declare function navigationVolumes(entries: NavigationSceneEntry[]): NavigationVolume[];
56
+ export declare function initializeNavigationBaker(): Promise<unknown>;
57
+ /** Converts a Rapier shape, preserving 32-bit mesh indices. No debug inflation is applied. */
58
+ export declare function navigationShapeGeometry(shape: RAPIER.Shape): BufferGeometry;
59
+ export declare function navigationGeometryInput(geometry: BufferGeometry, matrix: Matrix4): NavigationGeometry;
60
+ /** Canonical static collision inputs; reusable by future collision-data baking. */
61
+ export declare function collectNavigationInputs(options: NavigationBakeOptions, entries: NavigationSceneEntry[], bounds: Box3): Promise<NavigationContribution>;
62
+ /** Full authored density and holes, independent of streamed render/physics sections. */
63
+ export declare function landscapeNavigationGeometry(source: SceneObject, matrix: Matrix4, bounds: Box3): NavigationGeometry[];
64
+ export declare function mergeNavigationGeometry(inputs: NavigationGeometry[]): NavigationGeometry;
65
+ export type NavigationTileBuilder = (job: BuildTileMeshProps) => Promise<Uint8Array | undefined>;
66
+ /** Jobs can run in browser workers; Node executes the same tile builder directly. */
67
+ export declare function bakeNavigation(volume: NavigationVolume, inputs: NavigationContribution, build?: NavigationTileBuilder, signal?: AbortSignal): Promise<Uint8Array>;
68
+ //# sourceMappingURL=bake.d.ts.map
@@ -0,0 +1,4 @@
1
+ import*as e from"@dimforge/rapier3d-simd-compat";import{Box3 as t,BoxGeometry as o,BufferAttribute as a,BufferGeometry as i,CapsuleGeometry as n,ConeGeometry as r,CylinderGeometry as s,Euler as l,Float32BufferAttribute as c,Matrix4 as p,Quaternion as m,SphereGeometry as f,Vector3 as h}from"three";import{ConvexGeometry as d}from"three/examples/jsm/geometries/ConvexGeometry.js";import{NavMesh as u,NavMeshParams as y,Raw as g,UnsignedCharArray as w,exportNavMesh as x,init as v,recastConfigDefaults as M}from"recast-navigation";import{ShapeLibrary as b}from"../scene/objects/shapes.js";import{createRapierCollisionShape as A}from"../scene/collision/rapier-shape.js";import{buildConfig as S,buildTile as E}from"../gameplay/ai/build-tile.js";import{NavigationArea as I}from"../gameplay/ai/navigation-areas.js";import{SplineData as T}from"./spline-data.js";import{createCrossSections as N}from"./water-spline-geometry.js";export{importCollisionShapes}from"../scene/collision/collision-shape-import.js";export{createAuthoredCollisionShapes}from"../scene/collision/authored-colliders.js";export{decodeStorageValue,parseStorageJson}from"../scene/storage/packed-json.js";export const NAVIGATION_BAKE_VERSION="navigation-1-recast-0.39.0";export function navigationConfig(e,t){const o=Math.max(t.cellSize??.2,.01),a=Math.round(1e6*Math.max(1,Math.min(e.max.x-e.min.x,e.max.z-e.min.z)))/1e6;return{...M,tileSize:Math.max(32,Math.floor(Math.min(400,Math.max(50,Math.ceil(a/2)))/o)),walkableClimb:(t.walkableClimb??.3)/o,walkableSlopeAngle:t.walkableSlopeAngle??45,walkableRadius:2,walkableHeight:(t.walkableHeight??2)/o,detailSampleDist:1,minRegionArea:6,mergeRegionArea:400,cs:o,ch:o,maxSimplificationError:1.3,maxEdgeLen:200}}export function navigationSettings(e,t){const o=e=>e.map(e=>Math.round(1e6*e)/1e6);return JSON.stringify([NAVIGATION_BAKE_VERSION,o(e.min.toArray()),o(e.max.toArray()),t])}export function navigationEntries(e,t){const o=new Map(t.map(e=>[e.id,e])),a=[];return function e(t,i,n,r){for(const s of t){const t=(new p).compose((new h).fromArray(s.position??[0,0,0]),(new m).setFromEuler((new l).fromArray(s.rotation??[0,0,0])),(new h).fromArray(s.scale??[1,1,1])).premultiply(i),c=n+s.id;if(a.push({id:c,source:s,matrix:t}),"prefab"===s.type){const a=o.get(s.assetId);if(!a?.prefab)throw new Error(`Missing navigation prefab ${s.assetId}`);if(r.has(a.id))throw new Error(`Cyclic navigation prefab ${a.id}`);const i=new Set(r).add(a.id);e(a.prefab.objects.map(e=>e.id===a.prefab.mainActorId?{...e,actor:{...e.actor,params:{...e.actor?.params,...s.prefab?.params},innerParams:s.prefab?.innerParams??e.actor?.innerParams}}:e),t,c+"/",i)}s.children&&e(s.children,t,n,r)}}(e,new p,"",new Set),a}export function navigationVolumes(e){return e.filter(e=>["NavMesh","NavMeshActor"].includes(e.source.actor?.type)).map(e=>{const o=new h,a=new m,i=new h;if(e.matrix.decompose(o,a,i),i.set(Math.abs(i.x),Math.abs(i.y),Math.abs(i.z)),Math.min(i.x,i.y,i.z)<=0)throw new Error(`Empty navigation volume ${e.id}`);const n=(new t).setFromCenterAndSize(o,i),r=navigationConfig(n,Object.fromEntries(Object.entries(e.source.actor.params??{}).map(([e,t])=>[e,t.value])));return{id:e.id,bounds:n,config:r,settings:navigationSettings(n,r)}})}let j;export function initializeNavigationBaker(){return j??(j=Promise.all([v(),e.init()]).catch(e=>{throw j=void 0,e}))}export function navigationShapeGeometry(t){switch(t.type){case e.ShapeType.Cuboid:{const e=t;return new o(2*e.halfExtents.x,2*e.halfExtents.y,2*e.halfExtents.z)}case e.ShapeType.Ball:return new f(t.radius);case e.ShapeType.Capsule:{const e=t;return new n(e.radius,2*e.halfHeight)}case e.ShapeType.Cylinder:{const e=t;return new s(e.radius,e.radius,2*e.halfHeight)}case e.ShapeType.Cone:{const e=t;return new r(e.radius,2*e.halfHeight)}case e.ShapeType.TriMesh:{const e=t,o=new i;return o.setAttribute("position",new c(e.vertices,3)),o.setIndex(new a(Uint32Array.from(e.indices),1)),o}case e.ShapeType.ConvexPolyhedron:{const e=t,o=[];for(let t=0;t<e.vertices.length;t+=3)o.push((new h).fromArray(e.vertices,t));return new d(o)}default:throw new Error(`Unsupported navigation collision shape ${t.type}`)}}export function navigationGeometryInput(e,t){const o=e.getAttribute("position"),a=new Float32Array(3*o.count),i=new h;for(let e=0;e<o.count;e++)i.fromBufferAttribute(o,e).applyMatrix4(t).toArray(a,3*e);const n=e.index?Uint32Array.from(e.index.array):Uint32Array.from({length:o.count},(e,t)=>t);if(t.determinant()<0)for(let e=0;e<n.length;e+=3)[n[e+1],n[e+2]]=[n[e+2],n[e+1]];return{positions:a,indices:n}}export async function collectNavigationInputs(t,o,a){await initializeNavigationBaker();const i=new Map(t.assets.map(e=>[e.id,e])),n=[],r=[];for(const s of o){const{source:o,matrix:l}=s,c=await(t.contribute?.(s));if(c&&(n.push(...c.geometry??[]),r.push(...c.modifiers??[])),"WaterVolume"===o.actor?.type){const e=[-.5,.5].flatMap(e=>[-.5,.5].flatMap(t=>[-.5,.5].map(o=>new h(e,t,o).applyMatrix4(l))));r.push({area:I.Water,vertices:[[-.5,0,-.5],[.5,0,-.5],[.5,0,.5],[-.5,0,.5]].map(e=>(new h).fromArray(e).applyMatrix4(l).toArray()),minHeight:Math.min(...e.map(e=>e.y)),maxHeight:Math.max(...e.map(e=>e.y))})}if("WaterSplineVolume"===o.actor?.type){const e=new T,t=o.actor.innerParams?.find(e=>"spline"===e.path.join("."))?.params.splineData;e.setData(t?.value??e.splineData,!1);const a=Number(o.actor.params?.width?.value??5),i=Number(o.actor.params?.depth?.value??2),n=N(e,a,i);for(let e=1;e<n.length;e++){const t=n[e-1],o=n[e],a=[t.leftTop,t.rightTop,o.rightTop,o.leftTop,t.leftBottom,t.rightBottom,o.rightBottom,o.leftBottom].map(e=>e.clone().applyMatrix4(l));r.push({area:I.Water,vertices:a.slice(0,4).map(e=>e.toArray()),minHeight:Math.min(...a.map(e=>e.y)),maxHeight:Math.max(...a.map(e=>e.y))})}}if(!1===o.collisionDetection||null!=o.physics?.type&&2!==o.physics.type)continue;if("landscape"===o.shape&&o.landscape){n.push(...landscapeNavigationGeometry(o,l,a));continue}let f=[];if("shape_mesh"===o.type&&o.shape&&"landscape"!==o.shape){const e=b[o.shape];if(!e)throw new Error(`Unsupported navigation primitive ${o.shape}`);const t=Object.fromEntries(Object.entries(o.shapeParams??{}).map(([e,t])=>[e,t.value])),a=e.collision(t);a&&(f=[a])}else if("asset_mesh"===o.type){const e=i.get(o.assetId);if(!e){console.warn(`[Hology navigation] Missing scene mesh ${o.assetId} on ${s.id}; no collision exists to bake`);continue}if(!0!==e.collisionDetection)continue;f=await t.loadCollisionShapes(e)}const d=new h,u=new m,y=new h;l.decompose(d,u,y);for(const t of f){const o=A(e,t,y);if(!o)throw new Error(`Invalid navigation collision on ${s.id}`);const a=t.offset.clone().multiply(y).applyQuaternion(u).add(d),i=(new p).compose(a,u.clone().multiply((new m).setFromEuler(t.rotation)),new h(1,1,1)),r=navigationShapeGeometry(o.shape);n.push(navigationGeometryInput(r,i)),r.dispose()}}return{geometry:n,modifiers:r}}export function landscapeNavigationGeometry(e,t,o){const{options:a,heightMaps:i=[],holes:n=[]}=e.landscape,{sectionSize:r,density:s,sections:l}=a;if(!Number.isInteger(s)||s<1||r<=0)throw new Error(`Invalid landscape settings on ${e.id}`);const c=o.clone().applyMatrix4(t.clone().invert()),p=l.x*r/-2,m=l.y*r/-2,f=Math.max(0,Math.ceil((c.min.x-p-r/2)/r)),d=Math.min(l.x-1,Math.floor((c.max.x-p+r/2)/r)),u=Math.max(0,Math.ceil((c.min.z-m-r/2)/r)),y=Math.min(l.y-1,Math.floor((c.max.z-m+r/2)/r)),g=new Map(i.map(e=>[`${e.x},${e.y}`,e])),w=new Map;for(const e of n)if(e.w[0]>.5){let t=w.get(e.m);t||w.set(e.m,t=new Set),t.add(e.i)}const x=[],v=new h,M=s+1;for(let e=f;e<=d;e++)for(let o=u;o<=y;o++){const a=`${e},${o}`,i=new Float32Array(M*M*3),n=new Float32Array(M*M);for(const e of g.get(a)?.points??[])n[e.i]=e.y;for(let a=0;a<M;a++)for(let l=0;l<M;l++){const c=a*M+l;v.set(p+e*r-r/2+l*r/s,n[c],m+o*r-r/2+a*r/s).applyMatrix4(t).toArray(i,3*c)}const l=[],c=w.get(a),f=t.determinant()<0,h=(e,t,o)=>{c?.has(e)||c?.has(t)||c?.has(o)||l.push(e,f?o:t,f?t:o)};for(let e=0;e<s;e++)for(let t=0;t<s;t++){const o=e*M+t,a=o+M;h(o,a,o+1),h(a,a+1,o+1)}x.push({positions:i,indices:Uint32Array.from(l)})}return x}export function mergeNavigationGeometry(e){let t=0,o=0;for(const a of e)t+=a.positions.length,o+=a.indices.length;const a=new Float32Array(t),i=new Uint32Array(o);let n=0,r=0;for(const t of e){a.set(t.positions,n);for(let e=0;e<t.indices.length;e++)i[r+e]=t.indices[e]+n/3;n+=t.positions.length,r+=t.indices.length}return{positions:a,indices:i}}export async function bakeNavigation(e,t,o,a){await initializeNavigationBaker();let{positions:i,indices:n}=mergeNavigationGeometry(t.geometry??[]);if(o&&globalThis.crossOriginIsolated&&"undefined"!=typeof SharedArrayBuffer){const e=new Float32Array(new SharedArrayBuffer(i.byteLength)),t=new Uint32Array(new SharedArrayBuffer(n.byteLength));e.set(i),t.set(n),i=e,n=t}const r=[e.bounds.min.toArray(),e.bounds.max.toArray()],s=S({recastConfig:e.config,navMeshBounds:r});g.Module.destroy(s.config);const l=new u,c=y.create({orig:e.bounds.min,tileWidth:s.tcs,tileHeight:s.tcs,maxTiles:s.maxTiles,maxPolys:s.maxPolysPerTile}),p=l.initTiled(c);if(g.Module.destroy(c.raw),!p)throw l.destroy(),new Error("Could not initialize baked navmesh");try{let c=0,p=!1;const m=(await Promise.allSettled(Array.from({length:o?4:1},async()=>{try{for(;;){if(p)return;a?.throwIfAborted();const m=c++;if(m>=s.tileWidth*s.tileHeight)return;const f=m%s.tileWidth,h=Math.floor(m/s.tileWidth),d=e.bounds.min,u=e.bounds.max,y={positions:i,indices:n,recastConfig:e.config,navMeshBounds:r,tileX:f,tileY:h,tileBoundsMin:[d.x+f*s.tcs,d.y,d.z+h*s.tcs],tileBoundsMax:[d.x+(f+1)*s.tcs,u.y,d.z+(h+1)*s.tcs],keepIntermediates:!1,areaModifiers:t.modifiers??[]};let x;if(o){const e=await o(y);a?.throwIfAborted(),e&&(x=new w,x.copy(e))}else{const e=E(y);if(g.Module.destroy(e.buildContext.raw),!e.success)throw new Error("error"in e?e.error:"Navigation tile build failed");x=e.data}if(x){const e=l.addTile(x,g.Module.DT_TILE_FREE_DATA,0);if(g.Detour.statusFailed(e.status))throw x.destroy(),new Error(`Could not add baked navigation tile ${f},${h}`)}}}catch(e){throw p=!0,e}}))).find(e=>"rejected"===e.status);if(m)throw m.reason;return x(l)}finally{l.destroy()}}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -0,0 +1,11 @@
1
+ import { type NavigationBakeOptions } from './bake.js';
2
+ /** Content hash used for editor snapshots; binary resources are additionally versioned by the host. */
3
+ export declare function navigationCacheKey(options: NavigationBakeOptions, settings: string): Promise<string>;
4
+ export declare function editorNavigationFiles(): {
5
+ fs: typeof import('node:fs/promises');
6
+ path: typeof import('node:path');
7
+ root: string;
8
+ } | undefined;
9
+ export declare function readEditorNavigation(key: string): Promise<Uint8Array | undefined>;
10
+ export declare function writeEditorNavigation(slot: string, key: string, bytes: Uint8Array): Promise<void>;
11
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{NAVIGATION_BAKE_VERSION as t}from"./bake.js";export async function navigationCacheKey(i,a){const e=[],o=[...i.assets].sort((t,i)=>t.id.localeCompare(i.id)),n=editorNavigationFiles();if(n){for(const t of o)if("mesh"===t.type&&t.fileKey){const i=n.path.join(n.root,"public","data","asset-resources",t.fileKey);try{const a=await n.fs.stat(i);e.push([t.id,a.size,a.mtimeMs])}catch{e.push([t.id,"missing"])}}for(const t of["src","assets"]){const i=n.path.join(n.root,t);try{const a=(await n.fs.readdir(i,{recursive:!0})).sort();for(const o of a)if(/\.[cm]?[jt]sx?$/.test(o)){const a=await n.fs.stat(n.path.join(i,o));e.push([t,o,a.size,a.mtimeMs])}}catch{}}}const r=(new TextEncoder).encode(JSON.stringify([t,a,i.objects,o,e])),s=await crypto.subtle.digest("SHA-256",r);return Array.from(new Uint8Array(s),t=>t.toString(16).padStart(2,"0")).join("")}export function editorNavigationFiles(){if("undefined"==typeof window||!window.require)return;const t=window.process?.argv?.find(t=>t.startsWith("--path="))?.slice(7);return t?{fs:window.require("fs").promises,path:window.require("path"),root:t}:void 0}export async function readEditorNavigation(t){const a=editorNavigationFiles();if(!a)try{if("undefined"==typeof caches)return;const a=await(await caches.open("hology-navigation-1")).match(i(t));return a?new Uint8Array(await a.arrayBuffer()):void 0}catch{return}try{return new Uint8Array(await a.fs.readFile(a.path.join(a.root,".hology","cache","navigation-editor",t+".bin")))}catch{return}}export async function writeEditorNavigation(t,a,e){const o=editorNavigationFiles();if(!o){if("undefined"==typeof caches)return;const o=await caches.open("hology-navigation-1"),n=i("slot-"+encodeURIComponent(t)),r=await o.match(n),s=r?await r.text():void 0;return await o.put(i(a),new Response(Uint8Array.from(e))),await o.put(n,new Response(a)),void(s&&s!==a&&/^[a-f0-9]{64}$/.test(s)&&await o.delete(i(s)))}const n=o.path.join(o.root,".hology","cache","navigation-editor"),r=o.path.join(n,a+".bin");await o.fs.mkdir(n,{recursive:!0});const s=r+"."+Math.random().toString(36).slice(2)+".tmp";try{await o.fs.writeFile(s,e),await o.fs.rename(s,r);const i=o.path.join(n,encodeURIComponent(t)+".json");let c;try{c=JSON.parse(await o.fs.readFile(i,"utf8")).key}catch{}await o.fs.writeFile(i,JSON.stringify({key:a})),c&&c!==a&&/^[a-f0-9]{64}$/.test(c)&&await o.fs.unlink(o.path.join(n,c+".bin")).catch(()=>{})}finally{await o.fs.unlink(s).catch(()=>{})}}function i(t){return new URL("/__hology_navigation_cache/"+t,location.href).href}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -0,0 +1,64 @@
1
+ import { Subject } from 'rxjs';
2
+ import { Vector3 } from 'three';
3
+ export interface SplinePoint {
4
+ /** Actor-local point position. */
5
+ position: Vector3;
6
+ /** Actor-local offset from position to the incoming Bezier handle. */
7
+ inTangent: Vector3;
8
+ /** Actor-local offset from position to the outgoing Bezier handle. */
9
+ outTangent: Vector3;
10
+ }
11
+ export interface ClosestSplinePoint {
12
+ position: Vector3;
13
+ tangent: Vector3;
14
+ t: number;
15
+ distance: number;
16
+ distanceAlongSpline: number;
17
+ }
18
+ /** A generic cubic Bezier spline whose points and tangents are actor-local. */
19
+ export declare class SplineData {
20
+ /** Compact JSON is intentional: scene files keep the complete spline on one line. */
21
+ splineData: string;
22
+ /** Emits after an in-place authoring/runtime edit. Consumers can update incrementally. */
23
+ readonly changed: Subject<SplineData>;
24
+ private _points;
25
+ private _closed;
26
+ private arcLengths;
27
+ private arcTs;
28
+ private _length;
29
+ onInit(): void;
30
+ onEndPlay(): void;
31
+ get points(): readonly SplinePoint[];
32
+ get closed(): boolean;
33
+ get length(): number;
34
+ setData(data: string, emit?: boolean): void;
35
+ setPoints(points: readonly SplinePoint[], closed?: boolean): void;
36
+ updatePoint(index: number, point: SplinePoint): void;
37
+ addPoint(point: SplinePoint, index?: number): void;
38
+ /** Splits a Bezier segment without changing the shape of the spline. */
39
+ insertPointOnSegment(segmentIndex: number, t?: number): number;
40
+ removePoint(index: number): void;
41
+ setClosed(closed: boolean): void;
42
+ applySceneParameters(parameters: {
43
+ splineData?: string;
44
+ }, changed: Set<'splineData'>): boolean;
45
+ /** Samples an actor-local position using normalized t. */
46
+ samplePosition(t: number, target?: Vector3): Vector3;
47
+ sampleTangent(t: number, target?: Vector3): Vector3;
48
+ samplePositionAtDistance(distance: number, target?: Vector3): Vector3;
49
+ sampleTangentAtDistance(distance: number, target?: Vector3): Vector3;
50
+ /** Finds the closest actor-local point to an actor-local query position. */
51
+ closestPoint(point: Vector3, target?: Vector3): ClosestSplinePoint;
52
+ private commitChange;
53
+ private get segmentCount();
54
+ private resolveSegment;
55
+ private rebuildArcLengths;
56
+ private tAtDistance;
57
+ private distanceAtT;
58
+ }
59
+ export declare function packSplineData(points: readonly SplinePoint[], closed: boolean): string;
60
+ export declare function parseSplineData(data: string): {
61
+ points: SplinePoint[];
62
+ closed: boolean;
63
+ };
64
+ //# sourceMappingURL=spline-data.d.ts.map