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.js
CHANGED
|
@@ -280,7 +280,8 @@ var init_Caching = __esm({
|
|
|
280
280
|
this.fontCache,
|
|
281
281
|
this.bannerPatternCache,
|
|
282
282
|
this.mineRenderDataCache,
|
|
283
|
-
this.usernameUuidCache
|
|
283
|
+
this.usernameUuidCache,
|
|
284
|
+
this.biomeCache
|
|
284
285
|
];
|
|
285
286
|
}
|
|
286
287
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
@@ -331,6 +332,7 @@ var init_Caching = __esm({
|
|
|
331
332
|
_Caching.bannerPatternCache = _Caching.createAssetCache();
|
|
332
333
|
_Caching.mineRenderDataCache = _Caching.createAssetCache();
|
|
333
334
|
_Caching.usernameUuidCache = import_loading_cache.Caches.builder().expireAfterWrite(import_time.Time.minutes(5)).expirationInterval(import_time.Time.seconds(30)).buildAsync();
|
|
335
|
+
_Caching.biomeCache = _Caching.createAssetCache();
|
|
334
336
|
Caching = _Caching;
|
|
335
337
|
}
|
|
336
338
|
});
|
|
@@ -1677,7 +1679,7 @@ ${key}` : key, async () => {
|
|
|
1677
1679
|
case "blockStates":
|
|
1678
1680
|
return Object.values(value).every((property) => object(property) && "default" in property && Array.isArray(property.values));
|
|
1679
1681
|
case "blockTints":
|
|
1680
|
-
return ["constant", "grass", "stem", "redstone"].includes(value.source) && (value.source !== "constant" || Number.isInteger(value.color));
|
|
1682
|
+
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));
|
|
1681
1683
|
case "fluids":
|
|
1682
1684
|
return ["water", "lava"].includes(value.kind) && typeof value.renderModel === "boolean" && (value.levelProperty === void 0 || typeof value.levelProperty === "string");
|
|
1683
1685
|
case "dyes":
|
|
@@ -1821,15 +1823,19 @@ var init_Colormaps = __esm({
|
|
|
1821
1823
|
Colormaps = class {
|
|
1822
1824
|
/** Samples the selected resource pack's grass colormap using Minecraft's climate coordinates. */
|
|
1823
1825
|
static async grassColor(origin, temperature = 0.5, downfall = 1) {
|
|
1824
|
-
|
|
1826
|
+
return this.getColor("grass", origin, temperature, downfall);
|
|
1827
|
+
}
|
|
1828
|
+
/** Samples a resource-pack colormap at the supplied climate coordinates. */
|
|
1829
|
+
static async getColor(kind, origin, temperature = 0.5, downfall = 1) {
|
|
1830
|
+
const key = AssetKey.parse("textures", `minecraft:colormap/${kind}`, origin);
|
|
1825
1831
|
const temp = Math.fround(temperature);
|
|
1826
1832
|
const rain = Math.fround(downfall) * temp;
|
|
1827
1833
|
const x = Math.floor((1 - temp) * 255), y = Math.floor((1 - rain) * 255);
|
|
1828
1834
|
return await Caching.blockTintCache.get(`${key.serialize()}|${x},${y}`, async () => {
|
|
1829
1835
|
const image = await ModelTextures.get(key);
|
|
1830
|
-
if (!image) throw new MineRenderError(`Missing
|
|
1836
|
+
if (!image) throw new MineRenderError(`Missing ${kind} colormap: ${key.toNamespacedString()}`);
|
|
1831
1837
|
if (image.width !== 256 || image.height !== 256) {
|
|
1832
|
-
throw new MineRenderError(
|
|
1838
|
+
throw new MineRenderError(`${kind} colormaps must be 256 \xD7 256 pixels`);
|
|
1833
1839
|
}
|
|
1834
1840
|
const [red, green, blue] = image.data.getImageData(x, y, 1, 1).data;
|
|
1835
1841
|
return red << 16 | green << 8 | blue;
|
|
@@ -7516,6 +7522,7 @@ __export(index_browser_exports, {
|
|
|
7516
7522
|
BannerPatterns: () => BannerPatterns,
|
|
7517
7523
|
BasicAssetKey: () => BasicAssetKey,
|
|
7518
7524
|
BatchedExecutor: () => BatchedExecutor,
|
|
7525
|
+
Biomes: () => Biomes,
|
|
7519
7526
|
BlockEntities: () => BlockEntities,
|
|
7520
7527
|
BlockObject: () => BlockObject,
|
|
7521
7528
|
BlockStateResolver: () => BlockStateResolver,
|
|
@@ -7549,6 +7556,7 @@ __export(index_browser_exports, {
|
|
|
7549
7556
|
EntityObject: () => EntityObject,
|
|
7550
7557
|
Env: () => Env,
|
|
7551
7558
|
FluidModelObject: () => FluidModelObject,
|
|
7559
|
+
FlyControls: () => FlyControls,
|
|
7552
7560
|
Fonts: () => Fonts,
|
|
7553
7561
|
GUI_CONTAINER_LAYOUTS: () => GUI_CONTAINER_LAYOUTS,
|
|
7554
7562
|
Geometries: () => Geometries,
|
|
@@ -7651,6 +7659,7 @@ __export(index_browser_exports, {
|
|
|
7651
7659
|
isDisposable: () => isDisposable,
|
|
7652
7660
|
isDoubleArray: () => isDoubleArray,
|
|
7653
7661
|
isEntityObject: () => isEntityObject,
|
|
7662
|
+
isFlyControls: () => isFlyControls,
|
|
7654
7663
|
isGuiObject: () => isGuiObject,
|
|
7655
7664
|
isInstanceManager: () => isInstanceManager,
|
|
7656
7665
|
isInstanceReference: () => isInstanceReference,
|
|
@@ -7903,6 +7912,116 @@ init_AssetLoader();
|
|
|
7903
7912
|
init_Assets();
|
|
7904
7913
|
init_BannerPatterns();
|
|
7905
7914
|
|
|
7915
|
+
// src/assets/Biomes.ts
|
|
7916
|
+
init_AssetKey();
|
|
7917
|
+
init_AssetLoader();
|
|
7918
|
+
init_AssetParsers();
|
|
7919
|
+
init_Caching();
|
|
7920
|
+
init_MineRenderError();
|
|
7921
|
+
init_Colormaps();
|
|
7922
|
+
|
|
7923
|
+
// src/assets/_biomes/SwampGrassColor.ts
|
|
7924
|
+
var permutation;
|
|
7925
|
+
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]];
|
|
7926
|
+
var skew = (Math.sqrt(3) - 1) / 2;
|
|
7927
|
+
var unskew = (3 - Math.sqrt(3)) / 6;
|
|
7928
|
+
function createPermutation() {
|
|
7929
|
+
const multiplier = 0x5deece66dn, mask = (1n << 48n) - 1n;
|
|
7930
|
+
let seed = 2345n ^ multiplier;
|
|
7931
|
+
const next = (bits) => {
|
|
7932
|
+
seed = seed * multiplier + 11n & mask;
|
|
7933
|
+
return Number(seed >> BigInt(48 - bits));
|
|
7934
|
+
};
|
|
7935
|
+
for (let i = 0; i < 3; i++) {
|
|
7936
|
+
next(26);
|
|
7937
|
+
next(27);
|
|
7938
|
+
}
|
|
7939
|
+
const values = Uint8Array.from({ length: 256 }, (_, i) => i);
|
|
7940
|
+
for (let i = 0; i < 256; i++) {
|
|
7941
|
+
const bound = 256 - i;
|
|
7942
|
+
let offset;
|
|
7943
|
+
if ((bound & bound - 1) === 0) offset = Math.floor(bound * next(31) / 2147483648);
|
|
7944
|
+
else {
|
|
7945
|
+
let bits;
|
|
7946
|
+
do {
|
|
7947
|
+
bits = next(31);
|
|
7948
|
+
offset = bits % bound;
|
|
7949
|
+
} while (bits - offset + bound - 1 > 2147483647);
|
|
7950
|
+
}
|
|
7951
|
+
const other = i + offset;
|
|
7952
|
+
[values[i], values[other]] = [values[other], values[i]];
|
|
7953
|
+
}
|
|
7954
|
+
return values;
|
|
7955
|
+
}
|
|
7956
|
+
function swampGrassColor(x, z) {
|
|
7957
|
+
const p10 = permutation ?? (permutation = createPermutation());
|
|
7958
|
+
x *= 0.0225;
|
|
7959
|
+
z *= 0.0225;
|
|
7960
|
+
const s = (x + z) * skew;
|
|
7961
|
+
const i = Math.floor(x + s), j = Math.floor(z + s);
|
|
7962
|
+
const t = (i + j) * unskew;
|
|
7963
|
+
const dx = x - (i - t), dz = z - (j - t);
|
|
7964
|
+
const stepX = dx > dz ? 1 : 0, stepZ = 1 - stepX;
|
|
7965
|
+
const corner = (gx, gz, a, b) => {
|
|
7966
|
+
let falloff = 0.5 - a * a - b * b;
|
|
7967
|
+
if (falloff < 0) return 0;
|
|
7968
|
+
const gradient = gradients[p10[gx + p10[gz & 255] & 255] % 12];
|
|
7969
|
+
falloff *= falloff;
|
|
7970
|
+
return falloff * falloff * (gradient[0] * a + gradient[1] * b);
|
|
7971
|
+
};
|
|
7972
|
+
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));
|
|
7973
|
+
return noise < -0.1 ? 5011004 : 6975545;
|
|
7974
|
+
}
|
|
7975
|
+
|
|
7976
|
+
// src/assets/Biomes.ts
|
|
7977
|
+
var Biomes = class {
|
|
7978
|
+
/** Loads a biome registry entry, or returns `undefined` when no source provides it. */
|
|
7979
|
+
static async get(id, origin) {
|
|
7980
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(id)) throw new MineRenderError(`Invalid biome identifier: ${id}`);
|
|
7981
|
+
const [namespace, path] = id.includes(":") ? id.split(":") : ["minecraft", id];
|
|
7982
|
+
const key = new AssetKey(namespace, path, "worldgen", "biome", "data", ".json", origin?.root);
|
|
7983
|
+
return Caching.biomeCache.get(key.serialize(), async () => {
|
|
7984
|
+
const asset2 = await AssetLoader.get(key, "json" /* JSON */);
|
|
7985
|
+
if (asset2 === void 0) return void 0;
|
|
7986
|
+
if (!asset2 || typeof asset2 !== "object" || Array.isArray(asset2) || !asset2.effects || typeof asset2.effects !== "object" || Array.isArray(asset2.effects)) {
|
|
7987
|
+
throw new MineRenderError(`Invalid biome effects: ${id}`);
|
|
7988
|
+
}
|
|
7989
|
+
if (typeof asset2.temperature !== "number" || !Number.isFinite(asset2.temperature) || typeof asset2.downfall !== "number" || !Number.isFinite(asset2.downfall)) {
|
|
7990
|
+
throw new MineRenderError(`Invalid biome climate: ${id}`);
|
|
7991
|
+
}
|
|
7992
|
+
for (const kind of ["grass", "foliage", "dry_foliage", "water"]) {
|
|
7993
|
+
const color2 = asset2.effects[`${kind}_color`];
|
|
7994
|
+
if (color2 !== void 0) this.parseColor(color2, id, kind);
|
|
7995
|
+
}
|
|
7996
|
+
const modifier = asset2.effects.grass_color_modifier;
|
|
7997
|
+
if (modifier !== void 0 && modifier !== "none" && modifier !== "dark_forest" && modifier !== "swamp") {
|
|
7998
|
+
throw new MineRenderError(`Invalid biome grass color modifier: ${id}`);
|
|
7999
|
+
}
|
|
8000
|
+
return asset2;
|
|
8001
|
+
});
|
|
8002
|
+
}
|
|
8003
|
+
/** Returns packed sRGB, or `undefined` when the biome or requested water color is missing. */
|
|
8004
|
+
static async getColor(id, kind, origin, x = 0, z = 0) {
|
|
8005
|
+
const biome = await this.get(id, origin);
|
|
8006
|
+
if (!biome) return void 0;
|
|
8007
|
+
const rawColor = biome.effects[`${kind}_color`];
|
|
8008
|
+
let color2 = rawColor === void 0 ? void 0 : this.parseColor(rawColor, id, kind);
|
|
8009
|
+
if (kind === "water") return color2;
|
|
8010
|
+
const modifier = kind === "grass" ? biome.effects.grass_color_modifier : void 0;
|
|
8011
|
+
if (modifier === "swamp") return swampGrassColor(x, z);
|
|
8012
|
+
if (color2 === void 0) {
|
|
8013
|
+
const clamp = (value) => Math.max(0, Math.min(1, Math.fround(value)));
|
|
8014
|
+
color2 = await Colormaps.getColor(kind, origin, clamp(biome.temperature), clamp(biome.downfall));
|
|
8015
|
+
}
|
|
8016
|
+
return modifier === "dark_forest" ? (color2 & 16711422) + 2634762 >> 1 : color2;
|
|
8017
|
+
}
|
|
8018
|
+
static parseColor(value, id, kind) {
|
|
8019
|
+
if (typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value)) return parseInt(value.slice(1), 16);
|
|
8020
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 16777215) return value;
|
|
8021
|
+
throw new MineRenderError(`Invalid biome ${kind} color: ${id}`);
|
|
8022
|
+
}
|
|
8023
|
+
};
|
|
8024
|
+
|
|
7906
8025
|
// src/assets/BlockEntities.ts
|
|
7907
8026
|
var import_three10 = require("three");
|
|
7908
8027
|
init_AssetKey();
|
|
@@ -12341,8 +12460,20 @@ var BlockStateResolver = class _BlockStateResolver {
|
|
|
12341
12460
|
init_Colormaps();
|
|
12342
12461
|
init_MineRenderData();
|
|
12343
12462
|
var BlockTints = class {
|
|
12344
|
-
/**
|
|
12345
|
-
static async
|
|
12463
|
+
/** Returns a block's versioned biome color source, leaving fixed-color blocks unchanged. */
|
|
12464
|
+
static async biomeSource(key) {
|
|
12465
|
+
const rule = key && (await MineRenderData.get("blockTints", key.root))[key.toNamespacedString()];
|
|
12466
|
+
return rule ? rule.biome ?? (rule.source === "grass" ? "grass" : void 0) : void 0;
|
|
12467
|
+
}
|
|
12468
|
+
/** Resolves one block's biome tint at world block coordinates, without biome blending. */
|
|
12469
|
+
static async getBiomeColor(key, biome, position) {
|
|
12470
|
+
if (!biome) return void 0;
|
|
12471
|
+
const x = position?.[0], z = position?.[2];
|
|
12472
|
+
const source = await this.biomeSource(key);
|
|
12473
|
+
return source ? Biomes.getColor(biome, source, key, x, z) : void 0;
|
|
12474
|
+
}
|
|
12475
|
+
/** Resolves used tint indices from biome or preview colors; explicit tints take precedence. */
|
|
12476
|
+
static async get(key, state, model, tints, biomeColor) {
|
|
12346
12477
|
if (!key) return tints;
|
|
12347
12478
|
const candidates = (model.elements ?? []).flatMap((element) => Object.values(element.faces)).some((face) => face?.tintindex !== void 0 && face.tintindex >= 0 && tints?.[face.tintindex] === void 0);
|
|
12348
12479
|
if (!candidates) return tints;
|
|
@@ -12358,8 +12489,12 @@ var BlockTints = class {
|
|
|
12358
12489
|
}
|
|
12359
12490
|
}
|
|
12360
12491
|
if (!indices.size) return tints;
|
|
12492
|
+
const source = rule.biome ?? (rule.source === "grass" ? "grass" : void 0);
|
|
12493
|
+
const biome = source ? typeof biomeColor === "function" ? await biomeColor() : biomeColor : void 0;
|
|
12361
12494
|
let color2;
|
|
12362
|
-
|
|
12495
|
+
if (biome !== void 0) {
|
|
12496
|
+
color2 = biome;
|
|
12497
|
+
} else switch (rule.source) {
|
|
12363
12498
|
case "constant":
|
|
12364
12499
|
color2 = rule.color;
|
|
12365
12500
|
break;
|
|
@@ -12418,6 +12553,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12418
12553
|
this._entityGeneration = 0;
|
|
12419
12554
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
12420
12555
|
this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
|
|
12556
|
+
this.biomePosition = options?.biomePosition ? [...options.biomePosition] : void 0;
|
|
12421
12557
|
}
|
|
12422
12558
|
async init() {
|
|
12423
12559
|
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
@@ -12610,11 +12746,16 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12610
12746
|
const { FluidModelObject: FluidModelObject2, sampleFluid: sampleFluid2 } = await Promise.resolve().then(() => (init_FluidModelObject(), FluidModelObject_exports));
|
|
12611
12747
|
this._fluidSampler = sample;
|
|
12612
12748
|
const surface = sampleFluid2(kind, (x, y, z) => x === 0 && y === 0 && z === 0 ? { fluid: kind, level: this.fluidLevel } : sample?.(x, y, z) ?? {});
|
|
12613
|
-
|
|
12749
|
+
const tint = this.options.tints?.[0] ?? this.waterTint;
|
|
12750
|
+
const fluidKey = `${surface.key}|${tint ?? "default"}`;
|
|
12751
|
+
if (this._fluidKey === fluidKey) return;
|
|
12614
12752
|
const key = new AssetKey("minecraft", `${kind}/${surface.key}`, "models", "fluid", "assets", ".json", this.blockState.key?.root);
|
|
12615
12753
|
const replacement = await this.scene.addSceneObject(
|
|
12616
12754
|
{ key },
|
|
12617
|
-
() => new FluidModelObject2(kind, surface.sample, this.blockState.key,
|
|
12755
|
+
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, {
|
|
12756
|
+
...this.options,
|
|
12757
|
+
tints: tint === void 0 ? this.options.tints : { ...this.options.tints, 0: tint }
|
|
12758
|
+
})
|
|
12618
12759
|
);
|
|
12619
12760
|
const previous = this._fluidModel;
|
|
12620
12761
|
const matrix = previous ? this.getModelMatrix(previous) : new import_three34.Matrix4().makeTranslation(...this.position.toArray());
|
|
@@ -12623,7 +12764,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12623
12764
|
this._models = this._models.filter((model) => model !== previous);
|
|
12624
12765
|
this._models.push(replacement);
|
|
12625
12766
|
this._fluidModel = replacement;
|
|
12626
|
-
this._fluidKey =
|
|
12767
|
+
this._fluidKey = fluidKey;
|
|
12627
12768
|
this._isInstanced || (this._isInstanced = isInstanceReference(replacement));
|
|
12628
12769
|
this._instanceCounter = this._isInstanced ? 1 : 0;
|
|
12629
12770
|
if (previous) this.removeModels([previous]);
|
|
@@ -12646,6 +12787,7 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12646
12787
|
}
|
|
12647
12788
|
async recreateModels() {
|
|
12648
12789
|
this.clearModels();
|
|
12790
|
+
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;
|
|
12649
12791
|
if (resolveBlockFluidState(this.blockState.key, this.state, this._fluidRules)?.renderModel === false) {
|
|
12650
12792
|
await this.updateFluid(this._fluidSampler);
|
|
12651
12793
|
return;
|
|
@@ -12680,7 +12822,13 @@ var _BlockObject = class _BlockObject extends SceneObject {
|
|
|
12680
12822
|
const model = await Models.getMerged(modelKey);
|
|
12681
12823
|
const options = {
|
|
12682
12824
|
...this.options,
|
|
12683
|
-
tints: model ? await BlockTints.get(
|
|
12825
|
+
tints: model ? await BlockTints.get(
|
|
12826
|
+
this.blockState.key,
|
|
12827
|
+
this.state,
|
|
12828
|
+
model,
|
|
12829
|
+
this.options.tints,
|
|
12830
|
+
() => BlockTints.getBiomeColor(this.blockState.key, this.options.biome, this.biomePosition)
|
|
12831
|
+
) : this.options.tints,
|
|
12684
12832
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0,
|
|
12685
12833
|
cullMask: this.options.displayPosition ? 0 : ModelCulling.toLocalMask(this._cullMask, rotation)
|
|
12686
12834
|
};
|
|
@@ -13267,8 +13415,323 @@ init_ModelObject();
|
|
|
13267
13415
|
// src/index.ts
|
|
13268
13416
|
init_nbt();
|
|
13269
13417
|
|
|
13270
|
-
// src/renderer/
|
|
13418
|
+
// src/renderer/FlyControls.ts
|
|
13271
13419
|
var import_three35 = require("three");
|
|
13420
|
+
var VANILLA_FLY_SPEED = 10.89;
|
|
13421
|
+
var PITCH_LIMIT = Math.PI / 2;
|
|
13422
|
+
var MOVE_EPSILON = 1e-6;
|
|
13423
|
+
var _euler = new import_three35.Euler(0, 0, 0, "YXZ");
|
|
13424
|
+
var _forward = new import_three35.Vector3();
|
|
13425
|
+
var _right = new import_three35.Vector3();
|
|
13426
|
+
var _targetVelocity = new import_three35.Vector3();
|
|
13427
|
+
var FlyControls = class extends import_three35.Controls {
|
|
13428
|
+
constructor(camera, domElement) {
|
|
13429
|
+
super(camera, domElement ?? null);
|
|
13430
|
+
this.isFlyControls = true;
|
|
13431
|
+
/** Horizontal and vertical speed in scene units per second; vanilla creative flight by default. */
|
|
13432
|
+
this.movementSpeed = 16 * VANILLA_FLY_SPEED;
|
|
13433
|
+
/** Speed multiplier while the sprint key is held. */
|
|
13434
|
+
this.sprintMultiplier = 2;
|
|
13435
|
+
/** Radians per pixel of pointer movement. */
|
|
13436
|
+
this.lookSpeed = 2e-3;
|
|
13437
|
+
/** Smooth acceleration and deceleration, approximating vanilla flight momentum. */
|
|
13438
|
+
this.enableDamping = true;
|
|
13439
|
+
/** Portion of the remaining velocity change applied per 60 Hz frame (0–1) when damping is enabled. */
|
|
13440
|
+
this.dampingFactor = 0.25;
|
|
13441
|
+
/** Capture the pointer on click so the mouse turns the camera without dragging; dragging works regardless. */
|
|
13442
|
+
this.pointerLock = true;
|
|
13443
|
+
/** Scroll the wheel to change `movementSpeed` within `speedRange`. */
|
|
13444
|
+
this.enableWheelSpeed = true;
|
|
13445
|
+
/** Minimum and maximum `movementSpeed` reachable with the wheel. */
|
|
13446
|
+
this.speedRange = [16, 16 * 500];
|
|
13447
|
+
/** Touch joystick travel in CSS pixels for full speed. */
|
|
13448
|
+
this.joystickRadius = 64;
|
|
13449
|
+
/** Key bindings by `KeyboardEvent.code`. */
|
|
13450
|
+
this.keys = {
|
|
13451
|
+
forward: ["KeyW", "ArrowUp"],
|
|
13452
|
+
back: ["KeyS", "ArrowDown"],
|
|
13453
|
+
left: ["KeyA", "ArrowLeft"],
|
|
13454
|
+
right: ["KeyD", "ArrowRight"],
|
|
13455
|
+
up: ["Space"],
|
|
13456
|
+
down: ["ShiftLeft", "ShiftRight"],
|
|
13457
|
+
sprint: ["ControlLeft", "ControlRight"]
|
|
13458
|
+
};
|
|
13459
|
+
this._pressed = /* @__PURE__ */ new Set();
|
|
13460
|
+
this._velocity = new import_three35.Vector3();
|
|
13461
|
+
this._lastPosition = new import_three35.Vector3();
|
|
13462
|
+
this._lastQuaternion = new import_three35.Quaternion();
|
|
13463
|
+
this._position0 = new import_three35.Vector3();
|
|
13464
|
+
this._quaternion0 = new import_three35.Quaternion();
|
|
13465
|
+
this._dragMoved = false;
|
|
13466
|
+
this._locked = false;
|
|
13467
|
+
this._onKeyDown = (event) => this.handleKey(event, true);
|
|
13468
|
+
this._onKeyUp = (event) => this.handleKey(event, false);
|
|
13469
|
+
this._onPointerDown = (event) => this.handlePointerDown(event);
|
|
13470
|
+
this._onPointerMove = (event) => this.handlePointerMove(event);
|
|
13471
|
+
this._onPointerUp = (event) => this.handlePointerUp(event);
|
|
13472
|
+
this._onPointerLockChange = () => this.handlePointerLockChange();
|
|
13473
|
+
this._onContextMenu = (event) => event.preventDefault();
|
|
13474
|
+
this._onWheel = (event) => this.handleWheel(event);
|
|
13475
|
+
this._onBlur = () => this.releaseKeys();
|
|
13476
|
+
this._lastPosition.copy(camera.position);
|
|
13477
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13478
|
+
this.saveState();
|
|
13479
|
+
if (domElement) this.connect(domElement);
|
|
13480
|
+
}
|
|
13481
|
+
connect(element) {
|
|
13482
|
+
super.connect(element);
|
|
13483
|
+
const document2 = element.ownerDocument;
|
|
13484
|
+
document2.addEventListener("keydown", this._onKeyDown);
|
|
13485
|
+
document2.addEventListener("keyup", this._onKeyUp);
|
|
13486
|
+
document2.addEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13487
|
+
document2.defaultView?.addEventListener("blur", this._onBlur);
|
|
13488
|
+
element.addEventListener("pointerdown", this._onPointerDown);
|
|
13489
|
+
element.addEventListener("pointermove", this._onPointerMove);
|
|
13490
|
+
element.addEventListener("pointerup", this._onPointerUp);
|
|
13491
|
+
element.addEventListener("pointercancel", this._onPointerUp);
|
|
13492
|
+
element.addEventListener("contextmenu", this._onContextMenu);
|
|
13493
|
+
element.addEventListener("wheel", this._onWheel, { passive: false });
|
|
13494
|
+
element.addEventListener("blur", this._onBlur);
|
|
13495
|
+
element.style.touchAction = "none";
|
|
13496
|
+
if (element.tabIndex < 0) element.tabIndex = 0;
|
|
13497
|
+
}
|
|
13498
|
+
disconnect() {
|
|
13499
|
+
const element = this.domElement;
|
|
13500
|
+
if (!element) return;
|
|
13501
|
+
const document2 = element.ownerDocument;
|
|
13502
|
+
document2.removeEventListener("keydown", this._onKeyDown);
|
|
13503
|
+
document2.removeEventListener("keyup", this._onKeyUp);
|
|
13504
|
+
document2.removeEventListener("pointerlockchange", this._onPointerLockChange);
|
|
13505
|
+
document2.defaultView?.removeEventListener("blur", this._onBlur);
|
|
13506
|
+
element.removeEventListener("pointerdown", this._onPointerDown);
|
|
13507
|
+
element.removeEventListener("pointermove", this._onPointerMove);
|
|
13508
|
+
element.removeEventListener("pointerup", this._onPointerUp);
|
|
13509
|
+
element.removeEventListener("pointercancel", this._onPointerUp);
|
|
13510
|
+
element.removeEventListener("contextmenu", this._onContextMenu);
|
|
13511
|
+
element.removeEventListener("wheel", this._onWheel);
|
|
13512
|
+
element.removeEventListener("blur", this._onBlur);
|
|
13513
|
+
element.style.touchAction = "auto";
|
|
13514
|
+
this.unlock();
|
|
13515
|
+
this._locked = false;
|
|
13516
|
+
this.releaseKeys();
|
|
13517
|
+
this._dragPointer = void 0;
|
|
13518
|
+
this._joystick = void 0;
|
|
13519
|
+
}
|
|
13520
|
+
dispose() {
|
|
13521
|
+
this.disconnect();
|
|
13522
|
+
}
|
|
13523
|
+
/** Whether mouse look currently owns the pointer. */
|
|
13524
|
+
get locked() {
|
|
13525
|
+
return this._locked;
|
|
13526
|
+
}
|
|
13527
|
+
/** Requests pointer capture; browsers only allow this from a user gesture. */
|
|
13528
|
+
lock() {
|
|
13529
|
+
const element = this.domElement;
|
|
13530
|
+
if (!element || this._locked || typeof element.requestPointerLock !== "function") return;
|
|
13531
|
+
try {
|
|
13532
|
+
const result = element.requestPointerLock();
|
|
13533
|
+
if (result instanceof Promise) result.catch(() => void 0);
|
|
13534
|
+
} catch {
|
|
13535
|
+
}
|
|
13536
|
+
}
|
|
13537
|
+
/** Releases a captured pointer. */
|
|
13538
|
+
unlock() {
|
|
13539
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13540
|
+
if (document2?.pointerLockElement && document2.pointerLockElement === this.domElement) {
|
|
13541
|
+
document2.exitPointerLock();
|
|
13542
|
+
}
|
|
13543
|
+
}
|
|
13544
|
+
/** Stores the camera pose that {@link reset} restores. */
|
|
13545
|
+
saveState() {
|
|
13546
|
+
this._position0.copy(this.object.position);
|
|
13547
|
+
this._quaternion0.copy(this.object.quaternion);
|
|
13548
|
+
}
|
|
13549
|
+
/** Restores the saved camera pose and stops movement. */
|
|
13550
|
+
reset() {
|
|
13551
|
+
this.object.position.copy(this._position0);
|
|
13552
|
+
this.object.quaternion.copy(this._quaternion0);
|
|
13553
|
+
this._velocity.set(0, 0, 0);
|
|
13554
|
+
this.notifyChange();
|
|
13555
|
+
}
|
|
13556
|
+
/** Horizontal yaw in radians, where zero looks toward -Z. */
|
|
13557
|
+
get yaw() {
|
|
13558
|
+
return _euler.setFromQuaternion(this.object.quaternion).y;
|
|
13559
|
+
}
|
|
13560
|
+
/** Vertical pitch in radians, positive looking up. */
|
|
13561
|
+
get pitch() {
|
|
13562
|
+
return _euler.setFromQuaternion(this.object.quaternion).x;
|
|
13563
|
+
}
|
|
13564
|
+
/** Turns the camera; pitch is clamped to straight up and down. */
|
|
13565
|
+
setRotation(yaw, pitch) {
|
|
13566
|
+
_euler.set(import_three35.MathUtils.clamp(pitch, -PITCH_LIMIT, PITCH_LIMIT), yaw, 0);
|
|
13567
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13568
|
+
this.notifyChange();
|
|
13569
|
+
}
|
|
13570
|
+
/** Points the camera at a position without rolling it. */
|
|
13571
|
+
lookAt(target) {
|
|
13572
|
+
_forward.copy(target).sub(this.object.position);
|
|
13573
|
+
if (_forward.lengthSq() < MOVE_EPSILON) return;
|
|
13574
|
+
_forward.normalize();
|
|
13575
|
+
this.setRotation(Math.atan2(-_forward.x, -_forward.z), Math.asin(import_three35.MathUtils.clamp(_forward.y, -1, 1)));
|
|
13576
|
+
}
|
|
13577
|
+
/** Whether an action's key is held. */
|
|
13578
|
+
isPressed(action) {
|
|
13579
|
+
return this._pressed.has(action);
|
|
13580
|
+
}
|
|
13581
|
+
/**
|
|
13582
|
+
* Advances movement by `delta` seconds (measured since the previous call when omitted)
|
|
13583
|
+
* and dispatches `change` when the camera moved.
|
|
13584
|
+
*/
|
|
13585
|
+
update(delta) {
|
|
13586
|
+
if (delta === void 0) {
|
|
13587
|
+
const now = typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
13588
|
+
delta = this._lastTime === void 0 ? 0 : (now - this._lastTime) / 1e3;
|
|
13589
|
+
this._lastTime = now;
|
|
13590
|
+
}
|
|
13591
|
+
if (!this.enabled) {
|
|
13592
|
+
this._velocity.set(0, 0, 0);
|
|
13593
|
+
return;
|
|
13594
|
+
}
|
|
13595
|
+
if (delta > 0) this.move(delta);
|
|
13596
|
+
this.notifyChange();
|
|
13597
|
+
}
|
|
13598
|
+
move(delta) {
|
|
13599
|
+
const camera = this.object;
|
|
13600
|
+
let forward = (this._pressed.has("forward") ? 1 : 0) - (this._pressed.has("back") ? 1 : 0);
|
|
13601
|
+
let strafe = (this._pressed.has("right") ? 1 : 0) - (this._pressed.has("left") ? 1 : 0);
|
|
13602
|
+
const climb = (this._pressed.has("up") ? 1 : 0) - (this._pressed.has("down") ? 1 : 0);
|
|
13603
|
+
const joystick = this._joystick;
|
|
13604
|
+
if (joystick) {
|
|
13605
|
+
const radius = Math.max(this.joystickRadius, 1);
|
|
13606
|
+
forward = import_three35.MathUtils.clamp(forward + (joystick.originY - joystick.y) / radius, -1, 1);
|
|
13607
|
+
strafe = import_three35.MathUtils.clamp(strafe + (joystick.x - joystick.originX) / radius, -1, 1);
|
|
13608
|
+
}
|
|
13609
|
+
_euler.setFromQuaternion(camera.quaternion);
|
|
13610
|
+
const yaw = _euler.y;
|
|
13611
|
+
_forward.set(-Math.sin(yaw), 0, -Math.cos(yaw));
|
|
13612
|
+
_right.set(Math.cos(yaw), 0, -Math.sin(yaw));
|
|
13613
|
+
_targetVelocity.set(0, 0, 0);
|
|
13614
|
+
if (forward || strafe || climb) {
|
|
13615
|
+
_targetVelocity.addScaledVector(_forward, forward).addScaledVector(_right, strafe);
|
|
13616
|
+
if (_targetVelocity.lengthSq() > 1) _targetVelocity.normalize();
|
|
13617
|
+
_targetVelocity.y = climb;
|
|
13618
|
+
const speed = this.movementSpeed * (this._pressed.has("sprint") ? this.sprintMultiplier : 1);
|
|
13619
|
+
_targetVelocity.multiplyScalar(speed);
|
|
13620
|
+
}
|
|
13621
|
+
if (this.enableDamping) {
|
|
13622
|
+
const blend = 1 - Math.pow(1 - import_three35.MathUtils.clamp(this.dampingFactor, 0, 1), delta * 60);
|
|
13623
|
+
this._velocity.lerp(_targetVelocity, blend);
|
|
13624
|
+
if (_targetVelocity.lengthSq() === 0 && this._velocity.lengthSq() < MOVE_EPSILON) this._velocity.set(0, 0, 0);
|
|
13625
|
+
} else {
|
|
13626
|
+
this._velocity.copy(_targetVelocity);
|
|
13627
|
+
}
|
|
13628
|
+
camera.position.addScaledVector(this._velocity, delta);
|
|
13629
|
+
}
|
|
13630
|
+
notifyChange() {
|
|
13631
|
+
const camera = this.object;
|
|
13632
|
+
if (this._lastPosition.distanceToSquared(camera.position) > MOVE_EPSILON || 8 * (1 - this._lastQuaternion.dot(camera.quaternion)) > MOVE_EPSILON) {
|
|
13633
|
+
this._lastPosition.copy(camera.position);
|
|
13634
|
+
this._lastQuaternion.copy(camera.quaternion);
|
|
13635
|
+
this.dispatchEvent({ type: "change" });
|
|
13636
|
+
}
|
|
13637
|
+
}
|
|
13638
|
+
releaseKeys() {
|
|
13639
|
+
this._pressed.clear();
|
|
13640
|
+
}
|
|
13641
|
+
handleKey(event, down) {
|
|
13642
|
+
const action = this.actionFor(event.code);
|
|
13643
|
+
if (!action) return;
|
|
13644
|
+
const ownsInput = this.enabled && (this._locked || event.target === this.domElement);
|
|
13645
|
+
if (down && !ownsInput) return;
|
|
13646
|
+
const pressed = this._pressed.has(action);
|
|
13647
|
+
if (down) this._pressed.add(action);
|
|
13648
|
+
else this._pressed.delete(action);
|
|
13649
|
+
if (ownsInput || this.enabled && pressed) event.preventDefault();
|
|
13650
|
+
}
|
|
13651
|
+
actionFor(code) {
|
|
13652
|
+
for (const action in this.keys) {
|
|
13653
|
+
if (this.keys[action].includes(code)) return action;
|
|
13654
|
+
}
|
|
13655
|
+
return void 0;
|
|
13656
|
+
}
|
|
13657
|
+
handlePointerDown(event) {
|
|
13658
|
+
const element = this.domElement;
|
|
13659
|
+
if (!this.enabled || !element) return;
|
|
13660
|
+
element.focus?.({ preventScroll: true });
|
|
13661
|
+
if (this._locked) return;
|
|
13662
|
+
if (event.pointerType === "touch" && !this._joystick && this.onJoystickSide(event)) {
|
|
13663
|
+
this._joystick = { id: event.pointerId, originX: event.clientX, originY: event.clientY, x: event.clientX, y: event.clientY };
|
|
13664
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13665
|
+
return;
|
|
13666
|
+
}
|
|
13667
|
+
if (this._dragPointer !== void 0) return;
|
|
13668
|
+
if (event.pointerType === "mouse" && event.button !== 0 && event.button !== 2) return;
|
|
13669
|
+
this._dragPointer = event.pointerId;
|
|
13670
|
+
this._dragMoved = false;
|
|
13671
|
+
element.setPointerCapture?.(event.pointerId);
|
|
13672
|
+
}
|
|
13673
|
+
onJoystickSide(event) {
|
|
13674
|
+
const rect = this.domElement?.getBoundingClientRect?.();
|
|
13675
|
+
return !!rect && event.clientX < rect.left + rect.width / 2;
|
|
13676
|
+
}
|
|
13677
|
+
handlePointerMove(event) {
|
|
13678
|
+
if (!this.enabled) return;
|
|
13679
|
+
const joystick = this._joystick;
|
|
13680
|
+
if (joystick && event.pointerId === joystick.id) {
|
|
13681
|
+
joystick.x = event.clientX;
|
|
13682
|
+
joystick.y = event.clientY;
|
|
13683
|
+
return;
|
|
13684
|
+
}
|
|
13685
|
+
if (!this._locked && event.pointerId !== this._dragPointer) return;
|
|
13686
|
+
const dx = event.movementX ?? 0;
|
|
13687
|
+
const dy = event.movementY ?? 0;
|
|
13688
|
+
if (!dx && !dy) return;
|
|
13689
|
+
this._dragMoved = true;
|
|
13690
|
+
this.turn(dx, dy);
|
|
13691
|
+
}
|
|
13692
|
+
handlePointerUp(event) {
|
|
13693
|
+
if (this._joystick?.id === event.pointerId) {
|
|
13694
|
+
this._joystick = void 0;
|
|
13695
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13696
|
+
return;
|
|
13697
|
+
}
|
|
13698
|
+
if (event.pointerId !== this._dragPointer) return;
|
|
13699
|
+
this._dragPointer = void 0;
|
|
13700
|
+
this.domElement?.releasePointerCapture?.(event.pointerId);
|
|
13701
|
+
if (this.enabled && this.pointerLock && !this._dragMoved && event.pointerType === "mouse" && event.button === 0) {
|
|
13702
|
+
this.lock();
|
|
13703
|
+
}
|
|
13704
|
+
}
|
|
13705
|
+
handleWheel(event) {
|
|
13706
|
+
if (!this.enabled || !this.enableWheelSpeed) return;
|
|
13707
|
+
event.preventDefault();
|
|
13708
|
+
const steps = event.deltaMode === 0 ? event.deltaY / 100 : event.deltaY;
|
|
13709
|
+
const [min, max] = this.speedRange;
|
|
13710
|
+
this.movementSpeed = import_three35.MathUtils.clamp(this.movementSpeed * Math.pow(1.15, -steps), Math.min(min, max), Math.max(min, max));
|
|
13711
|
+
}
|
|
13712
|
+
handlePointerLockChange() {
|
|
13713
|
+
const document2 = this.domElement?.ownerDocument;
|
|
13714
|
+
const locked = !!document2 && document2.pointerLockElement === this.domElement;
|
|
13715
|
+
if (locked === this._locked) return;
|
|
13716
|
+
this._locked = locked;
|
|
13717
|
+
if (!locked) this.releaseKeys();
|
|
13718
|
+
this.dispatchEvent({ type: locked ? "lock" : "unlock" });
|
|
13719
|
+
}
|
|
13720
|
+
turn(dx, dy) {
|
|
13721
|
+
_euler.setFromQuaternion(this.object.quaternion);
|
|
13722
|
+
_euler.y -= dx * this.lookSpeed;
|
|
13723
|
+
_euler.x = import_three35.MathUtils.clamp(_euler.x - dy * this.lookSpeed, -PITCH_LIMIT, PITCH_LIMIT);
|
|
13724
|
+
_euler.z = 0;
|
|
13725
|
+
this.object.quaternion.setFromEuler(_euler);
|
|
13726
|
+
this.notifyChange();
|
|
13727
|
+
}
|
|
13728
|
+
};
|
|
13729
|
+
function isFlyControls(obj) {
|
|
13730
|
+
return obj?.isFlyControls === true;
|
|
13731
|
+
}
|
|
13732
|
+
|
|
13733
|
+
// src/renderer/MineRenderScene.ts
|
|
13734
|
+
var import_three36 = require("three");
|
|
13272
13735
|
init_SceneObject();
|
|
13273
13736
|
var import_ts_deepmerge8 = __toESM(require_dist());
|
|
13274
13737
|
init_ModelObject();
|
|
@@ -14178,7 +14641,7 @@ var SkinObject = class extends SceneObject {
|
|
|
14178
14641
|
// src/renderer/MineRenderScene.ts
|
|
14179
14642
|
init_EntityObject();
|
|
14180
14643
|
init_ItemTints();
|
|
14181
|
-
var _MineRenderScene = class _MineRenderScene extends
|
|
14644
|
+
var _MineRenderScene = class _MineRenderScene extends import_three36.Scene {
|
|
14182
14645
|
constructor(options) {
|
|
14183
14646
|
super();
|
|
14184
14647
|
this.isMineRenderScene = true;
|
|
@@ -14333,7 +14796,7 @@ function isMineRenderScene(obj) {
|
|
|
14333
14796
|
}
|
|
14334
14797
|
|
|
14335
14798
|
// src/renderer/Renderer.ts
|
|
14336
|
-
var
|
|
14799
|
+
var import_three38 = require("three");
|
|
14337
14800
|
var import_ts_deepmerge9 = __toESM(require_dist());
|
|
14338
14801
|
var import_stats = __toESM(require("stats.js"));
|
|
14339
14802
|
var import_postprocessing = require("postprocessing");
|
|
@@ -14342,11 +14805,11 @@ init_Model();
|
|
|
14342
14805
|
init_three();
|
|
14343
14806
|
|
|
14344
14807
|
// src/three/OrbitControls.js
|
|
14345
|
-
var
|
|
14808
|
+
var import_three37 = require("three");
|
|
14346
14809
|
var _changeEvent = { type: "change" };
|
|
14347
14810
|
var _startEvent = { type: "start" };
|
|
14348
14811
|
var _endEvent = { type: "end" };
|
|
14349
|
-
var OrbitControls = class extends
|
|
14812
|
+
var OrbitControls = class extends import_three37.EventDispatcher {
|
|
14350
14813
|
constructor(object4, domElement) {
|
|
14351
14814
|
super();
|
|
14352
14815
|
if (domElement === void 0) console.warn('THREE.OrbitControls: The second parameter "domElement" is now mandatory.');
|
|
@@ -14355,7 +14818,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14355
14818
|
this.domElement = domElement;
|
|
14356
14819
|
this.domElement.style.touchAction = "none";
|
|
14357
14820
|
this.enabled = true;
|
|
14358
|
-
this.target = new
|
|
14821
|
+
this.target = new import_three37.Vector3();
|
|
14359
14822
|
this.minDistance = 0;
|
|
14360
14823
|
this.maxDistance = Infinity;
|
|
14361
14824
|
this.minZoom = 0;
|
|
@@ -14377,8 +14840,8 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14377
14840
|
this.autoRotate = false;
|
|
14378
14841
|
this.autoRotateSpeed = 2;
|
|
14379
14842
|
this.keys = { LEFT: "ArrowLeft", UP: "ArrowUp", RIGHT: "ArrowRight", BOTTOM: "ArrowDown" };
|
|
14380
|
-
this.mouseButtons = { LEFT:
|
|
14381
|
-
this.touches = { ONE:
|
|
14843
|
+
this.mouseButtons = { LEFT: import_three37.MOUSE.ROTATE, MIDDLE: import_three37.MOUSE.DOLLY, RIGHT: import_three37.MOUSE.PAN };
|
|
14844
|
+
this.touches = { ONE: import_three37.TOUCH.ROTATE, TWO: import_three37.TOUCH.DOLLY_PAN };
|
|
14382
14845
|
this.target0 = this.target.clone();
|
|
14383
14846
|
this.position0 = this.object.position.clone();
|
|
14384
14847
|
this.zoom0 = this.object.zoom;
|
|
@@ -14407,11 +14870,11 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14407
14870
|
state = STATE.NONE;
|
|
14408
14871
|
};
|
|
14409
14872
|
this.update = function() {
|
|
14410
|
-
const offset = new
|
|
14411
|
-
const quat = new
|
|
14873
|
+
const offset = new import_three37.Vector3();
|
|
14874
|
+
const quat = new import_three37.Quaternion().setFromUnitVectors(object4.up, new import_three37.Vector3(0, 1, 0));
|
|
14412
14875
|
const quatInverse = quat.clone().invert();
|
|
14413
|
-
const lastPosition = new
|
|
14414
|
-
const lastQuaternion = new
|
|
14876
|
+
const lastPosition = new import_three37.Vector3();
|
|
14877
|
+
const lastQuaternion = new import_three37.Quaternion();
|
|
14415
14878
|
const twoPI = 2 * Math.PI;
|
|
14416
14879
|
return function update() {
|
|
14417
14880
|
const position = scope.object.position;
|
|
@@ -14497,20 +14960,20 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14497
14960
|
};
|
|
14498
14961
|
let state = STATE.NONE;
|
|
14499
14962
|
const EPS = 1e-6;
|
|
14500
|
-
const spherical = new
|
|
14501
|
-
const sphericalDelta = new
|
|
14963
|
+
const spherical = new import_three37.Spherical();
|
|
14964
|
+
const sphericalDelta = new import_three37.Spherical();
|
|
14502
14965
|
let scale = 1;
|
|
14503
|
-
const panOffset = new
|
|
14966
|
+
const panOffset = new import_three37.Vector3();
|
|
14504
14967
|
let zoomChanged = false;
|
|
14505
|
-
const rotateStart = new
|
|
14506
|
-
const rotateEnd = new
|
|
14507
|
-
const rotateDelta = new
|
|
14508
|
-
const panStart = new
|
|
14509
|
-
const panEnd = new
|
|
14510
|
-
const panDelta = new
|
|
14511
|
-
const dollyStart = new
|
|
14512
|
-
const dollyEnd = new
|
|
14513
|
-
const dollyDelta = new
|
|
14968
|
+
const rotateStart = new import_three37.Vector2();
|
|
14969
|
+
const rotateEnd = new import_three37.Vector2();
|
|
14970
|
+
const rotateDelta = new import_three37.Vector2();
|
|
14971
|
+
const panStart = new import_three37.Vector2();
|
|
14972
|
+
const panEnd = new import_three37.Vector2();
|
|
14973
|
+
const panDelta = new import_three37.Vector2();
|
|
14974
|
+
const dollyStart = new import_three37.Vector2();
|
|
14975
|
+
const dollyEnd = new import_three37.Vector2();
|
|
14976
|
+
const dollyDelta = new import_three37.Vector2();
|
|
14514
14977
|
const pointers = [];
|
|
14515
14978
|
const pointerPositions = {};
|
|
14516
14979
|
function getAutoRotationAngle() {
|
|
@@ -14526,7 +14989,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14526
14989
|
sphericalDelta.phi -= angle;
|
|
14527
14990
|
}
|
|
14528
14991
|
const panLeft = function() {
|
|
14529
|
-
const v = new
|
|
14992
|
+
const v = new import_three37.Vector3();
|
|
14530
14993
|
return function panLeft2(distance, objectMatrix) {
|
|
14531
14994
|
v.setFromMatrixColumn(objectMatrix, 0);
|
|
14532
14995
|
v.multiplyScalar(-distance);
|
|
@@ -14534,7 +14997,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14534
14997
|
};
|
|
14535
14998
|
}();
|
|
14536
14999
|
const panUp = function() {
|
|
14537
|
-
const v = new
|
|
15000
|
+
const v = new import_three37.Vector3();
|
|
14538
15001
|
return function panUp2(distance, objectMatrix) {
|
|
14539
15002
|
if (scope.screenSpacePanning === true) {
|
|
14540
15003
|
v.setFromMatrixColumn(objectMatrix, 1);
|
|
@@ -14547,7 +15010,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14547
15010
|
};
|
|
14548
15011
|
}();
|
|
14549
15012
|
const pan = function() {
|
|
14550
|
-
const offset = new
|
|
15013
|
+
const offset = new import_three37.Vector3();
|
|
14551
15014
|
return function pan2(deltaX, deltaY) {
|
|
14552
15015
|
const element = scope.domElement;
|
|
14553
15016
|
if (scope.object.isPerspectiveCamera) {
|
|
@@ -14796,12 +15259,12 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14796
15259
|
mouseAction = -1;
|
|
14797
15260
|
}
|
|
14798
15261
|
switch (mouseAction) {
|
|
14799
|
-
case
|
|
15262
|
+
case import_three37.MOUSE.DOLLY:
|
|
14800
15263
|
if (scope.enableZoom === false) return;
|
|
14801
15264
|
handleMouseDownDolly(event);
|
|
14802
15265
|
state = STATE.DOLLY;
|
|
14803
15266
|
break;
|
|
14804
|
-
case
|
|
15267
|
+
case import_three37.MOUSE.ROTATE:
|
|
14805
15268
|
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
14806
15269
|
if (scope.enablePan === false) return;
|
|
14807
15270
|
handleMouseDownPan(event);
|
|
@@ -14812,7 +15275,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14812
15275
|
state = STATE.ROTATE;
|
|
14813
15276
|
}
|
|
14814
15277
|
break;
|
|
14815
|
-
case
|
|
15278
|
+
case import_three37.MOUSE.PAN:
|
|
14816
15279
|
if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
|
14817
15280
|
if (scope.enableRotate === false) return;
|
|
14818
15281
|
handleMouseDownRotate(event);
|
|
@@ -14868,12 +15331,12 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14868
15331
|
switch (pointers.length) {
|
|
14869
15332
|
case 1:
|
|
14870
15333
|
switch (scope.touches.ONE) {
|
|
14871
|
-
case
|
|
15334
|
+
case import_three37.TOUCH.ROTATE:
|
|
14872
15335
|
if (scope.enableRotate === false) return;
|
|
14873
15336
|
handleTouchStartRotate();
|
|
14874
15337
|
state = STATE.TOUCH_ROTATE;
|
|
14875
15338
|
break;
|
|
14876
|
-
case
|
|
15339
|
+
case import_three37.TOUCH.PAN:
|
|
14877
15340
|
if (scope.enablePan === false) return;
|
|
14878
15341
|
handleTouchStartPan();
|
|
14879
15342
|
state = STATE.TOUCH_PAN;
|
|
@@ -14884,12 +15347,12 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14884
15347
|
break;
|
|
14885
15348
|
case 2:
|
|
14886
15349
|
switch (scope.touches.TWO) {
|
|
14887
|
-
case
|
|
15350
|
+
case import_three37.TOUCH.DOLLY_PAN:
|
|
14888
15351
|
if (scope.enableZoom === false && scope.enablePan === false) return;
|
|
14889
15352
|
handleTouchStartDollyPan();
|
|
14890
15353
|
state = STATE.TOUCH_DOLLY_PAN;
|
|
14891
15354
|
break;
|
|
14892
|
-
case
|
|
15355
|
+
case import_three37.TOUCH.DOLLY_ROTATE:
|
|
14893
15356
|
if (scope.enableZoom === false && scope.enableRotate === false) return;
|
|
14894
15357
|
handleTouchStartDollyRotate();
|
|
14895
15358
|
state = STATE.TOUCH_DOLLY_ROTATE;
|
|
@@ -14956,7 +15419,7 @@ var OrbitControls = class extends import_three36.EventDispatcher {
|
|
|
14956
15419
|
function trackPointer(event) {
|
|
14957
15420
|
let position = pointerPositions[event.pointerId];
|
|
14958
15421
|
if (position === void 0) {
|
|
14959
|
-
position = new
|
|
15422
|
+
position = new import_three37.Vector2();
|
|
14960
15423
|
pointerPositions[event.pointerId] = position;
|
|
14961
15424
|
}
|
|
14962
15425
|
position.set(event.pageX, event.pageY);
|
|
@@ -14976,10 +15439,10 @@ var MapControls = class extends OrbitControls {
|
|
|
14976
15439
|
constructor(object4, domElement) {
|
|
14977
15440
|
super(object4, domElement);
|
|
14978
15441
|
this.screenSpacePanning = false;
|
|
14979
|
-
this.mouseButtons.LEFT =
|
|
14980
|
-
this.mouseButtons.RIGHT =
|
|
14981
|
-
this.touches.ONE =
|
|
14982
|
-
this.touches.TWO =
|
|
15442
|
+
this.mouseButtons.LEFT = import_three37.MOUSE.PAN;
|
|
15443
|
+
this.mouseButtons.RIGHT = import_three37.MOUSE.ROTATE;
|
|
15444
|
+
this.touches.ONE = import_three37.TOUCH.PAN;
|
|
15445
|
+
this.touches.TWO = import_three37.TOUCH.DOLLY_ROTATE;
|
|
14983
15446
|
}
|
|
14984
15447
|
};
|
|
14985
15448
|
|
|
@@ -15050,14 +15513,14 @@ var _Renderer = class _Renderer {
|
|
|
15050
15513
|
switch (this.options.camera.type) {
|
|
15051
15514
|
case "perspective":
|
|
15052
15515
|
default:
|
|
15053
|
-
return new
|
|
15516
|
+
return new import_three38.PerspectiveCamera(
|
|
15054
15517
|
this.options.camera.perspective.fov,
|
|
15055
15518
|
this.options.camera.perspective.aspect ?? this.viewWidth / this.viewHeight,
|
|
15056
15519
|
this.options.camera.near,
|
|
15057
15520
|
this.options.camera.far
|
|
15058
15521
|
);
|
|
15059
15522
|
case "orthographic":
|
|
15060
|
-
return new
|
|
15523
|
+
return new import_three38.OrthographicCamera(
|
|
15061
15524
|
this.options.camera.orthographic.left ?? this.viewWidth / -2,
|
|
15062
15525
|
this.options.camera.orthographic.right ?? this.viewWidth / 2,
|
|
15063
15526
|
this.options.camera.orthographic.top ?? this.viewHeight / 2,
|
|
@@ -15073,7 +15536,7 @@ var _Renderer = class _Renderer {
|
|
|
15073
15536
|
}
|
|
15074
15537
|
const pixelRatio = this.options.render.pixelRatio ?? 1;
|
|
15075
15538
|
this._surface?.resize?.(Math.floor(this.viewWidth * pixelRatio), Math.floor(this.viewHeight * pixelRatio));
|
|
15076
|
-
const renderer = new
|
|
15539
|
+
const renderer = new import_three38.WebGLRenderer({
|
|
15077
15540
|
canvas: this._surface?.canvas,
|
|
15078
15541
|
context: this._surface?.context,
|
|
15079
15542
|
antialias: this.options.render.antialias,
|
|
@@ -15083,8 +15546,8 @@ var _Renderer = class _Renderer {
|
|
|
15083
15546
|
});
|
|
15084
15547
|
renderer.setClearColor(0, 0);
|
|
15085
15548
|
renderer.shadowMap.enabled = true;
|
|
15086
|
-
renderer.shadowMap.type =
|
|
15087
|
-
renderer.outputColorSpace =
|
|
15549
|
+
renderer.shadowMap.type = import_three38.PCFShadowMap;
|
|
15550
|
+
renderer.outputColorSpace = import_three38.SRGBColorSpace;
|
|
15088
15551
|
if (this._surface) {
|
|
15089
15552
|
renderer.setDrawingBufferSize(this.viewWidth, this.viewHeight, pixelRatio);
|
|
15090
15553
|
} else {
|
|
@@ -15102,20 +15565,77 @@ var _Renderer = class _Renderer {
|
|
|
15102
15565
|
}
|
|
15103
15566
|
createControls() {
|
|
15104
15567
|
if (!this.options.controls?.enabled) return void 0;
|
|
15105
|
-
|
|
15106
|
-
|
|
15107
|
-
|
|
15568
|
+
return this.createControlsFor(this.options.controls.mode ?? "orbit", this.initialTarget());
|
|
15569
|
+
}
|
|
15570
|
+
initialTarget() {
|
|
15108
15571
|
const target = this.options.camera.lookingAt;
|
|
15109
|
-
if (isVector3(target))
|
|
15572
|
+
if (isVector3(target)) return target.clone();
|
|
15573
|
+
if (isTripleArray(target)) return new import_three38.Vector3(target[0], target[1], target[2]);
|
|
15574
|
+
return new import_three38.Vector3();
|
|
15575
|
+
}
|
|
15576
|
+
createControlsFor(mode, target) {
|
|
15577
|
+
let controls;
|
|
15578
|
+
if (mode === "fly") {
|
|
15579
|
+
controls = new FlyControls(this.camera, this.renderer.domElement);
|
|
15580
|
+
controls.lookAt(target);
|
|
15581
|
+
controls.saveState();
|
|
15582
|
+
} else {
|
|
15583
|
+
const position = this.camera.position.clone();
|
|
15584
|
+
controls = new OrbitControls(this.camera, this.renderer.domElement);
|
|
15585
|
+
this.camera.position.copy(position);
|
|
15110
15586
|
controls.target.copy(target);
|
|
15111
|
-
|
|
15112
|
-
controls.
|
|
15587
|
+
controls.update();
|
|
15588
|
+
controls.saveState();
|
|
15113
15589
|
}
|
|
15114
|
-
|
|
15115
|
-
controls.saveState();
|
|
15590
|
+
this._controlsTime = void 0;
|
|
15116
15591
|
this.registerEventDispatcher(controls);
|
|
15117
15592
|
return controls;
|
|
15118
15593
|
}
|
|
15594
|
+
/**
|
|
15595
|
+
* Replaces renderer-owned controls with the selected mode, keeping the camera where it is.
|
|
15596
|
+
* Switching to orbit controls targets the point the camera looks at, at the previous orbit distance.
|
|
15597
|
+
* Returns the new controls, or undefined when controls were disabled at construction or after disposal.
|
|
15598
|
+
*/
|
|
15599
|
+
setControlsMode(mode) {
|
|
15600
|
+
const current = this._controls;
|
|
15601
|
+
if (this._disposed || !current) return void 0;
|
|
15602
|
+
if (this.controlsMode === mode) return current;
|
|
15603
|
+
let target;
|
|
15604
|
+
if (isFlyControls(current)) {
|
|
15605
|
+
const distance = this._orbitDistance ?? (this.camera.position.distanceTo(this.initialTarget()) || 1);
|
|
15606
|
+
target = new import_three38.Vector3(0, 0, -distance).applyQuaternion(this.camera.quaternion).add(this.camera.position);
|
|
15607
|
+
} else {
|
|
15608
|
+
target = current.target.clone();
|
|
15609
|
+
this._orbitDistance = this.camera.position.distanceTo(target);
|
|
15610
|
+
}
|
|
15611
|
+
const enabled = current.enabled;
|
|
15612
|
+
this.disposeControls(current);
|
|
15613
|
+
this._controls = this.createControlsFor(mode, target);
|
|
15614
|
+
this._controls.enabled = enabled;
|
|
15615
|
+
this.dirty = true;
|
|
15616
|
+
return this._controls;
|
|
15617
|
+
}
|
|
15618
|
+
disposeControls(controls) {
|
|
15619
|
+
this._controls = void 0;
|
|
15620
|
+
this.unregisterEventDispatcher(controls);
|
|
15621
|
+
controls.enabled = false;
|
|
15622
|
+
controls.dispose();
|
|
15623
|
+
}
|
|
15624
|
+
/** Advances owned controls; without a frame time, flight movement does not progress. */
|
|
15625
|
+
updateControls(time) {
|
|
15626
|
+
const controls = this._controls;
|
|
15627
|
+
if (!controls?.enabled) {
|
|
15628
|
+
this._controlsTime = void 0;
|
|
15629
|
+
return;
|
|
15630
|
+
}
|
|
15631
|
+
if (!isFlyControls(controls)) {
|
|
15632
|
+
controls.update();
|
|
15633
|
+
return;
|
|
15634
|
+
}
|
|
15635
|
+
const previous = this._controlsTime;
|
|
15636
|
+
if (time !== void 0) this._controlsTime = time;
|
|
15637
|
+
controls.update(time === void 0 || previous === void 0 ? 0 : (time - previous) / 1e3);
|
|
15638
|
+
}
|
|
15119
15639
|
//</editor-fold>
|
|
15120
15640
|
init() {
|
|
15121
15641
|
if (this._disposed) return;
|
|
@@ -15123,20 +15643,20 @@ var _Renderer = class _Renderer {
|
|
|
15123
15643
|
window["__THREE_DEVTOOLS__"].dispatchEvent(new CustomEvent("observe", { detail: this.scene }));
|
|
15124
15644
|
}
|
|
15125
15645
|
if (this.options.debug.grid) {
|
|
15126
|
-
const gridHelper = new
|
|
15646
|
+
const gridHelper = new import_three38.GridHelper(128, 16);
|
|
15127
15647
|
this._debugHelpers.push(gridHelper);
|
|
15128
15648
|
this.scene.add(gridHelper);
|
|
15129
|
-
const gridHelper2 = new
|
|
15649
|
+
const gridHelper2 = new import_three38.GridHelper(128, 16);
|
|
15130
15650
|
this._debugHelpers.push(gridHelper2);
|
|
15131
15651
|
gridHelper2.rotation.x = 90 * (Math.PI / 180);
|
|
15132
15652
|
this.scene.add(gridHelper2);
|
|
15133
|
-
const gridHelper3 = new
|
|
15653
|
+
const gridHelper3 = new import_three38.GridHelper(128, 16);
|
|
15134
15654
|
this._debugHelpers.push(gridHelper3);
|
|
15135
15655
|
gridHelper3.rotation.z = 90 * (Math.PI / 180);
|
|
15136
15656
|
this.scene.add(gridHelper3);
|
|
15137
15657
|
}
|
|
15138
15658
|
if (this.options.debug.axes) {
|
|
15139
|
-
const axesHelper = new
|
|
15659
|
+
const axesHelper = new import_three38.AxesHelper(64);
|
|
15140
15660
|
this._debugHelpers.push(axesHelper);
|
|
15141
15661
|
this.scene.add(axesHelper);
|
|
15142
15662
|
}
|
|
@@ -15192,6 +15712,12 @@ var _Renderer = class _Renderer {
|
|
|
15192
15712
|
events.add(changeEvent2);
|
|
15193
15713
|
dispatcher.addEventListener(changeEvent2, this._changeListener);
|
|
15194
15714
|
}
|
|
15715
|
+
unregisterEventDispatcher(dispatcher) {
|
|
15716
|
+
const events = this._eventDispatchers.get(dispatcher);
|
|
15717
|
+
if (!events) return;
|
|
15718
|
+
for (const event of events) dispatcher.removeEventListener(event, this._changeListener);
|
|
15719
|
+
this._eventDispatchers.delete(dispatcher);
|
|
15720
|
+
}
|
|
15195
15721
|
/** Updates the camera and canvas size. Width and height are in CSS pixels. */
|
|
15196
15722
|
resize(width, height) {
|
|
15197
15723
|
if (this._disposed) return;
|
|
@@ -15268,6 +15794,7 @@ var _Renderer = class _Renderer {
|
|
|
15268
15794
|
this.renderer.setAnimationLoop(null);
|
|
15269
15795
|
}
|
|
15270
15796
|
this._nextFrameTime = void 0;
|
|
15797
|
+
this._controlsTime = void 0;
|
|
15271
15798
|
for (const subscription of this._frameCallbacks.values()) subscription.previous = void 0;
|
|
15272
15799
|
}
|
|
15273
15800
|
/**
|
|
@@ -15297,10 +15824,7 @@ var _Renderer = class _Renderer {
|
|
|
15297
15824
|
}
|
|
15298
15825
|
this._element = void 0;
|
|
15299
15826
|
if (this._controls) {
|
|
15300
|
-
|
|
15301
|
-
this._controls = void 0;
|
|
15302
|
-
controls.enabled = false;
|
|
15303
|
-
controls.dispose();
|
|
15827
|
+
this.disposeControls(this._controls);
|
|
15304
15828
|
}
|
|
15305
15829
|
this.scene.clear();
|
|
15306
15830
|
for (const helper of this._debugHelpers) {
|
|
@@ -15317,9 +15841,7 @@ var _Renderer = class _Renderer {
|
|
|
15317
15841
|
}
|
|
15318
15842
|
animate(t = performance.now()) {
|
|
15319
15843
|
if (!this._running) return;
|
|
15320
|
-
|
|
15321
|
-
this._controls.update();
|
|
15322
|
-
}
|
|
15844
|
+
this.updateControls(t);
|
|
15323
15845
|
if (!this._running) return;
|
|
15324
15846
|
if (!this.dirty && !this.options.render.renderAlways && !this._frameCallbacks.size && !this._videoExporter) return;
|
|
15325
15847
|
const interval = this._frameInterval;
|
|
@@ -15356,7 +15878,7 @@ var _Renderer = class _Renderer {
|
|
|
15356
15878
|
/** Draws a fresh frame without starting the animation loop or invoking frame callbacks. */
|
|
15357
15879
|
renderOnce() {
|
|
15358
15880
|
if (this._disposed) throw new Error("Cannot render a disposed renderer");
|
|
15359
|
-
|
|
15881
|
+
this.updateControls();
|
|
15360
15882
|
this.drawFrame();
|
|
15361
15883
|
}
|
|
15362
15884
|
/**
|
|
@@ -15386,7 +15908,7 @@ var _Renderer = class _Renderer {
|
|
|
15386
15908
|
try {
|
|
15387
15909
|
if (!wasRunning) this.start();
|
|
15388
15910
|
this._videoExporter = exporter;
|
|
15389
|
-
|
|
15911
|
+
this.updateControls();
|
|
15390
15912
|
this.drawFrame();
|
|
15391
15913
|
} catch (error) {
|
|
15392
15914
|
exporter.cancel(error);
|
|
@@ -15437,6 +15959,19 @@ var _Renderer = class _Renderer {
|
|
|
15437
15959
|
get controls() {
|
|
15438
15960
|
return this._controls;
|
|
15439
15961
|
}
|
|
15962
|
+
/** Renderer-owned OrbitControls, or undefined in fly mode or without controls. */
|
|
15963
|
+
get orbitControls() {
|
|
15964
|
+
return this._controls && !isFlyControls(this._controls) ? this._controls : void 0;
|
|
15965
|
+
}
|
|
15966
|
+
/** Renderer-owned {@link FlyControls}, or undefined in orbit mode or without controls. */
|
|
15967
|
+
get flyControls() {
|
|
15968
|
+
return isFlyControls(this._controls) ? this._controls : void 0;
|
|
15969
|
+
}
|
|
15970
|
+
/** The active renderer-owned controls mode, or undefined without controls. */
|
|
15971
|
+
get controlsMode() {
|
|
15972
|
+
if (!this._controls) return void 0;
|
|
15973
|
+
return isFlyControls(this._controls) ? "fly" : "orbit";
|
|
15974
|
+
}
|
|
15440
15975
|
///
|
|
15441
15976
|
};
|
|
15442
15977
|
_Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
@@ -15454,8 +15989,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
|
15454
15989
|
top: void 0,
|
|
15455
15990
|
bottom: void 0
|
|
15456
15991
|
},
|
|
15457
|
-
position: new
|
|
15458
|
-
lookingAt: new
|
|
15992
|
+
position: new import_three38.Vector3(50, 50, 50),
|
|
15993
|
+
lookingAt: new import_three38.Vector3(0, 0, 0)
|
|
15459
15994
|
},
|
|
15460
15995
|
render: {
|
|
15461
15996
|
fpsLimit: 60,
|
|
@@ -15470,7 +16005,8 @@ _Renderer.DEFAULT_OPTIONS = (0, import_ts_deepmerge9.default)({}, {
|
|
|
15470
16005
|
enabled: true
|
|
15471
16006
|
},
|
|
15472
16007
|
controls: {
|
|
15473
|
-
enabled: false
|
|
16008
|
+
enabled: false,
|
|
16009
|
+
mode: "orbit"
|
|
15474
16010
|
},
|
|
15475
16011
|
debug: {
|
|
15476
16012
|
grid: false,
|
|
@@ -15724,7 +16260,7 @@ function parseSceneDocument(value) {
|
|
|
15724
16260
|
}
|
|
15725
16261
|
|
|
15726
16262
|
// src/scene/SceneDocumentLoader.ts
|
|
15727
|
-
var
|
|
16263
|
+
var import_three40 = require("three");
|
|
15728
16264
|
init_AssetKey();
|
|
15729
16265
|
init_AssetLoader();
|
|
15730
16266
|
init_BlockStates();
|
|
@@ -15785,7 +16321,7 @@ var SceneDocumentLoader = class {
|
|
|
15785
16321
|
if (definition.minecraftVersion !== void 0 && definition.minecraftVersion !== AssetLoader.version) {
|
|
15786
16322
|
throw new Error(`Scene requires Minecraft ${definition.minecraftVersion}; call AssetLoader.setVersion("${definition.minecraftVersion}") before loading it`);
|
|
15787
16323
|
}
|
|
15788
|
-
const root = new
|
|
16324
|
+
const root = new import_three40.Group();
|
|
15789
16325
|
root.name = "MineRender scene document";
|
|
15790
16326
|
const objects = [];
|
|
15791
16327
|
let disposed = false;
|
|
@@ -15825,7 +16361,7 @@ var SceneDocumentLoader = class {
|
|
|
15825
16361
|
return this.loadValidatedObject(scene, definition, parent);
|
|
15826
16362
|
}
|
|
15827
16363
|
static async loadValidatedObject(scene, definition, parent) {
|
|
15828
|
-
const root = new
|
|
16364
|
+
const root = new import_three40.Group();
|
|
15829
16365
|
root.name = definition.name ?? definition.id;
|
|
15830
16366
|
root.userData.sceneObjectId = definition.id;
|
|
15831
16367
|
root.position.fromArray(definition.position ?? [0, 0, 0]);
|
|
@@ -16703,12 +17239,12 @@ var AnvilWorldSource = class {
|
|
|
16703
17239
|
};
|
|
16704
17240
|
|
|
16705
17241
|
// src/world/Chunk.ts
|
|
16706
|
-
var
|
|
17242
|
+
var import_three44 = require("three");
|
|
16707
17243
|
init_BlockStates();
|
|
16708
17244
|
init_AssetKey();
|
|
16709
17245
|
|
|
16710
17246
|
// src/world/MineRenderWorld.ts
|
|
16711
|
-
var
|
|
17247
|
+
var import_three42 = require("three");
|
|
16712
17248
|
init_Model();
|
|
16713
17249
|
init_util();
|
|
16714
17250
|
init_AssetKey();
|
|
@@ -16716,7 +17252,7 @@ init_BlockStates();
|
|
|
16716
17252
|
init_CubeFace();
|
|
16717
17253
|
|
|
16718
17254
|
// src/world/SectionModels.ts
|
|
16719
|
-
var
|
|
17255
|
+
var import_three41 = require("three");
|
|
16720
17256
|
init_AssetKey();
|
|
16721
17257
|
init_Models();
|
|
16722
17258
|
init_CubeFace();
|
|
@@ -16740,7 +17276,7 @@ function cached(map, key, load) {
|
|
|
16740
17276
|
}
|
|
16741
17277
|
function compactQuads(geometry, keep) {
|
|
16742
17278
|
const quads = keep.flatMap((kept, index) => kept ? [index] : []);
|
|
16743
|
-
const compact = new
|
|
17279
|
+
const compact = new import_three41.BufferGeometry();
|
|
16744
17280
|
for (const [name, size] of Object.entries({ position: 3, normal: 3, uv: 2, uvBounds: 4, color: 3 })) {
|
|
16745
17281
|
const source2 = geometry.getAttribute(name);
|
|
16746
17282
|
const defaults = name === "uvBounds" ? [0, 0, 1, 1] : name === "color" ? [1, 1, 1] : void 0;
|
|
@@ -16752,7 +17288,7 @@ function compactQuads(geometry, keep) {
|
|
|
16752
17288
|
}
|
|
16753
17289
|
}
|
|
16754
17290
|
}
|
|
16755
|
-
compact.setAttribute(name, new
|
|
17291
|
+
compact.setAttribute(name, new import_three41.BufferAttribute(values, size));
|
|
16756
17292
|
}
|
|
16757
17293
|
const source = geometry.getIndex();
|
|
16758
17294
|
const indices = [];
|
|
@@ -16773,24 +17309,48 @@ var SectionModels = class {
|
|
|
16773
17309
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
16774
17310
|
}
|
|
16775
17311
|
/** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
|
|
16776
|
-
async get(blockState3, properties = {}, position) {
|
|
16777
|
-
const
|
|
16778
|
-
|
|
17312
|
+
async get(blockState3, properties = {}, position, biome) {
|
|
17313
|
+
const biomePosition = position ? [...position] : void 0;
|
|
17314
|
+
const prepared = await this.state(blockState3, properties);
|
|
17315
|
+
if (!prepared) return void 0;
|
|
17316
|
+
return Promise.all(prepared.groups.map(async (group) => {
|
|
17317
|
+
const variant = BlockStateResolver.choose(group, biomePosition);
|
|
17318
|
+
const choice = prepared.choices.get(variant);
|
|
17319
|
+
const tints = await BlockTints.get(
|
|
17320
|
+
blockState3.key,
|
|
17321
|
+
prepared.state,
|
|
17322
|
+
choice.model,
|
|
17323
|
+
void 0,
|
|
17324
|
+
() => BlockTints.getBiomeColor(blockState3.key, biome, biomePosition)
|
|
17325
|
+
);
|
|
17326
|
+
return this.template(variant, choice, tints);
|
|
17327
|
+
}));
|
|
16779
17328
|
}
|
|
16780
|
-
/** Resolves section templates
|
|
16781
|
-
async prepareState(blockState3, properties = {}) {
|
|
17329
|
+
/** Resolves section templates for one tint palette, with a synchronous weighted choice for each cell. */
|
|
17330
|
+
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
17331
|
+
const prepared = await this.state(blockState3, properties);
|
|
17332
|
+
if (!prepared) return void 0;
|
|
17333
|
+
let color2;
|
|
17334
|
+
const resolveColor = typeof biomeColor === "function" ? () => color2 ?? (color2 = biomeColor()) : biomeColor;
|
|
17335
|
+
const templates = /* @__PURE__ */ new Map();
|
|
17336
|
+
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
17337
|
+
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
17338
|
+
templates.set(variant, await this.template(variant, choice, tints));
|
|
17339
|
+
}));
|
|
17340
|
+
return { pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))) };
|
|
17341
|
+
}
|
|
17342
|
+
async state(blockState3, properties) {
|
|
16782
17343
|
let states = this.states.get(blockState3);
|
|
16783
17344
|
if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
|
|
16784
17345
|
const key = JSON.stringify(Object.entries(properties).sort(([a], [b]) => a.localeCompare(b)));
|
|
16785
|
-
|
|
16786
|
-
if (!prepared) return void 0;
|
|
16787
|
-
return { pick: (position) => prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, position))) };
|
|
17346
|
+
return cached(states, key, () => this.prepare(blockState3, properties));
|
|
16788
17347
|
}
|
|
16789
17348
|
/** Returns the shared still/flow atlas used by per-block fluid objects. */
|
|
16790
17349
|
fluidAtlas(kind, root) {
|
|
16791
|
-
|
|
17350
|
+
const key = new AssetKey("minecraft", kind, "models", "fluid", "assets", ".json", root);
|
|
17351
|
+
return cached(this.fluidAtlases, key.serialize(), async () => {
|
|
16792
17352
|
const atlas = await UVMapper.getAtlas({
|
|
16793
|
-
key
|
|
17353
|
+
key,
|
|
16794
17354
|
textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },
|
|
16795
17355
|
elements: []
|
|
16796
17356
|
});
|
|
@@ -16802,64 +17362,67 @@ var SectionModels = class {
|
|
|
16802
17362
|
const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
|
|
16803
17363
|
const groups = BlockStateResolver.matching(blockState3, state);
|
|
16804
17364
|
if (!groups.length) return void 0;
|
|
16805
|
-
const
|
|
17365
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
16806
17366
|
for (const group of groups) {
|
|
16807
17367
|
const choices = Array.isArray(group) ? group : [group];
|
|
16808
17368
|
if (!choices.length) return void 0;
|
|
16809
17369
|
for (const variant of choices) {
|
|
16810
17370
|
if (!variant.model) return void 0;
|
|
16811
|
-
const
|
|
17371
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
17372
|
+
modelKey.root = blockState3.key?.root;
|
|
17373
|
+
const model = await Models.getMerged(modelKey);
|
|
16812
17374
|
if (!model?.elements?.length) return void 0;
|
|
16813
17375
|
const atlas = await UVMapper.getAtlas(model);
|
|
16814
17376
|
const rotation = BlockStateResolver.rotation(variant);
|
|
16815
17377
|
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
16816
|
-
|
|
16817
|
-
let models = this.models.get(model);
|
|
16818
|
-
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
16819
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
16820
|
-
const template = await cached(models, key, async () => {
|
|
16821
|
-
const object4 = new SectionModel(model, {
|
|
16822
|
-
instanceMeshes: false,
|
|
16823
|
-
mergeMeshes: true,
|
|
16824
|
-
tints,
|
|
16825
|
-
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
16826
|
-
});
|
|
16827
|
-
await object4.init();
|
|
16828
|
-
let geometry = object4.children[0].geometry;
|
|
16829
|
-
geometry.applyMatrix4(new import_three40.Matrix4().makeRotationFromEuler(rotation));
|
|
16830
|
-
object4.clear();
|
|
16831
|
-
const keep = [];
|
|
16832
|
-
const cullFaces = [];
|
|
16833
|
-
for (const element of atlas.model.elements) {
|
|
16834
|
-
for (const face of CUBE_FACES) {
|
|
16835
|
-
const data = element.faces[face];
|
|
16836
|
-
keep.push(data !== void 0);
|
|
16837
|
-
if (!data) continue;
|
|
16838
|
-
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
16839
|
-
if (local < 0) {
|
|
16840
|
-
cullFaces.push(0);
|
|
16841
|
-
continue;
|
|
16842
|
-
}
|
|
16843
|
-
const normal = new import_three40.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
16844
|
-
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);
|
|
16845
|
-
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
16846
|
-
}
|
|
16847
|
-
}
|
|
16848
|
-
geometry = compactQuads(geometry, keep);
|
|
16849
|
-
const template2 = {
|
|
16850
|
-
geometry,
|
|
16851
|
-
atlas,
|
|
16852
|
-
cullFaces: new Uint8Array(cullFaces),
|
|
16853
|
-
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
16854
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
16855
|
-
};
|
|
16856
|
-
this.templates.add(template2);
|
|
16857
|
-
return template2;
|
|
16858
|
-
});
|
|
16859
|
-
templates.set(variant, template);
|
|
17378
|
+
prepared.set(variant, { model, atlas, rotation });
|
|
16860
17379
|
}
|
|
16861
17380
|
}
|
|
16862
|
-
return { groups,
|
|
17381
|
+
return { state, groups, choices: prepared };
|
|
17382
|
+
}
|
|
17383
|
+
async template(variant, { model, atlas, rotation }, tints) {
|
|
17384
|
+
let models = this.models.get(model);
|
|
17385
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
17386
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
17387
|
+
return cached(models, key, async () => {
|
|
17388
|
+
const object4 = new SectionModel(model, {
|
|
17389
|
+
instanceMeshes: false,
|
|
17390
|
+
mergeMeshes: true,
|
|
17391
|
+
tints,
|
|
17392
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
17393
|
+
});
|
|
17394
|
+
await object4.init();
|
|
17395
|
+
let geometry = object4.children[0].geometry;
|
|
17396
|
+
geometry.applyMatrix4(new import_three41.Matrix4().makeRotationFromEuler(rotation));
|
|
17397
|
+
object4.clear();
|
|
17398
|
+
const keep = [];
|
|
17399
|
+
const cullFaces = [];
|
|
17400
|
+
for (const element of atlas.model.elements) {
|
|
17401
|
+
for (const face of CUBE_FACES) {
|
|
17402
|
+
const data = element.faces[face];
|
|
17403
|
+
keep.push(data !== void 0);
|
|
17404
|
+
if (!data) continue;
|
|
17405
|
+
const local = CUBE_FACES.findIndex((name) => name === data.cullface);
|
|
17406
|
+
if (local < 0) {
|
|
17407
|
+
cullFaces.push(0);
|
|
17408
|
+
continue;
|
|
17409
|
+
}
|
|
17410
|
+
const normal = new import_three41.Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
17411
|
+
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);
|
|
17412
|
+
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
17413
|
+
}
|
|
17414
|
+
}
|
|
17415
|
+
geometry = compactQuads(geometry, keep);
|
|
17416
|
+
const template = {
|
|
17417
|
+
geometry,
|
|
17418
|
+
atlas,
|
|
17419
|
+
cullFaces: new Uint8Array(cullFaces),
|
|
17420
|
+
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
17421
|
+
layer: atlas.hasTranslucency ? 1 : 0
|
|
17422
|
+
};
|
|
17423
|
+
this.templates.add(template);
|
|
17424
|
+
return template;
|
|
17425
|
+
});
|
|
16863
17426
|
}
|
|
16864
17427
|
/** Disposes prepared geometry and clears this world's template caches. */
|
|
16865
17428
|
clear() {
|
|
@@ -17036,17 +17599,17 @@ var MineRenderWorld = class {
|
|
|
17036
17599
|
}
|
|
17037
17600
|
getBlockAt(posOrX, y, z) {
|
|
17038
17601
|
if (typeof posOrX == "number") {
|
|
17039
|
-
return this.getBlockAt(new
|
|
17602
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX, y, z));
|
|
17040
17603
|
}
|
|
17041
17604
|
if (isTripleArray(posOrX)) {
|
|
17042
|
-
return this.getBlockAt(new
|
|
17605
|
+
return this.getBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
17043
17606
|
}
|
|
17044
17607
|
this.validatePosBounds(posOrX);
|
|
17045
17608
|
return this.getChunkAt(posOrX)?.getBlockAt(posOrX);
|
|
17046
17609
|
}
|
|
17047
17610
|
getBiomeAt(posOrX, y, z) {
|
|
17048
|
-
if (typeof posOrX === "number") return this.getBiomeAt(new
|
|
17049
|
-
if (isTripleArray(posOrX)) return this.getBiomeAt(new
|
|
17611
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new import_three42.Vector3(posOrX, y, z));
|
|
17612
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three42.Vector3(...posOrX));
|
|
17050
17613
|
this.validatePosBounds(posOrX);
|
|
17051
17614
|
const cx = Math.floor(posOrX.x / 16), cy = Math.floor(posOrX.y / 16), cz = Math.floor(posOrX.z / 16);
|
|
17052
17615
|
const lx = posOrX.x - cx * 16, ly = posOrX.y - cy * 16, lz = posOrX.z - cz * 16;
|
|
@@ -17054,10 +17617,10 @@ var MineRenderWorld = class {
|
|
|
17054
17617
|
}
|
|
17055
17618
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
17056
17619
|
if (typeof posOrX == "number") {
|
|
17057
|
-
return this.setBlockAt(new
|
|
17620
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX, yOrBlock, z), block);
|
|
17058
17621
|
}
|
|
17059
17622
|
if (isTripleArray(posOrX)) {
|
|
17060
|
-
return this.setBlockAt(new
|
|
17623
|
+
return this.setBlockAt(new import_three42.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
17061
17624
|
}
|
|
17062
17625
|
return this.placeBlock(posOrX, yOrBlock);
|
|
17063
17626
|
}
|
|
@@ -17068,10 +17631,10 @@ var MineRenderWorld = class {
|
|
|
17068
17631
|
}
|
|
17069
17632
|
async setBlockVisibleAt(posOrX, yOrVisible, z, visible) {
|
|
17070
17633
|
if (typeof posOrX === "number") {
|
|
17071
|
-
return this.setBlockVisibleAt(new
|
|
17634
|
+
return this.setBlockVisibleAt(new import_three42.Vector3(posOrX, yOrVisible, z), visible);
|
|
17072
17635
|
}
|
|
17073
17636
|
if (isTripleArray(posOrX)) {
|
|
17074
|
-
return this.setBlockVisibleAt(new
|
|
17637
|
+
return this.setBlockVisibleAt(new import_three42.Vector3(...posOrX), yOrVisible);
|
|
17075
17638
|
}
|
|
17076
17639
|
this.validatePosBounds(posOrX);
|
|
17077
17640
|
await this.getChunkAt(posOrX)?.setBlockVisibleAt(posOrX, yOrVisible);
|
|
@@ -17097,7 +17660,7 @@ var MineRenderWorld = class {
|
|
|
17097
17660
|
const collect = async (positions2) => {
|
|
17098
17661
|
for (const pos of positions2) changes.set(pos.toArray().join(","), pos);
|
|
17099
17662
|
};
|
|
17100
|
-
const place = (block) => this.placeBlock(new
|
|
17663
|
+
const place = (block) => this.placeBlock(new import_three42.Vector3(...block.position), block, collect);
|
|
17101
17664
|
const keys = /* @__PURE__ */ new Map();
|
|
17102
17665
|
const types = /* @__PURE__ */ new Set();
|
|
17103
17666
|
for (const block of multiblock.blocks) {
|
|
@@ -17113,7 +17676,7 @@ var MineRenderWorld = class {
|
|
|
17113
17676
|
}
|
|
17114
17677
|
if (!executor) {
|
|
17115
17678
|
const groups2 = /* @__PURE__ */ new Map();
|
|
17116
|
-
const position = new
|
|
17679
|
+
const position = new import_three42.Vector3();
|
|
17117
17680
|
for (const block of multiblock.blocks) {
|
|
17118
17681
|
const [x, y, z] = block.position;
|
|
17119
17682
|
this.validatePosBounds(position.set(x, y, z));
|
|
@@ -17153,7 +17716,7 @@ var MineRenderWorld = class {
|
|
|
17153
17716
|
try {
|
|
17154
17717
|
positions = await chunk.placeBlocks(blocks);
|
|
17155
17718
|
} finally {
|
|
17156
|
-
positions ?? (positions = blocks.map(({ index }) => new
|
|
17719
|
+
positions ?? (positions = blocks.map(({ index }) => new import_three42.Vector3(
|
|
17157
17720
|
chunk.x * 16 + index % 16,
|
|
17158
17721
|
chunk.y * 16 + Math.floor(index / 256),
|
|
17159
17722
|
chunk.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17189,10 +17752,9 @@ var MineRenderWorld = class {
|
|
|
17189
17752
|
}
|
|
17190
17753
|
try {
|
|
17191
17754
|
await this.clearChunkColumn(chunk.x, chunk.z);
|
|
17192
|
-
let sliceStart = performance.now();
|
|
17193
17755
|
for (const section of chunk.sections) {
|
|
17194
17756
|
if (section.biomes) {
|
|
17195
|
-
const position = new
|
|
17757
|
+
const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17196
17758
|
this.validatePosBounds(position);
|
|
17197
17759
|
const copy = [...section.biomes];
|
|
17198
17760
|
if (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0)) {
|
|
@@ -17203,9 +17765,12 @@ var MineRenderWorld = class {
|
|
|
17203
17765
|
if (!column) this.biomes.set(key, column = /* @__PURE__ */ new Map());
|
|
17204
17766
|
column.set(section.y, copy);
|
|
17205
17767
|
}
|
|
17768
|
+
}
|
|
17769
|
+
let sliceStart = performance.now();
|
|
17770
|
+
for (const section of chunk.sections) {
|
|
17206
17771
|
if (!executor) {
|
|
17207
17772
|
if (!occupiedSections.has(section.y)) continue;
|
|
17208
|
-
const position = new
|
|
17773
|
+
const position = new import_three42.Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
17209
17774
|
this.validatePosBounds(position);
|
|
17210
17775
|
const target = this.getOrCreateChunkAt(position);
|
|
17211
17776
|
try {
|
|
@@ -17299,7 +17864,7 @@ var MineRenderWorld = class {
|
|
|
17299
17864
|
this.sectionModels?.clear();
|
|
17300
17865
|
}
|
|
17301
17866
|
updateCulling(positions) {
|
|
17302
|
-
const neighbor = new
|
|
17867
|
+
const neighbor = new import_three42.Vector3();
|
|
17303
17868
|
for (const pos of positions) {
|
|
17304
17869
|
const cx = Math.floor(pos.x / 16), cy = Math.floor(pos.y / 16), cz = Math.floor(pos.z / 16);
|
|
17305
17870
|
const chunk = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
@@ -17367,18 +17932,34 @@ var MineRenderWorld = class {
|
|
|
17367
17932
|
const key = this.worldPosToChunkKey(pos);
|
|
17368
17933
|
let chunk = this._chunks.get(key);
|
|
17369
17934
|
if (typeof chunk === "undefined") {
|
|
17935
|
+
const x = Math.floor(pos.x / 16), y = Math.floor(pos.y / 16), z = Math.floor(pos.z / 16);
|
|
17370
17936
|
chunk = new Chunk(
|
|
17371
17937
|
this.scene,
|
|
17372
|
-
|
|
17373
|
-
|
|
17374
|
-
|
|
17938
|
+
x,
|
|
17939
|
+
y,
|
|
17940
|
+
z,
|
|
17375
17941
|
(positions) => this.updateCulling(positions),
|
|
17376
17942
|
this.sectionModels,
|
|
17377
|
-
(
|
|
17378
|
-
const cx = Math.floor(
|
|
17943
|
+
(x2, y2, z2) => {
|
|
17944
|
+
const cx = Math.floor(x2 / 16), cy = Math.floor(y2 / 16), cz = Math.floor(z2 / 16);
|
|
17379
17945
|
const section = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
17380
|
-
const index = (
|
|
17946
|
+
const index = (y2 - cy * 16) * 256 + (z2 - cz * 16) * 16 + x2 - cx * 16;
|
|
17381
17947
|
return (section?.fluidByteIndex(index) ?? 0) | (section?.isOccludingIndex(index) ? 64 : 0);
|
|
17948
|
+
},
|
|
17949
|
+
(x2, y2, z2) => this.getBiomeAt(x2, y2, z2),
|
|
17950
|
+
async (biomes) => {
|
|
17951
|
+
if (this._chunks.get(key) !== chunk) return;
|
|
17952
|
+
const columnKey = `${x}_${z}`;
|
|
17953
|
+
let column = this.biomes.get(columnKey);
|
|
17954
|
+
if (biomes) {
|
|
17955
|
+
if (!column) this.biomes.set(columnKey, column = /* @__PURE__ */ new Map());
|
|
17956
|
+
column.set(y, biomes);
|
|
17957
|
+
} else {
|
|
17958
|
+
column?.delete(y);
|
|
17959
|
+
if (!column?.size) this.biomes.delete(columnKey);
|
|
17960
|
+
}
|
|
17961
|
+
await chunk.refreshBiomes();
|
|
17962
|
+
await this._chunks.get(`${x}_${y + 1}_${z}`)?.refreshBiomes();
|
|
17382
17963
|
}
|
|
17383
17964
|
);
|
|
17384
17965
|
this._chunks.set(key, chunk);
|
|
@@ -17391,7 +17972,7 @@ var MineRenderWorld = class {
|
|
|
17391
17972
|
}
|
|
17392
17973
|
/** Converts block coordinates to scene units by multiplying each component by 16. */
|
|
17393
17974
|
static worldToScenePosition(pos) {
|
|
17394
|
-
return new
|
|
17975
|
+
return new import_three42.Vector3(
|
|
17395
17976
|
pos.x * 16,
|
|
17396
17977
|
pos.y * 16,
|
|
17397
17978
|
pos.z * 16
|
|
@@ -17399,7 +17980,7 @@ var MineRenderWorld = class {
|
|
|
17399
17980
|
}
|
|
17400
17981
|
/** Converts scene units to block coordinates without rounding to an integer block. */
|
|
17401
17982
|
static sceneToWorldPosition(pos) {
|
|
17402
|
-
return new
|
|
17983
|
+
return new import_three42.Vector3(
|
|
17403
17984
|
pos.x / 16,
|
|
17404
17985
|
pos.y / 16,
|
|
17405
17986
|
pos.z / 16
|
|
@@ -17422,7 +18003,7 @@ var MineRenderWorld = class {
|
|
|
17422
18003
|
init_Model();
|
|
17423
18004
|
|
|
17424
18005
|
// src/world/SectionMesh.ts
|
|
17425
|
-
var
|
|
18006
|
+
var import_three43 = require("three");
|
|
17426
18007
|
init_CanvasCompat();
|
|
17427
18008
|
init_Materials();
|
|
17428
18009
|
|
|
@@ -17433,6 +18014,7 @@ function buildSectionGeometry(input) {
|
|
|
17433
18014
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
17434
18015
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
17435
18016
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
18017
|
+
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
17436
18018
|
for (const template of templateData) {
|
|
17437
18019
|
const { quads } = template;
|
|
17438
18020
|
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) {
|
|
@@ -17510,7 +18092,9 @@ function buildSectionGeometry(input) {
|
|
|
17510
18092
|
height
|
|
17511
18093
|
});
|
|
17512
18094
|
}
|
|
17513
|
-
|
|
18095
|
+
const tintIndex = (x + z * 16 + y * 256) * 3;
|
|
18096
|
+
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
18097
|
+
fluidPages.get(fluid).fluids.push({ quads, x, y, z, data, tint });
|
|
17514
18098
|
}
|
|
17515
18099
|
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));
|
|
17516
18100
|
}
|
|
@@ -17559,7 +18143,7 @@ function buildSectionGeometry(input) {
|
|
|
17559
18143
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
17560
18144
|
}
|
|
17561
18145
|
}
|
|
17562
|
-
for (const { quads, x, y, z, data } of page.fluids) {
|
|
18146
|
+
for (const { quads, x, y, z, data, tint } of page.fluids) {
|
|
17563
18147
|
const atlas = atlases[data.atlas];
|
|
17564
18148
|
const placement = page.placements[0];
|
|
17565
18149
|
const mapU = (u) => (placement.x + u * atlas.width) / page.width;
|
|
@@ -17583,7 +18167,7 @@ function buildSectionGeometry(input) {
|
|
|
17583
18167
|
mapU((rect[0] + rect[2]) / atlas.width),
|
|
17584
18168
|
mapV(1 - rect[1] / atlas.height)
|
|
17585
18169
|
], vertex * 4);
|
|
17586
|
-
colors.set(
|
|
18170
|
+
colors.set(tint, vertex * 3);
|
|
17587
18171
|
}
|
|
17588
18172
|
outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);
|
|
17589
18173
|
indexOffset += 6;
|
|
@@ -17650,7 +18234,7 @@ var SectionWorker = _SectionWorker;
|
|
|
17650
18234
|
|
|
17651
18235
|
// src/world/SectionMesh.ts
|
|
17652
18236
|
var templateCache = /* @__PURE__ */ new WeakMap();
|
|
17653
|
-
var WATER_TINT = new
|
|
18237
|
+
var WATER_TINT = new import_three43.Color(4159204).toArray();
|
|
17654
18238
|
function toInput(entries, maxAtlasSize, fluids) {
|
|
17655
18239
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
17656
18240
|
const atlases = [];
|
|
@@ -17724,7 +18308,7 @@ function toInput(entries, maxAtlasSize, fluids) {
|
|
|
17724
18308
|
input.cullMasks[i] = cullMask;
|
|
17725
18309
|
}
|
|
17726
18310
|
if (fluids) {
|
|
17727
|
-
input.fluids = { cells: fluids.cells };
|
|
18311
|
+
input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };
|
|
17728
18312
|
for (const kind of ["water", "lava"]) {
|
|
17729
18313
|
const atlas = fluids[kind];
|
|
17730
18314
|
if (!atlas) continue;
|
|
@@ -17745,7 +18329,7 @@ function toInput(entries, maxAtlasSize, fluids) {
|
|
|
17745
18329
|
}
|
|
17746
18330
|
return { input, atlases };
|
|
17747
18331
|
}
|
|
17748
|
-
var SectionMesh = class _SectionMesh extends
|
|
18332
|
+
var SectionMesh = class _SectionMesh extends import_three43.Group {
|
|
17749
18333
|
constructor() {
|
|
17750
18334
|
super(...arguments);
|
|
17751
18335
|
this.ownedMeshes = [];
|
|
@@ -17770,26 +18354,26 @@ var SectionMesh = class _SectionMesh extends import_three42.Group {
|
|
|
17770
18354
|
for (const { atlas, x, y } of page.placements) {
|
|
17771
18355
|
context.drawImage(atlases[atlas].image.canvas, x, y);
|
|
17772
18356
|
}
|
|
17773
|
-
const geometry = new
|
|
17774
|
-
geometry.setAttribute("position", new
|
|
17775
|
-
geometry.setAttribute("normal", new
|
|
17776
|
-
geometry.setAttribute("uv", new
|
|
17777
|
-
geometry.setAttribute("uvBounds", new
|
|
17778
|
-
geometry.setAttribute("color", new
|
|
17779
|
-
geometry.setIndex(new
|
|
18357
|
+
const geometry = new import_three43.BufferGeometry();
|
|
18358
|
+
geometry.setAttribute("position", new import_three43.Float32BufferAttribute(page.positions.buffer, 3));
|
|
18359
|
+
geometry.setAttribute("normal", new import_three43.Float32BufferAttribute(page.normals.buffer, 3));
|
|
18360
|
+
geometry.setAttribute("uv", new import_three43.Float32BufferAttribute(page.uvs.buffer, 2));
|
|
18361
|
+
geometry.setAttribute("uvBounds", new import_three43.Float32BufferAttribute(page.uvBounds.buffer, 4));
|
|
18362
|
+
geometry.setAttribute("color", new import_three43.Float32BufferAttribute(page.colors.buffer, 3));
|
|
18363
|
+
geometry.setIndex(new import_three43.Uint32BufferAttribute(page.indices.buffer, 1));
|
|
17780
18364
|
geometry.computeBoundingBox();
|
|
17781
18365
|
geometry.computeBoundingSphere();
|
|
17782
18366
|
const transparent = page.layer === 2 ? atlases[page.placements[0].atlas].hasTranslucency : page.layer === 1;
|
|
17783
18367
|
const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
|
|
17784
|
-
material.side =
|
|
18368
|
+
material.side = import_three43.FrontSide;
|
|
17785
18369
|
if (page.layer === 2) {
|
|
17786
|
-
material.side =
|
|
18370
|
+
material.side = import_three43.DoubleSide;
|
|
17787
18371
|
material.forceSinglePass = true;
|
|
17788
18372
|
material.depthWrite = !material.transparent;
|
|
17789
18373
|
}
|
|
17790
18374
|
material.vertexColors = true;
|
|
17791
18375
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
17792
|
-
const mesh = new
|
|
18376
|
+
const mesh = new import_three43.Mesh(geometry, material);
|
|
17793
18377
|
section.add(mesh);
|
|
17794
18378
|
const unsubscribe = [];
|
|
17795
18379
|
for (const { atlas: id, x, y } of page.placements) {
|
|
@@ -17825,17 +18409,20 @@ var SectionMesh = class _SectionMesh extends import_three42.Group {
|
|
|
17825
18409
|
init_FluidGeometry();
|
|
17826
18410
|
init_FluidQuads();
|
|
17827
18411
|
init_CubeFace();
|
|
18412
|
+
var WATER_TINT2 = new import_three44.Color(4159204).toArray();
|
|
17828
18413
|
var Chunk = class _Chunk {
|
|
17829
|
-
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell) {
|
|
18414
|
+
constructor(scene, x, y, z, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged) {
|
|
17830
18415
|
this.onBlocksChanged = onBlocksChanged;
|
|
17831
18416
|
this.sectionModels = sectionModels;
|
|
17832
18417
|
this.neighborCell = neighborCell;
|
|
18418
|
+
this.biomeAt = biomeAt;
|
|
18419
|
+
this.onBiomesChanged = onBiomesChanged;
|
|
17833
18420
|
this.data = new ChunkData();
|
|
17834
18421
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
17835
18422
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
17836
18423
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
17837
18424
|
this.fluidCells = new Uint8Array(4096);
|
|
17838
|
-
this.blockPosition = new
|
|
18425
|
+
this.blockPosition = new import_three44.Vector3();
|
|
17839
18426
|
this.meshDirty = false;
|
|
17840
18427
|
this.meshGeneration = 0;
|
|
17841
18428
|
this.scene = scene;
|
|
@@ -17845,21 +18432,71 @@ var Chunk = class _Chunk {
|
|
|
17845
18432
|
}
|
|
17846
18433
|
getBlockAt(posOrX, y, z) {
|
|
17847
18434
|
if (typeof posOrX == "number") {
|
|
17848
|
-
return this.getBlockAt(new
|
|
18435
|
+
return this.getBlockAt(new import_three44.Vector3(posOrX, y, z));
|
|
17849
18436
|
}
|
|
17850
18437
|
if (isTripleArray(posOrX)) {
|
|
17851
|
-
return this.getBlockAt(new
|
|
18438
|
+
return this.getBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]));
|
|
17852
18439
|
}
|
|
17853
18440
|
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
17854
18441
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
17855
18442
|
return this.renderedBlocks.get(index);
|
|
17856
18443
|
}
|
|
18444
|
+
getBiomeAt(posOrX, y, z) {
|
|
18445
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new import_three44.Vector3(posOrX, y, z));
|
|
18446
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new import_three44.Vector3(...posOrX));
|
|
18447
|
+
const pos = this.worldPosToChunkPos(posOrX);
|
|
18448
|
+
_Chunk.chunkPosToBlockIndex(pos);
|
|
18449
|
+
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];
|
|
18450
|
+
}
|
|
18451
|
+
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
18452
|
+
setBiomes(biomes) {
|
|
18453
|
+
const copy = biomes ? [...biomes] : void 0;
|
|
18454
|
+
if (copy && (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0))) {
|
|
18455
|
+
throw new RangeError("Section biomes must contain 64 nonempty biome IDs");
|
|
18456
|
+
}
|
|
18457
|
+
if (this.onBiomesChanged) return this.onBiomesChanged(copy);
|
|
18458
|
+
this.biomes = copy;
|
|
18459
|
+
return this.refreshBiomes();
|
|
18460
|
+
}
|
|
18461
|
+
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
18462
|
+
async refreshBiomes() {
|
|
18463
|
+
const affected = /* @__PURE__ */ new Map();
|
|
18464
|
+
const blocks = [];
|
|
18465
|
+
for (const index of this.renderedBlocks.keys()) {
|
|
18466
|
+
const block = this.data.get(index);
|
|
18467
|
+
const stateKey = ChunkData.paletteKey(block);
|
|
18468
|
+
let matches = affected.get(stateKey);
|
|
18469
|
+
if (!matches) {
|
|
18470
|
+
const key = AssetKey.parse("blockstates", block.type);
|
|
18471
|
+
matches = BlockStates.get(key).then(async (state) => {
|
|
18472
|
+
const origin = state?.key ?? key;
|
|
18473
|
+
const [source, fluid] = await Promise.all([BlockTints.biomeSource(origin), getBlockFluidState(origin, block.properties)]);
|
|
18474
|
+
return !!source || fluid?.kind === "water";
|
|
18475
|
+
});
|
|
18476
|
+
affected.set(stateKey, matches);
|
|
18477
|
+
}
|
|
18478
|
+
if (await matches) blocks.push({ index, block });
|
|
18479
|
+
}
|
|
18480
|
+
if (!blocks.length) return;
|
|
18481
|
+
const hidden = new Set(this.hiddenBlocks);
|
|
18482
|
+
try {
|
|
18483
|
+
await this.placeBlocks(blocks);
|
|
18484
|
+
} finally {
|
|
18485
|
+
for (const index of hidden) {
|
|
18486
|
+
this.hiddenBlocks.add(index);
|
|
18487
|
+
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
18488
|
+
}
|
|
18489
|
+
const positions = blocks.map(({ index }) => new import_three44.Vector3(...this.positionAt(index)));
|
|
18490
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
18491
|
+
else await this.rebuildSectionMesh();
|
|
18492
|
+
}
|
|
18493
|
+
}
|
|
17857
18494
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
17858
18495
|
if (typeof posOrX == "number") {
|
|
17859
|
-
return this.setBlockAt(new
|
|
18496
|
+
return this.setBlockAt(new import_three44.Vector3(posOrX, yOrBlock, z), block);
|
|
17860
18497
|
}
|
|
17861
18498
|
if (isTripleArray(posOrX)) {
|
|
17862
|
-
return this.setBlockAt(new
|
|
18499
|
+
return this.setBlockAt(new import_three44.Vector3(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
17863
18500
|
}
|
|
17864
18501
|
const worldPos = posOrX;
|
|
17865
18502
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -17892,14 +18529,15 @@ var Chunk = class _Chunk {
|
|
|
17892
18529
|
nbt: block.nbt === void 0 ? void 0 : structuredClone(block.nbt)
|
|
17893
18530
|
} : void 0
|
|
17894
18531
|
}));
|
|
17895
|
-
const states =
|
|
17896
|
-
const
|
|
17897
|
-
|
|
17898
|
-
|
|
17899
|
-
|
|
17900
|
-
|
|
17901
|
-
|
|
17902
|
-
|
|
18532
|
+
const states = /* @__PURE__ */ new Map();
|
|
18533
|
+
for (const { index, key, block } of placements) {
|
|
18534
|
+
if (key === void 0) continue;
|
|
18535
|
+
let state = states.get(key);
|
|
18536
|
+
if (!state) states.set(key, state = { stored: block, indices: [] });
|
|
18537
|
+
state.indices.push(index);
|
|
18538
|
+
}
|
|
18539
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
18540
|
+
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
17903
18541
|
const resolutions = new Map([...states.keys()].map((key, i) => [key, settled[i]]));
|
|
17904
18542
|
const positions = [];
|
|
17905
18543
|
let failed = false, failure;
|
|
@@ -17912,7 +18550,7 @@ var Chunk = class _Chunk {
|
|
|
17912
18550
|
if (this.fluidCells[index]) this.meshDirty = true;
|
|
17913
18551
|
this.fluidCells[index] = 0;
|
|
17914
18552
|
this.renderedBlocks.delete(index);
|
|
17915
|
-
const worldPos = new
|
|
18553
|
+
const worldPos = new import_three44.Vector3(
|
|
17916
18554
|
this.x * 16 + index % 16,
|
|
17917
18555
|
this.y * 16 + Math.floor(index / 256),
|
|
17918
18556
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
@@ -17923,7 +18561,8 @@ var Chunk = class _Chunk {
|
|
|
17923
18561
|
if (!readBlock) continue;
|
|
17924
18562
|
const resolved = resolutions.get(key);
|
|
17925
18563
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17926
|
-
const { blockState: blockState3, perBlock, fluid, prepared, stored } = resolved.value;
|
|
18564
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts, stored } = resolved.value;
|
|
18565
|
+
const context = contexts.get(index);
|
|
17927
18566
|
if (!blockState3) {
|
|
17928
18567
|
this.data.assign(index, 0);
|
|
17929
18568
|
continue;
|
|
@@ -17931,9 +18570,10 @@ var Chunk = class _Chunk {
|
|
|
17931
18570
|
const variantPosition = worldPos.toArray();
|
|
17932
18571
|
if (fluid) {
|
|
17933
18572
|
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18573
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
17934
18574
|
this.meshDirty = true;
|
|
17935
18575
|
}
|
|
17936
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18576
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
17937
18577
|
if (templates) {
|
|
17938
18578
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
17939
18579
|
this.meshDirty = true;
|
|
@@ -17943,7 +18583,9 @@ var Chunk = class _Chunk {
|
|
|
17943
18583
|
instanceMeshes: true,
|
|
17944
18584
|
maxInstanceCount: 2e3,
|
|
17945
18585
|
initialState: stored.properties,
|
|
17946
|
-
variantPosition
|
|
18586
|
+
variantPosition,
|
|
18587
|
+
biome: context?.biome,
|
|
18588
|
+
biomePosition: this.biomePosition(index, blockState3, stored)
|
|
17947
18589
|
});
|
|
17948
18590
|
object4.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
17949
18591
|
}
|
|
@@ -17966,24 +18608,21 @@ var Chunk = class _Chunk {
|
|
|
17966
18608
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
17967
18609
|
this.sectionBlocks.clear();
|
|
17968
18610
|
this.fluidCells.fill(0);
|
|
18611
|
+
this.waterTints = void 0;
|
|
17969
18612
|
this.renderedBlocks.clear();
|
|
17970
18613
|
this.hiddenBlocks.clear();
|
|
17971
18614
|
this.meshDirty = true;
|
|
17972
18615
|
this.data.copyFrom(data);
|
|
17973
|
-
const ids = /* @__PURE__ */ new
|
|
18616
|
+
const ids = /* @__PURE__ */ new Map();
|
|
17974
18617
|
for (let index = 0; index < 4096; index++) {
|
|
17975
18618
|
const id = this.data.idAt(index);
|
|
17976
|
-
if (id)
|
|
17977
|
-
|
|
17978
|
-
|
|
17979
|
-
|
|
17980
|
-
|
|
17981
|
-
|
|
17982
|
-
|
|
17983
|
-
const fluid = await getBlockFluidState(blockState3?.key, state.properties);
|
|
17984
|
-
const prepared = perBlock || fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, state.properties);
|
|
17985
|
-
return { blockState: blockState3, perBlock, fluid, prepared };
|
|
17986
|
-
}));
|
|
18619
|
+
if (!id) continue;
|
|
18620
|
+
let indices = ids.get(id);
|
|
18621
|
+
if (!indices) ids.set(id, indices = []);
|
|
18622
|
+
indices.push(index);
|
|
18623
|
+
}
|
|
18624
|
+
const palette = [...ids.keys()], biomes = /* @__PURE__ */ new Map();
|
|
18625
|
+
const settled = await Promise.allSettled(palette.map((id) => this.resolveState(this.data.stateAt(id), ids.get(id), biomes)));
|
|
17987
18626
|
const resolutions = new Map(palette.map((id, i) => [id, settled[i]]));
|
|
17988
18627
|
const perBlocks = [];
|
|
17989
18628
|
let failed = false, failure;
|
|
@@ -17993,24 +18632,28 @@ var Chunk = class _Chunk {
|
|
|
17993
18632
|
try {
|
|
17994
18633
|
const resolved = resolutions.get(id);
|
|
17995
18634
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
17996
|
-
const { blockState: blockState3, perBlock, fluid, prepared } = resolved.value;
|
|
18635
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts } = resolved.value;
|
|
18636
|
+
const context = contexts.get(index);
|
|
17997
18637
|
if (!blockState3) {
|
|
17998
18638
|
this.data.assign(index, 0);
|
|
17999
18639
|
this.fluidCells[index] = 0;
|
|
18000
18640
|
continue;
|
|
18001
18641
|
}
|
|
18002
|
-
if (fluid)
|
|
18642
|
+
if (fluid) {
|
|
18643
|
+
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
18644
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
18645
|
+
}
|
|
18003
18646
|
const variantPosition = [
|
|
18004
18647
|
this.x * 16 + index % 16,
|
|
18005
18648
|
this.y * 16 + Math.floor(index / 256),
|
|
18006
18649
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
18007
18650
|
];
|
|
18008
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
18651
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
18009
18652
|
if (templates) {
|
|
18010
18653
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
18011
18654
|
this.meshDirty = true;
|
|
18012
18655
|
} else {
|
|
18013
|
-
perBlocks.push({ index, blockState: blockState3 });
|
|
18656
|
+
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
18014
18657
|
}
|
|
18015
18658
|
const readBlock = this.data.snapshot(index);
|
|
18016
18659
|
this.renderedBlocks.set(index, { get block() {
|
|
@@ -18023,7 +18666,7 @@ var Chunk = class _Chunk {
|
|
|
18023
18666
|
failed = true;
|
|
18024
18667
|
}
|
|
18025
18668
|
}
|
|
18026
|
-
for (const { index, blockState: blockState3 } of perBlocks) {
|
|
18669
|
+
for (const { index, blockState: blockState3, biome } of perBlocks) {
|
|
18027
18670
|
let object4;
|
|
18028
18671
|
try {
|
|
18029
18672
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -18031,13 +18674,11 @@ var Chunk = class _Chunk {
|
|
|
18031
18674
|
instanceMeshes: true,
|
|
18032
18675
|
maxInstanceCount: 2e3,
|
|
18033
18676
|
initialState: this.data.stateAt(this.data.idAt(index)).properties,
|
|
18034
|
-
variantPosition:
|
|
18035
|
-
|
|
18036
|
-
|
|
18037
|
-
this.z * 16 + Math.floor(index / 16) % 16
|
|
18038
|
-
]
|
|
18677
|
+
variantPosition: this.positionAt(index),
|
|
18678
|
+
biome,
|
|
18679
|
+
biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
|
|
18039
18680
|
});
|
|
18040
|
-
object4.setPosition(new
|
|
18681
|
+
object4.setPosition(new import_three44.Vector3(
|
|
18041
18682
|
this.x * 256 + index % 16 * 16,
|
|
18042
18683
|
this.y * 256 + Math.floor(index / 256) * 16,
|
|
18043
18684
|
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
@@ -18054,6 +18695,68 @@ var Chunk = class _Chunk {
|
|
|
18054
18695
|
}
|
|
18055
18696
|
if (failed) throw failure;
|
|
18056
18697
|
}
|
|
18698
|
+
positionAt(index) {
|
|
18699
|
+
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
18700
|
+
}
|
|
18701
|
+
biomePosition(index, blockState3, stored) {
|
|
18702
|
+
const position = this.positionAt(index), name = blockState3.key?.toNamespacedString();
|
|
18703
|
+
if (stored.properties?.half === "upper" && (name === "minecraft:tall_grass" || name === "minecraft:large_fern")) position[1]--;
|
|
18704
|
+
return position;
|
|
18705
|
+
}
|
|
18706
|
+
async resolveState(stored, indices, biomes) {
|
|
18707
|
+
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
18708
|
+
const perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
18709
|
+
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
18710
|
+
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;
|
|
18711
|
+
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
18712
|
+
const prepare = (color2) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color2);
|
|
18713
|
+
const contexts = /* @__PURE__ */ new Map();
|
|
18714
|
+
const groups = /* @__PURE__ */ new Map();
|
|
18715
|
+
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
18716
|
+
for (const index of indices) {
|
|
18717
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
18718
|
+
const biome = this.biomeAt ? this.biomeAt(...position) : position[1] >= this.y * 16 ? this.getBiomeAt(position) : void 0;
|
|
18719
|
+
if (!biome) continue;
|
|
18720
|
+
const key = JSON.stringify(source === "grass" ? [biome, position[0], position[2]] : [biome]);
|
|
18721
|
+
let group = groups.get(key);
|
|
18722
|
+
if (!group) groups.set(key, group = { biome, position, indices: [] });
|
|
18723
|
+
group.indices.push(index);
|
|
18724
|
+
}
|
|
18725
|
+
}
|
|
18726
|
+
const groupedCount = [...groups.values()].reduce((sum, group) => sum + group.indices.length, 0);
|
|
18727
|
+
const prepared = groupedCount < indices.length ? await prepare() : void 0;
|
|
18728
|
+
await Promise.all([...groups.values()].map(async ({ biome, position, indices: indices2 }) => {
|
|
18729
|
+
const available = () => {
|
|
18730
|
+
const key = JSON.stringify([biome, blockState3?.key?.root]);
|
|
18731
|
+
let found = biomes.get(key);
|
|
18732
|
+
if (!found) {
|
|
18733
|
+
found = Biomes.get(biome, blockState3?.key).then((value) => value !== void 0);
|
|
18734
|
+
biomes.set(key, found);
|
|
18735
|
+
}
|
|
18736
|
+
return found;
|
|
18737
|
+
};
|
|
18738
|
+
const context = { biome };
|
|
18739
|
+
if (perBlock) {
|
|
18740
|
+
if (!await available()) context.biome = void 0;
|
|
18741
|
+
} else {
|
|
18742
|
+
context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
|
|
18743
|
+
if (fluid?.kind === "water" && await available()) {
|
|
18744
|
+
const color2 = await Biomes.getColor(biome, "water", blockState3?.key);
|
|
18745
|
+
if (color2 !== void 0 && color2 !== 4159204) context.waterTint = new import_three44.Color(color2).toArray();
|
|
18746
|
+
}
|
|
18747
|
+
}
|
|
18748
|
+
for (const index of indices2) contexts.set(index, context);
|
|
18749
|
+
}));
|
|
18750
|
+
return { blockState: blockState3, perBlock, fluid, prepared, contexts, stored };
|
|
18751
|
+
}
|
|
18752
|
+
setWaterTint(index, tint) {
|
|
18753
|
+
if (!this.sectionModels || !this.waterTints && tint === void 0) return;
|
|
18754
|
+
if (!this.waterTints) {
|
|
18755
|
+
this.waterTints = new Float32Array(4096 * 3);
|
|
18756
|
+
for (let cell = 0; cell < 4096; cell++) this.waterTints.set(WATER_TINT2, cell * 3);
|
|
18757
|
+
}
|
|
18758
|
+
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
18759
|
+
}
|
|
18057
18760
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
18058
18761
|
async setBlockVisibleAt(pos, visible) {
|
|
18059
18762
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -18157,7 +18860,7 @@ var Chunk = class _Chunk {
|
|
|
18157
18860
|
if (block && !block.object) origins.set(kind, block.block.type);
|
|
18158
18861
|
}
|
|
18159
18862
|
if (origins.size) {
|
|
18160
|
-
fluids = { cells: new Uint8Array(18 * 18 * 18) };
|
|
18863
|
+
fluids = { cells: new Uint8Array(18 * 18 * 18), waterTints: this.waterTints?.slice() };
|
|
18161
18864
|
for (let y = -1; y <= 16; y++) {
|
|
18162
18865
|
for (let z = -1; z <= 16; z++) {
|
|
18163
18866
|
for (let x = -1; x <= 16; x++) {
|
|
@@ -18188,7 +18891,7 @@ var Chunk = class _Chunk {
|
|
|
18188
18891
|
/** Removes stored blocks and render objects. Set `notify` to false to skip the owning world's update. */
|
|
18189
18892
|
async clear(notify = true) {
|
|
18190
18893
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
18191
|
-
new
|
|
18894
|
+
new import_three44.Vector3(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
18192
18895
|
)) : [];
|
|
18193
18896
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
18194
18897
|
this.sectionBlocks.clear();
|
|
@@ -18199,8 +18902,13 @@ var Chunk = class _Chunk {
|
|
|
18199
18902
|
this.renderedBlocks.clear();
|
|
18200
18903
|
this.hiddenBlocks.clear();
|
|
18201
18904
|
this.fluidCells.fill(0);
|
|
18905
|
+
this.waterTints = void 0;
|
|
18202
18906
|
this.data.clear();
|
|
18203
|
-
|
|
18907
|
+
this.biomes = void 0;
|
|
18908
|
+
if (notify) {
|
|
18909
|
+
await this.onBiomesChanged?.(void 0);
|
|
18910
|
+
await this.onBlocksChanged?.(positions);
|
|
18911
|
+
}
|
|
18204
18912
|
}
|
|
18205
18913
|
async dispose() {
|
|
18206
18914
|
await this.clear();
|
|
@@ -18216,14 +18924,14 @@ var Chunk = class _Chunk {
|
|
|
18216
18924
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
18217
18925
|
}
|
|
18218
18926
|
worldPosToChunkPos(pos) {
|
|
18219
|
-
return new
|
|
18927
|
+
return new import_three44.Vector3(
|
|
18220
18928
|
pos.x - this.x * 16,
|
|
18221
18929
|
pos.y - this.y * 16,
|
|
18222
18930
|
pos.z - this.z * 16
|
|
18223
18931
|
);
|
|
18224
18932
|
}
|
|
18225
18933
|
chunkPosToWorldPos(pos) {
|
|
18226
|
-
return new
|
|
18934
|
+
return new import_three44.Vector3(
|
|
18227
18935
|
this.x * 16 + pos.x,
|
|
18228
18936
|
this.y * 16 + pos.y,
|
|
18229
18937
|
this.z * 16 + pos.z
|