@holoscript/engine 6.0.3 → 6.0.4

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 (192) hide show
  1. package/dist/AutoMesher-CK47F6AV.js +17 -0
  2. package/dist/GPUBuffers-2LHBCD7X.js +9 -0
  3. package/dist/WebGPUContext-TNEUYU2Y.js +11 -0
  4. package/dist/animation/index.cjs +38 -38
  5. package/dist/animation/index.d.cts +1 -1
  6. package/dist/animation/index.d.ts +1 -1
  7. package/dist/animation/index.js +1 -1
  8. package/dist/audio/index.cjs +16 -6
  9. package/dist/audio/index.d.cts +1 -1
  10. package/dist/audio/index.d.ts +1 -1
  11. package/dist/audio/index.js +1 -1
  12. package/dist/camera/index.cjs +23 -23
  13. package/dist/camera/index.d.cts +1 -1
  14. package/dist/camera/index.d.ts +1 -1
  15. package/dist/camera/index.js +1 -1
  16. package/dist/character/index.cjs +6 -4
  17. package/dist/character/index.js +1 -1
  18. package/dist/choreography/index.cjs +1194 -0
  19. package/dist/choreography/index.d.cts +687 -0
  20. package/dist/choreography/index.d.ts +687 -0
  21. package/dist/choreography/index.js +1156 -0
  22. package/dist/chunk-2CSNRI2N.js +217 -0
  23. package/dist/chunk-33T2WINR.js +266 -0
  24. package/dist/chunk-35R73OFM.js +1257 -0
  25. package/dist/chunk-4MMDSUNP.js +1256 -0
  26. package/dist/chunk-5V6HOU72.js +319 -0
  27. package/dist/chunk-6QOP6PYF.js +1038 -0
  28. package/dist/chunk-7KMJVHIL.js +8944 -0
  29. package/dist/chunk-7VPUC62U.js +1106 -0
  30. package/dist/chunk-A2Y6RCAT.js +1878 -0
  31. package/dist/chunk-AHM42MK6.js +8944 -0
  32. package/dist/chunk-BL7IDTHE.js +218 -0
  33. package/dist/chunk-CITOMSWL.js +10462 -0
  34. package/dist/chunk-CXDPKW2K.js +8944 -0
  35. package/dist/chunk-CXZPLD4S.js +223 -0
  36. package/dist/chunk-CZYJE7IH.js +5169 -0
  37. package/dist/chunk-D2OP7YC7.js +6325 -0
  38. package/dist/chunk-EDRVQHUU.js +1544 -0
  39. package/dist/chunk-EJSLOOW2.js +3589 -0
  40. package/dist/chunk-F53SFGW5.js +1878 -0
  41. package/dist/chunk-HCFPELPY.js +919 -0
  42. package/dist/chunk-HNEE36PY.js +93 -0
  43. package/dist/chunk-HYXNV36F.js +1256 -0
  44. package/dist/chunk-IB7KHVFY.js +821 -0
  45. package/dist/chunk-IBBO7YYG.js +690 -0
  46. package/dist/chunk-ILIBGINU.js +5470 -0
  47. package/dist/chunk-IS4MHLKN.js +5479 -0
  48. package/dist/chunk-JT2PFKWD.js +5479 -0
  49. package/dist/chunk-K4CUB4NY.js +1038 -0
  50. package/dist/chunk-KATDQXRJ.js +10462 -0
  51. package/dist/chunk-KBQE6ZFJ.js +8944 -0
  52. package/dist/chunk-KBVD5K7E.js +560 -0
  53. package/dist/chunk-KCDPVQRY.js +4088 -0
  54. package/dist/chunk-KN4QJPKN.js +8944 -0
  55. package/dist/chunk-KWJ3ROSI.js +8944 -0
  56. package/dist/chunk-L45VF6DD.js +919 -0
  57. package/dist/chunk-LY4T37YK.js +307 -0
  58. package/dist/chunk-MDN5WZXA.js +1544 -0
  59. package/dist/chunk-MGCDP6VU.js +928 -0
  60. package/dist/chunk-NCX7X6G2.js +8681 -0
  61. package/dist/chunk-OF54BPVD.js +913 -0
  62. package/dist/chunk-OWSN2Q3Q.js +690 -0
  63. package/dist/chunk-PRRB5TTA.js +406 -0
  64. package/dist/chunk-PXWVQF76.js +4086 -0
  65. package/dist/chunk-PYCOIDT2.js +812 -0
  66. package/dist/chunk-PZCSADOV.js +928 -0
  67. package/dist/chunk-Q2XBVS2K.js +1038 -0
  68. package/dist/chunk-QDZRXWN5.js +1776 -0
  69. package/dist/chunk-RNWOZ6WQ.js +913 -0
  70. package/dist/chunk-ROLFT4CJ.js +1693 -0
  71. package/dist/chunk-SLTJRZ2N.js +266 -0
  72. package/dist/chunk-SRUS5XSU.js +4088 -0
  73. package/dist/chunk-TKCA3WZ5.js +5409 -0
  74. package/dist/chunk-TNRMXYI2.js +1650 -0
  75. package/dist/chunk-TQB3GJGM.js +9763 -0
  76. package/dist/chunk-TUFGXG6K.js +510 -0
  77. package/dist/chunk-U6KMTGQJ.js +632 -0
  78. package/dist/chunk-VMGJQST6.js +8681 -0
  79. package/dist/chunk-X4F4TCG4.js +5470 -0
  80. package/dist/chunk-ZIFROE75.js +1544 -0
  81. package/dist/chunk-ZIJQYHSQ.js +1204 -0
  82. package/dist/combat/index.cjs +4 -4
  83. package/dist/combat/index.d.cts +1 -1
  84. package/dist/combat/index.d.ts +1 -1
  85. package/dist/combat/index.js +1 -1
  86. package/dist/ecs/index.cjs +1 -1
  87. package/dist/ecs/index.js +1 -1
  88. package/dist/environment/index.cjs +14 -14
  89. package/dist/environment/index.d.cts +1 -1
  90. package/dist/environment/index.d.ts +1 -1
  91. package/dist/environment/index.js +1 -1
  92. package/dist/gpu/index.cjs +4810 -0
  93. package/dist/gpu/index.js +3714 -0
  94. package/dist/hologram/index.cjs +27 -1
  95. package/dist/hologram/index.js +1 -1
  96. package/dist/index-B2PIsAmR.d.cts +2180 -0
  97. package/dist/index-B2PIsAmR.d.ts +2180 -0
  98. package/dist/index-BHySEPX7.d.cts +2921 -0
  99. package/dist/index-BJV21zuy.d.cts +341 -0
  100. package/dist/index-BJV21zuy.d.ts +341 -0
  101. package/dist/index-BQutTphC.d.cts +790 -0
  102. package/dist/index-ByIq2XrS.d.cts +3910 -0
  103. package/dist/index-BysHjDSO.d.cts +224 -0
  104. package/dist/index-BysHjDSO.d.ts +224 -0
  105. package/dist/index-CKwAJGck.d.ts +455 -0
  106. package/dist/index-CUl3QstQ.d.cts +3006 -0
  107. package/dist/index-CUl3QstQ.d.ts +3006 -0
  108. package/dist/index-CmYtNiI-.d.cts +953 -0
  109. package/dist/index-CmYtNiI-.d.ts +953 -0
  110. package/dist/index-CnRzWxi_.d.cts +522 -0
  111. package/dist/index-CnRzWxi_.d.ts +522 -0
  112. package/dist/index-CwRWbSC7.d.ts +2921 -0
  113. package/dist/index-CxKIBstO.d.ts +790 -0
  114. package/dist/index-DJ6-R8vh.d.cts +455 -0
  115. package/dist/index-DQKisbcI.d.cts +4968 -0
  116. package/dist/index-DQKisbcI.d.ts +4968 -0
  117. package/dist/index-DRT2zJez.d.ts +3910 -0
  118. package/dist/index-DfNLiAka.d.cts +192 -0
  119. package/dist/index-DfNLiAka.d.ts +192 -0
  120. package/dist/index-nMvkoRm8.d.cts +405 -0
  121. package/dist/index-nMvkoRm8.d.ts +405 -0
  122. package/dist/index-s9yOFU37.d.cts +604 -0
  123. package/dist/index-s9yOFU37.d.ts +604 -0
  124. package/dist/index.cjs +22966 -6960
  125. package/dist/index.d.cts +864 -20
  126. package/dist/index.d.ts +864 -20
  127. package/dist/index.js +3062 -48
  128. package/dist/input/index.cjs +1 -1
  129. package/dist/input/index.js +1 -1
  130. package/dist/orbital/index.cjs +3 -3
  131. package/dist/orbital/index.d.cts +1 -1
  132. package/dist/orbital/index.d.ts +1 -1
  133. package/dist/orbital/index.js +1 -1
  134. package/dist/particles/index.cjs +16 -16
  135. package/dist/particles/index.d.cts +1 -1
  136. package/dist/particles/index.d.ts +1 -1
  137. package/dist/particles/index.js +1 -1
  138. package/dist/physics/index.cjs +2377 -21
  139. package/dist/physics/index.d.cts +1 -1
  140. package/dist/physics/index.d.ts +1 -1
  141. package/dist/physics/index.js +35 -1
  142. package/dist/postfx/index.cjs +3491 -0
  143. package/dist/postfx/index.js +93 -0
  144. package/dist/procedural/index.cjs +1 -1
  145. package/dist/procedural/index.js +1 -1
  146. package/dist/puppeteer-5VF6KDVO.js +52197 -0
  147. package/dist/puppeteer-IZVZ3SG4.js +52197 -0
  148. package/dist/rendering/index.cjs +33 -32
  149. package/dist/rendering/index.d.cts +1 -1
  150. package/dist/rendering/index.d.ts +1 -1
  151. package/dist/rendering/index.js +8 -6
  152. package/dist/runtime/index.cjs +23 -13
  153. package/dist/runtime/index.d.cts +1 -1
  154. package/dist/runtime/index.d.ts +1 -1
  155. package/dist/runtime/index.js +8 -6
  156. package/dist/runtime/protocols/index.cjs +349 -0
  157. package/dist/runtime/protocols/index.js +15 -0
  158. package/dist/scene/index.cjs +8 -8
  159. package/dist/scene/index.d.cts +1 -1
  160. package/dist/scene/index.d.ts +1 -1
  161. package/dist/scene/index.js +1 -1
  162. package/dist/shader/index.cjs +3087 -0
  163. package/dist/shader/index.js +3044 -0
  164. package/dist/simulation/index.cjs +10680 -0
  165. package/dist/simulation/index.d.cts +3 -0
  166. package/dist/simulation/index.d.ts +3 -0
  167. package/dist/simulation/index.js +307 -0
  168. package/dist/spatial/index.cjs +2443 -0
  169. package/dist/spatial/index.d.cts +1545 -0
  170. package/dist/spatial/index.d.ts +1545 -0
  171. package/dist/spatial/index.js +2400 -0
  172. package/dist/terrain/index.cjs +1 -1
  173. package/dist/terrain/index.d.cts +1 -1
  174. package/dist/terrain/index.d.ts +1 -1
  175. package/dist/terrain/index.js +1 -1
  176. package/dist/transformers.node-4NKAPD5U.js +45620 -0
  177. package/dist/vm/index.cjs +7 -8
  178. package/dist/vm/index.d.cts +1 -1
  179. package/dist/vm/index.d.ts +1 -1
  180. package/dist/vm/index.js +1 -1
  181. package/dist/vm-bridge/index.cjs +2 -2
  182. package/dist/vm-bridge/index.d.cts +2 -2
  183. package/dist/vm-bridge/index.d.ts +2 -2
  184. package/dist/vm-bridge/index.js +1 -1
  185. package/dist/vr/index.cjs +6 -6
  186. package/dist/vr/index.js +1 -1
  187. package/dist/world/index.cjs +3 -3
  188. package/dist/world/index.d.cts +1 -1
  189. package/dist/world/index.d.ts +1 -1
  190. package/dist/world/index.js +1 -1
  191. package/package.json +53 -21
  192. package/LICENSE +0 -21
