@woosh/meep-engine 2.59.0 → 2.59.2

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 (67) hide show
  1. package/build/meep.cjs +710 -644
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +710 -644
  4. package/editor/process/symbolic/SymbolicDisplayInternalAPI.js +3 -3
  5. package/editor/process/symbolic/makeParticleEmitterSymbolicDisplay.js +1 -1
  6. package/editor/process/symbolic/makePathSymbolicDisplay.js +1 -1
  7. package/editor/process/symbolic/makeSoundEmitterSymbolicDisplay.js +1 -1
  8. package/editor/tools/TopDownCameraControlTool.js +2 -2
  9. package/editor/tools/v2/TransformControls.js +1 -1
  10. package/editor/tools/v2/prototypeTransformControls.js +1 -1
  11. package/package.json +1 -1
  12. package/samples/generation/main.js +1 -1
  13. package/samples/terrain/editor.js +1 -1
  14. package/src/core/collection/array/arraySetDiff.js +11 -7
  15. package/src/core/geom/3d/aabb/aabb3_array_intersects_point.spec.js +48 -0
  16. package/src/core/geom/3d/aabb/aabb3_array_intersects_ray.js +5 -1
  17. package/src/core/geom/3d/aabb/aabb3_expand_array.spec.js +16 -0
  18. package/src/core/geom/3d/aabb/aabb3_raycast.spec.js +37 -0
  19. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -12
  20. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.spec.js +14 -0
  21. package/src/core/geom/3d/aabb/aabb3_transformed_compute_plane_side.js +6 -4
  22. package/src/core/geom/3d/aabb/compute_aabb_from_points.js +6 -3
  23. package/src/core/geom/3d/matrix/m4_multiply.spec.js +24 -0
  24. package/src/core/geom/3d/matrix/m4_multiply_alphatensor.js +56 -40
  25. package/src/core/geom/3d/matrix/m4_multiply_alphatensor.spec.js +24 -0
  26. package/src/core/geom/3d/shape/util/shape_to_visual_entity.js +2 -2
  27. package/src/core/geom/Vector3.spec.js +24 -14
  28. package/src/engine/EngineHarness.js +1 -1
  29. package/src/engine/control/ControlContext.js +1 -1
  30. package/src/engine/ecs/Entity.d.ts +2 -0
  31. package/src/engine/ecs/Entity.js +40 -37
  32. package/src/engine/ecs/Entity.spec.js +2 -2
  33. package/src/engine/ecs/EntityBuilderUtils.js +2 -2
  34. package/src/engine/ecs/EntityComponentDataset.js +91 -89
  35. package/src/engine/ecs/EntityFlags.js +4 -4
  36. package/src/engine/ecs/attachment/Attachment.js +5 -2
  37. package/src/engine/ecs/binding/ComponentPropertyBinding.js +13 -13
  38. package/src/engine/ecs/dynamic_actions/RuleExecution.js +1 -1
  39. package/src/engine/ecs/parent/EntityNode.js +2 -2
  40. package/src/engine/ecs/parent/EntityNode.spec.js +2 -2
  41. package/src/engine/ecs/tooltip/testTooltipComponentSystem.js +1 -1
  42. package/src/engine/ecs/util/hideEntityGracefully.js +6 -6
  43. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +1 -0
  44. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts +3 -0
  45. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +69 -28
  46. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +21 -15
  47. package/src/engine/graphics/ecs/mesh-v2/render/SGThreeObjectCache.js +30 -7
  48. package/src/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +1 -1
  49. package/src/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +71 -34
  50. package/src/engine/graphics/ecs/mesh-v2/sample/prototype_sg_raycast.js +1 -1
  51. package/src/engine/graphics/ecs/path/PathDisplaySystem.js +4 -4
  52. package/src/engine/graphics/ecs/path/entity/EntityPathMarker.js +1 -1
  53. package/src/engine/graphics/ecs/path/highlight/PathDisplayHighlightSystem.js +3 -3
  54. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +5 -5
  55. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +2 -2
  56. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +1 -1
  57. package/src/engine/graphics/sh3/prototypeSH3Probe.js +2 -2
  58. package/src/engine/intelligence/behavior/ecs/EntityBehavior.js +14 -17
  59. package/src/engine/intelligence/behavior/util/DelayBehavior.js +6 -6
  60. package/src/engine/ui/GUIEngine.js +368 -371
  61. package/src/engine/ui/notification/NotificationManager.js +1 -1
  62. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
  63. package/src/view/tooltip/gml/TooltipParser.js +21 -28
  64. package/src/view/tooltip/gml/compiler/GMLReferenceCompiler.js +3 -2
  65. package/src/core/geom/3d/aabb/aabb3_intersects_ray_branchless.js +0 -52
  66. package/src/core/geom/3d/aabb/aabb3_intersects_ray_fast.js +0 -176
  67. package/src/core/geom/3d/aabb/aabb3_intersects_ray_slab.js +0 -91
package/build/meep.cjs CHANGED
@@ -61968,34 +61968,38 @@ function arrayIndexByEquality(array, element, equals) {
61968
61968
  }
61969
61969
 
61970
61970
  /**
61971
+ * Compute a diff between two arrays, result is a 3 way split between common items, unique items in `a` array and unique items in `b` array
61971
61972
  * @template T
61972
61973
  * @param {T[]} a
61973
61974
  * @param {T[]} b
61974
- * @param {function(a:T,b:T):boolean} [equals]
61975
+ * @param {function(a:T,b:T):boolean} [equals] method to determine equality between two elements
61975
61976
  * @returns {{uniqueA:T[], uniqueB:T[], common:T[]}}
61976
61977
  */
