minerender 2.1.0-alpha.90 → 2.1.0-alpha.91

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.
@@ -28923,13 +28923,131 @@ var ChunkData = class _ChunkData {
28923
28923
  }
28924
28924
  };
28925
28925
 
28926
+ // src/world/_compression/Lz4.ts
28927
+ init_MineRenderError();
28928
+ function decodeAnvilLz4(data) {
28929
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
28930
+ const blocks = [];
28931
+ let cursor = 0, totalSize = 0;
28932
+ while (true) {
28933
+ if (cursor + 21 > data.length) throw invalid("truncated block header or missing terminator");
28934
+ if (view.getUint32(cursor) !== 1280980034 || view.getUint32(cursor + 4) !== 1819239275) {
28935
+ throw invalid("invalid block signature");
28936
+ }
28937
+ const token = data[cursor + 8];
28938
+ const method = token & 240;
28939
+ const size = view.getInt32(cursor + 9, true);
28940
+ const decodedSize = view.getInt32(cursor + 13, true);
28941
+ const checksum = view.getUint32(cursor + 17, true);
28942
+ cursor += 21;
28943
+ if (method !== 16 && method !== 32) throw invalid("unsupported block method");
28944
+ if (size < 0 || decodedSize < 0 || decodedSize > 2 ** (10 + (token & 15)) || size === 0 !== (decodedSize === 0) || method === 16 && size !== decodedSize) {
28945
+ throw invalid("invalid block lengths");
28946
+ }
28947
+ if (size === 0) {
28948
+ if (checksum !== 0 || cursor !== data.length) throw invalid("invalid terminator or trailing bytes");
28949
+ break;
28950
+ }
28951
+ if (cursor + size > data.length || decodedSize > size * 255) throw invalid("invalid block lengths");
28952
+ blocks.push({ start: cursor, size, decodedSize, raw: method === 16, checksum });
28953
+ totalSize += decodedSize;
28954
+ cursor += size;
28955
+ }
28956
+ const output = new Uint8Array(totalSize);
28957
+ let offset = 0;
28958
+ for (const block of blocks) {
28959
+ const source = data.subarray(block.start, block.start + block.size);
28960
+ const target = output.subarray(offset, offset + block.decodedSize);
28961
+ if (block.raw) target.set(source);
28962
+ else decodeBlock(source, target);
28963
+ if (checksum32(target) !== block.checksum) throw invalid("block checksum mismatch");
28964
+ offset += block.decodedSize;
28965
+ }
28966
+ return output;
28967
+ }
28968
+ function decodeBlock(source, target) {
28969
+ let input = 0, output = 0, matched = false;
28970
+ const length = (nibble) => {
28971
+ let value = nibble;
28972
+ if (value === 15) {
28973
+ let extension;
28974
+ do {
28975
+ if (input === source.length) throw invalid("truncated sequence length");
28976
+ extension = source[input++];
28977
+ value += extension;
28978
+ } while (extension === 255);
28979
+ }
28980
+ return value;
28981
+ };
28982
+ while (input < source.length) {
28983
+ const token = source[input++];
28984
+ const literals = length(token >>> 4);
28985
+ if (input + literals > source.length || output + literals > target.length) {
28986
+ throw invalid("literal sequence exceeds block bounds");
28987
+ }
28988
+ target.set(source.subarray(input, input + literals), output);
28989
+ input += literals;
28990
+ output += literals;
28991
+ if (input === source.length) {
28992
+ if (output !== target.length || matched && literals < 5) throw invalid("invalid final literal sequence");
28993
+ return;
28994
+ }
28995
+ if (input + 2 > source.length) throw invalid("truncated match offset");
28996
+ const distance = source[input] | source[input + 1] << 8;
28997
+ input += 2;
28998
+ if (distance === 0 || distance > output) throw invalid("match offset exceeds block history");
28999
+ const count = length(token & 15) + 4;
29000
+ if (output > target.length - 12 || output + count > target.length - 5) {
29001
+ throw invalid("match exceeds block bounds");
29002
+ }
29003
+ for (let end = output + count; output < end; output++) target[output] = target[output - distance];
29004
+ matched = true;
29005
+ }
29006
+ throw invalid("missing final literal sequence");
29007
+ }
29008
+ function checksum32(data) {
29009
+ const prime1 = 2654435761, prime2 = 2246822519, prime3 = 3266489917, prime4 = 668265263, prime5 = 374761393;
29010
+ const seed = 2538058380;
29011
+ const rotate = (value, bits) => value << bits | value >>> 32 - bits;
29012
+ const round = (value, word) => Math.imul(rotate(value + Math.imul(word, prime2), 13), prime1);
29013
+ const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
29014
+ let cursor = 0, hash;
29015
+ if (data.length >= 16) {
29016
+ let a = seed + prime1 + prime2, b = seed + prime2, c = seed, d = seed - prime1;
29017
+ while (cursor + 16 <= data.length) {
29018
+ a = round(a, view.getUint32(cursor, true));
29019
+ b = round(b, view.getUint32(cursor + 4, true));
29020
+ c = round(c, view.getUint32(cursor + 8, true));
29021
+ d = round(d, view.getUint32(cursor + 12, true));
29022
+ cursor += 16;
29023
+ }
29024
+ hash = rotate(a, 1) + rotate(b, 7) + rotate(c, 12) + rotate(d, 18);
29025
+ } else {
29026
+ hash = seed + prime5;
29027
+ }
29028
+ hash += data.length;
29029
+ while (cursor + 4 <= data.length) {
29030
+ hash = Math.imul(rotate(hash + Math.imul(view.getUint32(cursor, true), prime3), 17), prime4);
29031
+ cursor += 4;
29032
+ }
29033
+ while (cursor < data.length) {
29034
+ hash = Math.imul(rotate(hash + Math.imul(data[cursor++], prime5), 11), prime1);
29035
+ }
29036
+ hash = Math.imul(hash ^ hash >>> 15, prime2);
29037
+ hash = Math.imul(hash ^ hash >>> 13, prime3);
29038
+ return (hash ^ hash >>> 16) & 268435455;
29039
+ }
29040
+ function invalid(detail) {
29041
+ return new MineRenderError(`Invalid Anvil LZ4 stream: ${detail}`);
29042
+ }
29043
+
28926
29044
  // src/world/AnvilParser.ts