@@ -0,0 +1,406 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-AKLW2MUS.js";
4
+
5
+ // src/world/index.ts
6
+ var world_exports = {};
7
+ __export(world_exports, {
8
+ LODManager: () => LODManager,
9
+ OcclusionCulling: () => OcclusionCulling,
10
+ WorldStreamer: () => WorldStreamer
11
+ });
12
+
13
+ // src/world/LODManager.ts
14
+ var DEFAULT_LOD_LEVELS = [
15
+ { level: 0, maxDistance: 50, meshDetail: 1 },
16
+ { level: 1, maxDistance: 150, meshDetail: 0.5 },
17
+ { level: 2, maxDistance: 400, meshDetail: 0.25 },
18
+ { level: 3, maxDistance: Infinity, meshDetail: 0.1 }
19
+ ];
20
+ var DEFAULT_LOD_CONFIG = {
21
+ defaultLevels: DEFAULT_LOD_LEVELS,
22
+ hysteresis: 5,
23
+ transitionSpeed: 5,
24
+ maxObjects: 1e4
25
+ };
26
+ var LODManager = class {
27
+ config;
28
+ objects = /* @__PURE__ */ new Map();
29
+ viewerPosition = { x: 0, y: 0, z: 0 };
30
+ constructor(config) {
31
+ this.config = { ...DEFAULT_LOD_CONFIG, ...config };
32
+ }
33
+ // ---------------------------------------------------------------------------
34
+ // Object Management
35
+ // ---------------------------------------------------------------------------
36
+ register(id, position, levels, bias = 1) {
37
+ const obj = {
38
+ id,
39
+ position: { ...position },
40
+ currentLevel: 0,
41
+ levels: levels ?? [...this.config.defaultLevels],
42
+ bias,
43
+ visible: true,
44
+ transitionAlpha: 1
45
+ };
46
+ this.objects.set(id, obj);
47
+ return obj;
48
+ }
49
+ unregister(id) {
50
+ return this.objects.delete(id);
51
+ }
52
+ // ---------------------------------------------------------------------------
53
+ // Update
54
+ // ---------------------------------------------------------------------------
55
+ setViewerPosition(x, y, z) {
56
+ this.viewerPosition = { x, y, z };
57
+ }
58
+ update(dt) {
59
+ for (const obj of this.objects.values()) {
60
+ const dx = obj.position[0] - this.viewerPosition[0];
61
+ const dy = obj.position[1] - this.viewerPosition[1];
62
+ const dz = obj.position[2] - this.viewerPosition[2];
63
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz) * obj.bias;
64
+ let targetLevel = obj.levels.length - 1;
65
+ for (let i = 0; i < obj.levels.length; i++) {
66
+ const threshold = obj.levels[i].maxDistance;
67
+ const hysteresisAdjust = i > obj.currentLevel ? this.config.hysteresis : -this.config.hysteresis;
68
+ if (dist < threshold + hysteresisAdjust) {
69
+ targetLevel = i;
70
+ break;
71
+ }
72
+ }
73
+ if (targetLevel !== obj.currentLevel) {
74
+ obj.currentLevel = targetLevel;
75
+ obj.transitionAlpha = 0;
76
+ }
77
+ if (obj.transitionAlpha < 1) {
78
+ obj.transitionAlpha = Math.min(1, obj.transitionAlpha + dt * this.config.transitionSpeed);
79
+ }
80
+ }
81
+ }
82
+ // ---------------------------------------------------------------------------
83
+ // Queries
84
+ // ---------------------------------------------------------------------------
85
+ getObject(id) {
86
+ return this.objects.get(id);
87
+ }
88
+ getObjectCount() {
89
+ return this.objects.size;
90
+ }
91
+ getLevelDistribution() {
92
+ const dist = /* @__PURE__ */ new Map();
93
+ for (const obj of this.objects.values()) {
94
+ dist.set(obj.currentLevel, (dist.get(obj.currentLevel) ?? 0) + 1);
95
+ }
96
+ return dist;
97
+ }
98
+ getObjectsAtLevel(level) {
99
+ return [...this.objects.values()].filter((o) => o.currentLevel === level);
100
+ }
101
+ getAverageLOD() {
102
+ if (this.objects.size === 0) return 0;
103
+ let sum = 0;
104
+ for (const obj of this.objects.values()) sum += obj.currentLevel;
105
+ return sum / this.objects.size;
106
+ }
107
+ };
108
+
109
+ // src/world/OcclusionCulling.ts
110
+ var OcclusionCulling = class {
111
+ objects = /* @__PURE__ */ new Map();
112
+ zones = /* @__PURE__ */ new Map();
113
+ portals = /* @__PURE__ */ new Map();
114
+ frustumPlanes = [];
115
+ currentFrame = 0;
116
+ visibleCount = 0;
117
+ culledCount = 0;
118
+ layerMask = 4294967295;
119
+ // ---------------------------------------------------------------------------
120
+ // Object Management
121
+ // ---------------------------------------------------------------------------
122
+ register(id, bounds, layer = 0) {
123
+ const obj = {
124
+ id,
125
+ bounds,
126
+ visible: true,
127
+ lastTestFrame: 0,
128
+ layer
129
+ };
130
+ this.objects.set(id, obj);
131
+ return obj;
132
+ }
133
+ unregister(id) {
134
+ return this.objects.delete(id);
135
+ }
136
+ updateBounds(id, bounds) {
137
+ const obj = this.objects.get(id);
138
+ if (obj) obj.bounds = bounds;
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Zones & Portals
142
+ // ---------------------------------------------------------------------------
143
+ addZone(id, bounds, objectIds = []) {
144
+ this.zones.set(id, { id, bounds, objects: objectIds });
145
+ }
146
+ addPortal(id, bounds, zone1, zone2) {
147
+ this.portals.set(id, { id, bounds, connectedZones: [zone1, zone2], open: true });
148
+ }
149
+ setPortalOpen(id, open) {
150
+ const portal = this.portals.get(id);
151
+ if (portal) portal.open = open;
152
+ }
153
+ // ---------------------------------------------------------------------------
154
+ // Frustum Setup
155
+ // ---------------------------------------------------------------------------
156
+ setFrustum(planes) {
157
+ this.frustumPlanes = planes;
158
+ }
159
+ setLayerMask(mask) {
160
+ this.layerMask = mask;
161
+ }
162
+ // ---------------------------------------------------------------------------
163
+ // Culling
164
+ // ---------------------------------------------------------------------------
165
+ performCulling() {
166
+ this.currentFrame++;
167
+ this.visibleCount = 0;
168
+ this.culledCount = 0;
169
+ for (const obj of this.objects.values()) {
170
+ if ((this.layerMask & 1 << obj.layer) === 0) {
171
+ obj.visible = false;
172
+ this.culledCount++;
173
+ continue;
174
+ }
175
+ obj.visible = this.isInFrustum(obj.bounds);
176
+ obj.lastTestFrame = this.currentFrame;
177
+ if (obj.visible) {
178
+ this.visibleCount++;
179
+ } else {
180
+ this.culledCount++;
181
+ }
182
+ }
183
+ }
184
+ isInFrustum(bounds) {
185
+ if (this.frustumPlanes.length === 0) return true;
186
+ for (const plane of this.frustumPlanes) {
187
+ const px = plane.normal.x >= 0 ? bounds.max.x : bounds.min.x;
188
+ const py = plane.normal.y >= 0 ? bounds.max.y : bounds.min.y;
189
+ const pz = plane.normal.z >= 0 ? bounds.max.z : bounds.min.z;
190
+ const dot = plane.normal.x * px + plane.normal.y * py + plane.normal.z * pz + plane.distance;
191
+ if (dot < 0) return false;
192
+ }
193
+ return true;
194
+ }
195
+ // ---------------------------------------------------------------------------
196
+ // AABB Intersection
197
+ // ---------------------------------------------------------------------------
198
+ testAABBOverlap(a, b) {
199
+ return a.min.x <= b.max.x && a.max.x >= b.min.x && a.min.y <= b.max.y && a.max.y >= b.min.y && a.min.z <= b.max.z && a.max.z >= b.min.z;
200
+ }
201
+ queryRegion(region) {
202
+ const result = [];
203
+ for (const obj of this.objects.values()) {
204
+ if (this.testAABBOverlap(obj.bounds, region)) {
205
+ result.push(obj);
206
+ }
207
+ }
208
+ return result;
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Portal Visibility
212
+ // ---------------------------------------------------------------------------
213
+ getVisibleZones(startZone) {
214
+ const visited = /* @__PURE__ */ new Set();
215
+ const queue = [startZone];
216
+ visited.add(startZone);
217
+ while (queue.length > 0) {
218
+ const current = queue.shift();
219
+ for (const portal of this.portals.values()) {
220
+ if (!portal.open) continue;
221
+ const [z1, z2] = portal.connectedZones;
222
+ if (z1 === current && !visited.has(z2)) {
223
+ visited.add(z2);
224
+ queue.push(z2);
225
+ } else if (z2 === current && !visited.has(z1)) {
226
+ visited.add(z1);
227
+ queue.push(z1);
228
+ }
229
+ }
230
+ }
231
+ return [...visited];
232
+ }
233
+ // ---------------------------------------------------------------------------
234
+ // Queries
235
+ // ---------------------------------------------------------------------------
236
+ getVisibleObjects() {
237
+ return [...this.objects.values()].filter((o) => o.visible);
238
+ }
239
+ getVisibleCount() {
240
+ return this.visibleCount;
241
+ }
242
+ getCulledCount() {
243
+ return this.culledCount;
244
+ }
245
+ getTotalCount() {
246
+ return this.objects.size;
247
+ }
248
+ getCullRatio() {
249
+ return this.objects.size > 0 ? this.culledCount / this.objects.size : 0;
250
+ }
251
+ getCurrentFrame() {
252
+ return this.currentFrame;
253
+ }
254
+ };
255
+
256
+ // src/world/WorldStreamer.ts
257
+ var DEFAULT_STREAMING = {
258
+ chunkSize: 64,
259
+ loadRadius: 3,
260
+ unloadRadius: 5,
261
+ maxConcurrentLoads: 4,
262
+ memoryBudget: 256 * 1024 * 1024
263
+ // 256MB
264
+ };
265
+ var WorldStreamer = class {
266
+ config;
267
+ chunks = /* @__PURE__ */ new Map();
268
+ viewerPosition = { x: 0, z: 0 };
269
+ totalMemory = 0;
270
+ loadQueue = [];
271
+ activeLoads = 0;
272
+ chunkGenerator = null;
273
+ constructor(config) {
274
+ this.config = { ...DEFAULT_STREAMING, ...config };
275
+ }
276
+ // ---------------------------------------------------------------------------
277
+ // Chunk Generator
278
+ // ---------------------------------------------------------------------------
279
+ setChunkGenerator(gen) {
280
+ this.chunkGenerator = gen;
281
+ }
282
+ // ---------------------------------------------------------------------------
283
+ // Update
284
+ // ---------------------------------------------------------------------------
285
+ setViewerPosition(x, z) {
286
+ this.viewerPosition = { x, z };
287
+ }
288
+ update() {
289
+ const cx = Math.floor(this.viewerPosition.x / this.config.chunkSize);
290
+ const cz = Math.floor(this.viewerPosition.z / this.config.chunkSize);
291
+ for (let dx = -this.config.loadRadius; dx <= this.config.loadRadius; dx++) {
292
+ for (let dz = -this.config.loadRadius; dz <= this.config.loadRadius; dz++) {
293
+ const chunkX = cx + dx;
294
+ const chunkZ = cz + dz;
295
+ const id = `${chunkX},${chunkZ}`;
296
+ if (!this.chunks.has(id)) {
297
+ const dist = Math.sqrt(dx * dx + dz * dz);
298
+ if (dist <= this.config.loadRadius) {
299
+ this.requestLoad(chunkX, chunkZ, this.config.loadRadius - dist);
300
+ }
301
+ }
302
+ }
303
+ }
304
+ this.processLoadQueue();
305
+ for (const [id, chunk] of this.chunks) {
306
+ if (chunk.state !== "loaded") continue;
307
+ const dx = chunk.x - cx;
308
+ const dz = chunk.z - cz;
309
+ const dist = Math.sqrt(dx * dx + dz * dz);
310
+ if (dist > this.config.unloadRadius) {
311
+ this.unloadChunk(id);
312
+ }
313
+ }
314
+ }
315
+ // ---------------------------------------------------------------------------
316
+ // Loading / Unloading
317
+ // ---------------------------------------------------------------------------
318
+ requestLoad(x, z, priority) {
319
+ const id = `${x},${z}`;
320
+ if (this.chunks.has(id)) return;
321
+ const chunk = {
322
+ id,
323
+ x,
324
+ z,
325
+ state: "loading",
326
+ data: null,
327
+ priority,
328
+ lastAccessTime: Date.now(),
329
+ size: 0
330
+ };
331
+ this.chunks.set(id, chunk);
332
+ this.loadQueue.push(id);
333
+ this.loadQueue.sort((a, b) => {
334
+ const ca = this.chunks.get(a), cb = this.chunks.get(b);
335
+ return cb.priority - ca.priority;
336
+ });
337
+ }
338
+ processLoadQueue() {
339
+ while (this.loadQueue.length > 0 && this.activeLoads < this.config.maxConcurrentLoads) {
340
+ const id = this.loadQueue.shift();
341
+ const chunk = this.chunks.get(id);
342
+ if (!chunk || chunk.state !== "loading") continue;
343
+ this.activeLoads++;
344
+ if (this.chunkGenerator) {
345
+ chunk.data = this.chunkGenerator(chunk.x, chunk.z);
346
+ const serialized = JSON.stringify(chunk.data);
347
+ chunk.size = serialized.length;
348
+ this.totalMemory += chunk.size;
349
+ } else {
350
+ chunk.data = { x: chunk.x, z: chunk.z };
351
+ chunk.size = 64;
352
+ this.totalMemory += 64;
353
+ }
354
+ chunk.state = "loaded";
355
+ chunk.lastAccessTime = Date.now();
356
+ this.activeLoads--;
357
+ }
358
+ }
359
+ unloadChunk(id) {
360
+ const chunk = this.chunks.get(id);
361
+ if (!chunk) return;
362
+ this.totalMemory -= chunk.size;
363
+ this.chunks.delete(id);
364
+ }
365
+ // ---------------------------------------------------------------------------
366
+ // Manual Load
367
+ // ---------------------------------------------------------------------------
368
+ loadChunk(x, z) {
369
+ const id = `${x},${z}`;
370
+ const existing = this.chunks.get(id);
371
+ if (existing) return existing;
372
+ this.requestLoad(x, z, 999);
373
+ this.processLoadQueue();
374
+ return this.chunks.get(id);
375
+ }
376
+ // ---------------------------------------------------------------------------
377
+ // Queries
378
+ // ---------------------------------------------------------------------------
379
+ getChunk(x, z) {
380
+ return this.chunks.get(`${x},${z}`);
381
+ }
382
+ getLoadedChunks() {
383
+ return [...this.chunks.values()].filter((c) => c.state === "loaded");
384
+ }
385
+ getLoadedCount() {
386
+ let count = 0;
387
+ for (const c of this.chunks.values()) if (c.state === "loaded") count++;
388
+ return count;
389
+ }
390
+ getTotalMemory() {
391
+ return this.totalMemory;
392
+ }
393
+ isOverBudget() {
394
+ return this.totalMemory > this.config.memoryBudget;
395
+ }
396
+ getChunkSize() {
397
+ return this.config.chunkSize;
398
+ }
399
+ };
400
+
401
+ export {
402
+ LODManager,
403
+ OcclusionCulling,
404
+ WorldStreamer,
405
+ world_exports
406
+ };