minerender 2.1.0-beta.7 → 2.1.0-beta.8
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/README.md +10 -1
- package/dist/browser/esm/armor/Armor.mjs +84 -0
- package/dist/browser/esm/armor/Armor.mjs.map +1 -0
- package/dist/browser/esm/armor/index.mjs +3 -0
- package/dist/browser/esm/armor/index.mjs.map +1 -0
- package/dist/browser/esm/assets/BlockEntities.mjs +2 -0
- package/dist/browser/esm/assets/BlockEntities.mjs.map +1 -1
- package/dist/browser/esm/assets/Entities.mjs +39 -11
- package/dist/browser/esm/assets/Entities.mjs.map +1 -1
- package/dist/browser/esm/assets/MineRenderData.mjs +8 -17
- package/dist/browser/esm/assets/MineRenderData.mjs.map +1 -1
- package/dist/browser/esm/assets/ModelTextures.mjs +13 -7
- package/dist/browser/esm/assets/ModelTextures.mjs.map +1 -1
- package/dist/browser/esm/assets/_versions/DatasetVersions.mjs +22 -0
- package/dist/browser/esm/assets/_versions/DatasetVersions.mjs.map +1 -0
- package/dist/browser/esm/cache/Caching.mjs +8 -0
- package/dist/browser/esm/cache/Caching.mjs.map +1 -1
- package/dist/browser/esm/entity/scene/EntityObject.mjs +31 -5
- package/dist/browser/esm/entity/scene/EntityObject.mjs.map +1 -1
- package/dist/browser/esm/env/browser/BrowserEnv.mjs +11 -4
- package/dist/browser/esm/env/browser/BrowserEnv.mjs.map +1 -1
- package/dist/browser/esm/index.browser.d.mts +129 -13
- package/dist/browser/esm/index.browser.mjs.map +1 -1
- package/dist/browser/esm/index.mjs +1 -0
- package/dist/browser/esm/index.mjs.map +1 -1
- package/dist/browser/esm/model/ItemGlint.mjs +7 -6
- package/dist/browser/esm/model/ItemGlint.mjs.map +1 -1
- package/dist/browser/esm/model/block/scene/BlockObject.mjs +16 -5
- package/dist/browser/esm/model/block/scene/BlockObject.mjs.map +1 -1
- package/dist/browser/esm/scene/SceneDocument.mjs +35 -5
- package/dist/browser/esm/scene/SceneDocument.mjs.map +1 -1
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs +14 -3
- package/dist/browser/esm/scene/SceneDocumentLoader.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinGeometries.mjs +4 -1
- package/dist/browser/esm/skin/SkinGeometries.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinPart.mjs +2 -0
- package/dist/browser/esm/skin/SkinPart.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinTextureCoordinates.mjs +11 -1
- package/dist/browser/esm/skin/SkinTextureCoordinates.mjs.map +1 -1
- package/dist/browser/esm/skin/SkinTextures.mjs +1 -1
- package/dist/browser/esm/skin/SkinTextures.mjs.map +1 -1
- package/dist/browser/esm/skin/scene/SkinObject.mjs +119 -7
- package/dist/browser/esm/skin/scene/SkinObject.mjs.map +1 -1
- package/dist/browser/esm/texture/PalettedTextures.mjs +46 -0
- package/dist/browser/esm/texture/PalettedTextures.mjs.map +1 -0
- package/dist/browser/esm/texture/index.mjs +1 -0
- package/dist/browser/esm/texture/index.mjs.map +1 -1
- package/dist/browser/esm/util/util.mjs +0 -2
- package/dist/browser/esm/util/util.mjs.map +1 -1
- package/dist/browser/esm/world/Chunk.mjs +62 -33
- package/dist/browser/esm/world/Chunk.mjs.map +1 -1
- package/dist/browser/esm/world/MineRenderWorld.mjs +98 -13
- package/dist/browser/esm/world/MineRenderWorld.mjs.map +1 -1
- package/dist/browser/esm/world/SectionMesh.mjs +65 -9
- package/dist/browser/esm/world/SectionMesh.mjs.map +1 -1
- package/dist/browser/esm/world/SectionModels.mjs +21 -15
- package/dist/browser/esm/world/SectionModels.mjs.map +1 -1
- package/dist/browser/esm/world/SectionWorker.mjs +8 -2
- package/dist/browser/esm/world/SectionWorker.mjs.map +1 -1
- package/dist/browser/esm/world/WorldStreamer.mjs +109 -15
- package/dist/browser/esm/world/WorldStreamer.mjs.map +1 -1
- package/dist/browser/index.d.ts +129 -13
- package/dist/browser/index.js +1592 -894
- package/dist/browser/index.js.map +1 -1
- package/dist/bundle.js +1330 -619
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +117 -12
- package/dist/node/index.d.ts +117 -12
- package/dist/node/index.js +1505 -793
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +1303 -593
- package/dist/node/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/node/index.mjs
CHANGED
|
@@ -184,8 +184,6 @@ async function sleep(timeout) {
|
|
|
184
184
|
});
|
|
185
185
|
}
|
|
186
186
|
function yieldToEventLoop() {
|
|
187
|
-
const scheduler = globalThis.scheduler;
|
|
188
|
-
if (scheduler?.yield) return scheduler.yield();
|
|
189
187
|
return new Promise((resolve) => {
|
|
190
188
|
if (typeof MessageChannel !== "undefined") {
|
|
191
189
|
const channel = new MessageChannel();
|
|
@@ -242,6 +240,10 @@ var Caching;
|
|
|
242
240
|
var init_Caching = __esm({
|
|
243
241
|
"src/cache/Caching.ts"() {
|
|
244
242
|
Caching = class _Caching {
|
|
243
|
+
static {
|
|
244
|
+
/** Cached in place of a missing asset. The caches drop `undefined` results, which would request the asset again. */
|
|
245
|
+
this.MISSING = false;
|
|
246
|
+
}
|
|
245
247
|
static {
|
|
246
248
|
this._generation = 0;
|
|
247
249
|
}
|
|
@@ -309,6 +311,9 @@ var init_Caching = __esm({
|
|
|
309
311
|
static {
|
|
310
312
|
this.blockEntityIndexCache = _Caching.createAssetCache();
|
|
311
313
|
}
|
|
314
|
+
static {
|
|
315
|
+
this.entityDatasetVersionCache = _Caching.createAssetCache();
|
|
316
|
+
}
|
|
312
317
|
static {
|
|
313
318
|
this.unihexCache = _Caching.createAssetCache();
|
|
314
319
|
}
|
|
@@ -318,6 +323,12 @@ var init_Caching = __esm({
|
|
|
318
323
|
static {
|
|
319
324
|
this.bannerPatternCache = _Caching.createAssetCache();
|
|
320
325
|
}
|
|
326
|
+
static {
|
|
327
|
+
this.equipmentCache = _Caching.createAssetCache();
|
|
328
|
+
}
|
|
329
|
+
static {
|
|
330
|
+
this.trimCache = _Caching.createAssetCache();
|
|
331
|
+
}
|
|
321
332
|
static {
|
|
322
333
|
this.mineRenderDataCache = _Caching.createAssetCache();
|
|
323
334
|
}
|
|
@@ -353,9 +364,12 @@ var init_Caching = __esm({
|
|
|
353
364
|
this.entityTextureCache,
|
|
354
365
|
this.entityAnimationCache,
|
|
355
366
|
this.blockEntityIndexCache,
|
|
367
|
+
this.entityDatasetVersionCache,
|
|
356
368
|
this.fontCache,
|
|
357
369
|
this.unihexCache,
|
|
358
370
|
this.bannerPatternCache,
|
|
371
|
+
this.equipmentCache,
|
|
372
|
+
this.trimCache,
|
|
359
373
|
this.mineRenderDataCache,
|
|
360
374
|
this.usernameUuidCache,
|
|
361
375
|
this.biomeCache
|
|
@@ -2403,15 +2417,21 @@ var init_ModelTextures = __esm({
|
|
|
2403
2417
|
key.extension += ".mcmeta";
|
|
2404
2418
|
}
|
|
2405
2419
|
const keyStr = key.serialize();
|
|
2406
|
-
|
|
2407
|
-
return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), (k1) => {
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2420
|
+
const meta = await Caching.textureMetaCache.get(keyStr, (k) => {
|
|
2421
|
+
return this.PERSISTENT_META_CACHE.getOrLoad(AssetLoader.persistentKey(keyStr), async (k1) => {
|
|
2422
|
+
if (AssetLoader.persistentScope === "") {
|
|
2423
|
+
const path = key.getFullPath();
|
|
2424
|
+
const slash = path.lastIndexOf("/");
|
|
2425
|
+
const listKey = new AssetKey(key.namespace, `${path.slice(0, slash + 1)}_list`, "textures", void 0, "assets", ".json", key.root);
|
|
2426
|
+
const list2 = await Caching.listAssetCache.get(listKey.serialize(), () => AssetLoader.get(listKey, "list" /* LIST */)).catch(() => void 0);
|
|
2427
|
+
if (list2 && !list2.files.includes(`${path.slice(slash + 1)}${key.extension}`)) return Caching.MISSING;
|
|
2428
|
+
}
|
|
2429
|
+
const asset2 = await AssetLoader.get(key, "meta" /* META */);
|
|
2430
|
+
if (asset2) asset2.key = key;
|
|
2431
|
+
return asset2 ?? Caching.MISSING;
|
|
2413
2432
|
});
|
|
2414
2433
|
});
|
|
2434
|
+
return meta === Caching.MISSING ? void 0 : meta;
|
|
2415
2435
|
}
|
|
2416
2436
|
/** Clears persisted texture metadata. Use {@link Caching.clear} to discard in-memory textures and metadata. */
|
|
2417
2437
|
static async clearCache() {
|
|
@@ -3331,23 +3351,303 @@ var init_MinecraftCubeTexture = __esm({
|
|
|
3331
3351
|
}
|
|
3332
3352
|
});
|
|
3333
3353
|
|
|
3354
|
+
// src/assets/_versions/DatasetVersions.ts
|
|
3355
|
+
var parseRelease, compare2, nearestRelease;
|
|
3356
|
+
var init_DatasetVersions = __esm({
|
|
3357
|
+
"src/assets/_versions/DatasetVersions.ts"() {
|
|
3358
|
+
parseRelease = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
|
|
3359
|
+
compare2 = (left, right) => {
|
|
3360
|
+
for (let i = 0; i < 3; i++) {
|
|
3361
|
+
const difference = (left[i] ?? 0) - (right[i] ?? 0);
|
|
3362
|
+
if (difference) return difference;
|
|
3363
|
+
}
|
|
3364
|
+
return 0;
|
|
3365
|
+
};
|
|
3366
|
+
nearestRelease = (requestedVersion, published) => {
|
|
3367
|
+
const requested = parseRelease(requestedVersion);
|
|
3368
|
+
if (!requested) return void 0;
|
|
3369
|
+
const versions = published.map((name) => ({ name, number: parseRelease(name) })).filter((entry) => !!entry.number).sort((left, right) => compare2(left.number, right.number));
|
|
3370
|
+
const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
|
|
3371
|
+
const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare2(left.number, right.number))[0] ?? versions.filter((entry) => compare2(entry.number, requested) <= 0).pop() ?? versions[0];
|
|
3372
|
+
return selected?.name;
|
|
3373
|
+
};
|
|
3374
|
+
}
|
|
3375
|
+
});
|
|
3376
|
+
|
|
3377
|
+
// src/error/MineRenderError.ts
|
|
3378
|
+
var MineRenderError;
|
|
3379
|
+
var init_MineRenderError = __esm({
|
|
3380
|
+
"src/error/MineRenderError.ts"() {
|
|
3381
|
+
MineRenderError = class _MineRenderError extends Error {
|
|
3382
|
+
constructor(msg) {
|
|
3383
|
+
super(msg);
|
|
3384
|
+
Object.setPrototypeOf(this, _MineRenderError.prototype);
|
|
3385
|
+
}
|
|
3386
|
+
get name() {
|
|
3387
|
+
return "MineRenderError";
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
});
|
|
3392
|
+
|
|
3393
|
+
// src/assets/Entities.ts
|
|
3394
|
+
var Entities;
|
|
3395
|
+
var init_Entities = __esm({
|
|
3396
|
+
"src/assets/Entities.ts"() {
|
|
3397
|
+
init_AssetKey();
|
|
3398
|
+
init_DatasetVersions();
|
|
3399
|
+
init_AssetLoader();
|
|
3400
|
+
init_source();
|
|
3401
|
+
init_Caching();
|
|
3402
|
+
init_AssetDefaults();
|
|
3403
|
+
init_MineRenderError();
|
|
3404
|
+
init_ModelTextures();
|
|
3405
|
+
Entities = class {
|
|
3406
|
+
/**
|
|
3407
|
+
* Resolves `root` (default: the active version). Uses the exact dataset when published or when the
|
|
3408
|
+
* version is not a release; otherwise selects the nearest published release, like {@link MineRenderData.resolve}.
|
|
3409
|
+
* Textures keep the requested root.
|
|
3410
|
+
*/
|
|
3411
|
+
static async getDatasetRoot(root) {
|
|
3412
|
+
const requestRoot = (root ?? AssetLoader.ROOT).replace(/\/+$/, "");
|
|
3413
|
+
const requestedVersion = requestRoot.slice(requestRoot.lastIndexOf("/") + 1);
|
|
3414
|
+
const base = requestRoot.slice(0, requestRoot.lastIndexOf("/"));
|
|
3415
|
+
const selected = await Caching.entityDatasetVersionCache.get(root ?? `sources:${AssetLoader.ROOT}`, async () => {
|
|
3416
|
+
const key = new AssetKey("entity-models", "version", void 0, void 0, void 0, ".json", root);
|
|
3417
|
+
key.rootType = void 0;
|
|
3418
|
+
if (!parseRelease(requestedVersion) || await AssetLoader.get(key, "json" /* JSON */) !== void 0) return requestedVersion;
|
|
3419
|
+
const indexKey = new AssetKey("entity-models", "versions", void 0, void 0, void 0, ".json", base);
|
|
3420
|
+
indexKey.rootType = void 0;
|
|
3421
|
+
const index = await AssetLoader.get(indexKey, "json" /* JSON */);
|
|
3422
|
+
if (index === void 0) return requestedVersion;
|
|
3423
|
+
if (!index || typeof index !== "object" || Array.isArray(index) || !Array.isArray(index.versions) || !index.versions.every((entry) => entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.name === "string")) {
|
|
3424
|
+
throw new MineRenderError(`Invalid entity model version index at ${base}/entity-models/versions.json`);
|
|
3425
|
+
}
|
|
3426
|
+
return nearestRelease(requestedVersion, index.versions.map((entry) => entry.name)) ?? requestedVersion;
|
|
3427
|
+
});
|
|
3428
|
+
return selected === requestedVersion ? root : `${base}/${selected}`;
|
|
3429
|
+
}
|
|
3430
|
+
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
3431
|
+
static async getEntityList() {
|
|
3432
|
+
const root = await this.getDatasetRoot();
|
|
3433
|
+
const collect = async (path) => {
|
|
3434
|
+
const prefix2 = path ? `${path}/` : "";
|
|
3435
|
+
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json", root);
|
|
3436
|
+
const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
|
|
3437
|
+
if (!list2) return [];
|
|
3438
|
+
const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
|
|
3439
|
+
const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
|
|
3440
|
+
return [...files, ...children.flat()];
|
|
3441
|
+
};
|
|
3442
|
+
return collect("");
|
|
3443
|
+
}
|
|
3444
|
+
/** @internal */
|
|
3445
|
+
static async getModelFile(modelKey) {
|
|
3446
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3447
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
|
|
3448
|
+
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3449
|
+
}
|
|
3450
|
+
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
3451
|
+
static async getLayerList(modelKey) {
|
|
3452
|
+
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
3453
|
+
}
|
|
3454
|
+
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
3455
|
+
static async getPassList(modelKey) {
|
|
3456
|
+
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
3457
|
+
}
|
|
3458
|
+
/**
|
|
3459
|
+
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
3460
|
+
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
3461
|
+
*
|
|
3462
|
+
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
3463
|
+
* @param textureKey - Texture override for the first selected layer.
|
|
3464
|
+
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
3465
|
+
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
3466
|
+
*/
|
|
3467
|
+
static async getEntity(modelKey, textureKey, options) {
|
|
3468
|
+
const model = await this.getModelFile(modelKey);
|
|
3469
|
+
if (!model) return void 0;
|
|
3470
|
+
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
3471
|
+
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
3472
|
+
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
3473
|
+
draws.push(...passes);
|
|
3474
|
+
const names = [];
|
|
3475
|
+
const selected = draws.map((pass) => {
|
|
3476
|
+
const layer = model.layers[pass.layer];
|
|
3477
|
+
if (!layer) {
|
|
3478
|
+
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
3479
|
+
}
|
|
3480
|
+
let name = pass.layer;
|
|
3481
|
+
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
3482
|
+
names.push(name);
|
|
3483
|
+
return { name, layer, pass };
|
|
3484
|
+
});
|
|
3485
|
+
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
3486
|
+
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
3487
|
+
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
3488
|
+
let texture;
|
|
3489
|
+
if (override) {
|
|
3490
|
+
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
3491
|
+
texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
|
|
3492
|
+
} else if (textureLocation !== void 0) {
|
|
3493
|
+
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
3494
|
+
if (isAssetKey(modelKey)) texture.root = modelKey.root;
|
|
3495
|
+
} else {
|
|
3496
|
+
texture = await this.resolveTexture(modelKey);
|
|
3497
|
+
}
|
|
3498
|
+
const render = pass.render ?? layer.render;
|
|
3499
|
+
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
3500
|
+
})));
|
|
3501
|
+
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
|
|
3505
|
+
*/
|
|
3506
|
+
static async getAnimations(modelKey) {
|
|
3507
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3508
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", await this.getDatasetRoot(isAssetKey(modelKey) ? modelKey.root : void 0));
|
|
3509
|
+
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3510
|
+
return file?.animations;
|
|
3511
|
+
}
|
|
3512
|
+
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
3513
|
+
static async resolveTexture(modelKey) {
|
|
3514
|
+
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
3515
|
+
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
3516
|
+
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
|
|
3517
|
+
const texture = await Caching.entityTextureCache.get(key.serialize(), async () => {
|
|
3518
|
+
const name = path.split("/").pop();
|
|
3519
|
+
for (const candidate of [path, `${path}/${name}`]) {
|
|
3520
|
+
const texture3 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
|
|
3521
|
+
if (await ModelTextures.get(texture3)) return texture3;
|
|
3522
|
+
}
|
|
3523
|
+
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
3524
|
+
const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
|
|
3525
|
+
const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
3526
|
+
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
3527
|
+
if (!file) return Caching.MISSING;
|
|
3528
|
+
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
3529
|
+
const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
|
|
3530
|
+
const assets = variant?.assets;
|
|
3531
|
+
const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
|
|
3532
|
+
if (typeof textureId !== "string") return Caching.MISSING;
|
|
3533
|
+
const texture2 = AssetKey.parse("textures", textureId);
|
|
3534
|
+
texture2.root = root;
|
|
3535
|
+
return texture2;
|
|
3536
|
+
});
|
|
3537
|
+
return texture === Caching.MISSING ? void 0 : texture;
|
|
3538
|
+
}
|
|
3539
|
+
/** @deprecated Use getEntityList(); block entities share the entity dataset. */
|
|
3540
|
+
static getBlockList() {
|
|
3541
|
+
return this.getEntityList();
|
|
3542
|
+
}
|
|
3543
|
+
/** @deprecated Use getEntity(); block entities share the entity dataset. */
|
|
3544
|
+
static getBlock(modelKey, textureKey, options) {
|
|
3545
|
+
return this.getEntity(modelKey, textureKey, options);
|
|
3546
|
+
}
|
|
3547
|
+
};
|
|
3548
|
+
}
|
|
3549
|
+
});
|
|
3550
|
+
|
|
3551
|
+
// src/armor/Armor.ts
|
|
3552
|
+
var Armor_exports = {};
|
|
3553
|
+
__export(Armor_exports, {
|
|
3554
|
+
Armor: () => Armor
|
|
3555
|
+
});
|
|
3556
|
+
var ARMOR_TRANSFORM, Armor;
|
|
3557
|
+
var init_Armor = __esm({
|
|
3558
|
+
"src/armor/Armor.ts"() {
|
|
3559
|
+
init_AssetKey();
|
|
3560
|
+
init_AssetLoader();
|
|
3561
|
+
init_Entities();
|
|
3562
|
+
init_AssetParsers();
|
|
3563
|
+
init_Caching();
|
|
3564
|
+
init_MineRenderError();
|
|
3565
|
+
ARMOR_TRANSFORM = [
|
|
3566
|
+
{ rotate: [0, Math.PI, 0] },
|
|
3567
|
+
{ scale: [-1, -1, 1] },
|
|
3568
|
+
{ translate: [0, -24, 0] }
|
|
3569
|
+
];
|
|
3570
|
+
Armor = class {
|
|
3571
|
+
/** Loads 1.21.4+ armor in SkinObject's frame, or returns undefined when no layer draws. */
|
|
3572
|
+
static async getEntity(armor) {
|
|
3573
|
+
const model = await Entities.getModelFile(new BasicAssetKey("minecraft", "player"));
|
|
3574
|
+
const layers = {};
|
|
3575
|
+
const slots = { chest: "chestplate", legs: "leggings", feet: "boots", head: "helmet" };
|
|
3576
|
+
for (const slot of Object.keys(slots)) {
|
|
3577
|
+
const value = armor[slot];
|
|
3578
|
+
if (value === void 0) continue;
|
|
3579
|
+
const piece = typeof value === "string" ? { asset: value } : value;
|
|
3580
|
+
const name = slots[slot], geometry = model?.layers[name];
|
|
3581
|
+
if (!geometry) throw new MineRenderError(`Missing armor geometry ${name}; armor needs Minecraft 1.21.4 or later`);
|
|
3582
|
+
const id = this.identifier(piece.asset);
|
|
3583
|
+
const key = new AssetKey(id.namespace, id.path, "equipment", void 0, "assets", ".json");
|
|
3584
|
+
const equipment = await Caching.equipmentCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
3585
|
+
if (!equipment) throw new MineRenderError(`Missing equipment asset ${piece.asset}; armor takes equipment asset IDs such as minecraft:diamond and needs Minecraft 1.21.4 or later`);
|
|
3586
|
+
const layerType = slot === "legs" ? "humanoid_leggings" : "humanoid";
|
|
3587
|
+
const equipmentLayers = equipment.layers[layerType];
|
|
3588
|
+
if (!equipmentLayers?.length) continue;
|
|
3589
|
+
let count = 0;
|
|
3590
|
+
const add = (texture, settings) => {
|
|
3591
|
+
layers[++count === 1 ? name : `${name}#${count}`] = { key: texture, texture, layer: geometry, ...settings };
|
|
3592
|
+
};
|
|
3593
|
+
let glint = piece.glint;
|
|
3594
|
+
for (const layer of equipmentLayers) {
|
|
3595
|
+
let color2;
|
|
3596
|
+
if (layer.dyeable) {
|
|
3597
|
+
const undyed = layer.dyeable.color_when_undyed;
|
|
3598
|
+
color2 = piece.color || (Array.isArray(undyed) ? Math.floor(undyed[0] * 255) << 16 | Math.floor(undyed[1] * 255) << 8 | Math.floor(undyed[2] * 255) : undyed === void 0 ? void 0 : undyed & 16777215);
|
|
3599
|
+
if (color2 === void 0) continue;
|
|
3600
|
+
}
|
|
3601
|
+
const texture = this.identifier(layer.texture);
|
|
3602
|
+
add(
|
|
3603
|
+
new AssetKey(texture.namespace, `equipment/${layerType}/${texture.path}`, "textures", "entity", "assets", ".png"),
|
|
3604
|
+
{ ...color2 !== void 0 && { color: color2 }, ...glint && { glint: true } }
|
|
3605
|
+
);
|
|
3606
|
+
glint = false;
|
|
3607
|
+
}
|
|
3608
|
+
if (piece.trim) {
|
|
3609
|
+
const patternId = this.identifier(piece.trim.pattern), materialId = this.identifier(piece.trim.material);
|
|
3610
|
+
const patternKey = new AssetKey(patternId.namespace, patternId.path, "trim_pattern", void 0, "data", ".json");
|
|
3611
|
+
const materialKey = new AssetKey(materialId.namespace, materialId.path, "trim_material", void 0, "data", ".json");
|
|
3612
|
+
const pattern2 = await Caching.trimCache.get(patternKey.serialize(), () => AssetLoader.get(patternKey, "json" /* JSON */));
|
|
3613
|
+
if (!pattern2) throw new MineRenderError(`Missing trim pattern ${piece.trim.pattern}`);
|
|
3614
|
+
const material = await Caching.trimCache.get(materialKey.serialize(), () => AssetLoader.get(materialKey, "json" /* JSON */));
|
|
3615
|
+
if (!material) throw new MineRenderError(`Missing trim material ${piece.trim.material}`);
|
|
3616
|
+
const patternAsset = this.identifier(pattern2.asset_id);
|
|
3617
|
+
const suffix = material.override_armor_assets?.[id.toNamespacedString()] ?? material.asset_name;
|
|
3618
|
+
add(new AssetKey(patternAsset.namespace, `entity/${layerType}/${patternAsset.path}`, "textures", "trims", "assets", ".png"), {
|
|
3619
|
+
palette: {
|
|
3620
|
+
key: new AssetKey("minecraft", "color_palettes/trim_palette", "textures", "trims", "assets", ".png"),
|
|
3621
|
+
permutation: new AssetKey("minecraft", `color_palettes/${suffix}`, "textures", "trims", "assets", ".png")
|
|
3622
|
+
},
|
|
3623
|
+
render: pattern2.decal ? "cutout_z_offset" : "cutout"
|
|
3624
|
+
});
|
|
3625
|
+
}
|
|
3626
|
+
}
|
|
3627
|
+
const first = Object.values(layers)[0];
|
|
3628
|
+
return first ? { ...first, id: "minecraft:player", layers, transform: ARMOR_TRANSFORM } : void 0;
|
|
3629
|
+
}
|
|
3630
|
+
static identifier(value) {
|
|
3631
|
+
if (!isResourceLocation(value) || value.split(/[:/]/).some((part) => !part || part === "." || part === "..")) {
|
|
3632
|
+
throw new MineRenderError(`Invalid armor identifier ${value}`);
|
|
3633
|
+
}
|
|
3634
|
+
const [namespace, path] = value.includes(":") ? value.split(":") : ["minecraft", value];
|
|
3635
|
+
return new BasicAssetKey(namespace, path);
|
|
3636
|
+
}
|
|
3637
|
+
};
|
|
3638
|
+
}
|
|
3639
|
+
});
|
|
3640
|
+
|
|
3334
3641
|
// src/assets/MineRenderData.ts
|
|
3335
|
-
var object2,
|
|
3642
|
+
var object2, MineRenderData;
|
|
3336
3643
|
var init_MineRenderData = __esm({
|
|
3337
3644
|
"src/assets/MineRenderData.ts"() {
|
|
3645
|
+
init_DatasetVersions();
|
|
3338
3646
|
init_AssetKey();
|
|
3339
3647
|
init_AssetLoader();
|
|
3340
3648
|
init_AssetParsers();
|
|
3341
3649
|
init_Caching();
|
|
3342
3650
|
object2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
3343
|
-
release = (value) => /^\d+\.\d+(?:\.\d+)?$/.test(value) ? value.split(".").map(Number) : void 0;
|
|
3344
|
-
compare2 = (left, right) => {
|
|
3345
|
-
for (let i = 0; i < 3; i++) {
|
|
3346
|
-
const difference = (left[i] ?? 0) - (right[i] ?? 0);
|
|
3347
|
-
if (difference) return difference;
|
|
3348
|
-
}
|
|
3349
|
-
return 0;
|
|
3350
|
-
};
|
|
3351
3651
|
MineRenderData = class {
|
|
3352
3652
|
/** Loads one registry. Missing files and invalid data reject the request. */
|
|
3353
3653
|
static async get(dataset, root) {
|
|
@@ -3377,9 +3677,9 @@ var init_MineRenderData = __esm({
|
|
|
3377
3677
|
const scope = AssetLoader.persistentScope;
|
|
3378
3678
|
return this.cached(`resolve:${requestRoot === void 0 ? "sources" : "explicit"}:${root}`, scope, defaultRoot, async () => {
|
|
3379
3679
|
const requestedVersion = root.slice(root.lastIndexOf("/") + 1);
|
|
3380
|
-
let manifest = await this.manifest(root, requestRoot !== void 0 &&
|
|
3680
|
+
let manifest = await this.manifest(root, requestRoot !== void 0 && parseRelease(requestedVersion) ? requestedVersion : void 0, requestRoot);
|
|
3381
3681
|
if (manifest) return { requestedVersion, version: manifest.minecraftVersion, root, manifest };
|
|
3382
|
-
const requested =
|
|
3682
|
+
const requested = parseRelease(requestedVersion);
|
|
3383
3683
|
if (!requested) {
|
|
3384
3684
|
throw new Error(`No MineRender data is published for ${requestedVersion}; automatic fallback requires a release`);
|
|
3385
3685
|
}
|
|
@@ -3391,14 +3691,12 @@ var init_MineRenderData = __esm({
|
|
|
3391
3691
|
}
|
|
3392
3692
|
return value.versions;
|
|
3393
3693
|
});
|
|
3394
|
-
const
|
|
3395
|
-
const sameLine = versions.filter((entry) => entry.number[0] === requested[0] && entry.number[1] === requested[1]);
|
|
3396
|
-
const selected = sameLine.sort((left, right) => Math.abs((left.number[2] ?? 0) - (requested[2] ?? 0)) - Math.abs((right.number[2] ?? 0) - (requested[2] ?? 0)) || compare2(left.number, right.number))[0] ?? versions.filter((entry) => compare2(entry.number, requested) <= 0).pop() ?? versions[0];
|
|
3694
|
+
const selected = nearestRelease(requestedVersion, index.map((entry) => entry.name));
|
|
3397
3695
|
if (!selected) throw new Error(`No compatible MineRender data is published for ${requestedVersion}`);
|
|
3398
|
-
const resolvedRoot = `${base}/${selected
|
|
3399
|
-
manifest = await this.manifest(resolvedRoot, selected
|
|
3400
|
-
if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected
|
|
3401
|
-
return { requestedVersion, version: selected
|
|
3696
|
+
const resolvedRoot = `${base}/${selected}`;
|
|
3697
|
+
manifest = await this.manifest(resolvedRoot, selected, resolvedRoot);
|
|
3698
|
+
if (!manifest) throw new Error(`Missing MineRender manifest for published version ${selected}`);
|
|
3699
|
+
return { requestedVersion, version: selected, root: resolvedRoot, manifest };
|
|
3402
3700
|
});
|
|
3403
3701
|
}
|
|
3404
3702
|
static async manifest(root, expectedVersion, requestRoot) {
|
|
@@ -3730,22 +4028,6 @@ var init_ItemDefaults = __esm({
|
|
|
3730
4028
|
}
|
|
3731
4029
|
});
|
|
3732
4030
|
|
|
3733
|
-
// src/error/MineRenderError.ts
|
|
3734
|
-
var MineRenderError;
|
|
3735
|
-
var init_MineRenderError = __esm({
|
|
3736
|
-
"src/error/MineRenderError.ts"() {
|
|
3737
|
-
MineRenderError = class _MineRenderError extends Error {
|
|
3738
|
-
constructor(msg) {
|
|
3739
|
-
super(msg);
|
|
3740
|
-
Object.setPrototypeOf(this, _MineRenderError.prototype);
|
|
3741
|
-
}
|
|
3742
|
-
get name() {
|
|
3743
|
-
return "MineRenderError";
|
|
3744
|
-
}
|
|
3745
|
-
};
|
|
3746
|
-
}
|
|
3747
|
-
});
|
|
3748
|
-
|
|
3749
4031
|
// src/texture/Colormaps.ts
|
|
3750
4032
|
var Colormaps;
|
|
3751
4033
|
var init_Colormaps = __esm({
|
|
@@ -4526,6 +4808,7 @@ var log9, BlockEntities;
|
|
|
4526
4808
|
var init_BlockEntities = __esm({
|
|
4527
4809
|
"src/assets/BlockEntities.ts"() {
|
|
4528
4810
|
init_AssetKey();
|
|
4811
|
+
init_Entities();
|
|
4529
4812
|
init_AssetLoader();
|
|
4530
4813
|
init_source();
|
|
4531
4814
|
init_Caching();
|
|
@@ -4542,6 +4825,7 @@ var init_BlockEntities = __esm({
|
|
|
4542
4825
|
key.rootType = void 0;
|
|
4543
4826
|
const index = await Caching.blockEntityIndexCache.get(key.serialize(), async () => {
|
|
4544
4827
|
try {
|
|
4828
|
+
key.root = await Entities.getDatasetRoot(root);
|
|
4545
4829
|
return await AssetLoader.get(key, "json" /* JSON */) ?? {};
|
|
4546
4830
|
} catch (error) {
|
|
4547
4831
|
log9.warn("Could not load the block entity index; block entities are drawn as plain block models", error);
|
|
@@ -4627,136 +4911,6 @@ var init_DecoratedPots = __esm({
|
|
|
4627
4911
|
}
|
|
4628
4912
|
});
|
|
4629
4913
|
|
|
4630
|
-
// src/assets/Entities.ts
|
|
4631
|
-
var Entities;
|
|
4632
|
-
var init_Entities = __esm({
|
|
4633
|
-
"src/assets/Entities.ts"() {
|
|
4634
|
-
init_AssetKey();
|
|
4635
|
-
init_AssetLoader();
|
|
4636
|
-
init_source();
|
|
4637
|
-
init_Caching();
|
|
4638
|
-
init_AssetDefaults();
|
|
4639
|
-
init_MineRenderError();
|
|
4640
|
-
init_ModelTextures();
|
|
4641
|
-
Entities = class {
|
|
4642
|
-
/** Lists model paths in the `minecraft` namespace, including subdirectories and excluding `.json`. */
|
|
4643
|
-
static async getEntityList() {
|
|
4644
|
-
const collect = async (path) => {
|
|
4645
|
-
const prefix2 = path ? `${path}/` : "";
|
|
4646
|
-
const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
|
|
4647
|
-
const list2 = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
|
|
4648
|
-
if (!list2) return [];
|
|
4649
|
-
const files = list2.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
|
|
4650
|
-
const children = await Promise.all(list2.directories.map((directory) => collect(`${prefix2}${directory}`)));
|
|
4651
|
-
return [...files, ...children.flat()];
|
|
4652
|
-
};
|
|
4653
|
-
return collect("");
|
|
4654
|
-
}
|
|
4655
|
-
static async getModelFile(modelKey) {
|
|
4656
|
-
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
4657
|
-
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
4658
|
-
return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
4659
|
-
}
|
|
4660
|
-
/** Returns selectable geometry-layer names, or an empty list when the model is missing. */
|
|
4661
|
-
static async getLayerList(modelKey) {
|
|
4662
|
-
return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
|
|
4663
|
-
}
|
|
4664
|
-
/** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
|
|
4665
|
-
static async getPassList(modelKey) {
|
|
4666
|
-
return (await this.getModelFile(modelKey))?.passes ?? [];
|
|
4667
|
-
}
|
|
4668
|
-
/**
|
|
4669
|
-
* Loads the layers and textures to pass to {@link MineRenderScene.addEntity}.
|
|
4670
|
-
* By default, selects `main`, unconditional passes, and passes enabled by `options.when`.
|
|
4671
|
-
*
|
|
4672
|
-
* @param modelKey - Dataset model, such as `new BasicAssetKey("minecraft", "zombie")`.
|
|
4673
|
-
* @param textureKey - Texture override for the first selected layer.
|
|
4674
|
-
* @param options - Layer selection, conditional passes, and per-layer texture overrides.
|
|
4675
|
-
* @returns The selected model, or `undefined` when its dataset file is missing.
|
|
4676
|
-
*/
|
|
4677
|
-
static async getEntity(modelKey, textureKey, options) {
|
|
4678
|
-
const model = await this.getModelFile(modelKey);
|
|
4679
|
-
if (!model) return void 0;
|
|
4680
|
-
const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
|
|
4681
|
-
const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
|
|
4682
|
-
if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
|
|
4683
|
-
draws.push(...passes);
|
|
4684
|
-
const names = [];
|
|
4685
|
-
const selected = draws.map((pass) => {
|
|
4686
|
-
const layer = model.layers[pass.layer];
|
|
4687
|
-
if (!layer) {
|
|
4688
|
-
throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
|
|
4689
|
-
}
|
|
4690
|
-
let name = pass.layer;
|
|
4691
|
-
for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
|
|
4692
|
-
names.push(name);
|
|
4693
|
-
return { name, layer, pass };
|
|
4694
|
-
});
|
|
4695
|
-
const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
|
|
4696
|
-
const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
|
|
4697
|
-
const textureLocation = pass.textureLocation ?? layer.textureLocation;
|
|
4698
|
-
let texture;
|
|
4699
|
-
if (override) {
|
|
4700
|
-
const path = isAssetKey(override) ? override.getFullPath() : override.path;
|
|
4701
|
-
texture = isAssetKey(override) && override.assetType === "textures" && path.startsWith("entity/") ? override : new AssetKey(override.namespace, path, "textures", "entity", "assets", ".png", isAssetKey(override) ? override.root : void 0);
|
|
4702
|
-
} else if (textureLocation !== void 0) {
|
|
4703
|
-
texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
4704
|
-
if (isAssetKey(modelKey)) texture.root = modelKey.root;
|
|
4705
|
-
} else {
|
|
4706
|
-
texture = await this.resolveTexture(modelKey);
|
|
4707
|
-
}
|
|
4708
|
-
const render = pass.render ?? layer.render;
|
|
4709
|
-
return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
|
|
4710
|
-
})));
|
|
4711
|
-
return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
|
|
4712
|
-
}
|
|
4713
|
-
/**
|
|
4714
|
-
* Native and sampled vanilla clips by name, or undefined when the model or selected version has none.
|
|
4715
|
-
*/
|
|
4716
|
-
static async getAnimations(modelKey) {
|
|
4717
|
-
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
4718
|
-
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
|
|
4719
|
-
const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
|
|
4720
|
-
return file?.animations;
|
|
4721
|
-
}
|
|
4722
|
-
/** Finds a fallback texture using the model path, its directory, and vanilla variant data. */
|
|
4723
|
-
static async resolveTexture(modelKey) {
|
|
4724
|
-
const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
|
|
4725
|
-
const root = isAssetKey(modelKey) ? modelKey.root : void 0;
|
|
4726
|
-
const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
|
|
4727
|
-
return Caching.entityTextureCache.get(key.serialize(), async () => {
|
|
4728
|
-
const name = path.split("/").pop();
|
|
4729
|
-
for (const candidate of [path, `${path}/${name}`]) {
|
|
4730
|
-
const texture2 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
|
|
4731
|
-
if (await ModelTextures.get(texture2)) return texture2;
|
|
4732
|
-
}
|
|
4733
|
-
const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
|
|
4734
|
-
const list2 = await AssetLoader.get(listKey, "list" /* LIST */);
|
|
4735
|
-
const files = list2?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
|
|
4736
|
-
const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
|
|
4737
|
-
if (!file) return void 0;
|
|
4738
|
-
const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
|
|
4739
|
-
const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
|
|
4740
|
-
const assets = variant?.assets;
|
|
4741
|
-
const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
|
|
4742
|
-
if (typeof textureId !== "string") return void 0;
|
|
4743
|
-
const texture = AssetKey.parse("textures", textureId);
|
|
4744
|
-
texture.root = root;
|
|
4745
|
-
return texture;
|
|
4746
|
-
});
|
|
4747
|
-
}
|
|
4748
|
-
/** @deprecated Use getEntityList(); block entities share the entity dataset. */
|
|
4749
|
-
static getBlockList() {
|
|
4750
|
-
return this.getEntityList();
|
|
4751
|
-
}
|
|
4752
|
-
/** @deprecated Use getEntity(); block entities share the entity dataset. */
|
|
4753
|
-
static getBlock(modelKey, textureKey, options) {
|
|
4754
|
-
return this.getEntity(modelKey, textureKey, options);
|
|
4755
|
-
}
|
|
4756
|
-
};
|
|
4757
|
-
}
|
|
4758
|
-
});
|
|
4759
|
-
|
|
4760
4914
|
// src/assets/_fonts/Unihex.ts
|
|
4761
4915
|
var Unihex_exports = {};
|
|
4762
4916
|
__export(Unihex_exports, {
|
|
@@ -5896,6 +6050,266 @@ var init_model = __esm({
|
|
|
5896
6050
|
}
|
|
5897
6051
|
});
|
|
5898
6052
|
|
|
6053
|
+
// src/model/ItemGlint.ts
|
|
6054
|
+
var ItemGlint_exports = {};
|
|
6055
|
+
__export(ItemGlint_exports, {
|
|
6056
|
+
ItemGlint: () => ItemGlint
|
|
6057
|
+
});
|
|
6058
|
+
import { ClampToEdgeWrapping, CustomBlending as CustomBlending2, DoubleSide as DoubleSide2, EqualDepth, Float32BufferAttribute as Float32BufferAttribute3, LinearFilter, Mesh as Mesh4, OneFactor as OneFactor2, RepeatWrapping as RepeatWrapping2, ShaderMaterial as ShaderMaterial2, SrcColorFactor, Vector2 as Vector22, ZeroFactor } from "three";
|
|
6059
|
+
var ItemGlint;
|
|
6060
|
+
var init_ItemGlint = __esm({
|
|
6061
|
+
"src/model/ItemGlint.ts"() {
|
|
6062
|
+
init_AssetKey();
|
|
6063
|
+
init_Models();
|
|
6064
|
+
init_ModelTextures();
|
|
6065
|
+
init_Caching();
|
|
6066
|
+
init_Textures();
|
|
6067
|
+
init_Ticker();
|
|
6068
|
+
init_CubeFace();
|
|
6069
|
+
init_DisplayPosition();
|
|
6070
|
+
ItemGlint = class _ItemGlint {
|
|
6071
|
+
constructor(owner, material) {
|
|
6072
|
+
this.owner = owner;
|
|
6073
|
+
this.material = material;
|
|
6074
|
+
this.updateTime();
|
|
6075
|
+
}
|
|
6076
|
+
/** Enables glint for enchantments or a lodestone compass unless a boolean component overrides them. */
|
|
6077
|
+
static enabled(components = {}, itemId) {
|
|
6078
|
+
const override = Models.componentValue(components, "enchantment_glint_override");
|
|
6079
|
+
if (override !== void 0) {
|
|
6080
|
+
if (typeof override !== "boolean") throw new Error("Item enchantment_glint_override must be a boolean");
|
|
6081
|
+
return override;
|
|
6082
|
+
}
|
|
6083
|
+
if (itemId === "minecraft:compass") {
|
|
6084
|
+
Models.componentValue(components, "lodestone_tracker");
|
|
6085
|
+
if (Object.prototype.hasOwnProperty.call(components, "lodestone_tracker") || Object.prototype.hasOwnProperty.call(components, "minecraft:lodestone_tracker")) return true;
|
|
6086
|
+
}
|
|
6087
|
+
const enchantments = Models.componentValue(components, "enchantments");
|
|
6088
|
+
if (enchantments === void 0) return false;
|
|
6089
|
+
if (!enchantments || typeof enchantments !== "object" || Array.isArray(enchantments)) throw new Error("Item enchantments must be an object");
|
|
6090
|
+
return Object.keys(enchantments).length > 0;
|
|
6091
|
+
}
|
|
6092
|
+
/** @internal */
|
|
6093
|
+
static async create(owner, baseMap, root, entityMeshes, kind = "item") {
|
|
6094
|
+
const key = new AssetKey("minecraft", `enchanted_glint_${kind}`, "textures", "misc", "assets", ".png", root);
|
|
6095
|
+
const assetKey = key.serialize(), textureKey = `item-glint:${assetKey}`;
|
|
6096
|
+
let texture = Caching.textureCache.getIfPresent(textureKey);
|
|
6097
|
+
if (!texture) {
|
|
6098
|
+
const pending = ModelTextures.get(key);
|
|
6099
|
+
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKey);
|
|
6100
|
+
const [image, metadata] = await Promise.all([pending, ModelTextures.getMeta(key)]);
|
|
6101
|
+
if (!image) throw new Error(`Missing ${kind} glint texture ${key.toNamespacedString()}`);
|
|
6102
|
+
if (cachedAsset && Caching.textureAssetCache.getIfPresent(assetKey) !== cachedAsset) return this.create(owner, baseMap, root, entityMeshes, kind);
|
|
6103
|
+
texture = Caching.textureCache.get(textureKey, () => {
|
|
6104
|
+
const texture2 = Textures.createCanvasTexture(image.data.canvas);
|
|
6105
|
+
texture2.wrapS = texture2.wrapT = metadata?.texture?.clamp ? ClampToEdgeWrapping : RepeatWrapping2;
|
|
6106
|
+
if (metadata?.texture?.blur) texture2.magFilter = texture2.minFilter = LinearFilter;
|
|
6107
|
+
return texture2;
|
|
6108
|
+
});
|
|
6109
|
+
}
|
|
6110
|
+
const material = new ShaderMaterial2({
|
|
6111
|
+
name: "item-glint",
|
|
6112
|
+
transparent: true,
|
|
6113
|
+
depthWrite: false,
|
|
6114
|
+
depthFunc: EqualDepth,
|
|
6115
|
+
side: DoubleSide2,
|
|
6116
|
+
forceSinglePass: true,
|
|
6117
|
+
blending: CustomBlending2,
|
|
6118
|
+
blendSrc: SrcColorFactor,
|
|
6119
|
+
blendDst: OneFactor2,
|
|
6120
|
+
blendSrcAlpha: ZeroFactor,
|
|
6121
|
+
blendDstAlpha: OneFactor2,
|
|
6122
|
+
toneMapped: false,
|
|
6123
|
+
// TextureTransform.ARMOR_ENTITY_GLINT_TEXTURING uses a smaller UV scale than item glint.
|
|
6124
|
+
defines: entityMeshes ? { ENTITY_GLINT: true, ENTITY_GLINT_SCALE: kind === "armor" ? "0.16" : "0.5" } : {},
|
|
6125
|
+
uniforms: {
|
|
6126
|
+
...!entityMeshes && { baseMap: { value: baseMap } },
|
|
6127
|
+
glintMap: { value: texture },
|
|
6128
|
+
glintOffset: { value: new Vector22() },
|
|
6129
|
+
glintAlpha: { value: 0.75 }
|
|
6130
|
+
},
|
|
6131
|
+
vertexShader: `
|
|
6132
|
+
uniform vec2 glintOffset;
|
|
6133
|
+
#ifndef ENTITY_GLINT
|
|
6134
|
+
attribute vec4 uvBounds;
|
|
6135
|
+
attribute vec2 glintUv;
|
|
6136
|
+
flat out vec4 vUvBounds;
|
|
6137
|
+
centroid out vec2 vUv;
|
|
6138
|
+
#endif
|
|
6139
|
+
varying vec2 vGlintUv;
|
|
6140
|
+
void main() {
|
|
6141
|
+
#ifdef ENTITY_GLINT
|
|
6142
|
+
vec2 p = vec2(uv.x, 1.0 - uv.y) * ENTITY_GLINT_SCALE;
|
|
6143
|
+
#else
|
|
6144
|
+
vUv = uv;
|
|
6145
|
+
vUvBounds = uvBounds;
|
|
6146
|
+
vec2 p = glintUv * 8.0;
|
|
6147
|
+
#endif
|
|
6148
|
+
float angle = radians(10.0);
|
|
6149
|
+
vGlintUv = vec2(cos(angle) * p.x - sin(angle) * p.y, sin(angle) * p.x + cos(angle) * p.y) + glintOffset;
|
|
6150
|
+
vec4 mvPosition = vec4(position, 1.0);
|
|
6151
|
+
mvPosition = modelViewMatrix * mvPosition;
|
|
6152
|
+
gl_Position = projectionMatrix * mvPosition;
|
|
6153
|
+
}
|
|
6154
|
+
`,
|
|
6155
|
+
fragmentShader: `
|
|
6156
|
+
#ifndef ENTITY_GLINT
|
|
6157
|
+
uniform sampler2D baseMap;
|
|
6158
|
+
flat in vec4 vUvBounds;
|
|
6159
|
+
centroid in vec2 vUv;
|
|
6160
|
+
#endif
|
|
6161
|
+
uniform sampler2D glintMap;
|
|
6162
|
+
uniform float glintAlpha;
|
|
6163
|
+
varying vec2 vGlintUv;
|
|
6164
|
+
void main() {
|
|
6165
|
+
#ifndef ENTITY_GLINT
|
|
6166
|
+
vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);
|
|
6167
|
+
if (texture2D(baseMap, mapUv).a < 0.01) discard;
|
|
6168
|
+
#endif
|
|
6169
|
+
vec4 color = texture2D(glintMap, vec2(vGlintUv.x, 1.0 - vGlintUv.y));
|
|
6170
|
+
if (color.a < 0.1) discard;
|
|
6171
|
+
gl_FragColor = color;
|
|
6172
|
+
#include <colorspace_fragment>
|
|
6173
|
+
gl_FragColor.rgb *= glintAlpha;
|
|
6174
|
+
}
|
|
6175
|
+
`
|
|
6176
|
+
});
|
|
6177
|
+
if (!entityMeshes) Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
|
|
6178
|
+
const targets = entityMeshes ? [...entityMeshes] : [];
|
|
6179
|
+
if (!entityMeshes) owner.iterateAllMeshes((mesh) => targets.push({ mesh }));
|
|
6180
|
+
for (const { mesh: base, parent = base } of targets) {
|
|
6181
|
+
const pass = new Mesh4(base.geometry, material);
|
|
6182
|
+
pass.name = `${base.name}:glint`;
|
|
6183
|
+
pass.userData.minerenderItemGlint = true;
|
|
6184
|
+
pass.raycast = () => {
|
|
6185
|
+
};
|
|
6186
|
+
pass.renderOrder = parent.renderOrder + 0.5;
|
|
6187
|
+
parent.add(pass);
|
|
6188
|
+
}
|
|
6189
|
+
return new _ItemGlint(owner, material);
|
|
6190
|
+
}
|
|
6191
|
+
/**
|
|
6192
|
+
* Maps glint before model centering and display transforms. Ordinary sprites approximate Minecraft's shared atlas density.
|
|
6193
|
+
* @internal
|
|
6194
|
+
*/
|
|
6195
|
+
static mapUvs(geometry, faces, atlas, itemId, display) {
|
|
6196
|
+
const uv = geometry.getAttribute("uv");
|
|
6197
|
+
const mapped = new Float32Array(uv.count * 2);
|
|
6198
|
+
if (itemId === "minecraft:compass" || itemId === "minecraft:recovery_compass" || itemId === "minecraft:clock") {
|
|
6199
|
+
const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
|
|
6200
|
+
const scale = display === "gui" /* GUI */ ? 0.5 : display === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || display === "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */ ? 0.75 : 1;
|
|
6201
|
+
const factor = 1 / (16 * 128 * scale);
|
|
6202
|
+
for (let index = 0; index < positions.count; index++) {
|
|
6203
|
+
const x = positions.getX(index), y = positions.getY(index), z = positions.getZ(index);
|
|
6204
|
+
const nx = normals.getX(index), ny = normals.getY(index), nz = normals.getZ(index);
|
|
6205
|
+
const ax = Math.abs(nx), ay = Math.abs(ny), az = Math.abs(nz);
|
|
6206
|
+
let u, v;
|
|
6207
|
+
if (ay >= az && ay >= ax) {
|
|
6208
|
+
u = x;
|
|
6209
|
+
v = ny < 0 ? -z : z;
|
|
6210
|
+
} else if (az >= ax) {
|
|
6211
|
+
u = nz < 0 ? -x : x;
|
|
6212
|
+
v = -y;
|
|
6213
|
+
} else {
|
|
6214
|
+
u = nx < 0 ? -z : z;
|
|
6215
|
+
v = -y;
|
|
6216
|
+
}
|
|
6217
|
+
mapped[index * 2] = u * factor;
|
|
6218
|
+
mapped[index * 2 + 1] = v * factor;
|
|
6219
|
+
}
|
|
6220
|
+
geometry.setAttribute("glintUv", new Float32BufferAttribute3(mapped, 2));
|
|
6221
|
+
return;
|
|
6222
|
+
}
|
|
6223
|
+
for (const [faceIndex, face] of CUBE_FACES.entries()) {
|
|
6224
|
+
const texture = faces[face]?.texture?.substring(1);
|
|
6225
|
+
const position = texture && atlas.positions[texture] || [0, 0];
|
|
6226
|
+
const size = texture && atlas.sizes[texture] || [atlas.image.width, atlas.image.height];
|
|
6227
|
+
for (let corner = 0; corner < 4; corner++) {
|
|
6228
|
+
const index = faceIndex * 4 + corner;
|
|
6229
|
+
mapped[index * 2] = (uv.getX(index) * atlas.image.width - position[0]) / size[0] / 32;
|
|
6230
|
+
mapped[index * 2 + 1] = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] / 32;
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6233
|
+
geometry.setAttribute("glintUv", new Float32BufferAttribute3(mapped, 2));
|
|
6234
|
+
}
|
|
6235
|
+
updateTime() {
|
|
6236
|
+
const time = Math.trunc(Date.now() * 4);
|
|
6237
|
+
this.material.uniforms.glintOffset.value.set(-(time % 11e4) / 11e4, time % 3e4 / 3e4);
|
|
6238
|
+
}
|
|
6239
|
+
/** @internal */
|
|
6240
|
+
updateSubscription(active) {
|
|
6241
|
+
if (active && this.ticker === void 0) {
|
|
6242
|
+
this.updateTime();
|
|
6243
|
+
this.ticker = Ticker.add(() => {
|
|
6244
|
+
this.updateTime();
|
|
6245
|
+
this.owner.notifyDirty();
|
|
6246
|
+
});
|
|
6247
|
+
} else if (!active) {
|
|
6248
|
+
Ticker.remove(this.ticker);
|
|
6249
|
+
this.ticker = void 0;
|
|
6250
|
+
}
|
|
6251
|
+
}
|
|
6252
|
+
dispose() {
|
|
6253
|
+
Ticker.remove(this.ticker);
|
|
6254
|
+
this.ticker = void 0;
|
|
6255
|
+
this.material.dispose();
|
|
6256
|
+
}
|
|
6257
|
+
};
|
|
6258
|
+
}
|
|
6259
|
+
});
|
|
6260
|
+
|
|
6261
|
+
// src/texture/PalettedTextures.ts
|
|
6262
|
+
var PalettedTextures_exports = {};
|
|
6263
|
+
__export(PalettedTextures_exports, {
|
|
6264
|
+
PalettedTextures: () => PalettedTextures
|
|
6265
|
+
});
|
|
6266
|
+
var PalettedTextures;
|
|
6267
|
+
var init_PalettedTextures = __esm({
|
|
6268
|
+
"src/texture/PalettedTextures.ts"() {
|
|
6269
|
+
init_ModelTextures();
|
|
6270
|
+
init_Caching();
|
|
6271
|
+
init_CanvasImage();
|
|
6272
|
+
init_MineRenderError();
|
|
6273
|
+
PalettedTextures = class {
|
|
6274
|
+
/** Loads a texture with a palette permutation, sharing the resulting canvas between callers. */
|
|
6275
|
+
static async get(texture, key, permutation2) {
|
|
6276
|
+
return Caching.canvasImageDataCache.get(`palette:${texture.serialize()}:${key.serialize()}:${permutation2.serialize()}`, async () => {
|
|
6277
|
+
const source = await ModelTextures.get(texture);
|
|
6278
|
+
if (!source) return void 0;
|
|
6279
|
+
const [palette, replacement] = await Promise.all([ModelTextures.get(key), ModelTextures.get(permutation2)]);
|
|
6280
|
+
if (!palette) throw new MineRenderError(`Missing palette ${key.toNamespacedString()}`);
|
|
6281
|
+
if (!replacement) throw new MineRenderError(`Missing palette ${permutation2.toNamespacedString()}`);
|
|
6282
|
+
const pixels = source.data.getImageData(0, 0, source.width, source.height);
|
|
6283
|
+
const colors2 = palette.data.getImageData(0, 0, palette.width, palette.height).data;
|
|
6284
|
+
const replacements = replacement.data.getImageData(0, 0, replacement.width, replacement.height).data;
|
|
6285
|
+
const image = new CanvasImage(source.width, source.height);
|
|
6286
|
+
const output = image.context.createImageData(source.width, source.height);
|
|
6287
|
+
output.data.set(this.permute(pixels.data, colors2, replacements));
|
|
6288
|
+
image.putData(output);
|
|
6289
|
+
return { data: image.context, width: image.width, height: image.height };
|
|
6290
|
+
});
|
|
6291
|
+
}
|
|
6292
|
+
/** @internal */
|
|
6293
|
+
static permute(pixels, key, permutation2) {
|
|
6294
|
+
if (key.length !== permutation2.length) throw new MineRenderError("Palette images must have the same pixel count");
|
|
6295
|
+
const mapping = /* @__PURE__ */ new Map();
|
|
6296
|
+
for (let i = 0; i < key.length; i += 4) {
|
|
6297
|
+
if (key[i + 3] !== 0) mapping.set(key[i] << 16 | key[i + 1] << 8 | key[i + 2], i);
|
|
6298
|
+
}
|
|
6299
|
+
const output = new Uint8ClampedArray(pixels);
|
|
6300
|
+
for (let i = 0; i < pixels.length; i += 4) {
|
|
6301
|
+
if (pixels[i + 3] === 0) continue;
|
|
6302
|
+
const mapped = mapping.get(pixels[i] << 16 | pixels[i + 1] << 8 | pixels[i + 2]);
|
|
6303
|
+
if (mapped === void 0) continue;
|
|
6304
|
+
output.set(permutation2.subarray(mapped, mapped + 3), i);
|
|
6305
|
+
output[i + 3] = Math.floor(pixels[i + 3] * permutation2[mapped + 3] / 255);
|
|
6306
|
+
}
|
|
6307
|
+
return output;
|
|
6308
|
+
}
|
|
6309
|
+
};
|
|
6310
|
+
}
|
|
6311
|
+
});
|
|
6312
|
+
|
|
5899
6313
|
// src/entity/scene/EntityObject.ts
|
|
5900
6314
|
var EntityObject_exports = {};
|
|
5901
6315
|
__export(EntityObject_exports, {
|
|
@@ -5906,7 +6320,7 @@ import { Color as Color3, Object3D as Object3D3 } from "three";
|
|
|
5906
6320
|
function isEntityObject(obj) {
|
|
5907
6321
|
return obj.isEntityObject;
|
|
5908
6322
|
}
|
|
5909
|
-
var EntityObject;
|
|
6323
|
+
var ItemGlintClass, PalettedTexturesClass, EntityObject;
|
|
5910
6324
|
var init_EntityObject = __esm({
|
|
5911
6325
|
"src/entity/scene/EntityObject.ts"() {
|
|
5912
6326
|
init_SceneObject();
|
|
@@ -5936,8 +6350,14 @@ var init_EntityObject = __esm({
|
|
|
5936
6350
|
this.animationPlayers = [];
|
|
5937
6351
|
this.partPoses = /* @__PURE__ */ new Map();
|
|
5938
6352
|
this.options = (0, import_ts_deepmerge.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
|
|
5939
|
-
this.addEventListener("added", () =>
|
|
5940
|
-
|
|
6353
|
+
this.addEventListener("added", () => {
|
|
6354
|
+
this.updateScrollSubscription();
|
|
6355
|
+
this.glint?.updateSubscription(!!this.parent);
|
|
6356
|
+
});
|
|
6357
|
+
this.addEventListener("removed", () => {
|
|
6358
|
+
this.updateScrollSubscription();
|
|
6359
|
+
this.glint?.updateSubscription(!!this.parent);
|
|
6360
|
+
});
|
|
5941
6361
|
}
|
|
5942
6362
|
static {
|
|
5943
6363
|
this.DEFAULT_OPTIONS = (0, import_ts_deepmerge.default)({}, SceneObject.DEFAULT_OPTIONS);
|
|
@@ -5951,12 +6371,26 @@ var init_EntityObject = __esm({
|
|
|
5951
6371
|
mesh.material = material;
|
|
5952
6372
|
});
|
|
5953
6373
|
this.notifyDirty();
|
|
5954
|
-
} else
|
|
6374
|
+
} else {
|
|
6375
|
+
await this.applyTextures();
|
|
6376
|
+
const layers = Object.entries(this.entityLayers).filter(([, layer]) => layer.glint);
|
|
6377
|
+
const meshes = [];
|
|
6378
|
+
for (const [name] of layers) this.getLayerGroup(name)?.traverse((object4) => {
|
|
6379
|
+
if (isMesh(object4)) meshes.push(object4);
|
|
6380
|
+
});
|
|
6381
|
+
if (meshes.length) {
|
|
6382
|
+
const ItemGlint2 = ItemGlintClass ??= (await Promise.resolve().then(() => (init_ItemGlint(), ItemGlint_exports))).ItemGlint;
|
|
6383
|
+
this.glint = await ItemGlint2.create(this, void 0, this.getTextureKey(layers[0][1]).root, meshes.map((mesh) => ({ mesh })), "armor");
|
|
6384
|
+
this.glint.updateSubscription(!!this.parent);
|
|
6385
|
+
}
|
|
6386
|
+
}
|
|
5955
6387
|
}
|
|
5956
6388
|
dispose() {
|
|
5957
6389
|
super.dispose();
|
|
5958
6390
|
}
|
|
5959
6391
|
disposeAndRemoveAllChildren() {
|
|
6392
|
+
this.glint?.dispose();
|
|
6393
|
+
this.glint = void 0;
|
|
5960
6394
|
this.clearScrollMaterials();
|
|
5961
6395
|
for (const geometry of this.geometries) geometry.dispose();
|
|
5962
6396
|
this.geometries.clear();
|
|
@@ -6115,6 +6549,10 @@ var init_EntityObject = __esm({
|
|
|
6115
6549
|
);
|
|
6116
6550
|
}
|
|
6117
6551
|
async loadTextures(layer = this.entity) {
|
|
6552
|
+
if (layer.palette) {
|
|
6553
|
+
const PalettedTextures2 = PalettedTexturesClass ??= (await Promise.resolve().then(() => (init_PalettedTextures(), PalettedTextures_exports))).PalettedTextures;
|
|
6554
|
+
return PalettedTextures2.get(this.getTextureKey(layer), layer.palette.key, layer.palette.permutation);
|
|
6555
|
+
}
|
|
6118
6556
|
return ModelTextures.get(this.getTextureKey(layer));
|
|
6119
6557
|
}
|
|
6120
6558
|
createMeshes(force = false) {
|
|
@@ -6187,10 +6625,10 @@ var init_EntityObject = __esm({
|
|
|
6187
6625
|
this.clearScrollMaterials();
|
|
6188
6626
|
const results = await Promise.allSettled(Object.entries(this.entityLayers).map(async ([name, layer]) => {
|
|
6189
6627
|
const mode = layer.render ?? layer.layer.render ?? "cutout";
|
|
6190
|
-
const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
|
|
6628
|
+
const tint = (layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint]) ?? layer.color;
|
|
6191
6629
|
const scroll = Materials.entityModeScroll(mode);
|
|
6192
6630
|
const assetKeyStr = this.getTextureKey(layer).serialize();
|
|
6193
|
-
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}
|
|
6631
|
+
const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}` + (layer.palette ? `:${layer.palette.key.serialize()}:${layer.palette.permutation.serialize()}` : "");
|
|
6194
6632
|
let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
|
|
6195
6633
|
if (!mat) {
|
|
6196
6634
|
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
|
|
@@ -6228,13 +6666,13 @@ __export(GLTFExporter_exports, {
|
|
|
6228
6666
|
});
|
|
6229
6667
|
import {
|
|
6230
6668
|
BufferAttribute as BufferAttribute3,
|
|
6231
|
-
ClampToEdgeWrapping,
|
|
6669
|
+
ClampToEdgeWrapping as ClampToEdgeWrapping2,
|
|
6232
6670
|
Color as Color6,
|
|
6233
|
-
DoubleSide as
|
|
6671
|
+
DoubleSide as DoubleSide3,
|
|
6234
6672
|
InterpolateDiscrete,
|
|
6235
6673
|
InterpolateLinear,
|
|
6236
6674
|
NoColorSpace,
|
|
6237
|
-
LinearFilter,
|
|
6675
|
+
LinearFilter as LinearFilter2,
|
|
6238
6676
|
LinearMipmapLinearFilter,
|
|
6239
6677
|
LinearMipmapNearestFilter,
|
|
6240
6678
|
MathUtils,
|
|
@@ -6245,7 +6683,7 @@ import {
|
|
|
6245
6683
|
NearestMipmapNearestFilter,
|
|
6246
6684
|
PropertyBinding,
|
|
6247
6685
|
RGBAFormat as RGBAFormat2,
|
|
6248
|
-
RepeatWrapping as
|
|
6686
|
+
RepeatWrapping as RepeatWrapping3,
|
|
6249
6687
|
Scene as Scene2,
|
|
6250
6688
|
SRGBColorSpace as SRGBColorSpace5,
|
|
6251
6689
|
TextureSource,
|
|
@@ -6514,11 +6952,11 @@ var init_GLTFExporter = __esm({
|
|
|
6514
6952
|
THREE_TO_WEBGL[NearestFilter2] = WEBGL_CONSTANTS.NEAREST;
|
|
6515
6953
|
THREE_TO_WEBGL[NearestMipmapNearestFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_NEAREST;
|
|
6516
6954
|
THREE_TO_WEBGL[NearestMipmapLinearFilter] = WEBGL_CONSTANTS.NEAREST_MIPMAP_LINEAR;
|
|
6517
|
-
THREE_TO_WEBGL[
|
|
6955
|
+
THREE_TO_WEBGL[LinearFilter2] = WEBGL_CONSTANTS.LINEAR;
|
|
6518
6956
|
THREE_TO_WEBGL[LinearMipmapNearestFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_NEAREST;
|
|
6519
6957
|
THREE_TO_WEBGL[LinearMipmapLinearFilter] = WEBGL_CONSTANTS.LINEAR_MIPMAP_LINEAR;
|
|
6520
|
-
THREE_TO_WEBGL[
|
|
6521
|
-
THREE_TO_WEBGL[
|
|
6958
|
+
THREE_TO_WEBGL[ClampToEdgeWrapping2] = WEBGL_CONSTANTS.CLAMP_TO_EDGE;
|
|
6959
|
+
THREE_TO_WEBGL[RepeatWrapping3] = WEBGL_CONSTANTS.REPEAT;
|
|
6522
6960
|
THREE_TO_WEBGL[MirroredRepeatWrapping] = WEBGL_CONSTANTS.MIRRORED_REPEAT;
|
|
6523
6961
|
PATH_PROPERTIES = {
|
|
6524
6962
|
scale: "scale",
|
|
@@ -7268,7 +7706,7 @@ var init_GLTFExporter = __esm({
|
|
|
7268
7706
|
materialDef.alphaCutoff = material.alphaTest;
|
|
7269
7707
|
}
|
|
7270
7708
|
}
|
|
7271
|
-
if (material.side ===
|
|
7709
|
+
if (material.side === DoubleSide3) materialDef.doubleSided = true;
|
|
7272
7710
|
if (material.name !== "") materialDef.name = material.name;
|
|
7273
7711
|
this.serializeUserData(material, materialDef);
|
|
7274
7712
|
await this._invokeAllAsync(async function(ext) {
|
|
@@ -8337,7 +8775,7 @@ var init_GLTFExporter = __esm({
|
|
|
8337
8775
|
});
|
|
8338
8776
|
|
|
8339
8777
|
// src/gui/GuiText.ts
|
|
8340
|
-
import { BufferGeometry as BufferGeometry2, Color as Color8, Float32BufferAttribute as
|
|
8778
|
+
import { BufferGeometry as BufferGeometry2, Color as Color8, Float32BufferAttribute as Float32BufferAttribute5 } from "three";
|
|
8341
8779
|
async function layoutGuiText(text2, options = {}) {
|
|
8342
8780
|
const maxWidth = options.maxWidth ?? Infinity, lineHeight = options.lineHeight ?? 9;
|
|
8343
8781
|
if (!(maxWidth > 0) || !Number.isFinite(lineHeight) || lineHeight <= 0) {
|
|
@@ -8441,7 +8879,7 @@ function createGuiTextGeometry(layout, shadow = true) {
|
|
|
8441
8879
|
}
|
|
8442
8880
|
}
|
|
8443
8881
|
}
|
|
8444
|
-
return batches.map(({ image, positions, uvs, colors: colors2, indices }) => ({ image, geometry: new BufferGeometry2().setAttribute("position", new
|
|
8882
|
+
return batches.map(({ image, positions, uvs, colors: colors2, indices }) => ({ image, geometry: new BufferGeometry2().setAttribute("position", new Float32BufferAttribute5(positions, 3)).setAttribute("uv", new Float32BufferAttribute5(uvs, 2)).setAttribute("color", new Float32BufferAttribute5(colors2, 3)).setIndex(indices) }));
|
|
8445
8883
|
}
|
|
8446
8884
|
var init_GuiText = __esm({
|
|
8447
8885
|
"src/gui/GuiText.ts"() {
|
|
@@ -8450,7 +8888,7 @@ var init_GuiText = __esm({
|
|
|
8450
8888
|
});
|
|
8451
8889
|
|
|
8452
8890
|
// src/gui/GuiTextureGeometry.ts
|
|
8453
|
-
import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as
|
|
8891
|
+
import { BufferGeometry as BufferGeometry3, Float32BufferAttribute as Float32BufferAttribute6, PlaneGeometry } from "three";
|
|
8454
8892
|
function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop, scaling) {
|
|
8455
8893
|
if (crop || !scaling || scaling.type === "stretch") {
|
|
8456
8894
|
const [x, y, w, h] = crop ?? [0, 0, imageWidth, imageHeight];
|
|
@@ -8525,7 +8963,7 @@ function createGuiTextureGeometry(width, height, imageWidth, imageHeight, crop,
|
|
|
8525
8963
|
}
|
|
8526
8964
|
}
|
|
8527
8965
|
}
|
|
8528
|
-
return new BufferGeometry3().setAttribute("position", new
|
|
8966
|
+
return new BufferGeometry3().setAttribute("position", new Float32BufferAttribute6(positions, 3)).setAttribute("normal", new Float32BufferAttribute6(normals, 3)).setAttribute("uv", new Float32BufferAttribute6(uvs, 2)).setIndex(indices);
|
|
8529
8967
|
}
|
|
8530
8968
|
var init_GuiTextureGeometry = __esm({
|
|
8531
8969
|
"src/gui/GuiTextureGeometry.ts"() {
|
|
@@ -8536,7 +8974,7 @@ var init_GuiTextureGeometry = __esm({
|
|
|
8536
8974
|
import {
|
|
8537
8975
|
BufferAttribute as BufferAttribute4,
|
|
8538
8976
|
BufferGeometry as BufferGeometry4,
|
|
8539
|
-
Float32BufferAttribute as
|
|
8977
|
+
Float32BufferAttribute as Float32BufferAttribute7,
|
|
8540
8978
|
InterleavedBuffer,
|
|
8541
8979
|
InterleavedBufferAttribute,
|
|
8542
8980
|
TriangleFanDrawMode,
|
|
@@ -9064,8 +9502,8 @@ function computeMorphedAttributes(object4) {
|
|
|
9064
9502
|
}
|
|
9065
9503
|
}
|
|
9066
9504
|
}
|
|
9067
|
-
const morphedPositionAttribute = new
|
|
9068
|
-
const morphedNormalAttribute = new
|
|
9505
|
+
const morphedPositionAttribute = new Float32BufferAttribute7(modifiedPosition, 3);
|
|
9506
|
+
const morphedNormalAttribute = new Float32BufferAttribute7(modifiedNormal, 3);
|
|
9069
9507
|
return {
|
|
9070
9508
|
positionAttribute,
|
|
9071
9509
|
normalAttribute,
|
|
@@ -9352,7 +9790,7 @@ var init_SkinImage = __esm({
|
|
|
9352
9790
|
});
|
|
9353
9791
|
|
|
9354
9792
|
// src/skin/SkinTextures.ts
|
|
9355
|
-
import { DataTexture as DataTexture3, DoubleSide as
|
|
9793
|
+
import { DataTexture as DataTexture3, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial3, SRGBColorSpace as SRGBColorSpace6 } from "three";
|
|
9356
9794
|
var SkinTextures;
|
|
9357
9795
|
var init_SkinTextures = __esm({
|
|
9358
9796
|
"src/skin/SkinTextures.ts"() {
|
|
@@ -9397,7 +9835,7 @@ var init_SkinTextures = __esm({
|
|
|
9397
9835
|
texture.colorSpace = SRGBColorSpace6;
|
|
9398
9836
|
texture.flipY = true;
|
|
9399
9837
|
texture.needsUpdate = true;
|
|
9400
|
-
return new MeshBasicMaterial3({ map: texture, transparent, side: transparent ?
|
|
9838
|
+
return new MeshBasicMaterial3({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
|
|
9401
9839
|
}
|
|
9402
9840
|
static isSlim(image, scale) {
|
|
9403
9841
|
for (const [x, y] of [[46, 52], [54, 20]]) {
|
|
@@ -9450,7 +9888,7 @@ var init_SkinTextures = __esm({
|
|
|
9450
9888
|
return pixels;
|
|
9451
9889
|
}
|
|
9452
9890
|
static makeBaseOpaque(pixels, width, scale) {
|
|
9453
|
-
for (const [x0, y0, x1, y1] of [[0, 0, 32, 16], [0, 16, 64, 32], [16, 48, 48, 64]]) {
|
|
9891
|
+
for (const [x0, y0, x1, y1] of [[0, 0, 32, 16], [0, 16, 64, 32], [16, 48, 48, 64], [32, 0, 38, 7]]) {
|
|
9454
9892
|
for (let y = y0 * scale; y < y1 * scale; y++) {
|
|
9455
9893
|
for (let x = x0 * scale; x < x1 * scale; x++) pixels[(y * width + x) * 4 + 3] = 255;
|
|
9456
9894
|
}
|
|
@@ -9461,6 +9899,10 @@ var init_SkinTextures = __esm({
|
|
|
9461
9899
|
});
|
|
9462
9900
|
|
|
9463
9901
|
// src/skin/PlayerHeadTextures.ts
|
|
9902
|
+
var PlayerHeadTextures_exports = {};
|
|
9903
|
+
__export(PlayerHeadTextures_exports, {
|
|
9904
|
+
PlayerHeadTextures: () => PlayerHeadTextures
|
|
9905
|
+
});
|
|
9464
9906
|
var PlayerHeadTextures;
|
|
9465
9907
|
var init_PlayerHeadTextures = __esm({
|
|
9466
9908
|
"src/skin/PlayerHeadTextures.ts"() {
|
|
@@ -9779,274 +10221,71 @@ var init_SpecialItems = __esm({
|
|
|
9779
10221
|
load("bed_foot", key, new Matrix47().makeTranslation(0, 0, -16).multiply(transform))
|
|
9780
10222
|
]);
|
|
9781
10223
|
}
|
|
9782
|
-
case "minecraft:head":
|
|
9783
|
-
case "head": {
|
|
9784
|
-
const models = {
|
|
9785
|
-
skeleton: "skeleton_skull",
|
|
9786
|
-
wither_skeleton: "wither_skeleton_skull",
|
|
9787
|
-
zombie: "zombie_head",
|
|
9788
|
-
creeper: "creeper_head",
|
|
9789
|
-
dragon: "dragon_skull",
|
|
9790
|
-
piglin: "piglin_head"
|
|
9791
|
-
};
|
|
9792
|
-
const id = Object.prototype.hasOwnProperty.call(models, special.kind) ? models[special.kind] : void 0;
|
|
9793
|
-
if (!id) throw new Error(`Unsupported special item head kind ${special.kind}`);
|
|
9794
|
-
const animation = (special.animation ?? 0) * Math.PI * 0.2;
|
|
9795
|
-
const rotations = { head: [0, Math.PI, 0] };
|
|
9796
|
-
if (special.kind === "dragon") rotations.jaw = [(Math.sin(animation) + 1) * 0.2, 0, 0];
|
|
9797
|
-
if (special.kind === "piglin") {
|
|
9798
|
-
rotations.left_ear = [0, 0, -(Math.cos(animation * 1.2) + 2.5) * 0.2];
|
|
9799
|
-
rotations.right_ear = [0, 0, (Math.cos(animation) + 2.5) * 0.2];
|
|
9800
|
-
}
|
|
9801
|
-
return [await load(
|
|
9802
|
-
id,
|
|
9803
|
-
special.texture ? texture(special.texture, "") : void 0,
|
|
9804
|
-
new Matrix47().makeTranslation(8, 0, 8).multiply(new Matrix47().makeScale(-1, -1, 1)),
|
|
9805
|
-
rotations
|
|
9806
|
-
)];
|
|
9807
|
-
}
|
|
9808
|
-
}
|
|
9809
|
-
}
|
|
9810
|
-
/** An owned material with model-preview shading; its entity texture remains shared. */
|
|
9811
|
-
static createMaterial(source, shade) {
|
|
9812
|
-
const material = source.clone();
|
|
9813
|
-
if (shade) {
|
|
9814
|
-
material.onBeforeCompile = (shader) => {
|
|
9815
|
-
shader.vertexShader = `varying float itemLight;
|
|
9816
|
-
${shader.vertexShader}`.replace("#include <begin_vertex>", `
|
|
9817
|
-
#include <begin_vertex>
|
|
9818
|
-
vec3 N = inverseTransformDirection(normalMatrix * normal, viewMatrix);
|
|
9819
|
-
itemLight = (1.0 + N.y) * 0.25 - N.x * N.x * 0.15 + N.z * N.z * 0.05 + 0.5;
|
|
9820
|
-
`);
|
|
9821
|
-
shader.fragmentShader = `varying float itemLight;
|
|
9822
|
-
${shader.fragmentShader}`.replace(
|
|
9823
|
-
"#include <color_fragment>",
|
|
9824
|
-
"#include <color_fragment>\ndiffuseColor.rgb *= itemLight;"
|
|
9825
|
-
);
|
|
9826
|
-
};
|
|
9827
|
-
material.customProgramCacheKey = () => "special-item-side";
|
|
9828
|
-
}
|
|
9829
|
-
return material;
|
|
9830
|
-
}
|
|
9831
|
-
};
|
|
9832
|
-
}
|
|
9833
|
-
});
|
|
9834
|
-
|
|
9835
|
-
// src/model/GuiLight.ts
|
|
9836
|
-
var GuiLight;
|
|
9837
|
-
var init_GuiLight = __esm({
|
|
9838
|
-
"src/model/GuiLight.ts"() {
|
|
9839
|
-
GuiLight = /* @__PURE__ */ ((GuiLight2) => {
|
|
9840
|
-
GuiLight2["FRONT"] = "front";
|
|
9841
|
-
GuiLight2["SIDE"] = "side";
|
|
9842
|
-
return GuiLight2;
|
|
9843
|
-
})(GuiLight || {});
|
|
9844
|
-
}
|
|
9845
|
-
});
|
|
9846
|
-
|
|
9847
|
-
// src/model/ItemGlint.ts
|
|
9848
|
-
import { ClampToEdgeWrapping as ClampToEdgeWrapping3, CustomBlending as CustomBlending2, DoubleSide as DoubleSide4, EqualDepth, Float32BufferAttribute as Float32BufferAttribute7, LinearFilter as LinearFilter2, Mesh as Mesh5, OneFactor as OneFactor2, RepeatWrapping as RepeatWrapping3, ShaderMaterial as ShaderMaterial3, SrcColorFactor, Vector2 as Vector23, ZeroFactor } from "three";
|
|
9849
|
-
var ItemGlint;
|
|
9850
|
-
var init_ItemGlint = __esm({
|
|
9851
|
-
"src/model/ItemGlint.ts"() {
|
|
9852
|
-
init_AssetKey();
|
|
9853
|
-
init_Models();
|
|
9854
|
-
init_ModelTextures();
|
|
9855
|
-
init_Caching();
|
|
9856
|
-
init_Textures();
|
|
9857
|
-
init_Ticker();
|
|
9858
|
-
init_CubeFace();
|
|
9859
|
-
init_DisplayPosition();
|
|
9860
|
-
ItemGlint = class _ItemGlint {
|
|
9861
|
-
constructor(owner, material) {
|
|
9862
|
-
this.owner = owner;
|
|
9863
|
-
this.material = material;
|
|
9864
|
-
this.updateTime();
|
|
9865
|
-
}
|
|
9866
|
-
/** Enables glint for enchantments or a lodestone compass unless a boolean component overrides them. */
|
|
9867
|
-
static enabled(components = {}, itemId) {
|
|
9868
|
-
const override = Models.componentValue(components, "enchantment_glint_override");
|
|
9869
|
-
if (override !== void 0) {
|
|
9870
|
-
if (typeof override !== "boolean") throw new Error("Item enchantment_glint_override must be a boolean");
|
|
9871
|
-
return override;
|
|
9872
|
-
}
|
|
9873
|
-
if (itemId === "minecraft:compass") {
|
|
9874
|
-
Models.componentValue(components, "lodestone_tracker");
|
|
9875
|
-
if (Object.prototype.hasOwnProperty.call(components, "lodestone_tracker") || Object.prototype.hasOwnProperty.call(components, "minecraft:lodestone_tracker")) return true;
|
|
9876
|
-
}
|
|
9877
|
-
const enchantments = Models.componentValue(components, "enchantments");
|
|
9878
|
-
if (enchantments === void 0) return false;
|
|
9879
|
-
if (!enchantments || typeof enchantments !== "object" || Array.isArray(enchantments)) throw new Error("Item enchantments must be an object");
|
|
9880
|
-
return Object.keys(enchantments).length > 0;
|
|
9881
|
-
}
|
|
9882
|
-
/** @internal */
|
|
9883
|
-
static async create(owner, baseMap, root, entityMeshes) {
|
|
9884
|
-
const key = new AssetKey("minecraft", "enchanted_glint_item", "textures", "misc", "assets", ".png", root);
|
|
9885
|
-
const assetKey = key.serialize(), textureKey = `item-glint:${assetKey}`;
|
|
9886
|
-
let texture = Caching.textureCache.getIfPresent(textureKey);
|
|
9887
|
-
if (!texture) {
|
|
9888
|
-
const pending = ModelTextures.get(key);
|
|
9889
|
-
const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKey);
|
|
9890
|
-
const [image, metadata] = await Promise.all([pending, ModelTextures.getMeta(key)]);
|
|
9891
|
-
if (!image) throw new Error(`Missing item glint texture ${key.toNamespacedString()}`);
|
|
9892
|
-
if (cachedAsset && Caching.textureAssetCache.getIfPresent(assetKey) !== cachedAsset) return this.create(owner, baseMap, root, entityMeshes);
|
|
9893
|
-
texture = Caching.textureCache.get(textureKey, () => {
|
|
9894
|
-
const texture2 = Textures.createCanvasTexture(image.data.canvas);
|
|
9895
|
-
texture2.wrapS = texture2.wrapT = metadata?.texture?.clamp ? ClampToEdgeWrapping3 : RepeatWrapping3;
|
|
9896
|
-
if (metadata?.texture?.blur) texture2.magFilter = texture2.minFilter = LinearFilter2;
|
|
9897
|
-
return texture2;
|
|
9898
|
-
});
|
|
9899
|
-
}
|
|
9900
|
-
const material = new ShaderMaterial3({
|
|
9901
|
-
name: "item-glint",
|
|
9902
|
-
transparent: true,
|
|
9903
|
-
depthWrite: false,
|
|
9904
|
-
depthFunc: EqualDepth,
|
|
9905
|
-
side: DoubleSide4,
|
|
9906
|
-
forceSinglePass: true,
|
|
9907
|
-
blending: CustomBlending2,
|
|
9908
|
-
blendSrc: SrcColorFactor,
|
|
9909
|
-
blendDst: OneFactor2,
|
|
9910
|
-
blendSrcAlpha: ZeroFactor,
|
|
9911
|
-
blendDstAlpha: OneFactor2,
|
|
9912
|
-
toneMapped: false,
|
|
9913
|
-
defines: entityMeshes ? { ENTITY_GLINT: true } : {},
|
|
9914
|
-
uniforms: {
|
|
9915
|
-
...!entityMeshes && { baseMap: { value: baseMap } },
|
|
9916
|
-
glintMap: { value: texture },
|
|
9917
|
-
glintOffset: { value: new Vector23() },
|
|
9918
|
-
glintAlpha: { value: 0.75 }
|
|
9919
|
-
},
|
|
9920
|
-
vertexShader: `
|
|
9921
|
-
uniform vec2 glintOffset;
|
|
9922
|
-
#ifndef ENTITY_GLINT
|
|
9923
|
-
attribute vec4 uvBounds;
|
|
9924
|
-
attribute vec2 glintUv;
|
|
9925
|
-
flat out vec4 vUvBounds;
|
|
9926
|
-
centroid out vec2 vUv;
|
|
9927
|
-
#endif
|
|
9928
|
-
varying vec2 vGlintUv;
|
|
9929
|
-
void main() {
|
|
9930
|
-
#ifdef ENTITY_GLINT
|
|
9931
|
-
vec2 p = vec2(uv.x, 1.0 - uv.y) * 0.5;
|
|
9932
|
-
#else
|
|
9933
|
-
vUv = uv;
|
|
9934
|
-
vUvBounds = uvBounds;
|
|
9935
|
-
vec2 p = glintUv * 8.0;
|
|
9936
|
-
#endif
|
|
9937
|
-
float angle = radians(10.0);
|
|
9938
|
-
vGlintUv = vec2(cos(angle) * p.x - sin(angle) * p.y, sin(angle) * p.x + cos(angle) * p.y) + glintOffset;
|
|
9939
|
-
vec4 mvPosition = vec4(position, 1.0);
|
|
9940
|
-
mvPosition = modelViewMatrix * mvPosition;
|
|
9941
|
-
gl_Position = projectionMatrix * mvPosition;
|
|
9942
|
-
}
|
|
9943
|
-
`,
|
|
9944
|
-
fragmentShader: `
|
|
9945
|
-
#ifndef ENTITY_GLINT
|
|
9946
|
-
uniform sampler2D baseMap;
|
|
9947
|
-
flat in vec4 vUvBounds;
|
|
9948
|
-
centroid in vec2 vUv;
|
|
9949
|
-
#endif
|
|
9950
|
-
uniform sampler2D glintMap;
|
|
9951
|
-
uniform float glintAlpha;
|
|
9952
|
-
varying vec2 vGlintUv;
|
|
9953
|
-
void main() {
|
|
9954
|
-
#ifndef ENTITY_GLINT
|
|
9955
|
-
vec2 mapUv = clamp(vUv, vUvBounds.xy, vUvBounds.zw);
|
|
9956
|
-
if (texture2D(baseMap, mapUv).a < 0.01) discard;
|
|
9957
|
-
#endif
|
|
9958
|
-
vec4 color = texture2D(glintMap, vec2(vGlintUv.x, 1.0 - vGlintUv.y));
|
|
9959
|
-
if (color.a < 0.1) discard;
|
|
9960
|
-
gl_FragColor = color;
|
|
9961
|
-
#include <colorspace_fragment>
|
|
9962
|
-
gl_FragColor.rgb *= glintAlpha;
|
|
9963
|
-
}
|
|
9964
|
-
`
|
|
9965
|
-
});
|
|
9966
|
-
if (!entityMeshes) Object.assign(material.defaultAttributeValues, { uvBounds: [0, 0, 1, 1] });
|
|
9967
|
-
const targets = entityMeshes ? [...entityMeshes] : [];
|
|
9968
|
-
if (!entityMeshes) owner.iterateAllMeshes((mesh) => targets.push({ mesh }));
|
|
9969
|
-
for (const { mesh: base, parent = base } of targets) {
|
|
9970
|
-
const pass = new Mesh5(base.geometry, material);
|
|
9971
|
-
pass.name = `${base.name}:glint`;
|
|
9972
|
-
pass.userData.minerenderItemGlint = true;
|
|
9973
|
-
pass.raycast = () => {
|
|
9974
|
-
};
|
|
9975
|
-
pass.renderOrder = parent.renderOrder + 0.5;
|
|
9976
|
-
parent.add(pass);
|
|
9977
|
-
}
|
|
9978
|
-
return new _ItemGlint(owner, material);
|
|
9979
|
-
}
|
|
9980
|
-
/**
|
|
9981
|
-
* Maps glint before model centering and display transforms. Ordinary sprites approximate Minecraft's shared atlas density.
|
|
9982
|
-
* @internal
|
|
9983
|
-
*/
|
|
9984
|
-
static mapUvs(geometry, faces, atlas, itemId, display) {
|
|
9985
|
-
const uv = geometry.getAttribute("uv");
|
|
9986
|
-
const mapped = new Float32Array(uv.count * 2);
|
|
9987
|
-
if (itemId === "minecraft:compass" || itemId === "minecraft:recovery_compass" || itemId === "minecraft:clock") {
|
|
9988
|
-
const positions = geometry.getAttribute("position"), normals = geometry.getAttribute("normal");
|
|
9989
|
-
const scale = display === "gui" /* GUI */ ? 0.5 : display === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || display === "firstperson_righthand" /* FIRSTPERSON_RIGHTHAND */ ? 0.75 : 1;
|
|
9990
|
-
const factor = 1 / (16 * 128 * scale);
|
|
9991
|
-
for (let index = 0; index < positions.count; index++) {
|
|
9992
|
-
const x = positions.getX(index), y = positions.getY(index), z = positions.getZ(index);
|
|
9993
|
-
const nx = normals.getX(index), ny = normals.getY(index), nz = normals.getZ(index);
|
|
9994
|
-
const ax = Math.abs(nx), ay = Math.abs(ny), az = Math.abs(nz);
|
|
9995
|
-
let u, v;
|
|
9996
|
-
if (ay >= az && ay >= ax) {
|
|
9997
|
-
u = x;
|
|
9998
|
-
v = ny < 0 ? -z : z;
|
|
9999
|
-
} else if (az >= ax) {
|
|
10000
|
-
u = nz < 0 ? -x : x;
|
|
10001
|
-
v = -y;
|
|
10002
|
-
} else {
|
|
10003
|
-
u = nx < 0 ? -z : z;
|
|
10004
|
-
v = -y;
|
|
10005
|
-
}
|
|
10006
|
-
mapped[index * 2] = u * factor;
|
|
10007
|
-
mapped[index * 2 + 1] = v * factor;
|
|
10008
|
-
}
|
|
10009
|
-
geometry.setAttribute("glintUv", new Float32BufferAttribute7(mapped, 2));
|
|
10010
|
-
return;
|
|
10011
|
-
}
|
|
10012
|
-
for (const [faceIndex, face] of CUBE_FACES.entries()) {
|
|
10013
|
-
const texture = faces[face]?.texture?.substring(1);
|
|
10014
|
-
const position = texture && atlas.positions[texture] || [0, 0];
|
|
10015
|
-
const size = texture && atlas.sizes[texture] || [atlas.image.width, atlas.image.height];
|
|
10016
|
-
for (let corner = 0; corner < 4; corner++) {
|
|
10017
|
-
const index = faceIndex * 4 + corner;
|
|
10018
|
-
mapped[index * 2] = (uv.getX(index) * atlas.image.width - position[0]) / size[0] / 32;
|
|
10019
|
-
mapped[index * 2 + 1] = ((1 - uv.getY(index)) * atlas.image.height - position[1]) / size[1] / 32;
|
|
10224
|
+
case "minecraft:head":
|
|
10225
|
+
case "head": {
|
|
10226
|
+
const models = {
|
|
10227
|
+
skeleton: "skeleton_skull",
|
|
10228
|
+
wither_skeleton: "wither_skeleton_skull",
|
|
10229
|
+
zombie: "zombie_head",
|
|
10230
|
+
creeper: "creeper_head",
|
|
10231
|
+
dragon: "dragon_skull",
|
|
10232
|
+
piglin: "piglin_head"
|
|
10233
|
+
};
|
|
10234
|
+
const id = Object.prototype.hasOwnProperty.call(models, special.kind) ? models[special.kind] : void 0;
|
|
10235
|
+
if (!id) throw new Error(`Unsupported special item head kind ${special.kind}`);
|
|
10236
|
+
const animation = (special.animation ?? 0) * Math.PI * 0.2;
|
|
10237
|
+
const rotations = { head: [0, Math.PI, 0] };
|
|
10238
|
+
if (special.kind === "dragon") rotations.jaw = [(Math.sin(animation) + 1) * 0.2, 0, 0];
|
|
10239
|
+
if (special.kind === "piglin") {
|
|
10240
|
+
rotations.left_ear = [0, 0, -(Math.cos(animation * 1.2) + 2.5) * 0.2];
|
|
10241
|
+
rotations.right_ear = [0, 0, (Math.cos(animation) + 2.5) * 0.2];
|
|
10242
|
+
}
|
|
10243
|
+
return [await load(
|
|
10244
|
+
id,
|
|
10245
|
+
special.texture ? texture(special.texture, "") : void 0,
|
|
10246
|
+
new Matrix47().makeTranslation(8, 0, 8).multiply(new Matrix47().makeScale(-1, -1, 1)),
|
|
10247
|
+
rotations
|
|
10248
|
+
)];
|
|
10020
10249
|
}
|
|
10021
10250
|
}
|
|
10022
|
-
geometry.setAttribute("glintUv", new Float32BufferAttribute7(mapped, 2));
|
|
10023
|
-
}
|
|
10024
|
-
updateTime() {
|
|
10025
|
-
const time = Math.trunc(Date.now() * 4);
|
|
10026
|
-
this.material.uniforms.glintOffset.value.set(-(time % 11e4) / 11e4, time % 3e4 / 3e4);
|
|
10027
10251
|
}
|
|
10028
|
-
/**
|
|
10029
|
-
|
|
10030
|
-
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10252
|
+
/** An owned material with model-preview shading; its entity texture remains shared. */
|
|
10253
|
+
static createMaterial(source, shade) {
|
|
10254
|
+
const material = source.clone();
|
|
10255
|
+
if (shade) {
|
|
10256
|
+
material.onBeforeCompile = (shader) => {
|
|
10257
|
+
shader.vertexShader = `varying float itemLight;
|
|
10258
|
+
${shader.vertexShader}`.replace("#include <begin_vertex>", `
|
|
10259
|
+
#include <begin_vertex>
|
|
10260
|
+
vec3 N = inverseTransformDirection(normalMatrix * normal, viewMatrix);
|
|
10261
|
+
itemLight = (1.0 + N.y) * 0.25 - N.x * N.x * 0.15 + N.z * N.z * 0.05 + 0.5;
|
|
10262
|
+
`);
|
|
10263
|
+
shader.fragmentShader = `varying float itemLight;
|
|
10264
|
+
${shader.fragmentShader}`.replace(
|
|
10265
|
+
"#include <color_fragment>",
|
|
10266
|
+
"#include <color_fragment>\ndiffuseColor.rgb *= itemLight;"
|
|
10267
|
+
);
|
|
10268
|
+
};
|
|
10269
|
+
material.customProgramCacheKey = () => "special-item-side";
|
|
10039
10270
|
}
|
|
10040
|
-
|
|
10041
|
-
dispose() {
|
|
10042
|
-
Ticker.remove(this.ticker);
|
|
10043
|
-
this.ticker = void 0;
|
|
10044
|
-
this.material.dispose();
|
|
10271
|
+
return material;
|
|
10045
10272
|
}
|
|
10046
10273
|
};
|
|
10047
10274
|
}
|
|
10048
10275
|
});
|
|
10049
10276
|
|
|
10277
|
+
// src/model/GuiLight.ts
|
|
10278
|
+
var GuiLight;
|
|
10279
|
+
var init_GuiLight = __esm({
|
|
10280
|
+
"src/model/GuiLight.ts"() {
|
|
10281
|
+
GuiLight = /* @__PURE__ */ ((GuiLight2) => {
|
|
10282
|
+
GuiLight2["FRONT"] = "front";
|
|
10283
|
+
GuiLight2["SIDE"] = "side";
|
|
10284
|
+
return GuiLight2;
|
|
10285
|
+
})(GuiLight || {});
|
|
10286
|
+
}
|
|
10287
|
+
});
|
|
10288
|
+
|
|
10050
10289
|
// src/model/scene/ModelObject.ts
|
|
10051
10290
|
var ModelObject_exports = {};
|
|
10052
10291
|
__export(ModelObject_exports, {
|
|
@@ -11191,17 +11430,25 @@ var init_BlockObject = __esm({
|
|
|
11191
11430
|
if (!key || this.options.displayPosition) return false;
|
|
11192
11431
|
const generation = this._entityGeneration;
|
|
11193
11432
|
const created = [];
|
|
11433
|
+
const placement = new Matrix410();
|
|
11194
11434
|
let resolved;
|
|
11195
11435
|
try {
|
|
11196
11436
|
resolved = BlockEntities.resolve(await BlockEntities.getIndex(key.root), key.toNamespacedString(), this.state);
|
|
11197
11437
|
if (!resolved) return false;
|
|
11438
|
+
BlockEntities.matrix(resolved, placement);
|
|
11198
11439
|
for (const part of resolved.parts) {
|
|
11199
11440
|
const [namespace, path] = part.model.includes(":") ? part.model.split(":") : [key.namespace, part.model];
|
|
11200
|
-
|
|
11441
|
+
let texture = part.textureLocation === void 0 ? void 0 : AssetKey.parse("textures", part.textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
|
|
11442
|
+
if (part.textureLocation === void 0 && namespace === "minecraft" && path === "player_head") {
|
|
11443
|
+
const { PlayerHeadTextures: PlayerHeadTextures2 } = await Promise.resolve().then(() => (init_PlayerHeadTextures(), PlayerHeadTextures_exports));
|
|
11444
|
+
texture = (await PlayerHeadTextures2.get(void 0, key.root)).texture;
|
|
11445
|
+
}
|
|
11201
11446
|
if (texture) texture.root = key.root;
|
|
11202
11447
|
const entity = await Entities.getEntity(new BasicAssetKey(namespace, path), texture, { layer: part.layer });
|
|
11203
11448
|
if (!entity) throw new MineRenderError(`Missing entity model ${part.model}`);
|
|
11204
|
-
|
|
11449
|
+
const object4 = await this.scene.addEntity(entity, { wireframe: this.options.wireframe });
|
|
11450
|
+
this.placeEntity(object4, placement);
|
|
11451
|
+
created.push(object4);
|
|
11205
11452
|
}
|
|
11206
11453
|
} catch (error) {
|
|
11207
11454
|
log15.warn(`Could not draw block entity ${key.toNamespacedString()}, using its block model`, error);
|
|
@@ -11212,18 +11459,21 @@ var init_BlockObject = __esm({
|
|
|
11212
11459
|
this.removeEntities(created);
|
|
11213
11460
|
return true;
|
|
11214
11461
|
}
|
|
11215
|
-
|
|
11462
|
+
this._entityPlacement.copy(placement);
|
|
11216
11463
|
this._entities = created;
|
|
11217
11464
|
this.placeEntities();
|
|
11218
11465
|
this.setVisible(this.visible);
|
|
11219
11466
|
return true;
|
|
11220
11467
|
}
|
|
11221
11468
|
placeEntities() {
|
|
11222
|
-
const matrix = new Matrix410().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
|
|
11223
11469
|
for (const entity of this._entities) {
|
|
11224
|
-
|
|
11470
|
+
this.placeEntity(entity, this._entityPlacement);
|
|
11225
11471
|
}
|
|
11226
11472
|
}
|
|
11473
|
+
placeEntity(entity, placement) {
|
|
11474
|
+
const matrix = new Matrix410().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(placement);
|
|
11475
|
+
matrix.decompose(entity.position, entity.quaternion, entity.scale);
|
|
11476
|
+
}
|
|
11227
11477
|
get isOccluding() {
|
|
11228
11478
|
if (!this.visible) {
|
|
11229
11479
|
return false;
|
|
@@ -11517,6 +11767,7 @@ init_PersistentCache();
|
|
|
11517
11767
|
var NodeCache = class extends PersistentCache {
|
|
11518
11768
|
constructor(backing) {
|
|
11519
11769
|
super(backing);
|
|
11770
|
+
this.pendingWrites = /* @__PURE__ */ new Map();
|
|
11520
11771
|
}
|
|
11521
11772
|
ready() {
|
|
11522
11773
|
return this.initialized ??= this.backing.init();
|
|
@@ -11527,7 +11778,14 @@ var NodeCache = class extends PersistentCache {
|
|
|
11527
11778
|
}
|
|
11528
11779
|
async put(key, value) {
|
|
11529
11780
|
await this.ready();
|
|
11530
|
-
|
|
11781
|
+
const previous = this.pendingWrites.get(key);
|
|
11782
|
+
const write = (previous ? previous.catch(() => void 0) : Promise.resolve()).then(() => this.backing.setItem(key, value)).then(() => value);
|
|
11783
|
+
this.pendingWrites.set(key, write);
|
|
11784
|
+
try {
|
|
11785
|
+
return await write;
|
|
11786
|
+
} finally {
|
|
11787
|
+
if (this.pendingWrites.get(key) === write) this.pendingWrites.delete(key);
|
|
11788
|
+
}
|
|
11531
11789
|
}
|
|
11532
11790
|
async delete(key) {
|
|
11533
11791
|
await this.ready();
|
|
@@ -11573,7 +11831,10 @@ var NodeEnv = class {
|
|
|
11573
11831
|
openCache(name, version2) {
|
|
11574
11832
|
return new NodeCache(NodePersist.create({
|
|
11575
11833
|
dir: name + version2,
|
|
11576
|
-
encoding: "utf8"
|
|
11834
|
+
encoding: "utf8",
|
|
11835
|
+
// node-persist's unref'd one-second write queue delays loads and lets Node exit before writes finish.
|
|
11836
|
+
// NodeCache serializes writes to each key while allowing different files to write concurrently.
|
|
11837
|
+
writeQueue: false
|
|
11577
11838
|
}));
|
|
11578
11839
|
}
|
|
11579
11840
|
};
|
|
@@ -11650,6 +11911,9 @@ function shutdown() {
|
|
|
11650
11911
|
Caching.end();
|
|
11651
11912
|
}
|
|
11652
11913
|
|
|
11914
|
+
// src/armor/index.ts
|
|
11915
|
+
init_Armor();
|
|
11916
|
+
|
|
11653
11917
|
// src/assets/index.ts
|
|
11654
11918
|
init_AssetDefaults();
|
|
11655
11919
|
init_AssetKey();
|
|
@@ -11741,7 +12005,7 @@ init_EntityObject();
|
|
|
11741
12005
|
init_MineRenderError();
|
|
11742
12006
|
|
|
11743
12007
|
// src/export/SceneExporter.ts
|
|
11744
|
-
import { ClampToEdgeWrapping as
|
|
12008
|
+
import { ClampToEdgeWrapping as ClampToEdgeWrapping3, Color as Color7, Float32BufferAttribute as Float32BufferAttribute4, Matrix4 as Matrix46, Mesh as Mesh5, MeshBasicMaterial as MeshBasicMaterial2, NearestFilter as NearestFilter3, RGBAFormat as RGBAFormat3, Scene as Scene3, TextureSource as TextureSource2, Texture as Texture3, UnsignedByteType } from "three";
|
|
11745
12009
|
|
|
11746
12010
|
// ../../node_modules/three/examples/jsm/exporters/OBJExporter.js
|
|
11747
12011
|
import {
|
|
@@ -11749,7 +12013,7 @@ import {
|
|
|
11749
12013
|
ColorManagement,
|
|
11750
12014
|
Matrix3,
|
|
11751
12015
|
SRGBColorSpace as SRGBColorSpace3,
|
|
11752
|
-
Vector2 as
|
|
12016
|
+
Vector2 as Vector23,
|
|
11753
12017
|
Vector3 as Vector37
|
|
11754
12018
|
} from "three";
|
|
11755
12019
|
var OBJExporter = class {
|
|
@@ -11769,7 +12033,7 @@ var OBJExporter = class {
|
|
|
11769
12033
|
const vertex = new Vector37();
|
|
11770
12034
|
const color2 = new Color4();
|
|
11771
12035
|
const normal = new Vector37();
|
|
11772
|
-
const uv = new
|
|
12036
|
+
const uv = new Vector23();
|
|
11773
12037
|
const face = [];
|
|
11774
12038
|
function parseMesh(mesh) {
|
|
11775
12039
|
let nbVertex = 0;
|
|
@@ -12474,7 +12738,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
12474
12738
|
if (instanceColor) tint.multiply(instanceColor);
|
|
12475
12739
|
if (bakeColors) {
|
|
12476
12740
|
const original = geometry.getAttribute("color");
|
|
12477
|
-
const colors2 = new
|
|
12741
|
+
const colors2 = new Float32BufferAttribute4(new Float32Array(geometry.getAttribute("position").count * 3), 3);
|
|
12478
12742
|
for (let i = 0; i < colors2.count; i++) {
|
|
12479
12743
|
colors2.setXYZ(i, (original?.getX(i) ?? 1) * tint.r, (original?.getY(i) ?? 1) * tint.g, (original?.getZ(i) ?? 1) * tint.b);
|
|
12480
12744
|
}
|
|
@@ -12483,7 +12747,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
12483
12747
|
material.color.copy(tint);
|
|
12484
12748
|
}
|
|
12485
12749
|
}
|
|
12486
|
-
const copy = new
|
|
12750
|
+
const copy = new Mesh5(geometry, material);
|
|
12487
12751
|
copy.name = mesh.name;
|
|
12488
12752
|
copy.renderOrder = mesh.renderOrder;
|
|
12489
12753
|
scene.add(copy);
|
|
@@ -12525,7 +12789,7 @@ function createSnapshot(root, gltf, bakeColors = false) {
|
|
|
12525
12789
|
}
|
|
12526
12790
|
function selectAlphaMode(material, geometry) {
|
|
12527
12791
|
const texture = material.map;
|
|
12528
|
-
if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== RGBAFormat3 || texture.type !== UnsignedByteType || texture.wrapS !==
|
|
12792
|
+
if (material.type !== "MeshBasicMaterial" || !material.transparent || !material.depthWrite || material.opacity !== 1 || material.alphaMap || !texture?.isDataTexture || texture.format !== RGBAFormat3 || texture.type !== UnsignedByteType || texture.wrapS !== ClampToEdgeWrapping3 || texture.wrapT !== ClampToEdgeWrapping3 || texture.magFilter !== NearestFilter3 || texture.minFilter !== NearestFilter3 || texture.anisotropy > 1 || texture.offset.x !== 0 || texture.offset.y !== 0 || texture.repeat.x !== 1 || texture.repeat.y !== 1 || texture.rotation !== 0 || !texture.matrixAutoUpdate && !texture.matrix.elements.every((value, i) => value === (i % 4 === 0 ? 1 : 0))) return;
|
|
12529
12793
|
const uv = geometry.getAttribute(texture.channel === 0 ? "uv" : `uv${texture.channel}`);
|
|
12530
12794
|
const colors2 = geometry.getAttribute("color");
|
|
12531
12795
|
if (!uv || material.vertexColors && colors2?.itemSize === 4) return;
|
|
@@ -14190,6 +14454,7 @@ import { Scene as Scene4 } from "three";
|
|
|
14190
14454
|
|
|
14191
14455
|
// src/skin/scene/SkinObject.ts
|
|
14192
14456
|
init_SceneObject();
|
|
14457
|
+
import { Object3D as Object3D6 } from "three";
|
|
14193
14458
|
|
|
14194
14459
|
// src/skin/SkinPart.ts
|
|
14195
14460
|
var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
|
|
@@ -14206,11 +14471,21 @@ var SkinPart = /* @__PURE__ */ ((SkinPart2) => {
|
|
|
14206
14471
|
SkinPart2["RIGHT_TROUSERS"] = "rightTrousers";
|
|
14207
14472
|
SkinPart2["LEFT_TROUSERS"] = "leftTrousers";
|
|
14208
14473
|
SkinPart2["CAPE"] = "cape";
|
|
14474
|
+
SkinPart2["LEFT_EAR"] = "leftEar";
|
|
14475
|
+
SkinPart2["RIGHT_EAR"] = "rightEar";
|
|
14209
14476
|
return SkinPart2;
|
|
14210
14477
|
})(SkinPart || {});
|
|
14211
14478
|
var SKIN_PARTS = Object.values(SkinPart);
|
|
14212
14479
|
|
|
14213
14480
|
// src/skin/SkinTextureCoordinates.ts
|
|
14481
|
+
var earCoordinates = {
|
|
14482
|
+
west: { uv: [24, 1, 25, 7] },
|
|
14483
|
+
east: { uv: [31, 1, 32, 7] },
|
|
14484
|
+
south: { uv: [25, 1, 31, 7] },
|
|
14485
|
+
north: { uv: [32, 1, 38, 7] },
|
|
14486
|
+
up: { uv: [25, 0, 31, 1] },
|
|
14487
|
+
down: { uv: [31, 1, 37, 0] }
|
|
14488
|
+
};
|
|
14214
14489
|
var baseSkinCoordinates = {
|
|
14215
14490
|
head: {
|
|
14216
14491
|
west: {
|
|
@@ -14831,7 +15106,9 @@ var baseSkinCoordinates = {
|
|
|
14831
15106
|
south: { uv: [12, 1, 22, 17] },
|
|
14832
15107
|
up: { uv: [11, 1, 1, 0] },
|
|
14833
15108
|
down: { uv: [21, 0, 11, 1] }
|
|
14834
|
-
}
|
|
15109
|
+
},
|
|
15110
|
+
leftEar: earCoordinates,
|
|
15111
|
+
rightEar: earCoordinates
|
|
14835
15112
|
};
|
|
14836
15113
|
var classicSkinTextureCoordinates = {
|
|
14837
15114
|
...baseSkinCoordinates
|
|
@@ -14882,6 +15159,7 @@ var box4_12_4outer = [4.5, 12.5, 4.5];
|
|
|
14882
15159
|
var box3_12_4inner = [3, 12, 4];
|
|
14883
15160
|
var box3_12_4outer = [3.5, 12.5, 4.5];
|
|
14884
15161
|
var box10_16_1 = [10, 16, 1];
|
|
15162
|
+
var box8_8_3ear = [8, 8, 3];
|
|
14885
15163
|
var baseSkinGeometries = {
|
|
14886
15164
|
head: box8inner,
|
|
14887
15165
|
hat: box8outer,
|
|
@@ -14895,7 +15173,9 @@ var baseSkinGeometries = {
|
|
|
14895
15173
|
leftTrousers: box4_12_4outer,
|
|
14896
15174
|
rightLeg: box4_12_4inner,
|
|
14897
15175
|
rightTrousers: box4_12_4outer,
|
|
14898
|
-
cape: box10_16_1
|
|
15176
|
+
cape: box10_16_1,
|
|
15177
|
+
leftEar: box8_8_3ear,
|
|
15178
|
+
rightEar: box8_8_3ear
|
|
14899
15179
|
};
|
|
14900
15180
|
var classicSkinGeometries = { ...{}, ...baseSkinGeometries };
|
|
14901
15181
|
var slimSkinGeometries = {
|
|
@@ -14924,6 +15204,12 @@ var capeTextureSizes = {
|
|
|
14924
15204
|
};
|
|
14925
15205
|
|
|
14926
15206
|
// src/skin/scene/SkinObject.ts
|
|
15207
|
+
var ArmorClass;
|
|
15208
|
+
var EntityObjectClass;
|
|
15209
|
+
function hasCubes(part) {
|
|
15210
|
+
return part.cubes.length > 0 || Object.values(part.children).some(hasCubes);
|
|
15211
|
+
}
|
|
15212
|
+
var UPSIDE_DOWN_OFFSET = (1.8 + 0.1) * 16 / 0.9375;
|
|
14927
15213
|
var SkinObject = class extends SceneObject {
|
|
14928
15214
|
constructor(options) {
|
|
14929
15215
|
super();
|
|
@@ -14931,27 +15217,42 @@ var SkinObject = class extends SceneObject {
|
|
|
14931
15217
|
this.detectedSlim = false;
|
|
14932
15218
|
this.skinLoad = 0;
|
|
14933
15219
|
this.capeLoad = 0;
|
|
15220
|
+
this.armorLoad = 0;
|
|
15221
|
+
this.armorObjects = [];
|
|
14934
15222
|
this.options = (0, import_ts_deepmerge.default)({}, SceneObject.DEFAULT_OPTIONS, options ?? {});
|
|
14935
15223
|
this.slim = this.options.slim ?? false;
|
|
14936
15224
|
}
|
|
14937
15225
|
async init() {
|
|
14938
15226
|
const cape = this.getGroupByName("cape" /* CAPE */);
|
|
15227
|
+
const capeOnBody = cape?.parent === this.getGroupByName("body" /* BODY */);
|
|
14939
15228
|
this.createMeshes();
|
|
14940
|
-
if (cape)
|
|
15229
|
+
if (cape) {
|
|
15230
|
+
const body = this.getGroupByName("body" /* BODY */);
|
|
15231
|
+
if (capeOnBody) body.add(cape);
|
|
15232
|
+
else body.attach(cape);
|
|
15233
|
+
}
|
|
15234
|
+
for (const { part, object: object4 } of this.armorObjects) this.getGroupByName(part).add(object4);
|
|
15235
|
+
this.updateEars();
|
|
15236
|
+
this.updateUpsideDown();
|
|
14941
15237
|
}
|
|
14942
15238
|
removeMeshes() {
|
|
14943
15239
|
}
|
|
14944
15240
|
createMeshes() {
|
|
14945
15241
|
const mat = this.skinMaterial ?? Materials.MISSING_TEXTURE;
|
|
15242
|
+
this.model?.removeFromParent();
|
|
15243
|
+
const model = this.model = new Object3D6();
|
|
15244
|
+
this.add(model);
|
|
14946
15245
|
{
|
|
14947
|
-
const headGroup = this.
|
|
15246
|
+
const headGroup = this.createGroup("head", 0, 28, 0, "y" /* Y */, -4);
|
|
15247
|
+
model.add(headGroup);
|
|
14948
15248
|
const headGeo = this.getBoxGeometry("head" /* HEAD */);
|
|
14949
15249
|
const head = this.createAndAddMesh("head", headGroup, headGeo, mat, "y" /* Y */, 4);
|
|
14950
15250
|
const hatGeo = this.getBoxGeometry("hat" /* HAT */);
|
|
14951
15251
|
const hat = this.createAndAddMesh("hat", headGroup, hatGeo, mat, "y" /* Y */, 4);
|
|
14952
15252
|
}
|
|
14953
15253
|
{
|
|
14954
|
-
const bodyGroup = this.
|
|
15254
|
+
const bodyGroup = this.createGroup("body", 0, 24, 0);
|
|
15255
|
+
model.add(bodyGroup);
|
|
14955
15256
|
const bodyGeo = this.getBoxGeometry("body" /* BODY */);
|
|
14956
15257
|
const body = this.createAndAddMesh("body", bodyGroup, bodyGeo, mat, "y" /* Y */, -6);
|
|
14957
15258
|
const jacketGeo = this.getBoxGeometry("jacket" /* JACKET */);
|
|
@@ -14959,7 +15260,8 @@ var SkinObject = class extends SceneObject {
|
|
|
14959
15260
|
}
|
|
14960
15261
|
{
|
|
14961
15262
|
{
|
|
14962
|
-
const leftArmGroup = this.
|
|
15263
|
+
const leftArmGroup = this.createGroup("leftArm", 5, 22, 0);
|
|
15264
|
+
model.add(leftArmGroup);
|
|
14963
15265
|
const leftArmGeo = this.getBoxGeometry("leftArm" /* LEFT_ARM */);
|
|
14964
15266
|
const leftArm = this.createAndAddMesh("leftArm", leftArmGroup, leftArmGeo, mat, "y" /* Y */, -4);
|
|
14965
15267
|
leftArm.position.x = this.slim ? 0.5 : 1;
|
|
@@ -14968,7 +15270,8 @@ var SkinObject = class extends SceneObject {
|
|
|
14968
15270
|
leftSleeve.position.x = this.slim ? 0.5 : 1;
|
|
14969
15271
|
}
|
|
14970
15272
|
{
|
|
14971
|
-
const rightArmGroup = this.
|
|
15273
|
+
const rightArmGroup = this.createGroup("rightArm", -5, 22, 0);
|
|
15274
|
+
model.add(rightArmGroup);
|
|
14972
15275
|
const rightArmGeo = this.getBoxGeometry("rightArm" /* RIGHT_ARM */);
|
|
14973
15276
|
const rightArm = this.createAndAddMesh("rightArm", rightArmGroup, rightArmGeo, mat, "y" /* Y */, -4);
|
|
14974
15277
|
rightArm.position.x = this.slim ? -0.5 : -1;
|
|
@@ -14979,14 +15282,16 @@ var SkinObject = class extends SceneObject {
|
|
|
14979
15282
|
}
|
|
14980
15283
|
{
|
|
14981
15284
|
{
|
|
14982
|
-
const leftLegGroup = this.
|
|
15285
|
+
const leftLegGroup = this.createGroup("leftLeg", 1.9, 12, 0);
|
|
15286
|
+
model.add(leftLegGroup);
|
|
14983
15287
|
const leftLegGeo = this.getBoxGeometry("leftLeg" /* LEFT_LEG */);
|
|
14984
15288
|
const leftLeg = this.createAndAddMesh("leftLeg", leftLegGroup, leftLegGeo, mat, "y" /* Y */, -6);
|
|
14985
15289
|
const leftTrousersGeo = this.getBoxGeometry("leftTrousers" /* LEFT_TROUSERS */);
|
|
14986
15290
|
const leftTrousers = this.createAndAddMesh("leftTrousers", leftLegGroup, leftTrousersGeo, mat, "y" /* Y */, -6);
|
|
14987
15291
|
}
|
|
14988
15292
|
{
|
|
14989
|
-
const rightLegGroup = this.
|
|
15293
|
+
const rightLegGroup = this.createGroup("rightLeg", -1.9, 12, 0);
|
|
15294
|
+
model.add(rightLegGroup);
|
|
14990
15295
|
const rightLegGeo = this.getBoxGeometry("rightLeg" /* RIGHT_LEG */);
|
|
14991
15296
|
const rightLeg = this.createAndAddMesh("rightLeg", rightLegGroup, rightLegGeo, mat, "y" /* Y */, -6);
|
|
14992
15297
|
const rightTrousersGeo = this.getBoxGeometry("rightTrousers" /* RIGHT_TROUSERS */);
|
|
@@ -15053,6 +15358,54 @@ var SkinObject = class extends SceneObject {
|
|
|
15053
15358
|
}
|
|
15054
15359
|
this.notifyDirty();
|
|
15055
15360
|
}
|
|
15361
|
+
/**
|
|
15362
|
+
* Loads armor from 1.21.4+ equipment assets, or pass undefined to remove it.
|
|
15363
|
+
* Each piece moves with the skin part it covers.
|
|
15364
|
+
*/
|
|
15365
|
+
async setArmor(armor) {
|
|
15366
|
+
const load = ++this.armorLoad;
|
|
15367
|
+
const objects = [];
|
|
15368
|
+
if (armor) {
|
|
15369
|
+
const Armor2 = ArmorClass ??= (await Promise.resolve().then(() => (init_Armor(), Armor_exports))).Armor;
|
|
15370
|
+
const EntityObject2 = EntityObjectClass ??= (await Promise.resolve().then(() => (init_EntityObject(), EntityObject_exports))).EntityObject;
|
|
15371
|
+
const model = await Armor2.getEntity(armor);
|
|
15372
|
+
if (model) {
|
|
15373
|
+
const parts = { head: "head", body: "body", left_arm: "leftArm", right_arm: "rightArm", left_leg: "leftLeg", right_leg: "rightLeg" };
|
|
15374
|
+
for (const [name, part] of Object.entries(parts)) {
|
|
15375
|
+
const layers = {};
|
|
15376
|
+
for (const [draw, layer] of Object.entries(model.layers)) {
|
|
15377
|
+
const child = layer.layer.root.children[name];
|
|
15378
|
+
if (!child || !hasCubes(child)) continue;
|
|
15379
|
+
const pose = { offset: [0, 0, 0], rotation: [0, 0, 0] };
|
|
15380
|
+
layers[draw] = { ...layer, layer: { ...layer.layer, root: {
|
|
15381
|
+
pose,
|
|
15382
|
+
cubes: [],
|
|
15383
|
+
children: { [name]: { ...child, pose } }
|
|
15384
|
+
} } };
|
|
15385
|
+
}
|
|
15386
|
+
const first = Object.values(layers)[0];
|
|
15387
|
+
if (!first) continue;
|
|
15388
|
+
const object4 = new EntityObject2({ ...first, id: model.id, layers }, { flip: false });
|
|
15389
|
+
object4.rotation.x = Math.PI;
|
|
15390
|
+
objects.push({ part, object: object4 });
|
|
15391
|
+
}
|
|
15392
|
+
}
|
|
15393
|
+
}
|
|
15394
|
+
const results = await Promise.allSettled(objects.map(({ object: object4 }) => object4.init()));
|
|
15395
|
+
const failure = results.find((result) => result.status === "rejected");
|
|
15396
|
+
if (load !== this.armorLoad || failure) {
|
|
15397
|
+
for (const { object: object4 } of objects) object4.dispose();
|
|
15398
|
+
if (load === this.armorLoad && failure?.status === "rejected") throw failure.reason;
|
|
15399
|
+
return;
|
|
15400
|
+
}
|
|
15401
|
+
for (const { object: object4 } of this.armorObjects) {
|
|
15402
|
+
object4.dispose();
|
|
15403
|
+
object4.removeFromParent();
|
|
15404
|
+
}
|
|
15405
|
+
this.armorObjects = objects;
|
|
15406
|
+
for (const { part, object: object4 } of objects) this.getGroupByName(part)?.add(object4);
|
|
15407
|
+
this.notifyDirty();
|
|
15408
|
+
}
|
|
15056
15409
|
/** Select the arm model, or pass undefined to use texture detection. */
|
|
15057
15410
|
setSlim(slim) {
|
|
15058
15411
|
this.options.slim = slim;
|
|
@@ -15071,6 +15424,39 @@ var SkinObject = class extends SceneObject {
|
|
|
15071
15424
|
}
|
|
15072
15425
|
this.notifyDirty();
|
|
15073
15426
|
}
|
|
15427
|
+
/** Shows or hides deadmau5's ears, which vanilla draws from the skin texture at 24,0 for that player only. */
|
|
15428
|
+
setEars(ears) {
|
|
15429
|
+
if (ears === (this.options.ears ?? false)) return;
|
|
15430
|
+
this.options.ears = ears;
|
|
15431
|
+
this.updateEars();
|
|
15432
|
+
}
|
|
15433
|
+
updateEars() {
|
|
15434
|
+
const head = this.getGroupByName("head" /* HEAD */);
|
|
15435
|
+
if (!head) return;
|
|
15436
|
+
for (const [part, x] of [["leftEar" /* LEFT_EAR */, 6], ["rightEar" /* RIGHT_EAR */, -6]]) {
|
|
15437
|
+
const ear = this.getMeshByName(part);
|
|
15438
|
+
if (!this.options.ears) {
|
|
15439
|
+
ear?.removeFromParent();
|
|
15440
|
+
} else if (!ear) {
|
|
15441
|
+
const mesh = this.createAndAddMesh(part, head, this.getBoxGeometry(part), this.skinMaterial ?? Materials.MISSING_TEXTURE);
|
|
15442
|
+
mesh.position.set(x, 9, 0.5);
|
|
15443
|
+
}
|
|
15444
|
+
}
|
|
15445
|
+
this.notifyDirty();
|
|
15446
|
+
}
|
|
15447
|
+
/** Turns the player upside down, as vanilla does for players named Dinnerbone or Grumm. */
|
|
15448
|
+
setUpsideDown(upsideDown) {
|
|
15449
|
+
if (upsideDown === (this.options.upsideDown ?? false)) return;
|
|
15450
|
+
this.options.upsideDown = upsideDown;
|
|
15451
|
+
this.updateUpsideDown();
|
|
15452
|
+
}
|
|
15453
|
+
updateUpsideDown() {
|
|
15454
|
+
if (!this.model) return;
|
|
15455
|
+
const upsideDown = this.options.upsideDown ?? false;
|
|
15456
|
+
this.model.position.y = upsideDown ? UPSIDE_DOWN_OFFSET : 0;
|
|
15457
|
+
this.model.rotation.z = upsideDown ? Math.PI : 0;
|
|
15458
|
+
this.notifyDirty();
|
|
15459
|
+
}
|
|
15074
15460
|
/** Select the texture layout, or pass undefined to detect it from image dimensions. */
|
|
15075
15461
|
async setLegacy(legacy) {
|
|
15076
15462
|
if (legacy === this.options.legacy) return;
|
|
@@ -15080,6 +15466,11 @@ var SkinObject = class extends SceneObject {
|
|
|
15080
15466
|
dispose() {
|
|
15081
15467
|
this.skinLoad++;
|
|
15082
15468
|
this.capeLoad++;
|
|
15469
|
+
this.armorLoad++;
|
|
15470
|
+
for (const { object: object4 } of this.armorObjects.splice(0)) {
|
|
15471
|
+
object4.dispose();
|
|
15472
|
+
object4.removeFromParent();
|
|
15473
|
+
}
|
|
15083
15474
|
super.dispose();
|
|
15084
15475
|
}
|
|
15085
15476
|
//TODO: layer toggles
|
|
@@ -15099,7 +15490,7 @@ function isBlockObject2(obj) {
|
|
|
15099
15490
|
}
|
|
15100
15491
|
var ModelObjectClass;
|
|
15101
15492
|
var BlockObjectClass;
|
|
15102
|
-
var
|
|
15493
|
+
var EntityObjectClass2;
|
|
15103
15494
|
var GuiObjectClass;
|
|
15104
15495
|
var ItemTintsClass;
|
|
15105
15496
|
var MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
@@ -15243,7 +15634,7 @@ var MineRenderScene = class _MineRenderScene extends Scene4 {
|
|
|
15243
15634
|
}
|
|
15244
15635
|
/** Adds an entity loaded with {@link Entities.getEntity}, using its selected layers and textures. */
|
|
15245
15636
|
async addEntity(entity, options, parent = this) {
|
|
15246
|
-
const EntityObject2 =
|
|
15637
|
+
const EntityObject2 = EntityObjectClass2 ??= (await Promise.resolve().then(() => (init_EntityObject(), EntityObject_exports))).EntityObject;
|
|
15247
15638
|
return this.addSceneObject(entity, () => new EntityObject2(entity, options), options, parent);
|
|
15248
15639
|
}
|
|
15249
15640
|
/**
|
|
@@ -16598,6 +16989,23 @@ var itemContext = (withDisplayContext) => (value, path) => {
|
|
|
16598
16989
|
}
|
|
16599
16990
|
});
|
|
16600
16991
|
};
|
|
16992
|
+
function entityAnimation(value, path) {
|
|
16993
|
+
const animation = object3(value, path);
|
|
16994
|
+
if (["name", "clips"].filter((key) => animation[key] !== void 0).length !== 1) {
|
|
16995
|
+
fail(path, "expected exactly one of name or clips");
|
|
16996
|
+
}
|
|
16997
|
+
fields(value, path, { name: text, clips: (value2, path2) => {
|
|
16998
|
+
list((value3, path3) => {
|
|
16999
|
+
fields(value3, path3, { name: text, weight: nonnegative }, ["name"]);
|
|
17000
|
+
})(value2, path2);
|
|
17001
|
+
if (!value2.length) fail(path2, "expected at least one clip");
|
|
17002
|
+
const names = /* @__PURE__ */ new Set();
|
|
17003
|
+
for (const [index, clip] of value2.entries()) {
|
|
17004
|
+
if (names.has(clip.name)) fail(`${path2}[${index}].name`, `duplicate clip "${clip.name}"`);
|
|
17005
|
+
names.add(clip.name);
|
|
17006
|
+
}
|
|
17007
|
+
}, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean });
|
|
17008
|
+
}
|
|
16601
17009
|
function guiLayer(value, path) {
|
|
16602
17010
|
const layer = object3(value, path);
|
|
16603
17011
|
if (["texture", "item", "text"].filter((key) => layer[key] !== void 0).length !== 1) {
|
|
@@ -16638,13 +17046,27 @@ function validateObject(value, path) {
|
|
|
16638
17046
|
const required = ["id", "type"];
|
|
16639
17047
|
const renderOptions = { wireframe: boolean };
|
|
16640
17048
|
switch (input.type) {
|
|
16641
|
-
case "skin":
|
|
17049
|
+
case "skin": {
|
|
17050
|
+
const piece = (value2, path2) => {
|
|
17051
|
+
if (typeof value2 === "string") asset(value2, path2);
|
|
17052
|
+
else fields(value2, path2, {
|
|
17053
|
+
asset,
|
|
17054
|
+
color,
|
|
17055
|
+
glint: boolean,
|
|
17056
|
+
trim: (value3, path3) => {
|
|
17057
|
+
fields(value3, path3, { pattern: asset, material: asset }, ["pattern", "material"]);
|
|
17058
|
+
}
|
|
17059
|
+
}, ["asset"]);
|
|
17060
|
+
};
|
|
16642
17061
|
fields(value, path, {
|
|
16643
17062
|
...common,
|
|
16644
17063
|
skin: text,
|
|
16645
17064
|
cape: (value2, path2) => {
|
|
16646
17065
|
fields(value2, path2, { texture: text, layout: enumeration(["minecraft", "optifine", "labymod"]) }, ["texture"]);
|
|
16647
17066
|
},
|
|
17067
|
+
armor: (value2, path2) => {
|
|
17068
|
+
fields(value2, path2, { head: piece, chest: piece, legs: piece, feet: piece });
|
|
17069
|
+
},
|
|
16648
17070
|
hiddenParts: list(enumeration(SKIN_PARTS)),
|
|
16649
17071
|
pose: (value2, path2) => {
|
|
16650
17072
|
fields(value2, path2, {
|
|
@@ -16658,10 +17080,11 @@ function validateObject(value, path) {
|
|
|
16658
17080
|
});
|
|
16659
17081
|
},
|
|
16660
17082
|
options: (value2, path2) => {
|
|
16661
|
-
fields(value2, path2, { slim: boolean, legacy: boolean });
|
|
17083
|
+
fields(value2, path2, { slim: boolean, legacy: boolean, ears: boolean, upsideDown: boolean });
|
|
16662
17084
|
}
|
|
16663
17085
|
}, required);
|
|
16664
17086
|
break;
|
|
17087
|
+
}
|
|
16665
17088
|
case "block":
|
|
16666
17089
|
fields(value, path, {
|
|
16667
17090
|
...common,
|
|
@@ -16700,9 +17123,7 @@ function validateObject(value, path) {
|
|
|
16700
17123
|
})
|
|
16701
17124
|
});
|
|
16702
17125
|
},
|
|
16703
|
-
animation:
|
|
16704
|
-
fields(value2, path2, { name: text, loop: boolean, speed: nonnegative, time: nonnegative, paused: boolean }, ["name"]);
|
|
16705
|
-
}
|
|
17126
|
+
animation: entityAnimation
|
|
16706
17127
|
}, [...required, "asset"]);
|
|
16707
17128
|
if (Array.isArray(input.layers) && !input.layers.length) fail(`${path}.layers`, "expected at least one layer");
|
|
16708
17129
|
break;
|
|
@@ -16931,6 +17352,7 @@ var SceneDocumentLoader = class {
|
|
|
16931
17352
|
await skin.setSkinTexture(texture);
|
|
16932
17353
|
await content.initialize(skin);
|
|
16933
17354
|
if (definition.cape) await skin.setCapeTexture(await skinTexture(definition.cape.texture, true), definition.cape.layout);
|
|
17355
|
+
if (definition.armor) await skin.setArmor(definition.armor);
|
|
16934
17356
|
for (const [part, rotation] of Object.entries(definition.pose ?? {})) {
|
|
16935
17357
|
skin.getGroupByName(part)?.rotation.set(...rotation, "XYZ");
|
|
16936
17358
|
}
|
|
@@ -16969,10 +17391,20 @@ var SceneDocumentLoader = class {
|
|
|
16969
17391
|
const entity = await content.addEntity(model, { ...definition.options, instanceMeshes: false });
|
|
16970
17392
|
object4 = entity;
|
|
16971
17393
|
if (definition.animation) {
|
|
17394
|
+
const animation = definition.animation;
|
|
16972
17395
|
const animations = await Entities.getAnimations(key);
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
17396
|
+
if (animation.name !== void 0) {
|
|
17397
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, animation.name) ? animations[animation.name] : void 0;
|
|
17398
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${animation.name}"`);
|
|
17399
|
+
entity.playAnimation(clip, animation);
|
|
17400
|
+
} else {
|
|
17401
|
+
const clips = animation.clips.map(({ name }) => {
|
|
17402
|
+
const clip = animations && Object.prototype.hasOwnProperty.call(animations, name) ? animations[name] : void 0;
|
|
17403
|
+
if (!clip) throw new Error(`Entity ${definition.asset} has no animation "${name}"`);
|
|
17404
|
+
return clip;
|
|
17405
|
+
});
|
|
17406
|
+
entity.playAnimations(clips, { ...animation, weights: animation.clips.map((clip) => clip.weight ?? 1) });
|
|
17407
|
+
}
|
|
16976
17408
|
}
|
|
16977
17409
|
break;
|
|
16978
17410
|
}
|
|
@@ -17021,6 +17453,7 @@ init_Skins();
|
|
|
17021
17453
|
|
|
17022
17454
|
// src/texture/index.ts
|
|
17023
17455
|
init_Colormaps();
|
|
17456
|
+
init_PalettedTextures();
|
|
17024
17457
|
init_TextureAtlas();
|
|
17025
17458
|
init_TextureLoader();
|
|
17026
17459
|
init_Textures();
|
|
@@ -17810,7 +18243,7 @@ var AnvilWorldSource = class {
|
|
|
17810
18243
|
read.waiters++;
|
|
17811
18244
|
return new Promise((resolve, reject) => {
|
|
17812
18245
|
let finished = false;
|
|
17813
|
-
const
|
|
18246
|
+
const release = () => {
|
|
17814
18247
|
if (finished) return false;
|
|
17815
18248
|
finished = true;
|
|
17816
18249
|
signal?.removeEventListener("abort", abort);
|
|
@@ -17818,7 +18251,7 @@ var AnvilWorldSource = class {
|
|
|
17818
18251
|
return true;
|
|
17819
18252
|
};
|
|
17820
18253
|
const abort = () => {
|
|
17821
|
-
if (!
|
|
18254
|
+
if (!release()) return;
|
|
17822
18255
|
if (!read.waiters && !read.settled) {
|
|
17823
18256
|
if (this.pending.get(key) === read) this.pending.delete(key);
|
|
17824
18257
|
read.controller.abort(signal.reason);
|
|
@@ -17828,10 +18261,10 @@ var AnvilWorldSource = class {
|
|
|
17828
18261
|
signal?.addEventListener("abort", abort, { once: true });
|
|
17829
18262
|
read.promise.then(
|
|
17830
18263
|
(data) => {
|
|
17831
|
-
if (
|
|
18264
|
+
if (release()) resolve(data);
|
|
17832
18265
|
},
|
|
17833
18266
|
(error) => {
|
|
17834
|
-
if (
|
|
18267
|
+
if (release()) reject(error);
|
|
17835
18268
|
}
|
|
17836
18269
|
);
|
|
17837
18270
|
if (signal?.aborted) abort();
|
|
@@ -17853,7 +18286,8 @@ var AnvilWorldSource = class {
|
|
|
17853
18286
|
};
|
|
17854
18287
|
|
|
17855
18288
|
// src/world/Chunk.ts
|
|
17856
|
-
|
|
18289
|
+
init_BlockObject();
|
|
18290
|
+
import { Color as Color13, Vector3 as Vector321 } from "three";
|
|
17857
18291
|
init_BlockStates();
|
|
17858
18292
|
init_AssetKey();
|
|
17859
18293
|
|
|
@@ -17863,6 +18297,7 @@ init_util();
|
|
|
17863
18297
|
import { Vector3 as Vector319 } from "three";
|
|
17864
18298
|
init_AssetKey();
|
|
17865
18299
|
init_BlockStates();
|
|
18300
|
+
init_BlockEntities();
|
|
17866
18301
|
init_CubeFace();
|
|
17867
18302
|
|
|
17868
18303
|
// src/world/SectionModels.ts
|
|
@@ -17960,6 +18395,10 @@ var SectionModels = class {
|
|
|
17960
18395
|
biomeTint: source ? [...templates.values()].some((template) => template.biomeTint?.some((value) => value === 1)) || void 0 : void 0
|
|
17961
18396
|
};
|
|
17962
18397
|
}
|
|
18398
|
+
/** Starts loading the state's models and atlases so a later `prepareState` with the same properties finds them loaded. */
|
|
18399
|
+
async preload(blockState3, properties = {}) {
|
|
18400
|
+
await this.state(blockState3, properties);
|
|
18401
|
+
}
|
|
17963
18402
|
async state(blockState3, properties) {
|
|
17964
18403
|
let states = this.states.get(blockState3);
|
|
17965
18404
|
if (!states) this.states.set(blockState3, states = /* @__PURE__ */ new Map());
|
|
@@ -17982,22 +18421,24 @@ var SectionModels = class {
|
|
|
17982
18421
|
async prepare(blockState3, properties) {
|
|
17983
18422
|
const state = { ...await BlockStateResolver.defaults(blockState3), ...properties };
|
|
17984
18423
|
const groups = BlockStateResolver.matching(blockState3, state);
|
|
17985
|
-
if (!groups.length) return void 0;
|
|
18424
|
+
if (!groups.length || groups.some((group) => Array.isArray(group) && !group.length)) return void 0;
|
|
18425
|
+
const variants = groups.flatMap((group) => Array.isArray(group) ? group : [group]);
|
|
18426
|
+
if (variants.some((variant) => !variant.model)) return void 0;
|
|
18427
|
+
const settled = await Promise.allSettled(variants.map(async (variant) => {
|
|
18428
|
+
const modelKey = AssetKey.parse("models", variant.model);
|
|
18429
|
+
modelKey.root = blockState3.key?.root;
|
|
18430
|
+
const model = await Models.getMerged(modelKey);
|
|
18431
|
+
if (!model?.elements?.length) return void 0;
|
|
18432
|
+
const atlas = await UVMapper.getAtlas(model);
|
|
18433
|
+
const rotation = BlockStateResolver.rotation(variant);
|
|
18434
|
+
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
18435
|
+
return { model, atlas, rotation };
|
|
18436
|
+
}));
|
|
17986
18437
|
const prepared = /* @__PURE__ */ new Map();
|
|
17987
|
-
for (const
|
|
17988
|
-
|
|
17989
|
-
if (!
|
|
17990
|
-
|
|
17991
|
-
if (!variant.model) return void 0;
|
|
17992
|
-
const modelKey = AssetKey.parse("models", variant.model);
|
|
17993
|
-
modelKey.root = blockState3.key?.root;
|
|
17994
|
-
const model = await Models.getMerged(modelKey);
|
|
17995
|
-
if (!model?.elements?.length) return void 0;
|
|
17996
|
-
const atlas = await UVMapper.getAtlas(model);
|
|
17997
|
-
const rotation = BlockStateResolver.rotation(variant);
|
|
17998
|
-
if (!atlas || atlas.image.width > this.maxAtlasSize || atlas.image.height > this.maxAtlasSize) return void 0;
|
|
17999
|
-
prepared.set(variant, { model, atlas, rotation });
|
|
18000
|
-
}
|
|
18438
|
+
for (const [i, result] of settled.entries()) {
|
|
18439
|
+
if (result.status === "rejected") throw result.reason;
|
|
18440
|
+
if (!result.value) return void 0;
|
|
18441
|
+
prepared.set(variants[i], result.value);
|
|
18001
18442
|
}
|
|
18002
18443
|
return { state, groups, choices: prepared };
|
|
18003
18444
|
}
|
|
@@ -18457,6 +18898,7 @@ function skipsBlockFace(data, rule, block, neighbor, face) {
|
|
|
18457
18898
|
// src/world/MineRenderWorld.ts
|
|
18458
18899
|
init_log();
|
|
18459
18900
|
var log18 = logger("MineRenderWorld");
|
|
18901
|
+
var YIELD_INTERVAL_MS = 8;
|
|
18460
18902
|
var MineRenderWorld = class {
|
|
18461
18903
|
constructor(scene, options = {}) {
|
|
18462
18904
|
this._chunks = /* @__PURE__ */ new Map();
|
|
@@ -18570,7 +19012,7 @@ var MineRenderWorld = class {
|
|
|
18570
19012
|
failures.set(chunk, error);
|
|
18571
19013
|
if (this._chunks.get(`${chunk.x}_${chunk.y}_${chunk.z}`) === chunk) this.pendingBiomes.set(chunk, void 0);
|
|
18572
19014
|
}
|
|
18573
|
-
if (performance.now() - sliceStart >
|
|
19015
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
18574
19016
|
await yieldToEventLoop();
|
|
18575
19017
|
sliceStart = performance.now();
|
|
18576
19018
|
}
|
|
@@ -18671,15 +19113,18 @@ var MineRenderWorld = class {
|
|
|
18671
19113
|
const key = AssetKey.parse("blockstates", block.type);
|
|
18672
19114
|
keys.set(key.serialize(), key);
|
|
18673
19115
|
}
|
|
18674
|
-
await BlockStates.getAll(keys.values());
|
|
19116
|
+
const loaded = await BlockStates.getAll(keys.values());
|
|
19117
|
+
const states = new Map([...keys.keys()].map((key, i) => [key, loaded[i]]));
|
|
18675
19118
|
if (!useBatches) {
|
|
18676
19119
|
for (const block of multiblock.blocks) await place(block);
|
|
18677
19120
|
return;
|
|
18678
19121
|
}
|
|
18679
19122
|
if (!executor) {
|
|
18680
19123
|
const groups2 = /* @__PURE__ */ new Map();
|
|
19124
|
+
const distinct = /* @__PURE__ */ new Map();
|
|
18681
19125
|
const position = new Vector319();
|
|
18682
19126
|
for (const block of multiblock.blocks) {
|
|
19127
|
+
if (this.sectionModels && !Chunk.isAir(block)) distinct.set(ChunkData.paletteKey(block), block);
|
|
18683
19128
|
const [x, y, z] = block.position;
|
|
18684
19129
|
this.validatePosBounds(position.set(x, y, z));
|
|
18685
19130
|
const cx = Math.floor(x / 16), cy = Math.floor(y / 16), cz = Math.floor(z / 16);
|
|
@@ -18690,6 +19135,16 @@ var MineRenderWorld = class {
|
|
|
18690
19135
|
if (!group) groups2.set(chunk, group = []);
|
|
18691
19136
|
group.push({ index: (y - cy * 16) * 256 + (z - cz * 16) * 16 + x - cx * 16, block });
|
|
18692
19137
|
}
|
|
19138
|
+
if (this.sectionModels) {
|
|
19139
|
+
for (const block of distinct.values()) {
|
|
19140
|
+
const state = states.get(AssetKey.parse("blockstates", block.type).serialize());
|
|
19141
|
+
if (!state) continue;
|
|
19142
|
+
void (async () => {
|
|
19143
|
+
if (state.key && BlockEntities.entry(await BlockEntities.getIndex(state.key.root), state.key.toNamespacedString())) return;
|
|
19144
|
+
await this.sectionModels.preload(state, block.properties);
|
|
19145
|
+
})().catch(() => void 0);
|
|
19146
|
+
}
|
|
19147
|
+
}
|
|
18693
19148
|
await this.placeChunkGroups(groups2, changes);
|
|
18694
19149
|
return;
|
|
18695
19150
|
}
|
|
@@ -18725,7 +19180,7 @@ var MineRenderWorld = class {
|
|
|
18725
19180
|
));
|
|
18726
19181
|
for (const pos of positions) changes.set(`${pos.x},${pos.y},${pos.z}`, pos);
|
|
18727
19182
|
}
|
|
18728
|
-
if (performance.now() - sliceStart >
|
|
19183
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
18729
19184
|
await yieldToEventLoop();
|
|
18730
19185
|
sliceStart = performance.now();
|
|
18731
19186
|
}
|
|
@@ -18733,6 +19188,62 @@ var MineRenderWorld = class {
|
|
|
18733
19188
|
}
|
|
18734
19189
|
/** Replaces a chunk column's blocks, biomes, and saved light and, with `renderEntities`, its supported saved mobs. */
|
|
18735
19190
|
async placeChunk(chunk, executor) {
|
|
19191
|
+
return this.placeColumn(chunk, executor);
|
|
19192
|
+
}
|
|
19193
|
+
/**
|
|
19194
|
+
* Replaces parsed columns in input order, then refreshes neighboring geometry once.
|
|
19195
|
+
* Duplicate coordinates retain their order. A failed column stops placement; queued refreshes finish before rejection.
|
|
19196
|
+
*/
|
|
19197
|
+
async placeChunks(chunks) {
|
|
19198
|
+
const columns = [];
|
|
19199
|
+
for (const chunk of chunks) {
|
|
19200
|
+
const { x, z } = chunk ?? {};
|
|
19201
|
+
if (![x, z].every(Number.isSafeInteger)) {
|
|
19202
|
+
throw new RangeError("Chunk column coordinates must be safe integers");
|
|
19203
|
+
}
|
|
19204
|
+
const sections = Array.from(chunk.sections, (section) => {
|
|
19205
|
+
const { y } = section ?? {};
|
|
19206
|
+
if (!Number.isSafeInteger(y)) throw new RangeError("Chunk section coordinates must be safe integers");
|
|
19207
|
+
return { ...section, y };
|
|
19208
|
+
});
|
|
19209
|
+
columns.push({ ...chunk, x, z, sections });
|
|
19210
|
+
}
|
|
19211
|
+
if (!columns.length) return;
|
|
19212
|
+
await this.culling;
|
|
19213
|
+
let failed = false, failure, sliceStart = performance.now();
|
|
19214
|
+
try {
|
|
19215
|
+
for (const column of columns) {
|
|
19216
|
+
await this.placeColumn(column, void 0, true);
|
|
19217
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
19218
|
+
await yieldToEventLoop();
|
|
19219
|
+
sliceStart = performance.now();
|
|
19220
|
+
}
|
|
19221
|
+
}
|
|
19222
|
+
} catch (error) {
|
|
19223
|
+
failed = true;
|
|
19224
|
+
failure = error;
|
|
19225
|
+
} finally {
|
|
19226
|
+
try {
|
|
19227
|
+
const failures = await this.refreshBiomes(true);
|
|
19228
|
+
if (failures.size) log18.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
19229
|
+
} catch (error) {
|
|
19230
|
+
if (!failed) {
|
|
19231
|
+
failed = true;
|
|
19232
|
+
failure = error;
|
|
19233
|
+
}
|
|
19234
|
+
}
|
|
19235
|
+
try {
|
|
19236
|
+
await this.updateCulling([]);
|
|
19237
|
+
} catch (error) {
|
|
19238
|
+
if (!failed) {
|
|
19239
|
+
failed = true;
|
|
19240
|
+
failure = error;
|
|
19241
|
+
}
|
|
19242
|
+
}
|
|
19243
|
+
}
|
|
19244
|
+
if (failed) throw failure;
|
|
19245
|
+
}
|
|
19246
|
+
async placeColumn(chunk, executor, deferCulling = false) {
|
|
18736
19247
|
if (![chunk.x, chunk.z].every(Number.isSafeInteger)) {
|
|
18737
19248
|
throw new RangeError("Chunk column coordinates must be safe integers");
|
|
18738
19249
|
}
|
|
@@ -18794,7 +19305,7 @@ var MineRenderWorld = class {
|
|
|
18794
19305
|
} finally {
|
|
18795
19306
|
this.markSectionChanged(target);
|
|
18796
19307
|
}
|
|
18797
|
-
if (performance.now() - sliceStart >
|
|
19308
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
18798
19309
|
await yieldToEventLoop();
|
|
18799
19310
|
sliceStart = performance.now();
|
|
18800
19311
|
}
|
|
@@ -18817,9 +19328,12 @@ var MineRenderWorld = class {
|
|
|
18817
19328
|
await placeEntities?.();
|
|
18818
19329
|
} finally {
|
|
18819
19330
|
this.markBiomesChanged(chunk.x, chunk.z, void 0, false);
|
|
18820
|
-
|
|
18821
|
-
|
|
18822
|
-
|
|
19331
|
+
if (deferCulling) await this.updateCulling([...changes.values()], true);
|
|
19332
|
+
else {
|
|
19333
|
+
const failures = await this.refreshBiomes();
|
|
19334
|
+
if (failures.size) log18.warn("Failed to refresh biome colors", failures.values().next().value);
|
|
19335
|
+
await this.updateCulling([...changes.values()]);
|
|
19336
|
+
}
|
|
18823
19337
|
}
|
|
18824
19338
|
}
|
|
18825
19339
|
/**
|
|
@@ -18849,7 +19363,7 @@ var MineRenderWorld = class {
|
|
|
18849
19363
|
for (const { x, z } of columns.values()) {
|
|
18850
19364
|
this.entities?.clearColumn(x, z);
|
|
18851
19365
|
await this.clearChunkColumn(x, z);
|
|
18852
|
-
if (performance.now() - sliceStart >
|
|
19366
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
18853
19367
|
await yieldToEventLoop();
|
|
18854
19368
|
sliceStart = performance.now();
|
|
18855
19369
|
}
|
|
@@ -18988,15 +19502,25 @@ var MineRenderWorld = class {
|
|
|
18988
19502
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
18989
19503
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
18990
19504
|
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
18991
|
-
if (
|
|
19505
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
18992
19506
|
await yieldToEventLoop();
|
|
18993
19507
|
sliceStart = performance.now();
|
|
18994
19508
|
}
|
|
18995
19509
|
}
|
|
18996
|
-
const
|
|
18997
|
-
|
|
18998
|
-
|
|
18999
|
-
|
|
19510
|
+
const pending = [];
|
|
19511
|
+
for (const chunk of [...batch.keys()]) {
|
|
19512
|
+
const build = (async () => {
|
|
19513
|
+
await chunk.rebuildSectionMesh();
|
|
19514
|
+
batch.delete(chunk);
|
|
19515
|
+
})();
|
|
19516
|
+
void build.catch(() => void 0);
|
|
19517
|
+
pending.push(build);
|
|
19518
|
+
if (performance.now() - sliceStart > YIELD_INTERVAL_MS) {
|
|
19519
|
+
await yieldToEventLoop();
|
|
19520
|
+
sliceStart = performance.now();
|
|
19521
|
+
}
|
|
19522
|
+
}
|
|
19523
|
+
const builds = await Promise.allSettled(pending);
|
|
19000
19524
|
const failure = builds.find((result) => result.status === "rejected");
|
|
19001
19525
|
if (failure?.status === "rejected") throw failure.reason;
|
|
19002
19526
|
} catch (error) {
|
|
@@ -19113,7 +19637,7 @@ init_BlockEntities();
|
|
|
19113
19637
|
// src/world/SectionMesh.ts
|
|
19114
19638
|
init_CanvasCompat();
|
|
19115
19639
|
init_Materials();
|
|
19116
|
-
import { BufferGeometry as BufferGeometry9, Color as Color12, DoubleSide as DoubleSide8, Float32BufferAttribute as Float32BufferAttribute10, FrontSide as FrontSide4, Group as Group3, Mesh as Mesh12, Uint32BufferAttribute } from "three";
|
|
19640
|
+
import { BufferGeometry as BufferGeometry9, Color as Color12, DoubleSide as DoubleSide8, DynamicDrawUsage, Float32BufferAttribute as Float32BufferAttribute10, FrontSide as FrontSide4, Group as Group3, Matrix4 as Matrix413, Mesh as Mesh12, Uint32BufferAttribute, Vector3 as Vector320 } from "three";
|
|
19117
19641
|
|
|
19118
19642
|
// src/world/SectionGeometry.ts
|
|
19119
19643
|
init_FluidQuads();
|
|
@@ -19388,6 +19912,8 @@ function sectionGeometryTransferables(pages) {
|
|
|
19388
19912
|
|
|
19389
19913
|
// src/world/SectionWorker.ts
|
|
19390
19914
|
init_Env();
|
|
19915
|
+
init_log();
|
|
19916
|
+
var log19 = logger("SectionWorker");
|
|
19391
19917
|
var SectionWorker = class _SectionWorker {
|
|
19392
19918
|
constructor(worker) {
|
|
19393
19919
|
this.worker = worker;
|
|
@@ -19401,8 +19927,12 @@ var SectionWorker = class _SectionWorker {
|
|
|
19401
19927
|
if (reply.type === "pages") pending.resolve(reply.pages);
|
|
19402
19928
|
else pending.reject(new Error(reply.message));
|
|
19403
19929
|
});
|
|
19404
|
-
|
|
19405
|
-
|
|
19930
|
+
const fallBack = (message) => {
|
|
19931
|
+
log19.warn(`${message}, so sections build on the main thread`);
|
|
19932
|
+
this.fail(message);
|
|
19933
|
+
};
|
|
19934
|
+
worker.addEventListener("error", (event) => fallBack(event.message || "Section worker failed"));
|
|
19935
|
+
worker.addEventListener("messageerror", () => fallBack("Section worker message could not be deserialized"));
|
|
19406
19936
|
}
|
|
19407
19937
|
static {
|
|
19408
19938
|
this.initialized = false;
|
|
@@ -19440,6 +19970,9 @@ var SectionWorker = class _SectionWorker {
|
|
|
19440
19970
|
};
|
|
19441
19971
|
|
|
19442
19972
|
// src/world/SectionMesh.ts
|
|
19973
|
+
var BLOCK_SIZE = 16;
|
|
19974
|
+
var QUAD_VERTICES = 4;
|
|
19975
|
+
var QUAD_INDICES = 6;
|
|
19443
19976
|
var templateCache = /* @__PURE__ */ new WeakMap();
|
|
19444
19977
|
var WATER_TINT = new Color12(4159204).toArray();
|
|
19445
19978
|
function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
@@ -19476,8 +20009,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19476
20009
|
if (!data) {
|
|
19477
20010
|
const indices = template.geometry.getIndex();
|
|
19478
20011
|
const position = template.geometry.getAttribute("position");
|
|
19479
|
-
const quads = indices.count /
|
|
19480
|
-
if (indices.count %
|
|
20012
|
+
const quads = indices.count / QUAD_INDICES;
|
|
20013
|
+
if (indices.count % QUAD_INDICES !== 0 || position.count !== quads * QUAD_VERTICES) {
|
|
19481
20014
|
throw new RangeError("Section template geometry must hold four vertices and six indices per quad");
|
|
19482
20015
|
}
|
|
19483
20016
|
data = {
|
|
@@ -19487,8 +20020,8 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19487
20020
|
uvs: new Float32Array(quads * 8),
|
|
19488
20021
|
uvBounds: new Float32Array(quads * 16),
|
|
19489
20022
|
colors: new Float32Array(quads * 12),
|
|
19490
|
-
shade: new Float32Array(quads *
|
|
19491
|
-
indices: new Uint16Array(quads *
|
|
20023
|
+
shade: new Float32Array(quads * QUAD_VERTICES),
|
|
20024
|
+
indices: new Uint16Array(quads * QUAD_INDICES),
|
|
19492
20025
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
19493
20026
|
biomeTint: template.biomeTint ? new Uint8Array(template.biomeTint) : void 0,
|
|
19494
20027
|
atlas: 0,
|
|
@@ -19500,7 +20033,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19500
20033
|
const bounds = template.geometry.getAttribute("uvBounds");
|
|
19501
20034
|
const color2 = template.geometry.getAttribute("color");
|
|
19502
20035
|
const shade = template.geometry.getAttribute("shade");
|
|
19503
|
-
for (let vertex = 0; vertex < quads *
|
|
20036
|
+
for (let vertex = 0; vertex < quads * QUAD_VERTICES; vertex++) {
|
|
19504
20037
|
data.positions.set([position.getX(vertex), position.getY(vertex), position.getZ(vertex)], vertex * 3);
|
|
19505
20038
|
data.normals.set([normal.getX(vertex), normal.getY(vertex), normal.getZ(vertex)], vertex * 3);
|
|
19506
20039
|
data.uvs.set([uv.getX(vertex), uv.getY(vertex)], vertex * 2);
|
|
@@ -19513,7 +20046,7 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19513
20046
|
data.colors.set([color2?.getX(vertex) ?? 1, color2?.getY(vertex) ?? 1, color2?.getZ(vertex) ?? 1], vertex * 3);
|
|
19514
20047
|
data.shade[vertex] = shade?.getX(vertex) ?? 1;
|
|
19515
20048
|
}
|
|
19516
|
-
for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) -
|
|
20049
|
+
for (let i2 = 0; i2 < data.indices.length; i2++) data.indices[i2] = indices.getX(i2) - QUAD_VERTICES * Math.floor(i2 / QUAD_INDICES);
|
|
19517
20050
|
templateCache.set(template, data);
|
|
19518
20051
|
}
|
|
19519
20052
|
id = input.templateData.length;
|
|
@@ -19546,6 +20079,54 @@ function toInput(entries, maxAtlasSize, fluids, lighting) {
|
|
|
19546
20079
|
}
|
|
19547
20080
|
return { input, atlases: atlases2 };
|
|
19548
20081
|
}
|
|
20082
|
+
function sortTransparentQuads(mesh) {
|
|
20083
|
+
const index = mesh.geometry.getIndex();
|
|
20084
|
+
if (index.count <= QUAD_INDICES) return;
|
|
20085
|
+
index.setUsage(DynamicDrawUsage);
|
|
20086
|
+
const count = index.count / QUAD_INDICES;
|
|
20087
|
+
let source, centers, depths, order;
|
|
20088
|
+
const view = new Matrix413(), localCamera = new Vector320(), key = new Vector320(), previous = new Vector320();
|
|
20089
|
+
let previousOrthographic;
|
|
20090
|
+
mesh.onBeforeRender = (_renderer, _scene, camera) => {
|
|
20091
|
+
localCamera.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(view.copy(mesh.matrixWorld).invert());
|
|
20092
|
+
const orthographic = !!camera.isOrthographicCamera;
|
|
20093
|
+
if (orthographic) {
|
|
20094
|
+
view.multiplyMatrices(camera.matrixWorldInverse, mesh.matrixWorld);
|
|
20095
|
+
key.set(view.elements[2], view.elements[6], view.elements[10]);
|
|
20096
|
+
} else {
|
|
20097
|
+
key.copy(localCamera).divideScalar(BLOCK_SIZE).floor();
|
|
20098
|
+
}
|
|
20099
|
+
if (orthographic === previousOrthographic && key.equals(previous)) return;
|
|
20100
|
+
previous.copy(key);
|
|
20101
|
+
previousOrthographic = orthographic;
|
|
20102
|
+
if (!centers) {
|
|
20103
|
+
source = new Uint32Array(index.array);
|
|
20104
|
+
centers = new Float32Array(count * 3);
|
|
20105
|
+
depths = new Float32Array(count);
|
|
20106
|
+
order = Uint32Array.from({ length: count }, (_, quad) => quad);
|
|
20107
|
+
const positions = mesh.geometry.getAttribute("position");
|
|
20108
|
+
for (let quad = 0; quad < count; quad++) {
|
|
20109
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
20110
|
+
let center = 0;
|
|
20111
|
+
for (let corner = 0; corner < QUAD_VERTICES; corner++) center += positions.getComponent(quad * QUAD_VERTICES + corner, axis);
|
|
20112
|
+
centers[quad * 3 + axis] = center / QUAD_VERTICES;
|
|
20113
|
+
}
|
|
20114
|
+
}
|
|
20115
|
+
}
|
|
20116
|
+
for (let quad = 0; quad < count; quad++) {
|
|
20117
|
+
const x = centers[quad * 3], y = centers[quad * 3 + 1], z = centers[quad * 3 + 2];
|
|
20118
|
+
depths[quad] = orthographic ? key.x * x + key.y * y + key.z * z : -((x - localCamera.x) ** 2 + (y - localCamera.y) ** 2 + (z - localCamera.z) ** 2);
|
|
20119
|
+
}
|
|
20120
|
+
order.sort((a, b) => depths[a] - depths[b] || a - b);
|
|
20121
|
+
if (!order.some((quad, offset) => index.array[offset * QUAD_INDICES] !== source[quad * QUAD_INDICES])) return;
|
|
20122
|
+
for (let offset = 0; offset < count; offset++) {
|
|
20123
|
+
for (let indexOffset = 0; indexOffset < QUAD_INDICES; indexOffset++) {
|
|
20124
|
+
index.array[offset * QUAD_INDICES + indexOffset] = source[order[offset] * QUAD_INDICES + indexOffset];
|
|
20125
|
+
}
|
|
20126
|
+
}
|
|
20127
|
+
index.needsUpdate = true;
|
|
20128
|
+
};
|
|
20129
|
+
}
|
|
19549
20130
|
var SectionMesh = class _SectionMesh extends Group3 {
|
|
19550
20131
|
constructor() {
|
|
19551
20132
|
super(...arguments);
|
|
@@ -19555,7 +20136,11 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19555
20136
|
/** Returns the owning section cell for a triangle hit on this mesh's merged geometry. */
|
|
19556
20137
|
getBlockIndex(hit) {
|
|
19557
20138
|
if (hit.faceIndex === void 0 || hit.faceIndex === null) return void 0;
|
|
19558
|
-
|
|
20139
|
+
const mesh = hit.object;
|
|
20140
|
+
const owners = this.blockIndices.get(mesh);
|
|
20141
|
+
if (!owners) return void 0;
|
|
20142
|
+
const vertex = mesh.geometry.getIndex().getX(hit.faceIndex * 3);
|
|
20143
|
+
return owners[Math.floor(vertex / QUAD_VERTICES)];
|
|
19559
20144
|
}
|
|
19560
20145
|
/** Builds section-local meshes from visible quads. `maxAtlasSize` limits each atlas dimension in pixels. */
|
|
19561
20146
|
static build(entries, maxAtlasSize = 2048, fluids, lighting) {
|
|
@@ -19591,13 +20176,14 @@ var SectionMesh = class _SectionMesh extends Group3 {
|
|
|
19591
20176
|
const material = Materials.createShadedCanvasMaterial(canvas, transparent, false, true);
|
|
19592
20177
|
material.side = FrontSide4;
|
|
19593
20178
|
if (page.layer === 2) {
|
|
20179
|
+
material.depthWrite = !material.transparent;
|
|
19594
20180
|
material.side = DoubleSide8;
|
|
19595
20181
|
material.forceSinglePass = true;
|
|
19596
|
-
material.depthWrite = !material.transparent;
|
|
19597
20182
|
}
|
|
19598
20183
|
material.vertexColors = true;
|
|
19599
20184
|
const texture = material.uniforms?.map?.value ?? material.map;
|
|
19600
20185
|
const mesh = new Mesh12(geometry, material);
|
|
20186
|
+
if (transparent) sortTransparentQuads(mesh);
|
|
19601
20187
|
section.add(mesh);
|
|
19602
20188
|
section.blockIndices.set(mesh, page.blockIndices);
|
|
19603
20189
|
const unsubscribe = [];
|
|
@@ -19656,7 +20242,7 @@ var Chunk = class _Chunk {
|
|
|
19656
20242
|
this.sectionBlocks = /* @__PURE__ */ new Map();
|
|
19657
20243
|
this.hiddenBlocks = /* @__PURE__ */ new Set();
|
|
19658
20244
|
this.fluidCells = new Uint8Array(4096);
|
|
19659
|
-
this.blockPosition = new
|
|
20245
|
+
this.blockPosition = new Vector321();
|
|
19660
20246
|
this.meshDirty = false;
|
|
19661
20247
|
this.meshGeneration = 0;
|
|
19662
20248
|
this.blockChanges = /* @__PURE__ */ new Set();
|
|
@@ -19716,7 +20302,7 @@ var Chunk = class _Chunk {
|
|
|
19716
20302
|
const info = owner.chunk.renderedBlocks.get(owner.index);
|
|
19717
20303
|
if (!info) continue;
|
|
19718
20304
|
return {
|
|
19719
|
-
position: new
|
|
20305
|
+
position: new Vector321(
|
|
19720
20306
|
owner.chunk.x * 16 + owner.index % 16,
|
|
19721
20307
|
owner.chunk.y * 16 + Math.floor(owner.index / 256),
|
|
19722
20308
|
owner.chunk.z * 16 + Math.floor(owner.index / 16) % 16
|
|
@@ -19731,18 +20317,18 @@ var Chunk = class _Chunk {
|
|
|
19731
20317
|
}
|
|
19732
20318
|
getBlockAt(posOrX, y, z) {
|
|
19733
20319
|
if (typeof posOrX == "number") {
|
|
19734
|
-
return this.getBlockAt(new
|
|
20320
|
+
return this.getBlockAt(new Vector321(posOrX, y, z));
|
|
19735
20321
|
}
|
|
19736
20322
|
if (isTripleArray(posOrX)) {
|
|
19737
|
-
return this.getBlockAt(new
|
|
20323
|
+
return this.getBlockAt(new Vector321(posOrX[0], posOrX[1], posOrX[2]));
|
|
19738
20324
|
}
|
|
19739
20325
|
const pos = this.blockPosition.set(posOrX.x - this.x * 16, posOrX.y - this.y * 16, posOrX.z - this.z * 16);
|
|
19740
20326
|
const index = _Chunk.chunkPosToBlockIndex(pos);
|
|
19741
20327
|
return this.renderedBlocks.get(index);
|
|
19742
20328
|
}
|
|
19743
20329
|
getBiomeAt(posOrX, y, z) {
|
|
19744
|
-
if (typeof posOrX === "number") return this.getBiomeAt(new
|
|
19745
|
-
if (isTripleArray(posOrX)) return this.getBiomeAt(new
|
|
20330
|
+
if (typeof posOrX === "number") return this.getBiomeAt(new Vector321(posOrX, y, z));
|
|
20331
|
+
if (isTripleArray(posOrX)) return this.getBiomeAt(new Vector321(...posOrX));
|
|
19746
20332
|
const pos = this.worldPosToChunkPos(posOrX);
|
|
19747
20333
|
_Chunk.chunkPosToBlockIndex(pos);
|
|
19748
20334
|
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];
|
|
@@ -19820,17 +20406,17 @@ var Chunk = class _Chunk {
|
|
|
19820
20406
|
this.hiddenBlocks.add(index);
|
|
19821
20407
|
this.renderedBlocks.get(index)?.object?.setVisible(false);
|
|
19822
20408
|
}
|
|
19823
|
-
const positions = blocks.map(({ index }) => new
|
|
20409
|
+
const positions = blocks.map(({ index }) => new Vector321(...this.positionAt(index)));
|
|
19824
20410
|
if (this.onBlocksChanged) await this.onBlocksChanged(positions, deferCulling);
|
|
19825
20411
|
else await this.rebuildSectionMesh();
|
|
19826
20412
|
}
|
|
19827
20413
|
}
|
|
19828
20414
|
async setBlockAt(posOrX, yOrBlock, z, block) {
|
|
19829
20415
|
if (typeof posOrX == "number") {
|
|
19830
|
-
return this.setBlockAt(new
|
|
20416
|
+
return this.setBlockAt(new Vector321(posOrX, yOrBlock, z), block);
|
|
19831
20417
|
}
|
|
19832
20418
|
if (isTripleArray(posOrX)) {
|
|
19833
|
-
return this.setBlockAt(new
|
|
20419
|
+
return this.setBlockAt(new Vector321(posOrX[0], posOrX[1], posOrX[2]), yOrBlock);
|
|
19834
20420
|
}
|
|
19835
20421
|
const worldPos = posOrX;
|
|
19836
20422
|
const pos = this.worldPosToChunkPos(worldPos);
|
|
@@ -19892,8 +20478,10 @@ var Chunk = class _Chunk {
|
|
|
19892
20478
|
if (rejected?.status === "rejected") throw rejected.reason;
|
|
19893
20479
|
}
|
|
19894
20480
|
const positions = [];
|
|
19895
|
-
|
|
19896
|
-
|
|
20481
|
+
const jobs = /* @__PURE__ */ new Map();
|
|
20482
|
+
let failureOrder = Infinity, failure;
|
|
20483
|
+
for (const [order, { index, key, block }] of placements.entries()) {
|
|
20484
|
+
jobs.delete(index);
|
|
19897
20485
|
this.hiddenBlocks.delete(index);
|
|
19898
20486
|
this.data.assign(index, this.data.intern(block), block?.nbt);
|
|
19899
20487
|
const readBlock = this.data.snapshot(index);
|
|
@@ -19903,13 +20491,12 @@ var Chunk = class _Chunk {
|
|
|
19903
20491
|
this.fluidCells[index] = 0;
|
|
19904
20492
|
this.renderedBlocks.delete(index);
|
|
19905
20493
|
this.objectBlocks.delete(index);
|
|
19906
|
-
const worldPos = new
|
|
20494
|
+
const worldPos = new Vector321(
|
|
19907
20495
|
this.x * 16 + index % 16,
|
|
19908
20496
|
this.y * 16 + Math.floor(index / 256),
|
|
19909
20497
|
this.z * 16 + Math.floor(index / 16) % 16
|
|
19910
20498
|
);
|
|
19911
20499
|
positions.push(worldPos);
|
|
19912
|
-
let object4;
|
|
19913
20500
|
try {
|
|
19914
20501
|
if (!readBlock) continue;
|
|
19915
20502
|
const resolved = resolutions.get(key);
|
|
@@ -19931,7 +20518,7 @@ var Chunk = class _Chunk {
|
|
|
19931
20518
|
this.sectionBlocks.set(index, templates.map((template) => ({ index, template, cullMask: 0, biomeTint: context?.tint })));
|
|
19932
20519
|
this.meshDirty = true;
|
|
19933
20520
|
} else {
|
|
19934
|
-
|
|
20521
|
+
jobs.set(index, { order, readBlock, blockState: blockState3, position: MineRenderWorld.worldToScenePosition(worldPos), options: {
|
|
19935
20522
|
mergeMeshes: true,
|
|
19936
20523
|
instanceMeshes: true,
|
|
19937
20524
|
maxInstanceCount: 2e3,
|
|
@@ -19939,13 +20526,12 @@ var Chunk = class _Chunk {
|
|
|
19939
20526
|
variantPosition,
|
|
19940
20527
|
biome: context?.biome,
|
|
19941
20528
|
biomePosition: this.biomePosition(index, blockState3, stored)
|
|
19942
|
-
});
|
|
19943
|
-
|
|
20529
|
+
} });
|
|
20530
|
+
continue;
|
|
19944
20531
|
}
|
|
19945
20532
|
this.renderedBlocks.set(index, { get block() {
|
|
19946
20533
|
return readBlock();
|
|
19947
|
-
}, object:
|
|
19948
|
-
if (object4) this.objectBlocks.add(index);
|
|
20534
|
+
}, object: void 0 });
|
|
19949
20535
|
} catch (error) {
|
|
19950
20536
|
if (preserveDataOnFailure && readBlock) {
|
|
19951
20537
|
this.renderedBlocks.set(index, { get block() {
|
|
@@ -19953,12 +20539,35 @@ var Chunk = class _Chunk {
|
|
|
19953
20539
|
}, object: void 0 });
|
|
19954
20540
|
} else this.data.assign(index, 0);
|
|
19955
20541
|
this.fluidCells[index] = 0;
|
|
19956
|
-
|
|
19957
|
-
|
|
19958
|
-
|
|
20542
|
+
if (order < failureOrder) {
|
|
20543
|
+
failureOrder = order;
|
|
20544
|
+
failure = error;
|
|
20545
|
+
}
|
|
19959
20546
|
}
|
|
19960
20547
|
}
|
|
19961
|
-
|
|
20548
|
+
const pending = [...jobs];
|
|
20549
|
+
const objects = await Promise.allSettled(pending.map(([, job]) => this.createBlockObject(job.blockState, job.position, job.options)));
|
|
20550
|
+
for (const [i, [index, { order, readBlock }]] of pending.entries()) {
|
|
20551
|
+
const result = objects[i];
|
|
20552
|
+
if (result.status === "fulfilled") {
|
|
20553
|
+
this.renderedBlocks.set(index, { get block() {
|
|
20554
|
+
return readBlock();
|
|
20555
|
+
}, object: result.value });
|
|
20556
|
+
this.objectBlocks.add(index);
|
|
20557
|
+
} else {
|
|
20558
|
+
if (preserveDataOnFailure) {
|
|
20559
|
+
this.renderedBlocks.set(index, { get block() {
|
|
20560
|
+
return readBlock();
|
|
20561
|
+
}, object: void 0 });
|
|
20562
|
+
} else this.data.assign(index, 0);
|
|
20563
|
+
this.fluidCells[index] = 0;
|
|
20564
|
+
if (order < failureOrder) {
|
|
20565
|
+
failureOrder = order;
|
|
20566
|
+
failure = result.reason;
|
|
20567
|
+
}
|
|
20568
|
+
}
|
|
20569
|
+
}
|
|
20570
|
+
if (failureOrder < Infinity) throw failure;
|
|
19962
20571
|
return positions;
|
|
19963
20572
|
}
|
|
19964
20573
|
/** Replaces every cell from parsed section data. The caller refreshes neighbor culling. */
|
|
@@ -20029,37 +20638,42 @@ var Chunk = class _Chunk {
|
|
|
20029
20638
|
failed = true;
|
|
20030
20639
|
}
|
|
20031
20640
|
}
|
|
20032
|
-
|
|
20033
|
-
|
|
20034
|
-
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20038
|
-
|
|
20039
|
-
|
|
20040
|
-
|
|
20041
|
-
|
|
20042
|
-
|
|
20043
|
-
|
|
20044
|
-
|
|
20045
|
-
|
|
20046
|
-
|
|
20047
|
-
|
|
20048
|
-
)
|
|
20049
|
-
this.renderedBlocks.get(index).object = object4;
|
|
20641
|
+
const objects = await Promise.allSettled(perBlocks.map(({ index, blockState: blockState3, biome }) => this.createBlockObject(blockState3, new Vector321(
|
|
20642
|
+
this.x * 256 + index % 16 * 16,
|
|
20643
|
+
this.y * 256 + Math.floor(index / 256) * 16,
|
|
20644
|
+
this.z * 256 + Math.floor(index / 16) % 16 * 16
|
|
20645
|
+
), {
|
|
20646
|
+
mergeMeshes: true,
|
|
20647
|
+
instanceMeshes: true,
|
|
20648
|
+
maxInstanceCount: 2e3,
|
|
20649
|
+
initialState: this.data.stateAt(this.data.idAt(index)).properties,
|
|
20650
|
+
variantPosition: this.positionAt(index),
|
|
20651
|
+
biome,
|
|
20652
|
+
biomePosition: this.biomePosition(index, blockState3, this.data.stateAt(this.data.idAt(index)))
|
|
20653
|
+
})));
|
|
20654
|
+
for (const [i, { index }] of perBlocks.entries()) {
|
|
20655
|
+
const result = objects[i];
|
|
20656
|
+
if (result.status === "fulfilled") {
|
|
20657
|
+
this.renderedBlocks.get(index).object = result.value;
|
|
20050
20658
|
this.objectBlocks.add(index);
|
|
20051
|
-
}
|
|
20659
|
+
} else {
|
|
20052
20660
|
this.data.assign(index, 0);
|
|
20053
20661
|
this.fluidCells[index] = 0;
|
|
20054
20662
|
this.renderedBlocks.delete(index);
|
|
20055
20663
|
this.objectBlocks.delete(index);
|
|
20056
|
-
|
|
20057
|
-
if (!failed) failure = error;
|
|
20664
|
+
if (!failed) failure = result.reason;
|
|
20058
20665
|
failed = true;
|
|
20059
20666
|
}
|
|
20060
20667
|
}
|
|
20061
20668
|
if (failed) throw failure;
|
|
20062
20669
|
}
|
|
20670
|
+
createBlockObject(blockState3, position, options) {
|
|
20671
|
+
return this.scene.addSceneObject(blockState3, () => {
|
|
20672
|
+
const object4 = new BlockObject(blockState3, options);
|
|
20673
|
+
object4.position.copy(position);
|
|
20674
|
+
return object4;
|
|
20675
|
+
}, options);
|
|
20676
|
+
}
|
|
20063
20677
|
positionAt(index) {
|
|
20064
20678
|
return [this.x * 16 + index % 16, this.y * 16 + Math.floor(index / 256), this.z * 16 + Math.floor(index / 16) % 16];
|
|
20065
20679
|
}
|
|
@@ -20348,7 +20962,7 @@ var Chunk = class _Chunk {
|
|
|
20348
20962
|
async clear(notify = true) {
|
|
20349
20963
|
if (this.blockChanges.size) await Promise.allSettled(this.blockChanges);
|
|
20350
20964
|
const positions = notify && this.onBlocksChanged ? [...this.renderedBlocks.keys()].map((index) => this.chunkPosToWorldPos(
|
|
20351
|
-
new
|
|
20965
|
+
new Vector321(index % 16, Math.floor(index / 256), Math.floor(index / 16) % 16)
|
|
20352
20966
|
)) : [];
|
|
20353
20967
|
for (const info of this.renderedBlocks.values()) info.object?.removeFromScene();
|
|
20354
20968
|
this.sectionBlocks.clear();
|
|
@@ -20384,14 +20998,14 @@ var Chunk = class _Chunk {
|
|
|
20384
20998
|
return pos.y * 16 * 16 + pos.z * 16 + pos.x;
|
|
20385
20999
|
}
|
|
20386
21000
|
worldPosToChunkPos(pos) {
|
|
20387
|
-
return new
|
|
21001
|
+
return new Vector321(
|
|
20388
21002
|
pos.x - this.x * 16,
|
|
20389
21003
|
pos.y - this.y * 16,
|
|
20390
21004
|
pos.z - this.z * 16
|
|
20391
21005
|
);
|
|
20392
21006
|
}
|
|
20393
21007
|
chunkPosToWorldPos(pos) {
|
|
20394
|
-
return new
|
|
21008
|
+
return new Vector321(
|
|
20395
21009
|
this.x * 16 + pos.x,
|
|
20396
21010
|
this.y * 16 + pos.y,
|
|
20397
21011
|
this.z * 16 + pos.z
|
|
@@ -20400,6 +21014,7 @@ var Chunk = class _Chunk {
|
|
|
20400
21014
|
};
|
|
20401
21015
|
|
|
20402
21016
|
// src/world/WorldStreamer.ts
|
|
21017
|
+
var MAX_PREFETCHED_COLUMNS = 4;
|
|
20403
21018
|
var WorldStreamer = class {
|
|
20404
21019
|
constructor(world, source, options = {}) {
|
|
20405
21020
|
this.world = world;
|
|
@@ -20409,6 +21024,7 @@ var WorldStreamer = class {
|
|
|
20409
21024
|
this.missing = /* @__PURE__ */ new Map();
|
|
20410
21025
|
this.failed = /* @__PURE__ */ new Map();
|
|
20411
21026
|
this.desired = [];
|
|
21027
|
+
this.reads = /* @__PURE__ */ new Map();
|
|
20412
21028
|
this.disposed = false;
|
|
20413
21029
|
this.loadRadius = options.loadRadius ?? 2;
|
|
20414
21030
|
this.unloadRadius = options.unloadRadius ?? Math.min(32, this.loadRadius + 1);
|
|
@@ -20453,6 +21069,12 @@ var WorldStreamer = class {
|
|
|
20453
21069
|
if (this.loading && !this.within(this.loading.position, this.loadRadius)) {
|
|
20454
21070
|
this.loading.controller.abort();
|
|
20455
21071
|
}
|
|
21072
|
+
for (const [key, read] of this.reads) {
|
|
21073
|
+
if (!this.within(read.position, this.loadRadius)) {
|
|
21074
|
+
read.controller.abort();
|
|
21075
|
+
if (read.ready) this.reads.delete(key);
|
|
21076
|
+
}
|
|
21077
|
+
}
|
|
20456
21078
|
}
|
|
20457
21079
|
return this.running ??= Promise.resolve().then(() => this.drain());
|
|
20458
21080
|
}
|
|
@@ -20473,8 +21095,11 @@ var WorldStreamer = class {
|
|
|
20473
21095
|
this.desired = [];
|
|
20474
21096
|
this.center = void 0;
|
|
20475
21097
|
this.loading?.controller.abort();
|
|
21098
|
+
for (const read of this.reads.values()) read.controller.abort();
|
|
20476
21099
|
return this.disposal ??= Promise.resolve().then(async () => {
|
|
20477
21100
|
await this.running?.catch(() => void 0);
|
|
21101
|
+
await Promise.all([...this.reads.values()].map((read) => read.promise));
|
|
21102
|
+
this.reads.clear();
|
|
20478
21103
|
try {
|
|
20479
21104
|
await this.unloadMany([...this.owned.values()]);
|
|
20480
21105
|
} finally {
|
|
@@ -20500,6 +21125,10 @@ var WorldStreamer = class {
|
|
|
20500
21125
|
await this.unloadMany(obsolete);
|
|
20501
21126
|
continue;
|
|
20502
21127
|
}
|
|
21128
|
+
if (this.world.placeChunks) {
|
|
21129
|
+
if (await this.placeReadyChunks()) continue;
|
|
21130
|
+
return;
|
|
21131
|
+
}
|
|
20503
21132
|
const position = this.desired.find((position2) => this.needsLoad(position2));
|
|
20504
21133
|
if (!position) return;
|
|
20505
21134
|
let chunk;
|
|
@@ -20522,26 +21151,105 @@ var WorldStreamer = class {
|
|
|
20522
21151
|
continue;
|
|
20523
21152
|
}
|
|
20524
21153
|
this.owned.set(this.key(position), position);
|
|
21154
|
+
await this.placeOwnedColumns([position], () => this.world.placeChunk(chunk));
|
|
21155
|
+
}
|
|
21156
|
+
} finally {
|
|
21157
|
+
for (const [key, read] of this.reads) {
|
|
21158
|
+
read.controller.abort();
|
|
21159
|
+
if (read.ready) this.reads.delete(key);
|
|
21160
|
+
}
|
|
21161
|
+
this.running = void 0;
|
|
21162
|
+
}
|
|
21163
|
+
}
|
|
21164
|
+
fillReadSlots() {
|
|
21165
|
+
while (!this.disposed && this.reads.size < MAX_PREFETCHED_COLUMNS) {
|
|
21166
|
+
const position = this.desired.find((position2) => this.needsLoad(position2) && !this.reads.has(this.key(position2)));
|
|
21167
|
+
if (!position) return;
|
|
21168
|
+
const key = this.key(position);
|
|
21169
|
+
const read = {
|
|
21170
|
+
position,
|
|
21171
|
+
controller: new AbortController(),
|
|
21172
|
+
promise: Promise.resolve(),
|
|
21173
|
+
ready: false,
|
|
21174
|
+
failed: false
|
|
21175
|
+
};
|
|
21176
|
+
this.reads.set(key, read);
|
|
21177
|
+
read.promise = (async () => {
|
|
20525
21178
|
try {
|
|
20526
|
-
await this.
|
|
20527
|
-
this.
|
|
21179
|
+
read.chunk = await this.source.getChunk(position.x, position.z, read.controller.signal);
|
|
21180
|
+
if (read.chunk) this.validateChunk(read.chunk, position);
|
|
20528
21181
|
} catch (error) {
|
|
20529
|
-
|
|
20530
|
-
|
|
20531
|
-
|
|
20532
|
-
|
|
20533
|
-
|
|
20534
|
-
|
|
20535
|
-
} catch {
|
|
20536
|
-
throw Object.assign(new Error(failure.message), { cause: cleanupError });
|
|
20537
|
-
}
|
|
20538
|
-
throw failure;
|
|
21182
|
+
read.failed = true;
|
|
21183
|
+
read.error = error;
|
|
21184
|
+
} finally {
|
|
21185
|
+
read.ready = true;
|
|
21186
|
+
if (read.controller.signal.aborted || this.disposed || !this.within(position, this.loadRadius)) {
|
|
21187
|
+
this.reads.delete(key);
|
|
20539
21188
|
}
|
|
20540
|
-
|
|
21189
|
+
}
|
|
21190
|
+
})();
|
|
21191
|
+
}
|
|
21192
|
+
}
|
|
21193
|
+
/** Places only the ready prefix, so later source reads cannot delay the nearest ready column. */
|
|
21194
|
+
async placeReadyChunks() {
|
|
21195
|
+
this.fillReadSlots();
|
|
21196
|
+
const position = this.desired.find((position2) => this.needsLoad(position2));
|
|
21197
|
+
if (!position) {
|
|
21198
|
+
if (!this.reads.size) return false;
|
|
21199
|
+
await Promise.all([...this.reads.values()].map((read) => read.promise));
|
|
21200
|
+
return true;
|
|
21201
|
+
}
|
|
21202
|
+
const head = this.reads.get(this.key(position));
|
|
21203
|
+
if (!head) {
|
|
21204
|
+
for (let index = this.desired.length - 1; index >= 0; index--) {
|
|
21205
|
+
const key = this.key(this.desired[index]);
|
|
21206
|
+
if (this.reads.get(key)?.ready) {
|
|
21207
|
+
this.reads.delete(key);
|
|
21208
|
+
return true;
|
|
20541
21209
|
}
|
|
20542
21210
|
}
|
|
20543
|
-
|
|
20544
|
-
|
|
21211
|
+
await Promise.race([...this.reads.values()].map((read) => read.promise));
|
|
21212
|
+
return true;
|
|
21213
|
+
}
|
|
21214
|
+
if (!head.ready) {
|
|
21215
|
+
await head.promise;
|
|
21216
|
+
return true;
|
|
21217
|
+
}
|
|
21218
|
+
const chunks = [], positions = [];
|
|
21219
|
+
for (const desired of this.desired) {
|
|
21220
|
+
if (!this.needsLoad(desired)) continue;
|
|
21221
|
+
const key = this.key(desired), read = this.reads.get(key);
|
|
21222
|
+
if (!read?.ready) break;
|
|
21223
|
+
this.reads.delete(key);
|
|
21224
|
+
if (read.failed) this.failed.set(key, { ...desired, error: read.error });
|
|
21225
|
+
else if (!read.chunk) this.missing.set(key, desired);
|
|
21226
|
+
else {
|
|
21227
|
+
chunks.push(read.chunk);
|
|
21228
|
+
positions.push(desired);
|
|
21229
|
+
}
|
|
21230
|
+
}
|
|
21231
|
+
if (!chunks.length) return true;
|
|
21232
|
+
for (const position2 of positions) this.owned.set(this.key(position2), position2);
|
|
21233
|
+
await this.placeOwnedColumns(positions, () => this.world.placeChunks(chunks));
|
|
21234
|
+
return true;
|
|
21235
|
+
}
|
|
21236
|
+
async placeOwnedColumns(positions, place) {
|
|
21237
|
+
try {
|
|
21238
|
+
await place();
|
|
21239
|
+
for (const position of positions) this.loaded.set(this.key(position), position);
|
|
21240
|
+
} catch (error) {
|
|
21241
|
+
try {
|
|
21242
|
+
await this.unloadMany(positions);
|
|
21243
|
+
} catch (cleanupError) {
|
|
21244
|
+
const failure = error instanceof Error ? error : new Error(String(error));
|
|
21245
|
+
try {
|
|
21246
|
+
Object.defineProperty(failure, "cause", { value: cleanupError, configurable: true });
|
|
21247
|
+
} catch {
|
|
21248
|
+
throw Object.assign(new Error(failure.message), { cause: cleanupError });
|
|
21249
|
+
}
|
|
21250
|
+
throw failure;
|
|
21251
|
+
}
|
|
21252
|
+
throw error;
|
|
20545
21253
|
}
|
|
20546
21254
|
}
|
|
20547
21255
|
needsLoad(position) {
|
|
@@ -20742,6 +21450,7 @@ export {
|
|
|
20742
21450
|
AnvilParser,
|
|
20743
21451
|
AnvilWorldSource,
|
|
20744
21452
|
ArchiveAssetSource,
|
|
21453
|
+
Armor,
|
|
20745
21454
|
AssetKey,
|
|
20746
21455
|
AssetLoadError,
|
|
20747
21456
|
AssetLoader,
|
|
@@ -20825,6 +21534,7 @@ export {
|
|
|
20825
21534
|
OrbitControls,
|
|
20826
21535
|
PackFormats,
|
|
20827
21536
|
PackMetadata,
|
|
21537
|
+
PalettedTextures,
|
|
20828
21538
|
PersistentCache,
|
|
20829
21539
|
PlayerHeadTextures,
|
|
20830
21540
|
Renames,
|