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/node/index.mjs
CHANGED
|
@@ -323,6 +323,9 @@ var init_Caching = __esm({
|
|
|
323
323
|
static {
|
|
324
324
|
this.usernameUuidCache = Caches.builder().expireAfterWrite(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
325
325
|
}
|
|
326
|
+
static {
|
|
327
|
+
this.biomeCache = _Caching.createAssetCache();
|
|
328
|
+
}
|
|
326
329
|
static createAssetCache() {
|
|
327
330
|
return Caches.builder().expireAfterWrite(Time.minutes(10)).expireAfterAccess(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
328
331
|
}
|
|
@@ -352,7 +355,8 @@ var init_Caching = __esm({
|
|
|
352
355
|
this.fontCache,
|
|
353
356
|
this.bannerPatternCache,
|
|
354
357
|
this.mineRenderDataCache,
|
|
355
|
-
this.usernameUuidCache
|
|
358
|
+
this.usernameUuidCache,
|
|
359
|
+
this.biomeCache
|
|
356
360
|
];
|
|
357
361
|
}
|
|
358
362
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
@@ -1730,7 +1734,7 @@ ${key}` : key, async () => {
|
|
|
1730
1734
|
case "blockStates":
|
|
1731
1735
|
return Object.values(value).every((property) => object(property) && "default" in property && Array.isArray(property.values));
|
|
1732
1736
|
case "blockTints":
|
|
1733
|
-
return ["constant", "grass", "stem", "redstone"].includes(value.source) && (value.source !== "constant" || Number.isInteger(value.color));
|
|
1737
|
+
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));
|
|
1734
1738
|
case "fluids":
|
|
1735
1739
|
return ["water", "lava"].includes(value.kind) && typeof value.renderModel === "boolean" && (value.levelProperty === void 0 || typeof value.levelProperty === "string");
|
|
1736
1740
|
case "dyes":
|
|
@@ -1874,15 +1878,19 @@ var init_Colormaps = __esm({
|
|
|
1874
1878
|
Colormaps = class {
|
|
1875
1879
|
/** Samples the selected resource pack's grass colormap using Minecraft's climate coordinates. */
|
|
1876
1880
|
static async grassColor(origin, temperature = 0.5, downfall = 1) {
|
|
1877
|
-
|
|
1881
|
+
return this.getColor("grass", origin, temperature, downfall);
|
|
1882
|
+
}
|
|
1883
|
+
/** Samples a resource-pack colormap at the supplied climate coordinates. */
|
|
1884
|
+
static async getColor(kind, origin, temperature = 0.5, downfall = 1) {
|
|
1885
|
+
const key = AssetKey.parse("textures", `minecraft:colormap/${kind}`, origin);
|
|
1878
1886
|
const temp = Math.fround(temperature);
|
|
1879
1887
|
const rain = Math.fround(downfall) * temp;
|
|
1880
1888
|
const x = Math.floor((1 - temp) * 255), y = Math.floor((1 - rain) * 255);
|
|
1881
1889
|
return await Caching.blockTintCache.get(`${key.serialize()}|${x},${y}`, async () => {
|
|
1882
1890
|
const image = await ModelTextures.get(key);
|
|
1883
|
-
if (!image) throw new MineRenderError(`Missing
|
|
1891
|
+
if (!image) throw new MineRenderError(`Missing ${kind} colormap: ${key.toNamespacedString()}`);
|
|
1884
1892
|
if (image.width !== 256 || image.height !== 256) {
|
|
1885
|
-
throw new MineRenderError(
|
|
1893
|
+
throw new MineRenderError(`${kind} colormaps must be 256 \xD7 256 pixels`);
|
|
1886
1894
|
}
|
|
1887
1895
|
const [red, green, blue] = image.data.getImageData(x, y, 1, 1).data;
|
|
1888
1896
|
return red << 16 | green << 8 | blue;
|
|
@@ -7751,6 +7759,116 @@ init_AssetLoader();
|
|
|
7751
7759
|
init_Assets();
|
|
7752
7760
|
init_BannerPatterns();
|
|
7753
7761
|
|
|
7762
|
+
// src/assets/Biomes.ts
|
|
7763
|
+
init_AssetKey();
|
|
7764
|
+
init_AssetLoader();
|
|
7765
|
+
init_AssetParsers();
|
|
7766
|
+
init_Caching();
|
|
7767
|
+
init_MineRenderError();
|
|
7768
|
+
init_Colormaps();
|
|
7769
|
+
|
|
7770
|
+
// src/assets/_biomes/SwampGrassColor.ts
|
|
7771
|
+
var permutation;
|
|
7772
|
+
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]];
|
|
7773
|
+
var skew = (Math.sqrt(3) - 1) / 2;
|
|
7774
|
+
var unskew = (3 - Math.sqrt(3)) / 6;
|
|
7775
|
+
function createPermutation() {
|
|
7776
|
+
const multiplier = 0x5deece66dn, mask = (1n << 48n) - 1n;
|
|
7777
|
+
let seed = 2345n ^ multiplier;
|
|
7778
|
+
const next = (bits) => {
|
|
7779
|
+
seed = seed * multiplier + 11n & mask;
|
|
7780
|
+
return Number(seed >> BigInt(48 - bits));
|
|
7781
|
+
};
|
|
7782
|
+
for (let i = 0; i < 3; i++) {
|
|
7783
|
+
next(26);
|
|
7784
|
+
next(27);
|
|
7785
|
+
}
|
|
7786
|
+
const values = Uint8Array.from({ length: 256 }, (_, i) => i);
|
|
7787
|
+
for (let i = 0; i < 256; i++) {
|
|
7788
|
+
const bound = 256 - i;
|
|
7789
|
+
let offset;
|
|
7790
|
+
if ((bound & bound - 1) === 0) offset = Math.floor(bound * next(31) / 2147483648);
|
|
7791
|
+
else {
|
|
7792
|
+
let bits;
|
|
7793
|
+
do {
|
|
7794
|
+
bits = next(31);
|
|
7795
|
+
offset = bits % bound;
|
|
7796
|
+
} while (bits - offset + bound - 1 > 2147483647);
|
|
7797
|
+
}
|
|
7798
|
+
const other = i + offset;
|
|
7799
|
+
[values[i], values[other]] = [values[other], values[i]];
|
|
7800
|
+
}
|
|
7801
|
+
return values;
|
|
7802
|
+
}
|
|
7803
|
+
function swampGrassColor(x, z) {
|
|
7804
|
+
const p10 = permutation ??= createPermutation();
|
|
7805
|
+
x *= 0.0225;
|
|
7806
|
+
z *= 0.0225;
|
|
7807
|
+
const s = (x + z) * skew;
|
|
7808
|
+
const i = Math.floor(x + s), j = Math.floor(z + s);
|
|
7809
|
+
const t = (i + j) * unskew;
|
|
7810
|
+
const dx = x - (i - t), dz = z - (j - t);
|
|
7811
|
+
const stepX = dx > dz ? 1 : 0, stepZ = 1 - stepX;
|
|
7812
|
+
const corner = (gx, gz, a, b) => {
|
|
7813
|
+
let falloff = 0.5 - a * a - b * b;
|
|
7814
|
+
if (falloff < 0) return 0;
|
|
7815
|
+
const gradient = gradients[p10[gx + p10[gz & 255] & 255] % 12];
|
|
7816
|
+
falloff *= falloff;
|
|
7817
|
+
return falloff * falloff * (gradient[0] * a + gradient[1] * b);
|
|
7818
|
+
};
|
|
7819
|
+
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));
|
|
7820
|
+
return noise < -0.1 ? 5011004 : 6975545;
|
|
7821
|
+
}
|
|
7822
|
+
|
|
7823
|
+
// src/assets/Biomes.ts
|
|
7824
|
+
var Biomes = class {
|
|
7825
|
+
/** Loads a biome registry entry, or returns `undefined` when no source provides it. */
|
|
7826
|
+
static async get(id, origin) {
|
|
7827
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(id)) throw new MineRenderError(`Invalid biome identifier: ${id}`);
|
|
7828
|
+
const [namespace, path] = id.includes(":") ? id.split(":") : ["minecraft", id];
|
|
7829
|
+
const key = new AssetKey(namespace, path, "worldgen", "biome", "data", ".json", origin?.root);
|
|
7830
|
+
return Caching.biomeCache.get(key.serialize(), async () => {
|
|
7831
|
+
const asset2 = await AssetLoader.get(key, "json" /* JSON */);
|
|
7832
|
+
if (asset2 === void 0) return void 0;
|
|
7833
|
+
if (!asset2 || typeof asset2 !== "object" || Array.isArray(asset2) || !asset2.effects || typeof asset2.effects !== "object" || Array.isArray(asset2.effects)) {
|
|
7834
|
+
throw new MineRenderError(`Invalid biome effects: ${id}`);
|
|
7835
|
+
}
|
|
7836
|
+
if (typeof asset2.temperature !== "number" || !Number.isFinite(asset2.temperature) || typeof asset2.downfall !== "number" || !Number.isFinite(asset2.downfall)) {
|
|
7837
|
+
throw new MineRenderError(`Invalid biome climate: ${id}`);
|
|
7838
|
+
}
|
|
7839
|
+
for (const kind of ["grass", "foliage", "dry_foliage", "water"]) {
|
|
7840
|
+
const color2 = asset2.effects[`${kind}_color`];
|
|
7841
|
+
if (color2 !== void 0) this.parseColor(color2, id, kind);
|
|
7842
|
+
}
|
|
7843
|
+
const modifier = asset2.effects.grass_color_modifier;
|
|
7844
|
+
if (modifier !== void 0 && modifier !== "none" && modifier !== "dark_forest" && modifier !== "swamp") {
|
|
7845
|
+
throw new MineRenderError(`Invalid biome grass color modifier: ${id}`);
|
|
7846
|
+
}
|
|
7847
|
+
return asset2;
|
|
7848
|
+
});
|
|
7849
|
+
}
|
|
7850
|
+
/** Returns packed sRGB, or `undefined` when the biome or requested water color is missing. */
|
|
7851
|
+
static async getColor(id, kind, origin, x = 0, z = 0) {
|
|
7852
|
+
const biome = await this.get(id, origin);
|
|
7853
|
+
if (!biome) return void 0;
|
|
7854
|
+
const rawColor = biome.effects[`${kind}_color`];
|
|
7855
|
+
let color2 = rawColor === void 0 ? void 0 : this.parseColor(rawColor, id, kind);
|
|
7856
|
+
if (kind === "water") return color2;
|
|
7857
|
+
const modifier = kind === "grass" ? biome.effects.grass_color_modifier : void 0;
|
|
7858
|
+
if (modifier === "swamp") return swampGrassColor(x, z);
|
|
7859
|
+
if (color2 === void 0) {
|
|
7860
|
+
const clamp = (value) => Math.max(0, Math.min(1, Math.fround(value)));
|
|
7861
|
+
color2 = await Colormaps.getColor(kind, origin, clamp(biome.temperature), clamp(biome.downfall));
|
|
7862
|
+
}
|
|
7863
|
+
return modifier === "dark_forest" ? (color2 & 16711422) + 2634762 >> 1 : color2;
|
|
7864
|
+
}
|
|
7865
|
+
static parseColor(value, id, kind) {
|
|
7866
|
+
if (typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value)) return parseInt(value.slice(1), 16);
|
|
7867
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 16777215) return value;
|
|
7868
|
+
throw new MineRenderError(`Invalid biome ${kind} color: ${id}`);
|
|
7869
|
+
}
|
|
7870
|
+
};
|
|
7871
|
+
|
|
7754
7872
|
// src/assets/BlockEntities.ts
|
|
7755
7873
|
init_AssetKey();
|
|
7756
7874
|
init_AssetLoader();
|
|
@@ -12230,8 +12348,20 @@ var BlockStateResolver = class _BlockStateResolver {
|
|
|
12230
12348
|
init_Colormaps();
|
|
12231
12349
|
init_MineRenderData();
|
|
12232
12350
|
var BlockTints = class {
|
|
12233
|
-
/**
|
|
12234
|
-
static async
|
|
12351
|
+
/** Returns a block's versioned biome color source, leaving fixed-color blocks unchanged. */
|
|
12352
|
+
static async biomeSource(key) {
|
|
12353
|
+
const rule = key && (await MineRenderData.get("blockTints", key.root))[key.toNamespacedString()];
|
|
12354
|
+
return rule ? rule.biome ?? (rule.source === "grass" ? "grass" : void 0) : void 0;
|
|
12355
|
+
}
|
|
12356
|
+
/** Resolves one block's biome tint at world block coordinates, without biome blending. */
|
|
12357
|
+
static async getBiomeColor(key, biome, position) {
|
|
12358
|
+
if (!biome) return void 0;
|
|
12359
|
+
const x = position?.[0], z = position?.[2];
|
|
12360
|
+
const source = await this.biomeSource(key);
|
|
12361
|
+
return source ? Biomes.getColor(biome, source, key, x, z) : void 0;
|
|
12362
|
+
}
|
|
12363
|
+
/** Resolves used tint indices from biome or preview colors; explicit tints take precedence. */
|
|
12364
|
+
static async get(key, state, model, tints, biomeColor) {
|
|
12235
12365
|
if (!key) return tints;
|
|
12236
12366
|
const candidates = (model.elements ?? []).flatMap((element) => Object.values(element.faces)).some((face) => face?.tintindex !== void 0 && face.tintindex >= 0 && tints?.[face.tintindex] === void 0);
|
|
12237
12367
|
if (!candidates) return tints;
|
|
@@ -12247,8 +12377,12 @@ var BlockTints = class {
|
|
|
12247
12377
|
}
|
|
12248
12378
|
}
|
|
12249
12379
|
if (!indices.size) return tints;
|
|
12380
|
+
const source = rule.biome ?? (rule.source === "grass" ? "grass" : void 0);
|
|
12381
|
+
const biome = source ? typeof biomeColor === "function" ? await biomeColor() : biomeColor : void 0;
|
|
12250
12382
|
let color2;
|
|
12251
|
-
|
|
12383
|
+
if (biome !== void 0) {
|
|
12384
|
+
color2 = biome;
|
|
12385
|
+
} else switch (rule.source) {
|
|
12252
12386
|
case "constant":
|
|
12253
12387
|
color2 = rule.color;
|
|
12254
12388
|
break;
|
|
@@ -12307,6 +12441,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12307
12441
|
this._entityGeneration = 0;
|
|
12308
12442
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
12309
12443
|
this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
|
|
12444
|
+
this.biomePosition = options?.biomePosition ? [...options.biomePosition] : void 0;
|
|
12310
12445
|
}
|
|
12311
12446
|
static {
|
|
12312
12447
|
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge6.default)({}, ModelObject.DEFAULT_OPTIONS, {
|
|
@@ -12504,11 +12639,16 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12504
12639
|
const { FluidModelObject: FluidModelObject2, sampleFluid: sampleFluid2 } = await Promise.resolve().then(() => (init_FluidModelObject(), FluidModelObject_exports));
|
|
12505
12640
|
this._fluidSampler = sample;
|
|
12506
12641
|
const surface = sampleFluid2(kind, (x, y, z) => x === 0 && y === 0 && z === 0 ? { fluid: kind, level: this.fluidLevel } : sample?.(x, y, z) ?? {});
|
|
12507
|
-
|
|
12642
|
+
const tint = this.options.tints?.[0] ?? this.waterTint;
|
|
12643
|
+
const fluidKey = `${surface.key}|${tint ?? "default"}`;
|
|
12644
|
+
if (this._fluidKey === fluidKey) return;
|
|
12508
12645
|
const key = new AssetKey("minecraft", `${kind}/${surface.key}`, "models", "fluid", "assets", ".json", this.blockState.key?.root);
|
|
12509
12646
|
const replacement = await this.scene.addSceneObject(
|
|
12510
12647
|
{ key },
|
|
12511
|
-
() => new FluidModelObject2(kind, surface.sample, this.blockState.key,
|
|
12648
|
+
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, {
|
|
12649
|
+
...this.options,
|
|
12650
|
+
tints: tint === void 0 ? this.options.tints : { ...this.options.tints, 0: tint }
|
|
12651
|
+
})
|
|
12512
12652
|
);
|
|
12513
12653
|
const previous = this._fluidModel;
|
|
12514
12654
|
const matrix = previous ? this.getModelMatrix(previous) : new Matrix411().makeTranslation(...this.position.toArray());
|
|
@@ -12517,7 +12657,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12517
12657
|
this._models = this._models.filter((model) => model !== previous);
|
|
12518
12658
|
this._models.push(replacement);
|
|
12519
12659
|
this._fluidModel = replacement;
|
|
12520
|
-
this._fluidKey =
|
|
12660
|
+
this._fluidKey = fluidKey;
|
|
12521
12661
|
this._isInstanced ||= isInstanceReference(replacement);
|
|
12522
12662
|
this._instanceCounter = this._isInstanced ? 1 : 0;
|
|
12523
12663
|
if (previous) this.removeModels([previous]);
|
|
@@ -12540,6 +12680,7 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12540
12680
|
}
|
|
12541
12681
|
async recreateModels() {
|
|
12542
12682
|
this.clearModels();
|
|
12683
|
+
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;
|
|
12543
12684
|
if (resolveBlockFluidState(this.blockState.key, this.state, this._fluidRules)?.renderModel === false) {
|
|
12544
12685
|
await this.updateFluid(this._fluidSampler);
|
|
12545
12686
|
return;
|
|
@@ -12574,7 +12715,13 @@ var BlockObject = class _BlockObject extends SceneObject {
|
|
|
12574
12715
|
const model = await Models.getMerged(modelKey);
|
|
12575
12716
|
const options = {
|
|
12576
12717
|
...this.options,
|
|
12577
|
-
tints: model ? await BlockTints.get(
|
|
12718
|
+
tints: model ? await BlockTints.get(
|
|
12719
|
+
this.blockState.key,
|
|
12720
|
+
this.state,
|
|
12721
|
+
model,
|
|
12722
|
+
this.options.tints,
|
|
12723
|
+
() => BlockTints.getBiomeColor(this.blockState.key, this.options.biome, this.biomePosition)
|
|
12724
|
+
) : this.options.tints,
|
|
12578
12725
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0,
|
|
12579
12726
|
cullMask: this.options.displayPosition ? 0 : ModelCulling.toLocalMask(this._cullMask, rotation)
|
|
12580
12727
|
};
|
|
@@ -13157,6 +13304,321 @@ init_ModelObject();
|
|
|
13157
13304
|
// src/index.ts
|
|
13158
13305
|
init_nbt();
|
|
13159
13306
|
|
|
13307
|
+
// src/renderer/FlyControls.ts
|
|
13308
|
+
import { Controls, Euler as Euler11, MathUtils as MathUtils2, Quaternion as Quaternion6, Vector3 as Vector313 } from "three";
|
|
13309
|
+
var VANILLA_FLY_SPEED = 10.89;
|
|
13310
|
+
var PITCH_LIMIT = Math.PI / 2;
|
|
13311
|
+
var MOVE_EPSILON = 1e-6;
|
|
13312
|
+
var _euler = new Euler11(0, 0, 0, "YXZ");
|
|
13313
|
+
var _forward = new Vector313();
|
|
13314
|
+
var _right = new Vector313();
|
|
13315
|
+
var _targetVelocity = new Vector313();
|
|
13316
|
+
var FlyControls = class extends Controls {
|
|
13317
|
+
constructor(camera, domElement) {
|
|
13318
|
+
super(camera, domElement ?? null);
|
|
13319
|
+
this.isFlyControls = true;
|
|
13320
|
+
/** Horizontal and vertical speed in scene units per second; vanilla creative flight by default. */
|
|
13321
|
+
this.movementSpeed = 16 * VANILLA_FLY_SPEED;
|
|
13322
|
+
/** Speed multiplier while the sprint key is held. */
|
|
13323
|
+
this.sprintMultiplier = 2;
|
|
13324
|
+
/** Radians per pixel of pointer movement. */
|
|
13325
|
+
this.lookSpeed = 2e-3;
|
|
13326
|
+
/** Smooth acceleration and deceleration, approximating vanilla flight momentum. */
|
|
13327
|
+
this.enableDamping = true;
|
|
13328
|
+
/** Portion of the remaining velocity change applied per 60 Hz frame (0–1) when damping is enabled. */
|
|
13329
|
+
this.dampingFactor = 0.25;
|
|
13330
|
+
/** Capture the pointer on click so the mouse turns the camera without dragging; dragging works regardless. */
|
|
13331
|
+
this.pointerLock = true;
|
|
13332
|
+
/** Scroll the wheel to change `movementSpeed` within `speedRange`. */
|
|
13333
|
+
this.enableWheelSpeed = true;
|
|
13334
|
+
/** Minimum and maximum `movementSpeed` reachable with the wheel. */
|
|
13335
|
+
this.speedRange = [16, 16 * 500];
|
|
13336
|
+
/** Touch joystick travel in CSS pixels for full speed. */
|
|
13337
|
+
this.joystickRadius = 64;
|
|
13338
|
+
/** Key bindings by `KeyboardEvent.code`. */
|
|
13339
|
+
this.keys = {
|
|
13340
|
+
forward: ["KeyW", "ArrowUp"],
|
|
13341
|
+
back: ["KeyS", "ArrowDown"],
|
|
13342
|
+
left: ["KeyA", "ArrowLeft"],
|
|
13343
|
+
right: ["KeyD", "ArrowRight"],
|
|
13344
|
+
up: ["Space"],
|
|
13345
|
+
down: ["ShiftLeft", "ShiftRight"],
|
|
13346
|
+
sprint: ["ControlLeft", "ControlRight"]
|
|
13347
|
+
};
|
|
13348
|
+
this._pressed = /* @__PURE__ */ new Set();
|
|
13349
|
+
this._velocity = new Vector313();
|
|
13350
|
+
this._lastPosition = new Vector313();
|
|
13351
|
+
this._lastQuaternion = new Quaternion6();
|
|
13352
|
+
this._position0 = new Vector313();
|
|
13353
|
+
this._quaternion0 = new Quaternion6();
|
|
13354
|
+
this._dragMoved = false;
|
|
13355
|
+
this._locked = false;
|
|
13356
|
+
this._onKeyDown = (event) => this.handleKey(event, true);
|
|
13357
|
+
this._onKeyUp = (event) => this.handleKey(event, false);
|
|
13358
|
+
this._onPointerDown = (event) => this.handlePointerDown(event);
|
|
13359
|
+
this._onPointerMove = (event) => this.handlePointerMove(event);
|
|
13360
|
+
this._onPointerUp = (event) => this.handlePointerUp(event);
|
|
13361
|
+
this._onPointerLockChange = () => this.handlePointerLockChange();
|
|
13362
|
+
this._onContextMenu = (event) => event.preventDefault();
|
|
13363
|
+
this._onWheel = (event) => this.handleWheel(event);
|
|
13364
|
+
this._onBlur = () => this.releaseKeys();
|
|
13365
|
+
this._lastPosition.copy(camera.position);
|
|
13366
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13367
|
+
this.saveState();
|
|
13368
|
+
if (domElement) this.connect(domElement);
|
|
13369
|
+
}
|
|
13370
|
+
connect(element) {
|
|
13371
|
+
super.connect(element);
|
|
13372
|
+
const document2 = element.ownerDocument;
|
|
13373
|
+
document2.addEventListener("keydown", this._onKeyDown);
|
|
13374
|
+
document2.addEventListener("keyup", this._onKeyUp);
|
|
13375
|
+
document2.addEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13376
|
+
document2.defaultView?.addEventListener("blur", this._onBlur);
|
|
13377
|
+
element.addEventListener("pointerdown", this._onPointerDown);
|
|
13378
|
+
element.addEventListener("pointermove", this._onPointerMove);
|
|
13379
|
+
element.addEventListener("pointerup", this._onPointerUp);
|
|
13380
|
+
element.addEventListener("pointercancel", this._onPointerUp);
|
|
13381
|
+
element.addEventListener("contextmenu", this._onContextMenu);
|
|
13382
|
+
element.addEventListener("wheel", this._onWheel, { passive: false });
|
|
13383
|
+
element.addEventListener("blur", this._onBlur);
|
|
13384
|
+
element.style.touchAction = "none";
|
|
13385
|
+
if (element.tabIndex < 0) element.tabIndex = 0;
|
|
13386
|
+
}
|
|
13387
|
+
disconnect() {
|
|
13388
|
+
const element = this.domElement;
|
|
13389
|
+
if (!element) return;
|
|
13390
|
+
const document2 = element.ownerDocument;
|
|
13391
|
+
document2.removeEventListener("keydown", this._onKeyDown);
|
|
13392
|
+
document2.removeEventListener("keyup", this._onKeyUp);
|
|
13393
|
+
document2.removeEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13394
|
+
document2.defaultView?.removeEventListener("blur", this._onBlur);
|
|
13395
|
+
element.removeEventListener("pointerdown", this._onPointerDown);
|
|
13396
|
+
element.removeEventListener("pointermove", this._onPointerMove);
|
|
13397
|
+
element.removeEventListener("pointerup", this._onPointerUp);
|
|
13398
|
+
element.removeEventListener("pointercancel", this._onPointerUp);
|
|
13399
|
+
element.removeEventListener("contextmenu", this._onContextMenu);
|
|
13400
|
+
element.removeEventListener("wheel", this._onWheel);
|
|
13401
|
+
element.removeEventListener("blur", this._onBlur);
|
|
13402
|
+
element.style.touchAction = "auto";
|
|
13403
|
+
this.unlock();
|
|
13404
|
+
this._locked = false;
|
|
13405
|
+
this.releaseKeys();
|
|
13406
|
+
this._dragPointer = void 0;
|
|
13407
|
+
this._joystick = void 0;
|
|
13408
|
+
}
|
|
13409
|
+
dispose() {
|
|
13410
|
+
this.disconnect();
|
|
13411
|
+
}
|
|
13412
|
+
/** Whether mouse look currently owns the pointer. */
|
|
13413
|
+
get locked() {
|
|
13414
|
+
return this._locked;
|
|
13415
|
+
}
|
|
13416
|
+
/** Requests pointer capture; browsers only allow this from a user gesture. */
|
|
13417
|
+
lock() {
|
|
13418
|
+
const element = this.domElement;
|
|
13419
|
+
if (!element || this._locked || typeof element.requestPointerLock !== "function") return;
|
|
13420
|
+
try {
|
|
13421
|
+
const result = element.requestPointerLock();
|
|
13422
|
+
if (result instanceof Promise) result.catch(() => void 0);
|
|
13423
|
+
} catch {
|
|
13424
|
+
}
|
|
13425
|
+
}
|
|
13426
|
+
/** Releases a captured pointer. */
|
|
13427
|
+
unlock() {
|
|
13428
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13429
|
+
if (document2?.pointerLockElement && document2.pointerLockElement === this.domElement) {
|
|
13430
|
+
document2.exitPointerLock();
|
|
13431
|
+
}
|
|
13432
|
+
}
|
|
13433
|
+
/** Stores the camera pose that {@link reset} restores. */
|
|
13434
|
+
saveState() {
|
|
13435
|
+
this._position0.copy(this.object.position);
|
|
13436
|
+
this._quaternion0.copy(this.object.quaternion);
|
|
13437
|
+
}
|
|
13438
|
+
/** Restores the saved camera pose and stops movement. */
|
|
13439
|
+
reset() {
|
|
13440
|
+
this.object.position.copy(this._position0);
|
|
13441
|
+
this.object.quaternion.copy(this._quaternion0);
|
|
13442
|
+
this._velocity.set(0, 0, 0);
|
|
13443
|
+
this.notifyChange();
|
|
13444
|
+
}
|
|
13445
|
+
/** Horizontal yaw in radians, where zero looks toward -Z. */
|
|
13446
|
+
get yaw() {
|
|
13447
|
+
return _euler.setFromQuaternion(this.object.quaternion).y;
|
|
13448
|
+
}
|
|
13449
|
+
/** Vertical pitch in radians, positive looking up. */
|
|
13450
|
+
get pitch() {
|
|
13451
|
+
return _euler.setFromQuaternion(this.object.quaternion).x;
|
|
13452
|
+
}
|
|
13453
|
+
/** Turns the camera; pitch is clamped to straight up and down. */
|
|
13454
|
+
setRotation(yaw, pitch) {
|
|
13455
|
+
_euler.set(MathUtils2.clamp(pitch, -PITCH_LIMIT, PITCH_LIMIT), yaw, 0);
|
|
13456
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13457
|
+
this.notifyChange();
|
|
13458
|
+
}
|
|
13459
|
+
/** Points the camera at a position without rolling it. */
|
|
13460
|
+
lookAt(target) {
|
|
13461
|
+
_forward.copy(target).sub(this.object.position);
|
|
13462
|
+
if (_forward.lengthSq() < MOVE_EPSILON) return;
|
|
13463
|
+
_forward.normalize();
|
|
13464
|
+
this.setRotation(Math.atan2(-_forward.x, -_forward.z), Math.asin(MathUtils2.clamp(_forward.y, -1, 1)));
|
|
13465
|
+
}
|
|
13466
|
+
/** Whether an action's key is held. */
|
|
13467
|
+
isPressed(action) {
|
|
13468
|
+
return this._pressed.has(action);
|
|
13469
|
+
}
|
|
13470
|
+
/**
|
|
13471
|
+
* Advances movement by `delta` seconds (measured since the previous call when omitted)
|
|
13472
|
+
* and dispatches `change` when the camera moved.
|
|
13473
|
+
*/
|
|
13474
|
+
update(delta) {
|
|
13475
|
+
if (delta === void 0) {
|
|
13476
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
13477
|
+
delta = this._lastTime === void 0 ? 0 : (now - this._lastTime) / 1e3;
|
|
13478
|
+
this._lastTime = now;
|
|
13479
|
+
}
|
|
13480
|
+
if (!this.enabled) {
|
|
13481
|
+
this._velocity.set(0, 0, 0);
|
|
13482
|
+
return;
|
|
13483
|
+
}
|
|
13484
|
+
if (delta > 0) this.move(delta);
|
|
13485
|
+
this.notifyChange();
|
|
13486
|
+
}
|
|
13487
|
+
move(delta) {
|
|
13488
|
+
const camera = this.object;
|
|
13489
|
+
let forward = (this._pressed.has("forward") ? 1 : 0) - (this._pressed.has("back") ? 1 : 0);
|
|
13490
|
+
let strafe = (this._pressed.has("right") ? 1 : 0) - (this._pressed.has("left") ? 1 : 0);
|
|
13491
|
+
const climb = (this._pressed.has("up") ? 1 : 0) - (this._pressed.has("down") ? 1 : 0);
|
|
13492
|
+
const joystick = this._joystick;
|
|
13493
|
+
if (joystick) {
|
|
13494
|
+
const radius = Math.max(this.joystickRadius, 1);
|
|
13495
|
+
forward = MathUtils2.clamp(forward + (joystick.originY - joystick.y) / radius, -1, 1);
|
|
13496
|
+
strafe = MathUtils2.clamp(strafe + (joystick.x - joystick.originX) / radius, -1, 1);
|
|
13497
|
+
}
|
|
13498
|
+
_euler.setFromQuaternion(camera.quaternion);
|
|
13499
|
+
const yaw = _euler.y;
|
|
13500
|
+
_forward.set(-Math.sin(yaw), 0, -Math.cos(yaw));
|
|
13501
|
+
_right.set(Math.cos(yaw), 0, -Math.sin(yaw));
|
|
13502
|
+
_targetVelocity.set(0, 0, 0);
|
|
13503
|
+
if (forward || strafe || climb) {
|
|
13504
|
+
_targetVelocity.addScaledVector(_forward, forward).addScaledVector(_right, strafe);
|
|
13505
|
+
if (_targetVelocity.lengthSq() > 1) _targetVelocity.normalize();
|
|
13506
|
+
_targetVelocity.y = climb;
|
|
13507
|
+
const speed = this.movementSpeed * (this._pressed.has("sprint") ? this.sprintMultiplier : 1);
|
|
13508
|
+
_targetVelocity.multiplyScalar(speed);
|
|
13509
|
+
}
|
|
13510
|
+
if (this.enableDamping) {
|
|
13511
|
+
const blend = 1 - Math.pow(1 - MathUtils2.clamp(this.dampingFactor, 0, 1), delta * 60);
|
|
13512
|
+
this._velocity.lerp(_targetVelocity, blend);
|
|
13513
|
+
if (_targetVelocity.lengthSq() === 0 && this._velocity.lengthSq() < MOVE_EPSILON) this._velocity.set(0, 0, 0);
|
|
13514
|
+
} else {
|
|
13515
|
+
this._velocity.copy(_targetVelocity);
|
|
13516
|
+
}
|
|
13517
|
+
camera.position.addScaledVector(this._velocity, delta);
|
|
13518
|
+
}
|
|
13519
|
+
notifyChange() {
|
|
13520
|
+
const camera = this.object;
|
|
13521
|
+
if (this._lastPosition.distanceToSquared(camera.position) > MOVE_EPSILON || 8 * (1 - this._lastQuaternion.dot(camera.quaternion)) > MOVE_EPSILON) {
|
|
13522
|
+
this._lastPosition.copy(camera.position);
|
|
13523
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13524
|
+
this.dispatchEvent({ type: "change" });
|
|
13525
|
+
}
|
|
13526
|
+
}
|
|
13527
|
+
releaseKeys() {
|
|
13528
|
+
this._pressed.clear();
|
|
13529
|
+
}
|
|
13530
|
+
handleKey(event, down) {
|
|
13531
|
+
const action = this.actionFor(event.code);
|
|
13532
|
+
if (!action) return;
|
|
13533
|
+
const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
|
|
13534
|
+
if (down && !ownsInput) return;
|
|
13535
|
+
const pressed = this._pressed.has(action);
|
|
13536
|
+
if (down) this._pressed.add(action);
|
|
13537
|
+
else this._pressed.delete(action);
|
|
13538
|
+
if (ownsInput || this.enabled && pressed) event.preventDefault();
|
|
13539
|
+
}
|
|
13540
|
+
actionFor(code) {
|
|
13541
|
+
for (const action in this.keys) {
|
|
13542
|
+
if (this.keys[action].includes(code)) return action;
|
|
13543
|
+
}
|
|
13544
|
+
return void 0;
|
|
13545
|
+
}
|
|
13546
|
+
handlePointerDown(event) {
|
|
13547
|
+
const element = this.domElement;
|
|
13548
|
+
if (!this.enabled || !element) return;
|
|
13549
|
+
element.focus?.({ preventScroll: true });
|
|
13550
|
+
if (this._locked) return;
|
|
13551
|
+
if (event.pointerType === "touch" && !this._joystick && this.onJoystickSide(event)) {
|
|
13552
|
+
this._joystick = { id: event.pointerId, originX: event.clientX, originY: event.clientY, x: event.clientX, y: event.clientY };
|
|
13553
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13554
|
+
return;
|
|
13555
|
+
}
|
|
13556
|
+
if (this._dragPointer !== void 0) return;
|
|
13557
|
+
if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
|
|
13558
|
+
this._dragPointer = event.pointerId;
|
|
13559
|
+
this._dragMoved = false;
|
|
13560
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13561
|
+
}
|
|
13562
|
+
onJoystickSide(event) {
|
|
13563
|
+
const rect = this.domElement?.getBoundingClientRect?.();
|
|
13564
|
+
return !!rect && event.clientX < rect.left + rect.width / 2;
|
|
13565
|
+
}
|
|
13566
|
+
handlePointerMove(event) {
|
|
13567
|
+
if (!this.enabled) return;
|
|
13568
|
+
const joystick = this._joystick;
|
|
13569
|
+
if (joystick && event.pointerId === joystick.id) {
|
|
13570
|
+
joystick.x = event.clientX;
|
|
13571
|
+
joystick.y = event.clientY;
|
|
13572
|
+
return;
|
|
13573
|
+
}
|
|
13574
|
+
if (!this._locked && event.pointerId !== this._dragPointer) return;
|
|
13575
|
+
const dx = event.movementX ?? 0;
|
|
13576
|
+
const dy = event.movementY ?? 0;
|
|
13577
|
+
if (!dx && !dy) return;
|
|
13578
|
+
this._dragMoved = true;
|
|
13579
|
+
this.turn(dx, dy);
|
|
13580
|
+
}
|
|
13581
|
+
handlePointerUp(event) {
|
|
13582
|
+
if (this._joystick?.id === event.pointerId) {
|
|
13583
|
+
this._joystick = void 0;
|
|
13584
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13585
|
+
return;
|
|
13586
|
+
}
|
|
13587
|
+
if (event.pointerId !== this._dragPointer) return;
|
|
13588
|
+
this._dragPointer = void 0;
|
|
13589
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13590
|
+
if (this.enabled && this.pointerLock && !this._dragMoved && event.pointerType === "mouse" && event.button === 0) {
|
|
13591
|
+
this.lock();
|
|
13592
|
+
}
|
|
13593
|
+
}
|
|
13594
|
+
handleWheel(event) {
|
|
13595
|
+
if (!this.enabled || !this.enableWheelSpeed) return;
|
|
13596
|
+
event.preventDefault();
|
|
13597
|
+
const steps = event.deltaMode === 0 ? event.deltaY / 100 : event.deltaY;
|
|
13598
|
+
const [min, max] = this.speedRange;
|
|
13599
|
+
this.movementSpeed = MathUtils2.clamp(this.movementSpeed * Math.pow(1.15, -steps), Math.min(min, max), Math.max(min, max));
|
|
13600
|
+
}
|
|
13601
|
+
handlePointerLockChange() {
|
|
13602
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13603
|
+
const locked = !!document2 && document2.pointerLockElement === this.domElement;
|
|
13604
|
+
if (locked === this._locked) return;
|
|
13605
|
+
this._locked = locked;
|
|
13606
|
+
if (!locked) this.releaseKeys();
|
|
13607
|
+
this.dispatchEvent({ type: locked ? "lock" : "unlock" });
|
|
13608
|
+
}
|
|
13609
|
+
turn(dx, dy) {
|
|
13610
|
+
_euler.setFromQuaternion(this.object.quaternion);
|
|
13611
|
+
_euler.y -= dx * this.lookSpeed;
|
|
13612
|
+
_euler.x = MathUtils2.clamp(_euler.x - dy * this.lookSpeed, -PITCH_LIMIT, PITCH_LIMIT);
|
|
13613
|
+
_euler.z = 0;
|
|
13614
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13615
|
+
this.notifyChange();
|
|
13616
|
+
}
|
|
13617
|
+
};
|
|
13618
|
+
function isFlyControls(obj) {
|
|
13619
|
+
return obj?.isFlyControls === true;
|
|
13620
|
+
}
|
|
13621
|
+
|
|
13160
13622
|
// src/renderer/MineRenderScene.ts
|
|
13161
13623
|
init_SceneObject();
|
|
13162
13624
|
var import_ts_deepmerge8 = __toESM(require_dist());
|
|
@@ -14224,7 +14686,7 @@ function isMineRenderScene(obj) {
|
|
|
14224
14686
|
}
|
|
14225
14687
|
|
|
14226
14688
|
// src/renderer/Renderer.ts
|
|
14227
|
-
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as
|
|
14689
|
+
import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFShadowMap, PerspectiveCamera, SRGBColorSpace as SRGBColorSpace7, Vector3 as Vector315, WebGLRenderer } from "three";
|
|
14228
14690
|
var import_ts_deepmerge9 = __toESM(require_dist());
|
|
14229
14691
|
init_util();
|
|
14230
14692
|
init_Model();
|
|
@@ -14236,11 +14698,11 @@ import { EffectComposer, RenderPass } from "postprocessing";
|
|
|
14236
14698
|
import {
|
|
14237
14699
|
EventDispatcher,
|
|
14238
14700
|
MOUSE,
|
|
14239
|
-
Quaternion as
|
|
14701
|
+
Quaternion as Quaternion7,
|
|
14240
14702
|
Spherical,
|
|
14241
14703
|
TOUCH,
|
|
14242
14704
|
Vector2 as Vector26,
|
|
14243
|
-
Vector3 as
|
|
14705
|
+
Vector3 as Vector314
|
|
14244
14706
|
} from "three";
|
|
14245
14707
|
var _changeEvent = { type: "change" };
|
|
14246
14708
|
var _startEvent = { type: "start" };
|
|
@@ -14254,7 +14716,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14254
14716
|
this.domElement = domElement;
|
|
14255
14717
|
this.domElement.style.touchAction = "none";
|
|
14256
14718
|
this.enabled = true;
|
|
14257
|
-
this.target = new
|
|
14719
|
+
this.target = new Vector314();
|
|
14258
14720
|
this.minDistance = 0;
|
|
14259
14721
|
this.maxDistance = Infinity;
|
|
14260
14722
|
this.minZoom = 0;
|
|
@@ -14306,11 +14768,11 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14306
14768
|
state = STATE.NONE;
|
|
14307
14769
|
};
|
|
14308
14770
|
this.update = function() {
|
|
14309
|
-
const offset = new
|
|
14310
|
-
const quat = new
|
|
14771
|
+
const offset = new Vector314();
|
|
14772
|
+
const quat = new Quaternion7().setFromUnitVectors(object4.up, new Vector314(0, 1, 0));
|
|
14311
14773
|
const quatInverse = quat.clone().invert();
|
|
14312
|
-
const lastPosition = new
|
|
14313
|
-
const lastQuaternion = new
|
|
14774
|
+
const lastPosition = new Vector314();
|
|
14775
|
+
const lastQuaternion = new Quaternion7();
|
|
14314
14776
|
const twoPI = 2 * Math.PI;
|
|
14315
14777
|
return function update() {
|
|
14316
14778
|
const position = scope.object.position;
|
|
@@ -14399,7 +14861,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14399
14861
|
const spherical = new Spherical();
|
|
14400
14862
|
const sphericalDelta = new Spherical();
|
|
14401
14863
|
let scale = 1;
|
|
14402
|
-
const panOffset = new
|
|
14864
|
+
const panOffset = new Vector314();
|
|
14403
14865
|
let zoomChanged = false;
|
|
14404
14866
|
const rotateStart = new Vector26();
|
|
14405
14867
|
const rotateEnd = new Vector26();
|
|
@@ -14425,7 +14887,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14425
14887
|
sphericalDelta.phi -= angle;
|
|
14426
14888
|
}
|
|
14427
14889
|
const panLeft = function() {
|
|
14428
|
-
const v = new
|
|
14890
|
+
const v = new Vector314();
|
|
14429
14891
|
return function panLeft2(distance, objectMatrix) {
|
|
14430
14892
|
v.setFromMatrixColumn(objectMatrix, 0);
|
|
14431
14893
|
v.multiplyScalar(-distance);
|
|
@@ -14433,7 +14895,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14433
14895
|
};
|
|
14434
14896
|
}();
|
|
14435
14897
|
const panUp = function() {
|
|
14436
|
-
const v = new
|
|
14898
|
+
const v = new Vector314();
|
|
14437
14899
|
return function panUp2(distance, objectMatrix) {
|
|
14438
14900
|
if (scope.screenSpacePanning === true) {
|
|
14439
14901
|
v.setFromMatrixColumn(objectMatrix, 1);
|
|
@@ -14446,7 +14908,7 @@ var OrbitControls = class extends EventDispatcher {
|
|
|
14446
14908
|
};
|
|
14447
14909
|
}();
|
|
14448
14910
|
const pan = function() {
|
|
14449
|
-
const offset = new
|
|
14911
|
+
const offset = new Vector314();
|
|
14450
14912
|
return function pan2(deltaX, deltaY) {
|
|
14451
14913
|
const element = scope.domElement;
|
|
14452
14914
|
if (scope.object.isPerspectiveCamera) {
|
|
@@ -14957,8 +15419,8 @@ var Renderer = class _Renderer {
|
|
|
14957
15419
|
top: void 0,
|
|
14958
15420
|
bottom: void 0
|
|
14959
15421
|
},
|
|
14960
|
-
position: new
|
|
14961
|
-
lookingAt: new
|
|
15422
|
+
position: new Vector315(50, 50, 50),
|
|
15423
|
+
lookingAt: new Vector315(0, 0, 0)
|
|
14962
15424
|
},
|
|
14963
15425
|
render: {
|
|
14964
15426
|
fpsLimit: 60,
|
|
@@ -14973,7 +15435,8 @@ var Renderer = class _Renderer {
|
|
|
14973
15435
|
enabled: true
|
|
14974
15436
|
},
|
|
14975
15437
|
controls: {
|
|
14976
|
-
enabled: false
|
|
15438
|
+
enabled: false,
|
|
15439
|
+
mode: "orbit"
|
|
14977
15440
|
},
|
|
14978
15441
|
debug: {
|
|
14979
15442
|
grid: false,
|
|
@@ -15041,20 +15504,77 @@ var Renderer = class _Renderer {
|
|
|
15041
15504
|
}
|
|
15042
15505
|
createControls() {
|
|
15043
15506
|
if (!this.options.controls?.enabled) return void 0;
|
|
15044
|
-
|
|
15045
|
-
|
|
15046
|
-
|
|
15507
|
+
return this.createControlsFor(this.options.controls.mode ?? "orbit", this.initialTarget());
|
|
15508
|
+
}
|
|
15509
|
+
initialTarget() {
|
|
15047
15510
|
const target = this.options.camera.lookingAt;
|
|
15048
|
-
if (isVector3(target))
|
|
15511
|
+
if (isVector3(target)) return target.clone();
|
|
15512
|
+
if (isTripleArray(target)) return new Vector315(target[0], target[1], target[2]);
|
|
15513
|
+
return new Vector315();
|
|
15514
|
+
}
|
|
15515
|
+
createControlsFor(mode, target) {
|
|
15516
|
+
let controls;
|
|
15517
|
+
if (mode === "fly") {
|
|
15518
|
+
controls = new FlyControls(this.camera, this.renderer.domElement);
|
|
15519
|
+
controls.lookAt(target);
|
|
15520
|
+
controls.saveState();
|
|
15521
|
+
} else {
|
|
15522
|
+
const position = this.camera.position.clone();
|
|
15523
|
+
controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
15524
|
+
this.camera.position.copy(position);
|
|
15049
15525
|
controls.target.copy(target);
|
|
15050
|
-
|
|
15051
|
-
controls.
|
|
15526
|
+
controls.update();
|
|
15527
|
+
controls.saveState();
|
|
15052
15528
|
}
|
|
15053
|
-
|
|
15054
|
-
controls.saveState();
|
|
15529
|
+
this._controlsTime = void 0;
|
|
15055
15530
|
this.registerEventDispatcher(controls);
|
|
15056
15531
|
return controls;
|
|
15057
15532
|
}
|
|
15533
|
+
/**
|
|
15534
|
+
* Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
|
|
15535
|
+
* Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
|
|
15536
|
+
* Returns the new controls, or undefined when controls were disabled at construction or after disposal.
|
|
15537
|
+
*/
|
|
15538
|
+
setControlsMode(mode) {
|
|
15539
|
+
const current = this._controls;
|
|
15540
|
+
if (this._disposed || !current) return void 0;
|
|
15541
|
+
if (this.controlsMode === mode) return current;
|
|
15542
|
+
let target;
|
|
15543
|
+
if (isFlyControls(current)) {
|
|
15544
|
+
const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
|
|
15545
|
+
target = new Vector315(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
|
|
15546
|
+
} else {
|
|
15547
|
+
target = current.target.clone();
|
|
15548
|
+
this._orbitDistance = this.camera.position.distanceTo(target);
|
|
15549
|
+
}
|
|
15550
|
+
const enabled = current.enabled;
|
|
15551
|
+
this.disposeControls(current);
|
|
15552
|
+
this._controls = this.createControlsFor(mode, target);
|
|
15553
|
+
this._controls.enabled = enabled;
|
|
15554
|
+
this.dirty = true;
|
|
15555
|
+
return this._controls;
|
|
15556
|
+
}
|
|
15557
|
+
disposeControls(controls) {
|
|
15558
|
+
this._controls = void 0;
|
|
15559
|
+
this.unregisterEventDispatcher(controls);
|
|
15560
|
+
controls.enabled = false;
|
|
15561
|
+
controls.dispose();
|
|
15562
|
+
}
|
|
15563
|
+
/** Advances owned controls; without a frame time, flight movement does not progress. */
|
|
15564
|
+
updateControls(time) {
|
|
15565
|
+
const controls = this._controls;
|
|
15566
|
+
if (!controls?.enabled) {
|
|
15567
|
+
this._controlsTime = void 0;
|
|
15568
|
+
return;
|
|
15569
|
+
}
|
|
15570
|
+
if (!isFlyControls(controls)) {
|
|
15571
|
+
controls.update();
|
|
15572
|
+
return;
|
|
15573
|
+
}
|
|
15574
|
+
const previous = this._controlsTime;
|
|
15575
|
+
if (time !== void 0) this._controlsTime = time;
|
|
15576
|
+
controls.update(time === void 0 || previous === void 0 ? 0 : (time - previous) / 1e3);
|
|
15577
|
+
}
|
|
15058
15578
|
//</editor-fold>
|
|
15059
15579
|
init() {
|
|
15060
15580
|
if (this._disposed) return;
|
|
@@ -15131,6 +15651,12 @@ var Renderer = class _Renderer {
|
|
|
15131
15651
|
events.add(changeEvent2);
|
|
15132
15652
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
15133
15653
|
}
|
|
15654
|
+
unregisterEventDispatcher(dispatcher) {
|
|
15655
|
+
const events = this._eventDispatchers.get(dispatcher);
|
|
15656
|
+
if (!events) return;
|
|
15657
|
+
for (const event of events) dispatcher.removeEventListener(event, this._changeListener);
|
|
15658
|
+
this._eventDispatchers.delete(dispatcher);
|
|
15659
|
+
}
|
|
15134
15660
|
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
15135
15661
|
resize(width, height) {
|
|
15136
15662
|
if (this._disposed) return;
|
|
@@ -15207,6 +15733,7 @@ var Renderer = class _Renderer {
|
|
|
15207
15733
|
this.renderer.setAnimationLoop(null);
|
|
15208
15734
|
}
|
|
15209
15735
|
this._nextFrameTime = void 0;
|
|
15736
|
+
this._controlsTime = void 0;
|
|
15210
15737
|
for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
|
|
15211
15738
|
}
|
|
15212
15739
|
/**
|
|
@@ -15236,10 +15763,7 @@ var Renderer = class _Renderer {
|
|
|
15236
15763
|
}
|
|
15237
15764
|
this._element = void 0;
|
|
15238
15765
|
if (this._controls) {
|
|
15239
|
-
|
|
15240
|
-
this._controls = void 0;
|
|
15241
|
-
controls.enabled = false;
|
|
15242
|
-
controls.dispose();
|
|
15766
|
+
this.disposeControls(this._controls);
|
|
15243
15767
|
}
|
|
15244
15768
|
this.scene.clear();
|
|
15245
15769
|
for (const helper of this._debugHelpers) {
|
|
@@ -15256,9 +15780,7 @@ var Renderer = class _Renderer {
|
|
|
15256
15780
|
}
|
|
15257
15781
|
animate(t = performance.now()) {
|
|
15258
15782
|
if (!this._running) return;
|
|
15259
|
-
|
|
15260
|
-
this._controls.update();
|
|
15261
|
-
}
|
|
15783
|
+
this.updateControls(t);
|
|
15262
15784
|
if (!this._running) return;
|
|
15263
15785
|
if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size && !this._videoExporter) return;
|
|
15264
15786
|
const interval = this._frameInterval;
|
|
@@ -15295,7 +15817,7 @@ var Renderer = class _Renderer {
|
|
|
15295
15817
|
/** Draws a fresh frame without starting the animation loop or invoking frame callbacks. */
|
|
15296
15818
|
renderOnce() {
|
|
15297
15819
|
if (this._disposed) throw new Error("Cannot render a disposed renderer");
|
|
15298
|
-
|
|
15820
|
+
this.updateControls();
|
|
15299
15821
|
this.drawFrame();
|
|
15300
15822
|
}
|
|
15301
15823
|
/**
|
|
@@ -15325,7 +15847,7 @@ var Renderer = class _Renderer {
|
|
|
15325
15847
|
try {
|
|
15326
15848
|
if (!wasRunning) this.start();
|
|
15327
15849
|
this._videoExporter = exporter;
|
|
15328
|
-
|
|
15850
|
+
this.updateControls();
|
|
15329
15851
|
this.drawFrame();
|
|
15330
15852
|
} catch (error) {
|
|
15331
15853
|
exporter.cancel(error);
|
|
@@ -15376,6 +15898,19 @@ var Renderer = class _Renderer {
|
|
|
15376
15898
|
get controls() {
|
|
15377
15899
|
return this._controls;
|
|
15378
15900
|
}
|
|
15901
|
+
/** Renderer-owned OrbitControls, or undefined in fly mode or without controls. */
|
|
15902
|
+
get orbitControls() {
|
|
15903
|
+
return this._controls && !isFlyControls(this._controls) ? this._controls : void 0;
|
|
15904
|
+
}
|
|
15905
|
+
/** Renderer-owned {@link FlyControls}, or undefined in orbit mode or without controls. */
|
|
15906
|
+
get flyControls() {
|
|
15907
|
+
return isFlyControls(this._controls) ? this._controls : void 0;
|
|
15908
|
+
}
|
|
15909
|
+
/** The active renderer-owned controls mode, or undefined without controls. */
|
|
15910
|
+
get controlsMode() {
|
|
15911
|
+
if (!this._controls) return void 0;
|
|
15912
|
+
return isFlyControls(this._controls) ? "fly" : "orbit";
|
|
15913
|
+
}
|
|
15379
15914
|
///
|
|
15380
15915
|
};
|
|
15381
15916
|
|
|
@@ -16603,14 +17138,14 @@ var AnvilWorldSource = class {
|
|
|
16603
17138
|
};
|
|
16604
17139
|
|
|
16605
17140
|
// src/world/Chunk.ts
|
|
16606
|
-
import { Vector3 as
|
|
17141
|
+
import { Color as Color13, Vector3 as Vector318 } from "three";
|
|
16607
17142
|
init_BlockStates();
|
|
16608
17143
|
init_AssetKey();
|
|
16609
17144
|
|
|
16610
17145
|
// src/world/MineRenderWorld.ts
|
|
16611
17146
|
init_Model();
|
|
16612
17147
|
init_util();
|
|
16613
|
-
import { Vector3 as
|
|
17148
|
+
import { Vector3 as Vector317 } from "three";
|
|
16614
17149
|
init_AssetKey();
|
|
16615
17150
|
init_BlockStates();
|
|
16616
17151
|
init_CubeFace();
|
|
@@ -16619,7 +17154,7 @@ init_CubeFace();
|
|
|
16619
17154
|
init_AssetKey();
|
|
16620
17155
|
init_Models();
|
|
16621
17156
|
init_CubeFace();
|
|
16622
|
-
import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as
|
|
17157
|
+
import { BufferAttribute as BufferAttribute7, BufferGeometry as BufferGeometry8, Matrix4 as Matrix412, Vector3 as Vector316 } from "three";
|
|
16623
17158
|
init_ModelCulling();
|
|
16624
17159
|
init_ModelObject();
|
|
16625
17160
|
init_UVMapper();
|
|
@@ -16673,24 +17208,48 @@ var SectionModels = class {
|
|
|
16673
17208
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
16674
17209
|
}
|
|
16675
17210
|
/** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
|
|
16676
|
-
async get(blockState3, properties = {}, position) {
|
|
16677
|
-
const
|
|
16678
|
-
|
|
17211
|
+
async get(blockState3, properties = {}, position, biome) {
|
|
17212
|
+
const biomePosition = position ? [...position] : void 0;
|
|
17213
|
+
const prepared = await this.state(blockState3, properties);
|
|
17214
|
+
if (!prepared) return void 0;
|
|
17215
|
+
return Promise.all(prepared.groups.map(async (group) => {
|
|
17216
|
+
const variant = BlockStateResolver.choose(group, biomePosition);
|
|
17217
|
+
const choice = prepared.choices.get(variant);
|
|
17218
|
+
const tints = await BlockTints.get(
|
|
17219
|
+
blockState3.key,
|
|
17220
|
+
prepared.state,
|
|
17221
|
+
choice.model,
|
|
17222
|
+
void 0,
|
|
17223
|
+
() => BlockTints.getBiomeColor(blockState3.key, biome, biomePosition)
|
|
17224
|
+
);
|
|
17225
|
+
return this.template(variant, choice, tints);
|
|
17226
|
+
}));
|
|
17227
|
+
}
|
|
17228
|
+
/** Resolves section templates for one tint palette, with a synchronous weighted choice for each cell. */
|
|
17229
|
+
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
17230
|
+
const prepared = await this.state(blockState3, properties);
|
|
17231
|
+
if (!prepared) return void 0;
|
|
17232
|
+
let color2;
|
|
17233
|
+
const resolveColor = typeof biomeColor === "function" ? () => color2 ??= biomeColor() : biomeColor;
|
|
17234
|
+
const templates = /* @__PURE__ */ new Map();
|
|
17235
|
+
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
17236
|
+
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
17237
|
+
templates.set(variant, await this.template(variant, choice, tints));
|
|
17238
|
+
}));
|
|
17239
|
+
return { pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))) };
|
|
16679
17240
|
}
|
|
16680
|
-
|
|
16681
|
-
async prepareState(blockState3, properties = {}) {
|
|
17241
|
+
async state(blockState3, properties) {
|
|
16682
17242
|
let states = this.states.get(blockState3);
|
|
16683
17243
|
if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
|
|
16684
17244
|
const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
|
|
16685
|
-
|
|
16686
|
-
if (!prepared) return void 0;
|
|
16687
|
-
return { pick: (position) => prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, position))) };
|
|
17245
|
+
return cached(states, key, () => this.prepare(blockState3, properties));
|
|
16688
17246
|
}
|
|
16689
17247
|
/** Returns the shared still/flow atlas used by per-block fluid objects. */
|
|
16690
17248
|
fluidAtlas(kind, root) {
|
|
16691
|
-
|
|
17249
|
+
const key = new AssetKey("minecraft", kind, "models", "fluid", "assets", ".json", root);
|
|
17250
|
+
return cached(this.fluidAtlases, key.serialize(), async () => {
|
|
16692
17251
|
const atlas = await UVMapper.getAtlas({
|
|
16693
|
-
key
|
|
17252
|
+
key,
|
|
16694
17253
|
textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },
|
|
16695
17254
|
elements: []
|
|
16696
17255
|
});
|
|
@@ -16702,64 +17261,67 @@ var SectionModels = class {
|
|
|
16702
17261
|
const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
|
|
16703
17262
|
const groups = BlockStateResolver.matching(blockState3, state);
|
|
16704
17263
|
if (!groups.length) return void 0;
|
|
16705
|
-
const
|
|
17264
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
16706
17265
|
for (const group of groups) {
|
|
16707
17266
|
const choices = Array.isArray(group) ? group : [group];
|
|
16708
17267
|
if (!choices.length) return void 0;
|
|
16709
17268
|
for (const variant of choices) {
|
|
16710
17269
|
if (!variant.model) return void 0;
|
|
16711
|
-
const
|
|
17270
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
17271
|
+
modelKey.root = blockState3.key?.root;
|
|
17272
|
+
const model = await Models.getMerged(modelKey);
|
|
16712
17273
|
if (!model?.elements?.length) return void 0;
|
|
16713
17274
|
const atlas = await UVMapper.getAtlas(model);
|
|
16714
17275
|
const rotation = BlockStateResolver.rotation(variant);
|
|
16715
17276
|
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
16716
|
-
|
|
16717
|
-
let models = this.models.get(model);
|
|
16718
|
-
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
16719
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
16720
|
-
const template = await cached(models, key, async () => {
|
|
16721
|
-
const object4 = new SectionModel(model, {
|
|
16722
|
-
instanceMeshes: false,
|
|
16723
|
-
mergeMeshes: true,
|
|
16724
|
-
tints,
|
|
16725
|
-
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
16726
|
-
});
|
|
16727
|
-
await object4.init();
|
|
16728
|
-
let geometry = object4.children[0].geometry;
|
|
16729
|
-
geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
|
|
16730
|
-
object4.clear();
|
|
16731
|
-
const keep = [];
|
|
16732
|
-
const cullFaces = [];
|
|
16733
|
-
for (const element of atlas.model.elements) {
|
|
16734
|
-
for (const face of CUBE_FACES) {
|
|
16735
|
-
const data = element.faces[face];
|
|
16736
|
-
keep.push(data !== void 0);
|
|
16737
|
-
if (!data) continue;
|
|
16738
|
-
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
16739
|
-
if (local < 0) {
|
|
16740
|
-
cullFaces.push(0);
|
|
16741
|
-
continue;
|
|
16742
|
-
}
|
|
16743
|
-
const normal = new Vector315(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
16744
|
-
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);
|
|
16745
|
-
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
16746
|
-
}
|
|
16747
|
-
}
|
|
16748
|
-
geometry = compactQuads(geometry, keep);
|
|
16749
|
-
const template2 = {
|
|
16750
|
-
geometry,
|
|
16751
|
-
atlas,
|
|
16752
|
-
cullFaces: new Uint8Array(cullFaces),
|
|
16753
|
-
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
16754
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
16755
|
-
};
|
|
16756
|
-
this.templates.add(template2);
|
|
16757
|
-
return template2;
|
|
16758
|
-
});
|
|
16759
|
-
templates.set(variant, template);
|
|
17277
|
+
prepared.set(variant, { model, atlas, rotation });
|
|
16760
17278
|
}
|
|
16761
17279
|
}
|
|
16762
|
-
return { groups,
|
|
17280
|
+
return { state, groups, choices: prepared };
|
|
17281
|
+
}
|
|
17282
|
+
async template(variant, { model, atlas, rotation }, tints) {
|
|
17283
|
+
let models = this.models.get(model);
|
|
17284
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
17285
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
17286
|
+
return cached(models, key, async () => {
|
|
17287
|
+
const object4 = new SectionModel(model, {
|
|
17288
|
+
instanceMeshes: false,
|
|
17289
|
+
mergeMeshes: true,
|
|
17290
|
+
tints,
|
|
17291
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
17292
|
+
});
|
|
17293
|
+
await object4.init();
|
|
17294
|
+
let geometry = object4.children[0].geometry;
|
|
17295
|
+
geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
|
|
17296
|
+
object4.clear();
|
|
17297
|
+
const keep = [];
|
|
17298
|
+
const cullFaces = [];
|
|
17299
|
+
for (const element of atlas.model.elements) {
|
|
17300
|
+
for (const face of CUBE_FACES) {
|
|
17301
|
+
const data = element.faces[face];
|
|
17302
|
+
keep.push(data !== void 0);
|
|
17303
|
+
if (!data) continue;
|
|
17304
|
+
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
17305
|
+
if (local < 0) {
|
|
17306
|
+
cullFaces.push(0);
|
|
17307
|
+
continue;
|
|
17308
|
+
}
|
|
17309
|
+
const normal = new Vector316(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
17310
|
+
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);
|
|
17311
|
+
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
17312
|
+
}
|
|
17313
|
+
}
|
|
17314
|
+
geometry = compactQuads(geometry, keep);
|
|
17315
|
+
const template = {
|
|
17316
|
+
geometry,
|
|
17317
|
+
atlas,
|
|
17318
|
+
cullFaces: new Uint8Array(cullFaces),
|
|
17319
|
+
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17320
|
+
layer: atlas.hasTranslucency ? 1 : 0
|
|
17321
|
+
};
|
|
17322
|
+
this.templates.add(template);
|
|
17323
|
+
return template;
|
|
17324
|
+
});
|
|
16763
17325
|
}
|
|
16764
17326
|
/** Disposes prepared geometry and clears this world's template caches. */
|
|
16765
17327
|
clear() {
|
|
@@ -16936,17 +17498,17 @@ var MineRenderWorld = class {
|
|
|
16936
17498
|
}
|
|
16937
17499
|
getBlockAt(posOrX, y, z) {
|
|
16938
17500
|
if (typeof posOrX == "number") {
|
|
16939
|
-
return this.getBlockAt(new
|
|
17501
|
+
return this.getBlockAt(new Vector317(posOrX, y, z));
|
|
16940
17502
|
}
|
|
16941
17503
|
if (isTripleArray(posOrX)) {
|
|
16942
|
-
return this.getBlockAt(new
|
|
17504
|
+
return this.getBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]));
|
|
16943
17505
|
}
|
|
16944
17506
|
this.validatePosBounds(posOrX);
|
|
16945
17507
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
16946
17508
|
}
|
|
16947
17509
|
getBiomeAt(posOrX, y, z) {
|
|
16948
|
-
if (typeof posOrX === "number") return this.getBiomeAt(new
|
|
16949
|
-
if (isTripleArray(posOrX)) return this.getBiomeAt(new
|
|
17510
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector317(posOrX, y, z));
|
|
17511
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector317(...posOrX));
|
|
16950
17512
|
this.validatePosBounds(posOrX);
|
|
16951
17513
|
const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
|
|
16952
17514
|
const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
|
|
@@ -16954,10 +17516,10 @@ var MineRenderWorld = class {
|
|
|
16954
17516
|
}
|
|
16955
17517
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
16956
17518
|
if (typeof posOrX == "number") {
|
|
16957
|
-
return this.setBlockAt(new
|
|
17519
|
+
return this.setBlockAt(new Vector317(posOrX, yOrBlock, z), block);
|
|
16958
17520
|
}
|
|
16959
17521
|
if (isTripleArray(posOrX)) {
|
|
16960
|
-
return this.setBlockAt(new
|
|
17522
|
+
return this.setBlockAt(new Vector317(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
16961
17523
|
}
|
|
16962
17524
|
return this.placeBlock(posOrX, yOrBlock);
|
|
16963
17525
|
}
|
|
@@ -16968,10 +17530,10 @@ var MineRenderWorld = class {
|
|
|
16968
17530
|
}
|
|
16969
17531
|
async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
|
|
16970
17532
|
if (typeof posOrX === "number") {
|
|
16971
|
-
return this.setBlockVisibleAt(new
|
|
17533
|
+
return this.setBlockVisibleAt(new Vector317(posOrX, yOrVisible, z), visible);
|
|
16972
17534
|
}
|
|
16973
17535
|
if (isTripleArray(posOrX)) {
|
|
16974
|
-
return this.setBlockVisibleAt(new
|
|
17536
|
+
return this.setBlockVisibleAt(new Vector317(...posOrX), yOrVisible);
|
|
16975
17537
|
}
|
|
16976
17538
|
this.validatePosBounds(posOrX);
|
|
16977
17539
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
@@ -16997,7 +17559,7 @@ var MineRenderWorld = class {
|
|
|
16997
17559
|
const collect = async (positions2) => {
|
|
16998
17560
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
16999
17561
|
};
|
|
17000
|
-
const place = (block) => this.placeBlock(new
|
|
17562
|
+
const place = (block) => this.placeBlock(new Vector317(...block.position), block, collect);
|
|
17001
17563
|
const keys = /* @__PURE__ */ new Map();
|
|
17002
17564
|
const types = /* @__PURE__ */ new Set();
|
|
17003
17565
|
for (const block of multiblock.blocks) {
|
|
@@ -17013,7 +17575,7 @@ var MineRenderWorld = class {
|
|
|
17013
17575
|
}
|
|
17014
17576
|
if (!executor) {
|
|
17015
17577
|
const groups2 = /* @__PURE__ */ new Map();
|
|
17016
|
-
const position = new
|
|
17578
|
+
const position = new Vector317();
|
|
17017
17579
|
for (const block of multiblock.blocks) {
|
|
17018
17580
|
const [x, y, z] = block.position;
|
|
17019
17581
|
this.validatePosBounds(position.set(x, y, z));
|
|
@@ -17053,7 +17615,7 @@ var MineRenderWorld = class {
|
|
|
17053
17615
|
try {
|
|
17054
17616
|
positions = await chunk.placeBlocks(blocks);
|
|
17055
17617
|
} finally {
|
|
17056
|
-
positions ??= blocks.map(({ index }) => new
|
|
17618
|
+
positions ??= blocks.map(({ index }) => new Vector317(
|
|
17057
17619
|
chunk.x * 16 + index % 16,
|
|
17058
17620
|
chunk.y * 16 + Math.floor(index / 256),
|
|
17059
17621
|
chunk.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17089,10 +17651,9 @@ var MineRenderWorld = class {
|
|
|
17089
17651
|
}
|
|
17090
17652
|
try {
|
|
17091
17653
|
await this.clearChunkColumn(chunk.x, chunk.z);
|
|
17092
|
-
let sliceStart = performance.now();
|
|
17093
17654
|
for (const section of chunk.sections) {
|
|
17094
17655
|
if (section.biomes) {
|
|
17095
|
-
const position = new
|
|
17656
|
+
const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17096
17657
|
this.validatePosBounds(position);
|
|
17097
17658
|
const copy = [...section.biomes];
|
|
17098
17659
|
if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
|
|
@@ -17103,9 +17664,12 @@ var MineRenderWorld = class {
|
|
|
17103
17664
|
if (!column) this.biomes.set(key, column = /* @__PURE__ */ new Map());
|
|
17104
17665
|
column.set(section.y, copy);
|
|
17105
17666
|
}
|
|
17667
|
+
}
|
|
17668
|
+
let sliceStart = performance.now();
|
|
17669
|
+
for (const section of chunk.sections) {
|
|
17106
17670
|
if (!executor) {
|
|
17107
17671
|
if (!occupiedSections.has(section.y)) continue;
|
|
17108
|
-
const position = new
|
|
17672
|
+
const position = new Vector317(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17109
17673
|
this.validatePosBounds(position);
|
|
17110
17674
|
const target = this.getOrCreateChunkAt(position);
|
|
17111
17675
|
try {
|
|
@@ -17199,7 +17763,7 @@ var MineRenderWorld = class {
|
|
|
17199
17763
|
this.sectionModels?.clear();
|
|
17200
17764
|
}
|
|
17201
17765
|
updateCulling(positions) {
|
|
17202
|
-
const neighbor = new
|
|
17766
|
+
const neighbor = new Vector317();
|
|
17203
17767
|
for (const pos of positions) {
|
|
17204
17768
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
17205
17769
|
const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
@@ -17267,18 +17831,34 @@ var MineRenderWorld = class {
|
|
|
17267
17831
|
const key = this.worldPosToChunkKey(pos);
|
|
17268
17832
|
let chunk = this._chunks.get(key);
|
|
17269
17833
|
if (typeof chunk === "undefined") {
|
|
17834
|
+
const x = Math.floor(pos.x / 16), y = Math.floor(pos.y / 16), z = Math.floor(pos.z / 16);
|
|
17270
17835
|
chunk = new Chunk(
|
|
17271
17836
|
this.scene,
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17837
|
+
x,
|
|
17838
|
+
y,
|
|
17839
|
+
z,
|
|
17275
17840
|
(positions) => this.updateCulling(positions),
|
|
17276
17841
|
this.sectionModels,
|
|
17277
|
-
(
|
|
17278
|
-
const cx = Math.floor(
|
|
17842
|
+
(x2, y2, z2) => {
|
|
17843
|
+
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
17279
17844
|
const section = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
17280
|
-
const index = (
|
|
17845
|
+
const index = (y2 - cy * 16) * 256 + (z2 - cz * 16) * 16 + x2 - cx * 16;
|
|
17281
17846
|
return (section?.fluidByteIndex(index) ?? 0) | (section?.isOccludingIndex(index) ? 64 : 0);
|
|
17847
|
+
},
|
|
17848
|
+
(x2, y2, z2) => this.getBiomeAt(x2, y2, z2),
|
|
17849
|
+
async (biomes) => {
|
|
17850
|
+
if (this._chunks.get(key) !== chunk) return;
|
|
17851
|
+
const columnKey = `${x}_${z}`;
|
|
17852
|
+
let column = this.biomes.get(columnKey);
|
|
17853
|
+
if (biomes) {
|
|
17854
|
+
if (!column) this.biomes.set(columnKey, column = /* @__PURE__ */ new Map());
|
|
17855
|
+
column.set(y, biomes);
|
|
17856
|
+
} else {
|
|
17857
|
+
column?.delete(y);
|
|
17858
|
+
if (!column?.size) this.biomes.delete(columnKey);
|
|
17859
|
+
}
|
|
17860
|
+
await chunk.refreshBiomes();
|
|
17861
|
+
await this._chunks.get(`${x}_${y + 1}_${z}`)?.refreshBiomes();
|
|
17282
17862
|
}
|
|
17283
17863
|
);
|
|
17284
17864
|
this._chunks.set(key, chunk);
|
|
@@ -17291,7 +17871,7 @@ var MineRenderWorld = class {
|
|
|
17291
17871
|
}
|
|
17292
17872
|
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
17293
17873
|
static worldToScenePosition(pos) {
|
|
17294
|
-
return new
|
|
17874
|
+
return new Vector317(
|
|
17295
17875
|
pos.x * 16,
|
|
17296
17876
|
pos.y * 16,
|
|
17297
17877
|
pos.z * 16
|
|
@@ -17299,7 +17879,7 @@ var MineRenderWorld = class {
|
|
|
17299
17879
|
}
|
|
17300
17880
|
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
17301
17881
|
static sceneToWorldPosition(pos) {
|
|
17302
|
-
return new
|
|
17882
|
+
return new Vector317(
|
|
17303
17883
|
pos.x / 16,
|
|
17304
17884
|
pos.y / 16,
|
|
17305
17885
|
pos.z / 16
|
|
@@ -17333,6 +17913,7 @@ function buildSectionGeometry(input) {
|
|
|
17333
17913
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
17334
17914
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
17335
17915
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
17916
|
+
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
17336
17917
|
for (const template of templateData) {
|
|
17337
17918
|
const { quads } = template;
|
|
17338
17919
|
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) {
|
|
@@ -17410,7 +17991,9 @@ function buildSectionGeometry(input) {
|
|
|
17410
17991
|
height
|
|
17411
17992
|
});
|
|
17412
17993
|
}
|
|
17413
|
-
|
|
17994
|
+
const tintIndex = (x + z * 16 + y * 256) * 3;
|
|
17995
|
+
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
17996
|
+
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
17414
17997
|
}
|
|
17415
17998
|
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));
|
|
17416
17999
|
}
|
|
@@ -17459,7 +18042,7 @@ function buildSectionGeometry(input) {
|
|
|
17459
18042
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
17460
18043
|
}
|
|
17461
18044
|
}
|
|
17462
|
-
for (const { quads, x, y, z, data } of page.fluids) {
|
|
18045
|
+
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
17463
18046
|
const atlas = atlases[data.atlas];
|
|
17464
18047
|
const placement = page.placements[0];
|
|
17465
18048
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
@@ -17483,7 +18066,7 @@ function buildSectionGeometry(input) {
|
|
|
17483
18066
|
mapU((rect[0] + rect[2]) / atlas.width),
|
|
17484
18067
|
mapV(1 - rect[1] / atlas.height)
|
|
17485
18068
|
], vertex * 4);
|
|
17486
|
-
colors.set(
|
|
18069
|
+
colors.set(tint, vertex * 3);
|
|
17487
18070
|
}
|
|
17488
18071
|
outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);
|
|
17489
18072
|
indexOffset += 6;
|
|
@@ -17625,7 +18208,7 @@ function toInput(entries, maxAtlasSize, fluids) {
|
|
|
17625
18208
|
input.cullMasks[i] = cullMask;
|
|
17626
18209
|
}
|
|
17627
18210
|
if (fluids) {
|
|
17628
|
-
input.fluids = { cells: fluids.cells };
|
|
18211
|
+
input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };
|
|
17629
18212
|
for (const kind of ["water", "lava"]) {
|
|
17630
18213
|
const atlas = fluids[kind];
|
|
17631
18214
|
if (!atlas) continue;
|
|
@@ -17726,17 +18309,20 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
17726
18309
|
init_FluidGeometry();
|
|
17727
18310
|
init_FluidQuads();
|
|
17728
18311
|
init_CubeFace();
|
|
18312
|
+
var WATER_TINT2 = new Color13(4159204).toArray();
|
|
17729
18313
|
var Chunk = class _Chunk {
|
|
17730
|
-
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell) {
|
|
18314
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged) {
|
|
17731
18315
|
this.onBlocksChanged = onBlocksChanged;
|
|
17732
18316
|
this.sectionModels = sectionModels;
|
|
17733
18317
|
this.neighborCell = neighborCell;
|
|
18318
|
+
this.biomeAt = biomeAt;
|
|
18319
|
+
this.onBiomesChanged = onBiomesChanged;
|
|
17734
18320
|
this.data = new ChunkData();
|
|
17735
18321
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
17736
18322
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
17737
18323
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
17738
18324
|
this.fluidCells = new Uint8Array(4096);
|
|
17739
|
-
this.blockPosition = new
|
|
18325
|
+
this.blockPosition = new Vector318();
|
|
17740
18326
|
this.meshDirty = false;
|
|
17741
18327
|
this.meshGeneration = 0;
|
|
17742
18328
|
this.scene = scene;
|
|
@@ -17746,21 +18332,71 @@ var Chunk = class _Chunk {
|
|
|
17746
18332
|
}
|
|
17747
18333
|
getBlockAt(posOrX, y, z) {
|
|
17748
18334
|
if (typeof posOrX == "number") {
|
|
17749
|
-
return this.getBlockAt(new
|
|
18335
|
+
return this.getBlockAt(new Vector318(posOrX, y, z));
|
|
17750
18336
|
}
|
|
17751
18337
|
if (isTripleArray(posOrX)) {
|
|
17752
|
-
return this.getBlockAt(new
|
|
18338
|
+
return this.getBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]));
|
|
17753
18339
|
}
|
|
17754
18340
|
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
17755
18341
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
17756
18342
|
return this.renderedBlocks.get(index);
|
|
17757
18343
|
}
|
|
18344
|
+
getBiomeAt(posOrX, y, z) {
|
|
18345
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector318(posOrX, y, z));
|
|
18346
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector318(...posOrX));
|
|
18347
|
+
const pos = this.worldPosToChunkPos(posOrX);
|
|
18348
|
+
_Chunk.chunkPosToBlockIndex(pos);
|
|
18349
|
+
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];
|
|
18350
|
+
}
|
|
18351
|
+
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
18352
|
+
setBiomes(biomes) {
|
|
18353
|
+
const copy = biomes ? [...biomes] : void 0;
|
|
18354
|
+
if (copy && (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0))) {
|
|
18355
|
+
throw new RangeError("Section biomes must contain 64 nonempty biome IDs");
|
|
18356
|
+
}
|
|
18357
|
+
if (this.onBiomesChanged) return this.onBiomesChanged(copy);
|
|
18358
|
+
this.biomes = copy;
|
|
18359
|
+
return this.refreshBiomes();
|
|
18360
|
+
}
|
|
18361
|
+
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
18362
|
+
async refreshBiomes() {
|
|
18363
|
+
const affected = /* @__PURE__ */ new Map();
|
|
18364
|
+
const blocks = [];
|
|
18365
|
+
for (const index of this.renderedBlocks.keys()) {
|
|
18366
|
+
const block = this.data.get(index);
|
|
18367
|
+
const stateKey = ChunkData.paletteKey(block);
|
|
18368
|
+
let matches = affected.get(stateKey);
|
|
18369
|
+
if (!matches) {
|
|
18370
|
+
const key = AssetKey.parse("blockstates", block.type);
|
|
18371
|
+
matches = BlockStates.get(key).then(async (state) => {
|
|
18372
|
+
const origin = state?.key ?? key;
|
|
18373
|
+
const [source, fluid] = await Promise.all([BlockTints.biomeSource(origin), getBlockFluidState(origin, block.properties)]);
|
|
18374
|
+
return !!source || fluid?.kind === "water";
|
|
18375
|
+
});
|
|
18376
|
+
affected.set(stateKey, matches);
|
|
18377
|
+
}
|
|
18378
|
+
if (await matches) blocks.push({ index, block });
|
|
18379
|
+
}
|
|
18380
|
+
if (!blocks.length) return;
|
|
18381
|
+
const hidden = new Set(this.hiddenBlocks);
|
|
18382
|
+
try {
|
|
18383
|
+
await this.placeBlocks(blocks);
|
|
18384
|
+
} finally {
|
|
18385
|
+
for (const index of hidden) {
|
|
18386
|
+
this.hiddenBlocks.add(index);
|
|
18387
|
+
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
18388
|
+
}
|
|
18389
|
+
const positions = blocks.map(({ index }) => new Vector318(...this.positionAt(index)));
|
|
18390
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
18391
|
+
else await this.rebuildSectionMesh();
|
|
18392
|
+
}
|
|
18393
|
+
}
|
|
17758
18394
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
17759
18395
|
if (typeof posOrX == "number") {
|
|
17760
|
-
return this.setBlockAt(new
|
|
18396
|
+
return this.setBlockAt(new Vector318(posOrX, yOrBlock, z), block);
|
|
17761
18397
|
}
|
|
17762
18398
|
if (isTripleArray(posOrX)) {
|
|
17763
|
-
return this.setBlockAt(new
|
|
18399
|
+
return this.setBlockAt(new Vector318(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
17764
18400
|
}
|
|
17765
18401
|
const worldPos = posOrX;
|
|
17766
18402
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -17793,14 +18429,15 @@ var Chunk = class _Chunk {
|
|
|
17793
18429
|
nbt: block.nbt === void 0 ? void 0 : structuredClone(block.nbt)
|
|
17794
18430
|
} : void 0
|
|
17795
18431
|
}));
|
|
17796
|
-
const states =
|
|
17797
|
-
const
|
|
17798
|
-
|
|
17799
|
-
|
|
17800
|
-
|
|
17801
|
-
|
|
17802
|
-
|
|
17803
|
-
|
|
18432
|
+
const states = /* @__PURE__ */ new Map();
|
|
18433
|
+
for (const { index, key, block } of placements) {
|
|
18434
|
+
if (key === void 0) continue;
|
|
18435
|
+
let state = states.get(key);
|
|
18436
|
+
if (!state) states.set(key, state = { stored: block, indices: [] });
|
|
18437
|
+
state.indices.push(index);
|
|
18438
|
+
}
|
|
18439
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
18440
|
+
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
17804
18441
|
const resolutions = new Map([...states.keys()].map((key, i) => [key, settled[i]]));
|
|
17805
18442
|
const positions = [];
|
|
17806
18443
|
let failed = false, failure;
|
|
@@ -17813,7 +18450,7 @@ var Chunk = class _Chunk {
|
|
|
17813
18450
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
17814
18451
|
this.fluidCells[index] = 0;
|
|
17815
18452
|
this.renderedBlocks.delete(index);
|
|
17816
|
-
const worldPos = new
|
|
18453
|
+
const worldPos = new Vector318(
|
|
17817
18454
|
this.x * 16 + index % 16,
|
|
17818
18455
|
this.y * 16 + Math.floor(index / 256),
|
|
17819
18456
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17824,7 +18461,8 @@ var Chunk = class _Chunk {
|
|
|
17824
18461
|
if (!readBlock) continue;
|
|
17825
18462
|
const resolved = resolutions.get(key);
|
|
17826
18463
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17827
|
-
const { blockState: blockState3, perBlock, fluid, prepared, stored } = resolved.value;
|
|
18464
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts, stored } = resolved.value;
|
|
18465
|
+
const context = contexts.get(index);
|
|
17828
18466
|
if (!blockState3) {
|
|
17829
18467
|
this.data.assign(index, 0);
|
|
17830
18468
|
continue;
|
|
@@ -17832,9 +18470,10 @@ var Chunk = class _Chunk {
|
|
|
17832
18470
|
const variantPosition = worldPos.toArray();
|
|
17833
18471
|
if (fluid) {
|
|
17834
18472
|
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18473
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
17835
18474
|
this.meshDirty = true;
|
|
17836
18475
|
}
|
|
17837
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18476
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
17838
18477
|
if (templates) {
|
|
17839
18478
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
17840
18479
|
this.meshDirty = true;
|
|
@@ -17844,7 +18483,9 @@ var Chunk = class _Chunk {
|
|
|
17844
18483
|
instanceMeshes: true,
|
|
17845
18484
|
maxInstanceCount: 2e3,
|
|
17846
18485
|
initialState: stored.properties,
|
|
17847
|
-
variantPosition
|
|
18486
|
+
variantPosition,
|
|
18487
|
+
biome: context?.biome,
|
|
18488
|
+
biomePosition: this.biomePosition(index, blockState3, stored)
|
|
17848
18489
|
});
|
|
17849
18490
|
object4.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
17850
18491
|
}
|
|
@@ -17867,24 +18508,21 @@ var Chunk = class _Chunk {
|
|
|
17867
18508
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
17868
18509
|
this.sectionBlocks.clear();
|
|
17869
18510
|
this.fluidCells.fill(0);
|
|
18511
|
+
this.waterTints = void 0;
|
|
17870
18512
|
this.renderedBlocks.clear();
|
|
17871
18513
|
this.hiddenBlocks.clear();
|
|
17872
18514
|
this.meshDirty = true;
|
|
17873
18515
|
this.data.copyFrom(data);
|
|
17874
|
-
const ids = /* @__PURE__ */ new
|
|
18516
|
+
const ids = /* @__PURE__ */ new Map();
|
|
17875
18517
|
for (let index = 0; index < 4096; index++) {
|
|
17876
18518
|
const id = this.data.idAt(index);
|
|
17877
|
-
if (id)
|
|
17878
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
|
|
17884
|
-
const fluid = await getBlockFluidState(blockState3?.key, state.properties);
|
|
17885
|
-
const prepared = perBlock || fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, state.properties);
|
|
17886
|
-
return { blockState: blockState3, perBlock, fluid, prepared };
|
|
17887
|
-
}));
|
|
18519
|
+
if (!id) continue;
|
|
18520
|
+
let indices = ids.get(id);
|
|
18521
|
+
if (!indices) ids.set(id, indices = []);
|
|
18522
|
+
indices.push(index);
|
|
18523
|
+
}
|
|
18524
|
+
const palette = [...ids.keys()], biomes = /* @__PURE__ */ new Map();
|
|
18525
|
+
const settled = await Promise.allSettled(palette.map((id) => this.resolveState(this.data.stateAt(id), ids.get(id), biomes)));
|
|
17888
18526
|
const resolutions = new Map(palette.map((id, i) => [id, settled[i]]));
|
|
17889
18527
|
const perBlocks = [];
|
|
17890
18528
|
let failed = false, failure;
|
|
@@ -17894,24 +18532,28 @@ var Chunk = class _Chunk {
|
|
|
17894
18532
|
try {
|
|
17895
18533
|
const resolved = resolutions.get(id);
|
|
17896
18534
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17897
|
-
const { blockState: blockState3, perBlock, fluid, prepared } = resolved.value;
|
|
18535
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts } = resolved.value;
|
|
18536
|
+
const context = contexts.get(index);
|
|
17898
18537
|
if (!blockState3) {
|
|
17899
18538
|
this.data.assign(index, 0);
|
|
17900
18539
|
this.fluidCells[index] = 0;
|
|
17901
18540
|
continue;
|
|
17902
18541
|
}
|
|
17903
|
-
if (fluid)
|
|
18542
|
+
if (fluid) {
|
|
18543
|
+
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18544
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
18545
|
+
}
|
|
17904
18546
|
const variantPosition = [
|
|
17905
18547
|
this.x * 16 + index % 16,
|
|
17906
18548
|
this.y * 16 + Math.floor(index / 256),
|
|
17907
18549
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
17908
18550
|
];
|
|
17909
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18551
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
17910
18552
|
if (templates) {
|
|
17911
18553
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
17912
18554
|
this.meshDirty = true;
|
|
17913
18555
|
} else {
|
|
17914
|
-
perBlocks.push({ index, blockState: blockState3 });
|
|
18556
|
+
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
17915
18557
|
}
|
|
17916
18558
|
const readBlock = this.data.snapshot(index);
|
|
17917
18559
|
this.renderedBlocks.set(index, { get block() {
|
|
@@ -17924,7 +18566,7 @@ var Chunk = class _Chunk {
|
|
|
17924
18566
|
failed = true;
|
|
17925
18567
|
}
|
|
17926
18568
|
}
|
|
17927
|
-
for (const { index, blockState: blockState3 } of perBlocks) {
|
|
18569
|
+
for (const { index, blockState: blockState3, biome } of perBlocks) {
|
|
17928
18570
|
let object4;
|
|
17929
18571
|
try {
|
|
17930
18572
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -17932,13 +18574,11 @@ var Chunk = class _Chunk {
|
|
|
17932
18574
|
instanceMeshes: true,
|
|
17933
18575
|
maxInstanceCount: 2e3,
|
|
17934
18576
|
initialState: this.data.stateAt(this.data.idAt(index)).properties,
|
|
17935
|
-
variantPosition:
|
|
17936
|
-
|
|
17937
|
-
|
|
17938
|
-
this.z * 16 + Math.floor(index / 16) % 16
|
|
17939
|
-
]
|
|
18577
|
+
variantPosition: this.positionAt(index),
|
|
18578
|
+
biome,
|
|
18579
|
+
biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
|
|
17940
18580
|
});
|
|
17941
|
-
object4.setPosition(new
|
|
18581
|
+
object4.setPosition(new Vector318(
|
|
17942
18582
|
this.x * 256 + index % 16 * 16,
|
|
17943
18583
|
this.y * 256 + Math.floor(index / 256) * 16,
|
|
17944
18584
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
@@ -17955,6 +18595,68 @@ var Chunk = class _Chunk {
|
|
|
17955
18595
|
}
|
|
17956
18596
|
if (failed) throw failure;
|
|
17957
18597
|
}
|
|
18598
|
+
positionAt(index) {
|
|
18599
|
+
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
18600
|
+
}
|
|
18601
|
+
biomePosition(index, blockState3, stored) {
|
|
18602
|
+
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18603
|
+
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
18604
|
+
return position;
|
|
18605
|
+
}
|
|
18606
|
+
async resolveState(stored, indices, biomes) {
|
|
18607
|
+
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
18608
|
+
const perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
18609
|
+
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
18610
|
+
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;
|
|
18611
|
+
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
18612
|
+
const prepare = (color2) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color2);
|
|
18613
|
+
const contexts = /* @__PURE__ */ new Map();
|
|
18614
|
+
const groups = /* @__PURE__ */ new Map();
|
|
18615
|
+
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
18616
|
+
for (const index of indices) {
|
|
18617
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
18618
|
+
const biome = this.biomeAt ? this.biomeAt(...position) : position[1] >= this.y * 16 ? this.getBiomeAt(position) : void 0;
|
|
18619
|
+
if (!biome) continue;
|
|
18620
|
+
const key = JSON.stringify(source === "grass" ? [biome, position[0], position[2]] : [biome]);
|
|
18621
|
+
let group = groups.get(key);
|
|
18622
|
+
if (!group) groups.set(key, group = { biome, position, indices: [] });
|
|
18623
|
+
group.indices.push(index);
|
|
18624
|
+
}
|
|
18625
|
+
}
|
|
18626
|
+
const groupedCount = [...groups.values()].reduce((sum, group) => sum + group.indices.length, 0);
|
|
18627
|
+
const prepared = groupedCount < indices.length ? await prepare() : void 0;
|
|
18628
|
+
await Promise.all([...groups.values()].map(async ({ biome, position, indices: indices2 }) => {
|
|
18629
|
+
const available = () => {
|
|
18630
|
+
const key = JSON.stringify([biome, blockState3?.key?.root]);
|
|
18631
|
+
let found = biomes.get(key);
|
|
18632
|
+
if (!found) {
|
|
18633
|
+
found = Biomes.get(biome, blockState3?.key).then((value) => value !== void 0);
|
|
18634
|
+
biomes.set(key, found);
|
|
18635
|
+
}
|
|
18636
|
+
return found;
|
|
18637
|
+
};
|
|
18638
|
+
const context = { biome };
|
|
18639
|
+
if (perBlock) {
|
|
18640
|
+
if (!await available()) context.biome = void 0;
|
|
18641
|
+
} else {
|
|
18642
|
+
context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
|
|
18643
|
+
if (fluid?.kind === "water" && await available()) {
|
|
18644
|
+
const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
|
|
18645
|
+
if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new Color13(color2).toArray();
|
|
18646
|
+
}
|
|
18647
|
+
}
|
|
18648
|
+
for (const index of indices2) contexts.set(index, context);
|
|
18649
|
+
}));
|
|
18650
|
+
return { blockState: blockState3, perBlock, fluid, prepared, contexts, stored };
|
|
18651
|
+
}
|
|
18652
|
+
setWaterTint(index, tint) {
|
|
18653
|
+
if (!this.sectionModels || !this.waterTints && tint === void 0) return;
|
|
18654
|
+
if (!this.waterTints) {
|
|
18655
|
+
this.waterTints = new Float32Array(4096 * 3);
|
|
18656
|
+
for (let cell = 0; cell < 4096; cell++) this.waterTints.set(WATER_TINT2, cell * 3);
|
|
18657
|
+
}
|
|
18658
|
+
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
18659
|
+
}
|
|
17958
18660
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
17959
18661
|
async setBlockVisibleAt(pos, visible) {
|
|
17960
18662
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -18058,7 +18760,7 @@ var Chunk = class _Chunk {
|
|
|
18058
18760
|
if (block && !block.object) origins.set(kind, block.block.type);
|
|
18059
18761
|
}
|
|
18060
18762
|
if (origins.size) {
|
|
18061
|
-
fluids = { cells: new Uint8Array(18 * 18 * 18) };
|
|
18763
|
+
fluids = { cells: new Uint8Array(18 * 18 * 18), waterTints: this.waterTints?.slice() };
|
|
18062
18764
|
for (let y = -1; y <= 16; y++) {
|
|
18063
18765
|
for (let z = -1; z <= 16; z++) {
|
|
18064
18766
|
for (let x = -1; x <= 16; x++) {
|
|
@@ -18089,7 +18791,7 @@ var Chunk = class _Chunk {
|
|
|
18089
18791
|
/** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
|
|
18090
18792
|
async clear(notify = true) {
|
|
18091
18793
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
18092
|
-
new
|
|
18794
|
+
new Vector318(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
18093
18795
|
)) : [];
|
|
18094
18796
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
18095
18797
|
this.sectionBlocks.clear();
|
|
@@ -18100,8 +18802,13 @@ var Chunk = class _Chunk {
|
|
|
18100
18802
|
this.renderedBlocks.clear();
|
|
18101
18803
|
this.hiddenBlocks.clear();
|
|
18102
18804
|
this.fluidCells.fill(0);
|
|
18805
|
+
this.waterTints = void 0;
|
|
18103
18806
|
this.data.clear();
|
|
18104
|
-
|
|
18807
|
+
this.biomes = void 0;
|
|
18808
|
+
if (notify) {
|
|
18809
|
+
await this.onBiomesChanged?.(void 0);
|
|
18810
|
+
await this.onBlocksChanged?.(positions);
|
|
18811
|
+
}
|
|
18105
18812
|
}
|
|
18106
18813
|
async dispose() {
|
|
18107
18814
|
await this.clear();
|
|
@@ -18117,14 +18824,14 @@ var Chunk = class _Chunk {
|
|
|
18117
18824
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
18118
18825
|
}
|
|
18119
18826
|
worldPosToChunkPos(pos) {
|
|
18120
|
-
return new
|
|
18827
|
+
return new Vector318(
|
|
18121
18828
|
pos.x - this.x * 16,
|
|
18122
18829
|
pos.y - this.y * 16,
|
|
18123
18830
|
pos.z - this.z * 16
|
|
18124
18831
|
);
|
|
18125
18832
|
}
|
|
18126
18833
|
chunkPosToWorldPos(pos) {
|
|
18127
|
-
return new
|
|
18834
|
+
return new Vector318(
|
|
18128
18835
|
this.x * 16 + pos.x,
|
|
18129
18836
|
this.y * 16 + pos.y,
|
|
18130
18837
|
this.z * 16 + pos.z
|
|
@@ -18486,6 +19193,7 @@ export {
|
|
|
18486
19193
|
BannerPatterns,
|
|
18487
19194
|
BasicAssetKey,
|
|
18488
19195
|
BatchedExecutor,
|
|
19196
|
+
Biomes,
|
|
18489
19197
|
BlockEntities,
|
|
18490
19198
|
BlockObject,
|
|
18491
19199
|
BlockStateResolver,
|
|
@@ -18517,6 +19225,7 @@ export {
|
|
|
18517
19225
|
EntityObject,
|
|
18518
19226
|
Env,
|
|
18519
19227
|
FluidModelObject,
|
|
19228
|
+
FlyControls,
|
|
18520
19229
|
Fonts,
|
|
18521
19230
|
GUI_CONTAINER_LAYOUTS,
|
|
18522
19231
|
Geometries,
|
|
@@ -18622,6 +19331,7 @@ export {
|
|
|
18622
19331
|
isDisposable,
|
|
18623
19332
|
isDoubleArray,
|
|
18624
19333
|
isEntityObject,
|
|
19334
|
+
isFlyControls,
|
|
18625
19335
|
isGuiObject,
|
|
18626
19336
|
isInstanceManager,
|
|
18627
19337
|
isInstanceReference,
|