@woosh/meep-engine 2.47.12 → 2.47.14

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.
@@ -73247,6 +73247,14 @@ BitSet.prototype.__resize = function (bitCapacity) {
73247
73247
  this.__capacity = uint32_capacity * 32;
73248
73248
  };
73249
73249
 
73250
+ BitSet.prototype.__updateLength = function () {
73251
+ const found_length = this.previousSetBit(this.__length) + 1;
73252
+
73253
+ if (found_length < this.__length) {
73254
+ this.__setLength(found_length);
73255
+ }
73256
+ };
73257
+
73250
73258
  /**
73251
73259
  *
73252
73260
  * @param {int} new_length
@@ -73470,12 +73478,8 @@ BitSet.prototype.set = function (bitIndex, value) {
73470
73478
  //clear
73471
73479
  this.__data_uint32[word_offset] &= ~word_mask;
73472
73480
 
73473
- if (bitIndex === this.__length - 1) {
73474
- // trim down set size potentially
73475
- // const newLastSetBit = this.previousSetBit(bitIndex);
73476
-
73477
- this.__setLength(bitIndex );
73478
- }
73481
+ // trim down set size potentially
73482
+ this.__updateLength();
73479
73483
  }
73480
73484
 
73481
73485
  //DEBUG validate firstClearBit value
@@ -82231,11 +82235,11 @@ function isGroup(t) {
82231
82235
  class ConcurrentExecutor {
82232
82236
  /**
82233
82237
  *
82234
- * @param {number} quietTime in milliseconds
82235
- * @param {number} workTime in milliseconds
82238
+ * @param {number} [quietTime] in milliseconds
82239
+ * @param {number} [workTime] in milliseconds
82236
82240
  * @constructor
82237
82241
  */
