@woosh/meep-engine 2.36.4 → 2.36.7

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.
@@ -6,13 +6,15 @@ import {AssetLoader} from "./asset/loaders/AssetLoader";
6
6
  export class EngineConfiguration {
7
7
  addPlugin(plugin: EnginePlugin): boolean
8
8
 
9
- addSystem(system: System): boolean
9
+ addSystem<A, B, C, D, E>(system: System<A, B, C, D, E>): boolean
10
10
 
11
- addManySystems(...systems: System[]): void
11
+ addManySystems(...systems: System<any>[]): void
12
12
 
13
13
  addDataTable(table: StaticKnowledgeDataTableDescriptor): boolean
14
14
 
15
- addLoader<T>(type: string, loader: AssetLoader<T>): boolean;
15
+ addLoader<T>(type: string, loader: AssetLoader<T>): boolean
16
+
17
+ hasLoader(type: string): boolean
16
18
 
17
19
  apply(engine): Promise<any>
18
20
  }
@@ -28,6 +28,15 @@ export class EngineConfiguration {
28
28
  this.loaders = new Map();
29
29
  }
30
30
 
31
+ /**
32
+ *
33
+ * @param {string} type
34
+ * @returns {boolean}
35
+ */
36
+ hasLoader(type) {
37
+ return this.loaders.has(type);
38
+ }
39
+
31
40
  /**
32
41
  * @template T
33
42
  * @param {string} type
@@ -26,6 +26,7 @@ import { EngineConfiguration } from "./EngineConfiguration.js";
26
26
  import { JsonAssetLoader } from "./asset/loaders/JsonAssetLoader.js";
27
27
  import { logger } from "./logging/GlobalLogger.js";
28
28
  import { ConsoleLoggerBackend } from "./logging/ConsoleLoggerBackend.js";
29
+ import { noop } from "../core/function/Functions.js";
29
30
 
30
31
  /**
31
32
  *
@@ -85,10 +86,12 @@ export class EngineHarness {
85
86
  }
86
87
 
87
88
  /**
88
- *
89
+ * @param {(config:EngineConfiguration,engine:Engine)=>*} configuration
89
90
  * @returns {Promise<Engine>}
90
91
  */
