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