@woosh/meep-engine 2.48.1 → 2.48.5

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 (75) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/32BitEncoder.js +11 -3
  3. package/src/core/binary/BinaryBuffer.js +80 -59
  4. package/src/core/binary/int32_to_binary_string.js +32 -7
  5. package/src/core/binary/to_half_float_uint16.js +6 -4
  6. package/src/core/bvh2/visual/convert_bvh_to_dot_format_string.js +1 -1
  7. package/src/core/collection/list/List.js +3 -0
  8. package/src/core/geom/3d/CircleMath.js +13 -2
  9. package/src/core/geom/3d/matrix/m4_make_translation.js +15 -0
  10. package/src/core/geom/3d/triangle/computeTrianglePlaneSide.js +4 -13
  11. package/src/core/geom/Vector3.spec.js +10 -0
  12. package/src/core/graph/convertGraphToDotString.js +13 -3
  13. package/src/core/graph/v2/Graph.js +17 -1
  14. package/src/core/graph/v2/NodeContainer.js +58 -0
  15. package/src/core/model/ModuleRegistry.js +44 -10
  16. package/src/core/model/ResourceAccessKind.js +11 -0
  17. package/src/core/model/ResourceAccessSpecification.js +41 -0
  18. package/src/engine/Engine.js +1 -1
  19. package/src/engine/ecs/EntityEventBinding.js +74 -0
  20. package/src/engine/ecs/EntityManager.js +143 -0
  21. package/src/engine/ecs/System.js +53 -5
  22. package/src/engine/ecs/animation/InverseKinematicsSystem.js +6 -0
  23. package/src/engine/ecs/attachment/AttachmentSystem.js +8 -0
  24. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +5 -0
  25. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +7 -3
  26. package/src/engine/ecs/fow/FogOfWarSystem.js +6 -0
  27. package/src/engine/ecs/gui/GUIElementSystem.js +1 -1
  28. package/src/engine/ecs/gui/hud/HeadsUpDisplaySystem.js +8 -0
  29. package/src/engine/ecs/gui/position/ViewportPositionSystem.js +6 -0
  30. package/src/engine/ecs/speaker/VoiceSystem.js +13 -0
  31. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter2.js +451 -12
  32. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter2.spec.js +123 -0
  33. package/src/engine/ecs/system/computeSystemComponentDependencyGraph.js +71 -0
  34. package/src/engine/ecs/systems/RenderSystem.js +6 -0
  35. package/src/engine/ecs/terrain/ecs/Terrain.js +26 -44
  36. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +9 -0
  37. package/src/engine/ecs/terrain/tiles/TerrainTile.js +5 -0
  38. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +26 -6
  39. package/src/engine/ecs/tooltip/TooltipComponentSystem.js +7 -0
  40. package/src/engine/graphics/ecs/animation/animator/AnimationGraphSystem.js +6 -0
  41. package/src/engine/graphics/ecs/camera/CameraSystem.js +6 -0
  42. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +4 -0
  43. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +5 -0
  44. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraLanderSystem.js +6 -0
  45. package/src/engine/graphics/ecs/light/LightSystem.js +8 -0
  46. package/src/engine/graphics/ecs/mesh/MeshSystem.js +8 -1
  47. package/src/engine/graphics/ecs/path/PathDisplaySystem.js +7 -1
  48. package/src/engine/graphics/ecs/trail2d/Trail2DSystem.js +7 -0
  49. package/src/engine/graphics/geometry/instancing/InstancedMeshGroup.js +34 -7
  50. package/src/engine/graphics/particles/ecs/ParticleEmitterSystem.js +6 -0
  51. package/src/engine/grid/systems/GridPosition2TransformSystem.js +6 -0
  52. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +6 -0
  53. package/src/engine/intelligence/behavior/Behavior.js +11 -0
  54. package/src/engine/intelligence/behavior/composite/CompositeBehavior.js +10 -4
  55. package/src/engine/intelligence/behavior/decorator/AbstractDecoratorBehavior.js +1 -0
  56. package/src/engine/intelligence/behavior/util/behavior_traverse_tree.js +8 -0
  57. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +8 -0
  58. package/src/engine/network/RemoteController.js +60 -84
  59. package/src/engine/network/remoteEditor.js +108 -2
  60. package/src/engine/sound/SoundEngine.js +81 -79
  61. package/src/engine/sound/ecs/SoundControllerSystem.js +8 -0
  62. package/src/engine/sound/ecs/SoundListenerSystem.js +7 -0
  63. package/src/engine/sound/ecs/emitter/SoundEmitterComponentContext.js +42 -46
  64. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.js +15 -2
  65. package/src/engine/sound/ecs/emitter/SoundTrack.js +137 -35
  66. package/src/engine/sound/ecs/emitter/SoundTrackFlags.js +17 -1
  67. package/src/engine/sound/ecs/emitter/SoundTrackNodes.js +2 -4
  68. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.js +1 -2
  69. package/src/generation/theme/ThemeEngine.js +20 -3
  70. package/src/view/{elements/image → common}/HTMLElementCacheKey.js +5 -5
  71. package/src/view/elements/button/ButtonView.js +10 -2
  72. package/src/view/elements/image/ImageView.js +1 -1
  73. package/src/view/elements/video/VideoView.js +1 -1
  74. package/src/view/interaction/CommandButtonView.js +16 -153
  75. package/src/view/interaction/createInterfaceCommandButton.js +124 -0
