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.
@@ -1373,8 +1373,9 @@ declare class BlockStateResolver {
1373
1373
  static select(blockState: BlockState, state: BlockStateProperties, choose?: (variants: BlockStateVariant | BlockStateVariant[]) => BlockStateVariant): BlockStateVariant[];
1374
1374
  /** Returns matching model groups before choosing weighted alternatives. */
1375
1375
  static matching(blockState: BlockState, state: BlockStateProperties): (BlockStateVariant | BlockStateVariant[])[];
1376
- /** Selects a random alternative using positive integer weights, each defaulting to 1. */
1377
- static choose(variants: BlockStateVariant | BlockStateVariant[]): BlockStateVariant;
1376
+ /** Selects by positive integer weights (default 1); world block coordinates make the choice repeatable. */
1377
+ static choose(variants: BlockStateVariant | BlockStateVariant[], position?: Readonly<TripleArray>): BlockStateVariant;
1378
+ private static positionSample;
1378
1379
  /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
1379
1380
  static rotation(variant: BlockStateVariant): Euler;
1380
1381
  }
@@ -1944,6 +1945,7 @@ declare class BlockObject extends SceneObject {
1944
1945
  readonly isBlockObject: true;
1945
1946
  static readonly DEFAULT_OPTIONS: BlockObjectOptions;
1946
1947
  readonly options: BlockObjectOptions;
1948
+ private readonly variantPosition?;
1947
1949
  private _previousState;
1948
1950
  private _state;
1949
1951
  private _variant;
@@ -2017,6 +2019,8 @@ interface BlockObjectOptions extends ModelObjectOptions {
2017
2019
  applyDefaultState: boolean;
2018
2020
  /** Properties applied before model creation, overriding defaults when applyDefaultState is enabled. */
2019
2021
  initialState?: BlockStateProperties;
2022
+ /** Absolute block coordinates for repeatable variants, copied at construction. Omit for random previews. */
2023
+ variantPosition?: TripleArray;
2020
2024
  }
2021
2025
  declare function isBlockObject(obj: any): obj is BlockObject;
2022
2026
 
@@ -3298,7 +3302,7 @@ declare class SectionModels {
3298
3302
  private readonly templates;
3299
3303
  constructor(maxAtlasSize?: number);
3300
3304
  /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
3301
- get(blockState: BlockState, properties?: BlockStateProperties): Promise<SectionMeshTemplate[] | undefined>;
3305
+ get(blockState: BlockState, properties?: BlockStateProperties, position?: Readonly<TripleArray>): Promise<SectionMeshTemplate[] | undefined>;
3302
3306
  private prepare;
3303
3307
  /** Disposes prepared geometry and clears this world's template caches. */
3304
3308
  clear(): void;
@@ -1373,8 +1373,9 @@ declare class BlockStateResolver {
1373
1373
  static select(blockState: BlockState, state: BlockStateProperties, choose?: (variants: BlockStateVariant | BlockStateVariant[]) => BlockStateVariant): BlockStateVariant[];
1374
1374
  /** Returns matching model groups before choosing weighted alternatives. */
1375
1375
  static matching(blockState: BlockState, state: BlockStateProperties): (BlockStateVariant | BlockStateVariant[])[];
1376
- /** Selects a random alternative using positive integer weights, each defaulting to 1. */
1377
- static choose(variants: BlockStateVariant | BlockStateVariant[]): BlockStateVariant;
1376
+ /** Selects by positive integer weights (default 1); world block coordinates make the choice repeatable. */
1377
+ static choose(variants: BlockStateVariant | BlockStateVariant[], position?: Readonly<TripleArray>): BlockStateVariant;
1378
+ private static positionSample;
1378
1379
  /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
1379
1380
  static rotation(variant: BlockStateVariant): Euler;
1380
1381
  }
@@ -1944,6 +1945,7 @@ declare class BlockObject extends SceneObject {
1944
1945
  readonly isBlockObject: true;
1945
1946
  static readonly DEFAULT_OPTIONS: BlockObjectOptions;
1946
1947
  readonly options: BlockObjectOptions;
1948
+ private readonly variantPosition?;
1947
1949
  private _previousState;
1948
1950
  private _state;
1949
1951
  private _variant;
@@ -2017,6 +2019,8 @@ interface BlockObjectOptions extends ModelObjectOptions {
2017
2019
  applyDefaultState: boolean;
2018
2020
  /** Properties applied before model creation, overriding defaults when applyDefaultState is enabled. */
2019
2021
  initialState?: BlockStateProperties;
2022
+ /** Absolute block coordinates for repeatable variants, copied at construction. Omit for random previews. */
2023
+ variantPosition?: TripleArray;
2020
2024
  }
2021
2025
  declare function isBlockObject(obj: any): obj is BlockObject;
2022
2026
 
@@ -3298,7 +3302,7 @@ declare class SectionModels {
3298
3302
  private readonly templates;
3299
3303
  constructor(maxAtlasSize?: number);
3300
3304
  /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
3301
- get(blockState: BlockState, properties?: BlockStateProperties): Promise<SectionMeshTemplate[] | undefined>;
3305
+ get(blockState: BlockState, properties?: BlockStateProperties, position?: Readonly<TripleArray>): Promise<SectionMeshTemplate[] | undefined>;
3302
3306
  private prepare;
3303
3307
  /** Disposes prepared geometry and clears this world's template caches. */
3304
3308
  clear(): void;
@@ -23363,7 +23363,7 @@ function matchesCondition(condition, state) {
23363
23363
  return typeof value === "string" && state[key] !== void 0 && value.split("|").includes(`${state[key]}`);
23364
23364
  });
23365
23365
  }
23366
- var BlockStateResolver = class {
23366
+ var BlockStateResolver = class _BlockStateResolver {
23367
23367
  /** Loads vanilla property defaults, falling back to preview values inferred from the blockstate file. */
23368
23368
  static async defaults(blockState3) {
23369
23369
  const defaults = blockState3.key ? await BlockStates.getDefaultState(blockState3.key) : void 0;
@@ -23386,7 +23386,7 @@ var BlockStateResolver = class {
23386
23386
  }
23387
23387
  /** Selects matching models. Supply `choose` to control selection within each alternatives array. */
23388
23388
  static select(blockState3, state, choose = this.choose) {
23389
- return this.matching(blockState3, state).map(choose);
23389
+ return this.matching(blockState3, state).map((variants) => choose(variants));
23390
23390
  }
23391
23391
  /** Returns matching model groups before choosing weighted alternatives. */
23392
23392
  static matching(blockState3, state) {
@@ -23412,8 +23412,8 @@ var BlockStateResolver = class {
23412
23412
  }
23413
23413
  return out;
23414
23414
  }
23415
- /** Selects a random alternative using positive integer weights, each defaulting to 1. */
23416
- static choose(variants) {
23415
+ /** Selects by positive integer weights (default 1); world block coordinates make the choice repeatable. */
23416
+ static choose(variants, position) {
23417
23417
  if (!Array.isArray(variants)) return variants;
23418
23418
  if (!variants.length) throw new MineRenderError("Blockstate variant arrays must not be empty");
23419
23419
  const total = variants.reduce((sum, variant) => {
@@ -23423,13 +23423,29 @@ var BlockStateResolver = class {
23423
23423
  }
23424
23424
  return sum + weight;
23425
23425
  }, 0);
23426
- let choice = Math.random() * total;
23426
+ let choice = position === void 0 ? Math.random() * total : _BlockStateResolver.positionSample(position, total);
23427
23427
  for (const variant of variants) {
23428
23428
  choice -= variant.weight ?? 1;
23429
23429
  if (choice < 0) return variant;
23430
23430
  }
23431
23431
  return variants[variants.length - 1];
23432
23432
  }
23433
+ static positionSample(position, bound) {
23434
+ if (bound > 2147483647) {
23435
+ throw new MineRenderError("Position-based blockstate variant total weight must not exceed 2147483647");
23436
+ }
23437
+ let mixed = BigInt(Math.imul(position[0], 3129871)) ^ BigInt(position[2]) * 116129781n ^ BigInt(position[1]);
23438
+ mixed = BigInt.asIntN(64, mixed * mixed * 42317861n + mixed * 11n) >> 16n;
23439
+ let seed = (mixed ^ 0x5deece66dn) & 0xffffffffffffn;
23440
+ let bits, value;
23441
+ do {
23442
+ seed = seed * 0x5deece66dn + 11n & 0xffffffffffffn;
23443
+ bits = Number(seed >> 17n);
23444
+ if ((bound & bound - 1) === 0) return Number(BigInt(bound) * BigInt(bits) >> 31n);
23445
+ value = bits % bound;
23446
+ } while ((bits - value + bound - 1 | 0) < 0);
23447
+ return value;
23448
+ }
23433
23449
  /** Converts blockstate rotations in degrees into the Euler rotation used by model rendering. */
23434
23450
  static rotation(variant) {
23435
23451
  const rotation = new import_three29.Euler();
@@ -23549,6 +23565,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
23549
23565
  this._entityPlacement = new import_three32.Matrix4();
23550
23566
  this._entityGeneration = 0;
23551
23567
  this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
23568
+ this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
23552
23569
  }
23553
23570
  async init() {
23554
23571
  if (this.options.applyDefaultState) {
@@ -23785,7 +23802,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
23785
23802
  return !!(await Models.getMerged(modelKey))?.elements?.length;
23786
23803
  }
23787
23804
  getSingleVariant(variants) {
23788
- return BlockStateResolver.choose(variants);
23805
+ return BlockStateResolver.choose(variants, this.variantPosition);
23789
23806
  }
23790
23807
  // @deprecated
23791
23808
  async createAVariant(variants, instanceInfo) {
@@ -29678,13 +29695,14 @@ var SectionModels = class {
29678
29695
  if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
29679
29696
  }
29680
29697
  /** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
29681
- async get(blockState3, properties = {}) {
29698
+ async get(blockState3, properties = {}, position) {
29699
+ const variantPosition = position ? [...position] : void 0;
29682
29700
  let states = this.states.get(blockState3);
29683
29701
  if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
29684
29702
  const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
29685
29703
  const prepared = await cached(states, key, () => this.prepare(blockState3, properties));
29686
29704
  if (!prepared) return void 0;
29687
- return prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group)));
29705
+ return prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, variantPosition)));
29688
29706
  }
29689
29707
  async prepare(blockState3, properties) {
29690
29708
  const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
@@ -30473,7 +30491,8 @@ var Chunk = class _Chunk {
30473
30491
  this.data.set(index, void 0);
30474
30492
  continue;
30475
30493
  }
30476
- const templates = perBlock ? void 0 : await this.sectionModels.get(blockState3, stored.properties);
30494
+ const variantPosition = worldPos.toArray();
30495
+ const templates = perBlock ? void 0 : await this.sectionModels.get(blockState3, stored.properties, variantPosition);
30477
30496
  if (templates) {
30478
30497
  this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
30479
30498
  this.meshDirty = true;
@@ -30482,7 +30501,8 @@ var Chunk = class _Chunk {
30482
30501
  mergeMeshes: true,
30483
30502
  instanceMeshes: true,
30484
30503
  maxInstanceCount: 2e3,
30485
- initialState: stored.properties
30504
+ initialState: stored.properties,
30505
+ variantPosition
30486
30506
  });
30487
30507
  object3.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
30488
30508
  }