61977
61978
  function arraySetDiff(a, b, equals = strictEquals) {
61979
+ // TODO we can do this faster if we use a comparator instead of equality and pre-sort the data
61978
61980
  const uniqueA = a.slice();
61979
61981
  const uniqueB = b.slice();
61980
61982
 
61981
61983
  const common = [];
61982
61984
 
61983
- let lA = uniqueA.length;
61985
+ let a_length = uniqueA.length;
61984
61986
 
61985
- let i;
61986
- for (i = 0; i < lA; i++) {
61987
+ for (let i = 0; i < a_length; i++) {
61987
61988
  const elA = uniqueA[i];
61988
61989
 
61989
61990
  const j = arrayIndexByEquality(uniqueB, elA, equals);
61990
61991
 
61991
61992
  if (j !== -1) {
61993
+ // common element found
61994
+
61992
61995
  common.push(elA);
61993
61996
 
61997
+ // remove from respective unique sets
61994
61998
  uniqueA.splice(i, 1);
61995
61999
  uniqueB.splice(j, 1);
61996
62000
 
61997
62001
  i--;
61998
- lA--;
62002
+ a_length--;
61999
62003
  }
62000
62004
  }
62001
62005
 
@@ -68730,6 +68734,7 @@ const scratch_ray_0$1 = new Float32Array(6);
68730
68734
 
68731
68735
  /**
68732
68736
  * Represents a primitive 3d object, a combination of a material and geometry
68737
+ * This is roughly equivalent to single draw call, note that his is not a hierarchical data structure, if you want that - you will need to combine multiple entities, each with a `ShadedGeometry` component
68733
68738
  */
68734
68739
  class ShadedGeometry {
68735
68740
  constructor() {
@@ -69070,32 +69075,72 @@ const DEFAULT_FLAGS$4 = SGMeshFlags.CastShadow
69070
69075
  ;
69071
69076
 
69072
69077
  class SGMesh {
69073
- constructor() {
69074
- /**
69075
- *
69076
- * @type {string|null}
69077
- */
69078
- this.__url = null;
69078
+ /**
69079
+ * Allows settings a new material to all parts of the mesh
69080
+ * @type {Material|null}
69081
+ */
69082
+ #material_override = null;
69079
69083
 
69080
- /**
69081
- *
69082
- * @type {EntityNode|null}
69083
- * @private
69084
- */
69085
- this.__node = null;
69084
+ /**
69085
+ *
69086
+ * @type {number}
69087
+ */
69088
+ flags = DEFAULT_FLAGS$4;
69086
69089
 
69087
- /**
69088
- *
69089
- * @type {AABB3}
69090
- * @private
69091
- */
69092
- this.__initial_bounds = new AABB3();
69090
+ /**
69091
+ *
69092
+ * @type {string|null}
69093
+ */
69094
+ __url = null;
69093
69095
 
69094
- /**
69095
- *
69096
- * @type {number}
69097
- */
69098
- this.flags = DEFAULT_FLAGS$4;
69096
+ /**
69097
+ *
69098
+ * @type {EntityNode|null}
69099
+ * @private
69100
+ */
69101
+ __node = null;
69102
+
69103
+ /**
69104
+ *
69105
+ * @type {AABB3}
69106
+ * @private
69107
+ */
69108
+ __initial_bounds = new AABB3();
69109
+
69110
+ /**
69111
+ *
69112
+ * @param {Material} v
69113
+ */
69114
+ set materialOverride(v) {
69115
+ if (v === this.#material_override) {
69116
+ return;
69117
+ }
69118
+
69119
+ if (v === null) {
69120
+ throw new Error(`Once material override is set it can not be cleared, create a new SGMesh instance if you would like to clear override`);
69121
+ }
69122
+
69123
+ this.#material_override = v;
69124
+
69125
+ this.applyMaterialOverride();
69126
+ }
69127
+
69128
+ get materialOverride() {
69129
+ return this.#material_override;
69130
+ }
69131
+
69132
+ applyMaterialOverride() {
69133
+ if (this.__node === null) {
69134
+ return;
69135
+ }
69136
+
69137
+ this.__node.traverse(node => {
69138
+ const sg = node.entity.getComponent(ShadedGeometry);
69139
+
69140
+ if (sg !== null) {
69141
+ sg.material = this.#material_override;
69142
+ }
69143
+ });
69099
69144
  }
69100
69145
 
69101
69146
  /**
@@ -71977,35 +72022,6 @@ class TerrainSystem extends System {
71977
72022
  }
71978
72023
  }
71979
72024
 
71980
- /**
71981
- *
71982
- * @param {string} url
71983
- * @return {String|null}
71984
- */
71985
- function assetTypeByPath(url) {
71986
- //get extension
71987
- const dotPosition = url.lastIndexOf(".");
71988
- if (dotPosition === -1) {
71989
- console.warn(`No model extension could be deduced for URL: '${url}'`);
71990
- //no extension
71991
- return null;
71992
- } else {
71993
- //retrieve extension
71994
- const ext = url.substring(dotPosition + 1);
71995
- switch (ext) {
71996
- case "json":
71997
- return "three.js";
71998
- case "glb":
71999
- return "model/gltf";
72000
- case "gltf":
72001
- return "model/gltf+json";
72002
- default:
72003
- console.warn(`Unknown 3d mesh format extension: '${ext}'`);
72004
- return null;
72005
- }
72006
- }
72007
- }
72008
-
72009
72025
  /**
72010
72026
  * Component representing logical attachment to another entity, when parent disappears - so does the child
72011
72027
  */
@@ -74618,13 +74634,13 @@ const EntityFlags = {
74618
74634
  */
74619
74635
  Built: 1,
74620
74636
  /**
74621
- * If component type is not registered on the {@link EntityComponentDataset} when calling {@link EntityBuilder#build} - will register the component first
74637
+ * If component type is not registered on the {@link EntityComponentDataset} when calling {@link Entity#build} - will register the component first
74622
74638
  */
74623
74639
  RegisterComponents: 2,
74624
74640
  /**
74625
- * Entity builder will watch destruction of the entity (subscribe to event), this will make the {@link EntityBuilder} automatically
74626
- * recognize when the corresponding entity is destroyed outside the EntityBuilder API
74627
- * NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the EntityBuilder
74641
+ * Entity builder will watch destruction of the entity (subscribe to event), this will make the {@link Entity} automatically
74642
+ * recognize when the corresponding entity is destroyed outside the {@link Entity} API
74643
+ * NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the {@link Entity}
74628
74644
  */
74629
74645
  WatchDestruction: 4
74630
74646
  };
@@ -74645,9 +74661,10 @@ const DEFAULT_FLAGS$3 =
74645
74661
  class Entity {
74646
74662
 
74647
74663
  /**
74664
+ * When entity is live - this is the entity ID inside associated `EntityComponentDataset`, when the entity is not live - it's set to -1
74648
74665
  * @type {number}
74649
74666
  */
74650
- entity = void 0;
74667
+ id = -1;
74651
74668
 
74652
74669
  /**
74653
74670
  * Generation is a unique identifier coming from the dataset
@@ -74657,16 +74674,17 @@ class Entity {
74657
74674
  generation = -1;
74658
74675
 
74659
74676
  /**
74660
- *
74677
+ * Components associated with the entity
74678
+ * @readonly
74661
74679
  * @type {Array}
74662
74680
  */
74663
- element = [];
74681
+ components = [];
74664
74682
 
74665
74683
  /**
74666
74684
  *
74667
74685
  * @type {{name:string,listener:(function|Function), context:*}[]}
74668
74686
  */
74669
- deferredListeners = [];
74687
+ #deferredListeners = [];
74670
74688
 
74671
74689
  /**
74672
74690
  *
@@ -74681,7 +74699,7 @@ class Entity {
74681
74699
  flags = DEFAULT_FLAGS$3;
74682
74700
 
74683
74701
  /**
74684
- *
74702
+ * Arbitrary metadata, add anything you want here
74685
74703
  * @type {Object}
74686
74704
  */
74687
74705
  properties = {};
@@ -74697,7 +74715,7 @@ class Entity {
74697
74715
  * Handles event when entity is removed without invoking {@link #destroy} method
74698
74716
  * @private
74699
74717
  */
74700
- __handleEntityDestroyed() {
74718
+ #handleEntityDestroyed() {
74701
74719
  this.clearFlag(EntityFlags.Built);
74702
74720
  }
74703
74721
 
@@ -74740,7 +74758,7 @@ class Entity {
74740
74758
  * Remove all components from the entity
74741
74759
  */
74742
74760
  removeAllComponents() {
74743
- const elements = this.element;
74761
+ const elements = this.components;
74744
74762
  const n = elements.length;
74745
74763
  for (let i = n - 1; i >= 0; i--) {
74746
74764
  const component = elements[i];
@@ -74754,7 +74772,7 @@ class Entity {
74754
74772
  * @return {number}
74755
74773
  */
74756
74774
  get count() {
74757
- return this.element.length;
74775
+ return this.components.length;
74758
74776
  }
74759
74777
 
74760
74778
  /**
@@ -74764,16 +74782,16 @@ class Entity {
74764
74782
  */
74765
74783
  add(componentInstance) {
74766
74784
  if (componentInstance === undefined) {
74767
- throw new Error(`Can not add ${componentInstance} to EntityBuilder`);
74785
+ throw new Error(`Can not add ${componentInstance} to Entity`);
74768
74786
  }
74769
74787
 
74770
74788
  assert.notOk(this.hasComponent(Object.getPrototypeOf(componentInstance).constructor), 'Component of this type already exists');
74771
74789
 
74772
- this.element.push(componentInstance);
74790
+ this.components.push(componentInstance);
74773
74791
 
74774
74792
  if (this.getFlag(EntityFlags.Built)) {
74775
74793
  //already built, add component to entity
74776
- this.dataset.addComponentToEntity(this.entity, componentInstance);
74794
+ this.dataset.addComponentToEntity(this.id, componentInstance);
74777
74795
  }
74778
74796
 
74779
74797
  return this;
@@ -74794,7 +74812,7 @@ class Entity {
74794
74812
  * @returns {T|null} component of specified class
74795
74813
  */
74796
74814
  getComponent(klass) {
74797
- const elements = this.element;
74815
+ const elements = this.components;
74798
74816
  const element_count = elements.length;
74799
74817
 
74800
74818
  for (let i = 0; i < element_count; i++) {
@@ -74828,7 +74846,7 @@ class Entity {
74828
74846
  * @returns {*|null}
74829
74847
  */
74830
74848
  removeComponent(klass) {
74831
- const elements = this.element;
74849
+ const elements = this.components;
74832
74850
  const n = elements.length;
74833
74851
 
74834
74852
  for (let i = 0; i < n; i++) {
@@ -74840,7 +74858,7 @@ class Entity {
74840
74858
  //see if entity is built
74841
74859
  if (this.getFlag(EntityFlags.Built)) {
74842
74860
 
74843
- this.dataset.removeComponentFromEntity(this.entity, klass);
74861
+ this.dataset.removeComponentFromEntity(this.id, klass);
74844
74862
 
74845
74863
  }
74846
74864
 
@@ -74858,7 +74876,7 @@ class Entity {
74858
74876
  */
74859
74877
  sendEvent(eventName, event) {
74860
74878
  if (this.getFlag(EntityFlags.Built)) {
74861
- this.dataset.sendEvent(this.entity, eventName, event);
74879
+ this.dataset.sendEvent(this.id, eventName, event);
74862
74880
  } else {
74863
74881
  console.warn("Entity doesn't exist. Event " + eventName + ":" + event + " was not sent.");
74864
74882
  }
@@ -74894,9 +74912,9 @@ class Entity {
74894
74912
  */
74895
74913
  addEventListener(eventName, listener, context) {
74896
74914
  if (this.getFlag(EntityFlags.Built)) {
74897
- this.dataset.addEntityEventListener(this.entity, eventName, listener, context);
74915
+ this.dataset.addEntityEventListener(this.id, eventName, listener, context);
74898
74916
  } else {
74899
- this.deferredListeners.push({
74917
+ this.#deferredListeners.push({
74900
74918
  name: eventName,
74901
74919
  listener: listener,
74902
74920
  context
@@ -74914,9 +74932,9 @@ class Entity {
74914
74932
  */
74915
74933
  removeEventListener(eventName, listener, context) {
74916
74934
  if (this.getFlag(EntityFlags.Built)) {
74917
- this.dataset.removeEntityEventListener(this.entity, eventName, listener, context);
74935
+ this.dataset.removeEntityEventListener(this.id, eventName, listener, context);
74918
74936
  } else {
74919
- const listeners = this.deferredListeners;
74937
+ const listeners = this.#deferredListeners;
74920
74938
 
74921
74939
  for (let i = 0, numListeners = listeners.length; i < numListeners; i++) {
74922
74940
  const deferredDescriptor = listeners[i];
@@ -74945,16 +74963,16 @@ class Entity {
74945
74963
  if (this.getFlag(EntityFlags.Built)) {
74946
74964
 
74947
74965
  const dataset = this.dataset;
74948
- const entity = this.entity;
74966
+ const entity = this.id;
74949
74967
 
74950
74968
  //check that the entity is the same as what we have built
74951
- //assert.ok(checkExistingComponents(entity, this.element, dataset), `Signature of EntityBuilder does not match existing entity(id=${entity})`);
74969
+ //assert.ok(checkExistingComponents(entity, this.element, dataset), `Signature of Entity does not match existing entity(id=${entity})`);
74952
74970
 
74953
- dataset.removeEntityEventListener(entity, EventType.EntityRemoved, this.__handleEntityDestroyed, this);
74971
+ dataset.removeEntityEventListener(entity, EventType.EntityRemoved, this.#handleEntityDestroyed, this);
74954
74972
 
74955
74973
  dataset.removeEntity(entity);
74956
74974
 
74957
- this.entity = void 0;
74975
+ this.id = -1;
74958
74976
 
74959
74977
  this.clearFlag(EntityFlags.Built);
74960
74978
 
@@ -74975,18 +74993,18 @@ class Entity {
74975
74993
 
74976
74994
  if (
74977
74995
  this.getFlag(EntityFlags.Built)
74978
- && checkExistingComponents(this.entity, this.element, dataset)
74996
+ && checkExistingComponents(this.id, this.components, dataset)
74979
74997
  ) {
74980
74998
  //already built
74981
- return this.entity;
74999
+ return this.id;
74982
75000
  }
74983
75001
 
74984
- const entity = this.entity = dataset.createEntity();
75002
+ const entity = this.id = dataset.createEntity();
74985
75003
  this.dataset = dataset;
74986
75004
 
74987
75005
  let i;
74988
75006
 
74989
- const listeners = this.deferredListeners;
75007
+ const listeners = this.#deferredListeners;
74990
75008
  const listeners_count = listeners.length;
74991
75009
 
74992
75010
  for (i = 0; i < listeners_count; i++) {
@@ -74994,9 +75012,9 @@ class Entity {
74994
75012
  dataset.addEntityEventListener(entity, subscription.name, subscription.listener, subscription.context);
74995
75013
  }
74996
75014
  // reset listeners
74997
- this.deferredListeners.splice(0, listeners_count);
75015
+ this.#deferredListeners.splice(0, listeners_count);
74998
75016
 
74999
- const element = this.element;
75017
+ const element = this.components;
75000
75018
  const element_count = element.length;
75001
75019
 
75002
75020
  if (this.getFlag(EntityFlags.RegisterComponents)) {
@@ -75016,7 +75034,7 @@ class Entity {
75016
75034
  this.setFlag(EntityFlags.Built);
75017
75035
 
75018
75036
  if (this.getFlag(EntityFlags.WatchDestruction)) {
75019
- dataset.addEntityEventListener(entity, EventType.EntityRemoved, this.__handleEntityDestroyed, this);
75037
+ dataset.addEntityEventListener(entity, EventType.EntityRemoved, this.#handleEntityDestroyed, this);
75020
75038
  }
75021
75039
 
75022
75040
  this.on.built.send2(entity, dataset);
@@ -75024,7 +75042,7 @@ class Entity {
75024
75042
  }
75025
75043
 
75026
75044
  /**
75027
- *
75045
+ * Extract data about an entity and its components from a dataset
75028
75046
  * @param {number} entity
75029
75047
  * @param {EntityComponentDataset} dataset
75030
75048
  * @returns {Entity}
@@ -75037,7 +75055,7 @@ class Entity {
75037
75055
  .forEach(r.add, r);
75038
75056
 
75039
75057
  r.setFlag(EntityFlags.Built);
75040
- r.entity = entity;
75058
+ r.id = entity;
75041
75059
  r.dataset = dataset;
75042
75060
 
75043
75061
  return r;
@@ -75045,10 +75063,11 @@ class Entity {
75045
75063
  }
75046
75064
 
75047
75065
  /**
75066
+ * Useful for faster alternative to `instanceof` checks
75048
75067
  * @readonly
75049
75068
  * @type {boolean}
75050
75069
  */
75051
- Entity.prototype.isEntityBuilder = true;
75070
+ Entity.prototype.isEntity = true;
75052
75071
 
75053
75072
 
75054
75073
  /**
@@ -75446,7 +75465,7 @@ class EntityNode {
75446
75465
  throw new Error('Parent entity is not built');
75447
75466
  }
75448
75467
 
75449
- const parent_entity_id = parent_entity_builder.entity;
75468
+ const parent_entity_id = parent_entity_builder.id;
75450
75469
  parent_entity.entity = parent_entity_id;
75451
75470
 
75452
75471
  // add component back
@@ -75571,7 +75590,7 @@ class EntityNode {
75571
75590
  throw new Error('Parent entity is not built');
75572
75591
  }
75573
75592
 
75574
- const parent_entity_id = parent_entity_builder.entity;
75593
+ const parent_entity_id = parent_entity_builder.id;
75575
75594
  parent_entity.entity = parent_entity_id;
75576
75595
 
75577
75596
  assert.ok(parent.entity.hasComponent(Transform), "parent node must have a transform but doesn't. Transform is required for attachment transform hierarchy to work correctly");
@@ -75639,80 +75658,6 @@ class EntityNode {
75639
75658
  */
75640
75659
  EntityNode.prototype.isEntityNode = true;
75641
75660
 
75642
- /**
75643
- *
75644
- * @param {Transform} transform
75645
- * @param {THREE.Object3D} three_object
75646
- */
75647
- function copy_three_transform(transform, three_object) {
75648
-
75649
- // copy object transform
75650
- transform.position.copy(three_object.position);
75651
- transform.scale.copy(three_object.scale);
75652
- transform.rotation.copy(three_object.quaternion);
75653
-
75654
- //
75655
- transform.matrix.set(three_object.matrix.elements);
75656
- }
75657
-
75658
- /**
75659
- *
75660
- * @param {THREE.Object3D} root
75661
- * @returns {EntityNode}
75662
- */
75663
- function three_object_to_entity_composition(root) {
75664
- const node = new EntityNode();
75665
-
75666
- const node_transform = node.transform;
75667
-
75668
- // copy object transform
75669
- copy_three_transform(node_transform, root);
75670
-
75671
- const entity = node.entity;
75672
-
75673
- const transform = new Transform();
75674
- // initialize world transform
75675
- transform.fromMatrix4(root.matrixWorld.elements);
75676
-
75677
- entity.add(transform);
75678
-
75679
- if (root.isMesh) {
75680
- if (root.isSkinnedMesh) {
75681
- console.error(`Skinned meshes are not supported`);
75682
- }
75683
-
75684
- const sg = ShadedGeometry.from(root.geometry, root.material);
75685
-
75686
- entity.add(sg);
75687
- }
75688
-
75689
- const children = root.children;
75690
- const child_count = children.length;
75691
-
75692
- for (let i = 0; i < child_count; i++) {
75693
- const child = children[i];
75694
-
75695
- const child_node = three_object_to_entity_composition(child);
75696
-
75697
- node.addChild(child_node);
75698
- }
75699
-
75700
- return node;
75701
- }
75702
-
75703
- const SGMeshEvents = {
75704
-
75705
- /**
75706
- * When asset is attached/loaded onto the Mesh component.
75707
- * This is the time when the 3d data becomes renderable
75708
- */
75709
- AssetLoaded: '@ecd-component-SGMesh/asset-attached',
75710
- /**
75711
- * Required asset failed to load for whatever reason
75712
- */
75713
- AssetLoadFailed: '@ecd-component-SGMesh/asset-failed',
75714
- };
75715
-
75716
75661
  /**
75717
75662
  * @readonly
75718
75663
  * @type {number}
@@ -75935,6 +75880,109 @@ class TransformAttachmentSystem extends System {
75935
75880
  }
75936
75881
  }
75937
75882
 
75883
+ /**
75884
+ *
75885
+ * @param {string} url
75886
+ * @return {String|null}
75887
+ */
75888
+ function assetTypeByPath(url) {
75889
+ //get extension
75890
+ const dotPosition = url.lastIndexOf(".");
75891
+ if (dotPosition === -1) {
75892
+ console.warn(`No model extension could be deduced for URL: '${url}'`);
75893
+ //no extension
75894
+ return null;
75895
+ } else {
75896
+ //retrieve extension
75897
+ const ext = url.substring(dotPosition + 1);
75898
+ switch (ext) {
75899
+ case "json":
75900
+ return "three.js";
75901
+ case "glb":
75902
+ return "model/gltf";
75903
+ case "gltf":
75904
+ return "model/gltf+json";
75905
+ default:
75906
+ console.warn(`Unknown 3d mesh format extension: '${ext}'`);
75907
+ return null;
75908
+ }
75909
+ }
75910
+ }
75911
+
75912
+ /**
75913
+ *
75914
+ * @param {Transform} transform
75915
+ * @param {THREE.Object3D} three_object
75916
+ */
75917
+ function copy_three_transform(transform, three_object) {
75918
+
75919
+ // copy object transform
75920
+ transform.position.copy(three_object.position);
75921
+ transform.scale.copy(three_object.scale);
75922
+ transform.rotation.copy(three_object.quaternion);
75923
+
75924
+ //
75925
+ transform.matrix.set(three_object.matrix.elements);
75926
+ }
75927
+
75928
+ /**
75929
+ *
75930
+ * @param {THREE.Object3D} root
75931
+ * @returns {EntityNode}
75932
+ */
75933
+ function three_object_to_entity_composition(root) {
75934
+ const node = new EntityNode();
75935
+
75936
+ const node_transform = node.transform;
75937
+
75938
+ // copy object transform
75939
+ copy_three_transform(node_transform, root);
75940
+
75941
+ const entity = node.entity;
75942
+
75943
+ const transform = new Transform();
75944
+ // initialize world transform
75945
+ transform.fromMatrix4(root.matrixWorld.elements);
75946
+
75947
+ entity.add(transform);
75948
+
75949
+ if (root.isMesh) {
75950
+ if (root.isSkinnedMesh) {
75951
+ console.error(`Skinned meshes are not supported`);
75952
+ }
75953
+
75954
+ const sg = ShadedGeometry.from(root.geometry, root.material);
75955
+
75956
+ entity.add(sg);
75957
+ }
75958
+
75959
+ const children = root.children;
75960
+ const child_count = children.length;
75961
+
75962
+ for (let i = 0; i < child_count; i++) {
75963
+ const child = children[i];
75964
+
75965
+ const child_node = three_object_to_entity_composition(child);
75966
+
75967
+ node.addChild(child_node);
75968
+ }
75969
+
75970
+ return node;
75971
+ }
75972
+
75973
+ const SGMeshEvents = {
75974
+
75975
+ /**
75976
+ * When asset is attached/loaded onto the Mesh component.
75977
+ * This is the time when the 3d data becomes renderable
75978
+ */
75979
+ AssetLoaded: '@ecd-component-SGMesh/asset-attached',
75980
+ /**
75981
+ * Required asset failed to load for whatever reason
75982
+ */
75983
+ AssetLoadFailed: '@ecd-component-SGMesh/asset-failed',
75984
+ };
75985
+
75938
75986
  /**
75939
75987
  * @readonly
75940
75988
  * @type {number}
@@ -76099,6 +76147,8 @@ class SGMeshSystem extends System {
76099
76147
 
76100
76148
  });
76101
76149
 
76150
+ const material_override = mesh.materialOverride;
76151
+
76102
76152
  // apply flags to the hierarchy
76103
76153
  entity_node.traverse(node => {
76104
76154
  /**
@@ -76112,6 +76162,10 @@ class SGMeshSystem extends System {
76112
76162
 
76113
76163
  sg.writeFlag(ShadedGeometryFlags.CastShadow, mesh.castShadow);
76114
76164
  sg.writeFlag(ShadedGeometryFlags.ReceiveShadow, mesh.receiveShadow);
76165
+
76166
+ if (material_override !== null) {
76167
+ sg.material = material_override;
76168
+ }
76115
76169
  });
76116
76170
 
76117
76171
 
@@ -78436,11 +78490,17 @@ function build_three_object(sg) {
78436
78490
  return object;
78437
78491
  }
78438
78492
 
78493
+ class CacheValue {
78494
+ object = null
78495
+ key = null
78496
+ }
78497
+
78498
+
78439
78499
  class SGThreeObjectCache {
78440
78500
  constructor() {
78441
78501
  /**
78442
78502
  *
78443
- * @type {WeakMap<ShadedGeometry, THREE.Object3D>}
78503
+ * @type {Map<ShadedGeometry, CacheValue>}
78444
78504
  * @private
78445
78505
  */
78446
78506
  this.__object_cache = new WeakMap();
@@ -78453,15 +78513,28 @@ class SGThreeObjectCache {
78453
78513
  */
78454
78514
  get(sg) {
78455
78515
 
78456
- const existing_object = this.__object_cache.get(sg);
78516
+ const existing_value = this.__object_cache.get(sg);
78457
78517
 
78458
- if (existing_object !== undefined) {
78459
- return existing_object;
78518
+ if (existing_value !== undefined) {
78519
+ const object = existing_value.object;
78520
+
78521
+ // validate that the object is still the same
78522
+ if (existing_value.key.equals(sg)) {
78523
+ return object;
78524
+ }
78460
78525
  }
78461
78526
 
78462
- const new_object = build_three_object(sg);
78527
+ // replace scratch key as it's being used inside the cache now
78528
+ const key = sg.clone();
78463
78529
 
78464
- this.__object_cache.set(sg, new_object);
78530
+ const new_object = build_three_object(key);
78531
+
78532
+ const cacheValue = new CacheValue();
78533
+
78534
+ cacheValue.key = key;
78535
+ cacheValue.object = new_object;
78536
+
78537
+ this.__object_cache.set(sg, cacheValue);
78465
78538
 
78466
78539
  return new_object;
78467
78540
  }
@@ -92564,7 +92637,7 @@ Preloader.prototype.load = function (assetManager) {
92564
92637
 
92565
92638
  /**
92566
92639
  *
92567
- * @param {*} entityIndex
92640
+ * @param {number} entityIndex
92568
92641
  * @returns {boolean}
92569
92642
  */
92570
92643
  function validateEntityIndex(entityIndex) {
@@ -92573,7 +92646,7 @@ function validateEntityIndex(entityIndex) {
92573
92646
 
92574
92647
  /**
92575
92648
  *
92576
- * @param {*} componentIndex
92649
+ * @param {number} componentIndex
92577
92650
  * @returns {boolean}
92578
92651
  */
92579
92652
  function validateComponentIndex(componentIndex) {
@@ -92582,7 +92655,7 @@ function validateComponentIndex(componentIndex) {
92582
92655
 
92583
92656
  /**
92584
92657
  *
92585
- * @param index
92658
+ * @param {number} index
92586
92659
  * @param {string} name
92587
92660
  * @returns {boolean}
92588
92661
  */
@@ -92656,99 +92729,101 @@ function buildObserverCallbackArgs(entityIndex, mask, componentIndexMap, compone
92656
92729
  const scratch_array_0 = [];
92657
92730
  const scratch_array_1 = [];
92658
92731
 
92732
+ /**
92733
+ * Represents a storage for entities and their associated components
92734
+ * Entities are just integer IDs and components are stored in a virtual table, where each component type has a separate column and each entity is a row in that table
92735
+ * It is valid for entities to have no components or to have every possible component
92736
+ * Generally the entity IDs are compacted, meaning that when an entity is removed - it's ID will be later reused
92737
+ */
92659
92738
  class EntityComponentDataset {
92739
+
92660
92740
  /**
92661
- * @class
92662
- * @constructor
92741
+ * @private
92742
+ * @type {BitSet}
92663
92743
  */
92664
- constructor() {
92665
- /**
92666
- * @private
92667
- * @type {BitSet}
92668
- */
92669
- this.entityOccupancy = new BitSet();
92670
- /**
92671
- * @private
92672
- * @type {BitSet}
92673
- */
92674
- this.componentOccupancy = new BitSet();
92744
+ entityOccupancy = new BitSet();
92745
+ /**
92746
+ * @private
92747
+ * @type {BitSet}
92748
+ */
92749
+ componentOccupancy = new BitSet();
92675
92750
 
92676
- /**
92677
- * @private
92678
- * @type {Class[]}
92679
- */
92680
- this.componentTypeMap = [];
92751
+ /**
92752
+ * @private
92753
+ * @type {Class[]}
92754
+ */
92755
+ componentTypeMap = [];
92681
92756
 
92682
- /**
92683
- * Fast index lookup from a component class
92684
- * @type {Map<Class, number>}
92685
- * @private
92686
- */
92687
- this.__type_to_index_map = new Map();
92757
+ /**
92758
+ * Fast index lookup from a component class
92759
+ * @type {Map<Class, number>}
92760
+ * @private
92761
+ */
92762
+ __type_to_index_map = new Map();
92688
92763
 
92689
- /**
92690
- * How many component types exist for this collection. This is the same as componentMap.length
92691
- * @private
92692
- * @type {number}
92693
- */
92694
- this.componentTypeCount = 0;
92764
+ /**
92765
+ * How many component types exist for this collection. This is the same as componentMap.length
92766
+ * @private
92767
+ * @type {number}
92768
+ */
92769
+ componentTypeCount = 0;
92695
92770
 
92696
- /**
92697
- * @private
92698
- * @type {Object[][]}
92699
- */
92700
- this.components = [];
92771
+ /**
92772
+ * @private
92773
+ * @type {Object[][]}
92774
+ */
92775
+ components = [];
92701
92776
 
92702
- /**
92703
- * Current number of entities
92704
- * @private
92705
- * @type {number}
92706
- */
92707
- this.entityCount = 0;
92777
+ /**
92778
+ * Current number of entities
92779
+ * @private
92780
+ * @type {number}
92781
+ */
92782
+ entityCount = 0;
92708
92783
 
92709
- /**
92710
- * A counter that is incremented every time an entity is created
92711
- * Generation is used to provide an entity with a unique identity
92712
- * Entity IDs are re-used, but generation is always increasing
92713
- * Two entities with the same ID but different generation represent two distinct entities, one with "younger" generation (larger number) is the more recently created one
92714
- * @private
92715
- * @type {number}
92716
- */
92717
- this.generation = 0;
92784
+ /**
92785
+ * A counter that is incremented every time an entity is created
92786
+ * Generation is used to provide an entity with a unique identity
92787
+ * Entity IDs are re-used, but generation is always increasing
92788
+ * Two entities with the same ID but different generation represent two distinct entities, one with "younger" generation (larger number) is the more recently created one
92789
+ * @private
92790
+ * @type {number}
92791
+ */
92792
+ generation = 0;
92718
92793
 
92719
- /**
92720
- * @readonly
92721
- * @type {Signal}
92722
- */
92723
- this.onEntityCreated = new Signal();
92794
+ /**
92795
+ * @readonly
92796
+ * @type {Signal}
92797
+ */
92798
+ onEntityCreated = new Signal();
92724
92799
 
92725
- /**
92726
- * @readonly
92727
- * @type {Signal}
92728
- */
92729
- this.onEntityRemoved = new Signal();
92800
+ /**
92801
+ * @readonly
92802
+ * @type {Signal}
92803
+ */
92804
+ onEntityRemoved = new Signal();
92730
92805
 
92731
92806
 
92732
- /**
92733
- *
92734
- * @type {Array<Object<SignalHandler[]>>}
92735
- * @private
92736
- */
92737
- this.__entityEventListeners = [];
92807
+ /**
92808
+ *
92809
+ * @type {Array<Object<SignalHandler[]>>}
92810
+ * @private
92811
+ */
92812
+ __entityEventListeners = [];
92738
92813
 
92739
- /**
92740
- *
92741
- * @type {SignalHandler[][]}
92742
- * @private
92743
- */
92744
- this.__entityAnyEventListeners = [];
92814
+ /**
92815
+ *
92816
+ * @type {SignalHandler[][]}
92817
+ * @private
92818
+ */
92819
+ __entityAnyEventListeners = [];
92820
+
92821
+ /**
92822
+ * @private
92823
+ * @type {Array<Array<EntityObserver>>}
92824
+ */
92825
+ observers = [];
92745
92826
 
92746
- /**
92747
- * @private
92748
- * @type {Array<Array<EntityObserver>>}
92749
- */
92750
- this.observers = [];
92751
- }
92752
92827
 
92753
92828
  /**
92754
92829
  * returns a promise of a component instance based on a given type
@@ -93438,7 +93513,7 @@ class EntityComponentDataset {
93438
93513
  const componentClass = this.componentTypeMap[componentIndex];
93439
93514
 
93440
93515
  //dispatch event to components
93441
- this.sendEvent(entityIndex, EventType.ComponentRemoved, { klass: componentClass, instance: componentInstance });
93516
+ this.sendEvent(entityIndex, EventType.ComponentRemoved, {klass: componentClass, instance: componentInstance});
93442
93517
  }
93443
93518
 
93444
93519
  /**
@@ -93550,7 +93625,7 @@ class EntityComponentDataset {
93550
93625
  const componentClass = this.componentTypeMap[componentIndex];
93551
93626
 
93552
93627
  //dispatch event to components
93553
- this.sendEvent(entityIndex, EventType.ComponentAdded, { klass: componentClass, instance: componentInstance });
93628
+ this.sendEvent(entityIndex, EventType.ComponentAdded, {klass: componentClass, instance: componentInstance});
93554
93629
  }
93555
93630
 
93556
93631
  /**
@@ -100360,28 +100435,21 @@ function parseTooltipString(text) {
100360
100435
 
100361
100436
  class TooltipParser {
100362
100437
 
100363
- constructor() {
100364
-
100365
- /**
100366
- *
100367
- * @type {Cache<String,Token[]>}
100368
- * @private
100369
- */
100370
- this.__cache = new Cache({
100371
- maxWeight: 1048576,
100372
- keyWeigher: string_compute_byte_size,
100373
- valueWeigher(tokens) {
100374
- return tokens.length * 256;
100375
- },
100376
- keyHashFunction: computeStringHash,
100377
- keyEqualityFunction: strictEquals
100378
- });
100379
-
100380
- }
100381
100438
 
100382
- resetCache() {
100383
- this.__cache.clear();
100384
- }
100439
+ /**
100440
+ *
100441
+ * @type {Cache<String,Token[]>}
100442
+ * @private
100443
+ */
100444
+ #cache = new Cache({
100445
+ maxWeight: 1048576,
100446
+ keyWeigher: string_compute_byte_size,
100447
+ valueWeigher(tokens) {
100448
+ return tokens.length * 256;
100449
+ },
100450
+ keyHashFunction: computeStringHash,
100451
+ keyEqualityFunction: strictEquals
100452
+ });
100385
100453
 
100386
100454
  /**
100387
100455
  *
@@ -100390,7 +100458,7 @@ class TooltipParser {
100390
100458
  */
100391
100459
  parse(code) {
100392
100460
 
100393
- const existing = this.__cache.get(code);
100461
+ const existing = this.#cache.get(code);
100394
100462
 
100395
100463
  if (existing !== null) {
100396
100464
  // result is cached, reuse
@@ -100401,7 +100469,7 @@ class TooltipParser {
100401
100469
  const tokens = parseTooltipString(code);
100402
100470
 
100403
100471
  // cache result
100404
- this.__cache.put(code, tokens);
100472
+ this.#cache.put(code, tokens);
100405
100473
 
100406
100474
  return tokens;
100407
100475
  }
@@ -103151,7 +103219,7 @@ class NotificationManager {
103151
103219
  //find existing entry
103152
103220
  for (const [view, builder] of views) {
103153
103221
 
103154
- if (builder.entity === entity) {
103222
+ if (builder.id === entity) {
103155
103223
  //clear from the map
103156
103224
  views.delete(view);
103157
103225
  break;
@@ -103900,68 +103968,47 @@ class SceneGUIContext {
103900
103968
  */
103901
103969
 
103902
103970
 
103903
- function GUIEngine() {
103904
- this.windows = new List();
103905
-
103906
- /**
103907
- * When set to 'true' - indicated that GUI engine should be the only one receiving the inputs, this is useful for Modal dialogs and other overlays
103908
- * @readonly
103909
- * @type {ObservedBoolean}
103910
- */
103911
- this.captureInputs = new ObservedBoolean(false);
103971
+ class GUIEngine {
103972
+ windows = new List();
103912
103973
 
103913
103974
  /**
103914
103975
  *
103915
103976
  * @type {EntityManager|null}
103916
103977
  */
103917
- this.entityManager = null;
103978
+ entityManager = null;
103918
103979
 
103919
103980
  /**
103920
103981
  *
103921
103982
  * @type {Engine}
103922
103983
  */
103923
- this.engine = null;
103984
+ engine = null;
103924
103985
 
103925
103986
  /**
103926
103987
  *
103927
103988
  * @type {WeakMap<Scene, SceneGUIContext>}
103928
103989
  */
103929
- this.sceneContexts = new WeakMap();
103990
+ sceneContexts = new WeakMap();
103930
103991
 
103931
103992
  /**
103932
103993
  *
103933
103994
  * @type {TooltipManager}
103934
103995
  */
103935
- this.tooltips = new TooltipManager();
103996
+ tooltips = new TooltipManager();
103936
103997
 
103937
103998
  /**
103938
103999
  *
103939
104000
  * @type {DomTooltipManager}
103940
104001
  */
103941
- this.viewTooltips = new DomTooltipManager(this.tooltips);
104002
+ viewTooltips = new DomTooltipManager(this.tooltips);
103942
104003
 
103943
104004
 
103944
104005
  /**
103945
104006
  *
103946
104007
  * @type {Ticker}
103947
104008
  */
103948
- this.ticker = new Ticker();
103949
- this.ticker.subscribe(d => {
103950
-
103951
-
103952
- let ctx = null;
103953
- try {
103954
- ctx = this.getActiveSceneContext();
103955
- } catch (e) {
103956
- //skip
103957
- }
103958
-
103959
- if (ctx !== null) {
103960
- ctx.tick(d);
103961
- }
103962
- });
104009
+ ticker = new Ticker();
103963
104010
 
103964
- this.view = new EmptyView({
104011
+ view = new EmptyView({
103965
104012
  classList: ['gui-engine-root'],
103966
104013
  css: {
103967
104014
  position: "absolute",
@@ -103974,459 +104021,478 @@ function GUIEngine() {
103974
104021
  *
103975
104022
  * @type {GMLEngine}
103976
104023
  */
103977
- this.gml = new GMLEngine();
104024
+ gml = new GMLEngine();
103978
104025
 
103979
104026
  /**
103980
104027
  *
103981
104028
  * @type {ObservedString}
103982
104029
  */
103983
- this.cursor = new ObservedString(CursorType.Normal);
104030
+ cursor = new ObservedString(CursorType.Normal);
103984
104031
 
103985
104032
 
103986
104033
  /**
103987
104034
  *
103988
104035
  * @type {Localization|null}
103989
104036
  */
103990
- this.localization = null;
103991
- }
104037
+ localization = null;
103992
104038
 
103993
- /**
103994
- * @param {boolean} closeable
103995
- * @param {View} content
103996
- * @param {string} title
103997
- * @param {View} [wrapper]
103998
- * @returns {Entity}
103999
- */
104000
- GUIEngine.prototype.openWindow = function ({ closeable, content, title, wrapper }) {
104001
- const entityBuilder = new Entity();
104039
+ constructor() {
104040
+
104041
+ this.ticker.subscribe(d => {
104042
+
104043
+
104044
+ let ctx = null;
104045
+ try {
104046
+ ctx = this.getActiveSceneContext();
104047
+ } catch (e) {
104048
+ //skip
104049
+ }
104050
+
104051
+ if (ctx !== null) {
104052
+ ctx.tick(d);
104053
+ }
104054
+ });
104002
104055
 
104003
- function closeAction() {
104004
- entityBuilder.destroy();
104005
104056
  }
104006
104057
 
104007
- const windowView = new SimpleWindowView(content, {
104008
- closeAction,
104009
- title,
104010
- closeable
104011
- });
104058
+ /**
104059
+ * @param {boolean} closeable
104060
+ * @param {View} content
104061
+ * @param {string} title
104062
+ * @param {View} [wrapper]
104063
+ * @returns {Entity}
104064
+ */
104065
+ openWindow({closeable, content, title, wrapper}) {
104066
+ const entityBuilder = new Entity();
104012
104067
 
104013
- entityBuilder.add(new ViewportPosition());
104068
+ function closeAction() {
104069
+ entityBuilder.destroy();
104070
+ }
104014
104071
 
104015
- let vElement;
104016
- if (wrapper !== undefined) {
104017
- vElement = wrapper;
104018
- wrapper.addChild(windowView);
104019
- } else {
104020
- vElement = windowView;
104072
+ const windowView = new SimpleWindowView(content, {
104073
+ closeAction,
104074
+ title,
104075
+ closeable
104076
+ });
104077
+
104078
+ entityBuilder.add(new ViewportPosition());
104079
+
104080
+ let vElement;
104081
+ if (wrapper !== undefined) {
104082
+ vElement = wrapper;
104083
+ wrapper.addChild(windowView);
104084
+ } else {
104085
+ vElement = windowView;
104086
+ }
104087
+
104088
+ const guiElement = GUIElement.fromView(vElement);
104089
+ entityBuilder.add(guiElement)
104090
+ .add(SerializationMetadata.Transient);
104091
+
104092
+ const dataset = this.entityManager.dataset;
104093
+
104094
+ animateView(windowView, dataset);
104095
+
104096
+ entityBuilder.build(dataset);
104097
+
104098
+ return entityBuilder;
104021
104099
  }
104022
104100
 
104023
- const guiElement = GUIElement.fromView(vElement);
104024
- entityBuilder.add(guiElement)
104025
- .add(SerializationMetadata.Transient);
104101
+ /**
104102
+ *
104103
+ * @param {View} content
104104
+ * @param {string} title
104105
+ * @param {number} priority
104106
+ * @returns {SimpleLifecycle}
104107
+ */
104108
+ createModal({content, title, priority = 0}) {
104109
+ const entityManager = this.entityManager;
104026
104110
 
104027
- const dataset = this.entityManager.dataset;
104111
+ const self = this;
104112
+ let window = null;
104113
+ let overlay = null;
104028
104114
 
104029
- animateView(windowView, dataset);
104030
104115
 
104031
- entityBuilder.build(dataset);
104116
+ function destroy() {
104117
+ window.destroy();
104118
+ overlay.destroy();
104119
+ }
104032
104120
 
104033
- return entityBuilder;
104034
- };
104121
+ function makeOverlay() {
104122
+ const overlay = new View();
104123
+ overlay.el = document.createElement('div');
104124
+ overlay.el.classList.add('ui-modal-overlay');
104125
+ //make overlay dismiss modal
104126
+ overlay.el.addEventListener('click', function (event) {
104127
+ event.stopPropagation();
104128
+ lifecycle.makeDestroyed();
104129
+ });
104035
104130
 
104036
- /**
104037
- *
104038
- * @param {View} view
104039
- * @param {EntityComponentDataset} ecd
104040
- */
104041
- function animateView(view, ecd) {
104131
+ const builder = new Entity();
104042
104132
 
104043
- const animationTrack = new AnimationTrack(["alpha", "scale"]);
104044
- animationTrack.addKey(0, [0, 0.95]);
104045
- animationTrack.addKey(0.2, [1, 1]);
104133
+ builder.add(SerializationMetadata.Transient);
104134
+ builder.add(GUIElement.fromView(overlay));
104135
+ return builder;
104136
+ }
104046
104137
 
104047
- animationTrack.addTransition(0, TransitionFunctions.Linear);
104138
+ function build() {
104139
+ overlay = makeOverlay();
104048
104140
 
104049
- const playback = new AnimationTrackPlayback(animationTrack, function (alpha, scale) {
104050
- this.el.style.opacity = alpha;
104051
- this.scale.set(scale, scale);
104052
- }, view);
104141
+ overlay.build(entityManager.dataset);
104053
104142
 
104054
- //force view status to initial key of animation
104055
- playback.update();
104143
+ const view = content;
104056
104144
 
104057
- playTrackRealTime(playback, ecd);
104058
- }
104145
+ const vModalContainer = new EmptyView({classList: ['ui-modal-window-container']});
104059
104146
 
104060
- /**
104061
- *
104062
- * @param {View} content
104063
- * @param {string} title
104064
- * @param {number} priority
104065
- * @returns {SimpleLifecycle}
104066
- */
104067
- GUIEngine.prototype.createModal = function ({ content, title, priority = 0 }) {
104068
- const entityManager = this.entityManager;
104147
+ window = self.openWindow({
104148
+ title: title,
104149
+ content: view,
104150
+ closeable: false,
104151
+ wrapper: vModalContainer
104152
+ });
104069
104153
 
104070
- const self = this;
104071
- let window = null;
104072
- let overlay = null;
104154
+ const windowGuiElement = window.getComponent(GUIElement);
104155
+ windowGuiElement.anchor.set(0.5, 0.5);
104073
104156
 
104157
+ window.removeComponent(ViewportPosition);
104074
104158
 
104075
- function destroy() {
104076
- window.destroy();
104077
- overlay.destroy();
104078
- }
104159
+ }
104079
104160
 
104080
- function makeOverlay() {
104081
- const overlay = new View();
104082
- overlay.el = document.createElement('div');
104083
- overlay.el.classList.add('ui-modal-overlay');
104084
- //make overlay dismiss modal
104085
- overlay.el.addEventListener('click', function (event) {
104086
- event.stopPropagation();
104087
- lifecycle.makeDestroyed();
104088
- });
104161
+ const lifecycle = new SimpleLifecycle({priority});
104089
104162
 
104090
- const builder = new Entity();
104163
+ lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Active, build);
104164
+ lifecycle.sm.addEventHandlerStateExit(SimpleLifecycleStateType.Active, destroy);
104165
+
104166
+ this.getActiveSceneContext().modals.add(lifecycle);
104091
104167
 
104092
- builder.add(SerializationMetadata.Transient);
104093
- builder.add(GUIElement.fromView(overlay));
104094
- return builder;
104168
+ return lifecycle;
104095
104169
  }
104096
104170
 
104097
- function build() {
104098
- overlay = makeOverlay();
104171
+ /**
104172
+ *
104173
+ * @param {string} title
104174
+ * @param {View} content
104175
+ * @param {ObservedBoolean|ReactiveExpression} [confirmationEnabled]
104176
+ * @returns {Promise<any>}
104177
+ */
104178
+ createModalConfirmation({title, content, confirmationEnabled}) {
104099
104179
 
104100
- overlay.build(entityManager.dataset);
104180
+ const self = this;
104101
104181
 
104102
- const view = content;
104182
+ let lifecycle = null;
104103
104183
 
104104
- const vModalContainer = new EmptyView({ classList: ['ui-modal-window-container'] });
104105
104184
 
104106
- window = self.openWindow({
104107
- title: title,
104108
- content: view,
104109
- closeable: false,
104110
- wrapper: vModalContainer
104111
- });
104185
+ const result = new Promise(function (resolve, reject) {
104186
+ //make view
104112
104187
 
104113
- const windowGuiElement = window.getComponent(GUIElement);
104114
- windowGuiElement.anchor.set(0.5, 0.5);
104188
+ let resolved = false;
104115
104189
 
104116
- window.removeComponent(ViewportPosition);
104190
+ function clear() {
104191
+ lifecycle.makeDestroyed();
104192
+ }
104117
104193
 
104118
- }
104194
+ function callbackYes() {
104195
+ resolved = true;
104196
+ clear();
104197
+ resolve();
104198
+ }
104119
104199
 
104120
- const lifecycle = new SimpleLifecycle({ priority });
104200
+ function callbackNo() {
104201
+ resolved = true;
104202
+ clear();
104203
+ reject();
104204
+ }
104121
104205
 
104122
- lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Active, build);
104123
- lifecycle.sm.addEventHandlerStateExit(SimpleLifecycleStateType.Active, destroy);
104206
+ const view = new ConfirmationDialogView(content,
104207
+ [{
104208
+ name: "yes",
104209
+ displayName: self.localization.getString("system_confirmation_confirm"),
104210
+ callback: callbackYes,
104211
+ enabled: confirmationEnabled
104212
+ }, {
104213
+ name: "no",
104214
+ displayName: self.localization.getString("system_confirmation_cancel"),
104215
+ callback: callbackNo
104216
+ }]
104217
+ );
104124
104218
 
104125
- this.getActiveSceneContext().modals.add(lifecycle);
104219
+ lifecycle = self.createModal({
104220
+ content: view,
104221
+ title: title
104222
+ });
104126
104223
 
104127
- return lifecycle;
104128
- };
104224
+ lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Destroyed, function () {
104225
+ if (!resolved) {
104226
+ //if destroyed without resolution, reject the promise
104227
+ reject();
104228
+ }
104229
+ });
104230
+ });
104129
104231
 
104130
- /**
104131
- *
104132
- * @param {string} title
104133
- * @param {View} content
104134
- * @param {ObservedBoolean|ReactiveExpression} [confirmationEnabled]
104135
- * @returns {Promise<any>}
104136
- */
104137
- GUIEngine.prototype.createModalConfirmation = function ({ title, content, confirmationEnabled }) {
104138
104232
 
104139
- const self = this;
104233
+ return result;
104234
+ }
104140
104235
 
104141
- let lifecycle = null;
104236
+ /**
104237
+ * @param {string} text
104238
+ * @param {string} title
104239
+ * @returns {Promise} will be resolved or rejected based on user choice
104240
+ */
104241
+ confirmTextDialog({text, title}) {
104242
+ const content = createTextView(text);
104142
104243
 
104244
+ return this.createModalConfirmation({
104245
+ title,
104246
+ content: content
104247
+ });
104248
+ }
104143
104249
 
104144
- const result = new Promise(function (resolve, reject) {
104145
- //make view
104250
+ /**
104251
+ *
104252
+ * @param {string} text
104253
+ * @param {string} title
104254
+ * @returns {Promise}
104255
+ */
104256
+ createTextAlert({text, title}) {
104257
+ const content = createTextView(text);
104258
+ return this.createAlert({
104259
+ content,
104260
+ title
104261
+ });
104262
+ }
104146
104263
 
104147
- let resolved = false;
104264
+ /**
104265
+ *
104266
+ * @param {View} content
104267
+ * @param {string} title
104268
+ * @param {View[]} [marks]
104269
+ * @param {number} priority
104270
+ * @param {function(SimpleLifecycle)} [lifecycleHook]
104271
+ * @returns {Promise}
104272
+ */
104273
+ createAlert(
104274
+ {
104275
+ content,
104276
+ title,
104277
+ marks = [],
104278
+ priority = 0,
104279
+ lifecycleHook = noop
104280
+ }
104281
+ ) {
104282
+ /**
104283
+ *
104284
+ * @type {SimpleLifecycle|null}
104285
+ */
104286
+ let lifecycle = null;
104148
104287
 
104149
104288
  function clear() {
104150
104289
  lifecycle.makeDestroyed();
104151
104290
  }
104152
104291
 
104153
- function callbackYes() {
104154
- resolved = true;
104155
- clear();
104156
- resolve();
104157
- }
104158
-
104159
- function callbackNo() {
104160
- resolved = true;
104161
- clear();
104162
- reject();
104163
- }
104292
+ const localization = this.localization;
104164
104293
 
104165
104294
  const view = new ConfirmationDialogView(content,
104166
104295
  [{
104167
- name: "yes",
104168
- displayName: self.localization.getString("system_confirmation_confirm"),
104169
- callback: callbackYes,
104170
- enabled: confirmationEnabled
104171
- }, {
104172
- name: "no",
104173
- displayName: self.localization.getString("system_confirmation_cancel"),
104174
- callback: callbackNo
104296
+ name: "ok",
104297
+ displayName: localization.getString("system_confirmation_continue"),
104298
+ callback: clear
104175
104299
  }]
104176
104300
  );
104177
104301
 
104178
- lifecycle = self.createModal({
104179
- content: view,
104180
- title: title
104181
- });
104182
-
104183
- lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Destroyed, function () {
104184
- if (!resolved) {
104185
- //if destroyed without resolution, reject the promise
104186
- reject();
104187
- }
104188
- });
104189
- });
104190
-
104302
+ if (marks.length > 0) {
104303
+ const vMarks = new EmptyView({classList: ['marks']});
104191
104304
 
104192
- return result;
104193
- };
104305
+ marks.forEach(vMarks.addChild, vMarks);
104194
104306
 
104195
- /**
104196
- *
104197
- * @param {string} text
104198
- * @return {View}
104199
- */
104200
- function createTextView(text) {
104201
- const content = new View();
104202
- content.el = document.createElement('div');
104203
- content.el.classList.add('text');
104204
- content.el.innerText = text;
104307
+ view.addChild(vMarks);
104308
+ }
104205
104309
 
104206
- content.size.set(300, 100);
104207
- return content;
104208
- }
104209
104310
 
104210
- /**
104211
- * @param {string} text
104212
- * @param {string} title
104213
- * @returns {Promise} will be resolved or rejected based on user choice
104214
- */
104215
- GUIEngine.prototype.confirmTextDialog = function ({ text, title }) {
104216
- const content = createTextView(text);
104311
+ lifecycle = this.createModal({
104312
+ content: view,
104313
+ title,
104314
+ priority
104315
+ });
104217
104316
 
104218
- return this.createModalConfirmation({
104219
- title,
104220
- content: content
104221
- });
104222
- };
104317
+ const result = new Promise(function (resolve, reject) {
104318
+ lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Destroyed, resolve);
104319
+ });
104223
104320
 
104224
- /**
104225
- *
104226
- * @param {string} text
104227
- * @param {string} title
104228
- * @returns {Promise}
104229
- */
104230
- GUIEngine.prototype.createTextAlert = function ({ text, title }) {
104231
- const content = createTextView(text);
104232
- return this.createAlert({
104233
- content,
104234
- title
104235
- });
104236
- };
104321
+ lifecycleHook(lifecycle);
104237
104322
 
104238
- /**
104239
- *
104240
- * @param {View} content
104241
- * @param {string} title
104242
- * @param {View[]} [marks]
104243
- * @param {number} priority
104244
- * @param {function(SimpleLifecycle)} [lifecycleHook]
104245
- * @returns {Promise}
104246
- */
104247
- GUIEngine.prototype.createAlert = function (
104248
- {
104249
- content,
104250
- title,
104251
- marks = [],
104252
- priority = 0,
104253
- lifecycleHook = noop
104323
+ return result;
104254
104324
  }
104255
- ) {
104325
+
104256
104326
  /**
104257
104327
  *
104258
- * @type {SimpleLifecycle|null}
104328
+ * @param {Scene} scene
104329
+ * @return {SceneGUIContext}
104259
104330
  */
104260
- let lifecycle = null;
104331
+ obtainSceneContext(scene) {
104261
104332
 
104262
- function clear() {
104263
- lifecycle.makeDestroyed();
104264
- }
104265
-
104266
- const localization = this.localization;
104333
+ let context = this.sceneContexts.get(scene);
104267
104334
 
104268
- const view = new ConfirmationDialogView(content,
104269
- [{
104270
- name: "ok",
104271
- displayName: localization.getString("system_confirmation_continue"),
104272
- callback: clear
104273
- }]
104274
- );
104335
+ if (context === undefined) {
104336
+ context = new SceneGUIContext();
104275
104337
 
104276
- if (marks.length > 0) {
104277
- const vMarks = new EmptyView({ classList: ['marks'] });
104338
+ context.initialize(scene);
104339
+ context.startup();
104278
104340
 
104279
- marks.forEach(vMarks.addChild, vMarks);
104341
+ this.sceneContexts.set(scene, context);
104342
+ }
104280
104343
 
104281
- view.addChild(vMarks);
104344
+ return context;
104282
104345
  }
104283
104346
 
104347
+ /**
104348
+ * @returns {SceneGUIContext|null}
104349
+ */
104350
+ getActiveSceneContext() {
104351
+ const engine = this.engine;
104284
104352
 
104285
- lifecycle = this.createModal({
104286
- content: view,
104287
- title,
104288
- priority
104289
- });
104290
-
104291
- const result = new Promise(function (resolve, reject) {
104292
- lifecycle.sm.addEventHandlerStateEntry(SimpleLifecycleStateType.Destroyed, resolve);
104293
- });
104294
-
104295
- lifecycleHook(lifecycle);
104353
+ if (engine === null) {
104354
+ throw new Error(`Engine is not set`);
104355
+ }
104296
104356
 
104297
- return result;
104298
- };
104357
+ const sm = engine.sceneManager;
104299
104358
 
104300
- /**
104301
- *
104302
- * @param {Scene} scene
104303
- * @return {SceneGUIContext}
104304
- */
104305
- GUIEngine.prototype.obtainSceneContext = function (scene) {
104359
+ const scene = sm.current_scene;
104306
104360
 
104307
- let context = this.sceneContexts.get(scene);
104361
+ if (scene === null) {
104362
+ return null;
104363
+ }
104308
104364
 
104309
- if (context === undefined) {
104310
- context = new SceneGUIContext();
104365
+ return this.obtainSceneContext(scene);
104366
+ }
104311
104367
 
104312
- context.initialize(scene);
104313
- context.startup();
104368
+ /**
104369
+ * Invoked when locale is updated
104370
+ * @private
104371
+ */
104372
+ __update_localization() {
104373
+ // write locale to the view class so that CSS can be modifier on per-locale basis
104374
+ this.view.removeClassesByPattern(/locale-/);
104314
104375
 
104315
- this.sceneContexts.set(scene, context);
104376
+ this.view.addClass(`locale-${this.localization.locale.getValue()}`);
104316
104377
  }
104317
104378
 
104318
- return context;
104319
- };
104320
-
104321
- /**
104322
- * @returns {SceneGUIContext|null}
104323
- */
104324
- GUIEngine.prototype.getActiveSceneContext = function () {
104325
- const engine = this.engine;
104379
+ /**
104380
+ *
104381
+ * @param {Engine} engine
104382
+ */
104383
+ startup(engine) {
104384
+ this.engine = engine;
104385
+ this.entityManager = engine.entityManager;
104326
104386
 
104327
- if (engine === null) {
104328
- throw new Error(`Engine is not set`);
104329
- }
104387
+ const self = this;
104330
104388
 
104331
- const sm = engine.sceneManager;
104389
+ /**
104390
+ *
104391
+ * @type {Localization}
104392
+ */
104393
+ const localization = engine.localization;
104332
104394
 
104333
- const scene = sm.current_scene;
104395
+ this.gml.initialize(engine.staticKnowledge, localization);
104334
104396
 
104335
- if (scene === null) {
104336
- return null;
104337
- }
104397
+ this.tooltips.initialize(this.gml, engine.devices.pointer);
104338
104398
 
104339
- return this.obtainSceneContext(scene);
104340
- };
104399
+ //attach tooltips to GML
104400
+ this.gml.tooltips = this.viewTooltips;
104341
104401
 
104342
- /**
104343
- * Invoked when locale is updated
104344
- * @private
104345
- */
104346
- GUIEngine.prototype.__update_localization = function () {
104347
- // write locale to the view class so that CSS can be modifier on per-locale basis
104348
- this.view.removeClassesByPattern(/locale-/);
104402
+ this.view.addChild(this.tooltips.contextView);
104349
104403
 
104350
- this.view.addClass(`locale-${this.localization.locale.getValue()}`);
104351
- };
104404
+ engine.gameView.addChild(this.view);
104352
104405
 
104353
- /**
104354
- *
104355
- * @param {Engine} engine
104356
- */
104357
- GUIEngine.prototype.startup = function (engine) {
104358
- this.engine = engine;
104359
- this.entityManager = engine.entityManager;
104406
+ engine.gameView.size.process(function (x, y) {
104407
+ self.view.size.set(x, y);
104360
104408
 
104361
- const self = this;
104409
+ self.tooltips.contextView.size.set(x, y);
104410
+ });
104362
104411
 
104363
- /**
104364
- *
104365
- * @type {Localization}
104366
- */
104367
- const localization = engine.localization;
104412
+ this.ticker.start();
104368
104413
 
104369
- this.gml.initialize(engine.staticKnowledge, localization);
104414
+ this.localization = localization;
104370
104415
 
104371
- this.tooltips.initialize(this.gml, engine.devices.pointer);
104372
104416
 
104373
- //attach tooltips to GML
104374
- this.gml.tooltips = this.viewTooltips;
104417
+ //register cursor propagation
104418
+ this.cursor.process(function (newValue, oldValue) {
104419
+ function className(cursorName) {
104420
+ return `cursor-${cursorName}`;
104421
+ }
104375
104422
 
104376
- this.view.addChild(this.tooltips.contextView);
104423
+ const classList = engine.graphics.domElement.classList;
104377
104424
 
104378
- engine.gameView.addChild(this.view);
104425
+ if (typeof oldValue === 'string') {
104426
+ classList.remove(className(oldValue));
104427
+ }
104379
104428
 
104380
- engine.gameView.size.process(function (x, y) {
104381
- self.view.size.set(x, y);
104429
+ if (typeof newValue === 'string') {
104430
+ classList.add(className(newValue));
104431
+ }
104432
+ });
104382
104433
 
104383
- self.tooltips.contextView.size.set(x, y);
104384
- });
104434
+ // subscribe to localization changes
104435
+ this.localization.locale.onChanged.add(this.__update_localization, this);
104436
+ this.__update_localization();
104385
104437
 
104386
- this.ticker.start();
104438
+ return Promise.all([
104439
+ this.tooltips.startup()
104440
+ ]);
104441
+ }
104387
104442
 
104388
- this.localization = localization;
104443
+ shutdown() {
104444
+ this.windows.reset();
104445
+ this.entityManager = null;
104389
104446
 
104447
+ const pTooltips = this.tooltips.shutdown();
104390
104448
 
104391
- //register cursor propagation
104392
- this.cursor.process(function (newValue, oldValue) {
104393
- function className(cursorName) {
104394
- return `cursor-${cursorName}`;
104395
- }
104449
+ // unsubscribe from localization changes
104450
+ this.localization.locale.onChanged.remove(this.__update_localization, this);
104396
104451
 
104397
- const classList = engine.graphics.domElement.classList;
104452
+ return Promise.all([
104453
+ pTooltips
104454
+ ]);
104455
+ }
104456
+ }
104398
104457
 
104399
- if (typeof oldValue === 'string') {
104400
- classList.remove(className(oldValue));
104401
- }
104458
+ /**
104459
+ *
104460
+ * @param {View} view
104461
+ * @param {EntityComponentDataset} ecd
104462
+ */
104463
+ function animateView(view, ecd) {
104402
104464
 
104403
- if (typeof newValue === 'string') {
104404
- classList.add(className(newValue));
104405
- }
104406
- });
104465
+ const animationTrack = new AnimationTrack(["alpha", "scale"]);
104466
+ animationTrack.addKey(0, [0, 0.95]);
104467
+ animationTrack.addKey(0.2, [1, 1]);
104407
104468
 
104408
- // subscribe to localization changes
104409
- this.localization.locale.onChanged.add(this.__update_localization, this);
104410
- this.__update_localization();
104469
+ animationTrack.addTransition(0, TransitionFunctions.Linear);
104411
104470
 
104412
- return Promise.all([
104413
- this.tooltips.startup()
104414
- ]);
104415
- };
104471
+ const playback = new AnimationTrackPlayback(animationTrack, function (alpha, scale) {
104472
+ this.el.style.opacity = alpha;
104473
+ this.scale.set(scale, scale);
104474
+ }, view);
104416
104475
 
104417
- GUIEngine.prototype.shutdown = function () {
104418
- this.windows.reset();
104419
- this.entityManager = null;
104476
+ //force view status to initial key of animation
104477
+ playback.update();
104420
104478
 
104421
- const pTooltips = this.tooltips.shutdown();
104479
+ playTrackRealTime(playback, ecd);
104480
+ }
104422
104481
 
104423
- // unsubscribe from localization changes
104424
- this.localization.locale.onChanged.remove(this.__update_localization, this);
104482
+ /**
104483
+ *
104484
+ * @param {string} text
104485
+ * @return {View}
104486
+ */
104487
+ function createTextView(text) {
104488
+ const content = new View();
104489
+ content.el = document.createElement('div');
104490
+ content.el.classList.add('text');
104491
+ content.el.innerText = text;
104425
104492
 
104426
- return Promise.all([
104427
- pTooltips
104428
- ]);
104429
- };
104493
+ content.size.set(300, 100);
104494
+ return content;
104495
+ }
104430
104496
 
104431
104497
  /**
104432
104498
  * Created by Alex on 04/11/2016.
@@ -121033,7 +121099,7 @@ class EngineHarness {
121033
121099
  autoClip: cameraAutoClip
121034
121100
  });
121035
121101
 
121036
- const cameraEntity = camera.entity;
121102
+ const cameraEntity = camera.id;
121037
121103
 
121038
121104
  if (enableTerrain) {
121039
121105
  await EngineHarness.buildTerrain({