@@ -1,3 +1,5 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+
1
3
  /**
2
4
  *
3
5
  * @param {Behavior|CompositeBehavior|AbstractDecoratorBehavior} root
@@ -6,6 +8,12 @@
6
8
  */
7
9
  export function behavior_traverse_tree(root, visitor, thisArg) {
8
10
 
11
+ assert.defined(root, 'root');
12
+ assert.notNull(root, 'root');
13
+ assert.equal(root.isBehavior, true, 'root.isBehavior !== true');
14
+
15
+ assert.isFunction(visitor, 'visitor');
16
+
9
17
  const should_continue = visitor.call(thisArg, root);
10
18
 
11
19
  if (should_continue === false) {
@@ -13,6 +13,8 @@ import { Transform } from '../../../ecs/transform/Transform.js';
13
13
  import Vector3 from "../../../../core/geom/Vector3.js";
14
14
  import { PathFollowerEventType } from "./PathFollowerEventType.js";
15
15
  import { PathFollowerFlags } from "./PathFollowerFlags.js";
16
+ import { ResourceAccessSpecification } from "../../../../core/model/ResourceAccessSpecification.js";
17
+ import { ResourceAccessKind } from "../../../../core/model/ResourceAccessKind.js";
16
18
 
17
19
  const v3_forward = new Vector3();
18
20
  const v3_temp1 = new Vector3();
@@ -127,6 +129,12 @@ class PathFollowingSystem extends System {
127
129
 
128
130
  this.dependencies = [PathFollower];
129
131
 
132
+ this.components_used = [
133
+ ResourceAccessSpecification.from(PathFollower, ResourceAccessKind.Read | ResourceAccessKind.Write),
134
+ ResourceAccessSpecification.from(Transform, ResourceAccessKind.Read | ResourceAccessKind.Write),
135
+ ResourceAccessSpecification.from(Path, ResourceAccessKind.Read),
136
+ ];
137
+
130
138
  /**
131
139
  *
132
140
  * @type {number}
@@ -1,138 +1,114 @@
1
1
  import { BinaryBuffer } from "../../core/binary/BinaryBuffer.js";
2
- import BinaryBufferDeSerializer from "../ecs/storage/BinaryBufferDeSerializer.js";
3
- import { BinaryObjectSerializationAdapter } from "../ecs/storage/binary/object/BinaryObjectSerializationAdapter.js";
2
+ import { assert } from "../../core/assert.js";
4
3
 
5
- class LocalAPI {
4
+ /*
5
+ packet header structure
6
+ - TAG : 1 x utf8 string
7
+ - ID : 1 x uint32
8
+ - PAYLOAD : N x bytes
9
+ */
10
+
11
+ export class RemoteController {
6
12
  /**
7
13
  *
8
- * @type {Engine|null}
14
+ * @type {WebSocket|null}
9
15
  */
10
- engine = null;
16
+ #socket = null;
11
17
 
12
- _object_serde = new BinaryObjectSerializationAdapter();
18
+ #handlers = {};
13
19
 
14
- get _registry() {
15
- return this.engine.binarySerializationRegistry;
16
- }
20
+ #bound_event_handler = this.#handle_message_event.bind(this)
17
21
 
18
22
  /**
19
23
  *
20
- * @return {EntityComponentDataset}
21
- * @private
24
+ * @param {string} tag
25
+ * @param {function(BinaryBuffer):Promise} handler
26
+ * @param {*} thisArg
22
27
  */
23
- get _current_dataset() {
24
- return this.engine.entityManager.dataset;
25
- }
26
-
27
- /**
28
- * Server sent us a new world state
29
- * @param {BinaryBuffer} buffer
30
- */
31
- async writeCurrentSceneDataset(buffer) {
32
- const deSerializer = new BinaryBufferDeSerializer();
33
-
34
- const engine = this.engine;
35
-
36
- deSerializer.registry = this._registry;
28
+ addHandler(tag, handler, thisArg) {
29
+ const existing = this.#handlers[tag];
37
30
 
38
- const ecd = this._current_dataset;
39
-
40
- ecd.clear();
41
-
42
- const task = deSerializer.process(buffer, engine, ecd);
43
-
44
- const p = task.promise();
45
-
46
- engine.executor.run(task);
31
+ if (existing !== undefined) {
32
+ throw new Error(`Handler for tag '${tag}' already exists`);
33
+ }
47
34
 
48
- await p;
35
+ this.#handlers[tag] = {
36
+ method: handler,
37
+ scope: thisArg
38
+ };
49
39
  }
50
40
 
51
41
  /**
52
- *
53
- * @param {BinaryBuffer} buffer
54
- * @return {Promise<void>}
42
+ * NOTE: entire buffer contents will be sent up to current position
43
+ * @param {string} tag
44
+ * @param {BinaryBuffer} data
55
45
  */
56
- async createEntity(buffer) {
57
- // create entity on the current scene with a given ID
58
-
59
- const entity_id = buffer.readUintVar();
46
+ send(tag, data) {
47
+ assert.isString(tag, 'tag');
60
48
 
61
- this._current_dataset.createEntitySpecific(entity_id);
62
- }
49
+ const buffer = new BinaryBuffer();
63
50
 
64
- async addComponentToEntity(buffer) {
65
- const entity_id = buffer.readUintVar();
51
+ buffer.writeUTF8String(tag);
66
52
 
67
- this._object_serde.registry = this._registry;
68
- const component_instance = this._object_serde.deserialize(buffer);
53
+ buffer.writeBytes(data.raw_bytes, 0, data.position);
69
54
 
70
- this._current_dataset.addComponentToEntity(entity_id, component_instance);
55
+ buffer.trim();
71
56
 
57
+ this.#socket.send(buffer.data);
72
58
  }
73
59
 
74
- }
75
-
76
- export class RemoteController {
77
60
  /**
78
61
  *
79
- * @type {WebSocket|null}
80
- */
81
- socket = null;
82
-
83
- localAPI = new LocalAPI();
84
-
85
- /**
86
- *
87
- * @param {Engine} engine
62
+ * @param {MessageEvent} event
63
+ * @private
88
64
  */
89
- attach(engine) {
90
- this.localAPI.engine = engine;
65
+ async #handle_message_event(event) {
91
66
 
92
- }
67
+ /**
68
+ * @type {ArrayBuffer}
69
+ */
70
+ const data = event.data;
93
71
 
94
- /**
95
- *
96
- * @param {ArrayBuffer} data
97
- * @private
98
- */
99
- async __handle_message(data) {
100
72
  // console.log(`received message `, data);
101
73
 
102
- const buffer = BinaryBuffer.fromArrayBuffer(data);
74
+ const buffer = BinaryBuffer.fromArrayBuffer(data);
103
75
 
104
76
  // read packet ID
105
77
  const packet_id = buffer.readUTF8String();
106
78
 
107
- console.log(`packet ID: ${packet_id}`);
79
+ const handler = this.#handlers[packet_id];
108
80
 
109
- if (this.localAPI[packet_id] === undefined) {
110
- console.error(`Local API does not have method '${packet_id}'`);
81
+ if (handler === undefined) {
82
+ console.error(`No handler for packet '${packet_id}'`);
111
83
  return;
112
84
  }
113
85
 
114
86
  try {
115
- await this.localAPI[packet_id](buffer);
87
+ await handler.method.call(handler.scope, buffer);
116
88
  } catch (e) {
117
89
  //
118
90
  console.error(`Failed to process remote call to '${packet_id}':`, e);
119
91
  }
120
92
  }
121
93
 
94
+ /**
95
+ *
96
+ * @param {WebSocket} v
97
+ */
98
+ set socket(v) {
99
+ if (this.#socket !== null) {
100
+ // TODO unbind socket
101
+ }
122
102
 
123
- startup() {
124
- this.socket = new WebSocket('ws://localhost:9020');
103
+ this.#socket = v;
125
104
 
126
- this.socket.binaryType = "arraybuffer";
105
+ this.#socket.binaryType = "arraybuffer";
127
106
 
128
- this.socket.addEventListener('open', () => {
107
+ this.#socket.addEventListener('open', () => {
129
108
  console.log('socket connection open');
130
109
  });
131
110
 
132
- this.socket.addEventListener('message', (event) => {
133
-
134
-
135
- this.__handle_message(event.data);
136
- });
111
+ this.#socket.addEventListener('message', this.#bound_event_handler);
137
112
  }
113
+
138
114
  }
@@ -2,9 +2,96 @@ import { EngineHarness } from "../EngineHarness.js";
2
2
  import { RemoteController } from "./RemoteController.js";
3
3
  import { ShadedGeometrySystem } from "../graphics/ecs/mesh-v2/ShadedGeometrySystem.js";
4
4
  import { initializeGameBinarySerializationRegistry } from "../../../../model/game/GameBinarySerializationRegistry.js";
5
+ import { BinaryObjectSerializationAdapter } from "../ecs/storage/binary/object/BinaryObjectSerializationAdapter.js";
6
+ import BinaryBufferDeSerializer from "../ecs/storage/BinaryBufferDeSerializer.js";
5
7
 
6
8
  const harness = new EngineHarness();
7
9
 
10
+ class LocalAPI {
11
+ /**
12
+ *
13
+ * @type {Engine|null}
14
+ */
15
+ engine = null;
16
+
17
+ _object_serde = new BinaryObjectSerializationAdapter();
18
+
19
+ get _registry() {
20
+ return this.engine.binarySerializationRegistry;
21
+ }
22
+
23
+ /**
24
+ *
25
+ * @return {EntityComponentDataset}
26
+ * @private
27
+ */
28
+ get _current_dataset() {
29
+ return this.engine.entityManager.dataset;
30
+ }
31
+
32
+ /**
33
+ * Server sent us a new world state
34
+ * @param {BinaryBuffer} buffer
35
+ */
36
+ async writeCurrentSceneDataset(buffer) {
37
+ const deSerializer = new BinaryBufferDeSerializer();
38
+
39
+ const engine = this.engine;
40
+
41
+ deSerializer.registry = this._registry;
42
+
43
+ const ecd = this._current_dataset;
44
+
45
+ ecd.clear();
46
+
47
+ const task = deSerializer.process(buffer, engine, ecd);
48
+
49
+ const p = task.promise();
50
+
51
+ engine.executor.run(task);
52
+
53
+ await p;
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @param {BinaryBuffer} buffer
59
+ * @return {Promise<void>}
60
+ */
61
+ async createEntity(buffer) {
62
+ // create entity on the current scene with a given ID
63
+
64
+ const entity_id = buffer.readUintVar();
65
+
66
+ this._current_dataset.createEntitySpecific(entity_id);
67
+ }
68
+
69
+ async addComponentToEntity(buffer) {
70
+ const entity_id = buffer.readUintVar();
71
+
72
+ this._object_serde.registry = this._registry;
73
+ const component_instance = this._object_serde.deserialize(buffer);
74
+
75
+ this._current_dataset.addComponentToEntity(entity_id, component_instance);
76
+
77
+ }
78
+
79
+ }
80
+
81
+ /**
82
+ *
83
+ * @param {RemoteController} controller
84
+ * @param {Object} api
85
+ */
86
+ function attachLocalAPI(controller, api) {
87
+ for (const apiKey in api) {
88
+
89
+ controller.addHandler(apiKey, api[apiKey], api);
90
+
91
+ }
92
+
93
+ }
94
+
8
95
  /**
9
96
  *
10
97
  * @param {Engine} engine
@@ -20,9 +107,28 @@ async function main(engine) {
20
107
 
21
108
  const remote = new RemoteController();
22
109
 
23
- remote.attach(engine);
24
- remote.startup();
25
110
 
111
+ const api = new LocalAPI();
112
+ api.engine = engine;
113
+
114
+ Object.getOwnPropertyNames(Object.getPrototypeOf(api))
115
+ .forEach(name => {
116
+ if (name.startsWith("_")) {
117
+ return;
118
+ }
119
+
120
+ if (name === "constructor") {
121
+ return;
122
+ }
123
+
124
+ if (typeof api[name] !== "function") {
125
+ return;
126
+ }
127
+
128
+ remote.addHandler(name, api[name], api);
129
+ });
130
+
131
+ remote.socket = new WebSocket('ws://localhost:9020');
26
132
  }
27
133
 
28
134
  harness.initialize({
@@ -4,93 +4,95 @@
4
4
  */
5
5
 
6
6
 
7
- /**
8
- *
9
- * @constructor
10
- */
11
- function SoundEngine() {
7
+ class SoundEngine {
8
+ /**
9
+ *
10
+ * @constructor
11
+ */
12
+ constructor() {
13
+
14
+ // Fix up prefixing
15
+ let AudioContext = (
16
+ window.AudioContext ||
17
+ null
18
+ );
19
+
20
+ if (!AudioContext) {
21
+ throw new Error("AudioContext not supported!");
22
+ }
12
23
 
13
- // Fix up prefixing
14
- let AudioContext = (
15
- window.AudioContext ||
16
- window.webkitAudioContext ||
17
- null
18
- );
24
+ // Create a new audio context.
25
+ const context = this.context = new AudioContext({
26
+ /*
27
+ * The type of playback that the context will be used for, as a value from the AudioContextLatencyCategory enum or a double-precision floating-point value indicating the preferred maximum latency of the context in seconds. The user agent may or may not choose to meet this request; check the value of AudioContext.baseLatency to determine the true latency after creating the context.
28
+ *
29
+ * Values:
30
+ *
31
+ * "balanced" The user agent should balance audio output latency and power consumption when selecting a latency value.
32
+ * "interactive" The audio is involved in interactive elements, such as responding to user actions or needing to coincide with visual cues such as a video or game action. The user agent should select the lowest possible latency that doesn't cause glitches in the audio. This is likely to require increased power consumption. This is the default value.
33
+ * "playback" The user agent should select a latency that will maximize playback time by minimizing power consumption at the expense of latency. Useful for non-interactive playback, such as playing music.
34
+ */
35
+ latencyHint: 'interactive'
36
+ });
37
+
38
+ //start suspended to keep chrome satisfied, otherwise it prints a warning
39
+ context.suspend();
40
+
41
+ // master volume
42
+ const gainNode = context.createGain();
43
+
44
+ // Dynamic compressor makes quiet sounds louder and loud quieter
45
+ const compressor = context.createDynamicsCompressor();
46
+ this.destination = gainNode;
47
+ gainNode.connect(compressor);
48
+ compressor.connect(context.destination);
49
+
50
+ // master channel
51
+ Object.defineProperties(this, {
52
+ volume: {
53
+ get: function () {
54
+ return gainNode.gain.value;
55
+ },
56
+ set: function (val) {
57
+ gainNode.gain.setValueAtTime(val, context.currentTime, 0);
58
+ }
59
+ }
60
+ });
61
+ }
19
62
 
20
- if (!AudioContext) {
21
- throw new Error("AudioContext not supported!");
63
+ /**
64
+ *
65
+ * @return {number}
66
+ */
67
+ getCurrentTime() {
68
+ return this.context.currentTime;
22
69
  }
23
70
 
24
- // Create a new audio context.
25
- const context = this.context = new AudioContext({
26
- /*
27
- * The type of playback that the context will be used for, as a value from the AudioContextLatencyCategory enum or a double-precision floating-point value indicating the preferred maximum latency of the context in seconds. The user agent may or may not choose to meet this request; check the value of AudioContext.baseLatency to determine the true latency after creating the context.
28
- *
29
- * Values:
30
- *
31
- * "balanced" The user agent should balance audio output latency and power consumption when selecting a latency value.
32
- * "interactive" The audio is involved in interactive elements, such as responding to user actions or needing to coincide with visual cues such as a video or game action. The user agent should select the lowest possible latency that doesn't cause glitches in the audio. This is likely to require increased power consumption. This is the default value.
33
- * "playback" The user agent should select a latency that will maximize playback time by minimizing power consumption at the expense of latency. Useful for non-interactive playback, such as playing music.
34
- */
35
- latencyHint: 'interactive'
36
- });
37
-
38
- //start suspended to keep chrome satisfied, otherwise it prints a warning
39
- context.suspend();
40
-
41
- // master volume
42
- const gainNode = context.createGain();
43
-
44
- // Dynamic compressor makes quiet sounds louder and loud quieter
45
- const compressor = context.createDynamicsCompressor();
46
- this.destination = gainNode;
47
- gainNode.connect(compressor);
48
- compressor.connect(context.destination);
49
-
50
- // master channel
51
- Object.defineProperties(this, {
52
- volume: {
53
- get: function () {
54
- return gainNode.gain.value;
55
- },
56
- set: function (val) {
57
- gainNode.gain.setValueAtTime(val, context.currentTime, 0);
58
- }
59
- }
60
- });
61
- }
71
+ /**
72
+ * Audio context needs to be resumed as it is created in suspended state by default
73
+ * @see https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
74
+ * @returns {Promise<void>}
75
+ */
76
+ resumeContext() {
77
+ const pResumed = this.context.resume();
62
78
 
63
- /**
64
- *
65
- * @return {number}
66
- */
67
- SoundEngine.prototype.getCurrentTime = function () {
68
- return this.context.currentTime;
69
- }
79
+ return pResumed;
80
+ }
70
81
 
71
- /**
72
- * Audio context needs to be resumed as it is created in suspended state by default
73
- * @see https://developers.google.com/web/updates/2017/09/autoplay-policy-changes#webaudio
74
- * @returns {Promise<void>}
75
- */
76
- SoundEngine.prototype.resumeContext = function () {
77
- const pResumed = this.context.resume();
82
+ /**
83
+ *
84
+ * @returns {Promise<any>}
85
+ */
86
+ start() {
78
87
 
79
- return pResumed;
80
- };
88
+ return new Promise((resolve, reject) => {
89
+ //don't want for context to be resumed
90
+ const promise = this.resumeContext();
81
91
 
82
- /**
83
- *
84
- * @returns {Promise<any>}
85
- */
86
- SoundEngine.prototype.start = function () {
87
-
88
- return new Promise((resolve, reject) => {
89
- //don't want for context to be resumed
90
- this.resumeContext();
91
92
 
92
- resolve();
93
- });
94
- };
93
+ resolve();
94
+ });
95
+ }
96
+ }
95
97
 
96
98
  export default SoundEngine;
@@ -7,6 +7,8 @@ import { System } from '../../ecs/System.js';
7
7
  import { SoundEmitter } from './emitter/SoundEmitter.js';
8
8
  import SoundController from './SoundController.js';
9
9
  import { SoundTrack } from "./emitter/SoundTrack.js";
10
+ import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
11
+ import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
10
12
 
11
13
  /**
12
14
  *
@@ -30,6 +32,12 @@ class SoundControllerSystem extends System {
30
32
  constructor() {
31
33
  super();
32
34
  this.dependencies = [SoundController];
35
+
36
+
37
+ this.components_used = [
38
+ ResourceAccessSpecification.from(SoundEmitter, ResourceAccessKind.Write)
39
+ ];
40
+
33
41
  this.removers = [];
34
42
  }
35
43
 
@@ -10,6 +10,8 @@ import { browserInfo } from "../../Platform.js";
10
10
  import Vector3 from "../../../core/geom/Vector3.js";
11
11
  import { noop } from "../../../core/function/Functions.js";
12
12
  import { assert } from "../../../core/assert.js";
13
+ import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
14
+ import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
13
15
 
14
16
  const v3 = new Vector3();
15
17
  const v3_up = new Vector3();
@@ -92,6 +94,11 @@ class SoundListenerSystem extends System {
92
94
  assert.isInstanceOf(context, AudioContext, 'context', 'AudioContext');
93
95
 
94
96
  this.dependencies = [SoundListener, Transform];
97
+
98
+ this.components_used = [
99
+ ResourceAccessSpecification.from(SoundListener, ResourceAccessKind.Read|ResourceAccessKind.Write)
100
+ ];
101
+
95
102
  //
96
103
  this.webAudioContext = context;
97
104