@needle-tools/engine 2.35.5-pre → 2.37.0-pre

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 (168) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/needle-engine.d.ts +312 -232
  3. package/dist/needle-engine.js +456 -437
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +81 -76
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/api.d.ts +1 -0
  8. package/lib/engine/api.js +1 -0
  9. package/lib/engine/api.js.map +1 -1
  10. package/lib/engine/debug/debug.d.ts +1 -0
  11. package/lib/engine/debug/debug.js +3 -0
  12. package/lib/engine/debug/debug.js.map +1 -1
  13. package/lib/engine/debug/debug_overlay.js +12 -1
  14. package/lib/engine/debug/debug_overlay.js.map +1 -1
  15. package/lib/engine/engine_element_loading.js +1 -1
  16. package/lib/engine/engine_element_loading.js.map +1 -1
  17. package/lib/engine/engine_gameobject.d.ts +1 -0
  18. package/lib/engine/engine_gameobject.js +15 -2
  19. package/lib/engine/engine_gameobject.js.map +1 -1
  20. package/lib/engine/engine_gltf_builtin_components.js +4 -0
  21. package/lib/engine/engine_gltf_builtin_components.js.map +1 -1
  22. package/lib/engine/engine_mainloop_utils.d.ts +1 -1
  23. package/lib/engine/engine_mainloop_utils.js +7 -3
  24. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  25. package/lib/engine/engine_physics.d.ts +49 -57
  26. package/lib/engine/engine_physics.js +464 -417
  27. package/lib/engine/engine_physics.js.map +1 -1
  28. package/lib/engine/engine_physics.types.d.ts +16 -0
  29. package/lib/engine/engine_physics.types.js +19 -0
  30. package/lib/engine/engine_physics.types.js.map +1 -0
  31. package/lib/engine/engine_serialization_core.d.ts +3 -0
  32. package/lib/engine/engine_serialization_core.js +19 -6
  33. package/lib/engine/engine_serialization_core.js.map +1 -1
  34. package/lib/engine/engine_setup.js +4 -2
  35. package/lib/engine/engine_setup.js.map +1 -1
  36. package/lib/engine/engine_time.d.ts +1 -0
  37. package/lib/engine/engine_time.js +1 -0
  38. package/lib/engine/engine_time.js.map +1 -1
  39. package/lib/engine/engine_types.d.ts +46 -26
  40. package/lib/engine/engine_types.js +24 -37
  41. package/lib/engine/engine_types.js.map +1 -1
  42. package/lib/engine/engine_typestore.d.ts +1 -0
  43. package/lib/engine/engine_typestore.js +1 -0
  44. package/lib/engine/engine_typestore.js.map +1 -1
  45. package/lib/engine/engine_util_decorator.d.ts +6 -0
  46. package/lib/engine/engine_util_decorator.js +54 -0
  47. package/lib/engine/engine_util_decorator.js.map +1 -0
  48. package/lib/engine/engine_utils.d.ts +1 -1
  49. package/lib/engine/engine_utils.js +2 -2
  50. package/lib/engine/engine_utils.js.map +1 -1
  51. package/lib/engine/extensions/NEEDLE_animator_controller_model.js.map +1 -1
  52. package/lib/engine/extensions/NEEDLE_gameobject_data.js +2 -0
  53. package/lib/engine/extensions/NEEDLE_gameobject_data.js.map +1 -1
  54. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +5 -0
  55. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  56. package/lib/engine-components/Animation.d.ts +5 -0
  57. package/lib/engine-components/Animation.js +14 -0
  58. package/lib/engine-components/Animation.js.map +1 -1
  59. package/lib/engine-components/AnimatorController.d.ts +1 -0
  60. package/lib/engine-components/AnimatorController.js +14 -7
  61. package/lib/engine-components/AnimatorController.js.map +1 -1
  62. package/lib/engine-components/BoxHelperComponent.d.ts +2 -2
  63. package/lib/engine-components/BoxHelperComponent.js +28 -9
  64. package/lib/engine-components/BoxHelperComponent.js.map +1 -1
  65. package/lib/engine-components/Collider.d.ts +7 -2
  66. package/lib/engine-components/Collider.js +27 -15
  67. package/lib/engine-components/Collider.js.map +1 -1
  68. package/lib/engine-components/Component.d.ts +8 -16
  69. package/lib/engine-components/Component.js +18 -117
  70. package/lib/engine-components/Component.js.map +1 -1
  71. package/lib/engine-components/DragControls.js +9 -6
  72. package/lib/engine-components/DragControls.js.map +1 -1
  73. package/lib/engine-components/GroundProjection.d.ts +2 -0
  74. package/lib/engine-components/GroundProjection.js +18 -6
  75. package/lib/engine-components/GroundProjection.js.map +1 -1
  76. package/lib/engine-components/NavMesh.d.ts +0 -5
  77. package/lib/engine-components/NavMesh.js +100 -10
  78. package/lib/engine-components/NavMesh.js.map +1 -1
  79. package/lib/engine-components/NestedGltf.js +2 -0
  80. package/lib/engine-components/NestedGltf.js.map +1 -1
  81. package/lib/engine-components/ReflectionProbe.d.ts +22 -0
  82. package/lib/engine-components/ReflectionProbe.js +134 -0
  83. package/lib/engine-components/ReflectionProbe.js.map +1 -0
  84. package/lib/engine-components/Renderer.d.ts +13 -2
  85. package/lib/engine-components/Renderer.js +96 -45
  86. package/lib/engine-components/Renderer.js.map +1 -1
  87. package/lib/engine-components/RigidBody.d.ts +40 -25
  88. package/lib/engine-components/RigidBody.js +253 -142
  89. package/lib/engine-components/RigidBody.js.map +1 -1
  90. package/lib/engine-components/SpatialTrigger.js +1 -1
  91. package/lib/engine-components/SpatialTrigger.js.map +1 -1
  92. package/lib/engine-components/SpectatorCamera.d.ts +1 -0
  93. package/lib/engine-components/SpectatorCamera.js +9 -2
  94. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  95. package/lib/engine-components/SpringJoint.d.ts +0 -13
  96. package/lib/engine-components/SpringJoint.js +42 -41
  97. package/lib/engine-components/SpringJoint.js.map +1 -1
  98. package/lib/engine-components/VideoPlayer.js.map +1 -1
  99. package/lib/engine-components/WebARSessionRoot.d.ts +7 -7
  100. package/lib/engine-components/WebARSessionRoot.js +7 -7
  101. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  102. package/lib/engine-components/WebXR.d.ts +10 -8
  103. package/lib/engine-components/WebXR.js +50 -26
  104. package/lib/engine-components/WebXR.js.map +1 -1
  105. package/lib/engine-components/WebXRAvatar.d.ts +4 -5
  106. package/lib/engine-components/WebXRAvatar.js +9 -8
  107. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  108. package/lib/engine-components/WebXRController.d.ts +21 -21
  109. package/lib/engine-components/WebXRController.js +90 -68
  110. package/lib/engine-components/WebXRController.js.map +1 -1
  111. package/lib/engine-components/WebXRGrabRendering.d.ts +3 -3
  112. package/lib/engine-components/WebXRGrabRendering.js +2 -2
  113. package/lib/engine-components/WebXRGrabRendering.js.map +1 -1
  114. package/lib/engine-components/WebXRSync.d.ts +8 -8
  115. package/lib/engine-components/WebXRSync.js +15 -15
  116. package/lib/engine-components/WebXRSync.js.map +1 -1
  117. package/lib/engine-components/codegen/components.d.ts +2 -3
  118. package/lib/engine-components/codegen/components.js +2 -3
  119. package/lib/engine-components/codegen/components.js.map +1 -1
  120. package/lib/engine-components/ui/EventSystem.d.ts +1 -0
  121. package/lib/engine-components/ui/EventSystem.js +21 -1
  122. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  123. package/package.json +3 -4
  124. package/src/engine/api.ts +2 -1
  125. package/src/engine/codegen/register_types.js +291 -6
  126. package/src/engine/debug/debug.ts +4 -0
  127. package/src/engine/debug/debug_overlay.ts +9 -2
  128. package/src/engine/engine_element_loading.ts +1 -1
  129. package/src/engine/engine_gameobject.ts +19 -6
  130. package/src/engine/engine_gltf_builtin_components.ts +5 -1
  131. package/src/engine/engine_mainloop_utils.ts +7 -3
  132. package/src/engine/engine_physics.ts +508 -469
  133. package/src/engine/engine_physics.types.ts +19 -0
  134. package/src/engine/engine_serialization_core.ts +22 -8
  135. package/src/engine/engine_setup.ts +6 -2
  136. package/src/engine/engine_time.ts +2 -0
  137. package/src/engine/engine_types.ts +82 -55
  138. package/src/engine/engine_typestore.ts +2 -0
  139. package/src/engine/engine_util_decorator.ts +69 -0
  140. package/src/engine/engine_utils.ts +6 -5
  141. package/src/engine/extensions/EXT_texture_exr.js +1 -1
  142. package/src/engine/extensions/NEEDLE_animator_controller_model.ts +2 -1
  143. package/src/engine/extensions/NEEDLE_gameobject_data.ts +2 -0
  144. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +7 -0
  145. package/src/engine-components/Animation.ts +14 -1
  146. package/src/engine-components/AnimatorController.ts +19 -9
  147. package/src/engine-components/BoxHelperComponent.ts +30 -9
  148. package/src/engine-components/Collider.ts +29 -29
  149. package/src/engine-components/Component.ts +26 -135
  150. package/src/engine-components/DragControls.ts +9 -5
  151. package/src/engine-components/GroundProjection.ts +22 -7
  152. package/src/engine-components/NavMesh.ts +114 -115
  153. package/src/engine-components/NestedGltf.ts +2 -0
  154. package/src/engine-components/ReflectionProbe.ts +141 -0
  155. package/src/engine-components/Renderer.ts +796 -737
  156. package/src/engine-components/RigidBody.ts +258 -149
  157. package/src/engine-components/SpatialTrigger.ts +1 -1
  158. package/src/engine-components/SpectatorCamera.ts +10 -2
  159. package/src/engine-components/SpringJoint.ts +41 -41
  160. package/src/engine-components/VideoPlayer.ts +1 -2
  161. package/src/engine-components/WebARSessionRoot.ts +16 -16
  162. package/src/engine-components/WebXR.ts +65 -50
  163. package/src/engine-components/WebXRAvatar.ts +16 -16
  164. package/src/engine-components/WebXRController.ts +143 -112
  165. package/src/engine-components/WebXRGrabRendering.ts +6 -6
  166. package/src/engine-components/WebXRSync.ts +20 -20
  167. package/src/engine-components/codegen/components.ts +2 -3
  168. package/src/engine-components/ui/EventSystem.ts +26 -3
