@woosh/meep-engine 2.48.12 → 2.48.14

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 (68) hide show
  1. package/package.json +1 -1
  2. package/src/core/collection/queue/Deque.d.ts +9 -0
  3. package/src/core/collection/queue/Deque.js +3 -0
  4. package/src/core/collection/queue/Deque.spec.js +51 -0
  5. package/src/core/font/FontAssetLoader.js +2 -2
  6. package/src/core/math/bessel_3.js +3 -1
  7. package/src/core/math/noise/create_noise_2d.js +193 -0
  8. package/src/core/path/computeFileExtension.js +3 -2
  9. package/src/engine/Engine.js +14 -8
  10. package/src/engine/achievements/AchievementManager.js +16 -16
  11. package/src/engine/asset/AssetManager.d.ts +10 -5
  12. package/src/engine/asset/AssetManager.js +79 -24
  13. package/src/engine/asset/AssetManager.spec.js +1 -1
  14. package/src/engine/asset/AssetRequest.js +19 -1
  15. package/src/engine/asset/AssetRequestScope.d.ts +3 -0
  16. package/src/engine/asset/AssetRequestScope.js +64 -0
  17. package/src/engine/asset/PendingAsset.js +7 -7
  18. package/src/engine/asset/loaders/ArrayBufferLoader.js +1 -1
  19. package/src/engine/asset/loaders/AssetLoader.d.ts +9 -2
  20. package/src/engine/asset/loaders/AssetLoader.js +19 -16
  21. package/src/engine/asset/loaders/GLTFAssetLoader.d.ts +1 -1
  22. package/src/engine/asset/loaders/GLTFAssetLoader.js +2 -2
  23. package/src/engine/asset/loaders/JavascriptAssetLoader.js +17 -12
  24. package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
  25. package/src/engine/asset/loaders/LegacyThreeJSONAssetLoader.js +4 -1
  26. package/src/engine/asset/loaders/SVGAssetLoader.js +1 -1
  27. package/src/engine/asset/loaders/SoundAssetLoader.js +4 -6
  28. package/src/engine/asset/loaders/TextAssetLoader.js +1 -1
  29. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +24 -17
  30. package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts +1 -1
  31. package/src/engine/asset/loaders/texture/TextureAssetLoader.js +1 -1
  32. package/src/engine/asset/preloader/Preloader.js +1 -1
  33. package/src/engine/development/performance/MetricStatistics.js +7 -5
  34. package/src/engine/development/performance/RingBufferMetric.js +2 -2
  35. package/src/engine/ecs/foliage/ecs/Foliage2System.js +7 -5
  36. package/src/engine/ecs/foliage/ecs/InstancedMeshUtils.js +14 -1
  37. package/src/engine/ecs/gui/GUIElementSystem.d.ts +1 -1
  38. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +2 -2
  39. package/src/engine/ecs/terrain/ecs/PromiseSamplerHeight.js +16 -9
  40. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +3 -21
  41. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +16 -11
  42. package/src/engine/ecs/terrain/serialization/TerrainSerializationAdapter.js +1 -1
  43. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +18 -15
  44. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +4 -2
  45. package/src/engine/graphics/ecs/mesh/MeshSystem.js +1 -1
  46. package/src/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +6 -4
  47. package/src/engine/graphics/material/getTextureImmediate.js +5 -3
  48. package/src/engine/graphics/texture/3d/SingleChannelSampler3D.js +146 -0
  49. package/src/engine/graphics/texture/3d/scs3d_read_2d_slice.js +26 -0
  50. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +1 -1
  51. package/src/engine/graphics/texture/sampler/Sampler2D.js +22 -13
  52. package/src/engine/graphics/texture/sampler/filter/box.js +3 -3
  53. package/src/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +2 -1
  54. package/src/engine/graphics/texture/sampler/genericResampleSampler2D.js +9 -8
  55. package/src/engine/graphics/texture/sampler/loadSampler2D.js +18 -16
  56. package/src/engine/graphics/texture/sampler/sampler2d_scale_down_linear.js +8 -11
  57. package/src/engine/graphics/texture/virtual/tile/TileLoader.js +1 -1
  58. package/src/engine/graphics/trail/x/RibbonXPlugin.js +5 -3
  59. package/src/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
  60. package/src/engine/physics/fluid/FluidField.js +153 -1
  61. package/src/engine/physics/fluid/prototype.js +201 -0
  62. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +67 -0
  63. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.js +1 -1
  64. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +17 -12
  65. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +14 -10
  66. package/src/view/elements/MeshPreview.js +66 -64
  67. package/src/view/elements/image/SvgImageView.js +8 -6
  68. package/src/view/renderModel.js +1 -1
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.48.12",
8
+ "version": "2.48.14",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -7,6 +7,8 @@ export class Deque<T> {
7
7
 
8
8
  size(): number
9
9
 
10
+ isEmpty(): boolean
11
+
10
12
  remove(e: T): boolean
11
13
 
12
14
  has(e: T): boolean
@@ -17,4 +19,11 @@ export class Deque<T> {
17
19
 
18
20
  add(e: T): void
19
21
 
22
+ addFirst(e: T): void
23
+
24
+ removeFirst(): T
25
+
26
+ addLast(e: T): void
27
+
28
+ removeLast(): T
20
29
  }
@@ -1,6 +1,7 @@
1
1
  import { ceilPowerOfTwo } from "../../binary/operations/ceilPowerOfTwo.js";
2
2
  import { max2 } from "../../math/max2.js";
3
3
  import { array_copy } from "../array/copyArray.js";
4
+ import { assert } from "../../assert.js";
4
5
 
5
6
  const DEFAULT_SIZE = 16;
6
7
 
@@ -18,6 +19,8 @@ export class Deque {
18
19
  */
19
20
  constructor(minSize = DEFAULT_SIZE) {
20
21
 
22
+ assert.isNonNegativeInteger(minSize, 'minSize');
23
+
21
24
  const size = ceilPowerOfTwo(max2(DEFAULT_SIZE, minSize));
22
25
 
23
26
  /**
@@ -87,3 +87,54 @@ test('size', () => {
87
87
 
88
88
  expect(deque.size()).toBe(0);
89
89
  });
90
+
91
+ test("remove the only item", () => {
92
+ const deque = new Deque();
93
+
94
+ deque.add(7);
95
+
96
+ expect(deque.remove(7)).toBe(true);
97
+
98
+ expect(deque.size()).toBe(0);
99
+ });
100
+
101
+ test("remove first item", () => {
102
+
103
+ const deque = new Deque();
104
+
105
+ deque.add(7);
106
+ deque.add(13);
107
+
108
+ expect(deque.remove(7)).toBe(true);
109
+ expect(deque.size()).toBe(1);
110
+
111
+ expect(deque.pop()).toBe(13);
112
+ });
113
+
114
+ test("remove last item", () => {
115
+
116
+ const deque = new Deque();
117
+
118
+ deque.add(7);
119
+ deque.add(13);
120
+
121
+ expect(deque.remove(13)).toBe(true);
122
+ expect(deque.size()).toBe(1);
123
+
124
+ expect(deque.pop()).toBe(7);
125
+ });
126
+
127
+ test("remove middle item", () => {
128
+
129
+ const deque = new Deque();
130
+
131
+ deque.add(7);
132
+ deque.add(13);
133
+ deque.add(17);
134
+
135
+ expect(deque.remove(13)).toBe(true);
136
+ expect(deque.size()).toBe(2);
137
+
138
+ expect(deque.pop()).toBe(7);
139
+ expect(deque.pop()).toBe(17);
140
+ });
@@ -4,7 +4,7 @@ import { FontAsset } from "./FontAsset.js";
4
4
 
5
5
 
6
6
  export class FontAssetLoader extends AssetLoader {
7
- load(path, success, failure, progress) {
7
+ load(scope,path, success, failure, progress) {
8
8
  load(path, function (err, font) {
9
9
  if (err) {
10
10
  failure(err);
@@ -15,6 +15,6 @@ export class FontAssetLoader extends AssetLoader {
15
15
  success(asset);
16
16
 
17
17
  }
18
- });
18
+ },{});
19
19
  }
20
20
  }
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Kaiser Bessel Function of third kind
3
+ * NOTE: this is an approximation, if input value is sufficiently large - results will be way off
3
4
  * @see https://www.shadertoy.com/view/wlf3RH
4
5
  * @returns {number}
5
6
  * @param {number} x
@@ -7,5 +8,6 @@
7
8
  export function bessel_3(x) {
8
9
  const y = 0.5 * x;
9
10
  const y2 = (y * y);
10
- return (y2 * y * (1.0 / 6.0 + y2 * (1.0 / 24.0 + y2 * (1.0 / 240.0 + y2 * (1.0 / 4320.0 + y2 / 120960.0)))));
11
+ // return (y2 * y * (1.0 / 6.0 + y2 * (1.0 / 24.0 + y2 * (1.0 / 240.0 + y2 * (1.0 / 4320.0 + y2 / 120960.0)))));
12
+ return (y2 * y * (0.16666666666666666 + y2 * (0.041666666666666664 + y2 * (0.004166666666666667 + y2 * (2.314814814814815E-4 + y2 * 8.267195767195768E-6)))));
11
13
  }
@@ -0,0 +1,193 @@
1
+ /*
2
+ NOTE: this implementation is adapted from https://github.com/jwagner/simplex-noise.js
3
+ */
4
+
5
+ // these #__PURE__ comments help uglifyjs with dead code removal
6
+ //
7
+ const F2 = /*#__PURE__*/ 0.5 * (Math.sqrt(3.0) - 1.0);
8
+ const G2 = /*#__PURE__*/ (3.0 - Math.sqrt(3.0)) / 6.0;
9
+ const F3 = 1.0 / 3.0;
10
+ const G3 = 1.0 / 6.0;
11
+ const F4 = /*#__PURE__*/ (Math.sqrt(5.0) - 1.0) / 4.0;
12
+ const G4 = /*#__PURE__*/ (5.0 - Math.sqrt(5.0)) / 20.0;
13
+ const grad2 = /*#__PURE__*/ new Int8Array([1, 1,
14
+ -1, 1,
15
+ 1, -1,
16
+
17
+ -1, -1,
18
+ 1, 0,
19
+ -1, 0,
20
+
21
+ 1, 0,
22
+ -1, 0,
23
+ 0, 1,
24
+
25
+ 0, -1,
26
+ 0, 1,
27
+ 0, -1]);
28
+
29
+ // double seems to be faster than single or int's
30
+ // probably because most operations are in double precision
31
+ const grad3 = /*#__PURE__*/ new Float64Array([1, 1, 0,
32
+ -1, 1, 0,
33
+ 1, -1, 0,
34
+
35
+ -1, -1, 0,
36
+ 1, 0, 1,
37
+ -1, 0, 1,
38
+
39
+ 1, 0, -1,
40
+ -1, 0, -1,
41
+ 0, 1, 1,
42
+
43
+ 0, -1, 1,
44
+ 0, 1, -1,
45
+ 0, -1, -1]);
46
+
47
+ // double is a bit quicker here as well
48
+ const grad4 = /*#__PURE__*/ new Float64Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1,
49
+ 0, -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1,
50
+ 1, 0, 1, 1, 1, 0, 1, -1, 1, 0, -1, 1, 1, 0, -1, -1,
51
+ -1, 0, 1, 1, -1, 0, 1, -1, -1, 0, -1, 1, -1, 0, -1, -1,
52
+ 1, 1, 0, 1, 1, 1, 0, -1, 1, -1, 0, 1, 1, -1, 0, -1,
53
+ -1, 1, 0, 1, -1, 1, 0, -1, -1, -1, 0, 1, -1, -1, 0, -1,
54
+ 1, 1, 1, 0, 1, 1, -1, 0, 1, -1, 1, 0, 1, -1, -1, 0,
55
+ -1, 1, 1, 0, -1, 1, -1, 0, -1, -1, 1, 0, -1, -1, -1, 0]);
56
+
57
+
58
+ /**
59
+ * Creates a 2D noise function
60
+ * @param random the random function that will be used to build the permutation table
61
+ * @returns {function(x:number, y:number):number}
62
+ */
63
+ export function createNoise2D(random = Math.random) {
64
+ // allocate continuous chunk of memory
65
+ const buffer = new ArrayBuffer(512 * 2);
66
+
67
+ const perm = new Uint8Array(buffer, 0, 512);
68
+ buildPermutationTable(random, perm);
69
+
70
+ const permMod12 = new Uint8Array(buffer, 512, 512);
71
+
72
+ for (let i = 0; i < 512; i++) {
73
+ permMod12[i] = (perm[i] % 12) * 2;
74
+ }
75
+
76
+ return function noise2D(x, y) {
77
+ // if(!isFinite(x) || !isFinite(y)) return 0;
78
+ let n0 = 0; // Noise contributions from the three corners
79
+ let n1 = 0;
80
+ let n2 = 0;
81
+ // Skew the input space to determine which simplex cell we're in
82
+ const s = (x + y) * F2; // Hairy factor for 2D
83
+
84
+ const i = (x + s) | 0;
85
+ const j = (y + s) | 0;
86
+
87
+ const t = (i + j) * G2;
88
+ const X0 = i - t; // Unskew the cell origin back to (x,y) space
89
+ const Y0 = j - t;
90
+ const x0 = x - X0; // The x,y distances from the cell origin
91
+ const y0 = y - Y0;
92
+ // For the 2D case, the simplex shape is an equilateral triangle.
93
+ // Determine which simplex we are in.
94
+ let i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
95
+ if (x0 > y0) {
96
+ i1 = 1;
97
+ j1 = 0;
98
+ } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
99
+ else {
100
+ i1 = 0;
101
+ j1 = 1;
102
+ } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
103
+ // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
104
+ // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
105
+ // c = (3-sqrt(3))/6
106
+ const x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
107
+ const y1 = y0 - j1 + G2;
108
+ const x2 = x0 - 1.0 + 2.0 * G2; // Offsets for last corner in (x,y) unskewed coords
109
+ const y2 = y0 - 1.0 + 2.0 * G2;
110
+ // Work out the hashed gradient indices of the three simplex corners
111
+ const ii = i & 255;
112
+ const jj = j & 255;
113
+ // Calculate the contribution from the three corners
114
+ let t0 = 0.5 - x0 * x0 - y0 * y0;
115
+
116
+ if (t0 >= 0) {
117
+ const gi0 = ii + perm[jj];
118
+ const gi01 = permMod12[gi0];
119
+
120
+ const g0x = grad2[gi01];
121
+ const g0y = grad2[gi01 + 1];
122
+
123
+ t0 *= t0;
124
+ // n0 = t0 * t0 * (grad2[gi0] * x0 + grad2[gi0 + 1] * y0); // (x,y) of grad3 used for 2D gradient
125
+ n0 = t0 * t0 * (g0x * x0 + g0y * y0);
126
+ }
127
+
128
+ let t1 = 0.5 - x1 * x1 - y1 * y1;
129
+
130
+ if (t1 >= 0) {
131
+ const gi1 = ii + i1 + perm[jj + j1];
132
+ const gi11 = permMod12[gi1];
133
+
134
+ const g1x = grad2[gi11];
135
+ const g1y = grad2[gi11 + 1];
136
+
137
+ t1 *= t1;
138
+ // n1 = t1 * t1 * (grad2[gi1] * x1 + grad2[gi1 + 1] * y1);
139
+ n1 = t1 * t1 * (g1x * x1 + g1y * y1);
140
+ }
141
+
142
+ let t2 = 0.5 - x2 * x2 - y2 * y2;
143
+
144
+ if (t2 >= 0) {
145
+ const gi2 = ii + 1 + perm[jj + 1];
146
+
147
+ const gi21 = permMod12[gi2];
148
+
149
+ const g2x = grad2[gi21];
150
+ const g2y = grad2[gi21 + 1];
151
+
152
+ t2 *= t2;
153
+ // n2 = t2 * t2 * (grad2[gi2] * x2 + grad2[gi2 + 1] * y2);
154
+ n2 = t2 * t2 * (g2x * x2 + g2y * y2);
155
+ }
156
+
157
+ // Add contributions from each corner to get the final noise value.
158
+ // The result is scaled to return values in the interval [-1,1].
159
+ return 70.0 * (n0 + n1 + n2);
160
+ };
161
+ }
162
+
163
+ /**
164
+ * Builds a random permutation table.
165
+ * This is exported only for (internal) testing purposes.
166
+ * Do not rely on this export.
167
+ * @param {function} random
168
+ * @param {Uint8Array} p
169
+ * @private
170
+ */
171
+ export function buildPermutationTable(random, p) {
172
+ const table_size = 512;
173
+
174
+ const half_table_size = table_size >>> 1;
175
+
176
+ for (let i = 0; i < half_table_size; i++) {
177
+ p[i] = i;
178
+ }
179
+
180
+ for (let i = 0; i < half_table_size - 1; i++) {
181
+ const r = i + ~~(random() * (256 - i));
182
+ const aux = p[i];
183
+
184
+ p[i] = p[r];
185
+ p[r] = aux;
186
+ }
187
+
188
+ for (let i = 256; i < table_size; i++) {
189
+ p[i] = p[i - 256];
190
+ }
191
+
192
+ return p;
193
+ }
@@ -6,8 +6,9 @@ import { computePathBase } from "./computePathBase.js";
6
6
  * @returns {String|null}
7
7
  */
8
8
  export function computeFileExtension(path) {
9
- if (typeof path !== "string") {
10
- throw new Error('path is not a string');
9
+ const type_of_path = typeof path;
10
+ if (type_of_path !== "string") {
11
+ throw new Error(`path must be a string, instead was '${type_of_path}'`);
11
12
  }
12
13
 
13
14
  //get base
@@ -100,6 +100,15 @@ class Engine {
100
100
  */
101
101
  this.ticker = new Ticker();
102
102
 
103
+ /**
104
+ *
105
+ * @type {AssetManager<Engine>}
106
+ */
107
+ this.assetManager = new AssetManager({
108
+ context:this,
109
+ executor: this.executor
110
+ });
111
+
103
112
  this.__performacne_monitor = new PeriodicConsolePrinter(15, () => {
104
113
  const metrics = this.performance;
105
114
  const stats = new MetricStatistics();
@@ -198,11 +207,6 @@ class Engine {
198
207
  */
199
208
  this.storage = this.platform.getStorage();
200
209
 
201
- /**
202
- *
203
- * @type {AssetManager}
204
- */
205
- this.assetManager = new AssetManager(this);
206
210
 
207
211
  this.localization = new Localization();
208
212
  this.localization.setAssetManager(this.assetManager);
@@ -374,9 +378,11 @@ class Engine {
374
378
  loadAssetList(listURL) {
375
379
  const preloader = new Preloader();
376
380
  const assetManager = this.assetManager;
377
- assetManager.get(listURL, "json", function (asset) {
378
- preloader.addAll(asset.create());
379
- preloader.load(assetManager);
381
+ assetManager.get({
382
+ path: listURL, type: "json", callback: function (asset) {
383
+ preloader.addAll(asset.create());
384
+ preloader.load(assetManager);
385
+ }
380
386
  });
381
387
  return preloader;
382
388
  }
@@ -244,31 +244,31 @@ export class AchievementManager extends EnginePlugin {
244
244
  loadDefinitions(assetManager) {
245
245
  return new Promise((resolve, reject) => {
246
246
  assetManager.get(
247
- "data/database/achievements/data.json",
248
- GameAssetType.JSON,
249
- (asset) => {
250
- try {
247
+ {
248
+ path: "data/database/achievements/data.json", type: GameAssetType.JSON, callback: (asset) => {
249
+ try {
251
250
 
252
- const json = asset.create();
251
+ const json = asset.create();
253
252
 
254
- json.forEach(def => {
255
- const achievement = new Achievement();
253
+ json.forEach(def => {
254
+ const achievement = new Achievement();
256
255
 
257
- achievement.fromJSON(def);
256
+ achievement.fromJSON(def);
258
257
 
259
- this.entries.push(achievement);
260
- });
258
+ this.entries.push(achievement);
259
+ });
261
260
 
262
- } catch (e) {
261
+ } catch (e) {
263
262
 
264
- reject(e);
263
+ reject(e);
265
264
 
266
- return;
267
- }
265
+ return;
266
+ }
268
267
 
269
- resolve();
268
+ resolve();
270
269
 
271
- }, reject);
270
+ }, failure: reject
271
+ });
272
272
  });
273
273
  }
274
274
 
@@ -2,14 +2,19 @@ import {AssetLoader} from "./loaders/AssetLoader";
2
2
  import {Asset} from "./Asset";
3
3
  import {CrossOriginConfig} from "./CORS/CrossOriginConfig";
4
4
  import {AssetTransformer} from "./AssetTransformer";
5
- import Engine from "../Engine";
5
+ import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor";
6
6
 
7
7
  interface PromiseOptions {
8
8
  skip_queue: boolean
9
9
  }
10
10
 
11
- export class AssetManager {
12
- constructor(engine: Engine)
11
+ interface AssetManagerOptions<CTX> {
12
+ context: CTX,
13
+ executor?: ConcurrentExecutor
14
+ }
15
+
16
+ export declare class AssetManager<CTX> {
17
+ constructor(options?: AssetManagerOptions<CTX>)
13
18
 
14
19
  public readonly crossOriginConfig: CrossOriginConfig
15
20
 
@@ -25,11 +30,11 @@ export class AssetManager {
25
30
 
26
31
  clear(): void
27
32
 
28
- registerLoader<T>(type: string, loader: AssetLoader<T>): Promise<AssetLoader<T>>
33
+ registerLoader<T>(type: string, loader: AssetLoader<T, CTX>): Promise<AssetLoader<T,CTX>>
29
34
 
30
35
  unregisterLoader(type: string): Promise<void>
31
36
 
32
- getLoaderByType<T>(type: string): AssetLoader<T> | undefined
37
+ getLoaderByType<T>(type: string): AssetLoader<T, CTX> | undefined
33
38
 
34
39
  registerTransformer<T extends Asset<X>, X = any>(type: string, transformer: AssetTransformer<T>): void
35
40
 
@@ -19,6 +19,10 @@ import { AssetRequest, AssetRequestFlags } from "./AssetRequest.js";
19
19
  import FastBinaryHeap from "../../core/collection/heap/FastBinaryHeap.js";
20
20
  import { AssetLoadState } from "./AssetLoadState.js";
21
21
  import { PendingAsset } from "./PendingAsset.js";
22
+ import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor.js";
23
+ import { AssetLoader } from "./loaders/AssetLoader.js";
24
+ import { array_push_if_unique } from "../../core/collection/array/array_push_if_unique.js";
25
+ import { AssetRequestScope } from "./AssetRequestScope.js";
22
26
 
23
27
 
24
28
  class Response {
@@ -45,6 +49,7 @@ function get_pending_asset_priority_score(pending_asset) {
45
49
 
46
50
  /**
47
51
  * Handles loading/generating assets
52
+ * @template CTX
48
53
  * @class
49
54
  */
50
55
  export class AssetManager {
@@ -164,19 +169,30 @@ export class AssetManager {
164
169
 
165
170
  /**
166
171
  *
167
- * @type {Engine|null}
172
+ * @type {CTX|null}
168
173
  * @private
169
174
  */
170
- #engine = null;
175
+ #context = null;
171
176
 
172
177
  /**
173
178
  *
174
- * @param {Engine} engine
179
+ * @type {ConcurrentExecutor|null}
180
+ */
181
+ #executor = null;
182
+
183
+ /**
184
+ *
185
+ * @param {CTX} context
186
+ * @param {ConcurrentExecutor} executor
175
187
  * @constructor
176
188
  */
177
- constructor(engine) {
189
+ constructor({
190
+ context,
191
+ executor = new ConcurrentExecutor()
192
+ } = {}) {
178
193
 
179
- this.#engine = engine;
194
+ this.#context = context;
195
+ this.#executor = executor;
180
196
 
181
197
  }
182
198
 
@@ -185,7 +201,7 @@ export class AssetManager {
185
201
  return;
186
202
  }
187
203
 
188
- this.#engine.executor.run(this.#response_processor);
204
+ this.#executor.run(this.#response_processor);
189
205
 
190
206
  this.#is_running = true;
191
207
  }
@@ -205,7 +221,7 @@ export class AssetManager {
205
221
  await Promise.allSettled([Task.promise(this.#response_processor)]);
206
222
  }
207
223
 
208
- this.#engine.executor.removeTask(this.#response_processor);
224
+ this.#executor.removeTask(this.#response_processor);
209
225
 
210
226
  this.#is_running = false;
211
227
  }
@@ -237,12 +253,19 @@ export class AssetManager {
237
253
  /**
238
254
  * @param {String} path
239
255
  * @param {String} type
256
+ * @param {AssetRequestScope} [scope]
240
257
  * @param {boolean} [skip_queue] if true will skip the queue and dispatch request immediately
241
258
  * @returns {Promise<Asset>}
242
259
  */
243
- promise(path, type, { skip_queue = false } = {}) {
260
+ promise(path, type, { scope, skip_queue = false } = {}) {
244
261
  return new Promise((resolve, reject) => {
245
- this.get(path, type, resolve, reject);
262
+ this.get({
263
+ path,
264
+ type,
265
+ callback: resolve,
266
+ failure: reject,
267
+ scope
268
+ });
246
269
  });
247
270
  }
248
271
 
@@ -254,13 +277,23 @@ export class AssetManager {
254
277
  * @param {function(*)} [failure]
255
278
  * @param {function(loaded:number, total:number)} [progress]
256
279
  * @param {boolean} [skip_queue]
257
- */
258
- get(path, type, callback, failure = console.error, progress = noop, skip_queue = false) {
280
+ * @param {AssetRequestScope} [scope]
281
+ */
282
+ get({
283
+ path,
284
+ type,
285
+ callback,
286
+ failure = console.error,
287
+ progress = noop,
288
+ skip_queue = false,
289
+ scope = null
290
+ }) {
291
+
259
292
  if (typeof path !== "string") {
260
- throw new Error("Path must be string. Path = " + JSON.stringify(path));
293
+ throw new TypeError(`Path must be string. instead was '${typeof path}'`);
261
294
  }
262
295
 
263
- if(typeof type !== "string"){
296
+ if (typeof type !== "string") {
264
297
  throw new TypeError(`type must be a string, instead was '${typeof type}'`);
265
298
  }
266
299
 
@@ -274,6 +307,7 @@ export class AssetManager {
274
307
  //create request object
275
308
  const assetRequest = new AssetRequest(callback, failure, progress);
276
309
 
310
+ assetRequest.scope = scope;
277
311
  assetRequest.writeFlag(AssetRequestFlags.SkipQueue, skip_queue);
278
312
 
279
313
  //submit request
@@ -526,18 +560,34 @@ export class AssetManager {
526
560
  pendingAsset.progress.setUpperLimit(total);
527
561
  }
528
562
 
529
- try {
530
- const fullPath = this.rootPath + path;
563
+ // collect scopes
564
+ const scopes = [];
531
565
 
532
- if (typeof loader === "function") {
566
+ for (let i = 0; i < requests.length; i++) {
567
+ const request = requests[i];
568
+ const request_scope = request.scope;
533
569
 
534
- loader(fullPath, success, failure, progress);
570
+ if (request_scope !== null) {
571
+ array_push_if_unique(scopes, request_scope)
572
+ }
573
+ }
535
574
 
536
- } else {
575
+ let scope;
576
+ if (scopes.length > 0) {
577
+ scope = AssetRequestScope.from(scopes);
578
+ } else {
579
+ scope = AssetRequestScope.GLOBAL;
580
+ }
537
581
 
538
- loader.load(fullPath, success, failure, progress);
539
582
 
540
- }
583
+ const full_path = this.rootPath + path;
584
+
585
+ // console.log(`Request type: ${type}, path: ${path}, scope: ${scope}`);
586
+
587
+ try {
588
+
589
+
590
+ loader.load(scope, full_path, success, failure, progress);
541
591
 
542
592
  } catch (e) {
543
593
  console.error(`Loader failed on invocation. path=${path}, type=${type}`, 'Loader exception: ', e);
@@ -689,20 +739,25 @@ export class AssetManager {
689
739
  }
690
740
  }
691
741
 
692
- if (typeof loader === "function") {
693
742
 
743
+ let _loader = loader;
744
+
745
+ if (typeof _loader === "function") {
746
+
747
+ _loader = new AssetLoader();
748
+ _loader.load = loader;
694
749
 
695
750
  console.warn(`function-based loaders are deprecated (${type})`);
696
751
 
697
752
  } else {
698
753
 
699
- await loader.link(this, this.#engine);
754
+ await _loader.link(this, this.#context);
700
755
 
701
756
  }
702
757
 
703
- this.#loaders[type] = loader;
758
+ this.#loaders[type] = _loader;
704
759
 
705
- return loader;
760
+ return _loader;
706
761
  }
707
762
 
708
763
  /**
@@ -16,7 +16,7 @@ function dummyEngine() {
16
16
  }
17
17
 
18
18
  class DummyLoader extends AssetLoader {
19
- load(path, success, failure, progress) {
19
+ load(scope,path, success, failure, progress) {
20
20
  success(new Asset(() => 1));
21
21
  }
22
22
  }