@woosh/meep-engine 2.43.40 → 2.43.43

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 (51) hide show
  1. package/core/binary/BitSet.js +4 -18
  2. package/core/model/node-graph/Connection.js +41 -0
  3. package/core/model/node-graph/Connection.spec.js +21 -0
  4. package/core/model/node-graph/DataType.js +23 -1
  5. package/core/model/node-graph/DataType.spec.js +28 -0
  6. package/core/model/node-graph/NodeGraph.js +16 -7
  7. package/core/model/node-graph/node/NodeDescription.js +12 -5
  8. package/core/model/node-graph/node/NodeInstance.js +9 -3
  9. package/core/model/node-graph/node/NodeInstancePortReference.js +18 -0
  10. package/core/model/node-graph/node/NodeRegistry.js +36 -10
  11. package/core/model/node-graph/node/NodeRegistry.spec.js +25 -0
  12. package/core/model/node-graph/node/Port.js +12 -1
  13. package/core/model/node-graph/node/PortDirection.js +1 -1
  14. package/core/parser/simple/computeDataTypeFromValue.js +25 -0
  15. package/engine/graphics/render/frame_graph/RenderGraph.js +5 -1
  16. package/engine/graphics/render/gizmo/Gizmo.d.ts +3 -0
  17. package/engine/graphics/render/gizmo/GizmoRenderingPlugin.d.ts +5 -0
  18. package/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.d.ts +13 -0
  19. package/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +12 -0
  20. package/engine/intelligence/behavior/Behavior.d.ts +11 -0
  21. package/engine/intelligence/behavior/Behavior.js +4 -3
  22. package/engine/intelligence/behavior/BehaviorStatus.d.ts +8 -0
  23. package/engine/intelligence/behavior/SelectorBehavior.js +3 -1
  24. package/engine/intelligence/behavior/behavior_to_dot.js +251 -0
  25. package/engine/intelligence/behavior/behavior_to_dot.prototype.js +55 -0
  26. package/engine/intelligence/behavior/composite/CompositeBehavior.js +6 -0
  27. package/engine/intelligence/behavior/composite/ParallelBehavior.js +10 -0
  28. package/engine/intelligence/behavior/composite/SequenceBehavior.js +6 -50
  29. package/engine/intelligence/behavior/composite/SequenceBehaviorSerializationAdapter.js +52 -0
  30. package/engine/intelligence/behavior/ecs/BehaviorComponent.js +3 -8
  31. package/engine/intelligence/behavior/ecs/BehaviorComponentFlag.js +7 -0
  32. package/engine/intelligence/behavior/ecs/BehaviorSystem.js +2 -1
  33. package/engine/intelligence/behavior/ecs/ClockChannelType.js +7 -0
  34. package/engine/intelligence/behavior/primitive/SucceedingBehavior.js +1 -28
  35. package/engine/intelligence/behavior/primitive/SucceedingBehaviorSerializationAdapter.js +29 -0
  36. package/engine/intelligence/blackboard/AbstractBlackboard.js +9 -1
  37. package/engine/intelligence/blackboard/Blackboard.js +32 -54
  38. package/engine/intelligence/blackboard/Blackboard.spec.js +62 -0
  39. package/engine/intelligence/blackboard/{Blacboard.spec.js → BlackboardSerializationAdapter.spec.js} +1 -1
  40. package/engine/intelligence/blackboard/make_blackboard_proxy.js +47 -0
  41. package/engine/intelligence/blackboard/make_blackboard_proxy.spec.js +23 -0
  42. package/engine/intelligence/mcts/README.md +7 -0
  43. package/engine/intelligence/optimization/RandomOptimizer.js +2 -1
  44. package/engine/intelligence/resource/ResourceAllocationBid.js +3 -3
  45. package/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  46. package/engine/intelligence/resource/StrategicResourceAllocator.js +6 -4
  47. package/engine/intelligence/resource/TacticalModule.js +7 -0
  48. package/engine/knowledge/database/StaticKnowledgeDataTableDescriptor.js +5 -5
  49. package/engine/navigation/grid/GridField.js +1 -0
  50. package/engine/notify/NotificationLog.js +2 -2
  51. package/package.json +1 -1
