@hology/core 0.0.64 → 0.0.66

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 (33) hide show
  1. package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +0 -9
  2. package/dist/gameplay/actors/builtin/navmesh-actor.d.ts +2 -5
  3. package/dist/gameplay/actors/builtin/navmesh-actor.js +1 -1
  4. package/dist/gameplay/actors/factory.d.ts +1 -1
  5. package/dist/gameplay/ai/behavior-tree/bt.d.ts +167 -0
  6. package/dist/gameplay/ai/behavior-tree/bt.js +5 -0
  7. package/dist/gameplay/ai/behavior-tree/move.d.ts +11 -0
  8. package/dist/gameplay/ai/behavior-tree/move.js +5 -0
  9. package/dist/gameplay/ai/dynamic-tiled-navmesh.js +1 -1
  10. package/dist/gameplay/ai/dynamic-tiled-navmesh.worker.d.ts +1 -1
  11. package/dist/gameplay/ai/dynamic-tiled-navmesh.worker.js +1 -1
  12. package/dist/gameplay/ai/index.d.ts +2 -0
  13. package/dist/gameplay/ai/index.js +1 -1
  14. package/dist/gameplay/index.d.ts +1 -1
  15. package/dist/gameplay/services/asset-loader.d.ts +1 -1
  16. package/dist/gameplay/services/physics/physics-system.js +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.js +1 -1
  19. package/dist/rendering.js +1 -1
  20. package/dist/scene/asset-resource-loader.js +1 -1
  21. package/dist/scene/landscape/landscape-manager.d.ts +3 -2
  22. package/dist/scene/landscape/landscape-manager.js +1 -1
  23. package/dist/scene/landscape/landscape.js +1 -1
  24. package/dist/scene/materializer.d.ts +1 -0
  25. package/dist/scene/materializer.js +1 -1
  26. package/dist/shader/shader.d.ts +3 -1
  27. package/dist/shader/shader.js +1 -1
  28. package/dist/utils/type.d.ts +1 -0
  29. package/dist/utils/type.js +1 -1
  30. package/dist/worker/index.d.ts +4 -0
  31. package/dist/worker/index.js +5 -0
  32. package/package.json +7 -3
  33. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,4 @@