82238
- constructor(quietTime, workTime) {
82242
+ constructor(quietTime=1, workTime=15) {
82239
82243
  /**
82240
82244
  *
82241
82245
  * @type {number}
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.47.12",
8
+ "version": "2.47.14",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -162,6 +162,14 @@ BitSet.prototype.__resize = function (bitCapacity) {
162
162
  this.__capacity = uint32_capacity * 32;
163
163
  };
164
164
 
165
+ BitSet.prototype.__updateLength = function () {
166
+ const found_length = this.previousSetBit(this.__length) + 1;
167
+
168
+ if (found_length < this.__length) {
169
+ this.__setLength(found_length);
170
+ }
171
+ }
172
+
165
173
  /**
166
174
  *
167
175
  * @param {int} new_length
@@ -385,12 +393,8 @@ BitSet.prototype.set = function (bitIndex, value) {
385
393
  //clear
386
394
  this.__data_uint32[word_offset] &= ~word_mask;
387
395
 
388
- if (bitIndex === this.__length - 1) {
389
- // trim down set size potentially
390
- // const newLastSetBit = this.previousSetBit(bitIndex);
391
-
392
- this.__setLength(bitIndex );
393
- }
396
+ // trim down set size potentially
397
+ this.__updateLength();
394
398
  }
395
399
 
396
400
  //DEBUG validate firstClearBit value
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @template T
3
+ * @param {T} json
4
+ * @param {Map<string, function>} deserializers
5
+ */
6
+ export function abstractJSONDeserializer(json, deserializers) {
7
+ if (typeof json !== "object") {
8
+ // primitive type
9
+ return json;
10
+ }
11
+
12
+ const typeName = json.type;
13
+
14
+ if (typeof typeName !== "string") {
15
+ throw new Error(`Expected json.typeName to be a string, instead was '${typeof typeName}'(=${typeName})`);
16
+ }
17
+
18
+ const deserializer = deserializers.get(typeName);
19
+
20
+ if (deserializer === undefined) {
21
+ throw new Error(`No deserializer found for type '${typeName}'`);
22
+ }
23
+
24
+ return deserializer(json.data);
25
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @template T
3
+ * @param {T} source
4
+ * @param {Map<string, function(v:Object):Object>} serializers
5
+ * @param {Map<*,string>} classNames
6
+ */
7
+ export function abstractJSONSerializer(source, serializers, classNames) {
8
+
9
+
10
+ if (typeof source !== "object") {
11
+ // primitive type
12
+ return source;
13
+ }
14
+
15
+ // parameter is an object
16
+
17
+ // extract type name
18
+ const Klass = source.constructor;
19
+ let typeName = classNames.get(Klass);
20
+
21
+ if (typeName === undefined) {
22
+ // try fallback to "typeName" field on constructor
23
+ typeName = Klass.typeName;
24
+ }
25
+
26
+ if (typeName === undefined) {
27
+ throw new Error(`Failed to resolve type name. No name found in classNames registry and no .typeName field on the constructor`);
28
+ }
29
+
30
+ let serializer = serializers.get(typeName);
31
+ let serializerContext = undefined;
32
+
33
+ if (serializer === undefined) {
34
+ serializer = source.toJSON;
35
+ serializerContext = source;
36
+ }
37
+
38
+ if (serializer === undefined) {
39
+ throw new Error(`Failed to resolve serializer for object type '${typeName}'. No serializer found in serializers registry and no .toJSON method on object itself`);
40
+ }
41
+
42
+ return {
43
+ type: typeName,
44
+ data: serializer.call(serializerContext, source)
45
+ };
46
+
47
+
48
+ }
@@ -0,0 +1,118 @@
1
+ import { assert } from "../../../assert.js";
2
+ import { NodeInstance } from "../node/NodeInstance.d.ts";
3
+ import { abstractJSONDeserializer } from "../../../json/abstractJSONDeserializer.js";
4
+ import { NodeRegistry } from "../node/NodeRegistry.js";
5
+
6
+ /**
7
+ *
8
+ * @param {NodeInstance} node
9
+ * @param {*} json
10
+ * @param {Map<string, function>} deserializers
11
+ */
12
+ function nodeParametersFromJSON(node, json, deserializers) {
13
+
14
+ for (const key in json) {
15
+
16
+ const jParameter = json[key];
17
+
18
+ const value = abstractJSONDeserializer(jParameter, deserializers);
19
+
20
+ node.setParameterValue(key, value);
21
+
22
+ }
23
+
24
+ }
25
+
26
+ /**
27
+ *
28
+ * @param {NodeGraph} graph
29
+ * @param {{nodes:[], connections:[], descriptions:[]}} json
30
+ * @param {NodeRegistry} [node_registry]
31
+ * @param {Map<string, function>} [deserializers]
32
+ */
33
+ export function deserializeNodeGraphFromJSON({
34
+ graph,
35
+ json,
36
+ node_registry = new NodeRegistry(),
37
+ deserializers = new Map()
38
+ }) {
39
+
40
+ const j_nodes = json.nodes;
41
+ const j_connections = json.connections;
42
+ const j_descriptions = json.descriptions;
43
+
44
+
45
+ assert.defined(j_nodes, 'json.nodes');
46
+ assert.defined(j_connections, 'json.connections');
47
+ assert.defined(j_descriptions, 'json.descriptions');
48
+
49
+ graph.reset();
50
+
51
+ /**
52
+ *
53
+ * @type {NodeDescription[]}
54
+ */
55
+ const descriptions = [];
56
+
57
+ // parse node descriptions
58
+ for (let i = 0; i < j_descriptions.length; i++) {
59
+ const jDescription = j_descriptions[i];
60
+
61
+ const nodeDescription = abstractJSONDeserializer(jDescription, deserializers);
62
+
63
+ if (
64
+ typeof nodeDescription !== "object"
65
+ || nodeDescription.isNodeDescription !== true
66
+ ) {
67
+ throw new Error(`Deserialized object was expected to be a NodeDescription, instead got something else. Source JSON[${i}]: ${jDescription}`);
68
+ }
69
+
70
+ descriptions[i] = nodeDescription;
71
+
72
+ // make sure to register the node
73
+ node_registry.addNode(nodeDescription);
74
+ }
75
+
76
+ // parse nodes
77
+ const node_count = j_nodes.length;
78
+
79
+ for (let i = 0; i < node_count; i++) {
80
+ const jNode = j_nodes[i];
81
+
82
+ const node_id = jNode.id;
83
+
84
+ assert.isNonNegativeInteger(node_id, 'node.id');
85
+
86
+ const description_index = jNode.description;
87
+
88
+ const jParameters = jNode.parameters;
89
+
90
+ // get node description
91
+ const node_description = descriptions[description_index];
92
+
93
+ if (node_description === undefined) {
94
+ throw new Error(`Index ${description_index} not found in .description`);
95
+ }
96
+
97
+ const nodeInstance = new NodeInstance();
98
+
99
+ nodeInstance.id = node_id;
100
+ nodeInstance.setDescription(node_description);
101
+
102
+ nodeParametersFromJSON(nodeInstance, jParameters, deserializers);
103
+
104
+ graph.addNode(nodeInstance);
105
+ }
106
+
107
+ // parse connections
108
+ const connection_count = j_connections.length;
109
+
110
+ for (let i = 0; i < connection_count; i++) {
111
+ const jConnection = j_connections[i];
112
+
113
+ const jSource = jConnection.source;
114
+ const jTarget = jConnection.target;
115
+
116
+ graph.createConnection(jSource.instance, jSource.port, jTarget.instance, jTarget.port);
117
+ }
118
+ }
@@ -0,0 +1,106 @@
1
+ import { abstractJSONSerializer } from "../../../json/abstractJSONSerializer.js";
2
+
3
+ /**
4
+ *
5
+ * @param {NodeInstance} node
6
+ * @param {Map<string, function(v:Object):Object>} serializers
7
+ * @param {Map<*,string>} classNames
8
+ */
9
+ function nodeParametersToJSON(node, serializers, classNames) {
10
+ const result = {};
11
+
12
+ const parameters = node.parameters;
13
+
14
+ for (const key in parameters) {
15
+
16
+ const source = parameters[key];
17
+
18
+
19
+ result[key] = abstractJSONSerializer(source, serializers, classNames);
20
+
21
+ }
22
+
23
+ return result;
24
+ }
25
+
26
+
27
+ /**
28
+ *
29
+ * @param {NodeGraph} graph
30
+ * @param {Map<string, function(v:Object):Object>} [serializers]
31
+ * @param {Map<*,string>} [classNames]
32
+ */
33
+ export function serializeNodeGraphToJSON({ graph, serializers = new Map(), classNames = new Map() }) {
34
+ /**
35
+ *
36
+ * @type {NodeDescription[]}
37
+ */
38
+ const description_objects = [];
39
+ /**
40
+ *
41
+ * @type {Map<NodeDescription, number>}
42
+ */
43
+ const description_to_index_map = new Map();
44
+
45
+ /**
46
+ * JSON versions of descriptions
47
+ * @type {Object[]}
48
+ */
49
+ const descriptions = [];
50
+
51
+ // extract node descriptions
52
+ graph.traverseNodes(node => {
53
+
54
+ const description = node.description;
55
+
56
+ let index = description_objects.indexOf(description);
57
+
58
+ if (index !== -1) {
59
+ // already recorded
60
+ return;
61
+ }
62
+
63
+ index = description_objects.length;
64
+ description_objects.push(description);
65
+
66
+ description_to_index_map.set(description, index);
67
+
68
+ descriptions[index] = abstractJSONSerializer(description, serializers, classNames);
69
+ });
70
+
71
+ const nodes = [];
72
+
73
+ graph.traverseNodes(node => {
74
+
75
+ nodes.push({
76
+ id: node.id,
77
+ description: description_to_index_map.get(node.description),
78
+ parameters: nodeParametersToJSON(node, serializers, classNames)
79
+ });
80
+
81
+ });
82
+
83
+ const connections = [];
84
+
85
+ graph.traverseConnections(connection => {
86
+
87
+ connections.push({
88
+ source: {
89
+ instance: connection.source.instance.id,
90
+ port: connection.source.port.id
91
+ },
92
+ target: {
93
+ instance: connection.target.instance.id,
94
+ port: connection.target.port.id
95
+ }
96
+ });
97
+
98
+ });
99
+
100
+ return {
101
+ nodes,
102
+ connections,
103
+ descriptions
104
+ };
105
+ }
106
+
@@ -315,6 +315,14 @@ export class NodeDescription {
315
315
  getPorts() {
316
316
  return this.ports
317
317
  }
318
+
319
+ toJSON() {
320
+ throw new Error('Not Implemented');
321
+ }
322
+
323
+ fromJSON() {
324
+ throw new Error('Not Implemented');
325
+ }
318
326
  }
319
327
 
320
328
  /**
@@ -2,7 +2,7 @@ import Task from "../task/Task";
2
2
  import TaskGroup from "../task/TaskGroup";
3
3
 
4
4
  export default class ConcurrentExecutor {
5
- constructor(quietTime: number, workTime: number)
5
+ constructor(quietTime?: number, workTime?: number)
6
6
 
7
7
  runGroup(t: TaskGroup): void
8
8
 
@@ -24,11 +24,11 @@ function isGroup(t) {
24
24
  class ConcurrentExecutor {
25
25
  /**
26
26
  *
27
- * @param {number} quietTime in milliseconds
28
- * @param {number} workTime in milliseconds
27
+ * @param {number} [quietTime] in milliseconds
28
+ * @param {number} [workTime] in milliseconds
29
29
  * @constructor
30
30
  */
31
- constructor(quietTime, workTime) {
31
+ constructor(quietTime=1, workTime=15) {
32
32
  /**
33
33
  *
34
34
  * @type {number}
@@ -15,6 +15,10 @@ export class AssetManager {
15
15
 
16
16
  load_concurrency: number
17
17
 
18
+ startup(): void
19
+
20
+ shutdown(immediate?: boolean): Promise<void>
21
+
18
22
  promise<T>(path: string, type: string, options?: PromiseOptions): Promise<Asset<T>>
19
23
 
20
24
  remove(path: string, type: string): boolean
@@ -1,13 +1,18 @@
1
1
  import { Asset } from "./Asset.js";
2
2
  import { AssetManager } from "./AssetManager.js";
3
3
  import { AssetLoader } from "./loaders/AssetLoader.js";
4
+ import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor.js";
4
5
 
5
6
  /**
6
7
  *
7
8
  * @return {Engine}
8
9
  */
9
10
  function dummyEngine() {
10
- return {};
11
+ const executor = new ConcurrentExecutor();
12
+
13
+ return {
14
+ executor: executor
15
+ };
11
16
  }
12
17
 
13
18
  class DummyLoader extends AssetLoader {
@@ -16,11 +21,12 @@ class DummyLoader extends AssetLoader {
16
21
  }
17
22
  }
18
23
 
19
- test('successful get', () => {
24
+ test('successful get', async () => {
20
25
  const am = new AssetManager(dummyEngine());
21
26
 
22
- am.registerLoader('a', new DummyLoader());
27
+ await am.registerLoader('a', new DummyLoader());
23
28
 
29
+ am.startup();
24
30
 
25
31
  return new Promise(function (resolve, reject) {
26
32
  am.get('bla', 'a', resolve, reject);
@@ -30,7 +36,9 @@ test('successful get', () => {
30
36
  test('tryGet loaded resource', async () => {
31
37
  const am = new AssetManager(dummyEngine());
32
38
 
33
- am.registerLoader('a', new DummyLoader());
39
+ am.startup();
40
+
41
+ await am.registerLoader('a', new DummyLoader());
34
42
 
35
43
  await am.promise('bla', 'a');
36
44
 
@@ -7,9 +7,11 @@ import LabelView from "../../../../../view/common/LabelView.js";
7
7
  import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
8
8
  import InterfaceCommand from "../../../../../view/interaction/InterfaceCommand.js";
9
9
  import { InteractionCommand } from "../../../../../view/interaction/InteractionCommand.js";
10
- import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/serializeNodeGraphToJSON.js";
10
+ import { serializeNodeGraphToJSON } from "../../../../../core/model/node-graph/json/serializeNodeGraphToJSON.js";
11
11
  import { downloadAsFile } from "../../../../../core/binary/ByteArrayTools.js";
12
- import { deserializeNodeGraphFromJSON } from "../../../../../core/model/node-graph/deserializeNodeGraphFromJSON.js";
12
+ import {
13
+ deserializeNodeGraphFromJSON
14
+ } from "../../../../../core/model/node-graph/json/deserializeNodeGraphFromJSON.js";
13
15
 
14
16
  export class ParticleSpecificationEditorView extends View {
15
17
  constructor() {
@@ -78,7 +80,7 @@ export class ParticleSpecificationEditorView extends View {
78
80
  command: new InteractionCommand({
79
81
  id: 'serialize-json',
80
82
  action() {
81
- const json = serializeNodeGraphToJSON(nodeGraph);
83
+ const json = serializeNodeGraphToJSON({ graph: nodeGraph });
82
84
 
83
85
 
84
86
  downloadAsFile(JSON.stringify(json, 3, 3), 'graph.json', 'application/json');
@@ -105,7 +107,7 @@ export class ParticleSpecificationEditorView extends View {
105
107
 
106
108
  const json = JSON.parse(fr.result);
107
109
 
108
- deserializeNodeGraphFromJSON(nodeGraph, json, nodeRegistry);
110
+ deserializeNodeGraphFromJSON({ graph: nodeGraph, json: json, node_registry: nodeRegistry });
109
111
 
110
112
  visual.layout(nodeGraph);
111
113
  };
@@ -78,7 +78,7 @@ test('left to right', () => {
78
78
  1, 0, 0,
79
79
  1, 0, 0,
80
80
  1, 0, 0
81
- ])).toBeCloseTo(180);
81
+ ])).toBeCloseTo(-180);
82
82
  });
83
83
 
84
84
  test('right to left', () => {
@@ -94,7 +94,7 @@ test('top to bottom', () => {
94
94
  1, 1, 1,
95
95
  0, 0, 0,
96
96
  0, 0, 0
97
- ])).toBeCloseTo(-90);
97
+ ])).toBeCloseTo(90);
98
98
  });
99
99
 
100
100
  test('bottom to top', () => {
@@ -102,5 +102,5 @@ test('bottom to top', () => {
102
102
  0, 0, 0,
103
103
  0, 0, 0,
104
104
  1, 1, 1
105
- ])).toBeCloseTo(90);
105
+ ])).toBeCloseTo(-90);
106
106
  });
@@ -1,62 +0,0 @@
1
- import { assert } from "../../assert.js";
2
- import { NodeInstance } from "./node/NodeInstance.js";
3
-
4
- /**
5
- *
6
- * @param {NodeGraph} graph
7
- * @param {{nodes:[], connections:[]}} json
8
- * @param {NodeRegistry} node_registry
9
- */
10
- export function deserializeNodeGraphFromJSON(graph, json, node_registry) {
11
-
12
- const nodes = json.nodes;
13
- const connections = json.connections;
14
-
15
-
16
- assert.defined(nodes, 'json.nodes');
17
- assert.defined(connections, 'json.connections');
18
-
19
- graph.reset();
20
-
21
- // parse nodes
22
- const node_count = nodes.length;
23
-
24
- for (let i = 0; i < node_count; i++) {
25
- const jNode = nodes[i];
26
-
27
- const node_id = jNode.id;
28
-
29
- assert.isNonNegativeInteger(node_id, 'node.id');
30
-
31
- const description = jNode.description;
32
-
33
- const parameters = jNode.parameters;
34
-
35
- // get node description
36
- const node_description = node_registry.getNode(description);
37
-
38
- if (node_description === undefined) {
39
- throw new Error(`Node ${description} not found in the registry`);
40
- }
41
-
42
- const nodeInstance = new NodeInstance();
43
-
44
- nodeInstance.id = node_id;
45
- nodeInstance.setDescription(node_description);
46
- nodeInstance.setParameters(parameters);
47
-
48
- graph.addNode(nodeInstance);
49
- }
50
-
51
- // parse connections
52
- const connection_count = connections.length;
53
-
54
- for (let i = 0; i < connection_count; i++) {
55
- const jConnection = connections[i];
56
-
57
- const jSource = jConnection.source;
58
- const jTarget = jConnection.target;
59
-
60
- graph.createConnection(jSource.instance, jSource.port, jTarget.instance, jTarget.port);
61
- }
62
- }
@@ -1,40 +0,0 @@
1
- /**
2
- *
3
- * @param {NodeGraph} graph
4
- */
5
- export function serializeNodeGraphToJSON(graph) {
6
- const nodes = [];
7
-
8
- graph.traverseNodes(node => {
9
-
10
- nodes.push({
11
- id: node.id,
12
- description: node.description.id,
13
- parameters: node.parameters
14
- });
15
-
16
- });
17
-
18
- const connections = [];
19
-
20
- graph.traverseConnections(connection => {
21
-
22
- connections.push({
23
- source: {
24
- instance: connection.source.instance.id,
25
- port: connection.source.port.id
26
- },
27
- target: {
28
- instance: connection.target.instance.id,
29
- port: connection.target.port.id
30
- }
31
- });
32
-
33
- });
34
-
35
- return {
36
- nodes,
37
- connections
38
- };
39
- }
40
-