@needle-tools/engine 4.1.0-experimental.12 → 4.1.0

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 (238) hide show
  1. package/CHANGELOG.md +72 -10
  2. package/README.md +28 -17
  3. package/components.needle.json +1 -1
  4. package/dist/gltf-progressive.js +220 -221
  5. package/dist/gltf-progressive.light.js +220 -221
  6. package/dist/gltf-progressive.light.min.js +6 -6
  7. package/dist/gltf-progressive.light.umd.cjs +7 -7
  8. package/dist/gltf-progressive.min.js +6 -6
  9. package/dist/gltf-progressive.umd.cjs +7 -7
  10. package/dist/needle-engine.bundle.js +8286 -7952
  11. package/dist/needle-engine.bundle.light.js +8239 -7905
  12. package/dist/needle-engine.bundle.light.min.js +270 -227
  13. package/dist/needle-engine.bundle.light.umd.cjs +181 -138
  14. package/dist/needle-engine.bundle.min.js +270 -227
  15. package/dist/needle-engine.bundle.umd.cjs +177 -134
  16. package/dist/needle-engine.d.ts +140 -0
  17. package/dist/needle-engine.js +597 -590
  18. package/dist/needle-engine.light.d.ts +140 -0
  19. package/dist/needle-engine.light.js +597 -590
  20. package/dist/needle-engine.light.min.js +1 -1
  21. package/dist/needle-engine.light.umd.cjs +1 -1
  22. package/dist/needle-engine.min.js +1 -1
  23. package/dist/needle-engine.umd.cjs +1 -1
  24. package/dist/postprocessing.js +1 -1
  25. package/dist/postprocessing.light.js +1 -1
  26. package/dist/postprocessing.light.min.js +1 -1
  27. package/dist/postprocessing.min.js +1 -1
  28. package/dist/three-examples.js +2809 -2450
  29. package/dist/three-examples.light.js +2809 -2450
  30. package/dist/three-examples.light.min.js +47 -15
  31. package/dist/three-examples.light.umd.cjs +47 -15
  32. package/dist/three-examples.min.js +47 -15
  33. package/dist/three-examples.umd.cjs +47 -15
  34. package/dist/three-mesh-ui.js +1 -1
  35. package/dist/three-mesh-ui.light.js +1 -1
  36. package/dist/three-mesh-ui.light.min.js +1 -1
  37. package/dist/three-mesh-ui.min.js +1 -1
  38. package/dist/three.js +577 -572
  39. package/dist/three.light.js +577 -572
  40. package/dist/three.light.min.js +170 -170
  41. package/dist/three.light.umd.cjs +170 -170
  42. package/dist/three.min.js +170 -170
  43. package/dist/three.umd.cjs +170 -170
  44. package/dist/vendor.js +1327 -1331
  45. package/dist/vendor.light.js +1327 -1331
  46. package/dist/vendor.light.min.js +33 -33
  47. package/dist/vendor.light.umd.cjs +33 -33
  48. package/dist/vendor.min.js +33 -33
  49. package/dist/vendor.umd.cjs +33 -33
  50. package/lib/engine/assets/index.js.map +1 -1
  51. package/lib/engine/engine.d.ts +4 -0
  52. package/lib/engine/engine.js +12 -0
  53. package/lib/engine/engine.js.map +1 -0
  54. package/lib/engine/engine_addressables.d.ts +6 -4
  55. package/lib/engine/engine_addressables.js +8 -1
  56. package/lib/engine/engine_addressables.js.map +1 -1
  57. package/lib/engine/engine_context.d.ts +3 -2
  58. package/lib/engine/engine_context.js +28 -4
  59. package/lib/engine/engine_context.js.map +1 -1
  60. package/lib/engine/engine_gameobject.d.ts +2 -12
  61. package/lib/engine/engine_gameobject.js +5 -15
  62. package/lib/engine/engine_gameobject.js.map +1 -1
  63. package/lib/engine/engine_gltf_builtin_components.js +5 -0
  64. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  65. package/lib/engine/engine_input.d.ts +19 -6
  66. package/lib/engine/engine_input.js +0 -10
  67. package/lib/engine/engine_input.js.map +1 -1
  68. package/lib/engine/engine_license.js +1 -1
  69. package/lib/engine/engine_license.js.map +1 -1
  70. package/lib/engine/engine_modules.d.ts +7 -0
  71. package/lib/engine/engine_modules.js +7 -0
  72. package/lib/engine/engine_modules.js.map +1 -1
  73. package/lib/engine/engine_networking_auto.js +6 -11
  74. package/lib/engine/engine_networking_auto.js.map +1 -1
  75. package/lib/engine/engine_networking_instantiate.d.ts +1 -1
  76. package/lib/engine/engine_physics_rapier.d.ts +6 -4
  77. package/lib/engine/engine_physics_rapier.js +38 -24
  78. package/lib/engine/engine_physics_rapier.js.map +1 -1
  79. package/lib/engine/engine_scenetools.js +6 -2
  80. package/lib/engine/engine_scenetools.js.map +1 -1
  81. package/lib/engine/engine_types.d.ts +9 -2
  82. package/lib/engine/engine_types.js +6 -0
  83. package/lib/engine/engine_types.js.map +1 -1
  84. package/lib/engine/engine_web_api.d.ts +12 -0
  85. package/lib/engine/engine_web_api.js +113 -0
  86. package/lib/engine/engine_web_api.js.map +1 -0
  87. package/lib/engine/export/gltf/Writers.js.map +1 -1
  88. package/lib/engine/export/gltf/index.js +11 -1
  89. package/lib/engine/export/gltf/index.js.map +1 -1
  90. package/lib/engine/export/utils.d.ts +2 -0
  91. package/lib/engine/export/utils.js +8 -0
  92. package/lib/engine/export/utils.js.map +1 -0
  93. package/lib/engine/extensions/NEEDLE_gameobject_data.js +1 -1
  94. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  95. package/lib/engine/js-extensions/Object3D.d.ts +5 -1
  96. package/lib/engine/js-extensions/Object3D.js.map +1 -1
  97. package/lib/engine/webcomponents/needle menu/needle-menu.js +8 -2
  98. package/lib/engine/webcomponents/needle menu/needle-menu.js.map +1 -1
  99. package/lib/engine/xr/NeedleXRSession.js +3 -0
  100. package/lib/engine/xr/NeedleXRSession.js.map +1 -1
  101. package/lib/engine-components/AvatarLoader.js.map +1 -1
  102. package/lib/engine-components/Camera.d.ts +7 -4
  103. package/lib/engine-components/Camera.js +13 -10
  104. package/lib/engine-components/Camera.js.map +1 -1
  105. package/lib/engine-components/Collider.js +4 -5
  106. package/lib/engine-components/Collider.js.map +1 -1
  107. package/lib/engine-components/Component.d.ts +4 -3
  108. package/lib/engine-components/Component.js +6 -7
  109. package/lib/engine-components/Component.js.map +1 -1
  110. package/lib/engine-components/ContactShadows.d.ts +1 -1
  111. package/lib/engine-components/ContactShadows.js +7 -0
  112. package/lib/engine-components/ContactShadows.js.map +1 -1
  113. package/lib/engine-components/FlyControls.d.ts +10 -0
  114. package/lib/engine-components/FlyControls.js +29 -0
  115. package/lib/engine-components/FlyControls.js.map +1 -0
  116. package/lib/engine-components/GroundProjection.d.ts +1 -1
  117. package/lib/engine-components/GroundProjection.js +39 -32
  118. package/lib/engine-components/GroundProjection.js.map +1 -1
  119. package/lib/engine-components/OrbitControls.js +9 -1
  120. package/lib/engine-components/OrbitControls.js.map +1 -1
  121. package/lib/engine-components/RigidBody.d.ts +1 -0
  122. package/lib/engine-components/RigidBody.js +11 -4
  123. package/lib/engine-components/RigidBody.js.map +1 -1
  124. package/lib/engine-components/SceneSwitcher.d.ts +1 -1
  125. package/lib/engine-components/SceneSwitcher.js +1 -1
  126. package/lib/engine-components/SceneSwitcher.js.map +1 -1
  127. package/lib/engine-components/SpatialTrigger.d.ts +2 -2
  128. package/lib/engine-components/SpatialTrigger.js +4 -4
  129. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  130. package/lib/engine-components/TransformGizmo.d.ts +7 -1
  131. package/lib/engine-components/TransformGizmo.js +39 -32
  132. package/lib/engine-components/TransformGizmo.js.map +1 -1
  133. package/lib/engine-components/VideoPlayer.js +0 -1
  134. package/lib/engine-components/VideoPlayer.js.map +1 -1
  135. package/lib/engine-components/export/gltf/GltfExport.js +23 -4
  136. package/lib/engine-components/export/gltf/GltfExport.js.map +1 -1
  137. package/lib/engine-components/export/usdz/ThreeUSDZExporter.d.ts +1 -1
  138. package/lib/engine-components/export/usdz/ThreeUSDZExporter.js +2 -2
  139. package/lib/engine-components/export/usdz/index.d.ts +1 -1
  140. package/lib/engine-components/export/usdz/index.js +1 -1
  141. package/lib/engine-components/export/usdz/index.js.map +1 -1
  142. package/lib/engine-components/particlesystem/ParticleSystem.d.ts +5 -6
  143. package/lib/engine-components/particlesystem/ParticleSystem.js +23 -9
  144. package/lib/engine-components/particlesystem/ParticleSystem.js.map +1 -1
  145. package/lib/engine-components/particlesystem/ParticleSystemModules.js +8 -2
  146. package/lib/engine-components/particlesystem/ParticleSystemModules.js.map +1 -1
  147. package/lib/engine-components/postprocessing/Effects/Antialiasing.js.map +1 -1
  148. package/lib/engine-components/postprocessing/Effects/BloomEffect.js.map +1 -1
  149. package/lib/engine-components/postprocessing/Effects/ChromaticAberration.js.map +1 -1
  150. package/lib/engine-components/postprocessing/Effects/ColorAdjustments.js.map +1 -1
  151. package/lib/engine-components/postprocessing/Effects/Pixelation.js.map +1 -1
  152. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.js.map +1 -1
  153. package/lib/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.js.map +1 -1
  154. package/lib/engine-components/postprocessing/Effects/Sharpening.d.ts +2 -0
  155. package/lib/engine-components/postprocessing/Effects/Sharpening.js +29 -20
  156. package/lib/engine-components/postprocessing/Effects/Sharpening.js.map +1 -1
  157. package/lib/engine-components/postprocessing/Effects/TiltShiftEffect.js.map +1 -1
  158. package/lib/engine-components/postprocessing/Effects/Tonemapping.js.map +1 -1
  159. package/lib/engine-components/postprocessing/Effects/Vignette.js.map +1 -1
  160. package/lib/engine-components/postprocessing/PostProcessingHandler.js +1 -1
  161. package/lib/engine-components/postprocessing/PostProcessingHandler.js.map +1 -1
  162. package/lib/engine-components/webxr/Avatar.js +3 -3
  163. package/lib/engine-components/webxr/Avatar.js.map +1 -1
  164. package/lib/engine-components/webxr/WebXR.js +22 -13
  165. package/lib/engine-components/webxr/WebXR.js.map +1 -1
  166. package/lib/engine-components/webxr/WebXRImageTracking.d.ts +4 -0
  167. package/lib/engine-components/webxr/WebXRImageTracking.js +14 -4
  168. package/lib/engine-components/webxr/WebXRImageTracking.js.map +1 -1
  169. package/lib/engine-components/webxr/WebXRRig.d.ts +11 -1
  170. package/lib/engine-components/webxr/WebXRRig.js +13 -1
  171. package/lib/engine-components/webxr/WebXRRig.js.map +1 -1
  172. package/lib/engine-components-experimental/networking/PlayerSync.d.ts +4 -1
  173. package/lib/engine-components-experimental/networking/PlayerSync.js +18 -30
  174. package/lib/engine-components-experimental/networking/PlayerSync.js.map +1 -1
  175. package/lib/needle-engine.js +5 -5
  176. package/lib/needle-engine.js.map +1 -1
  177. package/package.json +14 -8
  178. package/plugins/common/config.cjs +22 -6
  179. package/plugins/common/config.js +27 -11
  180. package/plugins/next/next.js +47 -4
  181. package/plugins/vite/transform.js +3 -3
  182. package/src/engine/assets/index.ts +1 -0
  183. package/src/engine/codegen/register_types.ts +2 -2
  184. package/src/engine/engine_addressables.ts +19 -12
  185. package/src/engine/engine_context.ts +33 -8
  186. package/src/engine/engine_gameobject.ts +12 -16
  187. package/src/engine/engine_gltf_builtin_components.ts +7 -1
  188. package/src/engine/engine_input.ts +12 -5
  189. package/src/engine/engine_license.ts +2 -1
  190. package/src/engine/engine_modules.ts +7 -0
  191. package/src/engine/engine_networking_auto.ts +7 -22
  192. package/src/engine/engine_networking_instantiate.ts +1 -1
  193. package/src/engine/engine_physics_rapier.ts +48 -26
  194. package/src/engine/engine_scenetools.ts +6 -2
  195. package/src/engine/engine_types.ts +10 -2
  196. package/src/engine/export/gltf/Writers.ts +0 -1
  197. package/src/engine/export/gltf/index.ts +13 -3
  198. package/src/engine/export/index.ts +1 -1
  199. package/src/engine/export/utils.ts +10 -0
  200. package/src/engine/extensions/NEEDLE_gameobject_data.ts +1 -2
  201. package/src/engine/js-extensions/Object3D.ts +6 -1
  202. package/src/engine/webcomponents/needle menu/needle-menu.ts +16 -10
  203. package/src/engine/xr/NeedleXRSession.ts +4 -1
  204. package/src/engine-components/AvatarLoader.ts +1 -1
  205. package/src/engine-components/Camera.ts +14 -11
  206. package/src/engine-components/Collider.ts +4 -4
  207. package/src/engine-components/Component.ts +13 -7
  208. package/src/engine-components/ContactShadows.ts +11 -2
  209. package/src/engine-components/GroundProjection.ts +46 -38
  210. package/src/engine-components/OrbitControls.ts +9 -1
  211. package/src/engine-components/RigidBody.ts +13 -5
  212. package/src/engine-components/SceneSwitcher.ts +1 -1
  213. package/src/engine-components/SpatialTrigger.ts +6 -6
  214. package/src/engine-components/TransformGizmo.ts +41 -33
  215. package/src/engine-components/VideoPlayer.ts +0 -1
  216. package/src/engine-components/export/gltf/GltfExport.ts +26 -6
  217. package/src/engine-components/export/usdz/ThreeUSDZExporter.ts +2 -2
  218. package/src/engine-components/export/usdz/index.ts +1 -1
  219. package/src/engine-components/particlesystem/ParticleSystem.ts +26 -10
  220. package/src/engine-components/particlesystem/ParticleSystemModules.ts +10 -3
  221. package/src/engine-components/postprocessing/Effects/Antialiasing.ts +0 -1
  222. package/src/engine-components/postprocessing/Effects/BloomEffect.ts +1 -1
  223. package/src/engine-components/postprocessing/Effects/ChromaticAberration.ts +1 -1
  224. package/src/engine-components/postprocessing/Effects/ColorAdjustments.ts +1 -1
  225. package/src/engine-components/postprocessing/Effects/Pixelation.ts +1 -1
  226. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusion.ts +1 -1
  227. package/src/engine-components/postprocessing/Effects/ScreenspaceAmbientOcclusionN8.ts +1 -1
  228. package/src/engine-components/postprocessing/Effects/Sharpening.ts +32 -21
  229. package/src/engine-components/postprocessing/Effects/TiltShiftEffect.ts +0 -1
  230. package/src/engine-components/postprocessing/Effects/Tonemapping.ts +1 -1
  231. package/src/engine-components/postprocessing/Effects/Vignette.ts +1 -1
  232. package/src/engine-components/postprocessing/PostProcessingHandler.ts +2 -3
  233. package/src/engine-components/webxr/Avatar.ts +3 -3
  234. package/src/engine-components/webxr/WebXR.ts +23 -14
  235. package/src/engine-components/webxr/WebXRImageTracking.ts +23 -8
  236. package/src/engine-components/webxr/WebXRRig.ts +15 -2
  237. package/src/engine-components-experimental/networking/PlayerSync.ts +18 -37
  238. package/src/needle-engine.ts +5 -5
