minerender 2.1.0-alpha.115 → 2.1.0-alpha.117
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 +65 -11
- package/dist/browser/index.d.ts +65 -11
- package/dist/browser/index.js +441 -179
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +442 -180
- 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 +451 -183
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +65 -11
- package/dist/node/index.d.ts +65 -11
- package/dist/node/index.js +444 -179
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +444 -180
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -20101,8 +20101,8 @@ var MineRender = (() => {
|
|
|
20101
20101
|
width *= view.width / fullWidth;
|
|
20102
20102
|
height *= view.height / fullHeight;
|
|
20103
20103
|
}
|
|
20104
|
-
const
|
|
20105
|
-
if (
|
|
20104
|
+
const skew2 = this.filmOffset;
|
|
20105
|
+
if (skew2 !== 0) left += near * skew2 / this.getFilmWidth();
|
|
20106
20106
|
this.projectionMatrix.makePerspective(left, left + width, top, top - height, near, this.far, this.coordinateSystem, this.reversedDepth);
|
|
20107
20107
|
this.projectionMatrixInverse.copy(this.projectionMatrix).invert();
|
|
20108
20108
|
}
|
|
@@ -41489,7 +41489,8 @@ void main() {
|
|
|
41489
41489
|
this.fontCache,
|
|
41490
41490
|
this.bannerPatternCache,
|
|
41491
41491
|
this.mineRenderDataCache,
|
|
41492
|
-
this.usernameUuidCache
|
|
41492
|
+
this.usernameUuidCache,
|
|
41493
|
+
this.biomeCache
|
|
41493
41494
|
];
|
|
41494
41495
|
}
|
|
41495
41496
|
/** Invalidates in-memory entries so later lookups reload them. Persisted entries are retained. */
|
|
@@ -41540,6 +41541,7 @@ void main() {
|
|
|
41540
41541
|
_Caching.bannerPatternCache = _Caching.createAssetCache();
|
|
41541
41542
|
_Caching.mineRenderDataCache = _Caching.createAssetCache();
|
|
41542
41543
|
_Caching.usernameUuidCache = Caches.builder().expireAfterWrite(Time.minutes(5)).expirationInterval(Time.seconds(30)).buildAsync();
|
|
41544
|
+
_Caching.biomeCache = _Caching.createAssetCache();
|
|
41543
41545
|
Caching = _Caching;
|
|
41544
41546
|
}
|
|
41545
41547
|
});
|
|
@@ -43233,7 +43235,8 @@ void main() {
|
|
|
43233
43235
|
}
|
|
43234
43236
|
/**
|
|
43235
43237
|
* Uses the exact version when published. Otherwise, selects the nearest patch in the same
|
|
43236
|
-
* release line (older on ties), then the latest earlier release
|
|
43238
|
+
* release line (older on ties), then the latest earlier release or the oldest published release.
|
|
43239
|
+
* Unpublished snapshots reject.
|
|
43237
43240
|
*/
|
|
43238
43241
|
static async resolve(root) {
|
|
43239
43242
|
const requestRoot = root?.replace(/\/+$/, "");
|
|
@@ -43242,11 +43245,11 @@ void main() {
|
|
|
43242
43245
|
const scope = AssetLoader.persistentScope;
|
|
43243
43246
|
return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
|
|
43244
43247
|
const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
|
|
43245
|
-
let manifest = await this.manifest(root, release(requestedVersion) ? requestedVersion : void 0, requestRoot);
|
|
43248
|
+
let manifest = await this.manifest(root, requestRoot !== void 0 && release(requestedVersion) ? requestedVersion : void 0, requestRoot);
|
|
43246
43249
|
if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
|
|
43247
43250
|
const requested = release(requestedVersion);
|
|
43248
|
-
if (!requested
|
|
43249
|
-
throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release
|
|
43251
|
+
if (!requested) {
|
|
43252
|
+
throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
|
|
43250
43253
|
}
|
|
43251
43254
|
const base = root.slice(0, root.lastIndexOf("/"));
|
|
43252
43255
|
const index = await this.cached(`versions:${base}`, scope, defaultRoot, async () => {
|
|
@@ -43256,9 +43259,9 @@ void main() {
|
|
|
43256
43259
|
}
|
|
43257
43260
|
return value.versions;
|
|
43258
43261
|
});
|
|
43259
|
-
const versions2 = index.map((entry) => ({ name: entry.name, number: release(entry.name) })).filter((entry) => !!entry.number
|
|
43262
|
+
const versions2 = index.map((entry) => ({ name: entry.name, number: release(entry.name) })).filter((entry) => !!entry.number).sort((left, right) => compare(left.number, right.number));
|
|
43260
43263
|
const sameLine = versions2.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
|
|
43261
|
-
const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare(left.number, right.number))[0] ?? versions2.filter((entry) => compare(entry.number, requested) <= 0).pop();
|
|
43264
|
+
const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare(left.number, right.number))[0] ?? versions2.filter((entry) => compare(entry.number, requested) <= 0).pop() ?? versions2[0];
|
|
43262
43265
|
if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);
|
|
43263
43266
|
const resolvedRoot = `${base}/${selected.name}`;
|
|
43264
43267
|
manifest = await this.manifest(resolvedRoot, selected.name, resolvedRoot);
|
|
@@ -43305,7 +43308,7 @@ ${key}` : key, async () => {
|
|
|
43305
43308
|
case "blockStates":
|
|
43306
43309
|
return Object.values(value).every((property) => object(property) && "default" in property && Array.isArray(property.values));
|
|
43307
43310
|
case "blockTints":
|
|
43308
|
-
return ["constant", "grass", "stem", "redstone"].includes(value.source) && (value.source !== "constant" || Number.isInteger(value.color));
|
|
43311
|
+
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));
|
|
43309
43312
|
case "fluids":
|
|
43310
43313
|
return ["water", "lava"].includes(value.kind) && typeof value.renderModel === "boolean" && (value.levelProperty === void 0 || typeof value.levelProperty === "string");
|
|
43311
43314
|
case "dyes":
|
|
@@ -43377,12 +43380,7 @@ ${key}` : key, async () => {
|
|
|
43377
43380
|
static async getLayers(value, target, root) {
|
|
43378
43381
|
if (value === void 0) return [];
|
|
43379
43382
|
if (!Array.isArray(value)) throw new Error("banner_patterns must be an array");
|
|
43380
|
-
const activeRoot = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
43381
|
-
const checkSources = () => {
|
|
43382
|
-
if (activeRoot !== AssetLoader.ROOT || scope !== AssetLoader.persistentScope) throw new Error("Asset sources changed while loading banner patterns; retry the request");
|
|
43383
|
-
};
|
|
43384
43383
|
const colors = value.length ? await this.getColors(root) : void 0;
|
|
43385
|
-
checkSources();
|
|
43386
43384
|
return Promise.all(value.slice(0, 16).map(async (layer) => {
|
|
43387
43385
|
if (!layer || typeof layer !== "object" || Array.isArray(layer)) throw new Error("Each banner pattern requires a pattern and dye color");
|
|
43388
43386
|
if (typeof layer.color !== "string" || !Object.prototype.hasOwnProperty.call(colors, layer.color)) throw new Error(`Unsupported dye color ${layer.color}`);
|
|
@@ -43392,7 +43390,6 @@ ${key}` : key, async () => {
|
|
|
43392
43390
|
const id = this.identifier(pattern2);
|
|
43393
43391
|
const key = new AssetKey(id.namespace, id.getFullPath(), "banner_pattern", void 0, "data", ".json", root);
|
|
43394
43392
|
pattern2 = await Caching.bannerPatternCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
43395
|
-
checkSources();
|
|
43396
43393
|
if (!pattern2) throw new Error(`Missing banner pattern ${layer.pattern}`);
|
|
43397
43394
|
}
|
|
43398
43395
|
if (!pattern2 || typeof pattern2 !== "object" || Array.isArray(pattern2) || typeof pattern2.translation_key !== "string") throw new Error("Banner patterns require asset_id and translation_key");
|
|
@@ -43461,15 +43458,19 @@ ${key}` : key, async () => {
|
|
|
43461
43458
|
Colormaps = class {
|
|
43462
43459
|
/** Samples the selected resource pack's grass colormap using Minecraft's climate coordinates. */
|
|
43463
43460
|
static async grassColor(origin, temperature = 0.5, downfall = 1) {
|
|
43464
|
-
|
|
43461
|
+
return this.getColor("grass", origin, temperature, downfall);
|
|
43462
|
+
}
|
|
43463
|
+
/** Samples a resource-pack colormap at the supplied climate coordinates. */
|
|
43464
|
+
static async getColor(kind, origin, temperature = 0.5, downfall = 1) {
|
|
43465
|
+
const key = AssetKey.parse("textures", `minecraft:colormap/${kind}`, origin);
|
|
43465
43466
|
const temp = Math.fround(temperature);
|
|
43466
43467
|
const rain = Math.fround(downfall) * temp;
|
|
43467
43468
|
const x4 = Math.floor((1 - temp) * 255), y5 = Math.floor((1 - rain) * 255);
|
|
43468
43469
|
return await Caching.blockTintCache.get(`${key.serialize()}|${x4},${y5}`, async () => {
|
|
43469
43470
|
const image = await ModelTextures.get(key);
|
|
43470
|
-
if (!image) throw new MineRenderError(`Missing
|
|
43471
|
+
if (!image) throw new MineRenderError(`Missing ${kind} colormap: ${key.toNamespacedString()}`);
|
|
43471
43472
|
if (image.width !== 256 || image.height !== 256) {
|
|
43472
|
-
throw new MineRenderError(
|
|
43473
|
+
throw new MineRenderError(`${kind} colormaps must be 256 \xD7 256 pixels`);
|
|
43473
43474
|
}
|
|
43474
43475
|
const [red, green, blue] = image.data.getImageData(x4, y5, 1, 1).data;
|
|
43475
43476
|
return red << 16 | green << 8 | blue;
|
|
@@ -43688,30 +43689,24 @@ ${key}` : key, async () => {
|
|
|
43688
43689
|
}).then((r5) => r5?.files ?? []);
|
|
43689
43690
|
}
|
|
43690
43691
|
static async loadAndMerge(key, context = {}) {
|
|
43691
|
-
const checkSources = this.sourceCheck();
|
|
43692
43692
|
const model = key.type === "item" ? await this.getItemModel(key, context) : await this.getRaw(key);
|
|
43693
43693
|
if (!model) {
|
|
43694
43694
|
return void 0;
|
|
43695
43695
|
}
|
|
43696
43696
|
const merged = await ModelMerger.mergeWithParents(model);
|
|
43697
|
-
checkSources();
|
|
43698
43697
|
return merged;
|
|
43699
43698
|
}
|
|
43700
43699
|
static async getItemModel(key, context = {}) {
|
|
43701
|
-
const checkSources = this.sourceCheck();
|
|
43702
43700
|
const preview = this.snapshotContext(key, context);
|
|
43703
43701
|
const dataKey = await this.applyDefaults(key, preview);
|
|
43704
|
-
checkSources();
|
|
43705
43702
|
return this.getPreparedItemModel(key, preview, dataKey);
|
|
43706
43703
|
}
|
|
43707
43704
|
static async getPreparedItemModel(key, preview, dataKey) {
|
|
43708
|
-
const checkSources = this.sourceCheck();
|
|
43709
43705
|
const itemId = `${key.namespace}:${key.path}`;
|
|
43710
43706
|
const itemKey2 = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
|
|
43711
43707
|
const cacheKey = itemKey2.serialize() + this.contextKey(preview) + dataKey;
|
|
43712
43708
|
const model = await this.PERSISTENT_CACHE.getOrLoad(`${this.ITEM_CACHE_VERSION}:${AssetLoader.persistentKey(cacheKey)}`, async () => {
|
|
43713
43709
|
const result = await AssetLoader.getFirst([itemKey2, key], "json" /* JSON */);
|
|
43714
|
-
checkSources();
|
|
43715
43710
|
if (!result) return void 0;
|
|
43716
43711
|
if (result.key.assetType !== "items") return { ...result.asset, key, itemId, components: preview.components };
|
|
43717
43712
|
const load = async (selected) => {
|
|
@@ -43730,10 +43725,8 @@ ${key}` : key, async () => {
|
|
|
43730
43725
|
return { ...model3, itemId, components: preview.components, ...selected.special && { special: selected.special }, ...selected.tints && { tints: selected.tints } };
|
|
43731
43726
|
};
|
|
43732
43727
|
const model2 = await load(this.selectItemModel(result.asset.model, key, preview));
|
|
43733
|
-
checkSources();
|
|
43734
43728
|
return model2;
|
|
43735
43729
|
});
|
|
43736
|
-
checkSources();
|
|
43737
43730
|
const restore = (model2) => ({
|
|
43738
43731
|
...model2,
|
|
43739
43732
|
key: Object.assign(new AssetKey("", ""), model2.key),
|
|
@@ -43797,22 +43790,14 @@ ${key}` : key, async () => {
|
|
|
43797
43790
|
}
|
|
43798
43791
|
static async applyDefaults(key, preview) {
|
|
43799
43792
|
if (key.type !== "item") return "";
|
|
43800
|
-
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
43801
43793
|
const resolved = await MineRenderData.resolve(key.root);
|
|
43802
43794
|
const defaults = await ItemDefaults.get(`${key.namespace}:${key.path}`, key.root);
|
|
43803
43795
|
preview.components = { ...defaults, ...preview.components };
|
|
43804
43796
|
if (resolved.manifest.dataVersion < 3337 && key.namespace === DEFAULT_NAMESPACE && ["potion", "splash_potion", "lingering_potion"].includes(key.path) && !Object.prototype.hasOwnProperty.call(preview.components, "minecraft:enchantment_glint_override") && await ItemTints.hasPotionEffects(preview.components["minecraft:potion_contents"], key.root)) {
|
|
43805
43797
|
preview.components["minecraft:enchantment_glint_override"] = true;
|
|
43806
43798
|
}
|
|
43807
|
-
if (AssetLoader.ROOT !== root || AssetLoader.persistentScope !== scope) throw new Error("Asset sources changed while loading item defaults; retry the request");
|
|
43808
43799
|
return `|data:${resolved.root}:${resolved.manifest.datasets.itemDefaults?.sha256}:${resolved.manifest.datasets.potionColors?.sha256}`;
|
|
43809
43800
|
}
|
|
43810
|
-
static sourceCheck() {
|
|
43811
|
-
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
43812
|
-
return () => {
|
|
43813
|
-
if (AssetLoader.ROOT !== root || AssetLoader.persistentScope !== scope) throw new Error("Asset sources changed while loading item models; retry the request");
|
|
43814
|
-
};
|
|
43815
|
-
}
|
|
43816
43801
|
static contextKey(context) {
|
|
43817
43802
|
const itemReferences = Object.fromEntries(Object.entries(context.itemReferences).map(([id, key]) => [id, key.serialize()]));
|
|
43818
43803
|
return `|${this.ITEM_CACHE_VERSION}:${JSON.stringify(this.snapshotJson({ ...context, itemReferences }))}`;
|
|
@@ -43999,7 +43984,6 @@ ${key}` : key, async () => {
|
|
|
43999
43984
|
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
44000
43985
|
*/
|
|
44001
43986
|
static async getMerged(key, context = {}) {
|
|
44002
|
-
const checkSources = this.sourceCheck();
|
|
44003
43987
|
if (!key.assetType) {
|
|
44004
43988
|
key.assetType = "models";
|
|
44005
43989
|
}
|
|
@@ -44008,15 +43992,12 @@ ${key}` : key, async () => {
|
|
|
44008
43992
|
}
|
|
44009
43993
|
const preview = this.snapshotContext(key, context);
|
|
44010
43994
|
const dataKey = await this.applyDefaults(key, preview);
|
|
44011
|
-
checkSources();
|
|
44012
43995
|
const keyStr = AssetLoader.persistentKey(key.serialize() + (key.type === "item" ? this.contextKey(preview) + dataKey : ""));
|
|
44013
43996
|
const model = await Caching.mergedModelCache.get(keyStr, async () => {
|
|
44014
43997
|
const raw = key.type === "item" ? await this.getPreparedItemModel(key, preview, dataKey) : await this.getRaw(key);
|
|
44015
43998
|
const merged = raw ? await ModelMerger.mergeWithParents(raw) : void 0;
|
|
44016
|
-
checkSources();
|
|
44017
43999
|
return merged;
|
|
44018
44000
|
});
|
|
44019
|
-
checkSources();
|
|
44020
44001
|
return model;
|
|
44021
44002
|
}
|
|
44022
44003
|
/** Alias for {@link getMerged}. */
|
|
@@ -57531,7 +57512,7 @@ ${key}` : key, async () => {
|
|
|
57531
57512
|
var base = 36;
|
|
57532
57513
|
var tMin = 1;
|
|
57533
57514
|
var tMax = 26;
|
|
57534
|
-
var
|
|
57515
|
+
var skew2 = 38;
|
|
57535
57516
|
var damp2 = 700;
|
|
57536
57517
|
var initialBias = 72;
|
|
57537
57518
|
var initialN = 128;
|
|
@@ -57620,7 +57601,7 @@ ${key}` : key, async () => {
|
|
|
57620
57601
|
) {
|
|
57621
57602
|
delta = floor(delta / baseMinusTMin);
|
|
57622
57603
|
}
|
|
57623
|
-
return floor(k4 + (baseMinusTMin + 1) * delta / (delta +
|
|
57604
|
+
return floor(k4 + (baseMinusTMin + 1) * delta / (delta + skew2));
|
|
57624
57605
|
};
|
|
57625
57606
|
var decode2 = function decode3(input) {
|
|
57626
57607
|
var output = [];
|
|
@@ -95379,6 +95360,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
95379
95360
|
BannerPatterns: () => BannerPatterns,
|
|
95380
95361
|
BasicAssetKey: () => BasicAssetKey,
|
|
95381
95362
|
BatchedExecutor: () => BatchedExecutor,
|
|
95363
|
+
Biomes: () => Biomes,
|
|
95382
95364
|
BlockEntities: () => BlockEntities,
|
|
95383
95365
|
BlockObject: () => BlockObject,
|
|
95384
95366
|
BlockStateResolver: () => BlockStateResolver,
|
|
@@ -95841,6 +95823,122 @@ ${shader.fragmentShader}`.replace(
|
|
|
95841
95823
|
init_Assets();
|
|
95842
95824
|
init_BannerPatterns();
|
|
95843
95825
|
|
|
95826
|
+
// src/assets/Biomes.ts
|
|
95827
|
+
init_dirname();
|
|
95828
|
+
init_buffer2();
|
|
95829
|
+
init_process2();
|
|
95830
|
+
init_AssetKey();
|
|
95831
|
+
init_AssetLoader();
|
|
95832
|
+
init_AssetParsers();
|
|
95833
|
+
init_Caching();
|
|
95834
|
+
init_MineRenderError();
|
|
95835
|
+
init_Colormaps();
|
|
95836
|
+
|
|
95837
|
+
// src/assets/_biomes/SwampGrassColor.ts
|
|
95838
|
+
init_dirname();
|
|
95839
|
+
init_buffer2();
|
|
95840
|
+
init_process2();
|
|
95841
|
+
var permutation;
|
|
95842
|
+
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]];
|
|
95843
|
+
var skew = (Math.sqrt(3) - 1) / 2;
|
|
95844
|
+
var unskew = (3 - Math.sqrt(3)) / 6;
|
|
95845
|
+
function createPermutation() {
|
|
95846
|
+
const multiplier = 0x5deece66dn, mask = (1n << 48n) - 1n;
|
|
95847
|
+
let seed = 2345n ^ multiplier;
|
|
95848
|
+
const next = (bits2) => {
|
|
95849
|
+
seed = seed * multiplier + 11n & mask;
|
|
95850
|
+
return Number(seed >> BigInt(48 - bits2));
|
|
95851
|
+
};
|
|
95852
|
+
for (let i4 = 0; i4 < 3; i4++) {
|
|
95853
|
+
next(26);
|
|
95854
|
+
next(27);
|
|
95855
|
+
}
|
|
95856
|
+
const values = Uint8Array.from({ length: 256 }, (_4, i4) => i4);
|
|
95857
|
+
for (let i4 = 0; i4 < 256; i4++) {
|
|
95858
|
+
const bound = 256 - i4;
|
|
95859
|
+
let offset;
|
|
95860
|
+
if ((bound & bound - 1) === 0) offset = Math.floor(bound * next(31) / 2147483648);
|
|
95861
|
+
else {
|
|
95862
|
+
let bits2;
|
|
95863
|
+
do {
|
|
95864
|
+
bits2 = next(31);
|
|
95865
|
+
offset = bits2 % bound;
|
|
95866
|
+
} while (bits2 - offset + bound - 1 > 2147483647);
|
|
95867
|
+
}
|
|
95868
|
+
const other = i4 + offset;
|
|
95869
|
+
[values[i4], values[other]] = [values[other], values[i4]];
|
|
95870
|
+
}
|
|
95871
|
+
return values;
|
|
95872
|
+
}
|
|
95873
|
+
function swampGrassColor(x4, z4) {
|
|
95874
|
+
const p13 = permutation ?? (permutation = createPermutation());
|
|
95875
|
+
x4 *= 0.0225;
|
|
95876
|
+
z4 *= 0.0225;
|
|
95877
|
+
const s4 = (x4 + z4) * skew;
|
|
95878
|
+
const i4 = Math.floor(x4 + s4), j4 = Math.floor(z4 + s4);
|
|
95879
|
+
const t5 = (i4 + j4) * unskew;
|
|
95880
|
+
const dx = x4 - (i4 - t5), dz = z4 - (j4 - t5);
|
|
95881
|
+
const stepX = dx > dz ? 1 : 0, stepZ = 1 - stepX;
|
|
95882
|
+
const corner = (gx, gz, a4, b4) => {
|
|
95883
|
+
let falloff = 0.5 - a4 * a4 - b4 * b4;
|
|
95884
|
+
if (falloff < 0) return 0;
|
|
95885
|
+
const gradient = gradients[p13[gx + p13[gz & 255] & 255] % 12];
|
|
95886
|
+
falloff *= falloff;
|
|
95887
|
+
return falloff * falloff * (gradient[0] * a4 + gradient[1] * b4);
|
|
95888
|
+
};
|
|
95889
|
+
const noise = 70 * (corner(i4, j4, dx, dz) + corner(i4 + stepX, j4 + stepZ, dx - stepX + unskew, dz - stepZ + unskew) + corner(i4 + 1, j4 + 1, dx - 1 + 2 * unskew, dz - 1 + 2 * unskew));
|
|
95890
|
+
return noise < -0.1 ? 5011004 : 6975545;
|
|
95891
|
+
}
|
|
95892
|
+
|
|
95893
|
+
// src/assets/Biomes.ts
|
|
95894
|
+
var Biomes = class {
|
|
95895
|
+
/** Loads a biome registry entry, or returns `undefined` when no source provides it. */
|
|
95896
|
+
static async get(id, origin) {
|
|
95897
|
+
if (!/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(id)) throw new MineRenderError(`Invalid biome identifier: ${id}`);
|
|
95898
|
+
const [namespace, path] = id.includes(":") ? id.split(":") : ["minecraft", id];
|
|
95899
|
+
const key = new AssetKey(namespace, path, "worldgen", "biome", "data", ".json", origin?.root);
|
|
95900
|
+
return Caching.biomeCache.get(key.serialize(), async () => {
|
|
95901
|
+
const asset2 = await AssetLoader.get(key, "json" /* JSON */);
|
|
95902
|
+
if (asset2 === void 0) return void 0;
|
|
95903
|
+
if (!asset2 || typeof asset2 !== "object" || Array.isArray(asset2) || !asset2.effects || typeof asset2.effects !== "object" || Array.isArray(asset2.effects)) {
|
|
95904
|
+
throw new MineRenderError(`Invalid biome effects: ${id}`);
|
|
95905
|
+
}
|
|
95906
|
+
if (typeof asset2.temperature !== "number" || !Number.isFinite(asset2.temperature) || typeof asset2.downfall !== "number" || !Number.isFinite(asset2.downfall)) {
|
|
95907
|
+
throw new MineRenderError(`Invalid biome climate: ${id}`);
|
|
95908
|
+
}
|
|
95909
|
+
for (const kind of ["grass", "foliage", "dry_foliage", "water"]) {
|
|
95910
|
+
const color3 = asset2.effects[`${kind}_color`];
|
|
95911
|
+
if (color3 !== void 0) this.parseColor(color3, id, kind);
|
|
95912
|
+
}
|
|
95913
|
+
const modifier = asset2.effects.grass_color_modifier;
|
|
95914
|
+
if (modifier !== void 0 && modifier !== "none" && modifier !== "dark_forest" && modifier !== "swamp") {
|
|
95915
|
+
throw new MineRenderError(`Invalid biome grass color modifier: ${id}`);
|
|
95916
|
+
}
|
|
95917
|
+
return asset2;
|
|
95918
|
+
});
|
|
95919
|
+
}
|
|
95920
|
+
/** Returns packed sRGB, or `undefined` when the biome or requested water color is missing. */
|
|
95921
|
+
static async getColor(id, kind, origin, x4 = 0, z4 = 0) {
|
|
95922
|
+
const biome = await this.get(id, origin);
|
|
95923
|
+
if (!biome) return void 0;
|
|
95924
|
+
const rawColor = biome.effects[`${kind}_color`];
|
|
95925
|
+
let color3 = rawColor === void 0 ? void 0 : this.parseColor(rawColor, id, kind);
|
|
95926
|
+
if (kind === "water") return color3;
|
|
95927
|
+
const modifier = kind === "grass" ? biome.effects.grass_color_modifier : void 0;
|
|
95928
|
+
if (modifier === "swamp") return swampGrassColor(x4, z4);
|
|
95929
|
+
if (color3 === void 0) {
|
|
95930
|
+
const clamp2 = (value) => Math.max(0, Math.min(1, Math.fround(value)));
|
|
95931
|
+
color3 = await Colormaps.getColor(kind, origin, clamp2(biome.temperature), clamp2(biome.downfall));
|
|
95932
|
+
}
|
|
95933
|
+
return modifier === "dark_forest" ? (color3 & 16711422) + 2634762 >> 1 : color3;
|
|
95934
|
+
}
|
|
95935
|
+
static parseColor(value, id, kind) {
|
|
95936
|
+
if (typeof value === "string" && /^#[0-9a-fA-F]{6}$/.test(value)) return parseInt(value.slice(1), 16);
|
|
95937
|
+
if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 16777215) return value;
|
|
95938
|
+
throw new MineRenderError(`Invalid biome ${kind} color: ${id}`);
|
|
95939
|
+
}
|
|
95940
|
+
};
|
|
95941
|
+
|
|
95844
95942
|
// src/assets/BlockEntities.ts
|
|
95845
95943
|
init_dirname();
|
|
95846
95944
|
init_buffer2();
|
|
@@ -100445,8 +100543,20 @@ property list uchar int vertex_index
|
|
|
100445
100543
|
init_Colormaps();
|
|
100446
100544
|
init_MineRenderData();
|
|
100447
100545
|
var BlockTints = class {
|
|
100448
|
-
/**
|
|
100449
|
-
static async
|
|
100546
|
+
/** Returns a block's versioned biome color source, leaving fixed-color blocks unchanged. */
|
|
100547
|
+
static async biomeSource(key) {
|
|
100548
|
+
const rule = key && (await MineRenderData.get("blockTints", key.root))[key.toNamespacedString()];
|
|
100549
|
+
return rule ? rule.biome ?? (rule.source === "grass" ? "grass" : void 0) : void 0;
|
|
100550
|
+
}
|
|
100551
|
+
/** Resolves one block's biome tint at world block coordinates, without biome blending. */
|
|
100552
|
+
static async getBiomeColor(key, biome, position) {
|
|
100553
|
+
if (!biome) return void 0;
|
|
100554
|
+
const x4 = position?.[0], z4 = position?.[2];
|
|
100555
|
+
const source = await this.biomeSource(key);
|
|
100556
|
+
return source ? Biomes.getColor(biome, source, key, x4, z4) : void 0;
|
|
100557
|
+
}
|
|
100558
|
+
/** Resolves used tint indices from biome or preview colors; explicit tints take precedence. */
|
|
100559
|
+
static async get(key, state, model, tints, biomeColor) {
|
|
100450
100560
|
if (!key) return tints;
|
|
100451
100561
|
const candidates = (model.elements ?? []).flatMap((element) => Object.values(element.faces)).some((face) => face?.tintindex !== void 0 && face.tintindex >= 0 && tints?.[face.tintindex] === void 0);
|
|
100452
100562
|
if (!candidates) return tints;
|
|
@@ -100462,8 +100572,12 @@ property list uchar int vertex_index
|
|
|
100462
100572
|
}
|
|
100463
100573
|
}
|
|
100464
100574
|
if (!indices.size) return tints;
|
|
100575
|
+
const source = rule.biome ?? (rule.source === "grass" ? "grass" : void 0);
|
|
100576
|
+
const biome = source ? typeof biomeColor === "function" ? await biomeColor() : biomeColor : void 0;
|
|
100465
100577
|
let color3;
|
|
100466
|
-
|
|
100578
|
+
if (biome !== void 0) {
|
|
100579
|
+
color3 = biome;
|
|
100580
|
+
} else switch (rule.source) {
|
|
100467
100581
|
case "constant":
|
|
100468
100582
|
color3 = rule.color;
|
|
100469
100583
|
break;
|
|
@@ -100508,7 +100622,6 @@ property list uchar int vertex_index
|
|
|
100508
100622
|
init_ModelCulling();
|
|
100509
100623
|
init_FluidGeometry();
|
|
100510
100624
|
init_MineRenderData();
|
|
100511
|
-
init_AssetLoader();
|
|
100512
100625
|
init_Entities();
|
|
100513
100626
|
var _BlockObject = class _BlockObject extends SceneObject {
|
|
100514
100627
|
constructor(blockState3, options) {
|
|
@@ -100530,21 +100643,15 @@ property list uchar int vertex_index
|
|
|
100530
100643
|
this._entityGeneration = 0;
|
|
100531
100644
|
this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
|
|
100532
100645
|
this.variantPosition = options?.variantPosition ? [...options.variantPosition] : void 0;
|
|
100646
|
+
this.biomePosition = options?.biomePosition ? [...options.biomePosition] : void 0;
|
|
100533
100647
|
}
|
|
100534
100648
|
async init() {
|
|
100535
|
-
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
100536
|
-
const checkSources = () => {
|
|
100537
|
-
if (root !== AssetLoader.ROOT || scope !== AssetLoader.persistentScope) throw new Error("Asset sources changed while loading a block; retry the request");
|
|
100538
|
-
};
|
|
100539
100649
|
this._fluidRules = await MineRenderData.get("fluids", this.blockState.key?.root);
|
|
100540
|
-
checkSources();
|
|
100541
100650
|
if (this.options.applyDefaultState) {
|
|
100542
100651
|
this._setState(await BlockStateResolver.defaults(this.blockState));
|
|
100543
|
-
checkSources();
|
|
100544
100652
|
}
|
|
100545
100653
|
if (this.options.initialState !== void 0) this._setState(this.options.initialState);
|
|
100546
100654
|
await this.recreateModels();
|
|
100547
|
-
checkSources();
|
|
100548
100655
|
}
|
|
100549
100656
|
dispose() {
|
|
100550
100657
|
this.clearModels();
|
|
@@ -100722,11 +100829,16 @@ property list uchar int vertex_index
|
|
|
100722
100829
|
const { FluidModelObject: FluidModelObject2, sampleFluid: sampleFluid2 } = await Promise.resolve().then(() => (init_FluidModelObject(), FluidModelObject_exports));
|
|
100723
100830
|
this._fluidSampler = sample;
|
|
100724
100831
|
const surface = sampleFluid2(kind, (x4, y5, z4) => x4 === 0 && y5 === 0 && z4 === 0 ? { fluid: kind, level: this.fluidLevel } : sample?.(x4, y5, z4) ?? {});
|
|
100725
|
-
|
|
100832
|
+
const tint = this.options.tints?.[0] ?? this.waterTint;
|
|
100833
|
+
const fluidKey = `${surface.key}|${tint ?? "default"}`;
|
|
100834
|
+
if (this._fluidKey === fluidKey) return;
|
|
100726
100835
|
const key = new AssetKey("minecraft", `${kind}/${surface.key}`, "models", "fluid", "assets", ".json", this.blockState.key?.root);
|
|
100727
100836
|
const replacement = await this.scene.addSceneObject(
|
|
100728
100837
|
{ key },
|
|
100729
|
-
() => new FluidModelObject2(kind, surface.sample, this.blockState.key,
|
|
100838
|
+
() => new FluidModelObject2(kind, surface.sample, this.blockState.key, {
|
|
100839
|
+
...this.options,
|
|
100840
|
+
tints: tint === void 0 ? this.options.tints : { ...this.options.tints, 0: tint }
|
|
100841
|
+
})
|
|
100730
100842
|
);
|
|
100731
100843
|
const previous = this._fluidModel;
|
|
100732
100844
|
const matrix = previous ? this.getModelMatrix(previous) : new Matrix4().makeTranslation(...this.position.toArray());
|
|
@@ -100735,7 +100847,7 @@ property list uchar int vertex_index
|
|
|
100735
100847
|
this._models = this._models.filter((model) => model !== previous);
|
|
100736
100848
|
this._models.push(replacement);
|
|
100737
100849
|
this._fluidModel = replacement;
|
|
100738
|
-
this._fluidKey =
|
|
100850
|
+
this._fluidKey = fluidKey;
|
|
100739
100851
|
this._isInstanced || (this._isInstanced = isInstanceReference(replacement));
|
|
100740
100852
|
this._instanceCounter = this._isInstanced ? 1 : 0;
|
|
100741
100853
|
if (previous) this.removeModels([previous]);
|
|
@@ -100758,6 +100870,7 @@ property list uchar int vertex_index
|
|
|
100758
100870
|
}
|
|
100759
100871
|
async recreateModels() {
|
|
100760
100872
|
this.clearModels();
|
|
100873
|
+
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;
|
|
100761
100874
|
if (resolveBlockFluidState(this.blockState.key, this.state, this._fluidRules)?.renderModel === false) {
|
|
100762
100875
|
await this.updateFluid(this._fluidSampler);
|
|
100763
100876
|
return;
|
|
@@ -100792,7 +100905,13 @@ property list uchar int vertex_index
|
|
|
100792
100905
|
const model = await Models.getMerged(modelKey);
|
|
100793
100906
|
const options = {
|
|
100794
100907
|
...this.options,
|
|
100795
|
-
tints: model ? await BlockTints.get(
|
|
100908
|
+
tints: model ? await BlockTints.get(
|
|
100909
|
+
this.blockState.key,
|
|
100910
|
+
this.state,
|
|
100911
|
+
model,
|
|
100912
|
+
this.options.tints,
|
|
100913
|
+
() => BlockTints.getBiomeColor(this.blockState.key, this.options.biome, this.biomePosition)
|
|
100914
|
+
) : this.options.tints,
|
|
100796
100915
|
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0,
|
|
100797
100916
|
cullMask: this.options.displayPosition ? 0 : ModelCulling.toLocalMask(this._cullMask, rotation)
|
|
100798
100917
|
};
|
|
@@ -106527,7 +106646,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
106527
106646
|
init_process2();
|
|
106528
106647
|
init_MineRenderError();
|
|
106529
106648
|
init_MineRenderData();
|
|
106530
|
-
init_AssetLoader();
|
|
106531
106649
|
init_NBTHelper();
|
|
106532
106650
|
|
|
106533
106651
|
// src/world/ChunkData.ts
|
|
@@ -106804,14 +106922,12 @@ gl_FragDepth=readDepth(vUv);
|
|
|
106804
106922
|
/** Decodes all stored chunks. Gzip, zlib, LZ4, and uncompressed payloads are supported. */
|
|
106805
106923
|
static async parse(data, options = {}) {
|
|
106806
106924
|
options = { ...options };
|
|
106807
|
-
const checkSources = this.assetGuard();
|
|
106808
106925
|
options.signal?.throwIfAborted();
|
|
106809
106926
|
const bytes = this.bytes(data);
|
|
106810
106927
|
const chunks = [];
|
|
106811
106928
|
for (const location of this.locations(bytes)) {
|
|
106812
106929
|
chunks.push(await this.abortable(this.readChunk(bytes, location, options), options.signal));
|
|
106813
106930
|
}
|
|
106814
|
-
checkSources();
|
|
106815
106931
|
return { chunks };
|
|
106816
106932
|
}
|
|
106817
106933
|
/**
|
|
@@ -106822,22 +106938,12 @@ gl_FragDepth=readDepth(vUv);
|
|
|
106822
106938
|
*/
|
|
106823
106939
|
static async parseChunk(data, localX, localZ, options = {}) {
|
|
106824
106940
|
options = { ...options };
|
|
106825
|
-
const checkSources = this.assetGuard();
|
|
106826
106941
|
options.signal?.throwIfAborted();
|
|
106827
106942
|
const bytes = this.bytes(data);
|
|
106828
106943
|
const location = this.location(bytes, localX, localZ);
|
|
106829
106944
|
const chunk = location ? await this.abortable(this.readChunk(bytes, location, options), options.signal) : void 0;
|
|
106830
|
-
checkSources();
|
|
106831
106945
|
return chunk;
|
|
106832
106946
|
}
|
|
106833
|
-
static assetGuard() {
|
|
106834
|
-
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
106835
|
-
return () => {
|
|
106836
|
-
if (AssetLoader.ROOT !== root || AssetLoader.persistentScope !== scope) {
|
|
106837
|
-
throw new MineRenderError("Asset sources changed while parsing Anvil data; retry the request");
|
|
106838
|
-
}
|
|
106839
|
-
};
|
|
106840
|
-
}
|
|
106841
106947
|
/**
|
|
106842
106948
|
* Decodes one chunk from an `entities/r.x.z.mca` file without migrating its NBT.
|
|
106843
106949
|
* @param localX - Chunk x within the region, from 0 to 31.
|
|
@@ -107376,24 +107482,48 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107376
107482
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("maxAtlasSize must be a positive integer");
|
|
107377
107483
|
}
|
|
107378
107484
|
/** Returns templates for the matched parts, or `undefined` when the block needs an individual render object. */
|
|
107379
|
-
async get(blockState3, properties = {}, position) {
|
|
107380
|
-
const
|
|
107381
|
-
|
|
107485
|
+
async get(blockState3, properties = {}, position, biome) {
|
|
107486
|
+
const biomePosition = position ? [...position] : void 0;
|
|
107487
|
+
const prepared = await this.state(blockState3, properties);
|
|
107488
|
+
if (!prepared) return void 0;
|
|
107489
|
+
return Promise.all(prepared.groups.map(async (group) => {
|
|
107490
|
+
const variant = BlockStateResolver.choose(group, biomePosition);
|
|
107491
|
+
const choice = prepared.choices.get(variant);
|
|
107492
|
+
const tints = await BlockTints.get(
|
|
107493
|
+
blockState3.key,
|
|
107494
|
+
prepared.state,
|
|
107495
|
+
choice.model,
|
|
107496
|
+
void 0,
|
|
107497
|
+
() => BlockTints.getBiomeColor(blockState3.key, biome, biomePosition)
|
|
107498
|
+
);
|
|
107499
|
+
return this.template(variant, choice, tints);
|
|
107500
|
+
}));
|
|
107501
|
+
}
|
|
107502
|
+
/** Resolves section templates for one tint palette, with a synchronous weighted choice for each cell. */
|
|
107503
|
+
async prepareState(blockState3, properties = {}, biomeColor) {
|
|
107504
|
+
const prepared = await this.state(blockState3, properties);
|
|
107505
|
+
if (!prepared) return void 0;
|
|
107506
|
+
let color3;
|
|
107507
|
+
const resolveColor = typeof biomeColor === "function" ? () => color3 ?? (color3 = biomeColor()) : biomeColor;
|
|
107508
|
+
const templates = /* @__PURE__ */ new Map();
|
|
107509
|
+
await Promise.all([...prepared.choices].map(async ([variant, choice]) => {
|
|
107510
|
+
const tints = await BlockTints.get(blockState3.key, prepared.state, choice.model, void 0, resolveColor);
|
|
107511
|
+
templates.set(variant, await this.template(variant, choice, tints));
|
|
107512
|
+
}));
|
|
107513
|
+
return { pick: (position) => prepared.groups.map((group) => templates.get(BlockStateResolver.choose(group, position))) };
|
|
107382
107514
|
}
|
|
107383
|
-
|
|
107384
|
-
async prepareState(blockState3, properties = {}) {
|
|
107515
|
+
async state(blockState3, properties) {
|
|
107385
107516
|
let states = this.states.get(blockState3);
|
|
107386
107517
|
if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
|
|
107387
107518
|
const key = JSON.stringify(Object.entries(properties).sort(([a4], [b4]) => a4.localeCompare(b4)));
|
|
107388
|
-
|
|
107389
|
-
if (!prepared) return void 0;
|
|
107390
|
-
return { pick: (position) => prepared.groups.map((group) => prepared.templates.get(BlockStateResolver.choose(group, position))) };
|
|
107519
|
+
return cached(states, key, () => this.prepare(blockState3, properties));
|
|
107391
107520
|
}
|
|
107392
107521
|
/** Returns the shared still/flow atlas used by per-block fluid objects. */
|
|
107393
107522
|
fluidAtlas(kind, root) {
|
|
107394
|
-
|
|
107523
|
+
const key = new AssetKey("minecraft", kind, "models", "fluid", "assets", ".json", root);
|
|
107524
|
+
return cached(this.fluidAtlases, key.serialize(), async () => {
|
|
107395
107525
|
const atlas = await UVMapper.getAtlas({
|
|
107396
|
-
key
|
|
107526
|
+
key,
|
|
107397
107527
|
textures: { still: `minecraft:block/${kind}_still`, flow: `minecraft:block/${kind}_flow` },
|
|
107398
107528
|
elements: []
|
|
107399
107529
|
});
|
|
@@ -107405,64 +107535,67 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107405
107535
|
const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
|
|
107406
107536
|
const groups = BlockStateResolver.matching(blockState3, state);
|
|
107407
107537
|
if (!groups.length) return void 0;
|
|
107408
|
-
const
|
|
107538
|
+
const prepared = /* @__PURE__ */ new Map();
|
|
107409
107539
|
for (const group of groups) {
|
|
107410
107540
|
const choices = Array.isArray(group) ? group : [group];
|
|
107411
107541
|
if (!choices.length) return void 0;
|
|
107412
107542
|
for (const variant of choices) {
|
|
107413
107543
|
if (!variant.model) return void 0;
|
|
107414
|
-
const
|
|
107544
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
107545
|
+
modelKey.root = blockState3.key?.root;
|
|
107546
|
+
const model = await Models.getMerged(modelKey);
|
|
107415
107547
|
if (!model?.elements?.length) return void 0;
|
|
107416
107548
|
const atlas = await UVMapper.getAtlas(model);
|
|
107417
107549
|
const rotation = BlockStateResolver.rotation(variant);
|
|
107418
107550
|
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
107419
|
-
|
|
107420
|
-
let models = this.models.get(model);
|
|
107421
|
-
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
107422
|
-
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
107423
|
-
const template = await cached(models, key, async () => {
|
|
107424
|
-
const object4 = new SectionModel(model, {
|
|
107425
|
-
instanceMeshes: false,
|
|
107426
|
-
mergeMeshes: true,
|
|
107427
|
-
tints,
|
|
107428
|
-
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
107429
|
-
});
|
|
107430
|
-
await object4.init();
|
|
107431
|
-
let geometry = object4.children[0].geometry;
|
|
107432
|
-
geometry.applyMatrix4(new Matrix4().makeRotationFromEuler(rotation));
|
|
107433
|
-
object4.clear();
|
|
107434
|
-
const keep = [];
|
|
107435
|
-
const cullFaces = [];
|
|
107436
|
-
for (const element of atlas.model.elements) {
|
|
107437
|
-
for (const face of CUBE_FACES) {
|
|
107438
|
-
const data = element.faces[face];
|
|
107439
|
-
keep.push(data !== void 0);
|
|
107440
|
-
if (!data) continue;
|
|
107441
|
-
const local = CUBE_FACES.findIndex((name2) => name2 === data.cullface);
|
|
107442
|
-
if (local < 0) {
|
|
107443
|
-
cullFaces.push(0);
|
|
107444
|
-
continue;
|
|
107445
|
-
}
|
|
107446
|
-
const normal = new Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
107447
|
-
const world = CUBE_FACE_OFFSETS.findIndex(([x4, y5, z4]) => Math.abs(normal.x - x4) < 1e-6 && Math.abs(normal.y - y5) < 1e-6 && Math.abs(normal.z - z4) < 1e-6);
|
|
107448
|
-
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
107449
|
-
}
|
|
107450
|
-
}
|
|
107451
|
-
geometry = compactQuads(geometry, keep);
|
|
107452
|
-
const template2 = {
|
|
107453
|
-
geometry,
|
|
107454
|
-
atlas,
|
|
107455
|
-
cullFaces: new Uint8Array(cullFaces),
|
|
107456
|
-
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
107457
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
107458
|
-
};
|
|
107459
|
-
this.templates.add(template2);
|
|
107460
|
-
return template2;
|
|
107461
|
-
});
|
|
107462
|
-
templates.set(variant, template);
|
|
107551
|
+
prepared.set(variant, { model, atlas, rotation });
|
|
107463
107552
|
}
|
|
107464
107553
|
}
|
|
107465
|
-
return { groups,
|
|
107554
|
+
return { state, groups, choices: prepared };
|
|
107555
|
+
}
|
|
107556
|
+
async template(variant, { model, atlas, rotation }, tints) {
|
|
107557
|
+
let models = this.models.get(model);
|
|
107558
|
+
if (!models) this.models.set(model, models = /* @__PURE__ */ new Map());
|
|
107559
|
+
const key = JSON.stringify([rotation.x, rotation.y, rotation.z, variant.uvlock, tints]);
|
|
107560
|
+
return cached(models, key, async () => {
|
|
107561
|
+
const object4 = new SectionModel(model, {
|
|
107562
|
+
instanceMeshes: false,
|
|
107563
|
+
mergeMeshes: true,
|
|
107564
|
+
tints,
|
|
107565
|
+
uvLockRotation: variant.uvlock && (rotation.x !== 0 || rotation.y !== 0) ? [rotation.x, rotation.y, rotation.z] : void 0
|
|
107566
|
+
});
|
|
107567
|
+
await object4.init();
|
|
107568
|
+
let geometry = object4.children[0].geometry;
|
|
107569
|
+
geometry.applyMatrix4(new Matrix4().makeRotationFromEuler(rotation));
|
|
107570
|
+
object4.clear();
|
|
107571
|
+
const keep = [];
|
|
107572
|
+
const cullFaces = [];
|
|
107573
|
+
for (const element of atlas.model.elements) {
|
|
107574
|
+
for (const face of CUBE_FACES) {
|
|
107575
|
+
const data = element.faces[face];
|
|
107576
|
+
keep.push(data !== void 0);
|
|
107577
|
+
if (!data) continue;
|
|
107578
|
+
const local = CUBE_FACES.findIndex((name2) => name2 === data.cullface);
|
|
107579
|
+
if (local < 0) {
|
|
107580
|
+
cullFaces.push(0);
|
|
107581
|
+
continue;
|
|
107582
|
+
}
|
|
107583
|
+
const normal = new Vector3(...CUBE_FACE_OFFSETS[local]).applyEuler(rotation);
|
|
107584
|
+
const world = CUBE_FACE_OFFSETS.findIndex(([x4, y5, z4]) => Math.abs(normal.x - x4) < 1e-6 && Math.abs(normal.y - y5) < 1e-6 && Math.abs(normal.z - z4) < 1e-6);
|
|
107585
|
+
cullFaces.push(world < 0 ? 0 : 1 << world);
|
|
107586
|
+
}
|
|
107587
|
+
}
|
|
107588
|
+
geometry = compactQuads(geometry, keep);
|
|
107589
|
+
const template = {
|
|
107590
|
+
geometry,
|
|
107591
|
+
atlas,
|
|
107592
|
+
cullFaces: new Uint8Array(cullFaces),
|
|
107593
|
+
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
107594
|
+
layer: atlas.hasTranslucency ? 1 : 0
|
|
107595
|
+
};
|
|
107596
|
+
this.templates.add(template);
|
|
107597
|
+
return template;
|
|
107598
|
+
});
|
|
107466
107599
|
}
|
|
107467
107600
|
/** Disposes prepared geometry and clears this world's template caches. */
|
|
107468
107601
|
clear() {
|
|
@@ -107554,7 +107687,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107554
107687
|
|
|
107555
107688
|
// src/world/_entities/WorldEntities.ts
|
|
107556
107689
|
init_BannerPatterns();
|
|
107557
|
-
init_AssetLoader();
|
|
107558
107690
|
var WorldEntities = class {
|
|
107559
107691
|
constructor(scene) {
|
|
107560
107692
|
this.scene = scene;
|
|
@@ -107562,10 +107694,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107562
107694
|
}
|
|
107563
107695
|
/** Captures column ownership before asynchronous block or asset loading starts. */
|
|
107564
107696
|
prepare(entities = [], column) {
|
|
107565
|
-
const root = AssetLoader.ROOT, scope = AssetLoader.persistentScope;
|
|
107566
|
-
const checkSources = () => {
|
|
107567
|
-
if (root !== AssetLoader.ROOT || scope !== AssetLoader.persistentScope) throw new Error("Asset sources changed while loading saved entities; retry the request");
|
|
107568
|
-
};
|
|
107569
107697
|
const placements = entities.flatMap((entity) => {
|
|
107570
107698
|
const resolved = resolveSavedEntity(entity);
|
|
107571
107699
|
if (!resolved) return [];
|
|
@@ -107581,17 +107709,13 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107581
107709
|
let object4;
|
|
107582
107710
|
try {
|
|
107583
107711
|
if (!current()) return;
|
|
107584
|
-
checkSources();
|
|
107585
107712
|
const models = await Entities.getEntityList();
|
|
107586
|
-
checkSources();
|
|
107587
107713
|
if (!models.includes(placement.key.path) || !current()) return;
|
|
107588
107714
|
const model = await Entities.getEntity(placement.key, placement.texture, { when: placement.when });
|
|
107589
|
-
checkSources();
|
|
107590
107715
|
if (!model || !current()) return;
|
|
107591
107716
|
let tints = placement.tints;
|
|
107592
107717
|
if (placement.woolDye) {
|
|
107593
107718
|
const dye = (await BannerPatterns.getColors(placement.key.root))[placement.woolDye];
|
|
107594
|
-
checkSources();
|
|
107595
107719
|
const tint = placement.woolDye === "white" ? 15132390 : Math.floor((dye >> 16 & 255) * 0.75) << 16 | Math.floor((dye >> 8 & 255) * 0.75) << 8 | Math.floor((dye & 255) * 0.75);
|
|
107596
107720
|
tints = { ...tints, wool_color: tint };
|
|
107597
107721
|
}
|
|
@@ -107601,7 +107725,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107601
107725
|
object4.position.fromArray(placement.position).multiplyScalar(16).addScalar(-8);
|
|
107602
107726
|
object4.rotation.y = placement.yaw;
|
|
107603
107727
|
await object4.init();
|
|
107604
|
-
checkSources();
|
|
107605
107728
|
if (!current()) return;
|
|
107606
107729
|
placement.owner.add(object4);
|
|
107607
107730
|
this.scene.add(object4);
|
|
@@ -107798,7 +107921,6 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107798
107921
|
}
|
|
107799
107922
|
try {
|
|
107800
107923
|
await this.clearChunkColumn(chunk.x, chunk.z);
|
|
107801
|
-
let sliceStart = performance.now();
|
|
107802
107924
|
for (const section of chunk.sections) {
|
|
107803
107925
|
if (section.biomes) {
|
|
107804
107926
|
const position = new Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
@@ -107812,6 +107934,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107812
107934
|
if (!column) this.biomes.set(key, column = /* @__PURE__ */ new Map());
|
|
107813
107935
|
column.set(section.y, copy);
|
|
107814
107936
|
}
|
|
107937
|
+
}
|
|
107938
|
+
let sliceStart = performance.now();
|
|
107939
|
+
for (const section of chunk.sections) {
|
|
107815
107940
|
if (!executor) {
|
|
107816
107941
|
if (!occupiedSections.has(section.y)) continue;
|
|
107817
107942
|
const position = new Vector3(chunk.x * 16, section.y * 16, chunk.z * 16);
|
|
@@ -107976,18 +108101,34 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107976
108101
|
const key = this.worldPosToChunkKey(pos);
|
|
107977
108102
|
let chunk = this._chunks.get(key);
|
|
107978
108103
|
if (typeof chunk === "undefined") {
|
|
108104
|
+
const x4 = Math.floor(pos.x / 16), y5 = Math.floor(pos.y / 16), z4 = Math.floor(pos.z / 16);
|
|
107979
108105
|
chunk = new Chunk(
|
|
107980
108106
|
this.scene,
|
|
107981
|
-
|
|
107982
|
-
|
|
107983
|
-
|
|
108107
|
+
x4,
|
|
108108
|
+
y5,
|
|
108109
|
+
z4,
|
|
107984
108110
|
(positions) => this.updateCulling(positions),
|
|
107985
108111
|
this.sectionModels,
|
|
107986
|
-
(
|
|
107987
|
-
const cx = Math.floor(
|
|
108112
|
+
(x5, y6, z5) => {
|
|
108113
|
+
const cx = Math.floor(x5 / 16), cy = Math.floor(y6 / 16), cz = Math.floor(z5 / 16);
|
|
107988
108114
|
const section = this._chunks.get(`${cx}_${cy}_${cz}`);
|
|
107989
|
-
const index = (
|
|
108115
|
+
const index = (y6 - cy * 16) * 256 + (z5 - cz * 16) * 16 + x5 - cx * 16;
|
|
107990
108116
|
return (section?.fluidByteIndex(index) ?? 0) | (section?.isOccludingIndex(index) ? 64 : 0);
|
|
108117
|
+
},
|
|
108118
|
+
(x5, y6, z5) => this.getBiomeAt(x5, y6, z5),
|
|
108119
|
+
async (biomes) => {
|
|
108120
|
+
if (this._chunks.get(key) !== chunk) return;
|
|
108121
|
+
const columnKey = `${x4}_${z4}`;
|
|
108122
|
+
let column = this.biomes.get(columnKey);
|
|
108123
|
+
if (biomes) {
|
|
108124
|
+
if (!column) this.biomes.set(columnKey, column = /* @__PURE__ */ new Map());
|
|
108125
|
+
column.set(y5, biomes);
|
|
108126
|
+
} else {
|
|
108127
|
+
column?.delete(y5);
|
|
108128
|
+
if (!column?.size) this.biomes.delete(columnKey);
|
|
108129
|
+
}
|
|
108130
|
+
await chunk.refreshBiomes();
|
|
108131
|
+
await this._chunks.get(`${x4}_${y5 + 1}_${z4}`)?.refreshBiomes();
|
|
107991
108132
|
}
|
|
107992
108133
|
);
|
|
107993
108134
|
this._chunks.set(key, chunk);
|
|
@@ -108048,6 +108189,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108048
108189
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
108049
108190
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
108050
108191
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
108192
|
+
if (fluids?.waterTints && fluids.waterTints.length !== 4096 * 3) throw new RangeError("Section water tints must contain RGB for 4096 cells");
|
|
108051
108193
|
for (const template of templateData) {
|
|
108052
108194
|
const { quads } = template;
|
|
108053
108195
|
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) {
|
|
@@ -108125,7 +108267,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108125
108267
|
height
|
|
108126
108268
|
});
|
|
108127
108269
|
}
|
|
108128
|
-
|
|
108270
|
+
const tintIndex = (x4 + z4 * 16 + y5 * 256) * 3;
|
|
108271
|
+
const tint = fluid === "water" && fluids.waterTints ? fluids.waterTints.subarray(tintIndex, tintIndex + 3) : data.tint;
|
|
108272
|
+
fluidPages.get(fluid).fluids.push({ quads, x: x4, y: y5, z: z4, data, tint });
|
|
108129
108273
|
}
|
|
108130
108274
|
pages.push(...[...fluidPages.values()].sort((a4, b4) => Number(atlases[a4.placements[0].atlas].animated) - Number(atlases[b4.placements[0].atlas].animated) || a4.placements[0].atlas - b4.placements[0].atlas));
|
|
108131
108275
|
}
|
|
@@ -108174,7 +108318,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108174
108318
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
108175
108319
|
}
|
|
108176
108320
|
}
|
|
108177
|
-
for (const { quads, x: x4, y: y5, z: z4, data } of page.fluids) {
|
|
108321
|
+
for (const { quads, x: x4, y: y5, z: z4, data, tint } of page.fluids) {
|
|
108178
108322
|
const atlas = atlases[data.atlas];
|
|
108179
108323
|
const placement = page.placements[0];
|
|
108180
108324
|
const mapU = (u4) => (placement.x + u4 * atlas.width) / page.width;
|
|
@@ -108198,7 +108342,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108198
108342
|
mapU((rect[0] + rect[2]) / atlas.width),
|
|
108199
108343
|
mapV(1 - rect[1] / atlas.height)
|
|
108200
108344
|
], vertex2 * 4);
|
|
108201
|
-
colors.set(
|
|
108345
|
+
colors.set(tint, vertex2 * 3);
|
|
108202
108346
|
}
|
|
108203
108347
|
outputIndices.set([start, start + 1, start + 2, start, start + 2, start + 3], indexOffset);
|
|
108204
108348
|
indexOffset += 6;
|
|
@@ -108342,7 +108486,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108342
108486
|
input.cullMasks[i4] = cullMask;
|
|
108343
108487
|
}
|
|
108344
108488
|
if (fluids) {
|
|
108345
|
-
input.fluids = { cells: fluids.cells };
|
|
108489
|
+
input.fluids = { cells: fluids.cells, waterTints: fluids.waterTints };
|
|
108346
108490
|
for (const kind of ["water", "lava"]) {
|
|
108347
108491
|
const atlas = fluids[kind];
|
|
108348
108492
|
if (!atlas) continue;
|
|
@@ -108443,11 +108587,14 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108443
108587
|
init_FluidGeometry();
|
|
108444
108588
|
init_FluidQuads();
|
|
108445
108589
|
init_CubeFace();
|
|
108590
|
+
var WATER_TINT2 = new Color(4159204).toArray();
|
|
108446
108591
|
var Chunk = class _Chunk {
|
|
108447
|
-
constructor(scene, x4, y5, z4, onBlocksChanged, sectionModels, neighborCell) {
|
|
108592
|
+
constructor(scene, x4, y5, z4, onBlocksChanged, sectionModels, neighborCell, biomeAt, onBiomesChanged) {
|
|
108448
108593
|
this.onBlocksChanged = onBlocksChanged;
|
|
108449
108594
|
this.sectionModels = sectionModels;
|
|
108450
108595
|
this.neighborCell = neighborCell;
|
|
108596
|
+
this.biomeAt = biomeAt;
|
|
108597
|
+
this.onBiomesChanged = onBiomesChanged;
|
|
108451
108598
|
this.data = new ChunkData();
|
|
108452
108599
|
this.renderedBlocks = /* @__PURE__ */ new Map();
|
|
108453
108600
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
@@ -108472,6 +108619,56 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108472
108619
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
108473
108620
|
return this.renderedBlocks.get(index);
|
|
108474
108621
|
}
|
|
108622
|
+
getBiomeAt(posOrX, y5, z4) {
|
|
108623
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector3(posOrX, y5, z4));
|
|
108624
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector3(...posOrX));
|
|
108625
|
+
const pos = this.worldPosToChunkPos(posOrX);
|
|
108626
|
+
_Chunk.chunkPosToBlockIndex(pos);
|
|
108627
|
+
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];
|
|
108628
|
+
}
|
|
108629
|
+
/** Copies 64 biome IDs in x + z * 4 + y * 16 order and refreshes placed blocks. Omit the array to clear biome data. */
|
|
108630
|
+
setBiomes(biomes) {
|
|
108631
|
+
const copy = biomes ? [...biomes] : void 0;
|
|
108632
|
+
if (copy && (copy.length !== 64 || !copy.every((id) => typeof id === "string" && id.length > 0))) {
|
|
108633
|
+
throw new RangeError("Section biomes must contain 64 nonempty biome IDs");
|
|
108634
|
+
}
|
|
108635
|
+
if (this.onBiomesChanged) return this.onBiomesChanged(copy);
|
|
108636
|
+
this.biomes = copy;
|
|
108637
|
+
return this.refreshBiomes();
|
|
108638
|
+
}
|
|
108639
|
+
/** Rebuilds biome-tinted blocks while preserving hidden blocks and unrelated render objects. */
|
|
108640
|
+
async refreshBiomes() {
|
|
108641
|
+
const affected = /* @__PURE__ */ new Map();
|
|
108642
|
+
const blocks = [];
|
|
108643
|
+
for (const index of this.renderedBlocks.keys()) {
|
|
108644
|
+
const block = this.data.get(index);
|
|
108645
|
+
const stateKey = ChunkData.paletteKey(block);
|
|
108646
|
+
let matches = affected.get(stateKey);
|
|
108647
|
+
if (!matches) {
|
|
108648
|
+
const key = AssetKey.parse("blockstates", block.type);
|
|
108649
|
+
matches = BlockStates.get(key).then(async (state) => {
|
|
108650
|
+
const origin = state?.key ?? key;
|
|
108651
|
+
const [source, fluid] = await Promise.all([BlockTints.biomeSource(origin), getBlockFluidState(origin, block.properties)]);
|
|
108652
|
+
return !!source || fluid?.kind === "water";
|
|
108653
|
+
});
|
|
108654
|
+
affected.set(stateKey, matches);
|
|
108655
|
+
}
|
|
108656
|
+
if (await matches) blocks.push({ index, block });
|
|
108657
|
+
}
|
|
108658
|
+
if (!blocks.length) return;
|
|
108659
|
+
const hidden = new Set(this.hiddenBlocks);
|
|
108660
|
+
try {
|
|
108661
|
+
await this.placeBlocks(blocks);
|
|
108662
|
+
} finally {
|
|
108663
|
+
for (const index of hidden) {
|
|
108664
|
+
this.hiddenBlocks.add(index);
|
|
108665
|
+
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
108666
|
+
}
|
|
108667
|
+
const positions = blocks.map(({ index }) => new Vector3(...this.positionAt(index)));
|
|
108668
|
+
if (this.onBlocksChanged) await this.onBlocksChanged(positions);
|
|
108669
|
+
else await this.rebuildSectionMesh();
|
|
108670
|
+
}
|
|
108671
|
+
}
|
|
108475
108672
|
async setBlockAt(posOrX, yOrBlock, z4, block) {
|
|
108476
108673
|
if (typeof posOrX == "number") {
|
|
108477
108674
|
return this.setBlockAt(new Vector3(posOrX, yOrBlock, z4), block);
|
|
@@ -108510,14 +108707,15 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108510
108707
|
nbt: block.nbt === void 0 ? void 0 : structuredClone(block.nbt)
|
|
108511
108708
|
} : void 0
|
|
108512
108709
|
}));
|
|
108513
|
-
const states =
|
|
108514
|
-
const
|
|
108515
|
-
|
|
108516
|
-
|
|
108517
|
-
|
|
108518
|
-
|
|
108519
|
-
|
|
108520
|
-
|
|
108710
|
+
const states = /* @__PURE__ */ new Map();
|
|
108711
|
+
for (const { index, key, block } of placements) {
|
|
108712
|
+
if (key === void 0) continue;
|
|
108713
|
+
let state = states.get(key);
|
|
108714
|
+
if (!state) states.set(key, state = { stored: block, indices: [] });
|
|
108715
|
+
state.indices.push(index);
|
|
108716
|
+
}
|
|
108717
|
+
const biomes = /* @__PURE__ */ new Map();
|
|
108718
|
+
const settled = await Promise.allSettled([...states.values()].map(({ stored, indices }) => this.resolveState(stored, indices, biomes)));
|
|
108521
108719
|
const resolutions = new Map([...states.keys()].map((key, i4) => [key, settled[i4]]));
|
|
108522
108720
|
const positions = [];
|
|
108523
108721
|
let failed = false, failure;
|
|
@@ -108541,7 +108739,8 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108541
108739
|
if (!readBlock) continue;
|
|
108542
108740
|
const resolved = resolutions.get(key);
|
|
108543
108741
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
108544
|
-
const { blockState: blockState3, perBlock, fluid, prepared, stored } = resolved.value;
|
|
108742
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts, stored } = resolved.value;
|
|
108743
|
+
const context = contexts.get(index);
|
|
108545
108744
|
if (!blockState3) {
|
|
108546
108745
|
this.data.assign(index, 0);
|
|
108547
108746
|
continue;
|
|
@@ -108549,9 +108748,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108549
108748
|
const variantPosition = worldPos.toArray();
|
|
108550
108749
|
if (fluid) {
|
|
108551
108750
|
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
108751
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
108552
108752
|
this.meshDirty = true;
|
|
108553
108753
|
}
|
|
108554
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
108754
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
108555
108755
|
if (templates) {
|
|
108556
108756
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
108557
108757
|
this.meshDirty = true;
|
|
@@ -108561,7 +108761,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108561
108761
|
instanceMeshes: true,
|
|
108562
108762
|
maxInstanceCount: 2e3,
|
|
108563
108763
|
initialState: stored.properties,
|
|
108564
|
-
variantPosition
|
|
108764
|
+
variantPosition,
|
|
108765
|
+
biome: context?.biome,
|
|
108766
|
+
biomePosition: this.biomePosition(index, blockState3, stored)
|
|
108565
108767
|
});
|
|
108566
108768
|
object4.setPosition(MineRenderWorld.worldToScenePosition(worldPos));
|
|
108567
108769
|
}
|
|
@@ -108584,24 +108786,21 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108584
108786
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
108585
108787
|
this.sectionBlocks.clear();
|
|
108586
108788
|
this.fluidCells.fill(0);
|
|
108789
|
+
this.waterTints = void 0;
|
|
108587
108790
|
this.renderedBlocks.clear();
|
|
108588
108791
|
this.hiddenBlocks.clear();
|
|
108589
108792
|
this.meshDirty = true;
|
|
108590
108793
|
this.data.copyFrom(data);
|
|
108591
|
-
const ids = /* @__PURE__ */ new
|
|
108794
|
+
const ids = /* @__PURE__ */ new Map();
|
|
108592
108795
|
for (let index = 0; index < 4096; index++) {
|
|
108593
108796
|
const id = this.data.idAt(index);
|
|
108594
|
-
if (id)
|
|
108595
|
-
|
|
108596
|
-
|
|
108597
|
-
|
|
108598
|
-
|
|
108599
|
-
|
|
108600
|
-
|
|
108601
|
-
const fluid = await getBlockFluidState(blockState3?.key, state.properties);
|
|
108602
|
-
const prepared = perBlock || fluid?.renderModel === false ? void 0 : await this.sectionModels.prepareState(blockState3, state.properties);
|
|
108603
|
-
return { blockState: blockState3, perBlock, fluid, prepared };
|
|
108604
|
-
}));
|
|
108797
|
+
if (!id) continue;
|
|
108798
|
+
let indices = ids.get(id);
|
|
108799
|
+
if (!indices) ids.set(id, indices = []);
|
|
108800
|
+
indices.push(index);
|
|
108801
|
+
}
|
|
108802
|
+
const palette = [...ids.keys()], biomes = /* @__PURE__ */ new Map();
|
|
108803
|
+
const settled = await Promise.allSettled(palette.map((id) => this.resolveState(this.data.stateAt(id), ids.get(id), biomes)));
|
|
108605
108804
|
const resolutions = new Map(palette.map((id, i4) => [id, settled[i4]]));
|
|
108606
108805
|
const perBlocks = [];
|
|
108607
108806
|
let failed = false, failure;
|
|
@@ -108611,24 +108810,28 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108611
108810
|
try {
|
|
108612
108811
|
const resolved = resolutions.get(id);
|
|
108613
108812
|
if (resolved.status === "rejected") throw resolved.reason;
|
|
108614
|
-
const { blockState: blockState3, perBlock, fluid, prepared } = resolved.value;
|
|
108813
|
+
const { blockState: blockState3, perBlock, fluid, prepared, contexts } = resolved.value;
|
|
108814
|
+
const context = contexts.get(index);
|
|
108615
108815
|
if (!blockState3) {
|
|
108616
108816
|
this.data.assign(index, 0);
|
|
108617
108817
|
this.fluidCells[index] = 0;
|
|
108618
108818
|
continue;
|
|
108619
108819
|
}
|
|
108620
|
-
if (fluid)
|
|
108820
|
+
if (fluid) {
|
|
108821
|
+
this.fluidCells[index] = (fluid.kind === "water" ? 16 : 32) | Math.min(fluid.level, 8);
|
|
108822
|
+
if (fluid.kind === "water") this.setWaterTint(index, context?.waterTint);
|
|
108823
|
+
}
|
|
108621
108824
|
const variantPosition = [
|
|
108622
108825
|
this.x * 16 + index % 16,
|
|
108623
108826
|
this.y * 16 + Math.floor(index / 256),
|
|
108624
108827
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
108625
108828
|
];
|
|
108626
|
-
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : prepared?.pick(variantPosition);
|
|
108829
|
+
const templates = perBlock ? void 0 : fluid?.renderModel === false ? [] : (context?.prepared ?? prepared)?.pick(variantPosition);
|
|
108627
108830
|
if (templates) {
|
|
108628
108831
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0 })));
|
|
108629
108832
|
this.meshDirty = true;
|
|
108630
108833
|
} else {
|
|
108631
|
-
perBlocks.push({ index, blockState: blockState3 });
|
|
108834
|
+
perBlocks.push({ index, blockState: blockState3, biome: context?.biome });
|
|
108632
108835
|
}
|
|
108633
108836
|
const readBlock = this.data.snapshot(index);
|
|
108634
108837
|
this.renderedBlocks.set(index, { get block() {
|
|
@@ -108641,7 +108844,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108641
108844
|
failed = true;
|
|
108642
108845
|
}
|
|
108643
108846
|
}
|
|
108644
|
-
for (const { index, blockState: blockState3 } of perBlocks) {
|
|
108847
|
+
for (const { index, blockState: blockState3, biome } of perBlocks) {
|
|
108645
108848
|
let object4;
|
|
108646
108849
|
try {
|
|
108647
108850
|
object4 = await this.scene.addBlock(blockState3, {
|
|
@@ -108649,11 +108852,9 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108649
108852
|
instanceMeshes: true,
|
|
108650
108853
|
maxInstanceCount: 2e3,
|
|
108651
108854
|
initialState: this.data.stateAt(this.data.idAt(index)).properties,
|
|
108652
|
-
variantPosition:
|
|
108653
|
-
|
|
108654
|
-
|
|
108655
|
-
this.z * 16 + Math.floor(index / 16) % 16
|
|
108656
|
-
]
|
|
108855
|
+
variantPosition: this.positionAt(index),
|
|
108856
|
+
biome,
|
|
108857
|
+
biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
|
|
108657
108858
|
});
|
|
108658
108859
|
object4.setPosition(new Vector3(
|
|
108659
108860
|
this.x * 256 + index % 16 * 16,
|
|
@@ -108672,6 +108873,68 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108672
108873
|
}
|
|
108673
108874
|
if (failed) throw failure;
|
|
108674
108875
|
}
|
|
108876
|
+
positionAt(index) {
|
|
108877
|
+
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
108878
|
+
}
|
|
108879
|
+
biomePosition(index, blockState3, stored) {
|
|
108880
|
+
const position = this.positionAt(index), name2 = blockState3.key?.toNamespacedString();
|
|
108881
|
+
if (stored.properties?.half === "upper" && (name2 === "minecraft:tall_grass" || name2 === "minecraft:large_fern")) position[1]--;
|
|
108882
|
+
return position;
|
|
108883
|
+
}
|
|
108884
|
+
async resolveState(stored, indices, biomes) {
|
|
108885
|
+
const blockState3 = await BlockStates.get(AssetKey.parse("blockstates", stored.type));
|
|
108886
|
+
const perBlock = !blockState3 || !this.sectionModels || !!(blockState3.key && BlockEntities.entry(await BlockEntities.getIndex(blockState3.key.root), blockState3.key.toNamespacedString()));
|
|
108887
|
+
const fluid = await getBlockFluidState(blockState3?.key, stored.properties);
|
|
108888
|
+
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;
|
|
108889
|
+
const source = hasBiomes && blockState3 ? await BlockTints.biomeSource(blockState3.key) : void 0;
|
|
108890
|
+
const prepare = (color3) => perBlock || fluid?.renderModel === false ? void 0 : this.sectionModels.prepareState(blockState3, stored.properties, color3);
|
|
108891
|
+
const contexts = /* @__PURE__ */ new Map();
|
|
108892
|
+
const groups = /* @__PURE__ */ new Map();
|
|
108893
|
+
if (blockState3 && (source || fluid?.kind === "water")) {
|
|
108894
|
+
for (const index of indices) {
|
|
108895
|
+
const position = this.biomePosition(index, blockState3, stored);
|
|
108896
|
+
const biome = this.biomeAt ? this.biomeAt(...position) : position[1] >= this.y * 16 ? this.getBiomeAt(position) : void 0;
|
|
108897
|
+
if (!biome) continue;
|
|
108898
|
+
const key = JSON.stringify(source === "grass" ? [biome, position[0], position[2]] : [biome]);
|
|
108899
|
+
let group = groups.get(key);
|
|
108900
|
+
if (!group) groups.set(key, group = { biome, position, indices: [] });
|
|
108901
|
+
group.indices.push(index);
|
|
108902
|
+
}
|
|
108903
|
+
}
|
|
108904
|
+
const groupedCount = [...groups.values()].reduce((sum, group) => sum + group.indices.length, 0);
|
|
108905
|
+
const prepared = groupedCount < indices.length ? await prepare() : void 0;
|
|
108906
|
+
await Promise.all([...groups.values()].map(async ({ biome, position, indices: indices2 }) => {
|
|
108907
|
+
const available = () => {
|
|
108908
|
+
const key = JSON.stringify([biome, blockState3?.key?.root]);
|
|
108909
|
+
let found = biomes.get(key);
|
|
108910
|
+
if (!found) {
|
|
108911
|
+
found = Biomes.get(biome, blockState3?.key).then((value) => value !== void 0);
|
|
108912
|
+
biomes.set(key, found);
|
|
108913
|
+
}
|
|
108914
|
+
return found;
|
|
108915
|
+
};
|
|
108916
|
+
const context = { biome };
|
|
108917
|
+
if (perBlock) {
|
|
108918
|
+
if (!await available()) context.biome = void 0;
|
|
108919
|
+
} else {
|
|
108920
|
+
context.prepared = await prepare(async () => await available() ? BlockTints.getBiomeColor(blockState3?.key, biome, position) : void 0);
|
|
108921
|
+
if (fluid?.kind === "water" && await available()) {
|
|
108922
|
+
const color3 = await Biomes.getColor(biome, "water", blockState3?.key);
|
|
108923
|
+
if (color3 !== void 0 && color3 !== 4159204) context.waterTint = new Color(color3).toArray();
|
|
108924
|
+
}
|
|
108925
|
+
}
|
|
108926
|
+
for (const index of indices2) contexts.set(index, context);
|
|
108927
|
+
}));
|
|
108928
|
+
return { blockState: blockState3, perBlock, fluid, prepared, contexts, stored };
|
|
108929
|
+
}
|
|
108930
|
+
setWaterTint(index, tint) {
|
|
108931
|
+
if (!this.sectionModels || !this.waterTints && tint === void 0) return;
|
|
108932
|
+
if (!this.waterTints) {
|
|
108933
|
+
this.waterTints = new Float32Array(4096 * 3);
|
|
108934
|
+
for (let cell = 0; cell < 4096; cell++) this.waterTints.set(WATER_TINT2, cell * 3);
|
|
108935
|
+
}
|
|
108936
|
+
this.waterTints.set(tint ?? WATER_TINT2, index * 3);
|
|
108937
|
+
}
|
|
108675
108938
|
/** Changes visibility at world block coordinates while preserving the block's data. */
|
|
108676
108939
|
async setBlockVisibleAt(pos, visible) {
|
|
108677
108940
|
const index = _Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos));
|
|
@@ -108775,7 +109038,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108775
109038
|
if (block && !block.object) origins.set(kind, block.block.type);
|
|
108776
109039
|
}
|
|
108777
109040
|
if (origins.size) {
|
|
108778
|
-
fluids = { cells: new Uint8Array(18 * 18 * 18) };
|
|
109041
|
+
fluids = { cells: new Uint8Array(18 * 18 * 18), waterTints: this.waterTints?.slice() };
|
|
108779
109042
|
for (let y5 = -1; y5 <= 16; y5++) {
|
|
108780
109043
|
for (let z4 = -1; z4 <= 16; z4++) {
|
|
108781
109044
|
for (let x4 = -1; x4 <= 16; x4++) {
|
|
@@ -108817,8 +109080,13 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108817
109080
|
this.renderedBlocks.clear();
|
|
108818
109081
|
this.hiddenBlocks.clear();
|
|
108819
109082
|
this.fluidCells.fill(0);
|
|
109083
|
+
this.waterTints = void 0;
|
|
108820
109084
|
this.data.clear();
|
|
108821
|
-
|
|
109085
|
+
this.biomes = void 0;
|
|
109086
|
+
if (notify) {
|
|
109087
|
+
await this.onBiomesChanged?.(void 0);
|
|
109088
|
+
await this.onBlocksChanged?.(positions);
|
|
109089
|
+
}
|
|
108822
109090
|
}
|
|
108823
109091
|
async dispose() {
|
|
108824
109092
|
await this.clear();
|