91
- initialize() {
92
+ initialize({
93
+ configuration = noop
94
+ } = {}) {
92
95
 
93
96
  if (this.p !== null) {
94
97
  return this.p;
@@ -98,7 +101,12 @@ export class EngineHarness {
98
101
 
99
102
  const promise = new Promise(async function (resolve, reject) {
100
103
  const config = new EngineConfiguration();
101
- config.addLoader('json', new JsonAssetLoader());
104
+
105
+ configuration(config, engine);
106
+
107
+ if (!config.hasLoader('json')) {
108
+ config.addLoader('json', new JsonAssetLoader());
109
+ }
102
110
 
103
111
  await config.apply(engine);
104
112
 
@@ -0,0 +1,3 @@
1
+ export default class GUIElement {
2
+
3
+ }
@@ -1,7 +1,8 @@
1
1
  import {System} from "../System";
2
2
  import Engine from "../../Engine";
3
3
  import View from "../../../view/View";
4
+ import {GUIElement} from "./GUIElement";
4
5
 
5
- export default class GUIElementSystem extends System {
6
+ export default class GUIElementSystem extends System<GUIElement> {
6
7
  constructor(container: View, engine: Engine)
7
8
  }
@@ -16,7 +16,7 @@ export class EntityNode {
16
16
 
17
17
  removeChild(node: EntityNode): boolean
18
18
 
19
- traverseChildren(visitor: (EntityNode) => void, thisArg?: any): void
19
+ traverse(visitor: (node: EntityNode) => any, thisArg?: any): void
20
20
 
21
21
  build(ecd: EntityComponentDataset): void
22
22
 
@@ -5,6 +5,7 @@ import { assert } from "../../../core/assert.js";
5
5
  import { array_push_if_unique } from "../../../core/collection/array/array_push_if_unique.js";
6
6
  import { Transform } from "../transform/Transform.js";
7
7
  import { TransformAttachment, TransformAttachmentFlags } from "../transform-attachment/TransformAttachment.js";
8
+ import Signal from "../../../core/events/signal/Signal.js";
8
9
 
9
10
  export class EntityNode {
10
11
  /**
@@ -39,6 +40,29 @@ export class EntityNode {
39
40
  * @private
40
41
  */
41
42
  this.__transform = new Transform();
43
+
44
+ this.on = {
45
+ built: new Signal(),
46
+ destroyed: new Signal()
47
+ };
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param {(node:EntityNode)=>*} visitor
53
+ * @param {*} [thisArg]
54
+ */
55
+ traverse(visitor, thisArg) {
56
+ visitor.call(thisArg, this);
57
+
58
+ const children = this.__children;
59
+ const n = children.length;
60
+
61
+ for (let i = 0; i < n; i++) {
62
+ const child = children[i];
63
+
64
+ child.traverse(visitor, thisArg);
65
+ }
42
66
  }
43
67
 
44
68
  /**
@@ -276,6 +300,8 @@ export class EntityNode {
276
300
 
277
301
  child.build(ecd);
278
302
  }
303
+
304
+ this.on.built.send0();
279
305
  }
280
306
 
281
307
  destroy() {
@@ -295,5 +321,7 @@ export class EntityNode {
295
321
 
296
322
  // then main entity
297
323
  this.__entity.destroy();
324
+
325
+ this.on.destroyed.send0();
298
326
  }
299
327
  }
@@ -1,6 +1,7 @@
1
1
  import {System} from "../System";
2
2
  import {GraphicsEngine} from "../../graphics/GraphicsEngine";
3
+ import Renderable from "../components/Renderable";
3
4
 
4
- export default class RenderSystem extends System {
5
+ export default class RenderSystem extends System<Renderable> {
5
6
  constructor(graphics: GraphicsEngine)
6
7
  }
@@ -12,11 +12,62 @@ function update(parent_transform, attachment_transform, child_transform) {
12
12
  child_transform.multiplyTransforms(parent_transform, attachment_transform);
13
13
  }
14
14
 
15
+ class UpdateContext {
16
+ constructor() {
17
+ /**
18
+ *
19
+ * @type {TransformAttachment|null}
20
+ */
21
+ this.attachment = null;
22
+
23
+ /**
24
+ *
25
+ * @type {Transform|null}
26
+ */
27
+ this.transform = null;
28
+
29
+ /**
30
+ *
31
+ * @type {number}
32
+ */
33
+ this.entity = -1;
34
+
35
+ /**
36
+ *
37
+ * @type {Transform|null}
38
+ */
39
+ this.parent_transform = null;
40
+ }
41
+
42
+ update() {
43
+ update(this.parent_transform, this.attachment.transform, this.transform);
44
+ }
45
+
46
+ link() {
47
+ this.parent_transform.position.onChanged.add(this.update, this);
48
+ this.parent_transform.rotation.onChanged.add(this.update, this);
49
+ this.parent_transform.scale.onChanged.add(this.update, this);
50
+ }
51
+
52
+ unlink() {
53
+ this.parent_transform.position.onChanged.remove(this.update, this);
54
+ this.parent_transform.rotation.onChanged.remove(this.update, this);
55
+ this.parent_transform.scale.onChanged.remove(this.update, this);
56
+ }
57
+ }
58
+
15
59
  export class TransformAttachmentSystem extends System {
16
60
  constructor() {
17
61
  super();
18
62
 
19
63
  this.dependencies = [TransformAttachment, Transform];
64
+
65
+ /**
66
+ *
67
+ * @type {UpdateContext[]}
68
+ * @private
69
+ */
70
+ this.__contexts = [];
20
71
  }
21
72
 
22
73
  /**
@@ -25,25 +76,23 @@ export class TransformAttachmentSystem extends System {
25
76
  * @param {Transform} transform
26
77
  * @param {number} entity
27
78
  */
28
- __update_one(attachment, transform, entity) {
79
+ link(attachment, transform, entity) {
80
+ const ctx = new UpdateContext();
81
+ ctx.system = this;
29
82
 
30
- const em = this.entityManager;
31
- const ecd = em.dataset;
83
+ ctx.attachment = attachment;
84
+ ctx.transform = transform;
85
+ ctx.entity = entity;
32
86
 
33
- const parent_transform = ecd.getComponent(attachment.parent, Transform);
34
87
 
35
- update(parent_transform, attachment.transform, transform);
36
- }
88
+ ctx.parent_transform = this.entityManager.dataset.getComponent(attachment.parent, Transform);
89
+
90
+ ctx.link();
91
+
92
+ this.__contexts[entity] = ctx;
37
93
 
38
- /**
39
- *
40
- * @param {TransformAttachment} attachment
41
- * @param {Transform} transform
42
- * @param {number} entity
43
- */
44
- link(attachment, transform, entity) {
45
94
  if ((attachment.flags & TransformAttachmentFlags.Immediate) !== 0) {
46
- this.__update_one(attachment, transform, entity);
95
+ ctx.update();
47
96
  }
48
97
  }
49
98
 
@@ -55,5 +104,11 @@ export class TransformAttachmentSystem extends System {
55
104
  */
56
105
  unlink(attachment, transform, entity) {
57
106
 
107
+
108
+ const ctx = this.__contexts[entity];
109
+
110
+ delete this.__contexts[entity];
111
+
112
+ ctx.unlink();
58
113
  }
59
114
  }
@@ -4,7 +4,7 @@ import {GraphicsEngine} from "../../GraphicsEngine";
4
4
  import {EntityComponentDataset} from "../../../ecs/EntityComponentDataset";
5
5
  import {Camera} from "./Camera";
6
6
 
7
- export class CameraSystem extends System {
7
+ export class CameraSystem extends System<Camera> {
8
8
  constructor(scene: Scene, graphics: GraphicsEngine)
9
9
 
10
10
  public static getFirstActiveCamera(ecd: EntityComponentDataset): { entity: number, component: Camera | undefined }
@@ -1,7 +1,8 @@
1
1
  import {System} from "../../../ecs/System";
2
2
  import Engine from "../../../Engine";
3
+ import {Light} from "./Light";
3
4
 
4
- export default class LightSystem extends System {
5
+ export default class LightSystem extends System<Light> {
5
6
  constructor(engine: Engine, {
6
7
  shadowResolution
7
8
  }: {
@@ -1,6 +1,7 @@
1
1
  import {System} from "../../../ecs/System";
2
2
  import Engine from "../../../Engine";
3
+ import Mesh from "./Mesh";
3
4
 
4
- export class MeshSystem extends System {
5
+ export class MeshSystem extends System<Mesh> {
5
6
  constructor(engine: Engine)
6
7
  }
@@ -0,0 +1,8 @@
1
+ export class SGMesh {
2
+ url: string
3
+
4
+ castShadow: boolean
5
+ receiveShadow: boolean
6
+
7
+ static fromURL(url: string): SGMesh
8
+ }
@@ -117,6 +117,21 @@ export class SGMesh {
117
117
  set receiveShadow(v) {
118
118
  this.writeFlag(SGMeshFlags.ReceiveShadow, v);
119
119
  }
120
+
121
+ /**
122
+ *
123
+ * @param {string} url
124
+ * @returns {SGMesh}
125
+ */
126
+ static fromURL(url) {
127
+ const r = new SGMesh();
128
+
129
+ r.url = url;
130
+ r.castShadow = true;
131
+ r.receiveShadow = true;
132
+
133
+ return r;
134
+ }
120
135
  }
121
136
 
122
137
  SGMesh.typeName = "SGMesh";
@@ -0,0 +1,12 @@
1
+ export enum SGMeshEvents {
2
+
3
+ /**
4
+ * When asset is attached/loaded onto the Mesh component.
5
+ * This is the time when the 3d data becomes renderable
6
+ */
7
+ AssetLoaded= '@ecd-component-SGMesh/asset-attached',
8
+ /**
9
+ * Required asset failed to load for whatever reason
10
+ */
11
+ AssetLoadFailed= '@ecd-component-SGMesh/asset-failed',
12
+ }
@@ -0,0 +1,12 @@
1
+ export const SGMeshEvents = {
2
+
3
+ /**
4
+ * When asset is attached/loaded onto the Mesh component.
5
+ * This is the time when the 3d data becomes renderable
6
+ */
7
+ AssetLoaded: '@ecd-component-SGMesh/asset-attached',
8
+ /**
9
+ * Required asset failed to load for whatever reason
10
+ */
11
+ AssetLoadFailed: '@ecd-component-SGMesh/asset-failed',
12
+ };
@@ -0,0 +1,8 @@
1
+ import {System} from "../../../../ecs/System";
2
+ import {SGMesh} from "./SGMesh";
3
+ import {Transform} from "../../../../ecs/transform/Transform";
4
+ import Engine from "../../../../Engine";
5
+
6
+ export class SGMeshSystem extends System<SGMesh, Transform> {
7
+ constructor(engine: Engine)
8
+ }
@@ -3,6 +3,9 @@ import { SGMesh } from "./SGMesh.js";
3
3
  import { Transform } from "../../../../ecs/transform/Transform.js";
4
4
  import { assetTypeByPath } from "../../mesh/assetTypeByPath.js";
5
5
  import { three_object_to_entity_composition } from "../three_object_to_entity_composition.js";
6
+ import { ShadedGeometry } from "../ShadedGeometry.js";
7
+ import { ShadedGeometryFlags } from "../ShadedGeometryFlags.js";
8
+ import { SGMeshEvents } from "./SGMeshEvents.js";
6
9
 
7
10
 
8
11
  /**
@@ -57,10 +60,18 @@ export class SGMeshSystem extends System {
57
60
  */
58
61
  async process(entity, mesh, transform) {
59
62
  const am = this.__assetManager;
63
+ const ecd = this.entityManager.dataset;
60
64
 
61
- const assetType = assetTypeByPath(component.url);
65
+ const assetType = assetTypeByPath(mesh.url);
62
66
 
63
- const asset = await am.promise(mesh.url, assetType);
67
+ let asset;
68
+
69
+ try {
70
+ asset = await am.promise(mesh.url, assetType);
71
+ } catch (e) {
72
+ ecd.sendEvent(entity, SGMeshEvents.AssetLoadFailed);
73
+ return;
74
+ }
64
75
 
65
76
  // TODO check that entity still exists, as we get to this point asynchronously
66
77
 
@@ -68,7 +79,51 @@ export class SGMeshSystem extends System {
68
79
 
69
80
  mesh.__node = entity_node;
70
81
 
71
- entity_node.build(this.entityManager.dataset);
82
+ entity_node.transform.copy(transform);
83
+
84
+ entity_node.build(ecd);
85
+
86
+ function update_position() {
87
+ entity_node.transform.position.copy(transform.position);
88
+ }
89
+
90
+ function update_rotation() {
91
+ entity_node.transform.rotation.copy(transform.rotation);
92
+ }
93
+
94
+ function update_scale() {
95
+ entity_node.transform.scale.copy(transform.scale);
96
+ }
97
+
98
+ transform.position.onChanged.add(update_position);
99
+ transform.rotation.onChanged.add(update_rotation);
100
+ transform.scale.onChanged.add(update_scale);
101
+
102
+ entity_node.on.destroyed.addOne(() => {
103
+
104
+ transform.position.onChanged.remove(update_position);
105
+ transform.rotation.onChanged.remove(update_rotation);
106
+ transform.scale.onChanged.remove(update_scale);
107
+
108
+ });
109
+
110
+ // apply flags to the hierarchy
111
+ entity_node.traverse(node => {
112
+ /**
113
+ *
114
+ * @type {ShadedGeometry|null}
115
+ */
116
+ const sg = node.entity.getComponent(ShadedGeometry);
117
+ if (sg === null) {
118
+ return;
119
+ }
120
+
121
+ sg.writeFlag(ShadedGeometryFlags.CastShadow, mesh.castShadow);
122
+ sg.writeFlag(ShadedGeometryFlags.ReceiveShadow, mesh.receiveShadow);
123
+ });
124
+
125
+
126
+ ecd.sendEvent(entity, SGMeshEvents.AssetLoaded);
72
127
  }
73
128
 
74
129
  /**
@@ -0,0 +1,53 @@
1
+ import { EngineHarness } from "../../../../EngineHarness.js";
2
+ import { ShadedGeometrySystem } from "../ShadedGeometrySystem.js";
3
+ import { SGMeshSystem } from "./SGMeshSystem.js";
4
+ import EntityBuilder from "../../../../ecs/EntityBuilder.js";
5
+ import { Transform } from "../../../../ecs/transform/Transform.js";
6
+ import { SGMesh } from "./SGMesh.js";
7
+ import { GameAssetType } from "../../../../asset/GameAssetType.js";
8
+ import { GLTFAssetLoader } from "../../../../asset/loaders/GLTFAssetLoader.js";
9
+ import Vector3 from "../../../../../core/geom/Vector3.js";
10
+ import { BehaviorSystem } from "../../../../intelligence/behavior/ecs/BehaviorSystem.js";
11
+ import { BehaviorComponent } from "../../../../intelligence/behavior/ecs/BehaviorComponent.js";
12
+ import { OrbitingBehavior } from "../../../../../../model/game/util/behavior/OrbitingBehavior.js";
13
+ import { TransformAttachmentSystem } from "../../../../ecs/transform-attachment/TransformAttachmentSystem.js";
14
+
15
+ new EngineHarness().initialize({
16
+ configuration(config, engine) {
17
+ config.addManySystems(
18
+ new ShadedGeometrySystem(engine),
19
+ new SGMeshSystem(engine),
20
+ new BehaviorSystem(engine),
21
+ new TransformAttachmentSystem()
22
+ );
23
+
24
+ config.addLoader(GameAssetType.ModelGLTF_JSON, new GLTFAssetLoader());
25
+ }
26
+ }).then(main);
27
+
28
+ /**
29
+ *
30
+ * @param {Engine} engine
31
+ */
32
+ function main(engine) {
33
+ EngineHarness.buildBasics({
34
+ engine
35
+ });
36
+
37
+ const ecd = engine.entityManager.dataset;
38
+
39
+ const mesh = SGMesh.fromURL("data/models/RTS_Buildings_Humans/18/Building_R_18_out/Building_R_18.gltf");
40
+
41
+ new EntityBuilder()
42
+ .add(Transform.fromJSON({
43
+ position: new Vector3(10, 0, 10)
44
+ }))
45
+ // .add(SGMesh.fromURL("data/models/snaps/cube_blue.gltf"))
46
+ .add(mesh)
47
+ .add(BehaviorComponent.fromOne(OrbitingBehavior.from({
48
+ center: new Vector3(10, 0, 10),
49
+ radius: 5,
50
+ rate: 2
51
+ })))
52
+ .build(ecd);
53
+ }
@@ -0,0 +1,3 @@
1
+ export default class InputController {
2
+
3
+ }
@@ -1,5 +1,6 @@
1
1
  import {System} from "../../../ecs/System";
2
+ import {InputController} from "../components/InputController";
2
3
 
3
- export default class InputControllerSystem extends System {
4
+ export default class InputControllerSystem extends System<InputController> {
4
5
  constructor(devices: any)
5
- }
6
+ }
@@ -1,5 +1,6 @@
1
1
  import {System} from "../../../ecs/System";
2
+ import {Input} from "../components/Input";
2
3
 
3
- export class InputSystem extends System {
4
+ export class InputSystem extends System<Input> {
4
5
  constructor(devices: any)
5
6
  }
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.36.4",
8
+ "version": "2.36.7",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",