@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
@@ -118,61 +118,21 @@ export class SoundEmitterComponentContext {
118
118
  //connect to target
119
119
  nodes.volume.connect(targetNode);
120
120
 
121
- nodes.source.loop = soundTrack.getFlag(SoundTrackFlags.Loop);
122
121
  nodes.volume.gain.setValueAtTime(soundTrack.volume, 0);
123
122
 
124
123
  loadSoundTrackAsset(soundTrack, assetManager, function (asset) {
125
- /**
126
- *
127
- * @type {AudioBuffer}
128
- */
129
- const buffer = asset.create();
130
124
 
131
- // Make the sound source use the buffer and start playing it.
132
- if (nodes.source.buffer !== buffer) {
133
- nodes.source.buffer = buffer;
134
- }
125
+ soundTrack.buffer = asset.create();
135
126
 
136
127
  if (soundTrack.getFlag(SoundTrackFlags.StartWhenReady)) {
137
- //TODO: figure out a way to use AudioBuffer.playbackRate.value to control speed of playback
138
-
139
- if (soundTrack.time < 0) {
140
- // playback will start in the future
141
-
142
- /**
143
- * @type {AudioContext}
144
- */
145
- const audioContext = targetNode.context;
146
-
147
- let when = -soundTrack.time;
148
-
149
- if (audioContext !== undefined) {
150
- when += audioContext.currentTime;
151
- }
152
-
153
- nodes.source.start(when, 0);
154
- } else {
155
- // playback will start from within the track's duration (already playing)
156
128
 
157
- nodes.source.start(0, soundTrack.time);
158
- }
159
-
160
- soundTrack.setFlag(SoundTrackFlags.Playing);
129
+ soundTrack.start(context.currentTime);
161
130
  }
162
131
 
163
- }, console.error);
164
-
165
132
 
166
- nodes.source.onended = function () {
167
- if (!nodes.source.loop) {
168
- soundTrack.clearFlag(SoundTrackFlags.Playing);
169
-
170
- soundTrack.on.ended.dispatch();
133
+ }, console.error);
171
134
 
172
- //remove track
173
- emitter.tracks.removeOneOf(soundTrack);
174
- }
175
- };
135
+ soundTrack.on.ended.add(emitter.tracks.removeOneOf, emitter.tracks);
176
136
  }
177
137
 
178
138
  /**
@@ -187,6 +147,30 @@ export class SoundEmitterComponentContext {
187
147
  const volume = track.nodes.volume;
188
148
 
189
149
  volume.disconnect();
150
+
151
+ const emitter = this.emitter;
152
+
153
+ track.on.ended.remove(emitter.tracks.removeOneOf, emitter.tracks);
154
+ }
155
+
156
+ /**
157
+ * @param {SoundTrack} t
158
+ */
159
+ suspendTrack(t) {
160
+ if (t.getFlag(SoundTrackFlags.Playing)) {
161
+ t.suspend();
162
+ }
163
+ }
164
+
165
+ /**
166
+ *
167
+ * @param {SoundTrack} t
168
+ */
169
+ resumeTrack(t) {
170
+
171
+ if (t.getFlag(SoundTrackFlags.Playing)) {
172
+ t.start();
173
+ }
190
174
  }
191
175
 
192
176
  connect() {
@@ -194,10 +178,14 @@ export class SoundEmitterComponentContext {
194
178
  return;
195
179
  }
196
180
 
197
- const targetNode = this.emitter.getTargetNode();
181
+ const emitter = this.emitter;
182
+ const targetNode = emitter.getTargetNode();
198
183
 
199
184
  targetNode.connect(this.targetNode);
200
185
 
186
+ // update all track times
187
+ emitter.tracks.forEach(this.resumeTrack);
188
+
201
189
  this.__isConnected = true;
202
190
  }
203
191
 
@@ -206,12 +194,20 @@ export class SoundEmitterComponentContext {
206
194
  return;
207
195
  }
208
196
 