@@ -0,0 +1,19 @@
1
+
2
+
3
+ export enum CollisionDetectionMode {
4
+ Discrete = 0,
5
+ Continuous = 1,
6
+ }
7
+
8
+ export enum RigidbodyConstraints {
9
+ None = 0,
10
+ FreezePositionX = 2,
11
+ FreezePositionY = 4,
12
+ FreezePositionZ = 8,
13
+ FreezePosition = 14,
14
+ FreezeRotationX = 16,
15
+ FreezeRotationY = 32,
16
+ FreezeRotationZ = 64,
17
+ FreezeRotation = 112,
18
+ FreezeAll = 126,
19
+ }
@@ -3,13 +3,15 @@ import { getParam } from "./engine_utils";
3
3
  import { Object3D } from "three";
4
4
  import { Context } from "./engine_setup";
5
5
  import { isPersistentAsset } from "./extensions/NEEDLE_persistent_assets";
6
- import { SourceIdentifier } from "./engine_types";
6
+ import { IComponent, SourceIdentifier } from "./engine_types";
7
7
  import { debugExtension } from "../engine/engine_default_parameters";
8
8
  import { LogType, showBalloonMessage } from "./debug/debug";
9
9
  import { isLocalNetwork } from "./engine_networking_utils";
10
+ import { $BuiltInTypeFlag } from "./engine_typestore";
10
11
 
