minerender 2.1.0-alpha.94 → 2.1.0-alpha.95

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.
@@ -23211,7 +23211,7 @@ function matchesCondition(condition, state) {
23211
23211
  return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
23212
23212
  });
23213
23213
  }
23214
- var BlockStateResolver = class {
23214
+ var BlockStateResolver = class _BlockStateResolver {
23215
23215
  /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
23216
23216
  static async defaults(blockState3) {
23217
23217
  const defaults = blockState3.key ? await BlockStates.getDefaultState(blockState3.key) : void 0;
@@ -23234,7 +23234,7 @@ var BlockStateResolver = class {
23234
23234
  }
23235
23235
  /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
23236
23236
  static select(blockState3, state, choose = this.choose) {
23237
- return this.matching(blockState3, state).map(choose);
23237
+ return this.matching(blockState3, state).map((variants) => choose(variants));
23238
23238
  }
23239
23239
  /** Returns matching model groups before choosing weighted alternatives. */
23240
23240
  static matching(blockState3, state) {
@@ -23260,8 +23260,8 @@ var BlockStateResolver = class {
23260
23260
  }
23261
23261
  return out;
23262
23262
  }
23263
- /** Selects a random alternative using positive integer weights, each defaulting to 1. */
23264
- static choose(variants) {
23263
+ /** Selects by positive integer weights (default 1); world block coordinates make the choice repeatable. */
23264
+ static choose(variants, position) {
23265
23265
  if (!Array.isArray(variants)) return variants;
23266
23266
  if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
23267
23267
  const total = variants.reduce((sum, variant) => {
@@ -23271,13 +23271,29 @@ var BlockStateResolver = class {
23271
23271
  }
23272
23272
  return sum + weight;
23273
23273
  }, 0);
23274
- let choice = Math.random() * total;
23274
+ let choice = position === void 0 ? Math.random() * total : _BlockStateResolver.positionSample(position, total);
23275
23275
  for (const variant of variants) {
23276
23276
  choice -= variant.weight ?? 1;
23277
23277
  if (choice < 0) return variant;
23278
23278
  }
23279
23279
  return variants[variants.length - 1];
23280
23280
  }
23281
+ static positionSample(position, bound) {
23282
+ if (bound > 2147483647) {
23283
+ throw new MineRenderError("Position-based blockstate variant total weight must not exceed 2147483647");
23284
+ }
23285
+ let mixed = BigInt(Math.imul(position[0], 3129871)) ^ BigInt(position[2]) * 116129781n ^ BigInt(position[1]);
23286
+ mixed = BigInt.asIntN(64, mixed * mixed * 42317861n + mixed * 11n) >> 16n;
23287
+ let seed = (mixed ^ 0x5deece66dn) & 0xffffffffffffn;
23288
+ let bits, value;
23289
+ do {
23290
+ seed = seed * 0x5deece66dn + 11n & 0xffffffffffffn;
23291
+ bits = Number(seed >> 17n);
23292
+ if ((bound & bound - 1) === 0) return Number(BigInt(bound) * BigInt(bits) >> 31n);
23293
+ value = bits % bound;
23294
+ } while ((bits - value + bound - 1 | 0) < 0);
23295
+ return value;
23296
+ }
23281
23297
  /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
23282
23298
  static rotation(variant) {
23283
23299
  const rotation = new Euler9();
@@ -23397,6 +23413,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
23397
23413
  this._entityPlacement = new Matrix411();
23398
23414
  this._entityGeneration = 0;
23399
23415
  this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
23416
+ this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
23400
23417
  }
23401
23418
  async init() {
23402
23419
  if (this.options.applyDefaultState) {
@@ -23633,7 +23650,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
23633
23650
  return !!(await Models.getMerged(modelKey))?.elements?.length;
23634
23651
  }
23635
23652
  getSingleVariant(variants) {
23636
- return BlockStateResolver.choose(variants);
23653
+ return BlockStateResolver.choose(variants, this.variantPosition);
23637
23654
  }
23638
23655
  // @deprecated
23639
23656
  async createAVariant(variants, instanceInfo) {
@@ -29534,13 +29551,14 @@ var SectionModels = class {
29534
29551
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
29535
29552
  }
29536
29553
  /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
29537
- async get(blockState3, properties = {}) {
29554
+ async get(blockState3, properties = {}, position) {
29555
+ const variantPosition = position ? [...position] : void 0;
29538
29556
  let states = this.states.get(blockState3);
29539
29557
  if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
29540
29558
  const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
29541
29559
  const prepared = await cached(states, key, () => this.prepare(blockState3, properties));
29542
29560
  if (!prepared) return void 0;
29543
- return prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group)));
29561
+ return prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, variantPosition)));
29544
29562
  }
29545
29563
  async prepare(blockState3, properties) {
29546
29564
  const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
@@ -30329,7 +30347,8 @@ var Chunk = class _Chunk {
30329
30347
  this.data.set(index, void 0);
30330
30348
  continue;
30331
30349
  }
30332
- const templates = perBlock ? void 0 : await this.sectionModels.get(blockState3, stored.properties);
30350
+ const variantPosition = worldPos.toArray();
30351
+ const templates = perBlock ? void 0 : await this.sectionModels.get(blockState3, stored.properties, variantPosition);
30333
30352
  if (templates) {
30334
30353
  this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
30335
30354
  this.meshDirty = true;
@@ -30338,7 +30357,8 @@ var Chunk = class _Chunk {
30338
30357
  mergeMeshes: true,
30339
30358
  instanceMeshes: true,
30340
30359
  maxInstanceCount: 2e3,
30341
- initialState: stored.properties
30360
+ initialState: stored.properties,
30361
+ variantPosition
30342
30362
  });
30343
30363
  object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
30344
30364
  }