minerender 2.1.0-alpha.88 → 2.1.0-alpha.89

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.
@@ -23192,46 +23192,46 @@ function matchesCondition(condition, state) {
23192
23192
  }
23193
23193
  var BlockStateResolver = class {
23194
23194
  /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
23195
- static async defaults(blockState) {
23196
- const defaults = blockState.key ? await BlockStates.getDefaultState(blockState.key) : void 0;
23195
+ static async defaults(blockState2) {
23196
+ const defaults = blockState2.key ? await BlockStates.getDefaultState(blockState2.key) : void 0;
23197
23197
  const state = {};
23198
23198
  if (defaults && Object.keys(defaults).length > 0) {
23199
23199
  for (const key in defaults) state[key] = defaults[key].default;
23200
- } else if (blockState.variants) {
23201
- const variant = Object.keys(blockState.variants)[0];
23200
+ } else if (blockState2.variants) {
23201
+ const variant = Object.keys(blockState2.variants)[0];
23202
23202
  if (variant) {
23203
23203
  for (const property of variant.split(",")) {
23204
23204
  const [key, value] = property.split("=");
23205
23205
  state[key] = value;
23206
23206
  }
23207
23207
  }
23208
- } else if (blockState.multipart) {
23209
- const condition = blockState.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
23208
+ } else if (blockState2.multipart) {
23209
+ const condition = blockState2.multipart.map((part) => part.when).find((when) => when !== void 0 && Object.values(when).every((value) => typeof value === "string"));
23210
23210
  for (const [key, value] of Object.entries(condition ?? {})) state[key] = value.split("|")[0];
23211
23211
  }
23212
23212
  return state;
23213
23213
  }
23214
23214
  /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
23215
- static select(blockState, state, choose = this.choose) {
23216
- return this.matching(blockState, state).map(choose);
23215
+ static select(blockState2, state, choose = this.choose) {
23216
+ return this.matching(blockState2, state).map(choose);
23217
23217
  }
23218
23218
  /** Returns matching model groups before choosing weighted alternatives. */
23219
- static matching(blockState, state) {
23219
+ static matching(blockState2, state) {
23220
23220
  const out = [];
23221
- if (blockState.variants) {
23222
- if (Object.keys(blockState.variants).length === 1 && "" in blockState.variants) {
23223
- out.push(blockState.variants[""]);
23221
+ if (blockState2.variants) {
23222
+ if (Object.keys(blockState2.variants).length === 1 && "" in blockState2.variants) {
23223
+ out.push(blockState2.variants[""]);
23224
23224
  } else {
23225
- for (const variantKey in blockState.variants) {
23225
+ for (const variantKey in blockState2.variants) {
23226
23226
  const matches = variantKey.split(",").every((property) => {
23227
23227
  const [key, value] = property.split("=");
23228
23228
  return `${state[key]}` === `${value}`;
23229
23229
  });
23230
- if (matches) out.push(blockState.variants[variantKey]);
23230
+ if (matches) out.push(blockState2.variants[variantKey]);
23231
23231
  }
23232
23232
  }
23233
- } else if (blockState.multipart) {
23234
- for (const part of blockState.multipart) {
23233
+ } else if (blockState2.multipart) {
23234
+ for (const part of blockState2.multipart) {
23235
23235
  if (part.apply && (!part.when || matchesCondition(part.when, state))) {
23236
23236
  out.push(part.apply);
23237
23237
  }
@@ -23359,9 +23359,9 @@ init_ModelCulling();
23359
23359
  init_FluidGeometry();
23360
23360
  init_Entities();
23361
23361
  var _BlockObject = class _BlockObject extends SceneObject {
23362
- constructor(blockState, options) {
23362
+ constructor(blockState2, options) {
23363
23363
  super(options);
23364
- this.blockState = blockState;
23364
+ this.blockState = blockState2;
23365
23365
  this.isBlockObject = true;
23366
23366
  this._previousState = {};
23367
23367
  this._state = {};
@@ -25540,6 +25540,157 @@ function compoundList(tags, name) {
25540
25540
  throw new MineRenderError(`Schematic ${name} must be a compound list`);
25541
25541
  }
25542
25542
 
25543
+ // src/model/multiblock/SpongeSchematicParser.ts
25544
+ init_MineRenderError();
25545
+ var SpongeSchematicParser = class {
25546
+ /**
25547
+ * Parses decoded NBT with a local block palette, omitting air blocks.
25548
+ * Applies Offset to block and entity positions; size remains the source dimensions.
25549
+ * Biomes and metadata are not imported, and DataVersion does not trigger migration.
25550
+ */
25551
+ static async parse(nbt) {
25552
+ const tags = nbt.value.Schematic === void 0 ? nbt.value : compound(nbt.value.Schematic, "Schematic");
25553
+ const version2 = integer2(tags.Version, "Version");
25554
+ if (version2 !== 2 && version2 !== 3) {
25555
+ throw new MineRenderError(`Unsupported Sponge schematic version ${version2}; expected 2 or 3`);
25556
+ }
25557
+ const dataVersion = integer2(tags.DataVersion, "DataVersion");
25558
+ const size = ["Width", "Height", "Length"].map((name) => {
25559
+ const tag = tags[name];
25560
+ if (tag?.type !== "short" || !Number.isInteger(tag.value) || tag.value < -32768 || tag.value > 65535 || tag.value === 0) {
25561
+ throw new MineRenderError(`Sponge schematic ${name} must be a positive unsigned short`);
25562
+ }
25563
+ return tag.value & 65535;
25564
+ });
25565
+ const offset = tags.Offset === void 0 ? [0, 0, 0] : intPosition(tags.Offset, "Offset");
25566
+ const blocks = [];
25567
+ const container = version2 === 2 ? tags : tags.Blocks === void 0 ? void 0 : compound(tags.Blocks, "Blocks");
25568
+ if (container) {
25569
+ const paletteTag = container.Palette;
25570
+ if (!paletteTag) throw new MineRenderError("Sponge schematic requires a local Palette; global block IDs are not supported");
25571
+ const palette = /* @__PURE__ */ new Map();
25572
+ const paletteMax = version2 === 2 && tags.PaletteMax !== void 0 ? integer2(tags.PaletteMax, "PaletteMax") : void 0;
25573
+ if (paletteMax !== void 0 && paletteMax <= 0) throw new MineRenderError("Sponge schematic PaletteMax must be positive");
25574
+ for (const [state, tag] of Object.entries(compound(paletteTag, "Palette"))) {
25575
+ const id = integer2(tag, "Palette index");
25576
+ if (id < 0 || palette.has(id) || paletteMax !== void 0 && id >= paletteMax) {
25577
+ throw new MineRenderError(`Invalid or duplicate Sponge schematic palette index ${id}`);
25578
+ }
25579
+ palette.set(id, blockState(state));
25580
+ }
25581
+ const [width, height, length] = size;
25582
+ const volume = width * height * length;
25583
+ const data = container[version2 === 2 ? "BlockData" : "Data"];
25584
+ if (data?.type !== "byteArray" || !Array.isArray(data.value) || data.value.length < volume) {
25585
+ throw new MineRenderError(`Sponge schematic block data must contain ${volume} varints`);
25586
+ }
25587
+ const blockEntities = /* @__PURE__ */ new Map();
25588
+ for (const entity of compoundList2(container, "BlockEntities")) {
25589
+ const pos = intPosition(entity.Pos, "BlockEntities Pos");
25590
+ if (pos.some((value2, axis) => value2 < 0 || value2 >= size[axis])) {
25591
+ throw new MineRenderError("Sponge schematic block entity position is outside its dimensions");
25592
+ }
25593
+ const index = pos[0] + pos[2] * width + pos[1] * width * length;
25594
+ if (blockEntities.has(index)) throw new MineRenderError(`Duplicate Sponge schematic block entity at index ${index}`);
25595
+ const value = entityData(entity, version2);
25596
+ for (const [axis, name] of ["x", "y", "z"].entries()) {
25597
+ value[name] = { type: "int", value: pos[axis] + offset[axis] };
25598
+ }
25599
+ blockEntities.set(index, { type: "compound", value });
25600
+ }
25601
+ let cursor = 0;
25602
+ for (let index = 0; index < volume; index++) {
25603
+ let id = 0;
25604
+ for (let shift = 0; ; shift += 7) {
25605
+ const byte = data.value[cursor++];
25606
+ if (!Number.isInteger(byte) || byte < -128 || byte > 255) {
25607
+ throw new MineRenderError(`Invalid or truncated Sponge schematic varint at index ${index}`);
25608
+ }
25609
+ const unsigned = byte & 255;
25610
+ if (shift === 28 && unsigned > 7) {
25611
+ throw new MineRenderError(`Sponge schematic varint exceeds a nonnegative int at index ${index}`);
25612
+ }
25613
+ id += (unsigned & 127) * 2 ** shift;
25614
+ if ((unsigned & 128) === 0) break;
25615
+ }
25616
+ const state = palette.get(id);
25617
+ if (!state) throw new MineRenderError(`Sponge schematic palette index ${id} does not exist`);
25618
+ if (["minecraft:air", "minecraft:cave_air", "minecraft:void_air"].includes(state.type)) continue;
25619
+ blocks.push({
25620
+ type: state.type,
25621
+ properties: { ...state.properties },
25622
+ position: [
25623
+ index % width + offset[0],
25624
+ Math.floor(index / (width * length)) + offset[1],
25625
+ Math.floor(index / width) % length + offset[2]
25626
+ ],
25627
+ nbt: blockEntities.get(index)
25628
+ });
25629
+ }
25630
+ if (cursor !== data.value.length) throw new MineRenderError("Sponge schematic block data has trailing bytes");
25631
+ }
25632
+ const entities = compoundList2(tags, "Entities").map((entity) => {
25633
+ const pos = entity.Pos;
25634
+ if (pos?.type !== "list" || pos.value.type !== "double" || pos.value.value.length !== 3 || !pos.value.value.every(Number.isFinite)) {
25635
+ throw new MineRenderError("Sponge schematic entity Pos must contain three doubles");
25636
+ }
25637
+ const position = pos.value.value.map((value2, axis) => value2 + offset[axis]);
25638
+ const value = entityData(entity, version2);
25639
+ value.Pos = { type: "list", value: { type: "double", value: [...position] } };
25640
+ return { position, nbt: { type: "compound", value } };
25641
+ });
25642
+ return { size, blocks, entities, dataVersion };
25643
+ }
25644
+ };
25645
+ function integer2(tag, name) {
25646
+ if (tag?.type !== "int" || !Number.isInteger(tag.value) || tag.value < -2147483648 || tag.value > 2147483647) {
25647
+ throw new MineRenderError(`Sponge schematic ${name} must be an int`);
25648
+ }
25649
+ return tag.value;
25650
+ }
25651
+ function compound(tag, name) {
25652
+ if (tag?.type !== "compound" || !tag.value || typeof tag.value !== "object" || Array.isArray(tag.value)) {
25653
+ throw new MineRenderError(`Sponge schematic ${name} must be a compound`);
25654
+ }
25655
+ return tag.value;
25656
+ }
25657
+ function intPosition(tag, name) {
25658
+ if (tag?.type !== "intArray" || !Array.isArray(tag.value) || tag.value.length !== 3 || !tag.value.every((value) => Number.isInteger(value) && value >= -2147483648 && value <= 2147483647)) {
25659
+ throw new MineRenderError(`Sponge schematic ${name} must contain three ints`);
25660
+ }
25661
+ return [...tag.value];
25662
+ }
25663
+ function compoundList2(tags, name) {
25664
+ const tag = tags[name];
25665
+ if (tag === void 0) return [];
25666
+ if (tag.type === "list" && Array.isArray(tag.value.value)) {
25667
+ if (tag.value.value.length === 0) return [];
25668
+ if (tag.value.type === "compound") return tag.value.value;
25669
+ }
25670
+ throw new MineRenderError(`Sponge schematic ${name} must be a compound list`);
25671
+ }
25672
+ function blockState(state) {
25673
+ const match = /^((?:[a-z0-9_.-]+:)?[a-z0-9_./-]+)(?:\[([^\[\]]*)\])?$/.exec(state);
25674
+ if (!match) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
25675
+ const properties = {};
25676
+ if (match[2]) {
25677
+ for (const entry of match[2].split(",")) {
25678
+ const pair = /^([a-z0-9_]+)=([^\s=,\[\]]+)$/.exec(entry);
25679
+ if (!pair || Object.prototype.hasOwnProperty.call(properties, pair[1])) throw new MineRenderError(`Invalid Sponge schematic block state ${state}`);
25680
+ Object.defineProperty(properties, pair[1], { value: pair[2], enumerable: true, writable: true, configurable: true });
25681
+ }
25682
+ }
25683
+ return { type: match[1].includes(":") ? match[1] : `minecraft:${match[1]}`, properties };
25684
+ }
25685
+ function entityData(entity, version2) {
25686
+ const id = entity.Id;
25687
+ if (id?.type !== "string" || !id.value) throw new MineRenderError("Sponge schematic entity Id must be a nonempty string");
25688
+ const { Id, Pos, ...extra } = entity;
25689
+ const value = version2 === 2 ? extra : entity.Data === void 0 ? {} : { ...compound(entity.Data, "entity Data") };
25690
+ value.id = { type: "string", value: id.value.includes(":") ? id.value : `minecraft:${id.value}` };
25691
+ return value;
25692
+ }
25693
+
25543
25694
  // src/model/multiblock/StructureParser.ts
25544
25695
  init_MineRenderError();
25545
25696
  var StructureParser = class {
@@ -26764,8 +26915,8 @@ var _MineRenderScene = class _MineRenderScene extends Scene4 {
26764
26915
  * Set `options.initialState` to choose block properties such as `facing` or `axis`.
26765
26916
  * Use the returned object's `setPosition` method to move all of its model parts.
26766
26917
  */
26767
- async addBlock(blockState, options, parent = this) {
26768
- return this.addSceneObject(blockState, () => new BlockObject(blockState, options), options, parent);
26918
+ async addBlock(blockState2, options, parent = this) {
26919
+ return this.addSceneObject(blockState2, () => new BlockObject(blockState2, options), options, parent);
26769
26920
  }
26770
26921
  /**
26771
26922
  * Loads a skin and adds an initialized player model.
@@ -28978,18 +29129,18 @@ var SectionModels = class {
28978
29129
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
28979
29130
  }
28980
29131
  /** Returns a cube template, or `undefined` when the block requires an individual render object. */
28981
- async get(blockState, properties = {}) {
28982
- if (!blockState.variants || blockState.multipart) return void 0;
28983
- let states = this.states.get(blockState);
28984
- if (!states) this.states.set(blockState, states = /* @__PURE__ */ new Map());
29132
+ async get(blockState2, properties = {}) {
29133
+ if (!blockState2.variants || blockState2.multipart) return void 0;
29134
+ let states = this.states.get(blockState2);
29135
+ if (!states) this.states.set(blockState2, states = /* @__PURE__ */ new Map());
28985
29136
  const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
28986
- const prepared = await cached(states, key, () => this.prepare(blockState, properties));
29137
+ const prepared = await cached(states, key, () => this.prepare(blockState2, properties));
28987
29138
  if (!prepared) return void 0;
28988
29139
  return prepared.templates.get(BlockStateResolver.choose(prepared.variants));
28989
29140
  }
28990
- async prepare(blockState, properties) {
28991
- const state = { ...await BlockStateResolver.defaults(blockState), ...properties };
28992
- const groups = BlockStateResolver.matching(blockState, state);
29141
+ async prepare(blockState2, properties) {
29142
+ const state = { ...await BlockStateResolver.defaults(blockState2), ...properties };
29143
+ const groups = BlockStateResolver.matching(blockState2, state);
28993
29144
  if (groups.length !== 1) return void 0;
28994
29145
  const variants = groups[0];
28995
29146
  const choices = Array.isArray(variants) ? variants : [variants];
@@ -29001,7 +29152,7 @@ var SectionModels = class {
29001
29152
  const atlas = await UVMapper.getAtlas(model);
29002
29153
  const rotation = BlockStateResolver.rotation(variant);
29003
29154
  if (!atlas || atlas.hasAnimation || !ModelCulling.isOpaqueFullCube(atlas) || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize || ModelCulling.toLocalMask(63, rotation) !== 63) return void 0;
29004
- const tints = await BlockTints.get(blockState.key, state, model);
29155
+ const tints = await BlockTints.get(blockState2.key, state, model);
29005
29156
  let models = this.models.get(model);
29006
29157
  if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
29007
29158
  const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
@@ -29707,10 +29858,10 @@ var Chunk = class _Chunk {
29707
29858
  if (resolutions.has(key)) continue;
29708
29859
  const stored = { type: block.type, properties: block.properties ? { ...block.properties } : void 0 };
29709
29860
  const resolved = (async () => {
29710
- const blockState = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
29711
- const perBlock = !blockState || !this.sectionModels || !!getFluidKind(blockState.key, stored.properties) || !!(blockState.key && BlockEntities.entry(await BlockEntities.getIndex(blockState.key.root), blockState.key.toNamespacedString()));
29712
- if (!perBlock) await this.sectionModels.get(blockState, stored.properties);
29713
- return { blockState, perBlock };
29861
+ const blockState2 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
29862
+ const perBlock = !blockState2 || !this.sectionModels || !!getFluidKind(blockState2.key, stored.properties) || !!(blockState2.key && BlockEntities.entry(await BlockEntities.getIndex(blockState2.key.root), blockState2.key.toNamespacedString()));
29863
+ if (!perBlock) await this.sectionModels.get(blockState2, stored.properties);
29864
+ return { blockState: blockState2, perBlock };
29714
29865
  })();
29715
29866
  resolutions.set(key, resolved);
29716
29867
  void resolved.catch(() => void 0);
@@ -29735,17 +29886,17 @@ var Chunk = class _Chunk {
29735
29886
  if (!readBlock) continue;
29736
29887
  const stored = readBlock();
29737
29888
  const key = ChunkData.paletteKey(stored);
29738
- const { blockState, perBlock } = await resolutions.get(key);
29739
- if (!blockState) {
29889
+ const { blockState: blockState2, perBlock } = await resolutions.get(key);
29890
+ if (!blockState2) {
29740
29891
  this.data.set(index, void 0);
29741
29892
  continue;
29742
29893
  }
29743
- const template = perBlock ? void 0 : await this.sectionModels.get(blockState, stored.properties);
29894
+ const template = perBlock ? void 0 : await this.sectionModels.get(blockState2, stored.properties);
29744
29895
  if (template) {
29745
29896
  this.sectionBlocks.set(index, { index, template, cullMask: 0 });
29746
29897
  this.meshDirty = true;
29747
29898
  } else {
29748
- object3 = await this.scene.addBlock(blockState, {
29899
+ object3 = await this.scene.addBlock(blockState2, {
29749
29900
  mergeMeshes: true,
29750
29901
  instanceMeshes: true,
29751
29902
  maxInstanceCount: 2e3,
@@ -30151,6 +30302,7 @@ export {
30151
30302
  SkinTextures,
30152
30303
  Skins,
30153
30304
  SpecialItems,
30305
+ SpongeSchematicParser,
30154
30306
  StructureParser,
30155
30307
  TextureAtlas,
30156
30308
  TextureLoader,