11
12
  const debug = getParam("debugserializer");
12
13
 
14
+
13
15
  export type Constructor<T> = { new(...args: any[]): T };
14
16
  export declare type NodeToObjectMap = { [nodeId: string]: Object3D };
15
17
  export declare type ObjectToNodeMap = { [uuid: string]: number };
@@ -324,8 +326,16 @@ export function deserializeObject(obj: ISerializable, serializedData: object, co
324
326
  return true;
325
327
  }
326
328
 
329
+ const blockChecks = getParam("noerrors");
327
330
  function checkObjectAssignments(obj: any, _serializedData?: any) {
328
- if(isLocalNetwork() === false) return;
331
+ if(blockChecks) return;
332
+ if (isLocalNetwork() === false) return;
333
+ if (!obj) return;
334
+
335
+ // ignore builtin components that we dont want to check
336
+ if(obj.constructor && obj.constructor[$BuiltInTypeFlag] === true) return;
337
+
338
+ const typeName = obj.constructor?.name as string;
329
339
  // test if any object reference is missing serializable
330
340
  const ownKeys = Object.getOwnPropertyNames(obj);
331
341
  for (const key of ownKeys) {
@@ -337,18 +347,16 @@ function checkObjectAssignments(obj: any, _serializedData?: any) {
337
347
  if (typeof value["node"] === "number" || typeof value["guid"] === "string") {
338
348
  const hasOtherKeys = Object.keys(value).length > 1;
339
349
  if (!hasOtherKeys) {
340
- const typeName = obj.constructor?.name;
341
- showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(Object3D)\n${key}? : Object3D;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable">documentation</a>`, LogType.Warn);
342
- console.warn(obj);
350
+ showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(Object3D)\n${key}? : Object3D;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable" target="_blank">documentation</a>`, LogType.Warn);
351
+ console.warn(typeName, key, obj[key], obj);
343
352
  }
344
353
  }
345
354
  }
346
355
  }
347
356
  else if (typeof value === "string") {
348
357
  if (value.endsWith(".gltf") || value.endsWith(".glb")) {
349
- const typeName = obj.constructor?.name;
350
- showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(AssetReference)\n${key}? : AssetReference;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable">documentation</a>`, LogType.Warn);
351
- console.warn(obj);
358
+ showBalloonMessage(`<strong>Missing serialization for object reference!</strong>\n\nPlease change to: \n@serializable(AssetReference)\n${key}? : AssetReference;\n\nin script ${typeName}.ts\n<a href="https://docs.needle.tools/serializeable" target="_blank">documentation</a>`, LogType.Warn);
359
+ console.warn(typeName, key, obj[key], obj);
352
360
  }
353
361
  }
354
362
  }