209
- const targetNode = this.emitter.getTargetNode();
197
+ const emitter = this.emitter;
198
+ const targetNode = emitter.getTargetNode();
210
199
 
211
200
  if (targetNode !== null) {
212
201
  targetNode.disconnect();
213
202
  }
214
203
 
204
+ /*
205
+ The reason we suspend all tracks is to be able to track progression of a track after it is disconnected
206
+ From experiments it appears that at least on Chrome v111 disconnected sources do not advance time, which leads to dis-synchronization when we later reconnected
207
+ To circumvent this issue we introduced "Suspended" flag to keep track of timing on disconnected tracks
208
+ */
209
+ emitter.tracks.forEach(this.suspendTrack, this)
210
+
215
211
  this.__isConnected = false;
216
212
  }
217
213
 
@@ -21,6 +21,7 @@ import { SoundEmitterFlags } from "./SoundEmitterFlags.js";
21
21
  import { SoundEmitterChannel } from "./SoundEmitterChannel.js";
22
22
  import { invokeObjectCompare } from "../../../../core/model/object/invokeObjectCompare.js";
23
23
  import { tryRotateSingleNode } from "../../../../core/bvh2/transform/tryRotateSingleNode.js";
24
+ import { SoundTrackFlags } from "./SoundTrackFlags.js";
24
25
 
25
26
  /**
26
27
  * @readonly
@@ -88,7 +89,6 @@ export class SoundEmitterSystem extends System {
88
89
 
89
90
  assetManager.registerLoader(GameAssetType.Sound, new SoundAssetLoader(context));
90
91
 
91
-
92
92
  /**
93
93
  *
94
94
  * @type {SoundEmitterComponentContext[]}
@@ -352,7 +352,7 @@ export class SoundEmitterSystem extends System {
352
352
  */
353
353
  const tracks = emitter.tracks;
354
354
 
355
- const trackCount = tracks.length;
355
+ let trackCount = tracks.length;
356
356
 
357
357
 
358
358
  //update play time
@@ -360,6 +360,19 @@ export class SoundEmitterSystem extends System {
360
360
  const soundTrack = tracks.get(i);
361
361
 
362
362
  soundTrack.time += timeDelta;
363
+
364
+ if (
365
+ soundTrack.setFlag(SoundTrackFlags.Suspended | SoundTrackFlags.Playing)
366
+ && !soundTrack.getFlag(SoundTrackFlags.Loop)
367
+ && soundTrack.time > soundTrack.duration
368
+ ) {
369
+ // track is suspended, but should have ended, trigger this state manually
370
+ emitter.endTrack(soundTrack);
371
+
372
+ // update cursors
373
+ trackCount--;
374
+ i--;
375
+ }
363
376
  }
364
377
 
365
378
  }
@@ -10,51 +10,149 @@ import { compareNumbers } from "../../../../core/primitives/numbers/compareNumbe
10
10
  const DEFAULT_FLAGS = SoundTrackFlags.StartWhenReady;
11
11
 