@@ -1,4 +1,4 @@
1
- import { AxesHelper, BackSide, Blending, BufferGeometry, FrontSide, LinearSRGBColorSpace, Material, Matrix4, Mesh, NormalBlending, Object3D, PlaneGeometry, Quaternion, SpriteMaterial, Texture, Vector3, Vector4 } from "three";
1
+ import { AxesHelper, BackSide, Blending, BufferGeometry, FrontSide, LinearSRGBColorSpace, Material, Matrix4, Mesh, MeshBasicMaterial, MeshStandardMaterial, NormalBlending, Object3D, PlaneGeometry, Quaternion, SpriteMaterial, Texture, Vector3, Vector4 } from "three";
2
2
  import type { BatchedRenderer, Behavior, BurstParameters, EmissionState, EmitterShape, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, GeneratorMemory, Particle, ParticleSystemParameters, RecordState, TrailSettings, ValueGenerator } from "three.quarks";
3
3
  import { BatchedParticleRenderer, ConstantColor, ConstantValue, ParticleSystem as _ParticleSystem, RenderMode, TrailParticle, Vector3 as QVector3, Vector4 as QVector4 } from "three.quarks";
4
4
 
@@ -39,10 +39,10 @@ export class ParticleSystemRenderer extends Behaviour {
39
39
  renderMode?: ParticleSystemRenderMode;
40
40
 
41
41
  @serializable(Material)
42
- particleMaterial?: SpriteMaterial;
42
+ particleMaterial?: SpriteMaterial | MeshBasicMaterial;
43
43
 
44
44
  @serializable(Material)
45
- trailMaterial?: SpriteMaterial;
45
+ trailMaterial?: SpriteMaterial | MeshBasicMaterial;
46
46
 
47
47
  // @serializable(Mesh)
48
48
  particleMesh?: Mesh | string;
@@ -68,6 +68,7 @@ export class ParticleSystemRenderer extends Behaviour {
68
68
  // showBalloonWarning(msg);
69
69
  }
70
70
  }