@@ -509,6 +517,10 @@ function setBuffer(value): Array<any> {
509
517
  }
510
518
 
511
519
 
520
+ /** set to true while assigning properties during instantiation.
521
+ * Used for validate decorator to not invoke callbacks on components that are currently in the process of being built */
522
+ export const $isAssigningProperties = Symbol("assigned component properties");
523
+
512
524
  // const developmentMode = getParam("dev")
513
525
 
514
526
  /** Object.assign behaviour but check if property is writeable (e.g. getter only properties are skipped) */
@@ -533,6 +545,7 @@ export function assign(target: any, source: any) {
533
545
  // if (developmentMode)
534
546
  // onlyDeclared = false;
535
547
 
548
+ target[$isAssigningProperties] = true;
536
549
  for (const key of Object.keys(source)) {
537
550
  const desc = getPropertyDescriptor(target, key);
538
551
  if (onlyDeclared && desc === undefined) continue;
@@ -543,6 +556,7 @@ export function assign(target: any, source: any) {
543
556
  target[key] = source[key];
544
557
  }
545
558
  }
559
+ delete target[$isAssigningProperties];
546
560
  }
547
561
 
548
562
  // we need to recurse because the property might be defined in a base class
@@ -400,6 +400,10 @@ export class Context {
400
400
  }
401
401
 