@@ -3,6 +3,8 @@ import { assert } from "../../../core/assert.js";
3
3
  import Signal from "../../../core/events/signal/Signal.js";
4
4
  import { BlackboardValue } from "./BlackboardValue.js";
5
5
  import { AbstractBlackboard } from "./AbstractBlackboard.js";
6
+ import { make_blackboard_proxy } from "./make_blackboard_proxy.js";
7
+
6
8
 
7
9
  export class Blackboard extends AbstractBlackboard {
8
10
  constructor() {
@@ -18,54 +20,18 @@ export class Blackboard extends AbstractBlackboard {
18
20
 
19
21
  /**
20
22
  *
21
- * @type {Object<string,BlackboardValue>}
23
+ * @type {Object<BlackboardValue>}
22
24
  */
23
25
  this.data = {};
24
26
 
25
27
  /**
26
28
  * @private
27
29
  */
28
- this.proxy = new Proxy(this, {
29
- /**
30
- *
31
- * @param target
32
- * @param {string} p
33
- * @param receiver
34
- * @returns {*}
35
- */
36
- get(target, p, receiver) {
37
- const data = target.data;
38
-
39
- if (!data.hasOwnProperty(p)) {
40
- // property not found
41
- return undefined;
42
- }
43
-
44
- const blackboardValue = data[p];
45
-
46
- const resolved_value = blackboardValue.value.getValue();
47
-
48
- return resolved_value;
49
- },
50
- set(target, p, value, receiver) {
51
-
52
-
53
- const blackboardValue = target.data[p];
54
-
55
- if (blackboardValue === undefined) {
56
- // blackboard property not found
57
- return undefined;
58
- }
59
-
60
- blackboardValue.value.set(value);
61
-
62
- },
63
- ownKeys(target) {
64
-
65
- return Reflect.ownKeys(target.data);
30
+ this.proxy = make_blackboard_proxy(this);
31
+ }
66
32
 
67
- }
68
- });
33
+ getKeys() {
34
+ return Reflect.ownKeys(this.data);
69
35
  }
70
36
 
71
37
  /**
@@ -76,7 +42,16 @@ export class Blackboard extends AbstractBlackboard {
76
42
  return this.proxy;
77
43
  }
78
44
 
45
+ /**
46
+ *
47
+ * @param {string} name
48
+ * @param {DataType} type
49
+ * @return {boolean} true only if entry exists and matches type, or if supplied parameter type is set to "Any"
50
+ */
79
51
  contains(name, type) {
52
+ assert.isString(name, 'name');
53
+ assert.enum(type, DataType, 'type');
54
+
80
55
  const datum = this.data[name];
81
56
 
82
57
  if (datum === undefined) {
@@ -115,7 +90,7 @@ export class Blackboard extends AbstractBlackboard {
115
90
  * @param {RegExp} pattern
116
91
  */
117
92
  traverseWithPattern(pattern, visitor) {
118
- assert.notEqual(pattern, undefined, 'pattern is undefined');
93
+ assert.defined(pattern, 'pattern');
119
94
  assert.ok(pattern instanceof RegExp, 'pattern is not a RegExp');
120
95
 
121
96
  this.traverse(function (name, value, type) {
@@ -133,33 +108,36 @@ export class Blackboard extends AbstractBlackboard {
133
108
  * @returns {T}
134
109
  */
135
110
  acquire(name, type, initialValue) {
136
- assert.typeOf(name, 'string', 'name');
111
+ assert.isString(name, 'name');
112
+
113
+ let datum;
137
114
 
138
115
  if (this.data.hasOwnProperty(name)) {
139
116
  // property exists
140
- const datum = this.data[name];
117
+ datum = this.data[name];
141
118
 
142
119
  if (type !== DataType.Any && datum.type !== type) {
143
120
  throw new TypeError(`Value '${name}' exists, but is type(='${datum.type}'), expected type '${type}'`);
144
121
  }
145
122
 
146
- datum.referenceCount++;
147
-
148
- return datum.value;
149
123
  } else {
150
124
  //doesn't exist - create it
151
- const blackboardValue = new BlackboardValue(type);
125
+ datum = new BlackboardValue(type);
126
+
127
+ const concrete_value = datum.value;
152
128
 
153
129
  if (initialValue !== undefined) {
154
- blackboardValue.value.set(initialValue);
130
+ concrete_value.set(initialValue);
155
131
  }
156
132
 
157
- this.data[name] = blackboardValue;
158
-
159
- this.on.added.send4(name, blackboardValue.value.getValue(), type, this);
133
+ this.data[name] = datum;
160
134
 
161
- return blackboardValue.value;
135
+ this.on.added.send4(name, concrete_value.getValue(), type, this);
162
136
  }
137
+
138
+ datum.referenceCount++;
139
+
140
+ return datum.value;
163
141
  }
164
142
 
165
143
  /**
@@ -230,7 +208,7 @@ export class Blackboard extends AbstractBlackboard {
230
208
  if (value_type === 'number') {
231
209
  this.acquireNumber(propName, value).set(value);
232
210
  } else if (value_type === 'boolean') {
233
- this.acquireNumber(propName, value).set(value);
211
+ this.acquireBoolean(propName, value).set(value);
234
212
  } else if (value_type === 'string') {
235
213
  this.acquireString(propName, value).set(value);
236
214
  }
@@ -0,0 +1,62 @@
1
+ import { Blackboard } from "./Blackboard.js";
2
+ import { DataType } from "../../../core/parser/simple/DataType.js";
3
+
4
+ test('"contains" method', () => {
5
+ const bb = new Blackboard();
6
+
7
+ expect(bb.contains('a', DataType.Any)).toBe(false);
8
+
9
+ bb.acquireNumber('a', 0);
10
+
11
+ expect(bb.contains('a', DataType.Number)).toBe(true);
12
+ expect(bb.contains('a', DataType.Any)).toBe(true);
13
+ expect(bb.contains('a', DataType.Boolean)).toBe(false);
14
+
15
+ expect(bb.contains('b', DataType.Number)).toBe(false);
16
+ });
17
+
18
+
19
+ test("entry is deleted after reset", () => {
20
+ const bb = new Blackboard();
21
+
22
+ bb.acquireNumber('a');
23
+
24
+ bb.reset();
25
+
26
+ expect(bb.contains('a', DataType.Number)).toBe(false);
27
+ });
28
+
29
+ test("entry is copied across when blackboard is copied", () => {
30
+ const a = new Blackboard();
31
+
32
+ a.acquireNumber('test', 7);
33
+
34
+ const b = new Blackboard();
35
+
36
+ b.copy(a);
37
+
38
+ expect(b.contains('test', DataType.Number)).toBe(true);
39
+ expect(b.acquireNumber('test').getValue()).toBe(7);
40
+ });
41
+
42
+ test("to/from JSON serialization consistency", () => {
43
+
44
+ const source = new Blackboard();
45
+
46
+ source.acquireNumber('count', 7.1);
47
+ source.acquireBoolean('flag', true);
48
+ source.acquireString('label', 'hello');
49
+
50
+ const target = new Blackboard();
51
+
52
+ target.fromJSON(source.toJSON());
53
+
54
+ expect(target.contains('count', DataType.Number)).toBe(true);
55
+ expect(target.acquireNumber('count').getValue()).toBe(7.1);
56
+
57
+ expect(target.contains('flag', DataType.Boolean)).toBe(true);
58
+ expect(target.acquireBoolean('flag').getValue()).toBe(true);
59
+
60
+ expect(target.contains('label', DataType.String)).toBe(true);
61
+ expect(target.acquireString('label').getValue()).toBe('hello');
62
+ });
@@ -1,4 +1,4 @@
1
- import { Blackboard} from "./Blackboard.js";
1
+ import { Blackboard } from "./Blackboard.js";
2
2
  import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
3
3
  import { BlackboardSerializationAdapter } from "./BlackboardSerializationAdapter.js";
4
4
 
@@ -0,0 +1,47 @@
1
+ import DataType from "../../../core/parser/simple/DataType.js";
2
+ import { computeDataTypeFromValue } from "../../../core/parser/simple/computeDataTypeFromValue.js";
3
+
4
+ /**
5
+ * Given a blackboard, returns a Proxy instance, exposing blackboard attributes as plain JSON
6
+ * Useful for connecting blackboard to systems that are not explicitly designed to work with a blackboard
7
+ * @param {AbstractBlackboard} blackboard
8
+ * @returns {Proxy}
9
+ */
10
+ export function make_blackboard_proxy(blackboard) {
11
+ return new Proxy(blackboard, {
12
+ /**
13
+ *
14
+ * @param target
15
+ * @param {string} p
16
+ * @param receiver
17
+ * @returns {*}
18
+ */
19
+ get(target, p, receiver) {
20
+
21
+ if (!target.contains(p, DataType.Any)) {
22
+ // property not found
23
+ return undefined;
24
+ }
25
+
26
+ const value_container = target.acquire(p, DataType.Any);
27
+
28
+ return value_container.getValue();
29
+ },
30
+ set(target, p, value, receiver) {
31
+
32
+ const dataType = computeDataTypeFromValue(value);
33
+
34
+ const value_container = target.acquire(p, dataType, value);
35
+
36
+ value_container.set(value);
37
+
38
+ // succeeded
39
+ return true;
40
+ },
41
+ ownKeys(target) {
42
+
43
+ return target.getKeys();
44
+
45
+ }
46
+ })
47
+ }
@@ -0,0 +1,23 @@
1
+ import { Blackboard } from "./Blackboard.js";
2
+ import { make_blackboard_proxy } from "./make_blackboard_proxy.js";
3
+
4
+ test("setters propagate", () => {
5
+ const bb = new Blackboard();
6
+
7
+ const proxy = make_blackboard_proxy(bb);
8
+
9
+ proxy.hello = 7;
10
+
11
+ expect(bb.acquireNumber('hello').getValue()).toBe(7);
12
+ });
13
+
14
+
15
+ test("getters propagate", () => {
16
+ const bb = new Blackboard();
17
+
18
+ bb.acquireNumber('hello').set(7);
19
+
20
+ const proxy = make_blackboard_proxy(bb);
21
+
22
+ expect(proxy.hello).toBe(7);
23
+ });
@@ -0,0 +1,7 @@
1
+ Monte-Carlo Tree Search simulation package
2
+
3
+ Intended for development of AI features
4
+
5
+
6
+ References:
7
+ * https://en.wikipedia.org/wiki/Monte_Carlo_tree_search
@@ -2,7 +2,8 @@ import { seededRandom } from "../../../core/math/random/seededRandom.js";
2
2
  import { randomFromArray } from "../../../core/math/random/randomFromArray.js";
3
3
 
4
4
  /**
5
- * Hill climbing optimizer based on random moves
5
+ * Hill climbing optimizer based on testing random moves one move at a time, if overall fitness improves - that move is committed, otherwise it's rejected
6
+ * Very dumb, but quite effective. Requires very little code to write a competent optimizer, especially when state space is relatively small
6
7
  * @template S
7
8
  * @class
8
9
  */
@@ -12,10 +12,10 @@ export class ResourceAllocationBid {
12
12
  * @param {number} value
13
13
  */
14
14
  constructor(allocation, value) {
15
- assert.notEqual(allocation, undefined, 'allocation is undefined');
16
- assert.notEqual(allocation, null, 'allocation is null');
15
+ assert.defined(allocation, 'allocation');
16
+ assert.notNull(allocation, 'allocation');
17
17
 
18
- assert.typeOf(value, 'number', 'value');
18
+ assert.isNumber(value, 'value');
19
19
 
20
20
  /**
21
21
  *
@@ -1,7 +1,7 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
 
3
3
  /**
4
- *
4
+ * Sorting comparator
5
5
  * @param {ResourceAllocationBid} a
6
6
  * @param {ResourceAllocationBid} b
7
7
  * @returns {number}
@@ -31,6 +31,8 @@ export class StrategicResourceAllocator {
31
31
  */
32
32
  addTacticalModule(module) {
33
33
  assert.defined(module, 'module');
34
+ assert.notNull(module, 'module');
35
+ assert.equal(module.isTacticalModule, true, 'module.TacticalModule !== true');
34
36
 
35
37
  this.modules.push(module);
36
38
  }
@@ -53,13 +55,13 @@ export class StrategicResourceAllocator {
53
55
  const moduleResults = this.modules.map(m => {
54
56
  const promise = m.collectBids(resources);
55
57
 
56
- assert.notEqual(promise, undefined, 'promise is undefined');
57
- assert.notEqual(promise, null, 'promise is null');
58
- assert.typeOf(promise.then, 'function', "promise.then");
58
+ assert.defined(promise, 'promise');
59
+ assert.notNull(promise, 'promise');
60
+ assert.isFunction(promise.then, "promise.then");
59
61
 
60
62
  promise.then(moduleBids => {
61
63
 
62
- assert.ok(Array.isArray(moduleBids), `moduleBids expected to be an array, was something else (typeof='${typeof moduleBids}')`);
64
+ assert.isArray(moduleBids, 'moduleBids');
63
65
 
64
66
  moduleBids.forEach(b => bids.set(b, m));
65
67
 
@@ -12,3 +12,10 @@ export class TacticalModule {
12
12
  throw new Error('Method needs to be overridden');
13
13
  }
14
14
  }
15
+
16
+
17
+ /**
18
+ * @readonly
19
+ * @type {boolean}
20
+ */
21
+ TacticalModule.prototype.isTacticalModule = true;
@@ -31,12 +31,12 @@ export class StaticKnowledgeDataTableDescriptor {
31
31
  */
32
32
  static from(id, source, table) {
33
33
 
34
- assert.typeOf(id,'string','id');
35
- assert.typeOf(source,'string','source');
34
+ assert.isString(id, 'id');
35
+ assert.isString(source, 'source');
36
36
 
37
- assert.defined(table,'table');
38
- assert.notNull(table,'table');
39
- assert.equal(table.isStaticKnowledgeDataTable, true,'table.isStaticKnowledgeDataTable !== true');
37
+ assert.defined(table, 'table');
38
+ assert.notNull(table, 'table');
39
+ assert.equal(table.isStaticKnowledgeDataTable, true, 'table.isStaticKnowledgeDataTable !== true');
40
40
 
41
41
 
42
42
  const r = new StaticKnowledgeDataTableDescriptor();
@@ -9,6 +9,7 @@ const blockValue = 255;
9
9
  /**
10
10
  * A kind of 2D data texture
11
11
  * @deprecated prefer using {@link Sampler2D} instead, as it's more versatile and has wider feature set
12
+ *
12
13
  * @param {Number} width
13
14
  * @param {Number} height
14
15
  * @constructor
@@ -9,13 +9,13 @@ import { assert } from "../../core/assert.js";
9
9
 
10
10
  function NotificationLog() {
11
11
  /**
12
- *
12
+ * @readonly
13
13
  * @type {List<Notification>}
14
14
  */
15
15
  this.elements = new List();
16
16
 
17
17
  /**
18
- *
18
+ * Once number of entries in the log reaches this amount, the earliest entries will be removed to make space for new ones
19
19
  * @type {number}
20
20
  */
21
21
  this.maxLength = 1000;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.43.40",
8
+ "version": "2.43.43",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",