1
- import{materialFromAsset as e}from"../../scene/materializer.js";import{Mesh as t,PlaneGeometry as s,Vector3 as n,InstancedMesh as o,Matrix4 as a,Vector2 as i,Triangle as r,Box3 as c,MathUtils as l,MeshStandardMaterial as h,ShaderMaterial as u,PerspectiveCamera as f}from"three";import{indexBy as d}from"../../utils/collections.js";import{smoothNormalsCrossMeshes as p}from"./utils.js";import{defaultLandscapeMaterial as m,LandscapeMesh as w}from"./landscape.js";import{meanVectors3withWeight as y}from"../../utils/math.js";import{whenIdle as g}from"../../utils/async.js";import{Subject as M,debounceTime as x}from"rxjs";new n,new n;const b=new n,S=new n,v=new n;export class LandscapeManager{constructor(e,t,s,o,i,r,c){this.source=e,this.view=t,this.landscape=s,this.assetManagerService=o,this.assetService=i,this.shaders=r,this.applyMaterial=c,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new M,this.defaultLandscapeMaterial=m.clone(),this.scatterMeshPool=[],this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new a,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new n,this._cameraPosition=new n,this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=m.name,this.defaultLandscapeMaterial.color=m.color,this.refreshRequests.pipe(x(500)).subscribe((e=>this.refreshScatter(e.origin,e.force,e.predicate)))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new s(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new h({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new n,new n);this.view.camera.getWorldPosition(t);const s=[];v.fromArray(this.source.position);const o=this.view.camera instanceof f?Math.min(this.view.camera.far,1e3):1e3,a=1.1*o,i=e.sections.y*e.sectionSize/-2,r=e.sections.x*e.sectionSize/-2;for(let n=0;n<e.sections.x;n++)if(b.x=r+n*e.sectionSize,!(Math.abs(t.x-b.x)>a))for(let c=0;c<e.sections.y;c++){b.z=i+c*e.sectionSize,S.copy(v).add(b);const l=S.distanceTo(t),h=`${n},${c}`,u=this.landscape.sections.find((e=>e.x===n&&e.y===c));if(l<=o){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,r,i,n,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>a&&this.landscape.remove(u)}p(s)}applyHeightMap(e,t,s,n=1){const o=Math.pow(s+1,2),a=e.getAttribute("position");if(1===n)for(const e of t.points)a.setY(e.i,e.y);else{const e=d(t.points??[],(e=>e.i));for(let t=0;t<a.count;t++){const s=A(t,a.count,o);let n=0;n=s%1==0?e.get(s)?.y??0:Math.floor(e.get(s)?.y),a.setY(t,n)}}a.needsUpdate=!0,e.computeVertexNormals()}deleteOldScatterMeshes(){const e=new Set;for(const[t,s]of this.source.grass?.layers.entries()??[])for(const[n,o]of s.meshes.entries()){const s=`${t}-${n}`;e.add(s)}for(const t of this.scatterMeshes.keys())if(!e.has(t)){this.scatterMeshes.get(t).forEach((e=>{e.parent?.remove(e),e.dispose()})),this.scatterMeshes.delete(t)}}queueRefreshScatter(e,t=!1,s=(()=>!0)){this.refreshRequests.next({origin:e,force:t,predicate:s})}async refreshScatter(s,a=!1,i=(()=>!0)){a&&this.scatterGeometryCache.clear(),this.deleteOldScatterMeshes();for(const[c,h]of this.source.grass?.layers.entries()??[])for(const[u,f]of h.meshes.entries()){const h=`${c}-${u}`;this.scatterMeshes.has(h)||this.scatterMeshes.set(h,new Map);const p=this.scatterMeshes.get(h),m=await this.assetService.getAsset(f.assetId),w=await this.assetManagerService.getMesh(m),M=[];if(w.scene.traverse((e=>{e instanceof t&&M.push(e)})),1!==M.length){console.log(w),console.warn("Dynamic grass only works for meshes with a single geometry.");continue}if(!(M[0]instanceof t)){console.warn("Only meshes can be used for dynamic grass. Found:",w.scene);continue}const x=M[0];let b=x.geometry;this.scatterGeometryCache.has(x.geometry.uuid)?b=this.scatterGeometryCache.get(x.geometry.uuid):(b=x.geometry.clone(),!0===f.normalsUp&&H(b),null==b.userData.updatedMatrix&&(w.scene.updateMatrixWorld(),b.applyMatrix4(x.matrixWorld),b.userData.updatedMatrix=!0));const S=b.getIndex().count/3;if(S>400){console.warn(`The triangle count of ${m.name} is too big ${S}. Keep it below 400`);continue}const v=null!=m.materialAssignments&&m.materialAssignments.length>0?m.materialAssignments[0].materialId:null,A=null!=v&&"null"!==v?await e(await this.assetService.getAsset(v),null,this.assetService,this.assetManagerService,this.shaders,!1):null;let z=null!=A?A:x.material;const C=l.degToRad(f.maxSlope??90),G=Math.cos(C),R=this.landscape.sections,k=R.filter(L(s,f.viewDistance)),q=k.filter((e=>!p.has(e.uuid)||a)).filter((e=>i(e)));R.filter(P(s,2*f.viewDistance)).forEach((e=>{const t=p.get(e.uuid);null!=t&&(t.visible=!1)}));for(const e of k){const t=p.get(e.uuid);null!=t&&(t.visible=!0)}performance.now();const U=this.source.landscape.options,W=U.sectionSize,D=f.density??1??1,X=U.density,Y=W/X,E=D,F=Y/Math.sqrt(E),N=Math.pow(X,2),Z=F/Y,K=Math.floor(N*E),V=[0,0,0];for(const e of q)await g((async()=>{e.updateWorldMatrix(!0,!1);const t=this._matrix,s=new n,i=e.geometry.getAttribute("position"),l=e.geometry.getAttribute("normal"),h=(this.source.vertexMaterials??[]).filter((t=>t.m===e.name)),u=d(h,(e=>e.i));let m=p.get(e.uuid);if(null==m||m.count==K&&!a||(m.parent?.remove(m),this.scatterMeshPool.push(m),p.delete(e.uuid),m=null),null==m){const e=this.scatterMeshPool.findIndex((e=>e.count>=K));e>-1?(m=this.scatterMeshPool[e],m.geometry=b,m.material=z,this.scatterMeshPool.splice(e,1)):m=new o(b,z,K),m.raycast=()=>{},m.receiveShadow=!0}m.visible=!0;const w=new r(new n,new n,new n);let[g,M,x,S]=[new n,new n,new n,new n],[v,A,P]=[[],[],[]],[L,C,R]=[new n,new n,new n,new n];const k=new n,q=new n,U=new n,W=new n,D=new r(new n,new n,new n),H=new r(new n,new n,new n),Y=new r(new n,new n,new n),F=new r(new n,new n,new n);let J=0;e:for(let n=0;n<N;n++){const o=Math.floor(n/X);g.fromBufferAttribute(i,n+o),W.copy(g).applyMatrix4(e.matrixWorld),D.a.copy(g),D.b.fromBufferAttribute(i,n+1+o),D.c.fromBufferAttribute(i,n+X+1+o),H.a.copy(D.b),H.b.copy(D.c),H.c.fromBufferAttribute(i,n+X+2+o),Y.a.fromBufferAttribute(l,n+o),Y.b.fromBufferAttribute(l,n+1+o),Y.c.fromBufferAttribute(l,n+X+1+o),F.a.copy(Y.b),F.b.copy(Y.c),F.c.fromBufferAttribute(l,n+X+2+o);const a=[];a[0]=u.get(n+o)?.w,a[1]=u.get(n+1+o)?.w,a[2]=u.get(n+X+1+o)?.w,a[3]=u.get(n+X+2+o)?.w;let r=0;for(let n=0;n<=1+Z;n+=Z)for(let o=0;o<=1+Z;o+=Z){if(J>K)break e;if(r++,r>E)continue e;1-n>o?(M=D.a,x=D.b,S=D.c,L=Y.a,C=Y.b,R=Y.c,v=a[0],A=a[1],P=a[2]):(M=H.a,x=H.b,S=H.c,L=F.a,C=F.b,R=F.c,v=a[1],A=a[2],P=a[3]),w.a.copy(M),w.b.copy(x),w.c.copy(S),j(w),k.set(g.x,0,g.z),T(w,k),w.getBarycoord(k,s).toArray(V),B[0]=v,B[1]=A,B[2]=P;if($(B,V,.2)!==c-1)continue;if(y([M,x,S],V,q),y([L,C,R],V,U),null!=f.maxSlope&&f.maxSlope<90&&U.y<G)continue;const i=q.applyMatrix4(e.matrixWorld);i.y+=_(f.offsetMin,f.offsetMax);const l=_(f.scaleMin,f.scaleMax);t.makeScale(l,l,l);const h=t.elements;h[12]=i.x,h[13]=i.y,h[14]=i.z,!1!==f.randomRotation&&O(t),f.alignToNormal&&I(t,i,m.matrixWorld,U);const u=m.instanceMatrix.array,d=16*J;u[d]=h[0],u[d+1]=h[1],u[d+2]=h[2],u[d+3]=h[3],u[d+4]=h[4],u[d+5]=h[5],u[d+6]=h[6],u[d+7]=h[7],u[d+8]=h[8],u[d+9]=h[9],u[d+10]=h[10],u[d+11]=h[11],u[d+12]=h[12],u[d+13]=h[13],u[d+14]=h[14],u[d+15]=h[15],J++}}m.count=J,m.instanceMatrix.needsUpdate=!0,p.has(e.uuid)||this.landscape?.add(m),p.set(e.uuid,m),m.userData.meshConfig=f}));performance.now()}}stop(){this.view.removeOnLoop(this.onLoopHandler)}update(){this.view.camera&&(this.view.camera.getWorldPosition(this._cameraPosition),this._cameraPosition.distanceTo(this._lastUpdatePosition)>10&&(this._lastUpdatePosition.copy(this._cameraPosition),this.refreshGeometry(),this.refreshScatter(this._cameraPosition)))}clear(){this.scatterMeshes.forEach((e=>e.forEach((e=>e.parent?.remove(e)))))}createLandscapeMesh(e,t,n,o,a,i){const r=new s(t.sectionSize,t.sectionSize,t.density,t.density);r.rotateX(Math.PI/-2);const c=this.defaultLandscapeMaterial,l=new w(r,c);l.position.x=n+a*t.sectionSize,l.position.z=o+i*t.sectionSize,l.receiveShadow=!0,l.castShadow=!1,l.userData.landscape={x:a,y:i},l.x=a,l.y=i,l.name=`${a},${i}`;const h=e.landscape.heightMaps.find((e=>e.x===a&&e.y===i));return null!=h&&this.applyHeightMap(r,h,t.density,1),r.computeBoundsTree(),l}}function A(e,t,s){const n=Math.sqrt(t),o=Math.floor(e/n)/(n-1),a=e%n/(n-1),i=Math.sqrt(s);return(s-1)*o-(i-1)*o+(i-1)*a}new Map,new i(0,0),new i(1,0),new i(0,1),new i(1,0),new i(0,1),new i(1,1),new n;const z=new c;function P(e,t){return function(s){return z.setFromObject(s).distanceToPoint(e)>t}}function L(e,t){return function(s){return z.setFromObject(s).distanceToPoint(e)<t}}function j(e){e.a.y=0,e.b.y=0,e.c.y=0}const B=[];function $(e,t,s=.5){const n=B;let o=-1,a=0;for(let e=0;e<n.length;e++)if(null!=n[e])for(let i=0;i<n[e].length;i++){const r=n[e][i]*t[e];r>s&&r>a&&(a=r,o=i)}return o}function _(e,t){let s=t-e,n=R();return n*=s,n+=e,n}const C=[];let G=1e3;for(;G--;)C.push(Math.random());function R(){return++G>=C.length?C[G=0]:C[G]}const k=[];let q=20;for(;q--;)k.push((new a).makeRotationY(R()*Math.PI/2));function T(e,t){let s=R(),n=R();s+n>1&&(s=1-s,n=1-n);const o=e.a,a=e.b,i=e.c;t.x=o.x+s*(a.x-o.x)+n*(i.x-o.x),t.z=o.z+s*(a.z-o.z)+n*(i.z-o.z)}new n;new n;const U=new n,W=new n(0,1,0),D=(new a).makeRotationX(Math.PI/-2);function I(e,t,s,n){e.lookAt(U,n,W).multiply(D)}new a;function O(e){e.makeRotationX;const t=(++q>=k.length?k[q=0]:k[q]).elements,s=e.elements;s[0]=t[0],s[4]=t[4],s[8]=t[8],s[1]=t[1],s[5]=t[5],s[9]=t[9],s[2]=t[2],s[6]=t[6],s[10]=t[10]}function H(e){const t=e.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.normalized=!0,t.needsUpdate=!0}
1
+ import{materialFromAsset as e}from"../../scene/materializer.js";import{Mesh as t,PlaneGeometry as s,Vector3 as n,InstancedMesh as o,Matrix4 as a,Vector2 as i,Triangle as r,Box3 as c,MathUtils as l,MeshStandardMaterial as h,ShaderMaterial as u,PerspectiveCamera as f,BufferAttribute as p}from"three";import{indexBy as m}from"../../utils/collections.js";import{smoothNormalsCrossMeshes as d}from"./utils.js";import{defaultLandscapeMaterial as w,LandscapeMesh as g}from"./landscape.js";import{meanVectors3withWeight as y}from"../../utils/math.js";import{whenIdle as M}from"../../utils/async.js";import{Subject as x,debounceTime as b}from"rxjs";new n,new n;const S=new n,v=new n,A=new n;export class LandscapeManager{constructor(e,t,s,o,i,r,c){this.view=t,this.landscape=s,this.assetManagerService=o,this.assetService=i,this.shaders=r,this.applyMaterial=c,this.scatterMeshes=new Map,this.loadedScatterSquares=new Set,this.refreshRequests=new x,this.defaultLandscapeMaterial=w.clone(),this.scatterMeshPool=[],this.onLoopHandler=()=>this.update(),this.sectionCache=new Map,this._matrix=new a,this.scatterGeometryCache=new Map,this._lastUpdatePosition=new n,this._cameraPosition=new n,this.source=JSON.parse(JSON.stringify(e)),this.view.onLoop(this.onLoopHandler),this.defaultLandscapeMaterial.name=w.name,this.defaultLandscapeMaterial.color=w.color,this.refreshRequests.pipe(b(500)).subscribe((e=>this.refreshScatter(e.origin,e.force,e.predicate)))}updateShaders(e){this.shaders=e}async loadGrass(){const e=await this.assetService.getAsset("6ij937n72g");await this.assetManagerService.getMesh(e);this.grassGeometry=new s(2,2,3,3);const t=this.grassGeometry.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.needsUpdate=!0,this.grassMaterial=new h({color:3765785})}refreshGeometry(){const e=this.source.landscape.options,t=(new n,new n);this.view.camera.getWorldPosition(t);const s=[];A.fromArray(this.source.position);const o=this.view.camera instanceof f?Math.min(this.view.camera.far,1e3):1e3,a=1.1*o,i=e.sections.y*e.sectionSize/-2,r=e.sections.x*e.sectionSize/-2;for(let n=0;n<e.sections.x;n++)if(S.x=r+n*e.sectionSize,!(Math.abs(t.x-S.x)>a))for(let c=0;c<e.sections.y;c++){S.z=i+c*e.sectionSize,v.copy(A).add(S);const l=v.distanceTo(t),h=`${n},${c}`,u=this.landscape.sections.find((e=>e.x===n&&e.y===c));if(l<=o){if(null==u){this.sectionCache.has(h)||this.sectionCache.set(h,this.createLandscapeMesh(this.source,e,r,i,n,c));const t=this.sectionCache.get(h);this.applyMaterial(t),this.landscape.add(t),s.push(t)}}else l>a&&this.landscape.remove(u)}d(s)}applyHeightMap(e,t,s,n=1){const o=Math.pow(s+1,2),a=e.getAttribute("position");if(1===n)for(const e of t.points)a.setY(e.i,e.y);else{const e=m(t.points??[],(e=>e.i));for(let t=0;t<a.count;t++){const s=z(t,a.count,o);let n=0;n=s%1==0?e.get(s)?.y??0:Math.floor(e.get(s)?.y),a.setY(t,n)}}a.needsUpdate=!0,e.computeVertexNormals()}deleteOldScatterMeshes(){const e=new Set;for(const[t,s]of this.source.grass?.layers.entries()??[])for(const[n,o]of s.meshes.entries()){const s=`${t}-${n}`;e.add(s)}for(const t of this.scatterMeshes.keys())if(!e.has(t)){this.scatterMeshes.get(t).forEach((e=>{e.parent?.remove(e),e.dispose()})),this.scatterMeshes.delete(t)}}queueRefreshScatter(e,t=!1,s=(()=>!0)){this.refreshRequests.next({origin:e,force:t,predicate:s})}async refreshScatter(s,a=!1,i=(()=>!0)){a&&this.scatterGeometryCache.clear(),this.deleteOldScatterMeshes();for(const[c,h]of this.source.grass?.layers.entries()??[])for(const[u,f]of h.meshes.entries()){const h=`${c}-${u}`;this.scatterMeshes.has(h)||this.scatterMeshes.set(h,new Map);const p=this.scatterMeshes.get(h),d=await this.assetService.getAsset(f.assetId),w=await this.assetManagerService.getMesh(d),g=[];if(w.scene.traverse((e=>{e instanceof t&&g.push(e)})),1!==g.length){console.log(w),console.warn("Dynamic grass only works for meshes with a single geometry.");continue}if(!(g[0]instanceof t)){console.warn("Only meshes can be used for dynamic grass. Found:",w.scene);continue}const x=g[0];let b=x.geometry;this.scatterGeometryCache.has(x.geometry.uuid)?b=this.scatterGeometryCache.get(x.geometry.uuid):(b=x.geometry.clone(),!0===f.normalsUp&&X(b),null==b.userData.updatedMatrix&&(w.scene.updateMatrixWorld(),b.applyMatrix4(x.matrixWorld),b.userData.updatedMatrix=!0));const S=b.getIndex().count/3;if(S>400){console.warn(`The triangle count of ${d.name} is too big ${S}. Keep it below 400`);continue}const v=null!=d.materialAssignments&&d.materialAssignments.length>0?d.materialAssignments[0].materialId:null,A=null!=v&&"null"!==v?await e(await this.assetService.getAsset(v),null,this.assetService,this.assetManagerService,this.shaders,!1):null;let z=null!=A?A:x.material;const P=l.degToRad(f.maxSlope??90),G=Math.cos(P),R=this.landscape.sections,k=R.filter(j(s,f.viewDistance)),q=k.filter((e=>!p.has(e.uuid)||a)).filter((e=>i(e)));R.filter(L(s,2*f.viewDistance)).forEach((e=>{const t=p.get(e.uuid);null!=t&&(t.visible=!1)}));for(const e of k){const t=p.get(e.uuid);null!=t&&(t.visible=!0)}performance.now();const O=this.source.landscape.options,U=O.sectionSize,W=f.density??1??1,D=O.density,Y=U/D,E=W,F=Y/Math.sqrt(E),N=Math.pow(D,2),J=F/Y,Z=Math.floor(N*E),K=[0,0,0];for(const e of q)await M((async()=>{e.updateWorldMatrix(!0,!1);const t=this._matrix,s=new n,i=e.geometry.getAttribute("position"),l=e.geometry.getAttribute("normal"),h=(this.source.vertexMaterials??[]).filter((t=>t.m===e.name)),u=m(h,(e=>e.i));let d=p.get(e.uuid);if(null==d||d.count==Z&&!a||(d.parent?.remove(d),this.scatterMeshPool.push(d),p.delete(e.uuid),d=null),null==d){const e=this.scatterMeshPool.findIndex((e=>e.count>=Z));e>-1?(d=this.scatterMeshPool[e],d.geometry=b,d.material=z,this.scatterMeshPool.splice(e,1)):d=new o(b,z,Z),d.raycast=()=>{},d.receiveShadow=!0}d.visible=!0;const w=new r(new n,new n,new n);let[g,M,x,S]=[new n,new n,new n,new n],[v,A,P]=[[],[],[]],[L,j,R]=[new n,new n,new n,new n];const k=new n,q=new n,O=new n,U=new n,W=new r(new n,new n,new n),X=new r(new n,new n,new n),Y=new r(new n,new n,new n),F=new r(new n,new n,new n);let V=0;e:for(let n=0;n<N;n++){const o=Math.floor(n/D);g.fromBufferAttribute(i,n+o),U.copy(g).applyMatrix4(e.matrixWorld),W.a.copy(g),W.b.fromBufferAttribute(i,n+1+o),W.c.fromBufferAttribute(i,n+D+1+o),X.a.copy(W.b),X.b.copy(W.c),X.c.fromBufferAttribute(i,n+D+2+o),Y.a.fromBufferAttribute(l,n+o),Y.b.fromBufferAttribute(l,n+1+o),Y.c.fromBufferAttribute(l,n+D+1+o),F.a.copy(Y.b),F.b.copy(Y.c),F.c.fromBufferAttribute(l,n+D+2+o);const a=[];a[0]=u.get(n+o)?.w,a[1]=u.get(n+1+o)?.w,a[2]=u.get(n+D+1+o)?.w,a[3]=u.get(n+D+2+o)?.w;let r=0;for(let n=0;n<=1+J;n+=J)for(let o=0;o<=1+J;o+=J){if(V>Z)break e;if(r++,r>E)continue e;1-n>o?(M=W.a,x=W.b,S=W.c,L=Y.a,j=Y.b,R=Y.c,v=a[0],A=a[1],P=a[2]):(M=X.a,x=X.b,S=X.c,L=F.a,j=F.b,R=F.c,v=a[1],A=a[2],P=a[3]),w.a.copy(M),w.b.copy(x),w.c.copy(S),B(w),k.set(g.x,0,g.z),T(w,k),w.getBarycoord(k,s).toArray(K),$[0]=v,$[1]=A,$[2]=P;if(_($,K,.2)!==c-1)continue;if(y([M,x,S],K,q),y([L,j,R],K,O),null!=f.maxSlope&&f.maxSlope<90&&O.y<G)continue;const i=q.applyMatrix4(e.matrixWorld);i.y+=C(f.offsetMin,f.offsetMax);const l=C(f.scaleMin,f.scaleMax);t.makeScale(l,l,l);const h=t.elements;h[12]=i.x,h[13]=i.y,h[14]=i.z,!1!==f.randomRotation&&I(t),f.alignToNormal&&H(t,i,d.matrixWorld,O);const u=d.instanceMatrix.array,p=16*V;u[p]=h[0],u[p+1]=h[1],u[p+2]=h[2],u[p+3]=h[3],u[p+4]=h[4],u[p+5]=h[5],u[p+6]=h[6],u[p+7]=h[7],u[p+8]=h[8],u[p+9]=h[9],u[p+10]=h[10],u[p+11]=h[11],u[p+12]=h[12],u[p+13]=h[13],u[p+14]=h[14],u[p+15]=h[15],V++}}d.count=V,d.instanceMatrix.needsUpdate=!0,p.has(e.uuid)||this.landscape?.add(d),p.set(e.uuid,d),d.userData.meshConfig=f}));performance.now()}}stop(){this.view.removeOnLoop(this.onLoopHandler)}update(){this.view.camera&&(this.view.camera.getWorldPosition(this._cameraPosition),this._cameraPosition.distanceTo(this._lastUpdatePosition)>10&&(this._lastUpdatePosition.copy(this._cameraPosition),this.refreshGeometry(),this.refreshScatter(this._cameraPosition)))}clear(){this.scatterMeshes.forEach((e=>e.forEach((e=>e.parent?.remove(e)))))}createLandscapeMesh(e,t,n,o,a,i){const r=new s(t.sectionSize,t.sectionSize,t.density,t.density);r.rotateX(Math.PI/-2);const c=this.defaultLandscapeMaterial,l=new g(r,c);l.position.x=n+a*t.sectionSize,l.position.z=o+i*t.sectionSize,l.receiveShadow=!0,l.castShadow=!1,l.userData.landscape={x:a,y:i},l.x=a,l.y=i,l.name=`${a},${i}`;const h=e.landscape.heightMaps.find((e=>e.x===a&&e.y===i));if(null!=h&&this.applyHeightMap(r,h,t.density,1),r.computeBoundsTree(),null!=e.landscape.holes&&e.landscape.holes.length>0){const t=getHoleAttribute(l,!0);for(const s of e.landscape.holes)s.m===l.name&&t.setX(s.i,s.w[0])}return l}}export function getHoleAttribute(e,t=!1){if(!e.geometry.hasAttribute("hole")||t){const t=new Float32Array(e.geometry.getAttribute("position").array.length);e.geometry.setAttribute("hole",new p(t,1))}return e.geometry.getAttribute("hole")}function z(e,t,s){const n=Math.sqrt(t),o=Math.floor(e/n)/(n-1),a=e%n/(n-1),i=Math.sqrt(s);return(s-1)*o-(i-1)*o+(i-1)*a}new Map,new i(0,0),new i(1,0),new i(0,1),new i(1,0),new i(0,1),new i(1,1),new n;const P=new c;function L(e,t){return function(s){return P.setFromObject(s).distanceToPoint(e)>t}}function j(e,t){return function(s){return P.setFromObject(s).distanceToPoint(e)<t}}function B(e){e.a.y=0,e.b.y=0,e.c.y=0}const $=[];function _(e,t,s=.5){const n=$;let o=-1,a=0;for(let e=0;e<n.length;e++)if(null!=n[e])for(let i=0;i<n[e].length;i++){const r=n[e][i]*t[e];r>s&&r>a&&(a=r,o=i)}return o}function C(e,t){let s=t-e,n=k();return n*=s,n+=e,n}const G=[];let R=1e3;for(;R--;)G.push(Math.random());function k(){return++R>=G.length?G[R=0]:G[R]}const q=[];let O=20;for(;O--;)q.push((new a).makeRotationY(k()*Math.PI/2));function T(e,t){let s=k(),n=k();s+n>1&&(s=1-s,n=1-n);const o=e.a,a=e.b,i=e.c;t.x=o.x+s*(a.x-o.x)+n*(i.x-o.x),t.z=o.z+s*(a.z-o.z)+n*(i.z-o.z)}new n;new n;const U=new n,W=new n(0,1,0),D=(new a).makeRotationX(Math.PI/-2);function H(e,t,s,n){e.lookAt(U,n,W).multiply(D)}new a;function I(e){e.makeRotationX;const t=(++O>=q.length?q[O=0]:q[O]).elements,s=e.elements;s[0]=t[0],s[4]=t[4],s[8]=t[8],s[1]=t[1],s[5]=t[5],s[9]=t[9],s[2]=t[2],s[6]=t[6],s[10]=t[10]}function X(e){const t=e.getAttribute("normal");for(let e=0;e<t.count;e++)t.setXYZ(e,0,1,0);t.normalized=!0,t.needsUpdate=!0}
2
2
  /*
3
3
  * Copyright (©) 2023. All rights reserved.
4
4
  * See the LICENSE.md file for details.
@@ -1,4 +1,4 @@
1
- import{Group as e,Mesh as a}from"three";import{Color as r}from"three";import{varyingAttributes as t,float as n,mod as o,dot as s,vec2 as c,step as i,fract as l,mix as p,rgb as d,NodeShaderMaterial as u,rgba as m,standardMaterial as f}from"three-shader-graph";import{mixColorsByLayer as L,select as h}from"../../shader-nodes/index.js";export function initLandscape(e){e.sections.y,e.sectionSize,e.sections.x,e.sectionSize;return new LandscapeGroup}export function createLandscapeDefaultMaterial(){const e=t.uv,a=n(10),h=n(7),x=o(s(c(1,1),i(c(.5,.5),l(e.multiplyScalar(a)))),n(2)),S=o(s(c(1,1),i(c(.5,.5),l(e.multiplyScalar(h.multiply(a))))),n(2)),w=p(d(new r(4473924).convertLinearToSRGB()),d(new r(5592405).convertLinearToSRGB()),x),v=p(w,w.addScalar(n(.1)),S),y=L({layerColors:[m(v).rgb,...["#55DDE0","#33658A","#2F4858"].map((e=>new r(e).convertLinearToSRGB())).map((e=>d(e))).reverse()],enableNoise:!1}),D=new u({color:f({color:y})});return D.color=new r("#aaaaaa"),D.name="Default",D}export const defaultLandscapeMaterial=createLandscapeDefaultMaterial();export class LandscapeMesh extends a{}export class LandscapeGroup extends e{get sections(){return this.children.filter((e=>e instanceof LandscapeMesh))}}
1
+ import{Group as e,Mesh as a}from"three";import{Color as r}from"three";import{varyingAttributes as t,float as n,mod as o,dot as s,vec2 as c,step as i,fract as l,mix as p,rgb as d,NodeShaderMaterial as u,rgba as m,standardMaterial as f,attributeFloat as h,varyingFloat as L,RgbNode as x,varying as S}from"three-shader-graph";import{mixColorsByLayer as w,select as v}from"../../shader-nodes/index.js";export function initLandscape(e){e.sections.y,e.sectionSize,e.sections.x,e.sectionSize;return new LandscapeGroup}export function createLandscapeDefaultMaterial(){const e=t.uv,a=n(10),x=n(7),v=o(s(c(1,1),i(c(.5,.5),l(e.multiplyScalar(a)))),n(2)),y=o(s(c(1,1),i(c(.5,.5),l(e.multiplyScalar(x.multiply(a))))),n(2)),D=p(d(new r(4473924).convertLinearToSRGB()),d(new r(5592405).convertLinearToSRGB()),v),G=p(D,D.addScalar(n(.1)),y),M=w({layerColors:[m(G).rgb,...["#55DDE0","#33658A","#2F4858"].map((e=>new r(e).convertLinearToSRGB())).map((e=>d(e))).reverse()],enableNoise:!1}),g=h("hole"),B=(i(.5,L(g)),new u({color:f({color:M}),discard:S(g).gt(.5)}));return B.color=new r("#aaaaaa"),B.name="Default",B}export const defaultLandscapeMaterial=createLandscapeDefaultMaterial();export class LandscapeMesh extends a{}export class LandscapeGroup extends e{get sections(){return this.children.filter((e=>e instanceof LandscapeMesh))}}
2
2
  /*
3
3
  * Copyright (©) 2023. All rights reserved.
4
4
  * See the LICENSE.md file for details.
@@ -128,6 +128,7 @@ export interface FogSettings {
128
128
  export interface LandscapeData {
129
129
  options: LandscapeInitOptions;
130
130
  heightMaps: HeighMapSection[];
131
+ holes?: VertexMaterial[];
131
132
  }
132
133
  export interface HeighMapSection {
133
134
  x: number;
@@ -1,4 +1,4 @@
1
- import{Subject as e}from"rxjs";import*as t from"three";import{BoxGeometry as a,Color as s,Euler as r,Fog as i,FogExp2 as n,Group as o,Material as l,Matrix4 as c,Mesh as h,MeshLambertMaterial as m,MeshPhongMaterial as p,MeshStandardMaterial as d,Object3D as u,PointLight as f,Quaternion as y,SphereGeometry as g,Texture as w,Vector2 as S,Vector3 as v,Vector4 as A}from"three";import b,{SpriteRenderer as M}from"three-nebula";import{bool as x,BooleanNode as j,float as P,FloatNode as I,NodeShaderMaterial as D,rgb as N,RgbNode as E,Texture2dLookupNode as V,textureSampler2d as C,vec2 as F,Vec2Node as k,vec3 as z,Vec3Node as O,vec4 as _}from"three-shader-graph";import{VfxActor as B}from"../effects/vfx/vfx-actor.js";import{VisualEffect as T}from"../effects/vfx/vfx-param.js";import{BaseActor as $}from"../gameplay/actors/actor.js";import L from"../gameplay/actors/builtin/index.js";import{PhysicsBodyType as U,withInjectionContext as R}from"../gameplay/index.js";import{Sampler2DNode as W}from"../shader-nodes/index.js";import{LambertShader as J}from"../shader/builtin/lambert-shader.js";import{StandardShader as H}from"../shader/builtin/standard-shader.js";import{UnlitShader as q}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as G}from"../shader/parameter.js";import{ArrayMap as X,groupBy as Y}from"../utils/collections.js";import{iterateMaterials as Z}from"../utils/materials.js";import{filterChildrenShallow as Q,filterSceneShallow as K,findFirstVisibleObject as ee}from"../utils/three/traverse.js";import{AssetMeshInstance as te}from"./asset-resource-loader.js";import{isCollisionMesh as ae}from"./collision/collision-shape-import.js";import{BoxCollisionShape as se,PhysicalShapeMesh as re}from"./collision/collision-shape.js";import{LandscapeManager as ie}from"./landscape/landscape-manager.js";import{initLandscape as ne}from"./landscape/landscape.js";import{SectionGrid as oe,smoothNormalsCrossMeshes as le}from"./landscape/utils.js";import{createGrassFoliageMaterial as ce}from"./materials/grass-foliage.js";import{createGrassMaterial as he}from"./materials/grass.js";import{getMaterialAttribute as me}from"./materials/utils/material-painting.js";import{createWaterMaterial as pe}from"./materials/water.js";import{SerializedParamType as de}from"./model.js";import{ShapeLibrary as ue,ShapeLibraryKeys as fe}from"./objects/shapes.js";import{ambientLightName as ye,createSky as ge,defaultSkyMaterial as we}from"./sky.js";const Se={};export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new SceneMaterializer(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}export class SceneMaterializer{constructor(a,s,r,i,n,o,l,c){this.scene=a,this.dataProvider=s,this.assetsService=r,this.assetManagerService=i,this.renderingView=n,this.shaders=o,this.actorTypes=l,this.actorProvider=c,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.inEditor=!0,this.updated$=new e,this.removed$=new e,this.error$=new e,this.editorActorParamSnapshot=new Map,this.assets=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.originalFog=null,s.onUpdate((e=>this.update(e))),s.onRemove((e=>this.remove(e))),this.createAssetSubscription=r.onCreate.subscribe((e=>{this.assets.set(e.id,e)})),this.updateSubscription=r.onUpdate.subscribe((async e=>{this.assets.set(e.id,e),"material"==e.type?a.traverse((a=>{if(a instanceof t.Mesh)if(Array.isArray(a.material))for(let t=0;t<a.material.length;t++)this.refreshMaterial(a,a.material[t],e,t);else this.refreshMaterial(a,a.material,e)})):"mesh"==e.type?(this.findByAssetId(e.id).forEach((t=>{Ee(t.userData.src.materialAssignments,e.materialAssignments).forEach((e=>{this.applyMaterial(t,e)}))})),this.landscapeManagers.forEach((t=>{t.source.grass.layers.some((t=>t.meshes.some((t=>t.assetId===e.id))))&&t.queueRefreshScatter(this.renderingView?.camera.position??new v,!0)}))):"prefab"===e.type&&this.findByAssetId(e.id).forEach((e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}))}))}async refreshMaterial(e,t,a,s){if(t?.userData?.assetId!==a.id)return;const r=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!0);r.userData=t.userData,null!=s?Ce(e.material[s],r)||(e.material[s]=r):Ce(e.material,r)||(e.material=r)}get actorInstances(){return Array.from(this.materializedActors.values())}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter((e=>null!=e.assetId&&"asset_mesh"==e.type)).filter((e=>e.assetId))));await Promise.all(e.map((e=>this.assetsService.getAsset(e.assetId).then((e=>{if(null!=e)return this.assetManagerService.getMesh(e)})))))}async init(){await this.preInit(),Ae.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map((e=>this.materialize(e)))),await this.initActorsPostInit()}initActorsPostInit(e=this.actorInstances){const t=e.map((async e=>{const t=e.object.userData.src;if("vfx"===t.type)return Promise.resolve();const a=await this.assetsService.getAsset(t.assetId),s={...a?.actor?.params??{},...t.actor?.params??{}};for(const a of t.actor.innerParams??[])await this.applyActorComponentParams(e,a.path.slice(),a.params);const r=await xe(s,e.constructor,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders,this.actorProvider);Object.assign(e,r);try{return await this.actorProvider.initActor(e)}catch(e){console.error(`Failed to initiate actor (name="${t.name}", id=${t.id})`,e)}}));return Promise.all(t)}addVfxChildActors(e,t=e){}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await xe(a,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[r]&&await this.applyActorComponentParams(e[r],t,a)}canObjectBeInstanced(e){return e.physics?.type!==U.dynamic&&"sky"!==e.type&&"global_fog"!==e.type}async canAssetBeInstanced(e){if(!this._canBeInstancedCache.has(e.assetId)){const t=await this.createFromAsset(e);if(null==t)return!1;const a=[];t.traverse((e=>{!ae(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=a[0]instanceof h&&null!=a[0].geometry.morphAttributes&&Object.keys(a[0].geometry.morphAttributes).length>0,i=!0;this._canBeInstancedCache.set(e.assetId,s&&i&&!r)}return this._canBeInstancedCache.get(e.assetId)}async preInit(){this.renderingView?.onLoop((()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)})),this.assetsService.getAssets().then((e=>{for(const t of e)this.assets.set(t.id,t)}))}async initWithInstancing(){await this.preInit(),await this.prefetchAssets();const e=[],a=new X,i=new X;for(const t of this.dataProvider.getObjects())await Ne(t,(async(t,r,n)=>{const o="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t),l="shape_mesh"===t.type&&"landscape"!==t.shape&&t.physics?.type!==U.dynamic;if(o||l)if(r&&r.children?.length>0&&r.children.splice(r.children.findIndex((e=>e.id===t.id)),1),l){let e=t.shape+JSON.stringify(t.shapeParams??{})+t.castShadow+t.receiveShadow;const a=t.materialAssignments?.at(0)?.materialId,r=null!=a?this.assets.get(a):null;let o=null;if(null!=r&&"shader"!==r.material.type){if(e+=r.material.type+r.material.shader,null!=r.material.shaderParams){if(e+=Object.entries(r.material.shaderParams).filter((([e,t])=>"color"!=e)).map((e=>JSON.stringify(e))).join(),null!=r.material.shaderParams.color){const e=r.material.shaderParams.color;e.type===de.Color&&null!=e.value&&(o=new s(e.value))}}}else e+=a;i.push(e,{object:{...t,parentTransform:n},color:o})}else{const e=t.assetId+JSON.stringify(t.materialAssignments??[]);a.push(e,{...t,parentTransform:n})}else null==r&&e.push({...t,parentTransform:n})}));for(const e of a.values()){if(0==e.length)continue;const t=await this.createFromAsset(e[0]);if(null==t)continue;const a=await this.createInstancedMesh(e,t),s=new te;s.add(a),s.userData.src=e[0],t instanceof te&&(s.collisionShapes=t.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}for(const e of i.values()){if(0==e.length)continue;const a=e[0].object,i=await this.createFromShape(a),n=ee(i,(e=>!ae(e)&&null!=e.geometry)),o=n.material.clone();null!=e[0].color&&null!=o.color&&(o.color=new s(16777215));const l=n.geometry,h=new t.InstancedMesh(l,o,e.length);for(let a=0;a<e.length;a++){const s=e[a],o=(new t.Matrix4).compose((new v).fromArray(s.object.position),(new y).setFromEuler((new r).fromArray(s.object.rotation)),(new v).fromArray(s.object.scale)),l=(new c).copy(s.object.parentTransform).multiply(o);h.setMatrixAt(a,l),null!=s.color&&h.setColorAt(a,s.color),h.castShadow=i.castShadow??!0,h.receiveShadow=n.receiveShadow??!0;const m=new te;m.add(h),m.userData.src=e[0],i instanceof re&&(m.collisionShapes=[i.collisionShape]),m.castShadow=!1,m.receiveShadow=!1,this.scene.add(m)}}await Promise.all(e.map((e=>this.materialize(e)))),await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=ee(a,(e=>!ae(e)&&null!=e.geometry)),i=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(a,Ee(e[0].materialAssignments,i.materialAssignments)),s.updateMatrix();const n=s.geometry.clone().applyMatrix4(s.matrix),o=new t.InstancedMesh(n,s.material,e.length);s.material instanceof l&&(o.material.side=t.FrontSide);for(let a=0;a<e.length;a++){const s=(new t.Matrix4).compose((new v).fromArray(e[a].position),(new y).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new c).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=e[0].castShadow??i.castShadow??!0,o.receiveShadow=e[0].receiveShadow??i.receiveShadow??!0,o}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("actor"==e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay()):console.warn("Failed to remove actor",e)}const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter((t=>t.object.userData.src?.id===e.id)).forEach((e=>this.components.splice(this.components.indexOf(e,1)))),this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))})),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex((t=>t.source.id===e.id));if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return K(this.scene,(t=>t.userData.src?.assetId==e),(e=>null!=e.userData.src))}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter((e=>"null"!==e.materialId)).map((t=>this.applyMaterial(e,t))))}async applyMaterial(e,t){await applyMaterial(e,t,(e=>{const t=this.assets.get(e);if(null!=t)return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}),this._originalMaterials)}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof h)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material}))}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(L));K(this.scene,(e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type))).forEach((async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)}))}updateShaders(e){this.shaders=e;for(const[e,t]of Ae.entries())t.userData.customShaderName&&Ae.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),K(this.scene,(e=>!0)).forEach((e=>{e.traverse((async e=>{if(e instanceof h)if(Array.isArray(e.material))for(let t=0;t<e.material.length;t++){const a=e.material[t].userData?.customShaderName;if(null!=a){const a=this.assets.get(e.material[t].userData.assetId);this.refreshMaterial(e,e.material[t],a,t)}}else{const t=e.material.userData?.customShaderName;if(null!=t){const t=this.assets.get(e.material.userData.assetId);this.refreshMaterial(e,e.material,t)}}}))}))}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);const t=this.sceneObjectMap.get(e.id);if(t){let r=!1;if(t.traverseAncestors((e=>{"_hology_transform_group"===e.name&&(r=!0)})),!r){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse((e=>{e instanceof h&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof h&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);Ee(e.materialAssignments,a.materialAssignments).forEach((e=>this.applyMaterial(t,e)))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(r||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type)if("point"==e.light.type){const a=t;a.color=new s(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0)}else"directional"===e.light.type?this.applyDirectionalLight(e.light.directional):"ambient"===e.light.type&&this.applyDirectionalAmbientLight(t,e.light.ambient);else if("landscape"===e.shape)this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>!0))));else if("global_fog"===e.type){const t=(this.scene.fog instanceof n?"density":"linear")!==e.fog.type;this.scene.fog=Ie(e.fog),t&&(a=this.scene).traverse((e=>{if(e instanceof h){const t=e.material;t instanceof D&&(a.fog instanceof i?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof n&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}})),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.editorActorParamSnapshot.get(e.id);null!=t&&t===JSON.stringify(e.actor)||(console.log("Rematerializing actor because parameters changed"),r||(this.remove(e),await this.materializeAndInitActor(e)))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof re&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&ve(t,e.castShadow,e.receiveShadow),e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a}async materializeAndInitActor(e,t=this.findParent(e)){console.log("materialize actor and init");const a=await this.materialize(e,t);return Ne(e,(async e=>{if("actor"===e.type){const t=this.materializedActors.get(e.id);null!=t?await this.initActorsPostInit([t]):console.error(`Something went wrong when creating actor ${e.id}`)}})),a}findParent(e){const t=this.dataProvider.getObjects().flatMap((t=>t.id===e.id?null:Q(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?K(this.scene,(e=>e.userData?.src?.id===t.id),(e=>null!=e.userData?.src))[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new s(this.scene.fog.color))}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof h&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=Y(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof h){const t=me(e,!1);if(null!=t){for(let e=0;e<t.array.length;e++)t.setX(e,0);t.needsUpdate=!0}}}));const s=new Set;for(const[e,r]of a.entries()){const a=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let i=!1;if(null==a)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const n=me(a,!0);for(let e=0;e<n.array.length;e++)n.setX(e,0);for(const e of r)n.setX(e.i,e.w[0]),n.setY(e.i,e.w[1]),n.setZ(e.i,e.w[2]),i=!0;i&&s.add(e)}this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>s.has(e.name)))))}async materialize(e,t,s=!1){let r;switch(e.type){case"asset_mesh":r=await this.createFromAsset(e);break;case"shape_mesh":r=await this.createFromShape(e);break;case"light":r=await this.createLight(e);break;case"particles":r=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Ie(e.fog),this.fixFogColor(),r=new o;break;case"sky":this.sky=ge(),this.updateSky(e),r=this.sky;break;case"actor":r=await this.createFromActor(e);break;case"group":r=new o;break;case"prefab":r=await this.createFromPrefabAsset(e);break;case"vfx":r=await this.createFromVfx(e);break;default:if(this.inEditor)throw new Error("unknown type "+e.type);console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version.`)}if(null!=r){if(e.name&&e.name.length>0&&(r.name=e.name),null!=e.position&&r.position.fromArray(e.position),null!=e.scale&&r.scale.fromArray(e.scale),null!=e.rotation&&r.rotation.fromArray(e.rotation),s||(r.userData.src=e),this.inEditor,this.inEditor){let e=null;r instanceof re&&(e=function(e){if(e instanceof se)return new h(new a(...e.offset.toArray()),De);return null}(r.collisionShape)),null!=e&&(e.layers.disable(0),e.layers.enable(18),e.scale.multiplyScalar(1.1),r.add(e))}return this.objectMap.set(r.uuid,e),this.sceneObjectMap.set(e.id,r),e.physics?.type!==U.dynamic||null==t||this.inEditor?null==t?this.scene.add(r):t?.add(r):(t.add(r),r.getWorldPosition(r.position),r.getWorldQuaternion(r.quaternion),r.getWorldScale(r.scale),this.scene?.attach(r)),null!=e.children&&await Promise.all(e.children?.map((e=>this.materialize(e,r,s)))),this.inEditor||"asset_mesh"!=e.type&&"shape_mesh"!==e.type||null!=e.physics?.type&&e.physics.type==U.dynamic||Pe(r),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=we);const a=await this.assetsService.getAsset(e.sky.materialId),s=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);s.side=t.BackSide,null!=this.sky?this.sky.material=s:console.warn("No sky has been created")}async createComponent(e,t,a,s){const r=new Se[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e){const t=this.actorTypes.find((t=>t.name===e.actor?.type))?.type??L[e.actor?.type];if(null==t)return null;this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const a=await this.actorProvider.create(t,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!0);return this.materializedActors.set(e.id,a),a?.object}async createFromVfx(e){const t=await this.assetsService.getAsset(e.assetId);null==t&&console.error("Could not find asset",e);const a=await this.actorProvider.create(B,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!1);return await a.fromAsset(t),a.play(),this.materializedActors.set(e.id,a),a?.object}cleanup(){this.materializedActors.clear()}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e),a.traverse((e=>{e instanceof h&&this._originalMaterials.set(e.id,e.material)}));else{let r=new d({name:"Default",color:new s("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});const i=await this.createMeshByShape(e.shape,r,e.shapeParams);i.castShadow=e.castShadow??!0,i.receiveShadow=e.castShadow??!1,e.collisionDetection||(i.collisionShape=null),i.physics=e.physics,a=i,this._originalMaterials.set(a.id,i.material),a.traverse((e=>{}))}return t||(await Promise.all((e.materialAssignments??[]).filter((e=>null!=e.materialId)).map((e=>this.applyMaterial(a,e)))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new o;const a=ne(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new ie(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,(t=>{(e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(t,e)))}));return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new oe(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach((e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()})),this.inEditor&&!a||setTimeout((()=>le(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&fe.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,ue[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,ue[e].collision(s)),new re(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:a}=await this.assetManagerService.getMesh(t,{mergeGeomtries:!0});Ee(e.materialAssignments,t.materialAssignments).forEach((e=>this.applyMaterial(a,e)));const s=e.receiveShadow??!!t.receiveShadow??!0,r=e.castShadow??!!t.castShadow??!1;return a.receiveShadow=s,ve(a,r,s),e.collisionDetection||(a.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(a.physics=e.physics),this.applyVertexMaterials(e,a),a.traverse((e=>{e instanceof h&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&e.geometry.computeBoundsTree()})),a}async createFromPrefabAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);const a=new o;return t.prefab.objects.filter((e=>"global_fog"!==e.type)).forEach((e=>this.materialize(e,a,!0))),a}async createParticleSystem(e){const a=await this.assetsService.getAsset(e.assetId),s=new u;return await b.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new M(s,t);e.addRenderer(a),this.renderingView.onLoop((t=>e.update()))})),s}async createLight(e){if("point"===e.light.type){const t=new f(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=new g(.3,10,10),a=new d({color:new s(16771709)}),r=new h(e,a);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional),new o):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient),new o):void 0}applyDirectionalAmbientLight(e,t){const a=this.scene.children.find((e=>e.name===ye));null!=a?(a.intensity=t.intensity,a.color.set(t.color),a.groundColor.set(t.color)):console.warn("Couldn't find ambient light")}applyDirectionalLight(e){for(const t of this.renderingView.csm.lights)t.intensity=e.intensity,t.color.set(e.color),t.castShadow=e.castShadow;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.createAssetSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function ve(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Ae=new Map,be=new m({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const l=JSON.stringify(e.material);if(o&&Ae.has(l))return Ae.get(l);const c={opacity:e.material.params.opacity,map:null,emissive:e.material.params.emissive??null,metalness:e.material.params.metalness??0,flatShading:e.material.params.flatShading??!1,color:new s(e.material.params.color),transparent:null!=e.material.params.opacity&&e.material.params.opacity<1},h={};if(null!=e.material.params.map){const t=e.material.params.map,a=await r.getAsset(t);null!=a&&(c.map=await i.getTexture(a))}let m;switch(e.material.type){case"phong":m=new p({...c,...h});break;case"water":m=pe(c,a);break;case"grassFoliage":m=ce({color:c.color,map:c.map},a);break;case"grass":m=he({...c,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"unlit":case"lambert":case"shader":const t={standard:H,lambert:J,unlit:q}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await xe(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{m=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),m=Me.get(e.material.shader)}m.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),m=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(m),o&&Ae.set(l,m),m.side=e.material.side??m.side??t.FrontSide,m.transparent=(e.material.transparent??c.transparent??!1)||m.transparent,e.material.bloom&&(m.userData.hasBloom=!0),m.userData.assetId=e.id,m}async function xe(e,t,a,s,r,i,n,o){const l={};for(const[t,c]of Object.entries(e)){const e=await je(c,a,s,r,i,n,o);null!=e&&(l[t]=e)}return l}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await je(s,null,null,null);null!=e&&(t[a]=e)}return t}async function je(e,t,a,i,n,o,l){if(de.String,null==e||null==e.value||""===e.value)return null;const c=e.value;switch(e.type){case de.Number:case de.FloatNode:let h="string"==typeof c?parseFloat(c):c;return e.type===de.FloatNode?P(h):h;case de.Texture:return await a.getTexture(await t.getAsset(c));case de.Sampler2DNode:return C(await a.getTexture(await t.getAsset(c)));case de.Boolean:return c;case de.BooleanNode:return x(c);case de.Vector2:case de.Vec2Node:if("object"==typeof c){const t=c instanceof Array?(new S).fromArray(c):new S(c.x,c.y);return e.type===de.Vec2Node?F(t):t}return null;case de.Vector3:case de.Vec3Node:if("object"==typeof c){const t=c instanceof Array?(new v).fromArray(c):new v(c.x,c.y,c.z);return e.type===de.Vec3Node?z(t):t}return null;case de.Color:case de.RgbNode:const m=new s(c);return e.type===de.RgbNode?N(m):m;case de.String:return c;case de.BaseActor:const p=c;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(p);case de.Euler:const d=c;return(new r).fromArray(d);case de.Object3D:return(await a.getMesh(await t.getAsset(c))).scene;case de.Material:return await materialFromAsset(await t.getAsset(c),n,t,a,o);case de.AudioBuffer:return await a.getAudio(await t.getAsset(c));case de.VisualEffect:const u=await t.getAsset(c);if(null==l){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in u)return new T(l,u);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Pe(e){e.updateWorldMatrix(!1,!0),e.traverse((e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1}));const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}function Ie(e){return"linear"===e.type?new i(new s(e.color),e.near??100,e.far??1e3):"density"===e.type?new n(e.color,e.density):void console.warn("Invalid fog type",e)}const De=new d({color:4229780});async function Ne(e,a,s,i){null==i&&(i=(new c).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){if(null==e.position||null==e.rotation||null==e.scale)return t.identity();return t.compose((new v).fromArray(e.position),(new y).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>Ne(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?de.Number:t instanceof I||"function"==typeof e.prototype.isFloat?de.FloatNode:t instanceof w||e===w||e.isTexture?de.Texture:t instanceof W||e===V?de.Sampler2DNode:t instanceof Boolean||e===Boolean?de.Boolean:t instanceof j?de.BooleanNode:t instanceof s||e==s?de.Color:t instanceof E||"function"==typeof e.prototype.isRgb?de.RgbNode:t instanceof S||e==S?de.Vector2:t instanceof k||"function"==typeof e.prototype.isVec2?de.Vec2Node:t instanceof v||e==v?de.Vector3:t instanceof O||"function"==typeof e.prototype.isVec3?de.Vec3Node:t instanceof String||e===String?de.String:t instanceof $||e==$||e.prototype instanceof $||e.prototype==$?de.BaseActor:t instanceof r||e==r?de.Euler:t instanceof u||e==u?de.Object3D:t instanceof l||e==l?de.Material:t instanceof AudioBuffer||e==AudioBuffer?de.AudioBuffer:t instanceof T||e==T?de.VisualEffect:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map((e=>[e.name,{type:toSerializedParamType(e.type),value:t[e.name]?.value??a[e.name]??customParameterDefaultValueByType.get(toSerializedParamType(e.type))}])))}export function prepareCustomParamsFromType(e,t,a=null){const s=G(e);if(0===s.length)return{};let r;null!=a?R(a,(()=>{r=a.get(e)})):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case S:return t instanceof S?t.toArray():void a();case v:return t instanceof v?t.toArray():void a();case A:return t instanceof A?t.toArray():void a();case s:return t instanceof s?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new s(t).getHexString():void a();case String:return t;case r:return t instanceof r?t.toArray():void a()}}function Ee(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter((e=>Ve(e.materialId))),(t??[]).filter((e=>Ve(e.materialId))),(e=>e.color+e.name))}function Ve(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[de.RgbNode,"#000000"],[de.Color,"#000000"],[de.Vector4,[0,0,0,0]],[de.Vec4Node,[0,0,0,0]],[de.Vector3,[0,0,0]],[de.Vec3Node,[0,0,0]],[de.Vector2,[0,0]],[de.Vec2Node,[0,0]],[de.Euler,[0,0,0,"XYZ"]]]);export function applyMaterial(e,a,r,i){const n=[];return e.traverse((async e=>{if(e instanceof h||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of Z(e.material))t.hasOwnProperty("color")&&n.push(e)})),Promise.all(n.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const n=e.material[t];if(null==n.color||!(n.color instanceof s))continue;const o="#"+n.color.getHexString(),l=n.name;if(o===a.color&&(n.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await r(a.materialId),n=e.material[t];null!=s&&(e.material[t]=s,e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??o,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??l,null!=i&&i.set(e.id+"#"+t,n))}}else if("color"in e.material){const t="#"+e.material.color.getHexString(),s=e.material.name;if(t===a.color&&(e.material.name===a.name||null==a.name)||e.userData.originalColor===a.color&&e.userData.originalName===a.name){const n=await r(a.materialId),o=e.material;null!=n&&(e.material=n,e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,null!=i&&(i.has(e.id)||i.set(e.id,o)))}}})))}function Ce(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){return e.fragmentShader+e.vertexShader==a.fragmentShader+a.vertexShader&&function(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){for(const t in e.uniforms){if(null==a.uniforms[t])return!1;if(a.uniforms[t].value!==e.uniforms[t].value)return console.log("Different values",a.uniforms[t].value,e.uniforms[t].value),!1}return!0}return!1}(e,a)}return!1}
1
+ import{Subject as e}from"rxjs";import*as t from"three";import{BoxGeometry as a,Color as s,Euler as r,Fog as i,FogExp2 as n,Group as o,Material as l,Matrix4 as c,Mesh as h,MeshLambertMaterial as m,MeshPhongMaterial as p,MeshStandardMaterial as d,Object3D as u,PointLight as f,Quaternion as y,SphereGeometry as g,Texture as w,Vector2 as S,Vector3 as v,Vector4 as A}from"three";import b,{SpriteRenderer as M}from"three-nebula";import{bool as x,BooleanNode as j,float as I,FloatNode as P,NodeShaderMaterial as D,rgb as N,RgbNode as E,Texture2dLookupNode as V,textureSampler2d as C,vec2 as F,Vec2Node as k,vec3 as z,Vec3Node as O,vec4 as _}from"three-shader-graph";import{VfxActor as B}from"../effects/vfx/vfx-actor.js";import{VisualEffect as T}from"../effects/vfx/vfx-param.js";import{BaseActor as $}from"../gameplay/actors/actor.js";import L from"../gameplay/actors/builtin/index.js";import{PhysicsBodyType as U,withInjectionContext as R}from"../gameplay/index.js";import{Sampler2DNode as W}from"../shader-nodes/index.js";import{LambertShader as J}from"../shader/builtin/lambert-shader.js";import{StandardShader as H}from"../shader/builtin/standard-shader.js";import{UnlitShader as q}from"../shader/builtin/unlit-shader.js";import{extractShaderParameters as G}from"../shader/parameter.js";import{ArrayMap as X,groupBy as Y}from"../utils/collections.js";import{iterateMaterials as Z}from"../utils/materials.js";import{filterChildrenShallow as Q,filterSceneShallow as K,findFirstVisibleObject as ee}from"../utils/three/traverse.js";import{AssetMeshInstance as te}from"./asset-resource-loader.js";import{isCollisionMesh as ae}from"./collision/collision-shape-import.js";import{BoxCollisionShape as se,PhysicalShapeMesh as re}from"./collision/collision-shape.js";import{LandscapeManager as ie}from"./landscape/landscape-manager.js";import{initLandscape as ne}from"./landscape/landscape.js";import{SectionGrid as oe,smoothNormalsCrossMeshes as le}from"./landscape/utils.js";import{createGrassFoliageMaterial as ce}from"./materials/grass-foliage.js";import{createGrassMaterial as he}from"./materials/grass.js";import{getMaterialAttribute as me}from"./materials/utils/material-painting.js";import{createWaterMaterial as pe}from"./materials/water.js";import{SerializedParamType as de}from"./model.js";import{ShapeLibrary as ue,ShapeLibraryKeys as fe}from"./objects/shapes.js";import{ambientLightName as ye,createSky as ge,defaultSkyMaterial as we}from"./sky.js";const Se={};export const shapeDefaultColor="#aaaaaa";export class SceneMaterializerLoader{constructor(e,t,a){this.dataProvider=e,this.assetsService=t,this.assetManagerService=a}get(e,t){return new SceneMaterializer(e,this.dataProvider,this.assetsService,this.assetManagerService,t,[],[],{create:()=>null,initActor:async()=>{}})}}export class SceneMaterializer{constructor(a,s,r,i,n,o,l,c){this.scene=a,this.dataProvider=s,this.assetsService=r,this.assetManagerService=i,this.renderingView=n,this.shaders=o,this.actorTypes=l,this.actorProvider=c,this.objectMap=new Map,this.sceneObjectMap=new Map,this.components=[],this.landscapeManagers=[],this.materializedActors=new Map,this.inEditor=!0,this.updated$=new e,this.removed$=new e,this.error$=new e,this.editorActorParamSnapshot=new Map,this.assets=new Map,this._canBeInstancedCache=new Map,this._originalMaterials=new Map,this.geometryCache=new Map,this.collisionShapeCache=new Map,this.originalFog=null,s.onUpdate((e=>this.update(e))),s.onRemove((e=>this.remove(e))),this.createAssetSubscription=r.onCreate.subscribe((e=>{this.assets.set(e.id,e)})),this.updateSubscription=r.onUpdate.subscribe((async e=>{this.assets.set(e.id,e),"material"==e.type?a.traverse((a=>{if(a instanceof t.Mesh)if(Array.isArray(a.material))for(let t=0;t<a.material.length;t++)this.refreshMaterial(a,a.material[t],e,t);else this.refreshMaterial(a,a.material,e)})):"mesh"==e.type?(this.findByAssetId(e.id).forEach((t=>{Ee(t.userData.src.materialAssignments,e.materialAssignments).forEach((e=>{this.applyMaterial(t,e)}))})),this.landscapeManagers.forEach((t=>{t.source.grass.layers.some((t=>t.meshes.some((t=>t.assetId===e.id))))&&t.queueRefreshScatter(this.renderingView?.camera.position??new v,!0)}))):"prefab"===e.type&&this.findByAssetId(e.id).forEach((e=>{const t=e.userData.src;this.remove(t),this.materializeAndInitActor(t)}))}))}async refreshMaterial(e,t,a,s){if(t?.userData?.assetId!==a.id)return;const r=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!0);r.userData=t.userData,null!=s?Ce(e.material[s],r)||(e.material[s]=r):Ce(e.material,r)||(e.material=r)}get actorInstances(){return Array.from(this.materializedActors.values())}async prefetchAssets(){const e=Array.from(new Set(this.dataProvider.getObjects().filter((e=>null!=e.assetId&&"asset_mesh"==e.type)).filter((e=>e.assetId))));await Promise.all(e.map((e=>this.assetsService.getAsset(e.assetId).then((e=>{if(null!=e)return this.assetManagerService.getMesh(e)})))))}async init(){await this.preInit(),Ae.clear(),await this.prefetchAssets(),await Promise.all(this.dataProvider.getObjects().map((e=>this.materialize(e)))),await this.initActorsPostInit()}initActorsPostInit(e=this.actorInstances){const t=e.map((async e=>{const t=e.object.userData.src;if("vfx"===t.type)return Promise.resolve();const a=await this.assetsService.getAsset(t.assetId),s={...a?.actor?.params??{},...t.actor?.params??{}};for(const a of t.actor.innerParams??[])await this.applyActorComponentParams(e,a.path.slice(),a.params);const r=await xe(s,e.constructor,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders,this.actorProvider);Object.assign(e,r);try{return await this.actorProvider.initActor(e)}catch(e){console.error(`Failed to initiate actor (name="${t.name}", id=${t.id})`,e)}}));return Promise.all(t)}addVfxChildActors(e,t=e){}async applyActorComponentParams(e,t,a){const s=t.length,r=t.shift();if(0==s){const t=await xe(a,null,this.assetsService,this.assetManagerService,this.materializedActors,this.renderingView,this.shaders);for(const[a,s]of Object.entries(t))null!=s&&(e[a]=s)}else null!=e[r]&&await this.applyActorComponentParams(e[r],t,a)}canObjectBeInstanced(e){return e.physics?.type!==U.dynamic&&"sky"!==e.type&&"global_fog"!==e.type}async canAssetBeInstanced(e){if(!this._canBeInstancedCache.has(e.assetId)){const t=await this.createFromAsset(e);if(null==t)return!1;const a=[];t.traverse((e=>{!ae(e)&&e.isMesh&&a.push(e)}));const s=1==a.length&&0==a[0].children.length,r=a[0]instanceof h&&null!=a[0].geometry.morphAttributes&&Object.keys(a[0].geometry.morphAttributes).length>0,i=!0;this._canBeInstancedCache.set(e.assetId,s&&i&&!r)}return this._canBeInstancedCache.get(e.assetId)}async preInit(){this.renderingView?.onLoop((()=>{null!=this.sky&&this.renderingView.camera.getWorldPosition(this.sky.position)})),this.assetsService.getAssets().then((e=>{for(const t of e)this.assets.set(t.id,t)}))}async initWithInstancing(){await this.preInit(),await this.prefetchAssets();const e=[],a=new X,i=new X;for(const t of this.dataProvider.getObjects())await Ne(t,(async(t,r,n)=>{const o="asset_mesh"==t.type&&this.canObjectBeInstanced(t)&&await this.canAssetBeInstanced(t),l="shape_mesh"===t.type&&"landscape"!==t.shape&&t.physics?.type!==U.dynamic;if(o||l)if(r&&r.children?.length>0&&r.children.splice(r.children.findIndex((e=>e.id===t.id)),1),l){let e=t.shape+JSON.stringify(t.shapeParams??{})+t.castShadow+t.receiveShadow;const a=t.materialAssignments?.at(0)?.materialId,r=null!=a?this.assets.get(a):null;let o=null;if(null!=r&&"shader"!==r.material.type){if(e+=r.material.type+r.material.shader,null!=r.material.shaderParams){if(e+=Object.entries(r.material.shaderParams).filter((([e,t])=>"color"!=e)).map((e=>JSON.stringify(e))).join(),null!=r.material.shaderParams.color){const e=r.material.shaderParams.color;e.type===de.Color&&null!=e.value&&(o=new s(e.value))}}}else e+=a;i.push(e,{object:{...t,parentTransform:n},color:o})}else{const e=t.assetId+JSON.stringify(t.materialAssignments??[]);a.push(e,{...t,parentTransform:n})}else null==r&&e.push({...t,parentTransform:n})}));for(const e of a.values()){if(0==e.length)continue;const t=await this.createFromAsset(e[0]);if(null==t)continue;const a=await this.createInstancedMesh(e,t),s=new te;s.add(a),s.userData.src=e[0],t instanceof te&&(s.collisionShapes=t.collisionShapes),s.castShadow=!1,s.receiveShadow=!1,this.scene.add(s)}for(const e of i.values()){if(0==e.length)continue;const a=e[0].object,i=await this.createFromShape(a),n=ee(i,(e=>!ae(e)&&null!=e.geometry)),o=n.material.clone();null!=e[0].color&&null!=o.color&&(o.color=new s(16777215));const l=n.geometry,h=new t.InstancedMesh(l,o,e.length);for(let a=0;a<e.length;a++){const s=e[a],o=(new t.Matrix4).compose((new v).fromArray(s.object.position),(new y).setFromEuler((new r).fromArray(s.object.rotation)),(new v).fromArray(s.object.scale)),l=(new c).copy(s.object.parentTransform).multiply(o);h.setMatrixAt(a,l),null!=s.color&&h.setColorAt(a,s.color),h.castShadow=i.castShadow??!0,h.receiveShadow=n.receiveShadow??!0;const m=new te;m.add(h),m.userData.src=e[0],i instanceof re&&(m.collisionShapes=[i.collisionShape]),m.castShadow=!1,m.receiveShadow=!1,this.scene.add(m)}}await Promise.all(e.map((e=>this.materialize(e)))),await this.initActorsPostInit()}async createInstancedMesh(e,a){const s=ee(a,(e=>!ae(e)&&null!=e.geometry)),i=await this.assetsService.getAsset(e[0].assetId);await this.applyMaterials(a,Ee(e[0].materialAssignments,i.materialAssignments)),s.updateMatrix();const n=s.geometry.clone().applyMatrix4(s.matrix),o=new t.InstancedMesh(n,s.material,e.length);s.material instanceof l&&(o.material.side=t.FrontSide);for(let a=0;a<e.length;a++){const s=(new t.Matrix4).compose((new v).fromArray(e[a].position),(new y).setFromEuler((new r).fromArray(e[a].rotation)),(new v).fromArray(e[a].scale)),i=(new c).copy(e[a].parentTransform).multiply(s);o.setMatrixAt(a,i)}return o.castShadow=e[0].castShadow??i.castShadow??!0,o.receiveShadow=e[0].receiveShadow??i.receiveShadow??!0,o}remove(e){if(console.log("Remove scene object",e),"global_fog"==e.type)return void(this.scene.fog=this.originalFog);if("actor"==e.type){const t=this.materializedActors.get(e.id);null!=t?(t.disposed.next(!0),t.onEndPlay()):console.warn("Failed to remove actor",e)}const t=this.sceneObjectMap.get(e.id);t?.parent.remove(t),this.sceneObjectMap.delete(e.id),this.components.filter((t=>t.object.userData.src?.id===e.id)).forEach((e=>this.components.splice(this.components.indexOf(e,1)))),this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>{e.clear(),e.stop(),this.landscapeManagers.splice(this.landscapeManagers.indexOf(e,1))})),this.removed$.next({object:t,source:e})}deleteSceneObject(e){const t=this.sceneObjectMap.get(e.id);if(this.scene.remove(t),"landscape"==e.type){const t=this.landscapeManagers.findIndex((t=>t.source.id===e.id));if(t>-1){const e=this.landscapeManagers.splice(t,1)[0];e.clear(),e.stop()}}}findByAssetId(e){return K(this.scene,(t=>t.userData.src?.assetId==e),(e=>null!=e.userData.src))}applyMaterials(e,t){return null==t?Promise.resolve([]):Promise.all(t.filter((e=>"null"!==e.materialId)).map((t=>this.applyMaterial(e,t))))}async applyMaterial(e,t){await applyMaterial(e,t,(e=>{const t=this.assets.get(e);if(null!=t)return materialFromAsset(t,this.renderingView,this.assetsService,this.assetManagerService,this.shaders)}),this._originalMaterials)}unapplyMaterials(e){e.traverse((async e=>{if(e instanceof h)if(e.material instanceof Array)for(let t=0;t<e.material.length;t++)e.material[t]=this._originalMaterials.get(e.id+"#"+t)??e.material[t];else e.material=this._originalMaterials.get(e.id)??e.material}))}updateActors(e){console.log("update actors"),this.actorTypes=e;const t=new Set(Object.values(L));K(this.scene,(e=>e.userData.src?.id&&"actor"===e.userData.src.type&&this.materializedActors.has(e.userData.src?.id)&&!t.has(e.userData.src.actor.type))).forEach((async e=>{this.remove(e.userData.src),await this.materializeAndInitActor(e.userData.src)}))}updateShaders(e){this.shaders=e;for(const[e,t]of Ae.entries())t.userData.customShaderName&&Ae.delete(e);this.landscapeManagers.forEach((t=>t.updateShaders(e))),K(this.scene,(e=>!0)).forEach((e=>{e.traverse((async e=>{if(e instanceof h)if(Array.isArray(e.material))for(let t=0;t<e.material.length;t++){const a=e.material[t].userData?.customShaderName;if(null!=a){const a=this.assets.get(e.material[t].userData.assetId);this.refreshMaterial(e,e.material[t],a,t)}}else{const t=e.material.userData?.customShaderName;if(null!=t){const t=this.assets.get(e.material.userData.assetId);this.refreshMaterial(e,e.material,t)}}}))}))}async update(e){if("sky"===e.type&&null!=this.sky&&null!=this.sky.parent)return void this.updateSky(e);const t=this.sceneObjectMap.get(e.id);if(t){let r=!1;if(t.traverseAncestors((e=>{"_hology_transform_group"===e.name&&(r=!0)})),!r){const a=this.findParent(e);null!=a&&a.uuid!=t.uuid?a.attach(t):console.error("Parent is wrong")}if("prefab"!==e.type&&"group"!==e.type){this.unapplyMaterials(t);this.inEditor&&e.hidden&&!1?t.traverse((e=>{e instanceof h&&(e.material.wireframe=!0)})):t.traverse((e=>{e instanceof h&&(e.material.wireframe=!1)}))}if("asset_mesh"===e.type){const a=this.assets.get(e.assetId);Ee(e.materialAssignments,a.materialAssignments).forEach((e=>this.applyMaterial(t,e)))}else"shape_mesh"===e.type&&this.applyMaterials(t,e.materialAssignments);if(r||(null!=e.position&&t.position.fromArray(e.position),null!=e.scale&&t.scale.fromArray(e.scale),null!=e.rotation&&t.rotation.fromArray(e.rotation)),this.applyVertexMaterials(e,t),"light"==e.type)if("point"==e.light.type){const a=t;a.color=new s(e.light.point.color),a.intensity=e.light.point.intensity,a.decay=e.light.point.decay,a.castShadow=e.light.point.castShadow,a.distance=Math.max(e.light.point.distance,0)}else"directional"===e.light.type?this.applyDirectionalLight(e.light.directional):"ambient"===e.light.type&&this.applyDirectionalAmbientLight(t,e.light.ambient);else if("landscape"===e.shape){const a=this.landscapeManagers.find((t=>t.source.id===e.id)).source.landscape.options.density!==e.landscape.options.density;if(this.inEditor&&a){this.remove(e);const t=await this.materializeAndInitActor(e);return void this.updated$.next({object:t,source:e})}this.applyHeightMaps(t,e.landscape.heightMaps),this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>!0))))}else if("global_fog"===e.type){const t=(this.scene.fog instanceof n?"density":"linear")!==e.fog.type;this.scene.fog=Pe(e.fog),t&&(a=this.scene).traverse((e=>{if(e instanceof h){const t=e.material;t instanceof D&&(a.fog instanceof i?(t.uniforms.fogFar.value=a.fog.far,t.uniforms.fogNear.value=a.fog.near):a.fog instanceof n&&(t.uniforms.density={value:a.fog.density}),t.needsUpdate=!0,t.uniformsNeedUpdate=!0)}})),this.fixFogColor()}else if("actor"===e.type){if(this.materializedActors.has(e.id)){const t=this.editorActorParamSnapshot.get(e.id);null!=t&&t===JSON.stringify(e.actor)||(console.log("Rematerializing actor because parameters changed"),r||(this.remove(e),await this.materializeAndInitActor(e)))}}else if("shape_mesh"===e.type){const a=await this.createMeshByShape(e.shape,t.material,e.shapeParams);t instanceof re&&(t.geometry=a.geometry,t.collisionShape=a.collisionShape)}("asset_mesh"===e.type||"shape_mesh"===e.type&&"landscape"!==e.shape)&&ve(t,e.castShadow,e.receiveShadow),e.name&&e.name.length>0&&(t.name=e.name),this.updated$.next({object:t,source:e})}else{const t=await this.materializeAndInitActor(e);this.updated$.next({object:t,source:e})}var a}async materializeAndInitActor(e,t=this.findParent(e)){console.log("materialize actor and init");const a=await this.materialize(e,t);return Ne(e,(async e=>{if("actor"===e.type){const t=this.materializedActors.get(e.id);null!=t?await this.initActorsPostInit([t]):console.error(`Something went wrong when creating actor ${e.id}`)}})),a}findParent(e){const t=this.dataProvider.getObjects().flatMap((t=>t.id===e.id?null:Q(t,(t=>t.children?.some((t=>t.id===e.id))),(()=>!0))))[0];return null==t?this.scene:null!=t?K(this.scene,(e=>e.userData?.src?.id===t.id),(e=>null!=e.userData?.src))[0]:void 0}fixFogColor(){!0===this.renderingView.options.enableOutlines&&(this.scene.fog.color=new s(this.scene.fog.color))}findMeshWithGeometry(e){let t;return e.traverse((e=>{e instanceof h&&e.geometry&&(t=e)})),t}applyVertexMaterials(e,t){if(null==e.vertexMaterials||0===e.vertexMaterials.length)return;const a=Y(e.vertexMaterials,(e=>e.m));t.traverse((e=>{if(e instanceof h){const t=me(e,!1);if(null!=t){for(let e=0;e<t.array.length;e++)t.setX(e,0);t.needsUpdate=!0}}}));const s=new Set;for(const[e,r]of a.entries()){const a=null!=e?t.getObjectByName(e):this.findMeshWithGeometry(t);let i=!1;if(null==a)return void console.warn(`Failed to apply vertex materials on mesh with name "${e}"`);const n=me(a,!0);for(let e=0;e<n.array.length;e++)n.setX(e,0);for(const e of r)n.setX(e.i,e.w[0]),n.setY(e.i,e.w[1]),n.setZ(e.i,e.w[2]),i=!0;i&&s.add(e)}this.inEditor&&this.landscapeManagers.filter((t=>t.source.id===e.id)).forEach((e=>e.queueRefreshScatter(this.renderingView.camera.position,!0,(e=>s.has(e.name)))))}async materialize(e,t,s=!1){let r;switch(e.type){case"asset_mesh":r=await this.createFromAsset(e);break;case"shape_mesh":r=await this.createFromShape(e);break;case"light":r=await this.createLight(e);break;case"particles":r=await this.createParticleSystem(e),e.collisionDetection=!1;break;case"global_fog":this.scene.fog=Pe(e.fog),this.fixFogColor(),r=new o;break;case"sky":this.sky=ge(),this.updateSky(e),r=this.sky;break;case"actor":r=await this.createFromActor(e);break;case"group":r=new o;break;case"prefab":r=await this.createFromPrefabAsset(e);break;case"vfx":r=await this.createFromVfx(e);break;default:if(this.inEditor)throw new Error("unknown type "+e.type);console.warn(`Failed to materialize object. Unknown type '${e.type}'. This might be because the hology/core library is not compatible with the editor version.`)}if(null!=r){if(e.name&&e.name.length>0&&(r.name=e.name),null!=e.position&&r.position.fromArray(e.position),null!=e.scale&&r.scale.fromArray(e.scale),null!=e.rotation&&r.rotation.fromArray(e.rotation),s||(r.userData.src=e),this.inEditor,this.inEditor){let e=null;r instanceof re&&(e=function(e){if(e instanceof se)return new h(new a(...e.offset.toArray()),De);return null}(r.collisionShape)),null!=e&&(e.layers.disable(0),e.layers.enable(18),e.scale.multiplyScalar(1.1),r.add(e))}return this.objectMap.set(r.uuid,e),this.sceneObjectMap.set(e.id,r),e.physics?.type!==U.dynamic||null==t||this.inEditor?null==t?this.scene.add(r):t?.add(r):(t.add(r),r.getWorldPosition(r.position),r.getWorldQuaternion(r.quaternion),r.getWorldScale(r.scale),this.scene?.attach(r)),null!=e.children&&await Promise.all(e.children?.map((e=>this.materialize(e,r,s)))),this.inEditor||"asset_mesh"!=e.type&&"shape_mesh"!==e.type||null!=e.physics?.type&&e.physics.type==U.dynamic||Ie(r),r}}async updateSky(e){if(null==e?.sky?.materialId)return void(this.sky.material=we);const a=await this.assetsService.getAsset(e.sky.materialId),s=await materialFromAsset(a,this.renderingView,this.assetsService,this.assetManagerService,this.shaders,!1);s.side=t.BackSide,null!=this.sky?this.sky.material=s:console.warn("No sky has been created")}async createComponent(e,t,a,s){const r=new Se[a.path+"/"+a.className],i=t.id+s;r.id=i,r.object=e;for(const e of a.params)null!=e.value&&(r[e.name]=e.value);return this.components.push(r),i}async createFromActor(e){const t=this.actorTypes.find((t=>t.name===e.actor?.type))?.type??L[e.actor?.type];if(null==t)return null;this.inEditor&&this.editorActorParamSnapshot.set(e.id,JSON.stringify(e.actor));const a=await this.actorProvider.create(t,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!0);return this.materializedActors.set(e.id,a),a?.object}async createFromVfx(e){const t=await this.assetsService.getAsset(e.assetId);null==t&&console.error("Could not find asset",e);const a=await this.actorProvider.create(B,(new v).fromArray(e.position),(new r).fromArray(e.rotation),!1);return await a.fromAsset(t),a.play(),this.materializedActors.set(e.id,a),a?.object}cleanup(){this.materializedActors.clear()}async createFromShape(e){const t=this.inEditor&&e.hidden;let a;if("landscape"==e.shape)a=this.createLandscape(e),a.traverse((e=>{e instanceof h&&this._originalMaterials.set(e.id,e.material)}));else{let r=new d({name:"Default",color:new s("#aaaaaa"),visible:this.inEditor||!e.hidden,wireframe:!!t});const i=await this.createMeshByShape(e.shape,r,e.shapeParams);i.castShadow=e.castShadow??!0,i.receiveShadow=e.castShadow??!1,e.collisionDetection||(i.collisionShape=null),i.physics=e.physics,a=i,this._originalMaterials.set(a.id,i.material),a.traverse((e=>{}))}return t||(await Promise.all((e.materialAssignments??[]).filter((e=>null!=e.materialId)).map((e=>this.applyMaterial(a,e)))),this.applyVertexMaterials(e,a)),a}createLandscape(e){const t=e.landscape?.options;if(null==t)return console.error(`No landscape options exist on scene object ${e.id} ${e.name}`),new o;const a=ne(e.landscape.options);this.applyHeightMaps(a,e.landscape.heightMaps,!0);const s=new ie(e,this.renderingView,a,this.assetManagerService,this.assetsService,this.shaders,(t=>{(e.materialAssignments??[]).filter((e=>null!=e.materialId)).forEach((e=>this.applyMaterial(t,e)))}));return this.landscapeManagers.push(s),s.refreshGeometry(),a}applyHeightMaps(e,t,a=!1){const s=new oe(e.sections);for(const e of t??[]){const t=s.find(e.x,e.y);if(!t)return;const a=t.geometry.getAttribute("position");for(const t of e.points)a.setY(t.i,t.y);a.needsUpdate=!0}const r=e.sections;r.forEach((e=>{e.geometry.computeBoundsTree(),e.geometry.computeVertexNormals()})),this.inEditor&&!a||setTimeout((()=>le(r)),50)}async createMeshByShape(e,t,a={}){if("landscape"!==e&&fe.includes(e)){const s=await prepareShapeParameters(a??{}),r=e+JSON.stringify(a);return this.geometryCache.has(r)||this.geometryCache.set(r,ue[e].geometry(s)),this.collisionShapeCache.has(r)||this.collisionShapeCache.set(r,ue[e].collision(s)),new re(this.geometryCache.get(r),t,this.collisionShapeCache.get(r))}if(this.inEditor)throw new Error(`Unsupported shape '${e}'`);console.warn(`Failed to create shape. Unsupported shape '${e}'. This might be because the hology/core library is not compatible with the editor version.`)}async createFromAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);let{scene:a}=await this.assetManagerService.getMesh(t,{mergeGeomtries:!0});Ee(e.materialAssignments,t.materialAssignments).forEach((e=>this.applyMaterial(a,e)));const s=e.receiveShadow??!!t.receiveShadow??!0,r=e.castShadow??!!t.castShadow??!1;return a.receiveShadow=s,ve(a,r,s),e.collisionDetection||(a.collisionShapes=[]),null!=e.physics&&!0!==this.inEditor&&(a.physics=e.physics),this.applyVertexMaterials(e,a),a.traverse((e=>{e instanceof h&&"computeBoundsTree"in e.geometry&&null==e.geometry.boundsTree&&e.geometry.computeBoundsTree()})),a}async createFromPrefabAsset(e){const t=await this.assetsService.getAsset(e.assetId);if(null==t)return void console.warn(`Can not find asset with id ${e.assetId} and name ${e.name}`);const a=new o;return t.prefab.objects.filter((e=>"global_fog"!==e.type)).forEach((e=>this.materialize(e,a,!0))),a}async createParticleSystem(e){const a=await this.assetsService.getAsset(e.assetId),s=new u;return await b.fromJSONAsync(a.particleSystem,t).then((e=>{const a=new M(s,t);e.addRenderer(a),this.renderingView.onLoop((t=>e.update()))})),s}async createLight(e){if("point"===e.light.type){const t=new f(e.light.point.color,e.light.point.intensity,e.light.point.distance,e.light.point.decay);if(t.castShadow=e.light.point.castShadow??!0,this.inEditor){const e=new g(.3,10,10),a=new d({color:new s(16771709)}),r=new h(e,a);t.add(r)}return t}return"directional"===e.light.type?(this.applyDirectionalLight(e.light.directional),new o):"ambient"===e.light.type?(this.applyDirectionalAmbientLight(null,e.light.ambient),new o):void 0}applyDirectionalAmbientLight(e,t){const a=this.scene.children.find((e=>e.name===ye));null!=a?(a.intensity=t.intensity,a.color.set(t.color),a.groundColor.set(t.color)):console.warn("Couldn't find ambient light")}applyDirectionalLight(e){for(const t of this.renderingView.csm.lights)t.intensity=e.intensity,t.color.set(e.color),t.castShadow=e.castShadow;this.renderingView.csm.lightDirection.fromArray(e.direction).normalize()}dispose(){this.updateSubscription.unsubscribe(),this.createAssetSubscription.unsubscribe(),this.materializedActors.forEach((e=>e.disposed.next(!0)))}}function ve(e,t,a){e.castShadow=t,e.receiveShadow=a,e.traverse((e=>{e.castShadow=t,e.receiveShadow=a}))}const Ae=new Map,be=new m({color:16711935}),Me=new Map;export async function materialFromAsset(e,a,r,i,n,o=!0){const l=JSON.stringify(e.material);if(o&&Ae.has(l))return Ae.get(l);const c={opacity:e.material.params.opacity,map:null,emissive:e.material.params.emissive??null,metalness:e.material.params.metalness??0,flatShading:e.material.params.flatShading??!1,color:new s(e.material.params.color),transparent:null!=e.material.params.opacity&&e.material.params.opacity<1},h={};if(null!=e.material.params.map){const t=e.material.params.map,a=await r.getAsset(t);null!=a&&(c.map=await i.getTexture(a))}let m;switch(e.material.type){case"phong":m=new p({...c,...h});break;case"water":m=pe(c,a);break;case"grassFoliage":m=ce({color:c.color,map:c.map},a);break;case"grass":m=he({...c,colorTwo:new s(e.material.params.colorTwo),colorThree:new s(e.material.params.colorThree)},a);break;case"standard":case"unlit":case"lambert":case"shader":const t={standard:H,lambert:J,unlit:q}[e.material.type]??n.find((t=>t.name==e.material.shader))?.type;if(t){const s=new t,o=await xe(e.material?.shaderParams??{},t,r,i,null,a,n);Object.assign(s,o);try{m=s.build()}catch(t){console.log("Shader runtime error: "+t),Me.has(e.material.shader)||Me.set(e.material.shader,be.clone()),m=Me.get(e.material.shader)}m.userData.customShaderName=e.material.shader}else console.warn("Missing shader implementation with name "+e.material.shader),m=be;break;default:throw new Error("Unsupported material type"+e.material.type)}return a?.csm.setupMaterial(m),o&&Ae.set(l,m),m.side=e.material.side??m.side??t.FrontSide,m.transparent=(e.material.transparent??c.transparent??!1)||m.transparent,e.material.bloom&&(m.userData.hasBloom=!0),m.userData.assetId=e.id,m}async function xe(e,t,a,s,r,i,n,o){const l={};for(const[t,c]of Object.entries(e)){const e=await je(c,a,s,r,i,n,o);null!=e&&(l[t]=e)}return l}export async function prepareShapeParameters(e){const t={};for(const[a,s]of Object.entries(e)){const e=await je(s,null,null,null);null!=e&&(t[a]=e)}return t}async function je(e,t,a,i,n,o,l){if(de.String,null==e||null==e.value||""===e.value)return null;const c=e.value;switch(e.type){case de.Number:case de.FloatNode:let h="string"==typeof c?parseFloat(c):c;return e.type===de.FloatNode?I(h):h;case de.Texture:return await a.getTexture(await t.getAsset(c));case de.Sampler2DNode:return C(await a.getTexture(await t.getAsset(c)));case de.Boolean:return c;case de.BooleanNode:return x(c);case de.Vector2:case de.Vec2Node:if("object"==typeof c){const t=c instanceof Array?(new S).fromArray(c):new S(c.x,c.y);return e.type===de.Vec2Node?F(t):t}return null;case de.Vector3:case de.Vec3Node:if("object"==typeof c){const t=c instanceof Array?(new v).fromArray(c):new v(c.x,c.y,c.z);return e.type===de.Vec3Node?z(t):t}return null;case de.Color:case de.RgbNode:const m=new s(c);return e.type===de.RgbNode?N(m):m;case de.String:return c;case de.BaseActor:const p=c;return null==i&&console.warn("Class parameters can not be prepared as actors are not passed in"),i?.get(p);case de.Euler:const d=c;return(new r).fromArray(d);case de.Object3D:return(await a.getMesh(await t.getAsset(c))).scene;case de.Material:return await materialFromAsset(await t.getAsset(c),n,t,a,o);case de.AudioBuffer:return await a.getAudio(await t.getAsset(c));case de.VisualEffect:const u=await t.getAsset(c);if(null==l){console.error("Can not create instance of visual effect because missing actor provider");break}if("vfx"in u)return new T(l,u);console.error("Using a non-vfx asset for visual effect parameter")}return null}function Ie(e){e.updateWorldMatrix(!1,!0),e.traverse((e=>{e.matrixAutoUpdate=!1,e.matrixWorldNeedsUpdate=!1}));const t=e.updateMatrixWorld;e.updateMatrixWorld=function(){t.apply(e),e.updateMatrixWorld=function(){}}}function Pe(e){return"linear"===e.type?new i(new s(e.color),e.near??100,e.far??1e3):"density"===e.type?new n(e.color,e.density):void console.warn("Invalid fog type",e)}const De=new d({color:4229780});async function Ne(e,a,s,i){null==i&&(i=(new c).identity()),await a(e,s,i);const n=i.clone().multiply(function(e,t){if(null==e.position||null==e.rotation||null==e.scale)return t.identity();return t.compose((new v).fromArray(e.position),(new y).setFromEuler((new r).fromArray(e.rotation)),(new v).fromArray(e.scale))}(e,new t.Matrix4));return Promise.all((e.children??[]).map((t=>Ne(t,a,e,n))))}export function toSerializedParamType(e){const t=e.constructor.prototype;return t instanceof Number||e===Number?de.Number:t instanceof P||"function"==typeof e.prototype.isFloat?de.FloatNode:t instanceof w||e===w||e.isTexture?de.Texture:t instanceof W||e===V?de.Sampler2DNode:t instanceof Boolean||e===Boolean?de.Boolean:t instanceof j?de.BooleanNode:t instanceof s||e==s?de.Color:t instanceof E||"function"==typeof e.prototype.isRgb?de.RgbNode:t instanceof S||e==S?de.Vector2:t instanceof k||"function"==typeof e.prototype.isVec2?de.Vec2Node:t instanceof v||e==v?de.Vector3:t instanceof O||"function"==typeof e.prototype.isVec3?de.Vec3Node:t instanceof String||e===String?de.String:t instanceof $||e==$||e.prototype instanceof $||e.prototype==$?de.BaseActor:t instanceof r||e==r?de.Euler:t instanceof u||e==u?de.Object3D:t instanceof l||e==l?de.Material:t instanceof AudioBuffer||e==AudioBuffer?de.AudioBuffer:t instanceof T||e==T?de.VisualEffect:void console.warn("Failed to map parameter type to serialized version",{type:e})}export function prepareCustomParams(e,t,a={}){return Object.fromEntries(e.map((e=>[e.name,{type:toSerializedParamType(e.type),value:t[e.name]?.value??a[e.name]??customParameterDefaultValueByType.get(toSerializedParamType(e.type))}])))}export function prepareCustomParamsFromType(e,t,a=null){const s=G(e);if(0===s.length)return{};let r;null!=a?R(a,(()=>{r=a.get(e)})):r=new e;const i={};for(const e of s){const t=r[e.name];if(null!=t){const a=serializeCustomParameter(e.type,t);null!=a&&(i[e.name]=a)}}return prepareCustomParams(s,t,i)}export function serializeCustomParameter(e,t){function a(){console.error("Failed to serialize value",{type:e,value:t})}switch(e){case Number:case Boolean:return t;case S:return t instanceof S?t.toArray():void a();case v:return t instanceof v?t.toArray():void a();case A:return t instanceof A?t.toArray():void a();case s:return t instanceof s?"#"+t.getHexString():"string"==typeof t?t:"number"==typeof t?"#"+new s(t).getHexString():void a();case String:return t;case r:return t instanceof r?t.toArray():void a()}}function Ee(e,t){return function(e,t,a){const s=[],r=new Set;for(const i of[...e??[],...t??[]]){const e=a(i);r.has(e)||(r.add(e),s.push(i))}return s}((e??[]).filter((e=>Ve(e.materialId))),(t??[]).filter((e=>Ve(e.materialId))),(e=>e.color+e.name))}function Ve(e){return"null"!=e&&null!=e}export const customParameterDefaultValueByType=new Map([[de.RgbNode,"#000000"],[de.Color,"#000000"],[de.Vector4,[0,0,0,0]],[de.Vec4Node,[0,0,0,0]],[de.Vector3,[0,0,0]],[de.Vec3Node,[0,0,0]],[de.Vector2,[0,0]],[de.Vec2Node,[0,0]],[de.Euler,[0,0,0,"XYZ"]]]);export function applyMaterial(e,a,r,i){const n=[];return e.traverse((async e=>{if(e instanceof h||e.isMesh||e instanceof t.SkinnedMesh||e.isSkinnedMesh)for(const t of Z(e.material))t.hasOwnProperty("color")&&n.push(e)})),Promise.all(n.map((async e=>{if(e.material instanceof Array)for(let t=0;t<e.material.length;t++){const n=e.material[t];if(null==n.color||!(n.color instanceof s))continue;const o="#"+n.color.getHexString(),l=n.name;if(o===a.color&&(n.name===a.name||null==a.name)||e.userData["originalColor_"+t]===a.color&&e.userData["originalMaterialName_"+t]===a.name){const s=await r(a.materialId),n=e.material[t];null!=s&&(e.material[t]=s,e.userData["originalColor_"+t]=e.userData["originalColor_"+t]??o,e.userData["originalMaterialName_"+t]=e.userData["originalMaterialName_"+t]??l,null!=i&&i.set(e.id+"#"+t,n))}}else if("color"in e.material){const t="#"+e.material.color.getHexString(),s=e.material.name;if(t===a.color&&(e.material.name===a.name||null==a.name)||e.userData.originalColor===a.color&&e.userData.originalName===a.name){const n=await r(a.materialId),o=e.material;null!=n&&(e.material=n,e.userData.originalColor=e.userData.originalColor??t,e.userData.originalMaterialName=e.userData.originalMaterialName??s,null!=i&&(i.has(e.id)||i.set(e.id,o)))}}})))}function Ce(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){return e.fragmentShader+e.vertexShader==a.fragmentShader+a.vertexShader&&function(e,a){if(e instanceof t.ShaderMaterial&&a instanceof t.ShaderMaterial){for(const t in e.uniforms){if(null==a.uniforms[t])return!1;if(a.uniforms[t].value!==e.uniforms[t].value)return console.log("Different values",a.uniforms[t].value,e.uniforms[t].value),!1}return!0}return!1}(e,a)}return!1}
2
2
  /*
3
3
  * Copyright (©) 2023. All rights reserved.
4
4
  * See the LICENSE.md file for details.
@@ -1,6 +1,6 @@
1
1
  import { BaseActor } from '../gameplay/index.js';
2
2
  import { Material } from "three";
3
- import { RgbaNode, Mat4Node } from '../shader-nodes/index.js';
3
+ import { RgbaNode, Mat4Node, BooleanNode } from '../shader-nodes/index.js';
4
4
  import { Type } from '../utils/type.js';
5
5
  export * from './parameter.js';
6
6
  export declare abstract class Shader {
@@ -19,6 +19,8 @@ export type NodeShaderOutput = {
19
19
  alphaTest?: number;
20
20
  transform?: Mat4Node;
21
21
  transparent?: boolean;
22
+ discard?: BooleanNode;
23
+ landscape?: boolean;
22
24
  };
23
25
  export declare abstract class NodeShader {
24
26
  build(): Material;
@@ -1,4 +1,4 @@
1
- import{NodeShaderMaterial as r}from"../shader-nodes/index.js";export*from"./parameter.js";export class Shader{}export class NodeShader{build(){return new r({transparent:!1,...this.output()})}}
1
+ import{NodeShaderMaterial as r,BooleanNode as s,attributeFloat as e}from"../shader-nodes/index.js";export*from"./parameter.js";export class Shader{}const a=e("hole").gt(.5);export class NodeShader{build(){const e=this.output();return new r({transparent:!1,...e,...!0===e.landscape?{discard:null!=e.discard&&e.discard instanceof s?e.discard.or(a):a}:{}})}}
2
2
  /*
3
3
  * Copyright (©) 2023. All rights reserved.
4
4
  * See the LICENSE.md file for details.
@@ -2,3 +2,4 @@ export interface Type<T> extends Function {
2
2
  new (...args: any[]): T;
3
3
  }
4
4
  export type AbstractType<T> = abstract new (...args: any[]) => T;
5
+ export declare function assertType<T, K extends T>(value: T, type: Type<K>): asserts value is K;
@@ -1,4 +1,4 @@
1
- export{};
1
+ export function assertType(e,n){if(!(e instanceof n))throw new Error(`Invalid type: expected instance of ${n.name}`)}
2
2
  /*
3
3
  * Copyright (©) 2023. All rights reserved.
4
4
  * See the LICENSE.md file for details.
@@ -0,0 +1,4 @@
1
+ export declare function registerWorker(builder: () => Worker): void;
2
+ export declare function hasWorkerBuilder(): boolean;
3
+ export declare function createWorker(): Worker;
4
+ export declare function initWorker(): void;
@@ -0,0 +1,5 @@
1
+ import{setupNavMeshWorker as r}from"../gameplay/ai/dynamic-tiled-navmesh.worker";let e;export function registerWorker(r){e=r}export function hasWorkerBuilder(){return null!=e}export function createWorker(){return e()}export function initWorker(){r()}
2
+ /*
3
+ * Copyright (©) 2023. All rights reserved.
4
+ * See the LICENSE.md file for details.
5
+ */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hology/core",
3
- "version": "0.0.64",
3
+ "version": "0.0.66",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -28,7 +28,8 @@
28
28
  "./shader-nodes": "./dist/shader-nodes/index.js",
29
29
  "./gameplay": "./dist/gameplay/index.js",
30
30
  "./gameplay/actors": "./dist/gameplay/actors/index.js",
31
- "./gameplay/input": "./dist/gameplay/input/index.js"
31
+ "./gameplay/input": "./dist/gameplay/input/index.js",
32
+ "./worker": "./dist/worker/index.js"
32
33
  },
33
34
  "types": "./dist/index.d.ts",
34
35
  "typesVersions": {
@@ -77,6 +78,9 @@
77
78
  ],
78
79
  "gameplay/input": [
79
80
  "./dist/gameplay/input/index.d.ts"
81
+ ],
82
+ "worker": [
83
+ "./dist/worker/index.d.ts"
80
84
  ]
81
85
  }
82
86
  },
@@ -96,7 +100,7 @@
96
100
  "three-csm": "^4.2.1",
97
101
  "three-mesh-bvh": "^0.7.5",
98
102
  "three-nebula": "^10.0.3",
99
- "three-shader-graph": "0.2.6",
103
+ "three-shader-graph": "0.2.8",
100
104
  "three-stdlib": "2.34.0",
101
105
  "ts-key-enum": "^2.0.12",
102
106
  "typedi": "^0.10.0"