minerender 2.1.0-alpha.91 → 2.1.0-alpha.92

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.
package/dist/bundle.js CHANGED
@@ -119319,10 +119319,13 @@ gl_FragDepth=readDepth(vUv);
119319
119319
  return this.locations(this.bytes(data)).map(({ x: x4, z: z4 }) => ({ x: x4, z: z4 }));
119320
119320
  }
119321
119321
  /** Decodes all stored chunks. Gzip, zlib, LZ4, and uncompressed payloads are supported. */
119322
- static async parse(data) {
119322
+ static async parse(data, options = {}) {
119323
+ options.signal?.throwIfAborted();
119323
119324
  const bytes = this.bytes(data);
119324
119325
  const chunks = [];
119325
- for (const location of this.locations(bytes)) chunks.push(await this.readChunk(bytes, location));
119326
+ for (const location of this.locations(bytes)) {
119327
+ chunks.push(await this.abortable(this.readChunk(bytes, location, options), options.signal));
119328
+ }
119326
119329
  return { chunks };
119327
119330
  }
119328
119331
  /**
@@ -119331,13 +119334,28 @@ gl_FragDepth=readDepth(vUv);
119331
119334
  * @param localZ - Chunk z within the region, from 0 to 31.
119332
119335
  * @returns The chunk with absolute coordinates, or `undefined` if the region has no chunk there.
119333
119336
  */
119334
- static async parseChunk(data, localX, localZ) {
119337
+ static async parseChunk(data, localX, localZ, options = {}) {
119338
+ options.signal?.throwIfAborted();
119335
119339
  if (![localX, localZ].every((value) => Number.isInteger(value) && value >= 0 && value < 32)) {
119336
119340
  throw new RangeError("Region-local chunk coordinates must be integers from 0 to 31");
119337
119341
  }
119338
119342
  const bytes = this.bytes(data);
119339
119343
  const location = this.locations(bytes).find(({ x: x4, z: z4 }) => x4 === localX && z4 === localZ);
119340
- return location ? this.readChunk(bytes, location) : void 0;
119344
+ return location ? this.abortable(this.readChunk(bytes, location, options), options.signal) : void 0;
119345
+ }
119346
+ static async abortable(promise, signal) {
119347
+ if (!signal) return promise;
119348
+ let abort2;
119349
+ const cancelled = new Promise((_4, reject) => {
119350
+ abort2 = () => reject(signal.reason);
119351
+ signal.addEventListener("abort", abort2, { once: true });
119352
+ if (signal.aborted) abort2();
119353
+ });
119354
+ try {
119355
+ return await Promise.race([promise, cancelled]);
119356
+ } finally {
119357
+ signal.removeEventListener("abort", abort2);
119358
+ }
119341
119359
  }
119342
119360
  static bytes(data) {
119343
119361
  return data instanceof Uint8Array ? data : new Uint8Array(data);
@@ -119363,20 +119381,41 @@ gl_FragDepth=readDepth(vUv);
119363
119381
  }
119364
119382
  return locations;
119365
119383
  }
119366
- static async readChunk(data, location) {
119367
- const compression = data[location.offset + 4];
119368
- if (compression & 128) throw new MineRenderError("External Anvil .mcc chunks are not supported");
119384
+ static async readChunk(data, location, options) {
119385
+ options.signal?.throwIfAborted();
119386
+ const format3 = data[location.offset + 4];
119387
+ const external = (format3 & 128) !== 0;
119388
+ const compression = format3 & 127;
119369
119389
  if (compression !== 1 && compression !== 2 && compression !== 3 && compression !== 4) {
119370
119390
  throw new MineRenderError(`Unsupported Anvil compression ${compression}`);
119371
119391
  }
119372
119392
  let payload = data.subarray(location.offset + 5, location.offset + 4 + location.length);
119393
+ let expected;
119394
+ if (external) {
119395
+ if (!options.region || !options.readExternalChunk) {
119396
+ throw new MineRenderError("External Anvil .mcc chunks require region coordinates and readExternalChunk");
119397
+ }
119398
+ if (![options.region.x, options.region.z].every(Number.isSafeInteger)) {
119399
+ throw new RangeError("Anvil region coordinates must be safe integers");
119400
+ }
119401
+ expected = { x: options.region.x * 32 + location.x, z: options.region.z * 32 + location.z };
119402
+ if (![expected.x, expected.z].every(Number.isSafeInteger)) {
119403
+ throw new RangeError("External Anvil chunk coordinates must be safe integers");
119404
+ }
119405
+ const externalData = await options.readExternalChunk(expected.x, expected.z, options.signal);
119406
+ options.signal?.throwIfAborted();
119407
+ if (externalData === void 0) throw new MineRenderError(`External Anvil chunk c.${expected.x}.${expected.z}.mcc is missing`);
119408
+ payload = this.bytes(externalData);
119409
+ }
119373
119410
  if (compression === 4) {
119374
119411
  payload = decodeAnvilLz4(payload);
119375
119412
  } else if (compression !== 3) {
119376
119413
  const stream = new Blob([payload]).stream().pipeThrough(new DecompressionStream(compression === 1 ? "gzip" : "deflate"));
119377
119414
  payload = new Uint8Array(await new Response(stream).arrayBuffer());
119378
119415
  }
119416
+ options.signal?.throwIfAborted();
119379
119417
  const nbt = await NBTHelper.fromBuffer(payload, "big");
119418
+ options.signal?.throwIfAborted();
119380
119419
  const root = nbt.value;
119381
119420
  const level = root.Level?.type === "compound" ? root.Level.value : root;
119382
119421
  const dataVersion = root.DataVersion?.type === "int" ? root.DataVersion.value : void 0;
@@ -119389,6 +119428,9 @@ gl_FragDepth=readDepth(vUv);
119389
119428
  if ((chunk.x % 32 + 32) % 32 !== location.x || (chunk.z % 32 + 32) % 32 !== location.z) {
119390
119429
  throw new MineRenderError("Anvil chunk coordinates do not match its region location");
119391
119430
  }
119431
+ if (expected && (chunk.x !== expected.x || chunk.z !== expected.z)) {
119432
+ throw new MineRenderError(`Anvil chunk coordinates do not match external file c.${expected.x}.${expected.z}.mcc`);
119433
+ }
119392
119434
  for (const section of this.compounds(level.sections ?? level.Sections, "sections")) {
119393
119435
  const y5 = this.integer(section.Y, "section Y");
119394
119436
  if (section.Blocks || section.Data || section.Add) {
@@ -119523,6 +119565,7 @@ gl_FragDepth=readDepth(vUv);
119523
119565
  this.cachedBytes = 0;
119524
119566
  this.maxCachedRegions = options.maxCachedRegions ?? 4;
119525
119567
  this.maxCachedBytes = options.maxCachedBytes ?? 64 * 1024 * 1024;
119568
+ this.readExternalChunk = options.readExternalChunk;
119526
119569
  for (const [name2, value] of Object.entries({ maxCachedRegions: this.maxCachedRegions, maxCachedBytes: this.maxCachedBytes })) {
119527
119570
  if (!Number.isSafeInteger(value) || value < 0) throw new RangeError(`${name2} must be a nonnegative safe integer`);
119528
119571
  }
@@ -119536,7 +119579,11 @@ gl_FragDepth=readDepth(vUv);
119536
119579
  const data = await this.getRegion(regionX, regionZ, signal);
119537
119580
  signal?.throwIfAborted();
119538
119581
  if (!data) return void 0;
119539
- const chunk = await abortable2(AnvilParser.parseChunk(data, x4 - regionX * 32, z4 - regionZ * 32), signal);
119582
+ const chunk = await AnvilParser.parseChunk(data, x4 - regionX * 32, z4 - regionZ * 32, {
119583
+ region: { x: regionX, z: regionZ },
119584
+ readExternalChunk: this.readExternalChunk,
119585
+ signal
119586
+ });
119540
119587
  signal?.throwIfAborted();
119541
119588
  if (chunk && (chunk.x !== x4 || chunk.z !== z4)) {
119542
119589
  throw new MineRenderError(`Anvil chunk coordinates ${chunk.x},${chunk.z} do not match requested column ${x4},${z4}`);
@@ -119567,7 +119614,7 @@ gl_FragDepth=readDepth(vUv);
119567
119614
  settled: false,
119568
119615
  promise: Promise.resolve().then(() => {
119569
119616
  controller.signal.throwIfAborted();
119570
- return this.readRegion(x4, z4, controller.signal);
119617
+ return abortable2(this.readRegion(x4, z4, controller.signal), controller.signal);
119571
119618
  }).then((data) => {
119572
119619
  controller.signal.throwIfAborted();
119573
119620
  let bytes = data instanceof Uint8Array ? data : data === void 0 ? void 0 : new Uint8Array(data);