12
12
  export class SoundTrack {
13
+
13
14
  /**
14
15
  *
15
- * @constructor
16
+ * @type {AudioBuffer|null}
16
17
  */
17
- constructor() {
18
- /**
19
- *
20
- * @type {String|null}
21
- */
22
- this.url = null;
18
+ #buffer = null;
23
19
 
24
- /**
25
- *
26
- * @type {number}
27
- */
28
- this.time = 0;
20
+ /**
21
+ *
22
+ * @type {String|null}
23
+ */
24
+ url = null;
29
25
 
30
- /**
31
- * @deprecated Not used
32
- * @type {String|null}
33
- */
34
- this.channel = "";
26
+ /**
27
+ *
28
+ * @type {number}
29
+ */
30
+ time = 0;
35
31
 
36
- /**
37
- * @private
38
- * @type {number}
39
- */
40
- this.__volume = 1;
32
+ /**
33
+ * @deprecated Not used
34
+ * @type {String|null}
35
+ */
36
+ channel = "";
37
+
38
+ /**
39
+ * @private
40
+ * @type {number}
41
+ */
42
+ __volume = 1;
41
43
 
44
+ /**
45
+ * In seconds
46
+ * Obtained once clip is loaded
47
+ * @type {number}
48
+ */
49
+ duration = -1;
42
50
 
43
- /**
44
- *
45
- * @type {number|SoundTrackFlags}
46
- */
47
- this.flags = DEFAULT_FLAGS;
48
51
 
49
- this.on = {
50
- ended: new Signal()
51
- };
52
+ /**
53
+ *
54
+ * @type {number|SoundTrackFlags}
55
+ */
56
+ flags = DEFAULT_FLAGS;
52
57
 
58
+ on = {
53
59
  /**
54
- * @private
55
- * @type {SoundTrackNodes}
60
+ * @type {Signal<this>}
56
61
  */
57
- this.nodes = null;
62
+ ended: new Signal()
63
+ };
64
+
65
+ /**
66
+ * @private
67
+ * @type {SoundTrackNodes}
68
+ */
69
+ nodes = null;
70
+
71
+
72
+ /**
73
+ *
74
+ * @param {AudioBuffer} v
75
+ */
76
+ set buffer(v) {
77
+ this.#buffer = v;
78
+
79
+ this.duration = v.duration;
80
+
81
+ this.setFlag(SoundTrackFlags.Ready);
82
+ }
83
+
84
+ get buffer() {
85
+ return this.#buffer;
86
+ }
87
+
88
+ /**
89
+ *
90
+ * @returns {BaseAudioContext}
91
+ */
92
+ get #context() {
93
+ return this.nodes.volume.context;
94
+ }
95
+
96
+ start(startTime = 0) {
97
+ //TODO: figure out a way to use AudioBuffer.playbackRate.value to control speed of playback
98
+ const nodes = this.nodes;
99
+
100
+ if (nodes.source !== null) {
101
+
102
+ /*
103
+ source is already used up, need to create a new one
104
+ NOTE: AudioBufferSourceNode can only be used once, if we want to start playback again - we have to create a new one
105
+ see https://stackoverflow.com/questions/59815825/how-to-skip-ahead-n-seconds-while-playing-track-using-web-audio-api
106
+ */
107
+ this.suspend();
108
+
109
+ }
110
+
111
+ nodes.source = this.#context.createBufferSource();
112
+
113
+ //connect source to output
114
+ nodes.source.connect(nodes.volume);
115
+
116
+ const looping = this.getFlag(SoundTrackFlags.Loop);
117
+
118
+ nodes.source.loop = looping;
119
+
120
+ // Make the sound source use the buffer and start playing it.
121
+ nodes.source.buffer = this.#buffer;
122
+
123
+ nodes.source.onended = ()=> {
124
+ if(!looping){
125
+ this.clearFlag(SoundTrackFlags.Playing);
126
+ this.on.ended.send1(this);
127
+ }
128
+ }
129
+
130
+ let when = startTime;
131
+
132
+ if (this.time < 0) {
133
+ // playback will start in the future
134
+ when = -this.time;
135
+
136
+ nodes.source.start(when, 0);
137
+ } else {
138
+ // playback will start from within the track's duration (already playing)
139
+
140
+ nodes.source.start(when, this.time);
141
+ }
142
+
143
+ this.setFlag(SoundTrackFlags.Playing);
144
+ this.clearFlag(SoundTrackFlags.Suspended);
145
+ }
146
+
147
+ suspend() {
148
+ const nodes = this.nodes;
149
+
150
+ nodes.source.stop();
151
+ nodes.source.disconnect();
152
+
153
+ nodes.source = null;
154
+
155
+ this.setFlag(SoundTrackFlags.Suspended);
58
156
  }
59
157
 
60
158
  /**
@@ -310,7 +408,8 @@ export class SoundTrack {
310
408
  volume: this.volume,
311
409
  playing: this.getFlag(SoundTrackFlags.Playing),
312
410
  startWhenReady: this.getFlag(SoundTrackFlags.StartWhenReady),
313
- usingAssetAlias: this.getFlag(SoundTrackFlags.UsingAliasURL)
411
+ usingAssetAlias: this.getFlag(SoundTrackFlags.UsingAliasURL),
412
+ synchronized: this.getFlag(SoundTrackFlags.Synchronized)
314
413
  };
315
414
  }
316
415
 
@@ -322,7 +421,8 @@ export class SoundTrack {
322
421
  volume = 1,
323
422
  playing = false,
324
423
  startWhenReady = true,
325
- usingAssetAlias = false
424
+ usingAssetAlias = false,
425
+ synchronized = false
326
426
  }
327
427
  ) {
328
428
  assert.typeOf(url, 'string', 'url');
@@ -340,6 +440,8 @@ export class SoundTrack {
340
440
  this.writeFlag(SoundTrackFlags.Playing, playing);
341
441
 
342
442
  this.writeFlag(SoundTrackFlags.StartWhenReady, startWhenReady);
443
+
444
+ this.writeFlag(SoundTrackFlags.Synchronized, synchronized);
343
445
  }
344
446
 
345
447
  static fromJSON(json) {
@@ -9,5 +9,21 @@ export const SoundTrackFlags = {
9
9
  /**
10
10
  * URL field is not a path to actual resource, but instead an alias that needs to be resolved
11
11
  */
12
- UsingAliasURL: 8
12
+ UsingAliasURL: 8,
13
+
14
+ /**
15
+ * If set, this flag will result in track being scheduled instead of starting immediately, this will result in pore precise time synchronization
16
+ * as a trade-off, there will be a delay until next system update tick
17
+ */
18
+ Synchronized: 16,
19
+
20
+ /**
21
+ * Track is not actually playing, only time is being advanced
22
+ */
23
+ Suspended: 32,
24
+
25
+ /**
26
+ * Track is loaded and ready to play
27
+ */
28
+ Ready: 64
13
29
  };