28927
29045
  var AnvilParser = class {
28928
29046
  /** Lists occupied chunk positions within the region, using local coordinates from 0 to 31. */
28929
29047
  static getChunkList(data) {
28930
29048
  return this.locations(this.bytes(data)).map(({ x, z }) => ({ x, z }));
28931
29049
  }
28932
- /** Decodes all stored chunks. Gzip, zlib, and uncompressed payloads are supported. */
29050
+ /** Decodes all stored chunks. Gzip, zlib, LZ4, and uncompressed payloads are supported. */
28933
29051
  static async parse(data) {
28934
29052
  const bytes = this.bytes(data);
28935
29053
  const chunks = [];
@@ -28977,11 +29095,13 @@ var AnvilParser = class {
28977
29095
  static async readChunk(data, location) {
28978
29096
  const compression = data[location.offset + 4];
28979
29097
  if (compression & 128) throw new MineRenderError("External Anvil .mcc chunks are not supported");
28980
- if (compression !== 1 && compression !== 2 && compression !== 3) {
28981
- throw new MineRenderError(`Unsupported Anvil compression ${compression}${compression === 4 ? " (LZ4)" : ""}`);
29098
+ if (compression !== 1 && compression !== 2 && compression !== 3 && compression !== 4) {
29099
+ throw new MineRenderError(`Unsupported Anvil compression ${compression}`);
28982
29100
  }
28983
29101
  let payload = data.subarray(location.offset + 5, location.offset + 4 + location.length);
28984
- if (compression !== 3) {
29102
+ if (compression === 4) {
29103
+ payload = decodeAnvilLz4(payload);
29104
+ } else if (compression !== 3) {
28985
29105
  const stream = new Blob([payload]).stream().pipeThrough(new DecompressionStream(compression === 1 ? "gzip" : "deflate"));
28986
29106
  payload = new Uint8Array(await new Response(stream).arrayBuffer());
28987
29107
  }