@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.
- package/core/binary/BitSet.js +4 -18
- package/core/model/node-graph/Connection.js +41 -0
- package/core/model/node-graph/Connection.spec.js +21 -0
- package/core/model/node-graph/DataType.js +23 -1
- package/core/model/node-graph/DataType.spec.js +28 -0
- package/core/model/node-graph/NodeGraph.js +16 -7
- package/core/model/node-graph/node/NodeDescription.js +12 -5
- package/core/model/node-graph/node/NodeInstance.js +9 -3
- package/core/model/node-graph/node/NodeInstancePortReference.js +18 -0
- package/core/model/node-graph/node/NodeRegistry.js +36 -10
- package/core/model/node-graph/node/NodeRegistry.spec.js +25 -0
- package/core/model/node-graph/node/Port.js +12 -1
- package/core/model/node-graph/node/PortDirection.js +1 -1
- package/core/parser/simple/computeDataTypeFromValue.js +25 -0
- package/engine/graphics/render/frame_graph/RenderGraph.js +5 -1
- package/engine/graphics/render/gizmo/Gizmo.d.ts +3 -0
- package/engine/graphics/render/gizmo/GizmoRenderingPlugin.d.ts +5 -0
- package/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.d.ts +13 -0
- package/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +12 -0
- package/engine/intelligence/behavior/Behavior.d.ts +11 -0
- package/engine/intelligence/behavior/Behavior.js +4 -3
- package/engine/intelligence/behavior/BehaviorStatus.d.ts +8 -0
- package/engine/intelligence/behavior/SelectorBehavior.js +3 -1
- package/engine/intelligence/behavior/behavior_to_dot.js +251 -0
- package/engine/intelligence/behavior/behavior_to_dot.prototype.js +55 -0
- package/engine/intelligence/behavior/composite/CompositeBehavior.js +6 -0
- package/engine/intelligence/behavior/composite/ParallelBehavior.js +10 -0
- package/engine/intelligence/behavior/composite/SequenceBehavior.js +6 -50
- package/engine/intelligence/behavior/composite/SequenceBehaviorSerializationAdapter.js +52 -0
- package/engine/intelligence/behavior/ecs/BehaviorComponent.js +3 -8
- package/engine/intelligence/behavior/ecs/BehaviorComponentFlag.js +7 -0
- package/engine/intelligence/behavior/ecs/BehaviorSystem.js +2 -1
- package/engine/intelligence/behavior/ecs/ClockChannelType.js +7 -0
- package/engine/intelligence/behavior/primitive/SucceedingBehavior.js +1 -28
- package/engine/intelligence/behavior/primitive/SucceedingBehaviorSerializationAdapter.js +29 -0
- package/engine/intelligence/blackboard/AbstractBlackboard.js +9 -1
- package/engine/intelligence/blackboard/Blackboard.js +32 -54
- package/engine/intelligence/blackboard/Blackboard.spec.js +62 -0
- package/engine/intelligence/blackboard/{Blacboard.spec.js → BlackboardSerializationAdapter.spec.js} +1 -1
- package/engine/intelligence/blackboard/make_blackboard_proxy.js +47 -0
- package/engine/intelligence/blackboard/make_blackboard_proxy.spec.js +23 -0
- package/engine/intelligence/mcts/README.md +7 -0
- package/engine/intelligence/optimization/RandomOptimizer.js +2 -1
- package/engine/intelligence/resource/ResourceAllocationBid.js +3 -3
- package/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
- package/engine/intelligence/resource/StrategicResourceAllocator.js +6 -4
- package/engine/intelligence/resource/TacticalModule.js +7 -0
- package/engine/knowledge/database/StaticKnowledgeDataTableDescriptor.js +5 -5
- package/engine/navigation/grid/GridField.js +1 -0
- package/engine/notify/NotificationLog.js +2 -2
- 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<
|
|
23
|
+
* @type {Object<BlackboardValue>}
|
|
22
24
|
*/
|
|
23
25
|
this.data = {};
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* @private
|
|
27
29
|
*/
|
|
28
|
-
this.proxy =
|
|
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.
|
|
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.
|
|
111
|
+
assert.isString(name, 'name');
|
|
112
|
+
|
|
113
|
+
let datum;
|
|
137
114
|
|
|
138
115
|
if (this.data.hasOwnProperty(name)) {
|
|
139
116
|
// property exists
|
|
140
|
-
|
|
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
|
-
|
|
125
|
+
datum = new BlackboardValue(type);
|
|
126
|
+
|
|
127
|
+
const concrete_value = datum.value;
|
|
152
128
|
|
|
153
129
|
if (initialValue !== undefined) {
|
|
154
|
-
|
|
130
|
+
concrete_value.set(initialValue);
|
|
155
131
|
}
|
|
156
132
|
|
|
157
|
-
this.data[name] =
|
|
158
|
-
|
|
159
|
-
this.on.added.send4(name, blackboardValue.value.getValue(), type, this);
|
|
133
|
+
this.data[name] = datum;
|
|
160
134
|
|
|
161
|
-
|
|
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.
|
|
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
|
+
});
|
|
@@ -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
|
+
});
|
|
@@ -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.
|
|
16
|
-
assert.
|
|
15
|
+
assert.defined(allocation, 'allocation');
|
|
16
|
+
assert.notNull(allocation, 'allocation');
|
|
17
17
|
|
|
18
|
-
assert.
|
|
18
|
+
assert.isNumber(value, 'value');
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
*
|
|
@@ -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.
|
|
57
|
-
assert.
|
|
58
|
-
assert.
|
|
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.
|
|
64
|
+
assert.isArray(moduleBids, 'moduleBids');
|
|
63
65
|
|
|
64
66
|
moduleBids.forEach(b => bids.set(b, m));
|
|
65
67
|
|
|
@@ -31,12 +31,12 @@ export class StaticKnowledgeDataTableDescriptor {
|
|
|
31
31
|
*/
|
|
32
32
|
static from(id, source, table) {
|
|
33
33
|
|
|
34
|
-
assert.
|
|
35
|
-
assert.
|
|
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,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.
|
|
8
|
+
"version": "2.43.43",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|