@@ -8,13 +8,11 @@ export class SoundTrackNodes {
8
8
  *
9
9
  * @type {AudioBufferSourceNode}
10
10
  */
11
- this.source = context.createBufferSource();
11
+ this.source = null;
12
12
  /**
13
13
  *
14
14
  * @type {GainNode}
15
15
  */
16
16
  this.volume = context.createGain();
17
- //connect volume to source
18
- this.source.connect(this.volume);
19
17
  }
20
- }
18
+ }
@@ -4,10 +4,9 @@ import { noop } from "../../../../core/function/Functions.js";
4
4
  import { assert } from "../../../../core/assert.js";
5
5
 
6
6
  /**
7
- *
8
7
  * @param {SoundTrack} track
9
8
  * @param {AssetManager} assetManager
10
- * @param {function} [resolve]
9
+ * @param {function(Asset<AudioBuffer>)} [resolve]
11
10
  * @param {function} [reject]
12
11
  */
13
12
  export function loadSoundTrackAsset(track, assetManager, resolve = noop, reject = noop) {
@@ -366,7 +366,7 @@ export class ThemeEngine {
366
366
  * @param {number} seed
367
367
  * @returns {Task|TaskGroup}
368
368
  */
369
- applyNodes(grid, ecd, seed=0) {
369
+ applyNodes(grid, ecd, seed = 0) {
370
370
  /**
371
371
  *
372
372
  * @type {MarkerNode[]}
@@ -579,10 +579,27 @@ export class ThemeEngine {
579
579
  // build terrain tiles
580
580
  const tTerrainGeometry = futureTask(new Future((resolve, reject) => {
581
581
 
582
- terrain.updateWorkerHeights();
582
+ const is_linked = terrain.getFlag(TerrainFlags.Linked);
583
+
584
+ if (!is_linked) {
585
+ terrain.startBuildService();
586
+ }
587
+
588
+ if (!terrain.getFlag(TerrainFlags.Built)) {
589
+ terrain.buildNonVisual();
590
+ }
591
+
583
592
  terrain.__tiles.rebuild();
584
593
 
585
- terrain.promiseAllTiles().then(resolve, reject);
594
+ terrain.promiseAllTiles()
595
+ .then(resolve, reject)
596
+ .finally(() => {
597
+ if (!is_linked && !terrain.getFlag(TerrainFlags.Linked)) {
598
+ // cleanup after ourselves
599
+ terrain.stopBuildService();
600
+ }
601
+ });
602
+
586
603
  }), 'Wait for terrain tiles');
587
604
 
588
605
  const tInitializeThemes = this.initializeThemes(this.random(), ecd, grid);
@@ -1,8 +1,8 @@
1
- import { KeyValuePair } from "../../../core/collection/KeyValuePair.js";
2
- import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js";
3
- import { computeHashArray } from "../../../core/collection/array/computeHashArray.js";
4
- import { computeHashIntegerArray } from "../../../core/collection/array/computeHashIntegerArray.js";
5
- import { isArrayEqual } from "../../../core/collection/array/isArrayEqual.js";
1
+ import { KeyValuePair } from "../../core/collection/KeyValuePair.js";
2
+ import { computeStringHash } from "../../core/primitives/strings/computeStringHash.js";
3
+ import { computeHashArray } from "../../core/collection/array/computeHashArray.js";
4
+ import { computeHashIntegerArray } from "../../core/collection/array/computeHashIntegerArray.js";
5
+ import { isArrayEqual } from "../../core/collection/array/isArrayEqual.js";
6
6
 
7
7
  /**
8
8
  *
@@ -10,6 +10,7 @@ import domify from "../../DOM.js";
10
10
  class ButtonView extends View {
11
11
  /**
12
12
  *
13
+ * @param {string} [tag]
13
14
  * @param {function} action
14
15
  * @param {string|ObservedString} [name]
15
16
  * @param {string} [icon] URL
@@ -17,14 +18,21 @@ class ButtonView extends View {
17
18
  * @param {object} [css]
18
19
  * @constructor
19
20
  */
20
- constructor({ action, name, icon = undefined, classList = [], css }) {
21
+ constructor({
22
+ tag = 'div',
23
+ action,
24
+ name,
25
+ icon = undefined,
26
+ classList = [],
27
+ css
28
+ }) {
21
29
  super();
22
30
 
23
31
  if (typeof action !== "function") {
24
32
  throw new Error("Action must be a function");
25
33
  }
26
34
 
27
- const dRoot = domify();
35
+ const dRoot = domify(tag);
28
36
 
29
37
  this.el = dRoot.el;
30
38
  //add background and foreground elements for styling purposes
@@ -4,7 +4,7 @@
4
4
 
5
5
  import View from "../../View.js";
6
6
  import { noop } from "../../../core/function/Functions.js";
7
- import { HTMLElementCacheKey } from "./HTMLElementCacheKey.js";
7
+ import { HTMLElementCacheKey } from "../../common/HTMLElementCacheKey.js";
8
8
  import { KeyValuePair } from "../../../core/collection/KeyValuePair.js";
9
9
  import { ObjectPoolFactory } from "../../../core/model/object/ObjectPoolFactory.js";
10
10
  import { ImmutableObjectPool } from "../../../core/model/object/ImmutableObjectPool.js";
@@ -1,4 +1,4 @@
1
- import { HTMLElementCacheKey } from "../image/HTMLElementCacheKey.js";
1
+ import { HTMLElementCacheKey } from "../../common/HTMLElementCacheKey.js";
2
2
  import { KeyValuePair } from "../../../core/collection/KeyValuePair.js";
3
3
  import { Cache } from "../../../core/cache/Cache.js";
4
4
  import { noop } from "../../../core/function/Functions.js";