71
+
71
72
  }
72
73
 
73
74
  get transparent(): boolean {
@@ -80,6 +81,24 @@ export class ParticleSystemRenderer extends Behaviour {
80
81
  let material = (trailEnabled === true && this.trailMaterial) ? this.trailMaterial : this.particleMaterial;
81
82
 
82
83
  if (material) {
84
+
85
+ if (material.type === "MeshStandardMaterial") {
86
+ if (debug) console.debug("ParticleSystemRenderer.getMaterial: MeshStandardMaterial detected, converting to MeshBasicMaterial. See https://github.com/Alchemist0823/three.quarks/issues/101");
87
+ if ("map" in material && material.map) {
88
+ material.map.colorSpace = LinearSRGBColorSpace;
89
+ material.map.premultiplyAlpha = false;
90
+ }
91
+ const newMaterial = new MeshBasicMaterial({ map: material.map });
92
+ if (trailEnabled) this.trailMaterial = newMaterial;
93
+ else this.particleMaterial = newMaterial;
94
+ }
95
+
96
+
97
+ if (material.map) {
98
+ material.map.colorSpace = LinearSRGBColorSpace;
99
+ material.map.premultiplyAlpha = false;
100
+ }
101
+
83
102
  if (trailEnabled) {
84
103
  // the particle material for trails must be DoubleSide or BackSide (since otherwise the trail is invisible)
85
104
  if (material.side === FrontSide) {
@@ -896,7 +915,7 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
896
915
  if (particleSystemBehaviour instanceof ParticleSystemBaseBehaviour) {
897
916
  particleSystemBehaviour.system = this;
898
917
  }
899
- if (isDevEnvironment()) console.log("add behaviour", particleSystemBehaviour);
918
+ if (isDevEnvironment() || debug) console.debug("Add custom ParticleSystem Behaviour", particleSystemBehaviour);
900
919
  this._particleSystem.addBehavior(particleSystemBehaviour);
901
920
  return true;
902
921
  }
@@ -908,6 +927,7 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
908
927
  const behaviours = this._particleSystem.behaviors;
909
928
  const index = behaviours.indexOf(particleSystemBehaviour);
910
929
  if (index !== -1) {
930
+ if (isDevEnvironment() || debug) console.debug("Remove custom ParticleSystem Behaviour", index, particleSystemBehaviour);
911
931
  behaviours.splice(index, 1);
912
932
  return true;
913
933
  }
@@ -1145,13 +1165,9 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
1145
1165
  }
1146
1166
  }
1147
1167
 
1148
- private lastMaterialVersion: number = -1;
1168
+ // private lastMaterialVersion: number = -1;
1149
1169
  private onUpdate() {
1150
- const mat = this.renderer.getMaterial(this.trails.enabled);
1151
- if (mat && mat.version != this.lastMaterialVersion && this._particleSystem) {
1152
- this.lastMaterialVersion = mat.version;
1153
- this._particleSystem.texture = this._interface.texture;
1154
- }
1170
+
1155
1171
 
1156
1172
  if (this._bursts) {
1157
1173
  this.emission.bursts = this._bursts;
@@ -1,6 +1,6 @@
1
1
  import { createNoise4D, type NoiseFunction4D } from 'simplex-noise';
2
2
  import { BufferGeometry, Color, Euler, Matrix4, Mesh, Object3D, Quaternion, Triangle, Vector2, Vector3, Vector4 } from "three";
3
- import type { EmitterShape, IParticleSystem as QParticleSystem,Particle, ShapeJSON, Vector3 as QVector3, Vector4 as QVector4 } from "three.quarks";
3
+ import type { EmitterShape, IParticleSystem as QParticleSystem, Particle, ShapeJSON, Vector3 as QVector3, Vector4 as QVector4 } from "three.quarks";
4
4
 
5
5
  import { isDevEnvironment } from '../../engine/debug/index.js';
6
6
  import { Gizmos } from "../../engine/engine_gizmos.js";
@@ -360,9 +360,16 @@ export class MinMaxGradient {
360
360
  this.gradientMax.evaluate(t01, MinMaxGradient._temp2);
361
361
  return MinMaxGradient._temp.lerp(MinMaxGradient._temp2, t);
362
362
 
363
+ case ParticleSystemGradientMode.RandomColor:
364
+ case "RandomColor":
365
+ const random_t = Math.random();
366
+ this.gradientMin.evaluate(t01, MinMaxGradient._temp);
367
+ this.gradientMax.evaluate(t01, MinMaxGradient._temp2);
368
+ return MinMaxGradient._temp.lerp(MinMaxGradient._temp2, random_t);
369
+
363
370
  }
364
371
  // console.warn("Not implemented", ParticleSystemGradientMode[this.mode]);
365
- MinMaxGradient._temp.set(0xff00ff)
372
+ MinMaxGradient._temp.set(0xffffff)
366
373
  MinMaxGradient._temp.alpha = 1;
367
374
  return MinMaxGradient._temp;
368
375
  }
@@ -685,7 +692,7 @@ export class ShapeModule implements EmitterShape {
685
692
  }
686
693
 
687
694
  update(_system: QParticleSystem, _delta: number): void {
688
- throw new Error('Method not implemented: use onUpdate');
695
+ /* this is called by quarks */
689
696
  }
690
697
 
691
698
  onUpdate(system: IParticleSystem, _context: Context, simulationSpace: ParticleSystemSimulationSpace, obj: Object3D) {
@@ -1,5 +1,4 @@
1
1
  import { MODULES } from "../../../engine/engine_modules.js";
2
-
3
2
  import { serializable } from "../../../engine/engine_serialization.js";
4
3
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
5
4
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,7 +1,7 @@
1
1
  import type { BloomEffect as _BloomEffect } from "postprocessing";
2
2
  import { MathUtils } from "three";
3
- import { MODULES } from "../../../engine/engine_modules.js";
4
3
 
4
+ import { MODULES } from "../../../engine/engine_modules.js";
5
5
  import { serializable } from "../../../engine/engine_serialization.js";
6
6
  import { PostProcessingEffect } from "../PostProcessingEffect.js";
7
7
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,6 +1,6 @@
1
1
  import { Vector2 } from "three";
2
- import { MODULES } from "../../../engine/engine_modules.js";
3
2
 
3
+ import { MODULES } from "../../../engine/engine_modules.js";
4
4
  import { serializable } from "../../../engine/engine_serialization.js";
5
5
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
6
6
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,6 +1,6 @@
1
1
  import { NoToneMapping } from "three";
2
- import { MODULES } from "../../../engine/engine_modules.js";
3
2
 
3
+ import { MODULES } from "../../../engine/engine_modules.js";
4
4
  import { serializable } from "../../../engine/engine_serialization.js";
5
5
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
6
6
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,6 +1,6 @@
1
1
  import type { PixelationEffect as PixelationEffectPP } from "postprocessing";
2
- import { MODULES } from "../../../engine/engine_modules.js";
3
2
 
3
+ import { MODULES } from "../../../engine/engine_modules.js";
4
4
  import { serializable } from "../../../engine/engine_serialization.js";
5
5
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
6
6
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,7 +1,7 @@
1
1
  import type { DepthDownsamplingPass, NormalPass, SSAOEffect } from "postprocessing";
2
2
  import { Color, PerspectiveCamera } from "three";
3
- import { MODULES } from "../../../engine/engine_modules.js";
4
3
 
4
+ import { MODULES } from "../../../engine/engine_modules.js";
5
5
  import { serializable } from "../../../engine/engine_serialization.js";
6
6
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
7
7
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,7 +1,7 @@
1
1
  import type { N8AOPostPass } from "n8ao";
2
2
  import { Color, PerspectiveCamera } from "three";
3
- import { MODULES } from "../../../engine/engine_modules.js";
4
3
 
4
+ import { MODULES } from "../../../engine/engine_modules.js";
5
5
  import { serializable } from "../../../engine/engine_serialization.js";
6
6
  import { validate } from "../../../engine/engine_util_decorator.js";
7
7
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
@@ -1,4 +1,5 @@
1
1
  import { Uniform } from "three";
2
+
2
3
  import { MODULES } from "../../../engine/engine_modules.js";
3
4
  import { serializable } from "../../../engine/engine_serialization.js";
4
5
  import { PostProcessingEffect } from "../PostProcessingEffect.js";
@@ -23,30 +24,39 @@ export class SharpeningEffect extends PostProcessingEffect {
23
24
  private _effect?: any;
24
25
 
25
26
  onCreateEffect() {
27
+ this._effect ??= new (createSharpeningEffectType())();
26
28
  return this.effect;
27
29
  }
28
30
 
29
31
  private get effect() {
30
- this._effect ??= new (createSharpeningEffectType())();
31
- // return null;
32
32
  return this._effect;
33
33
  }
34
34
 
35
35
  @serializable()
36
36
  set amount(value: number) {
37
- this.effect.uniforms.get("amount")!.value = value;
37
+ this._amount = value;
38
+ if (this._effect)
39
+ this._effect.uniforms.get("amount")!.value = value;
38
40
  }
39
41
  get amount() {
40
- return this.effect.uniforms.get("amount")!.value;
42
+ if (this._effect)
43
+ return this._effect.uniforms.get("amount")!.value;
44
+ return this._amount;
41
45
  }
46
+ private _amount = 1;
42
47
 
43
48
  @serializable()
44
49
  set radius(value: number) {
45
- this.effect.uniforms.get("radius")!.value = value;
50
+ this._radius = value;
51
+ if (this._effect)
52
+ this._effect.uniforms.get("radius")!.value = value;
46
53
  }
47
54
  get radius() {
48
- return this.effect.uniforms.get("radius")!.value;
55
+ if (this._effect)
56
+ return this._effect.uniforms.get("radius")!.value;
57
+ return this._radius;
49
58
  }
59
+ private _radius = 1;
50
60
 
51
61
  // @serializable()
52
62
  // set threshold(value: number) {
@@ -62,21 +72,6 @@ export class SharpeningEffect extends PostProcessingEffect {
62
72
 
63
73
  function createSharpeningEffectType() {
64
74
 
65
- class _SharpeningEffect extends MODULES.POSTPROCESSING.MODULE!.Effect {
66
- constructor() {
67
- super("Sharpening", frag, {
68
- vertexShader: vert,
69
- blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.NORMAL,
70
- uniforms: new Map<string, Uniform<any>>([
71
- ["amount", new Uniform(1)],
72
- ["radius", new Uniform(1)],
73
- // ["threshold", new Uniform(0)],
74
- ]),
75
- });
76
- }
77
- }
78
- return _SharpeningEffect;
79
-
80
75
  const vert = `
81
76
  void mainSupport() {
82
77
  vUv = uv;
@@ -125,4 +120,20 @@ function createSharpeningEffectType() {
125
120
 
126
121
  `
127
122
 
123
+ class _SharpeningEffect extends MODULES.POSTPROCESSING.MODULE!.Effect {
124
+ constructor() {
125
+ super("Sharpening", frag, {
126
+ vertexShader: vert,
127
+ blendFunction: MODULES.POSTPROCESSING.MODULE.BlendFunction.NORMAL,
128
+ uniforms: new Map<string, Uniform<any>>([
129
+ ["amount", new Uniform(1)],
130
+ ["radius", new Uniform(1)],
131
+ // ["threshold", new Uniform(0)],
132
+ ]),
133
+ });
134
+ }
135
+ }
136
+ return _SharpeningEffect;
137
+
138
+
128
139
  }
@@ -1,5 +1,4 @@
1
1
  import { MODULES } from "../../../engine/engine_modules.js";
2
-
3
2
  import { serializable } from "../../../engine/engine_serialization.js";
4
3
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
5
4
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,7 +1,7 @@
1
1
  import type { ToneMappingEffect as _TonemappingEffect, ToneMappingMode } from "postprocessing";
2
2
  import { ACESFilmicToneMapping, AgXToneMapping, LinearToneMapping, NeutralToneMapping, NoToneMapping, ReinhardToneMapping } from "three";
3
- import { MODULES } from "../../../engine/engine_modules.js";
4
3
 
4
+ import { MODULES } from "../../../engine/engine_modules.js";
5
5
  import { serializable } from "../../../engine/engine_serialization.js";
6
6
  import { getParam } from "../../../engine/engine_utils.js";
7
7
  import { EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
@@ -1,6 +1,6 @@
1
1
  import type { VignetteEffect } from "postprocessing";
2
- import { MODULES } from "../../../engine/engine_modules.js";
3
2
 
3
+ import { MODULES } from "../../../engine/engine_modules.js";
4
4
  import { serializable } from "../../../engine/engine_serialization.js";
5
5
  import { type EffectProviderResult, PostProcessingEffect } from "../PostProcessingEffect.js";
6
6
  import { VolumeParameter } from "../VolumeParameter.js";
@@ -1,14 +1,13 @@
1
1
  import type { Effect, EffectComposer, Pass, ToneMappingEffect as _TonemappingEffect } from "postprocessing";
2
-
3
2
  import { HalfFloatType, NoToneMapping } from "three";
4
3
 
5
4
  import { showBalloonWarning } from "../../engine/debug/index.js";
5
+ // import { internal_SetSharpeningEffectModule } from "./Effects/Sharpening.js";
6
+ import { MODULES } from "../../engine/engine_modules.js";
6
7
  import { Context } from "../../engine/engine_setup.js";
7
8
  import type { Constructor } from "../../engine/engine_types.js";
8
9
  import { DeviceUtilities, getParam } from "../../engine/engine_utils.js";
9
10
  import { Camera } from "../Camera.js";
10
- // import { internal_SetSharpeningEffectModule } from "./Effects/Sharpening.js";
11
- import { MODULES } from "../../engine/engine_modules.js";
12
11
  import { PostProcessingEffect, PostProcessingEffectContext } from "./PostProcessingEffect.js";
13
12
 
14
13
  declare const NEEDLE_USE_POSTPROCESSING: boolean;
@@ -101,7 +101,7 @@ export class Avatar extends Behaviour {
101
101
  headObj.quaternion.x *= -1;
102
102
 
103
103
  // HACK: XRFlag limitation workaround to make sure first person user head is never rendered
104
- if (this.context.time.frameCount % 10 === 0) {
104
+ if (this.context.time.frameCount % 10 === 0 && this.head.asset) {
105
105
  const xrflags = GameObject.getComponentsInChildren(this.head.asset, XRFlag);
106
106
  for (const flag of xrflags) {
107
107
  flag.enabled = false;
@@ -242,9 +242,9 @@ export class Avatar extends Behaviour {
242
242
  await this.loadAvatarObjects(this.head, this.leftHand, this.rightHand);
243
243
 
244
244
  this._leftHandMeshes = [];
245
- this.leftHand.asset.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._leftHandMeshes!.push(obj); });
245
+ this.leftHand.asset?.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._leftHandMeshes!.push(obj as Mesh); });
246
246
  this._rightHandMeshes = [];
247
- this.rightHand.asset.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._rightHandMeshes!.push(obj); });
247
+ this.rightHand.asset?.traverse((obj) => { if ((obj as Mesh)?.isMesh) this._rightHandMeshes!.push(obj as Mesh); });
248
248
 
249
249
  if (PlayerState.isLocalPlayer(this.gameObject)) {
250
250
  this._syncTransforms = GameObject.getComponentsInChildren(this.gameObject, SyncedTransform);
@@ -227,23 +227,32 @@ export class WebXR extends Behaviour {
227
227
  XRState.Global.Set(isVR ? XRStateFlag.VR : XRStateFlag.AR);
228
228
 
229
229
  // Handle AR session root
230
- if (this.usePlacementReticle && args.xr.isAR) {
230
+ if (args.xr.isAR) {
231
231
  let sessionroot = GameObject.findObjectOfType(WebARSessionRoot);
232
+ // Only create a WebARSessionRoot if none is in the scene already
232
233
  if (!sessionroot) {
233
- const implicitSessionRoot = new Object3D();
234
- for (const ch of this.context.scene.children)
235
- implicitSessionRoot.add(ch);
236
- this.context.scene.add(implicitSessionRoot);
237
- sessionroot = GameObject.addComponent(implicitSessionRoot, WebARSessionRoot)!;
238
- this._createdComponentsInSession.push(sessionroot);
234
+ if (this.usePlacementReticle) {
235
+ const implicitSessionRoot = new Object3D();
236
+ for (const ch of this.context.scene.children)
237
+ implicitSessionRoot.add(ch);
238
+ this.context.scene.add(implicitSessionRoot);
239
+ sessionroot = GameObject.addComponent(implicitSessionRoot, WebARSessionRoot)!;
240
+ this._createdComponentsInSession.push(sessionroot);
241
+ }
242
+ else if (debug || isDevEnvironment()) {
243
+ console.warn("WebXR: No WebARSessionRoot found in scene and usePlacementReticle is disabled in WebXR component.")
244
+ }
245
+ }
246
+
247
+ if (sessionroot) {
248
+ // sessionroot.enabled = this.usePlacementReticle; // < not sure if we want to disable the session root when placement reticle if OFF...
249
+ sessionroot.customReticle = this.customARPlacementReticle;
250
+ sessionroot.arScale = this.arScale;
251
+ sessionroot.arTouchTransform = this.usePlacementAdjustment;
252
+ sessionroot.autoPlace = this.autoPlace;
253
+ sessionroot.autoCenter = this.autoCenter;
254
+ sessionroot.useXRAnchor = this.useXRAnchor;
239
255
  }
240
-
241
- sessionroot.customReticle = this.customARPlacementReticle;
242
- sessionroot.arScale = this.arScale;
243
- sessionroot.arTouchTransform = this.usePlacementAdjustment;
244
- sessionroot.autoPlace = this.autoPlace;
245
- sessionroot.autoCenter = this.autoCenter;
246
- sessionroot.useXRAnchor = this.useXRAnchor;
247
256
  }
248
257
 
249
258
  // handle VR controls
@@ -4,7 +4,8 @@ import { Object3DEventMap } from "three";
4
4
  import { isDevEnvironment, showBalloonWarning } from "../../engine/debug/index.js";
5
5
  import { AssetReference } from "../../engine/engine_addressables.js";
6
6
  import { serializable } from "../../engine/engine_serialization.js";
7
- import { CircularBuffer, getParam } from "../../engine/engine_utils.js";
7
+ import { IGameObject } from "../../engine/engine_types.js";
8
+ import { CircularBuffer, DeviceUtilities, getParam } from "../../engine/engine_utils.js";
8
9
  import { type NeedleXREventArgs, NeedleXRSession } from "../../engine/xr/api.js";
9
10
  import { IUSDExporterExtension } from "../../engine-components/export/usdz/Extension.js";
10
11
  import { imageToCanvas, USDObject, USDWriter, USDZExporterContext } from "../../engine-components/export/usdz/ThreeUSDZExporter.js";
@@ -236,11 +237,17 @@ export class WebXRImageTracking extends Behaviour {
236
237
  trackedImages?: WebXRImageTrackingModel[];
237
238
 
238
239
  /** Applies smoothing based on detected jitter to the tracked image. */
240
+ @serializable()
239
241
  smooth: boolean = true;
240
242
 
241
243
  private readonly trackedImageIndexMap: Map<number, WebXRImageTrackingModel> = new Map();
242
244
  private static _imageElements: Map<string, ImageBitmap | null> = new Map();
243
245
 
246
+ /** @returns true if image tracking is supported on this device. This may return false at runtime if the user's browser did not enable webxr incubations */
247
+ get supported() { return this._supported; }
248
+
249
+ private _supported: boolean = true;
250
+
244
251
  awake(): void {
245
252
  if (debug) console.log(this)
246
253
  if (!this.trackedImages) return;
@@ -324,6 +331,11 @@ export class WebXRImageTracking extends Behaviour {
324
331
  };
325
332
 
326
333
  onLeaveXR(_args: NeedleXREventArgs): void {
334
+
335
+ if(!this.supported && DeviceUtilities.isAndroidDevice()) {
336
+ showBalloonWarning(this.webXRIncubationsWarning);
337
+ }
338
+
327
339
  if (this.trackedImages) {
328
340
  for (const trackedImage of this.trackedImages) {
329
341
  if (trackedImage.object?.asset) {
@@ -344,9 +356,12 @@ export class WebXRImageTracking extends Behaviour {
344
356
  }
345
357
  }
346
358
 
347
- private readonly imageToObjectMap = new Map<WebXRImageTrackingModel, { object: GameObject | null, frames: number, lastTrackingTime: number }>();
359
+ private readonly imageToObjectMap = new Map<WebXRImageTrackingModel, { object: Object3D | null, frames: number, lastTrackingTime: number }>();
348
360
  private readonly currentImages: WebXRTrackedImage[] = [];
349
361
 
362
+
363
+ private readonly webXRIncubationsWarning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a target=\"_blank\" href=\"#\" onclick=\"() => console.log('I')\">chrome://flags/#webxr-incubations</a> flag.";
364
+
350
365
  onUpdateXR(args: NeedleXREventArgs): void {
351
366
  this.currentImages.length = 0;
352
367
 
@@ -354,12 +369,12 @@ export class WebXRImageTracking extends Behaviour {
354
369
  if (!frame) return;
355
370
 
356
371
  if (!("getImageTrackingResults" in frame)) {
357
- const warning = "Image tracking is currently not supported on this device. On Chrome for Android, you can enable the <a target=\"_blank\" href=\"#\" onclick=\"() => console.log('I')\">chrome://flags/#webxr-incubations</a> flag.";
358
372
  if (!this["didPrintWarning"]) {
359
373
  this["didPrintWarning"] = true;
360
- console.log(warning);
374
+ console.log(this.webXRIncubationsWarning);
361
375
  }
362
- showBalloonWarning(warning);
376
+ this._supported = false;
377
+ showBalloonWarning(this.webXRIncubationsWarning);
363
378
  return;
364
379
  }
365
380
  // Check if enabled features (if available) contains image tracking - if it's not available this statement should not catch
@@ -442,7 +457,7 @@ export class WebXRImageTracking extends Behaviour {
442
457
  trackedData = { object: null, frames: 0, lastTrackingTime: Date.now() };
443
458
  this.imageToObjectMap.set(model, trackedData);
444
459
 
445
- model.object.loadAssetAsync().then((asset: GameObject | null) => {
460
+ model.object.loadAssetAsync().then((asset: Object3D | null) => {
446
461
  if (model.createObjectInstance && asset) {
447
462
  asset = GameObject.instantiate(asset);
448
463
  }
@@ -461,7 +476,7 @@ export class WebXRImageTracking extends Behaviour {
461
476
  if (xr.rig) {
462
477
  xr.rig.gameObject.add(asset);
463
478
  image.applyToObject(asset);
464
- if (!asset.activeSelf)
479
+ if (!(asset as IGameObject).activeSelf)
465
480
  GameObject.setActive(asset, true);
466
481
  // InstancingUtil.markDirty(asset);
467
482
  }
@@ -489,7 +504,7 @@ export class WebXRImageTracking extends Behaviour {
489
504
  xr.rig.gameObject.add(trackedData.object);
490
505
 
491
506
  image.applyToObject(trackedData.object, this.smooth ? this.context.time.deltaTimeUnscaled * 3 : undefined);
492
- if (!trackedData.object.activeSelf) {
507
+ if (!(trackedData.object as IGameObject).activeSelf) {
493
508
  GameObject.setActive(trackedData.object, true);
494
509
  }
495
510
  // InstancingUtil.markDirty(trackedData.object);
@@ -23,11 +23,21 @@ export class XRRig extends Behaviour implements IXRRig {
23
23
 
24
24
  get isActive() { return this.activeAndEnabled && this.gameObject.visible; }
25
25
 
26
- /** Sets this rig to be the active XR rig (needs to be called during an active XR session) */
26
+ /**
27
+ * Sets this rig to be the active XR rig (needs to be called during an active XR session)
28
+ * Note that this might modify the priority of this rig to be the highest.
29
+ */
27
30
  setAsActiveXRRig() {
28
31
  NeedleXRSession.active?.setRigActive(this);
29
32
  }
33
+ /**
34
+ * Sets the priority of the rig.
35
+ */
36
+ setPriority(value: number) {
37
+ this.priority = value;
38
+ }
30
39
 
40
+ /** @internal */
31
41
  awake(): void {
32
42
  if (debug) {
33
43
  const gizmoObj = new Object3D() as IGameObject;
@@ -51,15 +61,18 @@ export class XRRig extends Behaviour implements IXRRig {
51
61
 
52
62
  private _startScale?: Vector3;
53
63
 
64
+ /** @internal */
54
65
  onEnterXR(args: NeedleXREventArgs): void {
55
66
  this._startScale = this.gameObject.scale.clone();
56
67
  args.xr.addRig(this);
57
- if(debug) console.log("WebXR: add Rig", this.name, this.priority);
68
+ if (debug) console.log("WebXR: add Rig", this.name, this.priority);
58
69
  }
70
+ /** @internal */
59
71
  onLeaveXR(args: NeedleXREventArgs): void {
60
72
  args.xr.removeRig(this);
61
73
  if (this._startScale && this.gameObject)
62
74
  this.gameObject.scale.copy(this._startScale);
63
75
  }
64
76
 
77
+
65
78
  }
@@ -20,7 +20,7 @@ declare type PlayerSyncWithAsset = PlayerSync & Required<Pick<PlayerSync, "asset
20
20
  * @category Networking
21
21
  */
22
22
  export class PlayerSync extends Behaviour {
23
-
23
+
24
24
  /**
25
25
  * This API is experimental and may change or be removed in the future.
26
26
  * Create a PlayerSync instance at runtime from a given URL
@@ -36,7 +36,7 @@ export class PlayerSync extends Behaviour {
36
36
  const assetReference = AssetReference.getOrCreateFromUrl(url);
37
37
  if (!assetReference.asset) {
38
38
  const i = await assetReference.loadAssetAsync();
39
- GameObject.getOrAddComponent(i, PlayerState);
39
+ if(i) GameObject.getOrAddComponent(i, PlayerState);
40
40
  }
41
41
  const ps = new PlayerSync();
42
42
  ps._internalInit(init);
@@ -103,6 +103,7 @@ export class PlayerSync extends Behaviour {
103
103
  const instance = await this._localInstance;
104
104
  if (instance) {
105
105
  const pl = GameObject.getComponentsInChildren(instance, PlayerState);
106
+ if (debug) console.log(`PlayerSync.createInstance: found ${pl?.length} PlayerState components. Owner: ${this.context.connection.connectionId}`);
106
107
  if (pl?.length) {
107
108
  for (const state of pl)
108
109
  state.owner = this.context.connection.connectionId!;
@@ -226,7 +227,7 @@ export class PlayerState extends Behaviour {
226
227
  }
227
228
 
228
229
  private onOwnerChange(newOwner: string, oldOwner: string) {
229
- if (debug) console.log("PlayerSync.onOwnerChange", this, "newOwner", newOwner, "oldOwner", oldOwner);
230
+ if (debug) console.log(`PlayerSync.onOwnerChange: ${oldOwner} ${newOwner} (me: ${this.context.connection.connectionId})`);
230
231
 
231
232
  // Remove from local owner array if it was local before
232
233
  const index = PlayerState._local.indexOf(this);
@@ -259,6 +260,7 @@ export class PlayerState extends Behaviour {
259
260
  PlayerState.dispatchEvent(PlayerStateEvent.OwnerChanged, evt);
260
261
  }
261
262
 
263
+ /** @internal */
262
264
  awake(): void {
263
265
  PlayerState.all.push(this);
264
266
  if (debug) console.log("Registered new PlayerState", this.guid, PlayerState.all.length - 1, PlayerState.all)
@@ -266,31 +268,10 @@ export class PlayerState extends Behaviour {
266
268
  this.context.connection.beginListen(RoomEvents.UserLeftRoom, this.onUserLeftRoom);
267
269
  }
268
270
 
269
- private onUserLeftRoom = (model: { userId: string }) => {
270
- if (model.userId === this.owner) {
271
- if (debug)
272
- console.log("PLAYERSYNC LEFT", this.owner)
273
- this.doDestroy();
274
- return;
275
- }
276
- }
277
-
278
-
271
+ /** @internal */
279
272
  async start() {
280
273
  if (debug) console.log("PLAYERSTATE.START, owner: " + this.owner, this.context.connection.usersInRoom([]))
281
274
 
282
- // generate number from owner
283
- // if (this.owner) {
284
- // // string to number
285
- // let num = 0;
286
- // for (let i = 0; i < this.owner.length; i++) {
287
- // num += this.owner.charCodeAt(i);
288
- // }
289
- // console.log(num)
290
- // num = num / 1000
291
- // this.gameObject.position.y = num;
292
- // }
293
-
294
275
  // If a player is spawned but not in the room anymore we want to destroy it
295
276
  // this might happen in a case where all users get disconnected at once and the server
296
277
  // still has the syncInstantiate messages that are sent to all clients
@@ -314,29 +295,20 @@ export class PlayerState extends Behaviour {
314
295
  }
315
296
  else if (debug) console.warn("PlayerState.start → owner is still undefined but dontDestroy is set to true", this.name);
316
297
  }
317
- else if(debug) console.log("PlayerState.start → owner is assigned", this.owner);
298
+ else if (debug) console.log("PlayerState.start → owner is assigned", this.owner);
318
299
  }, 2000);
319
300
  }
320
301
  }
321
302
 
322
- // onEnable() {
323
- // if (debug) this.startCoroutine(this.debugRoutine());
324
- // }
325
-
326
- // *debugRoutine() {
327
- // while (!this.destroyed && this.activeAndEnabled) {
328
- // Gizmos.DrawLabel(this.gameObject.worldPosition, this.owner ?? "no owner");
329
- // yield;
330
- // }
331
- // }
332
-
333
303
  /** this tells the server that this client has been destroyed and the networking message for the instantiate will be removed */
334
304
  doDestroy() {
335
305
  if (debug) console.log("PlayerSync.doDestroy → syncDestroy", this.name);
336
306
  syncDestroy(this.gameObject, this.context.connection, true, { saveInRoom: false });
337
307
  }
338
308
 
309
+ /** @internal */
339
310
  onDestroy() {
311
+ if(debug) console.warn("PlayerState.onDestroy", this.owner);
340
312
  this.context.connection.stopListen(RoomEvents.UserLeftRoom, this.onUserLeftRoom);
341
313
  PlayerState.all.splice(PlayerState.all.indexOf(this), 1);
342
314
 
@@ -346,4 +318,13 @@ export class PlayerState extends Behaviour {
346
318
  PlayerState._local.splice(index, 1);
347
319
  }
348
320
  }
321
+
322
+ private onUserLeftRoom = (model: { userId: string }) => {
323
+ if (model.userId === this.owner) {
324
+ if (debug)
325
+ console.log("PLAYERSYNC LEFT", this.owner)
326
+ this.doDestroy();
327
+ return;
328
+ }
329
+ }
349
330
  }