minerender 2.1.0-alpha.114 → 2.1.0-alpha.116
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/browser/index.d.mts +199 -13
- package/dist/browser/index.d.ts +199 -13
- package/dist/browser/index.js +939 -231
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +885 -177
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +6 -3
- package/dist/browser/section.worker.js.map +1 -1
- package/dist/browser/section.worker.mjs +6 -3
- package/dist/browser/section.worker.mjs.map +1 -1
- package/dist/bundle.js +903 -139
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +199 -13
- package/dist/node/index.d.ts +199 -13
- package/dist/node/index.js +944 -231
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +887 -177
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/browser/index.mjs
CHANGED
|
@@ -279,7 +279,8 @@ var init_Caching = __esm({
|
|
|
279
279
|
this.fontCache,
|
|
280
280
|
this.bannerPatternCache,
|
|
281
281
|
this.mineRenderDataCache,
|
|
282
|
-
this.usernameUuidCache
|
|
282
|
+
this.usernameUuidCache,
|
|
283
|
+
this.biomeCache
|
|
283
284
|
];
|
|
284
285
|
}
|
|
285
286
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
@@ -330,6 +331,7 @@ var init_Caching = __esm({
|
|
|
330
331
|
_Caching.bannerPatternCache = _Caching.createAssetCache();
|
|
331
332
|
_Caching.mineRenderDataCache = _Caching.createAssetCache();
|
|
332
333
|
_Caching.usernameUuidCache = Caches.builder().expireAfterWrite(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
334
|
+
_Caching.biomeCache = _Caching.createAssetCache();
|
|
333
335
|
Caching = _Caching;
|
|
334
336
|
}
|
|
335
337
|
});
|
|
@@ -1676,7 +1678,7 @@ ${key}` : key, async () => {
|
|
|
1676
1678
|
case "blockStates":
|
|
1677
1679
|
return Object.values(value).every((property) => object(property) && "default" in property && Array.isArray(property.values));
|
|
1678
1680
|
case "blockTints":
|
|
1679
|
-
return ["constant", "grass", "stem", "redstone"].includes(value.source) && (value.source !== "constant" || Number.isInteger(value.color));
|
|
1681
|
+
return ["constant", "grass", "stem", "redstone"].includes(value.source) && (value.source !== "constant" || Number.isInteger(value.color)) && (value.biome === void 0 || ["grass", "foliage", "dry_foliage", "water"].includes(value.biome));
|
|
1680
1682
|
case "fluids":
|
|
1681
1683
|
return ["water", "lava"].includes(value.kind) && typeof value.renderModel === "boolean" && (value.levelProperty === void 0 || typeof value.levelProperty === "string");
|
|
1682
1684
|
case "dyes":
|
|
@@ -1820,15 +1822,19 @@ var init_Colormaps = __esm({
|
|
|
1820
1822
|
Colormaps = class {
|
|
1821
1823
|
/** Samples the selected resource pack's grass colormap using Minecraft's climate coordinates. */
|
|
1822
1824
|
static async grassColor(origin, temperature = 0.5, downfall = 1) {
|
|
1823
|
-
|
|
1825
|
+
return this.getColor("grass", origin, temperature, downfall);
|
|
1826
|
+
}
|
|
1827
|
+
/** Samples a resource-pack colormap at the supplied climate coordinates. */
|
|
1828
|
+
static async getColor(kind, origin, temperature = 0.5, downfall = 1) {
|
|
1829
|
+
const key = AssetKey.parse("textures", `minecraft:colormap/${kind}`, origin);
|
|
1824
1830
|
const temp = Math.fround(temperature);
|
|
1825
1831
|
const rain = Math.fround(downfall) * temp;
|
|
1826
1832
|
const x = Math.floor((1 - temp) * 255), y = Math.floor((1 - rain) * 255);
|
|
1827
1833
|
return await Caching.blockTintCache.get(`${key.serialize()}|${x},${y}`, async () => {
|
|
1828
1834
|
const image = await ModelTextures.get(key);
|
|
1829
|
-
if (!image) throw new MineRenderError(`Missing
|
|
1835
|
+
if (!image) throw new MineRenderError(`Missing ${kind} colormap: ${key.toNamespacedString()}`);
|
|
1830
1836
|
if (image.width !== 256 || image.height !== 256) {
|
|
1831
|
-
throw new MineRenderError(
|
|
1837
|
+
throw new MineRenderError(`${kind} colormaps must be 256 \xD7 256 pixels`);
|
|
1832
1838
|
}
|
|
1833
1839
|
const [red, green, blue] = image.data.getImageData(x, y, 1, 1).data;
|
|
1834
1840
|
return red << 16 | green << 8 | blue;
|
|
@@ -7699,6 +7705,116 @@ init_AssetLoader();
|
|
|
7699
7705
|
init_Assets();
|
|
7700
7706
|
init_BannerPatterns();
|
|
7701
7707
|
|
|
7708
|
+
// src/assets/Biomes.ts
|
|
7709
|
+
init_AssetKey();
|
|
7710
|
+
init_AssetLoader();
|
|
7711
|
+
init_AssetParsers();
|
|
7712
|
+
init_Caching();
|
|
7713
|
+
init_MineRenderError();
|
|
7714
|
+
init_Colormaps();
|
|
7715
|
+
|
|
7716
|
+
// src/assets/_biomes/SwampGrassColor.ts
|
|
7717
|
+
var permutation;
|
|
7718
|
+
var gradients = [[1, 1], [-1, 1], [1, -1], [-1, -1], [1, 0], [-1, 0], [1, 0], [-1, 0], [0, 1], [0, -1], [0, 1], [0, -1]];
|
|
7719
|
+
var skew = (Math.sqrt(3) - 1) / 2;
|
|
7720
|
+
var unskew = (3 - Math.sqrt(3)) / 6;
|
|
7721
|
+
function createPermutation() {
|
|
7722
|
+
const multiplier = 0x5deece66dn, mask = (1n << 48n) - 1n;
|
|
7723
|
+
let seed = 2345n ^ multiplier;
|
|
7724
|
+
const next = (bits) => {
|
|
7725
|
+
seed = seed * multiplier + 11n & mask;
|
|
7726
|
+
return Number(seed >> BigInt(48 - bits));
|
|
7727
|
+
};
|
|
7728
|
+
for (let i = 0; i < 3; i++) {
|
|
7729
|
+
next(26);
|
|
7730
|
+
next(27);
|
|
7731
|
+
}
|
|
7732
|
+
const values = Uint8Array.from({ length: 256 }, (_, i) => i);
|
|
7733
|
+
for (let i = 0; i < 256; i++) {
|
|
7734
|
+
const bound = 256 - i;
|
|
7735
|
+
let offset;
|
|
7736
|
+
if ((bound & bound - 1) === 0) offset = Math.floor(bound * next(31) / 2147483648);
|
|
7737
|
+
else {
|
|
7738
|
+
let bits;
|
|
7739
|
+
do {
|
|
7740
|
+
bits = next(31);
|
|
7741
|
+
offset = bits % bound;
|
|
7742
|
+
} while (bits - offset + bound - 1 > 2147483647);
|
|
7743
|
+
}
|
|
7744
|
+
const other = i + offset;
|
|
7745
|
+
[values[i], values[other]] = [values[other], values[i]];
|
|
7746
|
+
}
|
|
7747
|
+
return values;
|
|
7748
|
+
}
|
|
7749
|
+
function swampGrassColor(x, z) {
|
|
7750
|
+
const p10 = permutation ?? (permutation = createPermutation());
|
|
7751
|
+
x *= 0.0225;
|
|
7752
|
+
z *= 0.0225;
|
|
7753
|
+
const s = (x + z) * skew;
|
|
7754
|
+
const i = Math.floor(x + s), j = Math.floor(z + s);
|
|
7755
|
+
const t = (i + j) * unskew;
|
|
7756
|
+
const dx = x - (i - t), dz = z - (j - t);
|
|
7757
|
+
const stepX = dx > dz ? 1 : 0, stepZ = 1 - stepX;
|
|
7758
|
+
const corner = (gx, gz, a, b) => {
|
|
7759
|
+
let falloff = 0.5 - a * a - b * b;
|
|
7760
|
+
if (falloff < 0) return 0;
|
|
7761
|
+
const gradient = gradients[p10[gx + p10[gz & 255] & 255] % 12];
|
|
7762
|
+
falloff *= falloff;
|
|
7763
|
+
return falloff * falloff * (gradient[0] * a + gradient[1] * b);
|
|
7764
|
+
};
|
|
7765
|
+
const noise = 70 * (corner(i, j, dx, dz) + corner(i + stepX, j + stepZ, dx - stepX + unskew, dz - stepZ + unskew) + corner(i + 1, j + 1, dx - 1 + 2 * unskew, dz - 1 + 2 * unskew));
|
|
7766
|
+
return noise < -0.1 ? 5011004 : 6975545;
|
|
7767
|
+
}
|
|
7768
|
+
|
|
7769
|
+
// src/assets/Biomes.ts
|
|
7770
|
+
var Biomes = class {
|
|
7771
|
+
/** Loads a biome registry entry, or returns `undefined` when no source provides it. */
|
|
7772
|
+
static async get(id, origin) {
|
|
7773
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(id)) throw new MineRenderError(`Invalid biome identifier: ${id}`);
|
|
7774
|
+
const [namespace, path] = id.includes(":") ? id.split(":") : ["minecraft", id];
|
|
7775
|
+
const key = new AssetKey(namespace, path, "worldgen", "biome", "data", ".json", origin?.root);
|
|
7776
|
+
return Caching.biomeCache.get(key.serialize(), async () => {
|
|
7777
|
+
const asset2 = await AssetLoader.get(key, "json" /* JSON */);
|
|
7778
|
+
if (asset2 === void 0) return void 0;
|
|
7779
|
+
if (!asset2 || typeof asset2 !== "object" || Array.isArray(asset2) || !asset2.effects || typeof asset2.effects !== "object" || Array.isArray(asset2.effects)) {
|
|
7780
|
+
throw new MineRenderError(`Invalid biome effects: ${id}`);
|
|
7781
|
+
}
|
|
7782
|
+
if (typeof asset2.temperature !== "number" || !Number.isFinite(asset2.temperature) || typeof asset2.downfall !== "number" || !Number.isFinite(asset2.downfall)) {
|
|
7783
|
+
throw new MineRenderError(`Invalid biome climate: ${id}`);
|
|
7784
|
+
}
|
|
7785
|
+
for (const kind of ["grass", "foliage", "dry_foliage", "water"]) {
|
|
7786
|
+
const color2 = asset2.effects[`${kind}_color`];
|
|
7787
|
+
if (color2 !== void 0) this.parseColor(color2, id, kind);
|
|
7788
|
+
}
|
|
7789
|
+
const modifier = asset2.effects.grass_color_modifier;
|
|
7790
|
+
if (modifier !== void 0 && modifier !== "none" && modifier !== "dark_forest" && modifier !== "swamp") {
|
|
7791
|
+
throw new MineRenderError(`Invalid biome grass color modifier: ${id}`);
|
|
7792
|
+
}
|
|
7793
|
+
return asset2;
|
|
7794
|
+
});
|
|
7795
|
+
}
|
|
7796
|
+
/** Returns packed sRGB, or `undefined` when the biome or requested water color is missing. */
|
|
7797
|
+
static async getColor(id, kind, origin, x = 0, z = 0) {
|
|
7798
|
+
const biome = await this.get(id, origin);
|
|
7799
|
+
if (!biome) return void 0;
|
|
7800
|
+
const rawColor = biome.effects[`${kind}_color`];
|
|
7801
|
+
let color2 = rawColor === void 0 ? void 0 : this.parseColor(rawColor, id, kind);
|
|
7802
|
+
if (kind === "water") return color2;
|
|
7803
|
+
const modifier = kind === "grass" ? biome.effects.grass_color_modifier : void 0;
|
|
7804
|
+
if (modifier === "swamp") return swampGrassColor(x, z);
|
|
7805
|
+
if (color2 === void 0) {
|
|
7806
|
+
const clamp = (value) => Math.max(0, Math.min(1, Math.fround(value)));
|
|
7807
|
+
color2 = await Colormaps.getColor(kind, origin, clamp(biome.temperature), clamp(biome.downfall));
|
|
7808
|
+
}
|
|
7809
|
+
return modifier === "dark_forest" ? (color2 & 16711422) + 2634762 >> 1 : color2;
|
|
7810
|
+
}
|
|
7811
|
+
static parseColor(value, id, kind) {
|
|
7812
|
+
if (typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value)) return parseInt(value.slice(1), 16);
|
|
7813
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 16777215) return value;
|
|
7814
|
+
throw new MineRenderError(`Invalid biome ${kind} color: ${id}`);
|
|
7815
|
+
}
|
|
7816
|
+
};
|
|
7817
|
+
|
|
7702
7818
|
// src/assets/BlockEntities.ts
|
|
7703
7819
|
init_AssetKey();
|
|
7704
7820
|
init_AssetLoader();
|
|
@@ -12178,8 +12294,20 @@ var BlockStateResolver = class _BlockStateResolver {
|
|
|
12178
12294
|
init_Colormaps();
|
|
12179
12295
|
init_MineRenderData();
|
|
12180
12296
|
var BlockTints = class {
|
|
12181
|
-
/**
|
|
12182
|
-
static async
|
|
12297
|
+
/** Returns a block's versioned biome color source, leaving fixed-color blocks unchanged. */
|
|
12298
|
+
static async biomeSource(key) {
|
|
12299
|
+
const rule = key && (await MineRenderData.get("blockTints", key.root))[key.toNamespacedString()];
|
|
12300
|
+
return rule ? rule.biome ?? (rule.source === "grass" ? "grass" : void 0) : void 0;
|
|
12301
|
+
}
|
|
12302
|
+
/** Resolves one block's biome tint at world block coordinates, without biome blending. */
|
|
12303
|
+
static async getBiomeColor(key, biome, position) {
|
|
12304
|
+
if (!biome) return void 0;
|
|
12305
|
+
const x = position?.[0], z = position?.[2];
|
|
12306
|
+
const source = await this.biomeSource(key);
|
|
12307
|
+
return source ? Biomes.getColor(biome, source, key, x, z) : void 0;
|
|
12308
|
+
}
|
|
12309
|
+
/** Resolves used tint indices from biome or preview colors; explicit tints take precedence. */
|
|
12310
|
+
static async get(key, state, model, tints, biomeColor) {
|
|
12183
12311
|
if (!key) return tints;
|
|
12184
12312
|
const candidates = (model.elements ?? []).flatMap((element) => Object.values(element.faces)).some((face) => face?.tintindex !== void 0 && face.tintindex >= 0 && tints?.[face.tintindex] === void 0);
|
|
12185
12313
|
if (!candidates) return tints;
|
|
@@ -12195,8 +12323,12 @@ var BlockTints = class {
|
|
|
12195
12323
|
}
|
|
12196
12324
|
}
|
|
12197
12325
|
if (!indices.size) return tints;
|
|
12326
|
+
const source = rule.biome ?? (rule.source === "grass" ? "grass" : void 0);
|
|
12327
|
+
const biome = source ? typeof biomeColor === "function" ? await biomeColor() : biomeColor : void 0;
|
|
12198
12328
|
let color2;
|
|
12199
|
-
|
|
12329
|
+
if (biome !== void 0) {
|
|
12330
|
+
color2 = biome;
|
|
12331
|
+
} else switch (rule.source) {
|
|
12200
12332
|
case "constant":
|
|
12201
12333
|
color2 = rule.color;
|
|
12202
12334
|
break;
|
|
@@ -12255,6 +12387,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12255
12387
|
this._entityGeneration = 0;
|
|
12256
12388
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
12257
12389
|
this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
|
|
12390
|
+
this.biomePosition = options?.biomePosition ? [...options.biomePosition] : void 0;
|
|
12258
12391
|
}
|
|
12259
12392
|
async init() {
|
|
12260
12393
|
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
@@ -12447,11 +12580,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12447
12580
|
const { FluidModelObject: FluidModelObject2, sampleFluid: sampleFluid2 } = await Promise.resolve().then(() => (init_FluidModelObject(), FluidModelObject_exports));
|
|
12448
12581
|
this._fluidSampler = sample;
|
|
12449
12582
|
const surface = sampleFluid2(kind, (x, y, z) => x === 0 && y === 0 && z === 0 ? { fluid: kind, level: this.fluidLevel } : sample?.(x, y, z) ?? {});
|
|
12450
|
-
|
|
12583
|
+
const tint = this.options.tints?.[0] ?? this.waterTint;
|
|
12584
|
+
const fluidKey = `${surface.key}|${tint ?? "default"}`;
|
|
12585
|
+
if (this._fluidKey === fluidKey) return;
|
|
12451
12586
|
const key = new AssetKey("minecraft", `${kind}/${surface.key}`, "models", "fluid", "assets", ".json", this.blockState.key?.root);
|
|
12452
12587
|
const replacement = await this.scene.addSceneObject(
|
|
12453
12588
|
{ key },
|
|
12454
|
-
() => new FluidModelObject2(kind, surface.sample, this.blockState.key,
|
|
12589
|
+
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, {
|
|
12590
|
+
...this.options,
|
|
12591
|
+
tints: tint === void 0 ? this.options.tints : { ...this.options.tints, 0: tint }
|
|
12592
|
+
})
|
|
12455
12593
|
);
|
|
12456
12594
|
const previous = this._fluidModel;
|
|
12457
12595
|
const matrix = previous ? this.getModelMatrix(previous) : new Matrix411().makeTranslation(...this.position.toArray());
|
|
@@ -12460,7 +12598,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12460
12598
|
this._models = this._models.filter((model) => model !== previous);
|
|
12461
12599
|
this._models.push(replacement);
|
|
12462
12600
|
this._fluidModel = replacement;
|
|
12463
|
-
this._fluidKey =
|
|
12601
|
+
this._fluidKey = fluidKey;
|
|
12464
12602
|
this._isInstanced || (this._isInstanced = isInstanceReference(replacement));
|
|
12465
12603
|
this._instanceCounter = this._isInstanced ? 1 : 0;
|
|
12466
12604
|
if (previous) this.removeModels([previous]);
|
|
@@ -12483,6 +12621,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12483
12621
|
}
|
|
12484
12622
|
async recreateModels() {
|
|
12485
12623
|
this.clearModels();
|
|
12624
|
+
this.waterTint = this.fluidKind === "water" && this.options.biome && this.options.tints?.[0] === void 0 ? await Biomes.getColor(this.options.biome, "water", this.blockState.key) : void 0;
|
|
12486
12625
|
if (resolveBlockFluidState(this.blockState.key, this.state, this._fluidRules)?.renderModel === false) {
|
|
12487
12626
|
await this.updateFluid(this._fluidSampler);
|
|
12488
12627
|
return;
|
|
@@ -12517,7 +12656,13 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12517
12656
|
const model = await Models.getMerged(modelKey);
|
|
12518
12657
|
const options = {
|
|
12519
12658
|
...this.options,
|
|
12520
|
-
tints: model ? await BlockTints.get(
|
|
12659
|
+
tints: model ? await BlockTints.get(
|
|
12660
|
+
this.blockState.key,
|
|
12661
|
+
this.state,
|
|
12662
|
+
model,
|
|
12663
|
+
this.options.tints,
|
|
12664
|
+
() => BlockTints.getBiomeColor(this.blockState.key, this.options.biome, this.biomePosition)
|
|
12665
|
+
) : this.options.tints,
|
|
12521
12666
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0,
|
|
12522
12667
|
cullMask: this.options.displayPosition ? 0 : ModelCulling.toLocalMask(this._cullMask, rotation)
|
|
12523
12668
|
};
|
|
@@ -13104,6 +13249,321 @@ init_ModelObject();
|
|
|
13104
13249
|
// src/index.ts
|
|
13105
13250
|
init_nbt();
|
|
13106
13251
|
|
|
13252
|
+
// src/renderer/FlyControls.ts
|
|
13253
|
+
import { Controls, Euler as Euler11, MathUtils as MathUtils2, Quaternion as Quaternion6, Vector3 as Vector313 } from "three";
|
|
13254
|
+
var VANILLA_FLY_SPEED = 10.89;
|
|
13255
|
+
var PITCH_LIMIT = Math.PI / 2;
|
|
13256
|
+
var MOVE_EPSILON = 1e-6;
|
|
13257
|
+
var _euler = new Euler11(0, 0, 0, "YXZ");
|
|
13258
|
+
var _forward = new Vector313();
|
|
13259
|
+
var _right = new Vector313();
|
|
13260
|
+
var _targetVelocity = new Vector313();
|
|
13261
|
+
var FlyControls = class extends Controls {
|
|
13262
|
+
constructor(camera, domElement) {
|
|
13263
|
+
super(camera, domElement ?? null);
|
|
13264
|
+
this.isFlyControls = true;
|
|
13265
|
+
/** Horizontal and vertical speed in scene units per second; vanilla creative flight by default. */
|
|
13266
|
+
this.movementSpeed = 16 * VANILLA_FLY_SPEED;
|
|
13267
|
+
/** Speed multiplier while the sprint key is held. */
|
|
13268
|
+
this.sprintMultiplier = 2;
|
|
13269
|
+
/** Radians per pixel of pointer movement. */
|
|
13270
|
+
this.lookSpeed = 2e-3;
|
|
13271
|
+
/** Smooth acceleration and deceleration, approximating vanilla flight momentum. */
|
|
13272
|
+
this.enableDamping = true;
|
|
13273
|
+
/** Portion of the remaining velocity change applied per 60 Hz frame (0–1) when damping is enabled. */
|
|
13274
|
+
this.dampingFactor = 0.25;
|
|
13275
|
+
/** Capture the pointer on click so the mouse turns the camera without dragging; dragging works regardless. */
|
|
13276
|
+
this.pointerLock = true;
|
|
13277
|
+
/** Scroll the wheel to change `movementSpeed` within `speedRange`. */
|
|
13278
|
+
this.enableWheelSpeed = true;
|
|
13279
|
+
/** Minimum and maximum `movementSpeed` reachable with the wheel. */
|
|
13280
|
+
this.speedRange = [16, 16 * 500];
|
|
13281
|
+
/** Touch joystick travel in CSS pixels for full speed. */
|
|
13282
|
+
this.joystickRadius = 64;
|
|
13283
|
+
/** Key bindings by `KeyboardEvent.code`. */
|
|
13284
|
+
this.keys = {
|
|
13285
|
+
forward: ["KeyW", "ArrowUp"],
|
|
13286
|
+
back: ["KeyS", "ArrowDown"],
|
|
13287
|
+
left: ["KeyA", "ArrowLeft"],
|
|
13288
|
+
right: ["KeyD", "ArrowRight"],
|
|
13289
|
+
up: ["Space"],
|
|
13290
|
+
down: ["ShiftLeft", "ShiftRight"],
|
|
13291
|
+
sprint: ["ControlLeft", "ControlRight"]
|
|
13292
|
+
};
|
|
13293
|
+
this._pressed = /* @__PURE__ */ new Set();
|
|
13294
|
+
this._velocity = new Vector313();
|
|
13295
|
+
this._lastPosition = new Vector313();
|
|
13296
|
+
this._lastQuaternion = new Quaternion6();
|
|
13297
|
+
this._position0 = new Vector313();
|
|
13298
|
+
this._quaternion0 = new Quaternion6();
|
|
13299
|
+
this._dragMoved = false;
|
|
13300
|
+
this._locked = false;
|
|
13301
|
+
this._onKeyDown = (event) => this.handleKey(event, true);
|
|
13302
|
+
this._onKeyUp = (event) => this.handleKey(event, false);
|
|
13303
|
+
this._onPointerDown = (event) => this.handlePointerDown(event);
|
|
13304
|
+
this._onPointerMove = (event) => this.handlePointerMove(event);
|
|
13305
|
+
this._onPointerUp = (event) => this.handlePointerUp(event);
|
|
13306
|
+
this._onPointerLockChange = () => this.handlePointerLockChange();
|
|
13307
|
+
this._onContextMenu = (event) => event.preventDefault();
|
|
13308
|
+
this._onWheel = (event) => this.handleWheel(event);
|
|
13309
|
+
this._onBlur = () => this.releaseKeys();
|
|
13310
|
+
this._lastPosition.copy(camera.position);
|
|
13311
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13312
|
+
this.saveState();
|
|
13313
|
+
if (domElement) this.connect(domElement);
|
|
13314
|
+
}
|
|
13315
|
+
connect(element) {
|
|
13316
|
+
super.connect(element);
|
|
13317
|
+
const document2 = element.ownerDocument;
|
|
13318
|
+
document2.addEventListener("keydown", this._onKeyDown);
|
|
13319
|
+
document2.addEventListener("keyup", this._onKeyUp);
|
|
13320
|
+
document2.addEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13321
|
+
document2.defaultView?.addEventListener("blur", this._onBlur);
|
|
13322
|
+
element.addEventListener("pointerdown", this._onPointerDown);
|
|
13323
|
+
element.addEventListener("pointermove", this._onPointerMove);
|
|
13324
|
+
element.addEventListener("pointerup", this._onPointerUp);
|
|
13325
|
+
element.addEventListener("pointercancel", this._onPointerUp);
|
|
13326
|
+
element.addEventListener("contextmenu", this._onContextMenu);
|
|
13327
|
+
element.addEventListener("wheel", this._onWheel, { passive: false });
|
|
13328
|
+
element.addEventListener("blur", this._onBlur);
|
|
13329
|
+
element.style.touchAction = "none";
|
|
13330
|
+
if (element.tabIndex < 0) element.tabIndex = 0;
|
|
13331
|
+
}
|
|
13332
|
+
disconnect() {
|
|
13333
|
+
const element = this.domElement;
|
|
13334
|
+
if (!element) return;
|
|
13335
|
+
const document2 = element.ownerDocument;
|
|
13336
|
+
document2.removeEventListener("keydown", this._onKeyDown);
|
|
13337
|
+
document2.removeEventListener("keyup", this._onKeyUp);
|
|
13338
|
+
document2.removeEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13339
|
+
document2.defaultView?.removeEventListener("blur", this._onBlur);
|
|
13340
|
+
element.removeEventListener("pointerdown", this._onPointerDown);
|
|
13341
|
+
element.removeEventListener("pointermove", this._onPointerMove);
|
|
13342
|
+
element.removeEventListener("pointerup", this._onPointerUp);
|
|
13343
|
+
element.removeEventListener("pointercancel", this._onPointerUp);
|
|
13344
|
+
element.removeEventListener("contextmenu", this._onContextMenu);
|
|
13345
|
+
element.removeEventListener("wheel", this._onWheel);
|
|
13346
|
+
element.removeEventListener("blur", this._onBlur);
|
|
13347
|
+
element.style.touchAction = "auto";
|
|
13348
|
+
this.unlock();
|
|
13349
|
+
this._locked = false;
|
|
13350
|
+
this.releaseKeys();
|
|
13351
|
+
this._dragPointer = void 0;
|
|
13352
|
+
this._joystick = void 0;
|
|
13353
|
+
}
|
|
13354
|
+
dispose() {
|
|
13355
|
+
this.disconnect();
|
|
13356
|
+
}
|
|
13357
|
+
/** Whether mouse look currently owns the pointer. */
|
|
13358
|
+
get locked() {
|
|
13359
|
+
return this._locked;
|
|
13360
|
+
}
|
|
13361
|
+
/** Requests pointer capture; browsers only allow this from a user gesture. */
|
|
13362
|
+
lock() {
|
|
13363
|
+
const element = this.domElement;
|
|
13364
|
+
if (!element || this._locked || typeof element.requestPointerLock !== "function") return;
|
|
13365
|
+
try {
|
|
13366
|
+
const result = element.requestPointerLock();
|
|
13367
|
+
if (result instanceof Promise) result.catch(() => void 0);
|
|
13368
|
+
} catch {
|
|
13369
|
+
}
|
|
13370
|
+
}
|
|
13371
|
+
/** Releases a captured pointer. */
|
|
13372
|
+
unlock() {
|
|
13373
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13374
|
+
if (document2?.pointerLockElement && document2.pointerLockElement === this.domElement) {
|
|
13375
|
+
document2.exitPointerLock();
|
|
13376
|
+
}
|
|
13377
|
+
}
|
|
13378
|
+
/** Stores the camera pose that {@link reset} restores. */
|
|
13379
|
+
saveState() {
|
|
13380
|
+
this._position0.copy(this.object.position);
|
|
13381
|
+
this._quaternion0.copy(this.object.quaternion);
|
|
13382
|
+
}
|
|
13383
|
+
/** Restores the saved camera pose and stops movement. */
|
|
13384
|
+
reset() {
|
|
13385
|
+
this.object.position.copy(this._position0);
|
|
13386
|
+
this.object.quaternion.copy(this._quaternion0);
|
|
13387
|
+
this._velocity.set(0, 0, 0);
|
|
13388
|
+
this.notifyChange();
|
|
13389
|
+
}
|
|
13390
|
+
/** Horizontal yaw in radians, where zero looks toward -Z. */
|
|
13391
|
+
get yaw() {
|
|
13392
|
+
return _euler.setFromQuaternion(this.object.quaternion).y;
|
|
13393
|
+
}
|
|
13394
|
+
/** Vertical pitch in radians, positive looking up. */
|
|
13395
|
+
get pitch() {
|
|
13396
|
+
return _euler.setFromQuaternion(this.object.quaternion).x;
|
|
13397
|
+
}
|
|
13398
|
+
/** Turns the camera; pitch is clamped to straight up and down. */
|
|
13399
|
+
setRotation(yaw, pitch) {
|
|
13400
|
+
_euler.set(MathUtils2.clamp(pitch, -PITCH_LIMIT, PITCH_LIMIT), yaw, 0);
|
|
13401
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13402
|
+
this.notifyChange();
|
|
13403
|
+
}
|
|
13404
|
+
/** Points the camera at a position without rolling it. */
|
|
13405
|
+
lookAt(target) {
|
|
13406
|
+
_forward.copy(target).sub(this.object.position);
|
|
13407
|
+
if (_forward.lengthSq() < MOVE_EPSILON) return;
|
|
13408
|
+
_forward.normalize();
|
|
13409
|
+
this.setRotation(Math.atan2(-_forward.x, -_forward.z), Math.asin(MathUtils2.clamp(_forward.y, -1, 1)));
|
|
13410
|
+
}
|
|
13411
|
+
/** Whether an action's key is held. */
|
|
13412
|
+
isPressed(action) {
|
|
13413
|
+
return this._pressed.has(action);
|
|
13414
|
+
}
|
|
13415
|
+
/**
|
|
13416
|
+
* Advances movement by `delta` seconds (measured since the previous call when omitted)
|
|
13417
|
+
* and dispatches `change` when the camera moved.
|
|
13418
|
+
*/
|
|
13419
|
+
update(delta) {
|
|
13420
|
+
if (delta === void 0) {
|
|
13421
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
13422
|
+
delta = this._lastTime === void 0 ? 0 : (now - this._lastTime) / 1e3;
|
|
13423
|
+
this._lastTime = now;
|
|
13424
|
+
}
|
|
13425
|
+
if (!this.enabled) {
|
|
13426
|
+
this._velocity.set(0, 0, 0);
|
|
13427
|
+
return;
|
|
13428
|
+
}
|
|
13429
|
+
if (delta > 0) this.move(delta);
|
|
13430
|
+
this.notifyChange();
|
|
13431
|
+
}
|
|
13432
|
+
move(delta) {
|
|
13433
|
+
const camera = this.object;
|
|
13434
|
+
let forward = (this._pressed.has("forward") ? 1 : 0) - (this._pressed.has("back") ? 1 : 0);
|
|
13435
|
+
let strafe = (this._pressed.has("right") ? 1 : 0) - (this._pressed.has("left") ? 1 : 0);
|
|
13436
|
+
const climb = (this._pressed.has("up") ? 1 : 0) - (this._pressed.has("down") ? 1 : 0);
|
|
13437
|
+
const joystick = this._joystick;
|
|
13438
|
+
if (joystick) {
|
|
13439
|
+
const radius = Math.max(this.joystickRadius, 1);
|
|
13440
|
+
forward = MathUtils2.clamp(forward + (joystick.originY - joystick.y) / radius, -1, 1);
|
|
13441
|
+
strafe = MathUtils2.clamp(strafe + (joystick.x - joystick.originX) / radius, -1, 1);
|
|
13442
|
+
}
|
|
13443
|
+
_euler.setFromQuaternion(camera.quaternion);
|
|
13444
|
+
const yaw = _euler.y;
|
|
13445
|
+
_forward.set(-Math.sin(yaw), 0, -Math.cos(yaw));
|
|
13446
|
+
_right.set(Math.cos(yaw), 0, -Math.sin(yaw));
|
|
13447
|
+
_targetVelocity.set(0, 0, 0);
|
|
13448
|
+
if (forward || strafe || climb) {
|
|
13449
|
+
_targetVelocity.addScaledVector(_forward, forward).addScaledVector(_right, strafe);
|
|
13450
|
+
if (_targetVelocity.lengthSq() > 1) _targetVelocity.normalize();
|
|
13451
|
+
_targetVelocity.y = climb;
|
|
13452
|
+
const speed = this.movementSpeed * (this._pressed.has("sprint") ? this.sprintMultiplier : 1);
|
|
13453
|
+
_targetVelocity.multiplyScalar(speed);
|
|
13454
|
+
}
|
|
13455
|
+
if (this.enableDamping) {
|
|
13456
|
+
const blend = 1 - Math.pow(1 - MathUtils2.clamp(this.dampingFactor, 0, 1), delta * 60);
|
|
13457
|
+
this._velocity.lerp(_targetVelocity, blend);
|
|
13458
|
+
if (_targetVelocity.lengthSq() === 0 && this._velocity.lengthSq() < MOVE_EPSILON) this._velocity.set(0, 0, 0);
|
|
13459
|
+
} else {
|
|
13460
|
+
this._velocity.copy(_targetVelocity);
|
|
13461
|
+
}
|
|
13462
|
+
camera.position.addScaledVector(this._velocity, delta);
|
|
13463
|
+
}
|
|
13464
|
+
notifyChange() {
|
|
13465
|
+
const camera = this.object;
|
|
13466
|
+
if (this._lastPosition.distanceToSquared(camera.position) > MOVE_EPSILON || 8 * (1 - this._lastQuaternion.dot(camera.quaternion)) > MOVE_EPSILON) {
|
|
13467
|
+
this._lastPosition.copy(camera.position);
|
|
13468
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13469
|
+
this.dispatchEvent({ type: "change" });
|
|
13470
|
+
}
|
|
13471
|
+
}
|
|
13472
|
+
releaseKeys() {
|
|
13473
|
+
this._pressed.clear();
|
|
13474
|
+
}
|
|
13475
|
+
handleKey(event, down) {
|
|
13476
|
+
const action = this.actionFor(event.code);
|
|
13477
|
+
if (!action) return;
|
|
13478
|
+
const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
|
|
13479
|
+
if (down && !ownsInput) return;
|
|
13480
|
+
const pressed = this._pressed.has(action);
|
|
13481
|
+
if (down) this._pressed.add(action);
|
|
13482
|
+
else this._pressed.delete(action);
|
|
13483
|
+
if (ownsInput || this.enabled && pressed) event.preventDefault();
|
|
13484
|
+
}
|
|
13485
|
+
actionFor(code) {
|
|
13486
|
+
for (const action in this.keys) {
|
|
13487
|
+
if (this.keys[action].includes(code)) return action;
|
|
13488
|
+
}
|
|
13489
|
+
return void 0;
|
|
13490
|
+
}
|
|
13491
|
+
handlePointerDown(event) {
|
|
13492
|
+
const element = this.domElement;
|
|
13493
|
+
if (!this.enabled || !element) return;
|
|
13494
|
+
element.focus?.({ preventScroll: true });
|
|
13495
|
+
if (this._locked) return;
|
|
13496
|
+
if (event.pointerType === "touch" && !this._joystick && this.onJoystickSide(event)) {
|
|
13497
|
+
this._joystick = { id: event.pointerId, originX: event.clientX, originY: event.clientY, x: event.clientX, y: event.clientY };
|
|
13498
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13499
|
+
return;
|
|
13500
|
+
}
|
|
13501
|
+
if (this._dragPointer !== void 0) return;
|
|
13502
|
+
if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
|
|
13503
|
+
this._dragPointer = event.pointerId;
|
|
13504
|
+
this._dragMoved = false;
|
|
13505
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13506
|
+
}
|
|
13507
|
+
onJoystickSide(event) {
|
|
13508
|
+
const rect = this.domElement?.getBoundingClientRect?.();
|
|
13509
|
+
return !!rect && event.clientX < rect.left + rect.width / 2;
|
|
13510
|
+
}
|
|
13511
|
+
handlePointerMove(event) {
|
|
13512
|
+
if (!this.enabled) return;
|
|
13513
|
+
const joystick = this._joystick;
|
|
13514
|
+
if (joystick && event.pointerId === joystick.id) {
|
|
13515
|
+
joystick.x = event.clientX;
|
|
13516
|
+
joystick.y = event.clientY;
|
|
13517
|
+
return;
|
|
13518
|
+
}
|
|
13519
|
+
if (!this._locked && event.pointerId !== this._dragPointer) return;
|
|
13520
|
+
const dx = event.movementX ?? 0;
|
|
13521
|
+
const dy = event.movementY ?? 0;
|
|
13522
|
+
if (!dx && !dy) return;
|
|
13523
|
+
this._dragMoved = true;
|
|
13524
|
+
this.turn(dx, dy);
|
|
13525
|
+
}
|
|
13526
|
+
handlePointerUp(event) {
|
|
13527
|
+
if (this._joystick?.id === event.pointerId) {
|
|
13528
|
+
this._joystick = void 0;
|
|
13529
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13530
|
+
return;
|
|
13531
|
+
}
|
|
13532
|
+
if (event.pointerId !== this._dragPointer) return;
|
|
13533
|
+
this._dragPointer = void 0;
|
|
13534
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13535
|
+
if (this.enabled && this.pointerLock && !this._dragMoved && event.pointerType === "mouse" && event.button === 0) {
|
|
13536
|
+
this.lock();
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
handleWheel(event) {
|
|
13540
|
+
if (!this.enabled || !this.enableWheelSpeed) return;
|
|
13541
|
+
event.preventDefault();
|
|
13542
|
+
const steps = event.deltaMode === 0 ? event.deltaY / 100 : event.deltaY;
|
|
13543
|
+
const [min, max] = this.speedRange;
|
|
13544
|
+
this.movementSpeed = MathUtils2.clamp(this.movementSpeed * Math.pow(1.15, -steps), Math.min(min, max), Math.max(min, max));
|
|
13545
|
+
}
|
|
13546
|
+
handlePointerLockChange() {
|
|
13547
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13548
|
+
const locked = !!document2 && document2.pointerLockElement === this.domElement;
|
|
13549
|
+
if (locked === this._locked) return;
|
|
13550
|
+
this._locked = locked;
|
|
13551
|
+
if (!locked) this.releaseKeys();
|
|
13552
|
+
this.dispatchEvent({ type: locked ? "lock" : "unlock" });
|
|
13553
|
+
}
|
|
13554
|
+
turn(dx, dy) {
|
|
13555
|
+
_euler.setFromQuaternion(this.object.quaternion);
|
|
13556
|
+
_euler.y -= dx * this.lookSpeed;
|
|
13557
|
+
_euler.x = MathUtils2.clamp(_euler.x - dy * this.lookSpeed, -PITCH_LIMIT, PITCH_LIMIT);
|
|
13558
|
+
_euler.z = 0;
|
|
13559
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13560
|
+
this.notifyChange();
|
|
13561
|
+
}
|
|
13562
|
+
};
|
|
13563
|
+
function isFlyControls(obj) {
|
|
13564
|
+
return obj?.isFlyControls === true;
|
|
13565
|
+
}
|
|
13566
|
+
|
|
13107
13567
|
// src/renderer/MineRenderScene.ts
|
|
13108
13568
|
init_SceneObject();
|
|
13109
13569
|
var import_ts_deepmerge8 = __toESM(require_dist());
|
|
@@ -14170,7 +14630,7 @@ function isMineRenderScene(obj) {
|
|
|
14170
14630
|
}
|
|
14171
14631
|
|
|
14172
14632
|
// src/renderer/Renderer.ts
|
|
14173
|
-
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as
|
|
14633
|
+
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector315, WebGLRenderer } from "three";
|
|
14174
14634
|
var import_ts_deepmerge9 = __toESM(require_dist());
|
|
14175
14635
|
init_util();
|
|
14176
14636
|
init_Model();
|
|
@@ -14182,11 +14642,11 @@ import { EffectComposer, RenderPass } from "postprocessing";
|
|
|
14182
14642
|
import {
|
|
14183
14643
|
EventDispatcher,
|
|
14184
14644
|
MOUSE,
|
|
14185
|
-
Quaternion as
|
|
14645
|
+
Quaternion as Quaternion7,
|
|
14186
14646
|
Spherical,
|
|
14187
14647
|
TOUCH,
|
|
14188
14648
|
Vector2 as Vector26,
|
|
14189
|
-
Vector3 as
|
|
14649
|
+
Vector3 as Vector314
|
|
14190
14650
|
} from "three";
|
|
14191
14651
|
var _changeEvent = { type: "change" };
|
|
14192
14652
|
var _startEvent = { type: "start" };
|
|
@@ -14200,7 +14660,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14200
14660
|
this.domElement = domElement;
|
|
14201
14661
|
this.domElement.style.touchAction = "none";
|
|
14202
14662
|
this.enabled = true;
|
|
14203
|
-
this.target = new
|
|
14663
|
+
this.target = new Vector314();
|
|
14204
14664
|
this.minDistance = 0;
|
|
14205
14665
|
this.maxDistance = Infinity;
|
|
14206
14666
|
this.minZoom = 0;
|
|
@@ -14252,11 +14712,11 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14252
14712
|
state = STATE.NONE;
|
|
14253
14713
|
};
|
|
14254
14714
|
this.update = function() {
|
|
14255
|
-
const offset = new
|
|
14256
|
-
const quat = new
|
|
14715
|
+
const offset = new Vector314();
|
|
14716
|
+
const quat = new Quaternion7().setFromUnitVectors(object4.up, new Vector314(0, 1, 0));
|
|
14257
14717
|
const quatInverse = quat.clone().invert();
|
|
14258
|
-
const lastPosition = new
|
|
14259
|
-
const lastQuaternion = new
|
|
14718
|
+
const lastPosition = new Vector314();
|
|
14719
|
+
const lastQuaternion = new Quaternion7();
|
|
14260
14720
|
const twoPI = 2 * Math.PI;
|
|
14261
14721
|
return function update() {
|
|
14262
14722
|
const position = scope.object.position;
|
|
@@ -14345,7 +14805,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14345
14805
|
const spherical = new Spherical();
|
|
14346
14806
|
const sphericalDelta = new Spherical();
|
|
14347
14807
|
let scale = 1;
|
|
14348
|
-
const panOffset = new
|
|
14808
|
+
const panOffset = new Vector314();
|
|
14349
14809
|
let zoomChanged = false;
|
|
14350
14810
|
const rotateStart = new Vector26();
|
|
14351
14811
|
const rotateEnd = new Vector26();
|
|
@@ -14371,7 +14831,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14371
14831
|
sphericalDelta.phi -= angle;
|
|
14372
14832
|
}
|
|
14373
14833
|
const panLeft = function() {
|
|
14374
|
-
const v = new
|
|
14834
|
+
const v = new Vector314();
|
|
14375
14835
|
return function panLeft2(distance, objectMatrix) {
|
|
14376
14836
|
v.setFromMatrixColumn(objectMatrix, 0);
|
|
14377
14837
|
v.multiplyScalar(-distance);
|
|
@@ -14379,7 +14839,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14379
14839
|
};
|
|
14380
14840
|
}();
|
|
14381
14841
|
const panUp = function() {
|
|
14382
|
-
const v = new
|
|
14842
|
+
const v = new Vector314();
|
|
14383
14843
|
return function panUp2(distance, objectMatrix) {
|
|
14384
14844
|
if (scope.screenSpacePanning === true) {
|
|
14385
14845
|
v.setFromMatrixColumn(objectMatrix, 1);
|
|
@@ -14392,7 +14852,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14392
14852
|
};
|
|
14393
14853
|
}();
|
|
14394
14854
|
const pan = function() {
|
|
14395
|
-
const offset = new
|
|
14855
|
+
const offset = new Vector314();
|
|
14396
14856
|
return function pan2(deltaX, deltaY) {
|
|
14397
14857
|
const element = scope.domElement;
|
|
14398
14858
|
if (scope.object.isPerspectiveCamera) {
|
|
@@ -14947,20 +15407,77 @@ var _Renderer = class _Renderer {
|
|
|
14947
15407
|
}
|
|
14948
15408
|
createControls() {
|
|
14949
15409
|
if (!this.options.controls?.enabled) return void 0;
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
|
|
15410
|
+
return this.createControlsFor(this.options.controls.mode ?? "orbit", this.initialTarget());
|
|
15411
|
+
}
|
|
15412
|
+
initialTarget() {
|
|
14953
15413
|
const target = this.options.camera.lookingAt;
|
|
14954
|
-
if (isVector3(target))
|
|
15414
|
+
if (isVector3(target)) return target.clone();
|
|
15415
|
+
if (isTripleArray(target)) return new Vector315(target[0], target[1], target[2]);
|
|
15416
|
+
return new Vector315();
|
|
15417
|
+
}
|
|
15418
|
+
createControlsFor(mode, target) {
|
|
15419
|
+
let controls;
|
|
15420
|
+
if (mode === "fly") {
|
|
15421
|
+
controls = new FlyControls(this.camera, this.renderer.domElement);
|
|
15422
|
+
controls.lookAt(target);
|
|
15423
|
+
controls.saveState();
|
|
15424
|
+
} else {
|
|
15425
|
+
const position = this.camera.position.clone();
|
|
15426
|
+
controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
15427
|
+
this.camera.position.copy(position);
|
|
14955
15428
|
controls.target.copy(target);
|
|
14956
|
-
|
|
14957
|
-
controls.
|
|
15429
|
+
controls.update();
|
|
15430
|
+
controls.saveState();
|
|
14958
15431
|
}
|
|
14959
|
-
|
|
14960
|
-
controls.saveState();
|
|
15432
|
+
this._controlsTime = void 0;
|
|
14961
15433
|
this.registerEventDispatcher(controls);
|
|
14962
15434
|
return controls;
|
|
14963
15435
|
}
|
|
15436
|
+
/**
|
|
15437
|
+
* Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
|
|
15438
|
+
* Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
|
|
15439
|
+
* Returns the new controls, or undefined when controls were disabled at construction or after disposal.
|
|
15440
|
+
*/
|
|
15441
|
+
setControlsMode(mode) {
|
|
15442
|
+
const current = this._controls;
|
|
15443
|
+
if (this._disposed || !current) return void 0;
|
|
15444
|
+
if (this.controlsMode === mode) return current;
|
|
15445
|
+
let target;
|
|
15446
|
+
if (isFlyControls(current)) {
|
|
15447
|
+
const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
|
|
15448
|
+
target = new Vector315(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
|
|
15449
|
+
} else {
|
|
15450
|
+
target = current.target.clone();
|
|
15451
|
+
this._orbitDistance = this.camera.position.distanceTo(target);
|
|
15452
|
+
}
|
|
15453
|
+
const enabled = current.enabled;
|
|
15454
|
+
this.disposeControls(current);
|
|
15455
|
+
this._controls = this.createControlsFor(mode, target);
|
|
15456
|
+
this._controls.enabled = enabled;
|
|
15457
|
+
this.dirty = true;
|
|
15458
|
+
return this._controls;
|
|
15459
|
+
}
|
|
15460
|
+
disposeControls(controls) {
|
|
15461
|
+
this._controls = void 0;
|
|
15462
|
+
this.unregisterEventDispatcher(controls);
|
|
15463
|
+
controls.enabled = false;
|
|
15464
|
+
controls.dispose();
|
|
15465
|
+
}
|
|
15466
|
+
/** Advances owned controls; without a frame time, flight movement does not progress. */
|
|
15467
|
+
updateControls(time) {
|
|
15468
|
+
const controls = this._controls;
|
|
15469
|
+
if (!controls?.enabled) {
|
|
15470
|
+
this._controlsTime = void 0;
|
|
15471
|
+
return;
|
|
15472
|
+
}
|
|
15473
|
+
if (!isFlyControls(controls)) {
|
|
15474
|
+
controls.update();
|
|
15475
|
+
return;
|
|
15476
|
+
}
|
|
15477
|
+
const previous = this._controlsTime;
|
|
15478
|
+
if (time !== void 0) this._controlsTime = time;
|
|
15479
|
+
controls.update(time === void 0 || previous === void 0 ? 0 : (time - previous) / 1e3);
|
|
15480
|
+
}
|
|
14964
15481
|
//</editor-fold>
|
|
14965
15482
|
init() {
|
|
14966
15483
|
if (this._disposed) return;
|
|
@@ -15037,6 +15554,12 @@ var _Renderer = class _Renderer {
|
|
|
15037
15554
|
events.add(changeEvent2);
|
|
15038
15555
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
15039
15556
|
}
|
|
15557
|
+
unregisterEventDispatcher(dispatcher) {
|
|
15558
|
+
const events = this._eventDispatchers.get(dispatcher);
|
|
15559
|
+
if (!events) return;
|
|
15560
|
+
for (const event of events) dispatcher.removeEventListener(event, this._changeListener);
|
|
15561
|
+
this._eventDispatchers.delete(dispatcher);
|
|
15562
|
+
}
|
|
15040
15563
|
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
15041
15564
|
resize(width, height) {
|
|
15042
15565
|
if (this._disposed) return;
|
|
@@ -15113,6 +15636,7 @@ var _Renderer = class _Renderer {
|
|
|
15113
15636
|
this.renderer.setAnimationLoop(null);
|
|
15114
15637
|
}
|
|
15115
15638
|
this._nextFrameTime = void 0;
|
|
15639
|
+
this._controlsTime = void 0;
|
|
15116
15640
|
for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
|
|
15117
15641
|
}
|
|
15118
15642
|
/**
|
|
@@ -15142,10 +15666,7 @@ var _Renderer = class _Renderer {
|
|
|
15142
15666
|
}
|
|
15143
15667
|
this._element = void 0;
|
|
15144
15668
|
if (this._controls) {
|
|
15145
|
-
|
|
15146
|
-
this._controls = void 0;
|
|
15147
|
-
controls.enabled = false;
|
|
15148
|
-
controls.dispose();
|
|
15669
|
+
this.disposeControls(this._controls);
|
|
15149
15670
|
}
|
|
15150
15671
|
this.scene.clear();
|
|
15151
15672
|
for (const helper of this._debugHelpers) {
|
|
@@ -15162,9 +15683,7 @@ var _Renderer = class _Renderer {
|
|
|
15162
15683
|
}
|
|
15163
15684
|
animate(t = performance.now()) {
|
|
15164
15685
|
if (!this._running) return;
|
|
15165
|
-
|
|
15166
|
-
this._controls.update();
|
|
15167
|
-
}
|
|
15686
|
+
this.updateControls(t);
|
|
15168
15687
|
if (!this._running) return;
|
|
15169
15688
|
if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size && !this._videoExporter) return;
|
|
15170
15689
|
const interval = this._frameInterval;
|
|
@@ -15201,7 +15720,7 @@ var _Renderer = class _Renderer {
|
|
|
15201
15720
|
/** Draws a fresh frame without starting the animation loop or invoking frame callbacks. */
|
|
15202
15721
|
renderOnce() {
|
|
15203
15722
|
if (this._disposed) throw new Error("Cannot render a disposed renderer");
|
|
15204
|
-
|
|
15723
|
+
this.updateControls();
|
|
15205
15724
|
this.drawFrame();
|
|
15206
15725
|
}
|
|
15207
15726
|
/**
|
|
@@ -15231,7 +15750,7 @@ var _Renderer = class _Renderer {
|
|
|
15231
15750
|
try {
|
|
15232
15751
|
if (!wasRunning) this.start();
|
|
15233
15752
|
this._videoExporter = exporter;
|
|
15234
|
-
|
|
15753
|
+
this.updateControls();
|
|
15235
15754
|
this.drawFrame();
|
|
15236
15755
|
} catch (error) {
|
|
15237
15756
|
exporter.cancel(error);
|
|
@@ -15282,6 +15801,19 @@ var _Renderer = class _Renderer {
|
|
|
15282
15801
|
get controls() {
|
|
15283
15802
|
return this._controls;
|
|
15284
15803
|
}
|
|
15804
|
+
/** Renderer-owned OrbitControls, or undefined in fly mode or without controls. */
|
|
15805
|
+
get orbitControls() {
|
|
15806
|
+
return this._controls && !isFlyControls(this._controls) ? this._controls : void 0;
|
|
15807
|
+
}
|
|
15808
|
+
/** Renderer-owned {@link FlyControls}, or undefined in orbit mode or without controls. */
|
|
15809
|
+
get flyControls() {
|
|
15810
|
+
return isFlyControls(this._controls) ? this._controls : void 0;
|
|
15811
|
+
}
|
|
15812
|
+
/** The active renderer-owned controls mode, or undefined without controls. */
|
|
15813
|
+
get controlsMode() {
|
|
15814
|
+
if (!this._controls) return void 0;
|
|
15815
|
+
return isFlyControls(this._controls) ? "fly" : "orbit";
|
|
15816
|
+
}
|
|
15285
15817
|
///
|
|
15286
15818
|
};
|
|
15287
15819
|
_Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
@@ -15299,8 +15831,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
|
15299
15831
|
top: void 0,
|
|
15300
15832
|
bottom: void 0
|
|
15301
15833
|
},
|
|
15302
|
-
position: new
|
|
15303
|
-
lookingAt: new
|
|
15834
|
+
position: new Vector315(50, 50, 50),
|
|
15835
|
+
lookingAt: new Vector315(0, 0, 0)
|
|
15304
15836
|
},
|
|
15305
15837
|
render: {
|
|
15306
15838
|
fpsLimit: 60,
|
|
@@ -15315,7 +15847,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
|
15315
15847
|
enabled: true
|
|
15316
15848
|
},
|
|
15317
15849
|
controls: {
|
|
15318
|
-
enabled: false
|
|
15850
|
+
enabled: false,
|
|
15851
|
+
mode: "orbit"
|
|
15319
15852
|
},
|
|
15320
15853
|
debug: {
|
|
15321
15854
|
grid: false,
|
|
@@ -16548,14 +17081,14 @@ var AnvilWorldSource = class {
|
|
|
16548
17081
|
};
|
|
16549
17082
|
|
|
16550
17083
|
// src/world/Chunk.ts
|
|
16551
|
-
import { Vector3 as
|
|
17084
|
+
import { Color as Color13, Vector3 as Vector318 } from "three";
|
|
16552
17085
|
init_BlockStates();
|
|
16553
17086
|
init_AssetKey();
|
|
16554
17087
|
|
|
16555
17088
|
// src/world/MineRenderWorld.ts
|
|
16556
17089
|
init_Model();
|
|
16557
17090
|
init_util();
|
|
16558
|
-
import { Vector3 as
|
|
17091
|
+
import { Vector3 as Vector317 } from "three";
|
|
16559
17092
|
init_AssetKey();
|
|
16560
17093
|
init_BlockStates();
|
|
16561
17094
|
init_CubeFace();
|
|
@@ -16564,7 +17097,7 @@ init_CubeFace();
|
|
|
16564
17097
|
init_AssetKey();
|
|
16565
17098
|
init_Models();
|
|
16566
17099
|
init_CubeFace();
|
|
16567
|
-
import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as
|
|
17100
|
+
import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector316 } from "three";
|
|
16568
17101
|
init_ModelCulling();
|
|
16569
17102
|
init_ModelObject();
|
|
16570
17103
|
init_UVMapper();
|
|
@@ -16618,24 +17151,48 @@ var SectionModels = class {
|
|
|
16618
17151
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
16619
17152
|
}
|
|
16620
17153
|
/** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
|
|
16621
|
-
async get(blockState3, properties = {}, position) {
|
|
16622
|
-
const
|
|
16623
|
-
|
|
17154
|
+
async get(blockState3, properties = {}, position, biome) {
|
|
17155
|
+
const biomePosition = position ? [...position] : void 0;
|
|
17156
|
+
const prepared = await this.state(blockState3, properties);
|
|
17157
|
+
if (!prepared) return void 0;
|
|
17158
|
+
return Promise.all(prepared.groups.map(async (group) => {
|
|
17159
|
+
const variant = BlockStateResolver.choose(group, biomePosition);
|
|
17160
|
+
const choice = prepared.choices.get(variant);
|
|
17161
|
+
const tints = await BlockTints.get(
|
|
17162
|
+
blockState3.key,
|
|
17163
|
+
prepared.state,
|
|
17164
|
+
choice.model,
|
|
17165
|
+
void 0,
|
|
17166
|
+
() => BlockTints.getBiomeColor(blockState3.key, biome, biomePosition)
|
|
17167
|
+
);
|
|
17168
|
+
return this.template(variant, choice, tints);
|
|
17169
|
+
}));
|
|
17170
|
+
}
|
|
17171
|
+
/** Resolves section templates for one tint palette, with a synchronous weighted choice for each cell. */
|
|
17172
|
+
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
17173
|
+
const prepared = await this.state(blockState3, properties);
|
|
17174
|
+
if (!prepared) return void 0;
|
|
17175
|
+
let color2;
|
|
17176
|
+
const resolveColor = typeof biomeColor === "function" ? () => color2 ?? (color2 = biomeColor()) : biomeColor;
|
|
17177
|
+
const templates = /* @__PURE__ */ new Map();
|
|
17178
|
+
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
17179
|
+
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
17180
|
+
templates.set(variant, await this.template(variant, choice, tints));
|
|
17181
|
+
}));
|
|
17182
|
+
return { pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))) };
|
|
16624
17183
|
}
|
|
16625
|
-
|
|
16626
|
-
async prepareState(blockState3, properties = {}) {
|
|
17184
|
+
async state(blockState3, properties) {
|
|
16627
17185
|
let states = this.states.get(blockState3);
|
|
16628
17186
|
if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
|
|
16629
17187
|
const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
|
|
16630
|
-
|
|
16631
|
-
if (!prepared) return void 0;
|
|
16632
|
-
return { pick: (position) => prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, position))) };
|
|
17188
|
+
return cached(states, key, () => this.prepare(blockState3, properties));
|
|
16633
17189
|
}
|
|
16634
17190
|
/** Returns the shared still/flow atlas used by per-block fluid objects. */
|
|
16635
17191
|
fluidAtlas(kind, root) {
|
|
16636
|
-
|
|
17192
|
+
const key = new AssetKey("minecraft", kind, "models", "fluid", "assets", ".json", root);
|
|
17193
|
+
return cached(this.fluidAtlases, key.serialize(), async () => {
|
|
16637
17194
|
const atlas = await UVMapper.getAtlas({
|
|
16638
|
-
key
|
|
17195
|
+
key,
|
|
16639
17196
|
textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },
|
|
16640
17197
|
elements: []
|
|
16641
17198
|
});
|
|
@@ -16647,64 +17204,67 @@ var SectionModels = class {
|
|
|
16647
17204
|
const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
|
|
16648
17205
|
const groups = BlockStateResolver.matching(blockState3, state);
|
|
16649
17206
|
if (!groups.length) return void 0;
|
|
16650
|
-
const
|
|
17207
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
16651
17208
|
for (const group of groups) {
|
|
16652
17209
|
const choices = Array.isArray(group) ? group : [group];
|
|
16653
17210
|
if (!choices.length) return void 0;
|
|
16654
17211
|
for (const variant of choices) {
|
|
16655
17212
|
if (!variant.model) return void 0;
|
|
16656
|
-
const
|
|
17213
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
17214
|
+
modelKey.root = blockState3.key?.root;
|
|
17215
|
+
const model = await Models.getMerged(modelKey);
|
|
16657
17216
|
if (!model?.elements?.length) return void 0;
|
|
16658
17217
|
const atlas = await UVMapper.getAtlas(model);
|
|
16659
17218
|
const rotation = BlockStateResolver.rotation(variant);
|
|
16660
17219
|
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
16661
|
-
|
|
16662
|
-
let models = this.models.get(model);
|
|
16663
|
-
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
16664
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
16665
|
-
const template = await cached(models, key, async () => {
|
|
16666
|
-
const object4 = new SectionModel(model, {
|
|
16667
|
-
instanceMeshes: false,
|
|
16668
|
-
mergeMeshes: true,
|
|
16669
|
-
tints,
|
|
16670
|
-
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
16671
|
-
});
|
|
16672
|
-
await object4.init();
|
|
16673
|
-
let geometry = object4.children[0].geometry;
|
|
16674
|
-
geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
|
|
16675
|
-
object4.clear();
|
|
16676
|
-
const keep = [];
|
|
16677
|
-
const cullFaces = [];
|
|
16678
|
-
for (const element of atlas.model.elements) {
|
|
16679
|
-
for (const face of CUBE_FACES) {
|
|
16680
|
-
const data = element.faces[face];
|
|
16681
|
-
keep.push(data !== void 0);
|
|
16682
|
-
if (!data) continue;
|
|
16683
|
-
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
16684
|
-
if (local < 0) {
|
|
16685
|
-
cullFaces.push(0);
|
|
16686
|
-
continue;
|
|
16687
|
-
}
|
|
16688
|
-
const normal = new Vector315(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
16689
|
-
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
16690
|
-
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
16691
|
-
}
|
|
16692
|
-
}
|
|
16693
|
-
geometry = compactQuads(geometry, keep);
|
|
16694
|
-
const template2 = {
|
|
16695
|
-
geometry,
|
|
16696
|
-
atlas,
|
|
16697
|
-
cullFaces: new Uint8Array(cullFaces),
|
|
16698
|
-
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
16699
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
16700
|
-
};
|
|
16701
|
-
this.templates.add(template2);
|
|
16702
|
-
return template2;
|
|
16703
|
-
});
|
|
16704
|
-
templates.set(variant, template);
|
|
17220
|
+
prepared.set(variant, { model, atlas, rotation });
|
|
16705
17221
|
}
|
|
16706
17222
|
}
|
|
16707
|
-
return { groups,
|
|
17223
|
+
return { state, groups, choices: prepared };
|
|
17224
|
+
}
|
|
17225
|
+
async template(variant, { model, atlas, rotation }, tints) {
|
|
17226
|
+
let models = this.models.get(model);
|
|
17227
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
17228
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
17229
|
+
return cached(models, key, async () => {
|
|
17230
|
+
const object4 = new SectionModel(model, {
|
|
17231
|
+
instanceMeshes: false,
|
|
17232
|
+
mergeMeshes: true,
|
|
17233
|
+
tints,
|
|
17234
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
17235
|
+
});
|
|
17236
|
+
await object4.init();
|
|
17237
|
+
let geometry = object4.children[0].geometry;
|
|
17238
|
+
geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
|
|
17239
|
+
object4.clear();
|
|
17240
|
+
const keep = [];
|
|
17241
|
+
const cullFaces = [];
|
|
17242
|
+
for (const element of atlas.model.elements) {
|
|
17243
|
+
for (const face of CUBE_FACES) {
|
|
17244
|
+
const data = element.faces[face];
|
|
17245
|
+
keep.push(data !== void 0);
|
|
17246
|
+
if (!data) continue;
|
|
17247
|
+
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
17248
|
+
if (local < 0) {
|
|
17249
|
+
cullFaces.push(0);
|
|
17250
|
+
continue;
|
|
17251
|
+
}
|
|
17252
|
+
const normal = new Vector316(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
17253
|
+
const world = CUBE_FACE_OFFSETS.findIndex(([x, y, z]) => Math.abs(normal.x - x) < 1e-6 && Math.abs(normal.y - y) < 1e-6 && Math.abs(normal.z - z) < 1e-6);
|
|
17254
|
+
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
17255
|
+
}
|
|
17256
|
+
}
|
|
17257
|
+
geometry = compactQuads(geometry, keep);
|
|
17258
|
+
const template = {
|
|
17259
|
+
geometry,
|
|
17260
|
+
atlas,
|
|
17261
|
+
cullFaces: new Uint8Array(cullFaces),
|
|
17262
|
+
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17263
|
+
layer: atlas.hasTranslucency ? 1 : 0
|
|
17264
|
+
};
|
|
17265
|
+
this.templates.add(template);
|
|
17266
|
+
return template;
|
|
17267
|
+
});
|
|
16708
17268
|
}
|
|
16709
17269
|
/** Disposes prepared geometry and clears this world's template caches. */
|
|
16710
17270
|
clear() {
|
|
@@ -16881,17 +17441,17 @@ var MineRenderWorld = class {
|
|
|
16881
17441
|
}
|
|
16882
17442
|
getBlockAt(posOrX, y, z) {
|
|
16883
17443
|
if (typeof posOrX == "number") {
|
|
16884
|
-
return this.getBlockAt(new
|
|
17444
|
+
return this.getBlockAt(new Vector317(posOrX, y, z));
|
|
16885
17445
|
}
|
|
16886
17446
|
if (isTripleArray(posOrX)) {
|
|
16887
|
-
return this.getBlockAt(new
|
|
17447
|
+
return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
|
|
16888
17448
|
}
|
|
16889
17449
|
this.validatePosBounds(posOrX);
|
|
16890
17450
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
16891
17451
|
}
|
|
16892
17452
|
getBiomeAt(posOrX, y, z) {
|
|
16893
|
-
if (typeof posOrX === "number") return this.getBiomeAt(new
|
|
16894
|
-
if (isTripleArray(posOrX)) return this.getBiomeAt(new
|
|
17453
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector317(posOrX, y, z));
|
|
17454
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector317(...posOrX));
|
|
16895
17455
|
this.validatePosBounds(posOrX);
|
|
16896
17456
|
const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
|
|
16897
17457
|
const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
|
|
@@ -16899,10 +17459,10 @@ var MineRenderWorld = class {
|
|
|
16899
17459
|
}
|
|
16900
17460
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
16901
17461
|
if (typeof posOrX == "number") {
|
|
16902
|
-
return this.setBlockAt(new
|
|
17462
|
+
return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
|
|
16903
17463
|
}
|
|
16904
17464
|
if (isTripleArray(posOrX)) {
|
|
16905
|
-
return this.setBlockAt(new
|
|
17465
|
+
return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
16906
17466
|
}
|
|
16907
17467
|
return this.placeBlock(posOrX, yOrBlock);
|
|
16908
17468
|
}
|
|
@@ -16913,10 +17473,10 @@ var MineRenderWorld = class {
|
|
|
16913
17473
|
}
|
|
16914
17474
|
async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
|
|
16915
17475
|
if (typeof posOrX === "number") {
|
|
16916
|
-
return this.setBlockVisibleAt(new
|
|
17476
|
+
return this.setBlockVisibleAt(new Vector317(posOrX, yOrVisible, z), visible);
|
|
16917
17477
|
}
|
|
16918
17478
|
if (isTripleArray(posOrX)) {
|
|
16919
|
-
return this.setBlockVisibleAt(new
|
|
17479
|
+
return this.setBlockVisibleAt(new Vector317(...posOrX), yOrVisible);
|
|
16920
17480
|
}
|
|
16921
17481
|
this.validatePosBounds(posOrX);
|
|
16922
17482
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
@@ -16942,7 +17502,7 @@ var MineRenderWorld = class {
|
|
|
16942
17502
|
const collect = async (positions2) => {
|
|
16943
17503
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
16944
17504
|
};
|
|
16945
|
-
const place = (block) => this.placeBlock(new
|
|
17505
|
+
const place = (block) => this.placeBlock(new Vector317(...block.position), block, collect);
|
|
16946
17506
|
const keys = /* @__PURE__ */ new Map();
|
|
16947
17507
|
const types = /* @__PURE__ */ new Set();
|
|
16948
17508
|
for (const block of multiblock.blocks) {
|
|
@@ -16958,7 +17518,7 @@ var MineRenderWorld = class {
|
|
|
16958
17518
|
}
|
|
16959
17519
|
if (!executor) {
|
|
16960
17520
|
const groups2 = /* @__PURE__ */ new Map();
|
|
16961
|
-
const position = new
|
|
17521
|
+
const position = new Vector317();
|
|
16962
17522
|
for (const block of multiblock.blocks) {
|
|
16963
17523
|
const [x, y, z] = block.position;
|
|
16964
17524
|
this.validatePosBounds(position.set(x, y, z));
|
|
@@ -16998,7 +17558,7 @@ var MineRenderWorld = class {
|
|
|
16998
17558
|
try {
|
|
16999
17559
|
positions = await chunk.placeBlocks(blocks);
|
|
17000
17560
|
} finally {
|
|
17001
|
-
positions ?? (positions = blocks.map(({ index }) => new
|
|
17561
|
+
positions ?? (positions = blocks.map(({ index }) => new Vector317(
|
|
17002
17562
|
chunk.x * 16 + index % 16,
|
|
17003
17563
|
chunk.y * 16 + Math.floor(index / 256),
|
|
17004
17564
|
chunk.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17034,10 +17594,9 @@ var MineRenderWorld = class {
|
|
|
17034
17594
|
}
|
|
17035
17595
|
try {
|
|
17036
17596
|
await this.clearChunkColumn(chunk.x, chunk.z);
|
|
17037
|
-
let sliceStart = performance.now();
|
|
17038
17597
|
for (const section of chunk.sections) {
|
|
17039
17598
|
if (section.biomes) {
|
|
17040
|
-
const position = new
|
|
17599
|
+
const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17041
17600
|
this.validatePosBounds(position);
|
|
17042
17601
|
const copy = [...section.biomes];
|
|
17043
17602
|
if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
|
|
@@ -17048,9 +17607,12 @@ var MineRenderWorld = class {
|
|
|
17048
17607
|
if (!column) this.biomes.set(key, column = /* @__PURE__ */ new Map());
|
|
17049
17608
|
column.set(section.y, copy);
|
|
17050
17609
|
}
|
|
17610
|
+
}
|
|
17611
|
+
let sliceStart = performance.now();
|
|
17612
|
+
for (const section of chunk.sections) {
|
|
17051
17613
|
if (!executor) {
|
|
17052
17614
|
if (!occupiedSections.has(section.y)) continue;
|
|
17053
|
-
const position = new
|
|
17615
|
+
const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17054
17616
|
this.validatePosBounds(position);
|
|
17055
17617
|
const target = this.getOrCreateChunkAt(position);
|
|
17056
17618
|
try {
|
|
@@ -17144,7 +17706,7 @@ var MineRenderWorld = class {
|
|
|
17144
17706
|
this.sectionModels?.clear();
|
|
17145
17707
|
}
|
|
17146
17708
|
updateCulling(positions) {
|
|
17147
|
-
const neighbor = new
|
|
17709
|
+
const neighbor = new Vector317();
|
|
17148
17710
|
for (const pos of positions) {
|
|
17149
17711
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
17150
17712
|
const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
@@ -17212,18 +17774,34 @@ var MineRenderWorld = class {
|
|
|
17212
17774
|
const key = this.worldPosToChunkKey(pos);
|
|
17213
17775
|
let chunk = this._chunks.get(key);
|
|
17214
17776
|
if (typeof chunk === "undefined") {
|
|
17777
|
+
const x = Math.floor(pos.x / 16), y = Math.floor(pos.y / 16), z = Math.floor(pos.z / 16);
|
|
17215
17778
|
chunk = new Chunk(
|
|
17216
17779
|
this.scene,
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17780
|
+
x,
|
|
17781
|
+
y,
|
|
17782
|
+
z,
|
|
17220
17783
|
(positions) => this.updateCulling(positions),
|
|
17221
17784
|
this.sectionModels,
|
|
17222
|
-
(
|
|
17223
|
-
const cx = Math.floor(
|
|
17785
|
+
(x2, y2, z2) => {
|
|
17786
|
+
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
17224
17787
|
const section = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
17225
|
-
const index = (
|
|
17788
|
+
const index = (y2 - cy * 16) * 256 + (z2 - cz * 16) * 16 + x2 - cx * 16;
|
|
17226
17789
|
return (section?.fluidByteIndex(index) ?? 0) | (section?.isOccludingIndex(index) ? 64 : 0);
|
|
17790
|
+
},
|
|
17791
|
+
(x2, y2, z2) => this.getBiomeAt(x2, y2, z2),
|
|
17792
|
+
async (biomes) => {
|
|
17793
|
+
if (this._chunks.get(key) !== chunk) return;
|
|
17794
|
+
const columnKey = `${x}_${z}`;
|
|
17795
|
+
let column = this.biomes.get(columnKey);
|
|
17796
|
+
if (biomes) {
|
|
17797
|
+
if (!column) this.biomes.set(columnKey, column = /* @__PURE__ */ new Map());
|
|
17798
|
+
column.set(y, biomes);
|
|
17799
|
+
} else {
|
|
17800
|
+
column?.delete(y);
|
|
17801
|
+
if (!column?.size) this.biomes.delete(columnKey);
|
|
17802
|
+
}
|
|
17803
|
+
await chunk.refreshBiomes();
|
|
17804
|
+
await this._chunks.get(`${x}_${y + 1}_${z}`)?.refreshBiomes();
|
|
17227
17805
|
}
|
|
17228
17806
|
);
|
|
17229
17807
|
this._chunks.set(key, chunk);
|
|
@@ -17236,7 +17814,7 @@ var MineRenderWorld = class {
|
|
|
17236
17814
|
}
|
|
17237
17815
|
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
17238
17816
|
static worldToScenePosition(pos) {
|
|
17239
|
-
return new
|
|
17817
|
+
return new Vector317(
|
|
17240
17818
|
pos.x * 16,
|
|
17241
17819
|
pos.y * 16,
|
|
17242
17820
|
pos.z * 16
|
|
@@ -17244,7 +17822,7 @@ var MineRenderWorld = class {
|
|
|
17244
17822
|
}
|
|
17245
17823
|
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
17246
17824
|
static sceneToWorldPosition(pos) {
|
|
17247
|
-
return new
|
|
17825
|
+
return new Vector317(
|
|
17248
17826
|
pos.x / 16,
|
|
17249
17827
|
pos.y / 16,
|
|
17250
17828
|
pos.z / 16
|
|
@@ -17278,6 +17856,7 @@ function buildSectionGeometry(input) {
|
|
|
17278
17856
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
17279
17857
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
17280
17858
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
17859
|
+
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
17281
17860
|
for (const template of templateData) {
|
|
17282
17861
|
const { quads } = template;
|
|
17283
17862
|
if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads) {
|
|
@@ -17355,7 +17934,9 @@ function buildSectionGeometry(input) {
|
|
|
17355
17934
|
height
|
|
17356
17935
|
});
|
|
17357
17936
|
}
|
|
17358
|
-
|
|
17937
|
+
const tintIndex = (x + z * 16 + y * 256) * 3;
|
|
17938
|
+
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
17939
|
+
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
17359
17940
|
}
|
|
17360
17941
|
pages.push(...[...fluidPages.values()].sort((a, b) => Number(atlases[a.placements[0].atlas].animated) - Number(atlases[b.placements[0].atlas].animated) || a.placements[0].atlas - b.placements[0].atlas));
|
|
17361
17942
|
}
|
|
@@ -17404,7 +17985,7 @@ function buildSectionGeometry(input) {
|
|
|
17404
17985
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
17405
17986
|
}
|
|
17406
17987
|
}
|
|
17407
|
-
for (const { quads, x, y, z, data } of page.fluids) {
|
|
17988
|
+
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
17408
17989
|
const atlas = atlases[data.atlas];
|
|
17409
17990
|
const placement = page.placements[0];
|
|
17410
17991
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
@@ -17428,7 +18009,7 @@ function buildSectionGeometry(input) {
|
|
|
17428
18009
|
mapU((rect[0] + rect[2]) / atlas.width),
|
|
17429
18010
|
mapV(1 - rect[1] / atlas.height)
|
|
17430
18011
|
], vertex * 4);
|
|
17431
|
-
colors.set(
|
|
18012
|
+
colors.set(tint, vertex * 3);
|
|
17432
18013
|
}
|
|
17433
18014
|
outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);
|
|
17434
18015
|
indexOffset += 6;
|
|
@@ -17569,7 +18150,7 @@ function toInput(entries, maxAtlasSize, fluids) {
|
|
|
17569
18150
|
input.cullMasks[i] = cullMask;
|
|
17570
18151
|
}
|
|
17571
18152
|
if (fluids) {
|
|
17572
|
-
input.fluids = { cells: fluids.cells };
|
|
18153
|
+
input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };
|
|
17573
18154
|
for (const kind of ["water", "lava"]) {
|
|
17574
18155
|
const atlas = fluids[kind];
|
|
17575
18156
|
if (!atlas) continue;
|
|
@@ -17670,17 +18251,20 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
17670
18251
|
init_FluidGeometry();
|
|
17671
18252
|
init_FluidQuads();
|
|
17672
18253
|
init_CubeFace();
|
|
18254
|
+
var WATER_TINT2 = new Color13(4159204).toArray();
|
|
17673
18255
|
var Chunk = class _Chunk {
|
|
17674
|
-
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell) {
|
|
18256
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged) {
|
|
17675
18257
|
this.onBlocksChanged = onBlocksChanged;
|
|
17676
18258
|
this.sectionModels = sectionModels;
|
|
17677
18259
|
this.neighborCell = neighborCell;
|
|
18260
|
+
this.biomeAt = biomeAt;
|
|
18261
|
+
this.onBiomesChanged = onBiomesChanged;
|
|
17678
18262
|
this.data = new ChunkData();
|
|
17679
18263
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
17680
18264
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
17681
18265
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
17682
18266
|
this.fluidCells = new Uint8Array(4096);
|
|
17683
|
-
this.blockPosition = new
|
|
18267
|
+
this.blockPosition = new Vector318();
|
|
17684
18268
|
this.meshDirty = false;
|
|
17685
18269
|
this.meshGeneration = 0;
|
|
17686
18270
|
this.scene = scene;
|
|
@@ -17690,21 +18274,71 @@ var Chunk = class _Chunk {
|
|
|
17690
18274
|
}
|
|
17691
18275
|
getBlockAt(posOrX, y, z) {
|
|
17692
18276
|
if (typeof posOrX == "number") {
|
|
17693
|
-
return this.getBlockAt(new
|
|
18277
|
+
return this.getBlockAt(new Vector318(posOrX, y, z));
|
|
17694
18278
|
}
|
|
17695
18279
|
if (isTripleArray(posOrX)) {
|
|
17696
|
-
return this.getBlockAt(new
|
|
18280
|
+
return this.getBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]));
|
|
17697
18281
|
}
|
|
17698
18282
|
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
17699
18283
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
17700
18284
|
return this.renderedBlocks.get(index);
|
|
17701
18285
|
}
|
|
18286
|
+
getBiomeAt(posOrX, y, z) {
|
|
18287
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector318(posOrX, y, z));
|
|
18288
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector318(...posOrX));
|
|
18289
|
+
const pos = this.worldPosToChunkPos(posOrX);
|
|
18290
|
+
_Chunk.chunkPosToBlockIndex(pos);
|
|
18291
|
+
return this.biomeAt ? this.biomeAt(posOrX.x, posOrX.y, posOrX.z) : this.biomes?.[Math.floor(pos.x / 4) + Math.floor(pos.z / 4) * 4 + Math.floor(pos.y / 4) * 16];
|
|
18292
|
+
}
|
|
18293
|
+
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
18294
|
+
setBiomes(biomes) {
|
|
18295
|
+
const copy = biomes ? [...biomes] : void 0;
|
|
18296
|
+
if (copy && (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0))) {
|
|
18297
|
+
throw new RangeError("Section biomes must contain 64 nonempty biome IDs");
|
|
18298
|
+
}
|
|
18299
|
+
if (this.onBiomesChanged) return this.onBiomesChanged(copy);
|
|
18300
|
+
this.biomes = copy;
|
|
18301
|
+
return this.refreshBiomes();
|
|
18302
|
+
}
|
|
18303
|
+
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
18304
|
+
async refreshBiomes() {
|
|
18305
|
+
const affected = /* @__PURE__ */ new Map();
|
|
18306
|
+
const blocks = [];
|
|
18307
|
+
for (const index of this.renderedBlocks.keys()) {
|
|
18308
|
+
const block = this.data.get(index);
|
|
18309
|
+
const stateKey = ChunkData.paletteKey(block);
|
|
18310
|
+
let matches = affected.get(stateKey);
|
|
18311
|
+
if (!matches) {
|
|
18312
|
+
const key = AssetKey.parse("blockstates", block.type);
|
|
18313
|
+
matches = BlockStates.get(key).then(async (state) => {
|
|
18314
|
+
const origin = state?.key ?? key;
|
|
18315
|
+
const [source, fluid] = await Promise.all([BlockTints.biomeSource(origin), getBlockFluidState(origin, block.properties)]);
|
|
18316
|
+
return !!source || fluid?.kind === "water";
|
|
18317
|
+
});
|
|
18318
|
+
affected.set(stateKey, matches);
|
|
18319
|
+
}
|
|
18320
|
+
if (await matches) blocks.push({ index, block });
|
|
18321
|
+
}
|
|
18322
|
+
if (!blocks.length) return;
|
|
18323
|
+
const hidden = new Set(this.hiddenBlocks);
|
|
18324
|
+
try {
|
|
18325
|
+
await this.placeBlocks(blocks);
|
|
18326
|
+
} finally {
|
|
18327
|
+
for (const index of hidden) {
|
|
18328
|
+
this.hiddenBlocks.add(index);
|
|
18329
|
+
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
18330
|
+
}
|
|
18331
|
+
const positions = blocks.map(({ index }) => new Vector318(...this.positionAt(index)));
|
|
18332
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
18333
|
+
else await this.rebuildSectionMesh();
|
|
18334
|
+
}
|
|
18335
|
+
}
|
|
17702
18336
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
17703
18337
|
if (typeof posOrX == "number") {
|
|
17704
|
-
return this.setBlockAt(new
|
|
18338
|
+
return this.setBlockAt(new Vector318(posOrX, yOrBlock, z), block);
|
|
17705
18339
|
}
|
|
17706
18340
|
if (isTripleArray(posOrX)) {
|
|
17707
|
-
return this.setBlockAt(new
|
|
18341
|
+
return this.setBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
17708
18342
|
}
|
|
17709
18343
|
const worldPos = posOrX;
|
|
17710
18344
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -17737,14 +18371,15 @@ var Chunk = class _Chunk {
|
|
|
17737
18371
|
nbt: block.nbt === void 0 ? void 0 : structuredClone(block.nbt)
|
|
17738
18372
|
} : void 0
|
|
17739
18373
|
}));
|
|
17740
|
-
const states =
|
|
17741
|
-
const
|
|
17742
|
-
|
|
17743
|
-
|
|
17744
|
-
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
18374
|
+
const states = /* @__PURE__ */ new Map();
|
|
18375
|
+
for (const { index, key, block } of placements) {
|
|
18376
|
+
if (key === void 0) continue;
|
|
18377
|
+
let state = states.get(key);
|
|
18378
|
+
if (!state) states.set(key, state = { stored: block, indices: [] });
|
|
18379
|
+
state.indices.push(index);
|
|
18380
|
+
}
|
|
18381
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
18382
|
+
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
17748
18383
|
const resolutions = new Map([...states.keys()].map((key, i) => [key, settled[i]]));
|
|
17749
18384
|
const positions = [];
|
|
17750
18385
|
let failed = false, failure;
|
|
@@ -17757,7 +18392,7 @@ var Chunk = class _Chunk {
|
|
|
17757
18392
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
17758
18393
|
this.fluidCells[index] = 0;
|
|
17759
18394
|
this.renderedBlocks.delete(index);
|
|
17760
|
-
const worldPos = new
|
|
18395
|
+
const worldPos = new Vector318(
|
|
17761
18396
|
this.x * 16 + index % 16,
|
|
17762
18397
|
this.y * 16 + Math.floor(index / 256),
|
|
17763
18398
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17768,7 +18403,8 @@ var Chunk = class _Chunk {
|
|
|
17768
18403
|
if (!readBlock) continue;
|
|
17769
18404
|
const resolved = resolutions.get(key);
|
|
17770
18405
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17771
|
-
const { blockState: blockState3, perBlock, fluid, prepared, stored } = resolved.value;
|
|
18406
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts, stored } = resolved.value;
|
|
18407
|
+
const context = contexts.get(index);
|
|
17772
18408
|
if (!blockState3) {
|
|
17773
18409
|
this.data.assign(index, 0);
|
|
17774
18410
|
continue;
|
|
@@ -17776,9 +18412,10 @@ var Chunk = class _Chunk {
|
|
|
17776
18412
|
const variantPosition = worldPos.toArray();
|
|
17777
18413
|
if (fluid) {
|
|
17778
18414
|
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18415
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
17779
18416
|
this.meshDirty = true;
|
|
17780
18417
|
}
|
|
17781
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18418
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
17782
18419
|
if (templates) {
|
|
17783
18420
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
17784
18421
|
this.meshDirty = true;
|
|
@@ -17788,7 +18425,9 @@ var Chunk = class _Chunk {
|
|
|
17788
18425
|
instanceMeshes: true,
|
|
17789
18426
|
maxInstanceCount: 2e3,
|
|
17790
18427
|
initialState: stored.properties,
|
|
17791
|
-
variantPosition
|
|
18428
|
+
variantPosition,
|
|
18429
|
+
biome: context?.biome,
|
|
18430
|
+
biomePosition: this.biomePosition(index, blockState3, stored)
|
|
17792
18431
|
});
|
|
17793
18432
|
object4.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
17794
18433
|
}
|
|
@@ -17811,24 +18450,21 @@ var Chunk = class _Chunk {
|
|
|
17811
18450
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
17812
18451
|
this.sectionBlocks.clear();
|
|
17813
18452
|
this.fluidCells.fill(0);
|
|
18453
|
+
this.waterTints = void 0;
|
|
17814
18454
|
this.renderedBlocks.clear();
|
|
17815
18455
|
this.hiddenBlocks.clear();
|
|
17816
18456
|
this.meshDirty = true;
|
|
17817
18457
|
this.data.copyFrom(data);
|
|
17818
|
-
const ids = /* @__PURE__ */ new
|
|
18458
|
+
const ids = /* @__PURE__ */ new Map();
|
|
17819
18459
|
for (let index = 0; index < 4096; index++) {
|
|
17820
18460
|
const id = this.data.idAt(index);
|
|
17821
|
-
if (id)
|
|
17822
|
-
|
|
17823
|
-
|
|
17824
|
-
|
|
17825
|
-
|
|
17826
|
-
|
|
17827
|
-
|
|
17828
|
-
const fluid = await getBlockFluidState(blockState3?.key, state.properties);
|
|
17829
|
-
const prepared = perBlock || fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, state.properties);
|
|
17830
|
-
return { blockState: blockState3, perBlock, fluid, prepared };
|
|
17831
|
-
}));
|
|
18461
|
+
if (!id) continue;
|
|
18462
|
+
let indices = ids.get(id);
|
|
18463
|
+
if (!indices) ids.set(id, indices = []);
|
|
18464
|
+
indices.push(index);
|
|
18465
|
+
}
|
|
18466
|
+
const palette = [...ids.keys()], biomes = /* @__PURE__ */ new Map();
|
|
18467
|
+
const settled = await Promise.allSettled(palette.map((id) => this.resolveState(this.data.stateAt(id), ids.get(id), biomes)));
|
|
17832
18468
|
const resolutions = new Map(palette.map((id, i) => [id, settled[i]]));
|
|
17833
18469
|
const perBlocks = [];
|
|
17834
18470
|
let failed = false, failure;
|
|
@@ -17838,24 +18474,28 @@ var Chunk = class _Chunk {
|
|
|
17838
18474
|
try {
|
|
17839
18475
|
const resolved = resolutions.get(id);
|
|
17840
18476
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17841
|
-
const { blockState: blockState3, perBlock, fluid, prepared } = resolved.value;
|
|
18477
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts } = resolved.value;
|
|
18478
|
+
const context = contexts.get(index);
|
|
17842
18479
|
if (!blockState3) {
|
|
17843
18480
|
this.data.assign(index, 0);
|
|
17844
18481
|
this.fluidCells[index] = 0;
|
|
17845
18482
|
continue;
|
|
17846
18483
|
}
|
|
17847
|
-
if (fluid)
|
|
18484
|
+
if (fluid) {
|
|
18485
|
+
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18486
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
18487
|
+
}
|
|
17848
18488
|
const variantPosition = [
|
|
17849
18489
|
this.x * 16 + index % 16,
|
|
17850
18490
|
this.y * 16 + Math.floor(index / 256),
|
|
17851
18491
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
17852
18492
|
];
|
|
17853
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18493
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
17854
18494
|
if (templates) {
|
|
17855
18495
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
17856
18496
|
this.meshDirty = true;
|
|
17857
18497
|
} else {
|
|
17858
|
-
perBlocks.push({ index, blockState: blockState3 });
|
|
18498
|
+
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
17859
18499
|
}
|
|
17860
18500
|
const readBlock = this.data.snapshot(index);
|
|
17861
18501
|
this.renderedBlocks.set(index, { get block() {
|
|
@@ -17868,7 +18508,7 @@ var Chunk = class _Chunk {
|
|
|
17868
18508
|
failed = true;
|
|
17869
18509
|
}
|
|
17870
18510
|
}
|
|
17871
|
-
for (const { index, blockState: blockState3 } of perBlocks) {
|
|
18511
|
+
for (const { index, blockState: blockState3, biome } of perBlocks) {
|
|
17872
18512
|
let object4;
|
|
17873
18513
|
try {
|
|
17874
18514
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -17876,13 +18516,11 @@ var Chunk = class _Chunk {
|
|
|
17876
18516
|
instanceMeshes: true,
|
|
17877
18517
|
maxInstanceCount: 2e3,
|
|
17878
18518
|
initialState: this.data.stateAt(this.data.idAt(index)).properties,
|
|
17879
|
-
variantPosition:
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
this.z * 16 + Math.floor(index / 16) % 16
|
|
17883
|
-
]
|
|
18519
|
+
variantPosition: this.positionAt(index),
|
|
18520
|
+
biome,
|
|
18521
|
+
biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
|
|
17884
18522
|
});
|
|
17885
|
-
object4.setPosition(new
|
|
18523
|
+
object4.setPosition(new Vector318(
|
|
17886
18524
|
this.x * 256 + index % 16 * 16,
|
|
17887
18525
|
this.y * 256 + Math.floor(index / 256) * 16,
|
|
17888
18526
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
@@ -17899,6 +18537,68 @@ var Chunk = class _Chunk {
|
|
|
17899
18537
|
}
|
|
17900
18538
|
if (failed) throw failure;
|
|
17901
18539
|
}
|
|
18540
|
+
positionAt(index) {
|
|
18541
|
+
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
18542
|
+
}
|
|
18543
|
+
biomePosition(index, blockState3, stored) {
|
|
18544
|
+
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18545
|
+
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
18546
|
+
return position;
|
|
18547
|
+
}
|
|
18548
|
+
async resolveState(stored, indices, biomes) {
|
|
18549
|
+
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
18550
|
+
const perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
18551
|
+
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
18552
|
+
const hasBiomes = this.getBiomeAt(this.x * 16, this.y * 16, this.z * 16) !== void 0 || this.biomeAt?.(this.x * 16, this.y * 16 - 1, this.z * 16) !== void 0;
|
|
18553
|
+
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
18554
|
+
const prepare = (color2) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color2);
|
|
18555
|
+
const contexts = /* @__PURE__ */ new Map();
|
|
18556
|
+
const groups = /* @__PURE__ */ new Map();
|
|
18557
|
+
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
18558
|
+
for (const index of indices) {
|
|
18559
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
18560
|
+
const biome = this.biomeAt ? this.biomeAt(...position) : position[1] >= this.y * 16 ? this.getBiomeAt(position) : void 0;
|
|
18561
|
+
if (!biome) continue;
|
|
18562
|
+
const key = JSON.stringify(source === "grass" ? [biome, position[0], position[2]] : [biome]);
|
|
18563
|
+
let group = groups.get(key);
|
|
18564
|
+
if (!group) groups.set(key, group = { biome, position, indices: [] });
|
|
18565
|
+
group.indices.push(index);
|
|
18566
|
+
}
|
|
18567
|
+
}
|
|
18568
|
+
const groupedCount = [...groups.values()].reduce((sum, group) => sum + group.indices.length, 0);
|
|
18569
|
+
const prepared = groupedCount < indices.length ? await prepare() : void 0;
|
|
18570
|
+
await Promise.all([...groups.values()].map(async ({ biome, position, indices: indices2 }) => {
|
|
18571
|
+
const available = () => {
|
|
18572
|
+
const key = JSON.stringify([biome, blockState3?.key?.root]);
|
|
18573
|
+
let found = biomes.get(key);
|
|
18574
|
+
if (!found) {
|
|
18575
|
+
found = Biomes.get(biome, blockState3?.key).then((value) => value !== void 0);
|
|
18576
|
+
biomes.set(key, found);
|
|
18577
|
+
}
|
|
18578
|
+
return found;
|
|
18579
|
+
};
|
|
18580
|
+
const context = { biome };
|
|
18581
|
+
if (perBlock) {
|
|
18582
|
+
if (!await available()) context.biome = void 0;
|
|
18583
|
+
} else {
|
|
18584
|
+
context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
|
|
18585
|
+
if (fluid?.kind === "water" && await available()) {
|
|
18586
|
+
const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
|
|
18587
|
+
if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new Color13(color2).toArray();
|
|
18588
|
+
}
|
|
18589
|
+
}
|
|
18590
|
+
for (const index of indices2) contexts.set(index, context);
|
|
18591
|
+
}));
|
|
18592
|
+
return { blockState: blockState3, perBlock, fluid, prepared, contexts, stored };
|
|
18593
|
+
}
|
|
18594
|
+
setWaterTint(index, tint) {
|
|
18595
|
+
if (!this.sectionModels || !this.waterTints && tint === void 0) return;
|
|
18596
|
+
if (!this.waterTints) {
|
|
18597
|
+
this.waterTints = new Float32Array(4096 * 3);
|
|
18598
|
+
for (let cell = 0; cell < 4096; cell++) this.waterTints.set(WATER_TINT2, cell * 3);
|
|
18599
|
+
}
|
|
18600
|
+
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
18601
|
+
}
|
|
17902
18602
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
17903
18603
|
async setBlockVisibleAt(pos, visible) {
|
|
17904
18604
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -18002,7 +18702,7 @@ var Chunk = class _Chunk {
|
|
|
18002
18702
|
if (block && !block.object) origins.set(kind, block.block.type);
|
|
18003
18703
|
}
|
|
18004
18704
|
if (origins.size) {
|
|
18005
|
-
fluids = { cells: new Uint8Array(18 * 18 * 18) };
|
|
18705
|
+
fluids = { cells: new Uint8Array(18 * 18 * 18), waterTints: this.waterTints?.slice() };
|
|
18006
18706
|
for (let y = -1; y <= 16; y++) {
|
|
18007
18707
|
for (let z = -1; z <= 16; z++) {
|
|
18008
18708
|
for (let x = -1; x <= 16; x++) {
|
|
@@ -18033,7 +18733,7 @@ var Chunk = class _Chunk {
|
|
|
18033
18733
|
/** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
|
|
18034
18734
|
async clear(notify = true) {
|
|
18035
18735
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
18036
|
-
new
|
|
18736
|
+
new Vector318(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
18037
18737
|
)) : [];
|
|
18038
18738
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
18039
18739
|
this.sectionBlocks.clear();
|
|
@@ -18044,8 +18744,13 @@ var Chunk = class _Chunk {
|
|
|
18044
18744
|
this.renderedBlocks.clear();
|
|
18045
18745
|
this.hiddenBlocks.clear();
|
|
18046
18746
|
this.fluidCells.fill(0);
|
|
18747
|
+
this.waterTints = void 0;
|
|
18047
18748
|
this.data.clear();
|
|
18048
|
-
|
|
18749
|
+
this.biomes = void 0;
|
|
18750
|
+
if (notify) {
|
|
18751
|
+
await this.onBiomesChanged?.(void 0);
|
|
18752
|
+
await this.onBlocksChanged?.(positions);
|
|
18753
|
+
}
|
|
18049
18754
|
}
|
|
18050
18755
|
async dispose() {
|
|
18051
18756
|
await this.clear();
|
|
@@ -18061,14 +18766,14 @@ var Chunk = class _Chunk {
|
|
|
18061
18766
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
18062
18767
|
}
|
|
18063
18768
|
worldPosToChunkPos(pos) {
|
|
18064
|
-
return new
|
|
18769
|
+
return new Vector318(
|
|
18065
18770
|
pos.x - this.x * 16,
|
|
18066
18771
|
pos.y - this.y * 16,
|
|
18067
18772
|
pos.z - this.z * 16
|
|
18068
18773
|
);
|
|
18069
18774
|
}
|
|
18070
18775
|
chunkPosToWorldPos(pos) {
|
|
18071
|
-
return new
|
|
18776
|
+
return new Vector318(
|
|
18072
18777
|
this.x * 16 + pos.x,
|
|
18073
18778
|
this.y * 16 + pos.y,
|
|
18074
18779
|
this.z * 16 + pos.z
|
|
@@ -18266,6 +18971,7 @@ export {
|
|
|
18266
18971
|
BannerPatterns,
|
|
18267
18972
|
BasicAssetKey,
|
|
18268
18973
|
BatchedExecutor,
|
|
18974
|
+
Biomes,
|
|
18269
18975
|
BlockEntities,
|
|
18270
18976
|
BlockObject,
|
|
18271
18977
|
BlockStateResolver,
|
|
@@ -18299,6 +19005,7 @@ export {
|
|
|
18299
19005
|
EntityObject,
|
|
18300
19006
|
Env,
|
|
18301
19007
|
FluidModelObject,
|
|
19008
|
+
FlyControls,
|
|
18302
19009
|
Fonts,
|
|
18303
19010
|
GUI_CONTAINER_LAYOUTS,
|
|
18304
19011
|
Geometries,
|
|
@@ -18401,6 +19108,7 @@ export {
|
|
|
18401
19108
|
isDisposable,
|
|
18402
19109
|
isDoubleArray,
|
|
18403
19110
|
isEntityObject,
|
|
19111
|
+
isFlyControls,
|
|
18404
19112
|
isGuiObject,
|
|
18405
19113
|
isInstanceManager,
|
|
18406
19114
|
isInstanceReference,
|