@woosh/meep-engine 2.84.10 → 2.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49071,15 +49071,21 @@ function interpolate_bicubic(t, a, b, c, d) {
49071
49071
  function computeStridedIntegerArrayHash(
49072
49072
  array, offset, length, stride
49073
49073
  ) {
49074
- let result = length;
49074
+ let hash = length;
49075
49075
 
49076
49076
  for (let i = offset; i < length; i += stride) {
49077
- const value = array[i];
49077
+ const value = array[i] >>> 0; //force int32
49078
49078
 
49079
- result = ((result * 31) + value) | 0;
49079
+ /**
49080
+ * Simple hashing scheme, multiplying existing hash by a prime and adding next value
49081
+ * (h<<5) - h === h*31
49082
+ * @type {number}
49083
+ */
49084
+ hash = ((hash << 5) - hash) + value;
49080
49085
  }
49081
49086
 
49082
- return result;
49087
+ // force uint32
49088
+ return hash >>> 0;
49083
49089
  }
49084
49090
 
49085
49091
  function typedArrayConstructorByInstance(a) {
@@ -50478,22 +50484,7 @@ Vector1.one = Object.freeze(new Vector1(1));
50478
50484
  * @param {number} length
50479
50485
  */
50480
50486
  function computeIntegerArrayHash(data, offset, length) {
50481
- const end = offset + length;
50482
-
50483
- let hash = length;
50484
-
50485
- for (let i = offset; i < end; i++) {
50486
- const singleValue = data[i];
50487
- /**
50488
- * Simple hashing scheme, multiplying existing hash by a prime and adding next value
50489
- * (h<<5) - h === h*31
50490
- * @type {number}
50491
- */
50492
- hash = ((hash << 5) - hash) + singleValue;
50493
- hash |= 0; // Convert to 32bit integer
50494
- }
50495
-
50496
- return hash;
50487
+ return computeStridedIntegerArrayHash(data, offset, length, 1);
50497
50488
  }
50498
50489
 
50499
50490
  /**
@@ -60814,7 +60805,7 @@ class Cache {
60814
60805
 
60815
60806
  if (
60816
60807
  this.weight > this.maxWeight
60817
- && new_weight >= this.maxWeight //make it less likely to drop entire cache
60808
+ && new_weight <= this.maxWeight //make it less likely to drop entire cache
60818
60809
  ) {
60819
60810
  this.evictUntilWeight(this.maxWeight);
60820
60811
  }
@@ -61166,6 +61157,7 @@ function arrayIndexByEquality(array, element, equals) {
61166
61157
 
61167
61158
  /**
61168
61159
  * 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
61160
+ * @see prefer to use {@link arraySetSortingDiff}, as it's much faster, especially for large sets
61169
61161
  * @template T
61170
61162
  * @param {T[]} a
61171
61163
  * @param {T[]} b
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.84.10",
8
+ "version": "2.85.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -216,7 +216,7 @@ export class Cache {
216
216
 
217
217
  if (
218
218
  this.weight > this.maxWeight
219
- && new_weight >= this.maxWeight //make it less likely to drop entire cache
219
+ && new_weight <= this.maxWeight //make it less likely to drop entire cache
220
220
  ) {
221
221
  this.evictUntilWeight(this.maxWeight);
222
222
  }
@@ -41,7 +41,7 @@ function record_get_value_weight(record) {
41
41
  /**
42
42
  * Asynchronous cache capable of resolving its own values by keys
43
43
  * Modelled on Guava's LoadingCache concept
44
- * @template K,V
44
+ * @template K, V
45
45
  */
46
46
  export class LoadingCache {
47
47
  /**
@@ -73,7 +73,6 @@ export class LoadingCache {
73
73
 
74
74
  /**
75
75
  * @see {@link Cache} for more details on what each parameter means
76
- * @template K,V
77
76
  * @param [maxWeight]
78
77
  * @param [keyWeigher]
79
78
  * @param [valueWeigher]
@@ -183,6 +182,15 @@ export class LoadingCache {
183
182
  this.#internal.put(key, new Record(Promise.resolve(value), current_time_in_seconds()));
184
183
  }
185
184
 
185
+ /**
186
+ *
187
+ * @param {K} key
188
+ * @returns {boolean}
189
+ */
190
+ contains(key) {
191
+ return this.#internal.contains(key);
192
+ }
193
+
186
194
  /**
187
195
  *
188
196
  * @param {K} key
@@ -84,3 +84,36 @@ test("clear", async () => {
84
84
 
85
85
  expect(await cache.get("x")).toEqual(3);
86
86
  });
87
+
88
+ test("eviction", async () => {
89
+
90
+ /**
91
+ *
92
+ * @type {LoadingCache<number, number>}
93
+ */
94
+ const cache = new LoadingCache({
95
+ valueWeigher(num) {
96
+ return num;
97
+ },
98
+ load: async () => {
99
+ return 2;
100
+ },
101
+ maxWeight: 6,
102
+ });
103
+
104
+ await cache.get(1);
105
+ await cache.get(2);
106
+ await cache.get(3);
107
+
108
+ expect(cache.contains(1)).toBe(true);
109
+ expect(cache.contains(2)).toBe(true);
110
+ expect(cache.contains(3)).toBe(true);
111
+
112
+ await cache.get(4);
113
+
114
+ expect(cache.contains(1)).toBe(false);
115
+ expect(cache.contains(2)).toBe(true);
116
+ expect(cache.contains(3)).toBe(true);
117
+ expect(cache.contains(4)).toBe(true);
118
+
119
+ });
@@ -5,6 +5,7 @@ import { arrayIndexByEquality } from "./arrayIndexByEquality.js";
5
5
 
6
6
  /**
7
7
  * 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
8
+ * @see prefer to use {@link arraySetSortingDiff}, as it's much faster, especially for large sets
8
9
  * @template T
9
10
  * @param {T[]} a
10
11
  * @param {T[]} b
@@ -1,6 +1,6 @@
1
1
  import { assert } from "../../../assert.js";
2
- import { NodeInstance } from "../node/NodeInstance.js";
3
2
  import { abstractJSONDeserializer } from "../../../json/abstractJSONDeserializer.js";
3
+ import { NodeInstance } from "../node/NodeInstance.js";
4
4
  import { NodeRegistry } from "../node/NodeRegistry.js";
5
5
 
6
6
  /**
@@ -25,47 +25,73 @@ function nodeParametersFromJSON(node, json, deserializers) {
25
25
 
26
26
  /**
27
27
  *
28
- * @param {NodeGraph} graph
29
- * @param {{nodes:[], connections:[], descriptions:[]}} json
30
- * @param {NodeRegistry} [node_registry]
31
- * @param {Map<string, function>} [deserializers]
32
- * @param {boolean} [allow_node_id_collisions]
28
+ * @param {[]} j_descriptions
29
+ * @param {Map<string,function>} deserializers
30
+ * @param {NodeRegistry} node_registry
31
+ * @param {boolean} allow_node_id_collisions
32
+ * @returns {Promise<NodeDescription[]>}
33
33
  */
34
- export function deserializeNodeGraphFromJSON({
35
- graph,
36
- json,
37
- node_registry = new NodeRegistry(),
38
- deserializers = new Map(),
39
- allow_node_id_collisions = false
40
- }) {
41
-
42
- const j_nodes = json.nodes;
43
- const j_connections = json.connections;
44
- const j_descriptions = json.descriptions;
45
-
46
-
47
- assert.defined(j_nodes, 'json.nodes');
48
- assert.defined(j_connections, 'json.connections');
49
- assert.defined(j_descriptions, 'json.descriptions');
34
+ async function deserializeNodeDescriptors(j_descriptions, deserializers, node_registry, allow_node_id_collisions) {
35
+ /**
36
+ *
37
+ * @type {NodeDescription[]}
38
+ */
39
+ const result = [];
50
40
 
51
- graph.reset();
41
+ /**
42
+ *
43
+ * @type {{index:number, promise:Promise<NodeDescription>}[]}
44
+ */
45
+ const deferred = [];
52
46
 
53
47
  /**
54
48
  *
55
49
  * @type {NodeDescription[]}
56
50
  */
57
- const descriptions = [];
51
+ const deserialized = [];
58
52
 
59
- // parse node descriptions
60
- for (let i = 0; i < j_descriptions.length; i++) {
53
+
54
+ const node_description_count = j_descriptions.length;
55
+
56
+ // parse node result
57
+ for (let i = 0; i < node_description_count; i++) {
61
58
  const jDescription = j_descriptions[i];
62
59
 
63
- const loaded_node = abstractJSONDeserializer(jDescription, deserializers);
60
+ const result = abstractJSONDeserializer(jDescription, deserializers);
61
+
62
+ if (result instanceof Promise) {
63
+ deferred.push({
64
+ index: i,
65
+ promise: result
66
+ });
67
+ } else {
68
+ deserialized[i] = result;
69
+ }
70
+
71
+ }
72
+
73
+ if (deferred.length > 0) {
74
+ const resolved = await Promise.all(deferred.map(m => m.promise));
75
+
76
+ for (let i = 0; i < deferred.length; i++) {
77
+ const node_description = resolved[i];
78
+
79
+ const spec = deferred[i];
80
+
81
+ deserialized[spec.index] = node_description;
82
+ }
83
+ }
84
+
85
+ for (let i = 0; i < node_description_count; i++) {
86
+
87
+ const loaded_node = deserialized[i];
64
88
 
65
89
  if (
66
90
  typeof loaded_node !== "object"
67
91
  || loaded_node.isNodeDescription !== true
68
92
  ) {
93
+ const jDescription = j_descriptions[i];
94
+
69
95
  throw new Error(`Deserialized object was expected to be a NodeDescription, instead got something else. Source JSON[${i}]: ${jDescription}`);
70
96
  }
71
97
 
@@ -73,7 +99,7 @@ export function deserializeNodeGraphFromJSON({
73
99
 
74
100
  if (existing_node === undefined) {
75
101
 
76
- descriptions[i] = loaded_node;
102
+ result[i] = loaded_node;
77
103
 
78
104
  // make sure to register the node
79
105
  node_registry.addNode(loaded_node);
@@ -85,7 +111,7 @@ export function deserializeNodeGraphFromJSON({
85
111
  // collision exists
86
112
 
87
113
  if (allow_node_id_collisions) {
88
- descriptions[i] = loaded_node;
114
+ result[i] = loaded_node;
89
115
  } else {
90
116
  // illegal collision
91
117
  throw new Error(`Loaded node does not match the one in the registry. Loaded: ${loaded_node}, Existing: ${existing_node}`);
@@ -94,11 +120,45 @@ export function deserializeNodeGraphFromJSON({
94
120
  } else {
95
121
 
96
122
  // re-use node from registry
97
- descriptions[i] = existing_node;
123
+ result[i] = existing_node;
98
124
  }
99
125
  }
100
-
101
126
  }
127
+ return result;
128
+ }
129
+
130
+ /**
131
+ *
132
+ * @param {NodeGraph} graph
133
+ * @param {{nodes:[], connections:[], descriptions:[]}} json
134
+ * @param {NodeRegistry} [node_registry]
135
+ * @param {Map<string, function>} [deserializers]
136
+ * @param {boolean} [allow_node_id_collisions]
137
+ */
138
+ export async function deserializeNodeGraphFromJSON({
139
+ graph,
140
+ json,
141
+ node_registry = new NodeRegistry(),
142
+ deserializers = new Map(),
143
+ allow_node_id_collisions = false
144
+ }) {
145
+
146
+ const j_nodes = json.nodes;
147
+ const j_connections = json.connections;
148
+ const j_descriptions = json.descriptions;
149
+
150
+ assert.defined(j_nodes, 'json.nodes');
151
+ assert.defined(j_connections, 'json.connections');
152
+ assert.defined(j_descriptions, 'json.descriptions');
153
+
154
+ graph.reset();
155
+
156
+ const descriptions = await deserializeNodeDescriptors(
157
+ j_descriptions,
158
+ deserializers,
159
+ node_registry,
160
+ allow_node_id_collisions
161
+ );
102
162
 
103
163
  // parse nodes
104
164
  const node_count = j_nodes.length;
@@ -1,3 +1,5 @@
1
+ import { computeStridedIntegerArrayHash } from "./computeStridedIntegerArrayHash.js";
2
+
1
3
  /**
2
4
  *
3
5
  * @param {Uint8Array|number[]|ArrayLike<number>|IArguments} data
@@ -5,20 +7,5 @@
5
7
  * @param {number} length
6
8
  */
7
9
  export function computeIntegerArrayHash(data, offset, length) {
8
- const end = offset + length;
9
-
10
- let hash = length;
11
-
12
- for (let i = offset; i < end; i++) {
13
- const singleValue = data[i];
14
- /**
15
- * Simple hashing scheme, multiplying existing hash by a prime and adding next value
16
- * (h<<5) - h === h*31
17
- * @type {number}
18
- */
19
- hash = ((hash << 5) - hash) + singleValue;
20
- hash |= 0; // Convert to 32bit integer
21
- }
22
-
23
- return hash;
10
+ return computeStridedIntegerArrayHash(data, offset, length, 1);
24
11
  }
@@ -9,13 +9,19 @@
9
9
  export function computeStridedIntegerArrayHash(
10
10
  array, offset, length, stride
11
11
  ) {
12
- let result = length;
12
+ let hash = length;
13
13
 
14
14
  for (let i = offset; i < length; i += stride) {
15
- const value = array[i];
15
+ const value = array[i] >>> 0; //force int32
16
16
 
17
- result = ((result * 31) + value) | 0;
17
+ /**
18
+ * Simple hashing scheme, multiplying existing hash by a prime and adding next value
19
+ * (h<<5) - h === h*31
20
+ * @type {number}
21
+ */
22
+ hash = ((hash << 5) - hash) + value;
18
23
  }
19
24
 
20
- return result;
25
+ // force uint32
26
+ return hash >>> 0;
21
27
  }
@@ -1,17 +1,17 @@
1
- import View from "../../../../../view/View.js";
2
1
  import { NodeGraphEditorView } from "../../../../../../editor/view/node-graph/NodeGraphEditorView.js";
3
2
  import { NodeGraphCamera } from "../../../../../../editor/view/node-graph/NodeGraphView.js";
4
- import ListView from "../../../../../view/common/ListView.js";
3
+ import { downloadAsFile } from "../../../../../core/binary/downloadAsFile.js";
5
4
  import List from "../../../../../core/collection/list/List.js";
6
- import LabelView from "../../../../../view/common/LabelView.js";
7
- import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
8
- import InterfaceCommand from "../../../../../view/interaction/InterfaceCommand.js";
9
- import { InteractionCommand } from "../../../../../view/interaction/InteractionCommand.js";
10
- import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/json/serializeNodeGraphToJSON.js";
11
5
  import {
12
6
  deserializeNodeGraphFromJSON
13
7
  } from "../../../../../core/model/node-graph/json/deserializeNodeGraphFromJSON.js";
14
- import {downloadAsFile} from "../../../../../core/binary/downloadAsFile.js";
8
+ import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/json/serializeNodeGraphToJSON.js";
9
+ import LabelView from "../../../../../view/common/LabelView.js";
10
+ import ListView from "../../../../../view/common/ListView.js";
11
+ import { InteractionCommand } from "../../../../../view/interaction/InteractionCommand.js";
12
+ import InterfaceCommand from "../../../../../view/interaction/InterfaceCommand.js";
13
+ import View from "../../../../../view/View.js";
14
+ import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
15
15
 
16
16
  export class ParticleSpecificationEditorView extends View {
17
17
  constructor() {
@@ -101,13 +101,13 @@ export class ParticleSpecificationEditorView extends View {
101
101
  function processFile(file) {
102
102
  const fr = new FileReader();
103
103
 
104
- fr.onload = () => {
104
+ fr.onload = async () => {
105
105
 
106
106
  visual.nodes.clear();
107
107
 
108
108
  const json = JSON.parse(fr.result);
109
109
 
110
- deserializeNodeGraphFromJSON({ graph: nodeGraph, json: json, node_registry: nodeRegistry });
110
+ await deserializeNodeGraphFromJSON({ graph: nodeGraph, json: json, node_registry: nodeRegistry });
111
111
 
112
112
  visual.layout(nodeGraph);
113
113
  };