402
402
  private async internalOnCreate(buildScene: (context: Context, opts?: LoadingOptions) => Promise<void>, opts?: LoadingOptions) {
403
+
404
+ // TODO: we could configure if we need physics
405
+ await this.physics.createWorld();
406
+
403
407
  // load and create scene
404
408
  let prepare_succeeded = true;
405
409
  try {
@@ -562,7 +566,7 @@ export class Context {
562
566
  this.executeCoroutines(FrameEvent.LateUpdate);
563
567
 
564
568
  try {
565
- const physicsSteps = 2;
569
+ const physicsSteps = 1;
566
570
  const dt = this.time.deltaTime / physicsSteps;
567
571
  for (let i = 0; i < physicsSteps; i++) {
568
572
  this.physics.step(dt);
@@ -600,7 +604,7 @@ export class Context {
600
604
  this._isRendering = true;
601
605
  this.renderRequiredTextures();
602
606
  if (!this.isManagedExternally) {
603
- if (this.composer) {
607
+ if (this.composer && !this.isInXR) {
604
608
  this.composer.render();
605
609
  }
606
610
  else if (this.mainCamera) {
@@ -5,6 +5,8 @@ export class Time {
5
5
 
6
6
  deltaTime = 0;
7
7
  time = 0;
8
+
9
+ /** same as frameCount */
8
10
  frame = 0;
9
11
 
10
12
  get realtimeSinceStartup(): number {
@@ -1,6 +1,6 @@
1
- import { Camera, Color, Material, Object3D, Vector3 } from "three";
2
- import { Body, ContactEquation } from "cannon-es";
1
+ import { Camera, Color, Material, Object3D, Vector3, Quaternion } from "three";
3
2
  import { RGBAColor } from "../engine-components/js-extensions/RGBAColor";
3
+ import { CollisionDetectionMode, RigidbodyConstraints } from "./engine_physics.types";
4
4
 
5
5
  /** used to find data registered via gltf files e.g. find lightmaps for a Renderer component that were shipped inside a gltf */
6
6
  export declare type SourceIdentifier = string;
@@ -58,9 +58,10 @@ export interface IComponent {
58
58
  onDisable();
59
59
  onDestroy();
60
60
 
61
+ /** called for properties decorated with the @validate decorator */
62
+ onValidate?(property?: string);
63
+
61
64
  start?(): void;
62
- // available update loop events:
63
- // earlyUpdate, update, lateUpdate, onBeforeRender, onAfterRender
64
65
  earlyUpdate?(): void;
65
66
  update?(): void;
66
67
  lateUpdate?(): void;
@@ -69,17 +70,15 @@ export interface IComponent {
69
70
 
70
71
  onCollisionEnter?(col: Collision);
71
72
  onCollisionExit?(col: Collision);
72
- onCollisionExitRaw?(col: Collision);
73
73
  onCollisionStay?(col: Collision);
74
74
 
75
- onTriggerEnter?(col: Collision);
76
- onTriggerStay?(col: Collision);
77
- onTriggerExit?(col: Collision);
78
-
79
- __internalHandleCollision(col: Collision, isTriggerCollision: boolean);
80
- __internalHandleExitCollisionEvent(obj: Object3D, isTriggerCollision: boolean);
75
+ onTriggerEnter?(col: ICollider);
76
+ onTriggerStay?(col: ICollider);
77
+ onTriggerExit?(col: ICollider);
81
78
 
82
79
  get forward(): Vector3;
80
+ get worldPosition(): Vector3;
81
+ get worldQuaternion(): Quaternion;
83
82
  }
84
83
 
85
84
 
@@ -101,7 +100,8 @@ export declare interface ILight extends IComponent {
101
100
  }
102
101
 
103
102
  export declare interface ISharedMaterials {
104
- [num:number] : Material;
103
+ [num: number]: Material;
104
+ get length(): number;
105
105
  }
106
106
 
107
107
  export declare interface IRenderer extends IComponent {
@@ -109,6 +109,10 @@ export declare interface IRenderer extends IComponent {
109
109
  get sharedMaterials(): ISharedMaterials;
110
110
  }
111
111
 
112
+ // export declare interface IPhysicsComponent extends IComponent {
113
+ // get type() : string;
114
+ // }
115
+
112
116
  export declare interface ICollider extends IComponent {
113
117
  get isCollider();
114
118
  attachedRigidbody: IRigidbody | null;
@@ -116,67 +120,98 @@ export declare interface ICollider extends IComponent {
116
120
  }
117
121
 
118
122
  export declare interface IRigidbody extends IComponent {
119
- initialize(): void;
120
- body;
123
+ constraints: RigidbodyConstraints;
124
+ isKinematic: boolean;
125
+ mass: number;
126
+ drag: number;
127
+ angularDrag: number;
128
+ useGravity: boolean;
129
+ collisionDetectionMode: CollisionDetectionMode;
130
+
131
+ lockPositionX: boolean;
132
+ lockPositionY: boolean;
133
+ lockPositionZ: boolean;
134
+ lockRotationX: boolean;
135
+ lockRotationY: boolean;
136
+ lockRotationZ: boolean;
121
137
  }
122
138
 
123
139
 
140
+ export const $physicsKey = Symbol("object");
124
141
 
125
142
 
143
+ export declare type ICollisionContext = {
144
+ getCollider(obj: Object3D): ICollider;
145
+ }
126
146
 
127
147
 
128
-
129
- export const $physicsKey = Symbol("object");
130
-
131
- export declare type CannonCollision = {
132
- body: Body;
133
- contact: ContactEquation;
134
- target: Body;
135
- type: string;
148
+ export type Vec3 = {
149
+ x: number,
150
+ y: number,
151
+ z: number
136
152
  }
137
153
 
138
- export declare type ICollisionContext = {
139
- getCollider(obj: Object3D): ICollider;
154
+ export type Vec2 = {
155
+ x: number,
156
+ y: number
140
157
  }
141
158
 
142
- export class Collision {
159
+ export class ContactPoint {
143
160
 
144
- get __internalCollision(): CannonCollision {
145
- return this.collision;
146
- }
161
+ readonly localPoint: Vec3;
162
+ readonly distance: number;
163
+ readonly normal: Vec3;
147
164
 
148
- get __internalInvertedSourceReceiver(): boolean {
149
- return this.invert;
165
+ constructor(localPt: Vec3, dist: number, normal: Vec3) {
166
+ this.localPoint = localPt;
167
+ this.distance = dist;
168
+ this.normal = normal;
150
169
  }
151
170
 
152
- private readonly invert: boolean;
153
- private readonly collision: CannonCollision;
154
- private readonly targetBody: Body;
155
- private readonly context: ICollisionContext;
171
+ }
156
172
 
157
- readonly me: Object3D;
173
+ /// all info in here must be readonly because the object is only created once per started collision
174
+ export class Collision {
175
+
176
+ private readonly contacts: ContactPoint[];
158
177
 
159
- private _normal?: Vector3;
160
- get normal(): Vector3 {
161
- if (!this._normal) {
162
- const vec = this.collision.contact.ni;
163
- this._normal = new Vector3(vec.x, vec.y, vec.z);
164
- }
165
- return this._normal;
178
+ constructor(obj: Object3D, otherCollider: ICollider, contacts: ContactPoint[]) {
179
+ this.me = obj;
180
+ this._collider = otherCollider;
181
+ this._gameObject = otherCollider.gameObject;
182
+ this.contacts = contacts;
166
183
  }
167
184
 
168
- private _collider?: ICollider;
185
+ readonly me: Object3D;
186
+ private _collider: ICollider;
187
+
188
+ /** the collider the collision happened with */
169
189
  get collider(): ICollider {
170
- if (!this._collider) {
171
- this._collider = this.context.getCollider(this.gameObject);
172
- }
173
190
  return this._collider;
174
191
  }
175
192
 
193
+ /** the object the collision happened with */
194
+ private _gameObject: Object3D;
176
195
  get gameObject(): Object3D {
177
- return this.targetBody[$physicsKey];
196
+ return this._gameObject;
197
+ }
198
+
199
+ /** the rigidbody we hit, null if none attached */
200
+ get rigidBody(): IRigidbody | null {
201
+ return this.collider?.attachedRigidbody;
178
202
  }
179
203
 
204
+
205
+ // private _normal?: Vector3;
206
+ // get normal(): Vector3 {
207
+ // if (!this._normal) {
208
+ // const vec = this.collision.contact.ni;
209
+ // this._normal = new Vector3(vec.x, vec.y, vec.z);
210
+ // }
211
+ // return this._normal;
212
+ // }
213
+
214
+
180
215
  // private _point?: Vector3;
181
216
  // get point(): Vector3 {
182
217
  // if (!this._point) {
@@ -186,12 +221,4 @@ export class Collision {
186
221
  // }
187
222
  // return this._point;
188
223
  // }
189
-
190
- constructor(obj: Object3D, collision: CannonCollision, context: ICollisionContext, invert: boolean = false) {
191
- this.me = obj;
192
- this.collision = collision;
193
- this.context = context;
194
- this.targetBody = invert ? collision.target : collision.body;
195
- this.invert = invert;
196
- }
197
224
  }
@@ -18,4 +18,6 @@ class _TypeStore {
18
18
  }
19
19
  }
20
20
 
21
+ export const $BuiltInTypeFlag = Symbol("BuiltInType");
22
+
21
23
  export const TypeStore = new _TypeStore();
@@ -0,0 +1,69 @@
1
+ import { $isAssigningProperties } from "./engine_serialization_core";
2
+ import { LogType, showBalloonMessage } from "./debug/debug";
3
+ import { IComponent } from "./engine_types";
4
+
5
+
6
+ declare type setter = (v: any) => void;
7
+ declare type getter = () => any;
8
+
9
+ /** create accessor callbacks for a field */
10
+ export const validate = function (set?: setter, get?: getter) {
11
+ // "descriptor : undefined" prevents @validate() to be added to property getters or setters
12
+ return function (target: IComponent | any, propertyKey: string, descriptor?: undefined) {
13
+ createPropertyWrapper(target, propertyKey, descriptor, set, get);
14
+ }
15
+ }
16
+
17
+
18
+ function createPropertyWrapper(target: IComponent | any, propertyKey: string, descriptor?: PropertyDescriptor,
19
+ set?: setter,
20
+ get?: getter) {
21
+
22
+ if (!get && !set && !target.onValidate) return;
23
+
24
+ // this is not undefined when its a property getter or setter already and not just a field
25
+ // we currently only support validation of fields
26
+ if (descriptor !== undefined) {
27
+ console.error("Invalid usage of validate decorator. Only fields can be validated.", target, propertyKey, descriptor);
28
+ showBalloonMessage("Invalid usage of validate decorator. Only fields can be validated. Property: " + propertyKey, LogType.Error);
29
+ return;
30
+ }
31
+
32
+ if (target.__internalAwake) {
33
+ // this is the hidden key we save the original property to
34
+ const $prop = Symbol(propertyKey);
35
+ // save the original awake method
36
+ // we need to delay decoration until the object has been created
37
+ const awake = target.__internalAwake;
38
+ target.__internalAwake = function () {
39
+
40
+ // only build wrapper once per type
41
+ if (this[$prop] === undefined) {
42
+
43
+ // make sure the field is initialized in a hidden property
44
+ this[$prop] = this[propertyKey];
45
+
46
+ Object.defineProperty(this, propertyKey, {
47
+ set: function (v) {
48
+ if (this[$isAssigningProperties] === true) {
49
+ this[$prop] = v;
50
+ }
51
+ else {
52
+ set?.call(this, v);
53
+ const oldValue = this[$prop];
54
+ this[$prop] = v;
55
+ this.onValidate?.call(this, propertyKey, oldValue);
56
+ }
57
+ },
58
+ get: function () {
59
+ get?.call(this);
60
+ return this[$prop];
61
+ },
62
+ });
63
+ }
64
+
65
+ // call the original awake method
66
+ awake.call(this);
67
+ };
68
+ }
69
+ }
@@ -217,7 +217,7 @@ export function getPath(source: SourceIdentifier | undefined, uri: string): stri
217
217
  // }
218
218
 
219
219
 
220
- export type WriteCallback = (data: any) => void;
220
+ export type WriteCallback = (data: any, prop: string) => void;
221
221
 
222
222
  export interface IWatch {
223
223
  subscribeWrite(callback: WriteCallback);
@@ -226,6 +226,7 @@ export interface IWatch {
226
226
  dispose();
227
227
  }
228
228
 
229
+
229
230
  // TODO: make it possible to add multiple watches to the same object property
230
231
  class WatchImpl implements IWatch {
231
232
  subscribeWrite(callback: WriteCallback) {
@@ -236,14 +237,14 @@ class WatchImpl implements IWatch {
236
237
  constructor(object: object, prop: string) {
237
238
  this._object = object;
238
239
  this._prop = prop;
239
- this._wrapperProp = "__$_NEEDLE_" + prop;
240
+ this._wrapperProp = Symbol("$" + prop);
240
241
  this.apply();
241
242
  }
242
243
 
243
244
  private _applied: boolean = false;
244
245
  private _object: any;
245
246
  private _prop: string;
246
- private _wrapperProp: string;
247
+ private _wrapperProp: symbol;
247
248
 
248
249
  apply() {
249
250
  if (this._applied) return;
@@ -267,7 +268,7 @@ class WatchImpl implements IWatch {
267
268
  const setter = (value) => {
268
269
  object[this._wrapperProp] = value;
269
270
  for (const write of this.writeCallbacks) {
270
- write(value);
271
+ write(value, this._prop);
271
272
  }
272
273
  }
273
274
  // add the wrapper to the object
@@ -320,7 +321,7 @@ export class Watch implements IWatch {
320
321
  apply() {
321
322
  for (const w of this._watches) {
322
323
  w.apply();
323
- }
324
+ }
324
325
  }
325
326
 
326
327
  revoke() {
@@ -32,7 +32,7 @@ export class EXT_texture_exr {
32
32
  const extension = textureDef.extensions[ name ];
33
33
 
34
34
  // TODO should the loader be cached here?
35
- let loader = new EXRLoader(parser.options.manager);
35
+ const loader = new EXRLoader(parser.options.manager);
36
36
 
37
37
  if(debug) console.log("EXT_texture_exr.loadTexture", extension, loader);
38
38
 
@@ -97,7 +97,7 @@ export declare type Motion = {
97
97
  action_loopback?: AnimationAction,
98
98
  }
99
99
 
100
- export function createMotion(name:string, id? : InstantiateIdProvider): Motion {
100
+ export function createMotion(name: string, id?: InstantiateIdProvider): Motion {
101
101
  return {
102
102
  name: "",
103
103
  isLooping: false,
@@ -123,6 +123,7 @@ export declare type Transition = {
123
123
  hasExitTime: number,
124
124
  destinationState: number | State,
125
125
  conditions: Condition[],
126
+ // isAny?: boolean
126
127
  }
127
128
 
128
129
  export declare type Condition = {
@@ -66,6 +66,8 @@ export class NEEDLE_gameobject_data implements GLTFLoaderPlugin {
66
66
 
67
67
  private applyExtensionData(node: Object3D, ext: GameObjectData) {
68
68
  node.userData.layer = ext.layers;
69
+ node.layers.disableAll();
70
+ node.layers.set(ext.layers);
69
71
  node.userData.tag = ext.tag;
70
72
  node.userData.hideFlags = ext.hideFlags;
71
73
  node.userData.static = ext.static;
@@ -203,6 +203,9 @@ export class CustomShader extends RawShaderMaterial {
203
203
  if (this.uniforms["_TimeParameters"]) {
204
204
  this.uniforms["_TimeParameters"].value = context.rendererData.timeVec4;
205
205
  }
206
+ else if (this.uniforms["_Time"]) {
207
+ this.uniforms["_Time"].value = context.rendererData.timeVec4;
208
+ }
206
209
 
207
210
  const mainLight: ILight | null = context.mainLight;
208
211
  if (mainLight) {
@@ -327,6 +330,10 @@ export class NEEDLE_techniques_webgl implements GLTFLoaderPlugin {
327
330
 
328
331
  const uniforms: {} = {};
329
332
  const techniqueUniforms = technique.uniforms;
333
+
334
+ if (vert.includes("_Time"))
335
+ uniforms["_Time"] = { value: new THREE.Vector4(0, 0, 0, 0) };
336
+
330
337
  for (const u in techniqueUniforms) {
331
338
  const uniformName = u;
332
339
  // const uniformValues = techniqueUniforms[u];
@@ -1,9 +1,11 @@
1
1
  import { Behaviour } from "./Component";
2
2
  import * as THREE from 'three'
3
- import { AnimationAction, AnimationClip } from "three";
3
+ import { AnimationAction, AnimationClip, Vector2 } from "three";
4
4
  import { MixerEvent } from "./Animator";
5
5
  import { serializeable } from "../engine/engine_serialization_decorator";
6
6
  import { InstancingUtil } from "../engine/engine_instancing";
7
+ import { Mathf } from "../engine/engine_math";
8
+ import { Vec2 } from "../engine/engine_types";
7
9
 
8
10
  export declare class PlayOptions {
9
11
  fadeDuration?: number;
@@ -12,6 +14,8 @@ export declare class PlayOptions {
12
14
  startTime?: number;
13
15
  endTime?: number;
14
16
  clampWhenFinished?: boolean;
17
+ minMaxSpeed?: Vec2;
18
+ minMaxOffsetNormalized?: Vec2;
15
19
  }
16
20
 
17
21
  export class Animation extends Behaviour {
@@ -21,6 +25,9 @@ export class Animation extends Behaviour {
21
25
  @serializeable()
22
26
  randomStartTime: boolean = true;
23
27
 
28
+ minMaxSpeed?: Vec2;
29
+ minMaxOffsetNormalized?: Vec2;
30
+
24
31
  private _tempAnimationClipBeforeGameObjectExisted: AnimationClip | null = null;
25
32
  get clip(): AnimationClip | null {
26
33
  return this.animations?.length ? this.animations[0] : null;
@@ -120,6 +127,9 @@ export class Animation extends Behaviour {
120
127
  console.error("Could not find clip", clipOrNumber)
121
128
  return;
122
129
  }
130
+ if (!options) options = {};
131
+ if (!options.minMaxOffsetNormalized) options.minMaxOffsetNormalized = this.minMaxOffsetNormalized;
132
+ if (!options.minMaxSpeed) options.minMaxSpeed = this.minMaxSpeed;
123
133
  for (const act of this.actions) {
124
134
  if (act.getClip() === clip) {
125
135
  return this.internalOnPlay(act, options);
@@ -150,6 +160,9 @@ export class Animation extends Behaviour {
150
160
  action.enabled = true;
151
161
  action.time = 0;
152
162
  action.timeScale = 1;
163
+ const clip = action.getClip();
164
+ if (options?.minMaxOffsetNormalized) action.time = Mathf.lerp(options.minMaxOffsetNormalized.x, options.minMaxOffsetNormalized.y, Math.random()) * clip.duration;
165
+ if (options?.minMaxSpeed) action.timeScale = Mathf.lerp(options.minMaxSpeed.x, options.minMaxSpeed.y, Math.random());
153
166
  if (options?.clampWhenFinished) action.clampWhenFinished = true;
154
167
  if (options?.startTime !== undefined) action.time = options.startTime;
155
168
 
@@ -188,6 +188,8 @@ export class AnimatorController {
188
188
 
189
189
  private evaluateTransitions() {
190
190
 
191
+ const currentLayer = 0;
192
+
191
193
  let didEnterStateThisFrame = false;
192
194
  if (!this._activeState) {
193
195
  this.setStartTransition();
@@ -200,8 +202,11 @@ export class AnimatorController {
200
202
  let index = 0;
201
203
  for (const transition of state.transitions) {
202
204
  ++index;
203
- // transition without exit time and without condition are ignored
204
- if (!transition.hasExitTime && transition.conditions.length <= 0) continue;
205
+ // transition without exit time and without condition that transition to itself are ignored
206
+ if (!transition.hasExitTime && transition.conditions.length <= 0) {
207
+ // if (this._activeState && this.getState(transition.destinationState, currentLayer)?.hash === this._activeState.hash)
208
+ continue;
209
+ }
205
210
 
206
211
  let allConditionsAreMet = true;
207
212
  for (const cond of transition.conditions) {
@@ -213,7 +218,7 @@ export class AnimatorController {
213
218
  if (!allConditionsAreMet) continue;
214
219
 
215
220
  if (debug && allConditionsAreMet) {
216
- console.log("All conditions are met", transition.conditions, action);
221
+ console.log("All conditions are met", transition);
217
222
  }
218
223
 
219
224
  // disable triggers
@@ -279,17 +284,22 @@ export class AnimatorController {
279
284
 
280
285
  }
281
286
 
287
+ private getState(state : State | number, layerIndex:number) : State | null {
288
+ if (typeof state === "number") {
289
+ if (state == -1) state = this.model.layers[layerIndex].stateMachine.defaultState; // exit state -> entry state
290
+ state = this.model.layers[layerIndex].stateMachine.states[state];
291
+ }
292
+ return state;
293
+ }
294
+
282
295
  private transitionTo(state: State | number, durationInSec: number, offsetNormalized: number) {
283
296
 
284
297
  if (!this.animator) return;
285
298
 
286
299
  const layerIndex = 0;
287
300
 
288
- if (typeof state === "number") {
289
- if (state == -1) state = this.model.layers[layerIndex].stateMachine.defaultState; // exit state -> entry state
290
- state = this.model.layers[layerIndex].stateMachine.states[state];
291
- }
292
-
301
+ state = this.getState(state, layerIndex) as State;
302
+
293
303
  if (!state?.motion || !state.motion.clip) {
294
304
  // if(debug) console.warn("State has no clip or motion", state);
295
305
  return;
@@ -409,7 +419,7 @@ export class AnimatorController {
409
419
  const sm = layer.stateMachine;
410
420
  for (let index = 0; index < sm.states.length; index++) {
411
421
  const state = sm.states[index];
412
-
422
+
413
423
  // ensure we have a motion even if none was exported
414
424
  if (!state.motion) {
415
425
  state.motion = createMotion(state.name);