minerender 2.1.0-alpha.77 → 2.1.0-alpha.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/index.d.mts +85 -7
- package/dist/browser/index.d.ts +85 -7
- package/dist/browser/index.js +364 -43
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +364 -43
- package/dist/browser/index.mjs.map +1 -1
- package/dist/bundle.js +364 -43
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +85 -7
- package/dist/node/index.d.ts +85 -7
- package/dist/node/index.js +365 -43
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +364 -43
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -43053,6 +43053,8 @@ void main() {
|
|
|
43053
43053
|
ModelMerger = class {
|
|
43054
43054
|
/** Loads the parent chain and returns a merged model without modifying the supplied definition. */
|
|
43055
43055
|
static async mergeWithParents(model) {
|
|
43056
|
+
const parts = model.parts;
|
|
43057
|
+
if (parts) return { ...model, parts: await Promise.all(parts.map((part) => this.mergeWithParents(part))) };
|
|
43056
43058
|
const models = await this.collectAllParents(model);
|
|
43057
43059
|
let merged = {};
|
|
43058
43060
|
for (const source of [...models, model]) {
|
|
@@ -43119,6 +43121,7 @@ void main() {
|
|
|
43119
43121
|
init_PersistentCache();
|
|
43120
43122
|
init_AssetKey();
|
|
43121
43123
|
init_AssetParsers();
|
|
43124
|
+
init_DisplayPosition();
|
|
43122
43125
|
Models = class _Models {
|
|
43123
43126
|
// opened lazily: touching the store at import time would hit IndexedDB/disk just for loading
|
|
43124
43127
|
// the library, and would require an EnvProvider before any entry has had a chance to register
|
|
@@ -43133,34 +43136,174 @@ void main() {
|
|
|
43133
43136
|
return (await AssetLoader.getFirst([key, legacyKey], "list" /* LIST */))?.asset;
|
|
43134
43137
|
}).then((r5) => r5?.files ?? []);
|
|
43135
43138
|
}
|
|
43136
|
-
static async loadAndMerge(key) {
|
|
43137
|
-
const model = key.type === "item" ? await this.getItemModel(key) : await this.getRaw(key);
|
|
43139
|
+
static async loadAndMerge(key, context = {}) {
|
|
43140
|
+
const model = key.type === "item" ? await this.getItemModel(key, context) : await this.getRaw(key);
|
|
43138
43141
|
if (!model) {
|
|
43139
43142
|
return void 0;
|
|
43140
43143
|
}
|
|
43141
43144
|
return ModelMerger.mergeWithParents(model);
|
|
43142
43145
|
}
|
|
43143
|
-
static async getItemModel(key) {
|
|
43146
|
+
static async getItemModel(key, context = {}) {
|
|
43147
|
+
const preview = this.snapshotContext(key, context);
|
|
43144
43148
|
const itemKey = new AssetKey(key.namespace, key.path, "items", void 0, key.rootType, ".json", key.root);
|
|
43145
|
-
const
|
|
43149
|
+
const cacheKey = itemKey.serialize() + this.contextKey(preview);
|
|
43150
|
+
const model = await this.PERSISTENT_CACHE.getOrLoad(`item-v3:${AssetLoader.persistentKey(cacheKey)}`, async () => {
|
|
43146
43151
|
const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
|
|
43147
43152
|
if (!result) return void 0;
|
|
43148
43153
|
if (result.key.assetType !== "items") return { ...result.asset, key };
|
|
43149
|
-
const
|
|
43150
|
-
|
|
43151
|
-
|
|
43152
|
-
|
|
43153
|
-
|
|
43154
|
-
|
|
43154
|
+
const load = async (selected) => {
|
|
43155
|
+
if ("parts" in selected) {
|
|
43156
|
+
return { key, parts: await Promise.all(selected.parts.map(load)) };
|
|
43157
|
+
}
|
|
43158
|
+
if ("item" in selected) {
|
|
43159
|
+
const model3 = await this.getItemModel(selected.item, { displayContext: preview.displayContext });
|
|
43160
|
+
if (!model3) throw new Error(`Item ${key.toNamespacedString()} references missing item ${selected.item.toNamespacedString()}`);
|
|
43161
|
+
return model3;
|
|
43162
|
+
}
|
|
43163
|
+
const modelKey = AssetKey.parse("models", selected.model);
|
|
43164
|
+
modelKey.root = key.root;
|
|
43165
|
+
const model2 = await this.getRaw(modelKey);
|
|
43166
|
+
if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${selected.model}`);
|
|
43167
|
+
return { ...model2, ...selected.special && { special: selected.special }, ...selected.tints && { tints: selected.tints } };
|
|
43168
|
+
};
|
|
43169
|
+
return load(this.selectItemModel(result.asset.model, key, preview));
|
|
43170
|
+
});
|
|
43171
|
+
const restore = (model2) => ({
|
|
43172
|
+
...model2,
|
|
43173
|
+
key: Object.assign(new AssetKey("", ""), model2.key),
|
|
43174
|
+
...model2.parts && { parts: model2.parts.map(restore) }
|
|
43155
43175
|
});
|
|
43156
|
-
return model ?
|
|
43176
|
+
return model ? restore(model) : void 0;
|
|
43177
|
+
}
|
|
43178
|
+
static contextIdentifier(id) {
|
|
43179
|
+
if (typeof id !== "string" || !/^(?:[a-z0-9_.-]+:)?[a-z0-9_./-]+$/.test(id)) {
|
|
43180
|
+
throw new Error(`Invalid item-preview identifier: ${id}`);
|
|
43181
|
+
}
|
|
43182
|
+
return id.includes(":") ? id : `minecraft:${id}`;
|
|
43183
|
+
}
|
|
43184
|
+
static snapshotContext(key, context) {
|
|
43185
|
+
const displayContext = context.displayContext ?? "gui" /* GUI */;
|
|
43186
|
+
if (displayContext !== "none" && !Object.values(DisplayPosition).includes(displayContext)) {
|
|
43187
|
+
throw new Error(`Unsupported item display context: ${displayContext}`);
|
|
43188
|
+
}
|
|
43189
|
+
for (const map of [context.properties, context.components, context.itemReferences]) {
|
|
43190
|
+
if (map !== void 0 && (!map || typeof map !== "object" || Array.isArray(map))) {
|
|
43191
|
+
throw new Error("Item-preview properties, components, and references must be objects keyed by identifier");
|
|
43192
|
+
}
|
|
43193
|
+
}
|
|
43194
|
+
const count = context.count === void 0 ? 1 : context.count;
|
|
43195
|
+
if (!Number.isSafeInteger(count) || count < 0) throw new Error("Item-preview count must be a nonnegative safe integer");
|
|
43196
|
+
const properties = {};
|
|
43197
|
+
for (const [id, value] of Object.entries(context.properties ?? {})) {
|
|
43198
|
+
const property = this.contextIdentifier(id);
|
|
43199
|
+
if (!["boolean", "string", "number"].includes(typeof value) || typeof value === "number" && !Number.isFinite(value)) {
|
|
43200
|
+
throw new Error(`Item-preview property ${property} must be a boolean, string, or finite number`);
|
|
43201
|
+
}
|
|
43202
|
+
if (Object.prototype.hasOwnProperty.call(properties, property)) throw new Error(`Duplicate item-preview property: ${property}`);
|
|
43203
|
+
properties[property] = value;
|
|
43204
|
+
}
|
|
43205
|
+
const components = {};
|
|
43206
|
+
for (const [id, value] of Object.entries(context.components ?? {})) {
|
|
43207
|
+
const component = this.contextIdentifier(id);
|
|
43208
|
+
if (Object.prototype.hasOwnProperty.call(components, component)) throw new Error(`Duplicate item-preview component: ${component}`);
|
|
43209
|
+
components[component] = this.snapshotJson(value);
|
|
43210
|
+
}
|
|
43211
|
+
const itemReferences = {};
|
|
43212
|
+
for (const [id, value] of Object.entries(context.itemReferences ?? {})) {
|
|
43213
|
+
const reference = this.contextIdentifier(id);
|
|
43214
|
+
if (!isAssetKey(value) || value.assetType !== "models" || value.type !== "item") {
|
|
43215
|
+
throw new Error(`Item-preview reference ${reference} must be an item-model AssetKey`);
|
|
43216
|
+
}
|
|
43217
|
+
this.contextIdentifier(`${value.namespace}:${value.path}`);
|
|
43218
|
+
if (Object.prototype.hasOwnProperty.call(itemReferences, reference)) throw new Error(`Duplicate item-preview reference: ${reference}`);
|
|
43219
|
+
itemReferences[reference] = Object.assign(new AssetKey("", ""), value, { root: value.root ?? key.root });
|
|
43220
|
+
}
|
|
43221
|
+
return { displayContext, properties, components, count, itemReferences };
|
|
43222
|
+
}
|
|
43223
|
+
static contextKey(context) {
|
|
43224
|
+
const itemReferences = Object.fromEntries(Object.entries(context.itemReferences).map(([id, key]) => [id, key.serialize()]));
|
|
43225
|
+
return `|item-v3:${JSON.stringify(this.snapshotJson({ ...context, itemReferences }))}`;
|
|
43226
|
+
}
|
|
43227
|
+
static snapshotJson(value, ancestors = /* @__PURE__ */ new Set()) {
|
|
43228
|
+
if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return value;
|
|
43229
|
+
if (typeof value !== "object" || ancestors.has(value) || !Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
43230
|
+
throw new Error("Item-preview components must contain finite JSON values without circular references");
|
|
43231
|
+
}
|
|
43232
|
+
ancestors.add(value);
|
|
43233
|
+
const copy = Array.isArray(value) ? Array.from(value, (entry) => this.snapshotJson(entry, ancestors)) : Object.fromEntries(Object.keys(value).sort().map((key) => [key, this.snapshotJson(value[key], ancestors)]));
|
|
43234
|
+
ancestors.delete(value);
|
|
43235
|
+
return copy;
|
|
43236
|
+
}
|
|
43237
|
+
static propertyValue(node, context) {
|
|
43238
|
+
const kind = node.type.replace(/^minecraft:/, "");
|
|
43239
|
+
const property = node.property ? this.contextIdentifier(node.property) : void 0;
|
|
43240
|
+
if (kind === "select" && property === "minecraft:display_context") return context.displayContext;
|
|
43241
|
+
if (property && Object.prototype.hasOwnProperty.call(context.properties, property)) return context.properties[property];
|
|
43242
|
+
const fallback = kind === "condition" ? false : kind === "range_dispatch" ? 0 : void 0;
|
|
43243
|
+
const component = (id) => context.components[this.contextIdentifier(id)];
|
|
43244
|
+
if (property === "minecraft:custom_model_data") {
|
|
43245
|
+
const index = node.index ?? 0;
|
|
43246
|
+
if (!Number.isSafeInteger(index) || index < 0) throw new Error("Item-model custom_model_data index must be a nonnegative integer");
|
|
43247
|
+
const data = component("custom_model_data");
|
|
43248
|
+
if (data === void 0) return fallback;
|
|
43249
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) throw new Error("Item-preview custom_model_data must be an object");
|
|
43250
|
+
const field = kind === "condition" ? "flags" : kind === "select" ? "strings" : "floats";
|
|
43251
|
+
const values = data[field];
|
|
43252
|
+
if (values === void 0) return fallback;
|
|
43253
|
+
if (!Array.isArray(values)) throw new Error(`Item-preview custom_model_data.${field} must be an array`);
|
|
43254
|
+
return index < values.length ? values[index] : fallback;
|
|
43255
|
+
}
|
|
43256
|
+
if (kind === "condition" && property === "minecraft:has_component") {
|
|
43257
|
+
if (node.ignore_default) throw new Error("Item-preview has_component with ignore_default requires an explicit properties override; item defaults are unavailable");
|
|
43258
|
+
return Object.prototype.hasOwnProperty.call(context.components, this.contextIdentifier(node.component));
|
|
43259
|
+
}
|
|
43260
|
+
if (kind === "select") {
|
|
43261
|
+
switch (property) {
|
|
43262
|
+
case "minecraft:component":
|
|
43263
|
+
return component(node.component);
|
|
43264
|
+
case "minecraft:block_state": {
|
|
43265
|
+
const state = component("block_state");
|
|
43266
|
+
if (state === void 0) return void 0;
|
|
43267
|
+
if (!state || typeof state !== "object" || Array.isArray(state)) throw new Error("Item-preview block_state must be an object");
|
|
43268
|
+
if (typeof node.block_state_property !== "string") throw new Error("Item-model block_state requires block_state_property");
|
|
43269
|
+
return Object.prototype.hasOwnProperty.call(state, node.block_state_property) ? state[node.block_state_property] : void 0;
|
|
43270
|
+
}
|
|
43271
|
+
case "minecraft:charge_type": {
|
|
43272
|
+
const projectiles = component("charged_projectiles");
|
|
43273
|
+
if (projectiles === void 0) return "none";
|
|
43274
|
+
if (!Array.isArray(projectiles)) throw new Error("Item-preview charged_projectiles must be an array of item stacks");
|
|
43275
|
+
const ids = projectiles.map((stack) => {
|
|
43276
|
+
if (!stack || typeof stack !== "object" || Array.isArray(stack)) throw new Error("Item-preview charged_projectiles must contain item-stack objects");
|
|
43277
|
+
return this.contextIdentifier(stack.id);
|
|
43278
|
+
});
|
|
43279
|
+
return !ids.length ? "none" : ids.includes("minecraft:firework_rocket") ? "rocket" : "arrow";
|
|
43280
|
+
}
|
|
43281
|
+
}
|
|
43282
|
+
}
|
|
43283
|
+
if (kind === "range_dispatch" && (property === "minecraft:damage" || property === "minecraft:count")) {
|
|
43284
|
+
const damage = property === "minecraft:damage";
|
|
43285
|
+
const maximumComponent = component(damage ? "max_damage" : "max_stack_size");
|
|
43286
|
+
const maximum = maximumComponent === void 0 ? damage ? 0 : 1 : maximumComponent;
|
|
43287
|
+
const damageComponent = component("damage");
|
|
43288
|
+
const value = damage ? damageComponent === void 0 ? 0 : damageComponent : context.count;
|
|
43289
|
+
if (typeof value !== "number" || typeof maximum !== "number" || maximum < 0) throw new Error(`Item-preview ${property} requires numeric components and a nonnegative maximum`);
|
|
43290
|
+
const clamped = Math.max(0, Math.min(maximum, value));
|
|
43291
|
+
return node.normalize === false ? clamped : clamped / maximum;
|
|
43292
|
+
}
|
|
43293
|
+
return fallback;
|
|
43157
43294
|
}
|
|
43158
|
-
|
|
43159
|
-
static defaultItemModel(node, key) {
|
|
43295
|
+
static selectItemModel(node, key, context) {
|
|
43160
43296
|
if (!node || typeof node.type !== "string") {
|
|
43161
43297
|
throw new Error(`Unsupported item model definition for ${key.toNamespacedString()}`);
|
|
43162
43298
|
}
|
|
43163
43299
|
switch (node.type.replace(/^minecraft:/, "")) {
|
|
43300
|
+
case "composite":
|
|
43301
|
+
if (Array.isArray(node.models)) return { parts: node.models.map((child) => this.selectItemModel(child, key, context)) };
|
|
43302
|
+
break;
|
|
43303
|
+
case "bundle/selected_item": {
|
|
43304
|
+
const item = context.itemReferences["minecraft:bundle/selected_item"];
|
|
43305
|
+
return item ? { item } : { parts: [] };
|
|
43306
|
+
}
|
|
43164
43307
|
case "model":
|
|
43165
43308
|
if (typeof node.model === "string" && node.model) return { model: node.model, tints: node.tints };
|
|
43166
43309
|
break;
|
|
@@ -43181,17 +43324,29 @@ void main() {
|
|
|
43181
43324
|
}
|
|
43182
43325
|
throw new Error(`Unsupported special item renderer ${special.type} for ${key.toNamespacedString()}`);
|
|
43183
43326
|
}
|
|
43184
|
-
case "condition":
|
|
43185
|
-
|
|
43327
|
+
case "condition": {
|
|
43328
|
+
const value = this.propertyValue(node, context);
|
|
43329
|
+
if (typeof value !== "boolean") throw new Error(`Item-preview condition ${node.property} requires a boolean`);
|
|
43330
|
+
return this.selectItemModel(value ? node.on_true : node.on_false, key, context);
|
|
43331
|
+
}
|
|
43186
43332
|
case "select": {
|
|
43187
|
-
const
|
|
43188
|
-
|
|
43333
|
+
const value = this.propertyValue(node, context);
|
|
43334
|
+
const component = node.property && this.contextIdentifier(node.property) === "minecraft:component";
|
|
43335
|
+
if (!component && value !== void 0 && typeof value !== "string") throw new Error(`Item-preview selector ${node.property} requires a string`);
|
|
43336
|
+
const matches = (candidate) => component ? JSON.stringify(this.snapshotJson(candidate)) === JSON.stringify(this.snapshotJson(value)) : candidate === value;
|
|
43337
|
+
const selected = value === void 0 ? void 0 : node.cases?.find((entry) => matches(entry.when) || Array.isArray(entry.when) && entry.when.some(matches))?.model;
|
|
43338
|
+
return this.selectItemModel(selected ?? node.fallback, key, context);
|
|
43189
43339
|
}
|
|
43190
43340
|
case "range_dispatch": {
|
|
43341
|
+
const value = this.propertyValue(node, context);
|
|
43342
|
+
if (typeof value !== "number") throw new Error(`Item-preview range ${node.property} requires a number`);
|
|
43343
|
+
if (Number.isNaN(value)) return this.selectItemModel(node.fallback, key, context);
|
|
43344
|
+
const scaled = value * (node.scale ?? 1);
|
|
43345
|
+
if (!Number.isFinite(scaled)) throw new Error(`Item-preview range ${node.property} requires a finite value and scale`);
|
|
43191
43346
|
const selected = node.entries?.reduce((match, entry) => {
|
|
43192
|
-
return entry.threshold <=
|
|
43347
|
+
return entry.threshold <= scaled && (!match || entry.threshold >= match.threshold) ? entry : match;
|
|
43193
43348
|
}, void 0);
|
|
43194
|
-
return this.
|
|
43349
|
+
return this.selectItemModel(selected?.model ?? node.fallback, key, context);
|
|
43195
43350
|
}
|
|
43196
43351
|
}
|
|
43197
43352
|
throw new Error(`Unsupported item model ${node?.type ?? "definition"} for ${key.toNamespacedString()}`);
|
|
@@ -43218,25 +43373,28 @@ void main() {
|
|
|
43218
43373
|
}
|
|
43219
43374
|
/**
|
|
43220
43375
|
* Loads a model and resolves its parent chain. Returns `undefined` when the model is missing.
|
|
43221
|
-
* Item keys
|
|
43376
|
+
* Item keys default to GUI context and a stack count of 1. Unresolved conditions are false and numeric properties are zero.
|
|
43377
|
+
* Pass `context` to supply component values, property overrides, and item references for a preview.
|
|
43378
|
+
* Composite items retain independently merged children in `ItemModel.parts`.
|
|
43222
43379
|
*
|
|
43223
43380
|
* @param key - Model key, for example `AssetKey.parse("models", "minecraft:item/diamond_sword")`.
|
|
43224
43381
|
*/
|
|
43225
|
-
static async getMerged(key) {
|
|
43382
|
+
static async getMerged(key, context = {}) {
|
|
43226
43383
|
if (!key.assetType) {
|
|
43227
43384
|
key.assetType = "models";
|
|
43228
43385
|
}
|
|
43229
43386
|
if (!key.extension) {
|
|
43230
43387
|
key.extension = ".json";
|
|
43231
43388
|
}
|
|
43232
|
-
const
|
|
43389
|
+
const preview = this.snapshotContext(key, context);
|
|
43390
|
+
const keyStr = key.serialize() + (key.type === "item" ? this.contextKey(preview) : "");
|
|
43233
43391
|
return Caching.mergedModelCache.get(keyStr, (k4) => {
|
|
43234
|
-
return _Models.loadAndMerge(key);
|
|
43392
|
+
return _Models.loadAndMerge(key, preview);
|
|
43235
43393
|
});
|
|
43236
43394
|
}
|
|
43237
43395
|
/** Alias for {@link getMerged}. */
|
|
43238
|
-
static async get(key) {
|
|
43239
|
-
return this.getMerged(key);
|
|
43396
|
+
static async get(key, context = {}) {
|
|
43397
|
+
return this.getMerged(key, context);
|
|
43240
43398
|
}
|
|
43241
43399
|
/** Clears persisted models. Use {@link Caching.clear} to also discard in-memory assets. */
|
|
43242
43400
|
static async clearCache() {
|
|
@@ -90454,22 +90612,45 @@ ${shader.fragmentShader}`.replace(
|
|
|
90454
90612
|
this.originalModel = originalModel;
|
|
90455
90613
|
this.isModelObject = true;
|
|
90456
90614
|
this.specialMaterials = /* @__PURE__ */ new Map();
|
|
90615
|
+
this.geometries = /* @__PURE__ */ new Set();
|
|
90457
90616
|
this.meshesCreated = false;
|
|
90458
90617
|
this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
|
|
90459
|
-
if (originalModel.special) this.options.instanceMeshes = false;
|
|
90618
|
+
if (originalModel.special || originalModel.parts) this.options.instanceMeshes = false;
|
|
90460
90619
|
if (this.options.tints) this.options.tints = { ...this.options.tints };
|
|
90461
90620
|
this.addEventListener("added", () => this.updateAnimationSubscription());
|
|
90462
90621
|
this.addEventListener("removed", () => this.updateAnimationSubscription());
|
|
90463
90622
|
}
|
|
90464
90623
|
async init() {
|
|
90624
|
+
const parts = this.originalModel.parts;
|
|
90625
|
+
if (parts) {
|
|
90626
|
+
try {
|
|
90627
|
+
for (const part of parts) {
|
|
90628
|
+
const object3 = new _ModelObject(part, { ...this.options, instanceMeshes: false });
|
|
90629
|
+
this.add(object3);
|
|
90630
|
+
await object3.init();
|
|
90631
|
+
}
|
|
90632
|
+
let order = 0;
|
|
90633
|
+
this.iterateAllMeshes((mesh) => {
|
|
90634
|
+
mesh.renderOrder = order++;
|
|
90635
|
+
for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
|
|
90636
|
+
material.transparent = true;
|
|
90637
|
+
}
|
|
90638
|
+
});
|
|
90639
|
+
} catch (error2) {
|
|
90640
|
+
this.disposeAndRemoveAllChildren();
|
|
90641
|
+
throw error2;
|
|
90642
|
+
}
|
|
90643
|
+
this.notifyDirty();
|
|
90644
|
+
return;
|
|
90645
|
+
}
|
|
90465
90646
|
this.options.tints = await ItemTints.get(this.originalModel, this.options.tints);
|
|
90466
90647
|
const special = this.originalModel.special;
|
|
90467
90648
|
if (special) {
|
|
90468
|
-
const
|
|
90649
|
+
const parts2 = await SpecialItems.getParts(special, this.originalModel.key?.root);
|
|
90469
90650
|
const transform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : new Matrix4();
|
|
90470
90651
|
transform.multiply(new Matrix4().makeTranslation(-8, -8, -8));
|
|
90471
90652
|
try {
|
|
90472
|
-
for (const part of
|
|
90653
|
+
for (const part of parts2) {
|
|
90473
90654
|
const object3 = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
|
|
90474
90655
|
object3.matrix.copy(transform).multiply(part.transform);
|
|
90475
90656
|
object3.matrixWorldNeedsUpdate = true;
|
|
@@ -90520,6 +90701,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
90520
90701
|
if (this.atlas.model.elements) {
|
|
90521
90702
|
this.atlas.model.elements?.forEach((el) => {
|
|
90522
90703
|
const elGeo = this._getBoxGeometryFromElement(el).clone();
|
|
90704
|
+
this.geometries.add(elGeo);
|
|
90523
90705
|
if (this.options.cullMask) {
|
|
90524
90706
|
const indices = Array.from(elGeo.getIndex().array);
|
|
90525
90707
|
elGeo.setIndex(indices.filter((_4, index) => {
|
|
@@ -90573,10 +90755,14 @@ ${shader.fragmentShader}`.replace(
|
|
|
90573
90755
|
let combinedGeo;
|
|
90574
90756
|
if (allGeos.length > 0) {
|
|
90575
90757
|
combinedGeo = mergeBufferGeometries(allGeos);
|
|
90758
|
+
for (const geometry of allGeos) {
|
|
90759
|
+
this.geometries.delete(geometry);
|
|
90760
|
+
}
|
|
90576
90761
|
} else {
|
|
90577
90762
|
combinedGeo = new BoxGeometry(16, 16, 16);
|
|
90578
90763
|
if (displayTransform) DisplayTransforms.apply(combinedGeo, displayTransform);
|
|
90579
90764
|
}
|
|
90765
|
+
this.geometries.add(combinedGeo);
|
|
90580
90766
|
combinedGeo.computeBoundingBox();
|
|
90581
90767
|
let mesh;
|
|
90582
90768
|
if (this.options.instanceMeshes) {
|
|
@@ -90601,6 +90787,9 @@ ${shader.fragmentShader}`.replace(
|
|
|
90601
90787
|
const mat = Materials.createShadedCanvasMaterial(this.atlas.image.canvas, this.atlas.hasTransparency, false, true);
|
|
90602
90788
|
this.atlasMaterial = mat;
|
|
90603
90789
|
this.atlasTexture = mat.uniforms?.map?.value ?? mat.map;
|
|
90790
|
+
if (this.options.displayPosition === "gui" /* GUI */ && this.originalModel.gui_light === "front" /* FRONT */ && mat.uniforms?.SHADE) {
|
|
90791
|
+
mat.uniforms.SHADE.value = false;
|
|
90792
|
+
}
|
|
90604
90793
|
this.iterateAllMeshes((mesh) => {
|
|
90605
90794
|
if (mesh.geometry.hasAttribute("color")) mat.vertexColors = true;
|
|
90606
90795
|
mesh.material = mat;
|
|
@@ -90609,7 +90798,9 @@ ${shader.fragmentShader}`.replace(
|
|
|
90609
90798
|
}
|
|
90610
90799
|
}
|
|
90611
90800
|
updateAnimationSubscription() {
|
|
90612
|
-
|
|
90801
|
+
let root = this;
|
|
90802
|
+
while (root.parent && isModelObject(root.parent)) root = root.parent;
|
|
90803
|
+
const active = !!root.parent && (!this.isInstanced || this.instanceCounter > 0);
|
|
90613
90804
|
if (active && this.atlas?.hasAnimation && this.atlasTexture) {
|
|
90614
90805
|
if (!this.unsubscribeAtlas) {
|
|
90615
90806
|
this.atlasTexture.needsUpdate = true;
|
|
@@ -90625,6 +90816,9 @@ ${shader.fragmentShader}`.replace(
|
|
|
90625
90816
|
this.unsubscribeAtlas?.();
|
|
90626
90817
|
this.unsubscribeAtlas = void 0;
|
|
90627
90818
|
}
|
|
90819
|
+
for (const child of this.children) {
|
|
90820
|
+
if (isModelObject(child)) child.updateAnimationSubscription();
|
|
90821
|
+
}
|
|
90628
90822
|
}
|
|
90629
90823
|
nextInstance() {
|
|
90630
90824
|
const reference = super.nextInstance();
|
|
@@ -90644,6 +90838,8 @@ ${shader.fragmentShader}`.replace(
|
|
|
90644
90838
|
this.atlasMaterial = void 0;
|
|
90645
90839
|
for (const material of this.specialMaterials.values()) material.dispose();
|
|
90646
90840
|
this.specialMaterials.clear();
|
|
90841
|
+
for (const geometry of this.geometries) geometry.dispose();
|
|
90842
|
+
this.geometries.clear();
|
|
90647
90843
|
super.disposeAndRemoveAllChildren();
|
|
90648
90844
|
}
|
|
90649
90845
|
};
|
|
@@ -93757,6 +93953,7 @@ ${shader.fragmentShader}`.replace(
|
|
|
93757
93953
|
Env: () => Env,
|
|
93758
93954
|
FluidModelObject: () => FluidModelObject,
|
|
93759
93955
|
Fonts: () => Fonts,
|
|
93956
|
+
GUI_CONTAINER_LAYOUTS: () => GUI_CONTAINER_LAYOUTS,
|
|
93760
93957
|
Geometries: () => Geometries,
|
|
93761
93958
|
GuiHelper: () => GuiHelper,
|
|
93762
93959
|
GuiLight: () => GuiLight,
|
|
@@ -97340,6 +97537,7 @@ property list uchar int vertex_index
|
|
|
97340
97537
|
init_buffer2();
|
|
97341
97538
|
init_process2();
|
|
97342
97539
|
init_AssetKey();
|
|
97540
|
+
init_ModelTextures();
|
|
97343
97541
|
|
|
97344
97542
|
// src/gui/GuiText.ts
|
|
97345
97543
|
init_dirname();
|
|
@@ -97452,7 +97650,128 @@ property list uchar int vertex_index
|
|
|
97452
97650
|
}
|
|
97453
97651
|
|
|
97454
97652
|
// src/gui/GuiHelper.ts
|
|
97653
|
+
var GUI_CONTAINER_LAYOUTS = {
|
|
97654
|
+
generic_54: {
|
|
97655
|
+
texture: "minecraft:gui/container/generic_54",
|
|
97656
|
+
crop: [0, 0, 176, 222],
|
|
97657
|
+
slotOrigin: [8, 18],
|
|
97658
|
+
slotOffset: [18, 18],
|
|
97659
|
+
rowSize: 9,
|
|
97660
|
+
slotCount: 54
|
|
97661
|
+
},
|
|
97662
|
+
crafting_table: {
|
|
97663
|
+
texture: "minecraft:gui/container/crafting_table",
|
|
97664
|
+
crop: [0, 0, 176, 166],
|
|
97665
|
+
slotOrigin: [30, 17],
|
|
97666
|
+
slotOffset: [18, 18],
|
|
97667
|
+
rowSize: 3,
|
|
97668
|
+
slotCount: 9,
|
|
97669
|
+
resultPosition: [124, 35]
|
|
97670
|
+
}
|
|
97671
|
+
};
|
|
97455
97672
|
var GuiHelper = class {
|
|
97673
|
+
/**
|
|
97674
|
+
* Creates a 182×5 boss bar using the active resource pack. Finite progress is clamped to 0–1.
|
|
97675
|
+
* The fill crops the source image; explicit crops do not apply `.mcmeta` sprite scaling.
|
|
97676
|
+
*/
|
|
97677
|
+
static async bossBar(options = {}) {
|
|
97678
|
+
const { color: color3 = "pink", progress = 1, position = [0, 0] } = options;
|
|
97679
|
+
this.validatePosition(position);
|
|
97680
|
+
if (!["pink", "blue", "red", "green", "yellow", "purple", "white"].includes(color3)) {
|
|
97681
|
+
throw new Error(`Unsupported boss bar color: ${color3}`);
|
|
97682
|
+
}
|
|
97683
|
+
if (!Number.isFinite(progress)) throw new Error("Boss bar progress must be finite");
|
|
97684
|
+
const value = Math.max(0, Math.min(1, progress));
|
|
97685
|
+
const width = value > 0 ? Math.floor(value * 181) + 1 : 0;
|
|
97686
|
+
const texture = `minecraft:gui/sprites/boss_bar/${color3}`;
|
|
97687
|
+
const layers = [{
|
|
97688
|
+
name: "boss-bar-background",
|
|
97689
|
+
texture: `${texture}_background`,
|
|
97690
|
+
position: [...position],
|
|
97691
|
+
size: [182, 5]
|
|
97692
|
+
}];
|
|
97693
|
+
if (width > 0) {
|
|
97694
|
+
layers.push({
|
|
97695
|
+
...await this.cropTexture(`${texture}_progress`, [0, 0, width, 5], [182, 5], position),
|
|
97696
|
+
name: "boss-bar-progress"
|
|
97697
|
+
});
|
|
97698
|
+
}
|
|
97699
|
+
return layers;
|
|
97700
|
+
}
|
|
97701
|
+
/**
|
|
97702
|
+
* Creates a 192×192 book page with optional arrows and supplied text. Buttons are hidden by default.
|
|
97703
|
+
* Callers choose the page content and button states; this helper does not paginate or handle clicks.
|
|
97704
|
+
*/
|
|
97705
|
+
static async book(options = {}) {
|
|
97706
|
+
const {
|
|
97707
|
+
position = [0, 0],
|
|
97708
|
+
previous = "hidden",
|
|
97709
|
+
next = "hidden",
|
|
97710
|
+
text: text2,
|
|
97711
|
+
color: color3 = 0,
|
|
97712
|
+
shadow = false,
|
|
97713
|
+
maxWidth = 114,
|
|
97714
|
+
lineHeight = 9,
|
|
97715
|
+
...style
|
|
97716
|
+
} = options;
|
|
97717
|
+
this.validatePosition(position);
|
|
97718
|
+
for (const state of [previous, next]) {
|
|
97719
|
+
if (!["hidden", "normal", "hover"].includes(state)) throw new Error(`Unsupported book button state: ${state}`);
|
|
97720
|
+
}
|
|
97721
|
+
const layers = [{
|
|
97722
|
+
...await this.cropTexture("minecraft:gui/book", [0, 0, 192, 192], [256, 256], position),
|
|
97723
|
+
name: "book-background"
|
|
97724
|
+
}];
|
|
97725
|
+
for (const [name2, direction, state, x4] of [
|
|
97726
|
+
["previous", "backward", previous, 43],
|
|
97727
|
+
["next", "forward", next, 116]
|
|
97728
|
+
]) {
|
|
97729
|
+
if (state === "hidden") continue;
|
|
97730
|
+
layers.push({
|
|
97731
|
+
name: `book-${name2}`,
|
|
97732
|
+
texture: `minecraft:gui/sprites/widget/page_${direction}${state === "hover" ? "_highlighted" : ""}`,
|
|
97733
|
+
position: [position[0] + x4, position[1] + 157],
|
|
97734
|
+
size: [23, 13]
|
|
97735
|
+
});
|
|
97736
|
+
}
|
|
97737
|
+
if (text2 !== void 0) {
|
|
97738
|
+
layers.push({
|
|
97739
|
+
name: "book-text",
|
|
97740
|
+
text: text2,
|
|
97741
|
+
position: [position[0] + 36, position[1] + 30],
|
|
97742
|
+
color: color3,
|
|
97743
|
+
shadow,
|
|
97744
|
+
maxWidth,
|
|
97745
|
+
lineHeight,
|
|
97746
|
+
...style
|
|
97747
|
+
});
|
|
97748
|
+
}
|
|
97749
|
+
return layers;
|
|
97750
|
+
}
|
|
97751
|
+
/** Creates a container background. Use {@link GUI_CONTAINER_LAYOUTS} with {@link inventorySlot} to place its items. */
|
|
97752
|
+
static async container(type, position = [0, 0]) {
|
|
97753
|
+
this.validatePosition(position);
|
|
97754
|
+
if (type !== "generic_54" && type !== "crafting_table") throw new Error(`Unsupported GUI container: ${type}`);
|
|
97755
|
+
const layout = GUI_CONTAINER_LAYOUTS[type];
|
|
97756
|
+
return [{ ...await this.cropTexture(layout.texture, layout.crop, [256, 256], position), name: "background" }];
|
|
97757
|
+
}
|
|
97758
|
+
static validatePosition(position) {
|
|
97759
|
+
if (!Array.isArray(position) || position.length !== 2 || !position.every(Number.isFinite)) {
|
|
97760
|
+
throw new Error("GUI position must contain two finite coordinates");
|
|
97761
|
+
}
|
|
97762
|
+
}
|
|
97763
|
+
static async cropTexture(texture, crop, referenceSize, position) {
|
|
97764
|
+
const image = await ModelTextures.preload(AssetKey.parse("textures", texture));
|
|
97765
|
+
if (!image) throw new Error(`Could not load GUI texture ${texture}`);
|
|
97766
|
+
const [x4, y5, width, height] = crop;
|
|
97767
|
+
const scaleX = image.width / referenceSize[0], scaleY = image.height / referenceSize[1];
|
|
97768
|
+
return {
|
|
97769
|
+
texture,
|
|
97770
|
+
crop: [x4 * scaleX, y5 * scaleY, width * scaleX, height * scaleY],
|
|
97771
|
+
position: [...position],
|
|
97772
|
+
size: [width, height]
|
|
97773
|
+
};
|
|
97774
|
+
}
|
|
97456
97775
|
/** Sizes a tooltip around supplied text; the first entry is its title. */
|
|
97457
97776
|
static async tooltip(lines, options = {}) {
|
|
97458
97777
|
if (!lines.length) return [];
|
|
@@ -97487,8 +97806,9 @@ property list uchar int vertex_index
|
|
|
97487
97806
|
}
|
|
97488
97807
|
/** Creates crafting-table layers for ingredients and the result; stack counts are not drawn. */
|
|
97489
97808
|
static recipe(recipe, options = {}) {
|
|
97809
|
+
const layout = GUI_CONTAINER_LAYOUTS.crafting_table;
|
|
97490
97810
|
const layers = [
|
|
97491
|
-
{ name: "background", texture:
|
|
97811
|
+
{ name: "background", texture: layout.texture, crop: [...layout.crop] }
|
|
97492
97812
|
];
|
|
97493
97813
|
const itemKey = (ingredient) => {
|
|
97494
97814
|
const item = typeof ingredient === "string" && !ingredient.startsWith("#") ? ingredient : typeof ingredient === "object" && "item" in ingredient ? ingredient.item : options.resolveIngredient?.(ingredient);
|
|
@@ -97503,7 +97823,7 @@ property list uchar int vertex_index
|
|
|
97503
97823
|
layers.push({
|
|
97504
97824
|
name: `ingredient-${slot}`,
|
|
97505
97825
|
item: itemKey(ingredient),
|
|
97506
|
-
position: this.inventorySlot(slot,
|
|
97826
|
+
position: this.inventorySlot(slot, layout.slotOrigin, layout.slotOffset, layout.rowSize)
|
|
97507
97827
|
});
|
|
97508
97828
|
};
|
|
97509
97829
|
switch (recipe.type) {
|
|
@@ -97538,7 +97858,7 @@ property list uchar int vertex_index
|
|
|
97538
97858
|
layers.push({
|
|
97539
97859
|
name: "result",
|
|
97540
97860
|
item: itemKey("id" in recipe.result ? recipe.result.id : recipe.result.item),
|
|
97541
|
-
position: [
|
|
97861
|
+
position: [...layout.resultPosition]
|
|
97542
97862
|
});
|
|
97543
97863
|
return layers;
|
|
97544
97864
|
}
|
|
@@ -97649,7 +97969,6 @@ property list uchar int vertex_index
|
|
|
97649
97969
|
init_Materials();
|
|
97650
97970
|
init_ModelObject();
|
|
97651
97971
|
init_DisplayPosition();
|
|
97652
|
-
init_GuiLight();
|
|
97653
97972
|
var GuiObject = class extends SceneObject {
|
|
97654
97973
|
constructor(textureLayers, options) {
|
|
97655
97974
|
super({ ...options, instanceMeshes: false, mergeMeshes: false });
|
|
@@ -97717,12 +98036,16 @@ property list uchar int vertex_index
|
|
|
97717
98036
|
mesh2.geometry.computeBoundingBox();
|
|
97718
98037
|
bounds.union(mesh2.geometry.boundingBox.clone().applyMatrix4(new Matrix4().multiplyMatrices(inverse, mesh2.matrixWorld)));
|
|
97719
98038
|
});
|
|
97720
|
-
item.position.z = depth
|
|
97721
|
-
|
|
98039
|
+
item.position.z = depth;
|
|
98040
|
+
if (!bounds.isEmpty()) {
|
|
98041
|
+
item.position.z -= bounds.min.z;
|
|
98042
|
+
depth += bounds.max.z - bounds.min.z;
|
|
98043
|
+
this.bounds.expandByPoint(new Vector2(bounds.min.x, -bounds.max.y));
|
|
98044
|
+
this.bounds.expandByPoint(new Vector2(bounds.max.x, -bounds.min.y));
|
|
98045
|
+
}
|
|
98046
|
+
depth += 0.01;
|
|
97722
98047
|
this.bounds.expandByPoint(new Vector2(x4, y5));
|
|
97723
98048
|
this.bounds.expandByPoint(new Vector2(x4 + width2, y5 + height2));
|
|
97724
|
-
this.bounds.expandByPoint(new Vector2(bounds.min.x, -bounds.max.y));
|
|
97725
|
-
this.bounds.expandByPoint(new Vector2(bounds.max.x, -bounds.min.y));
|
|
97726
98049
|
continue;
|
|
97727
98050
|
}
|
|
97728
98051
|
const key = typeof layer.texture === "string" ? AssetKey.parse("textures", layer.texture) : layer.texture;
|
|
@@ -97762,15 +98085,13 @@ property list uchar int vertex_index
|
|
|
97762
98085
|
item.name = `group:${layer.name ?? index}`;
|
|
97763
98086
|
this.add(item);
|
|
97764
98087
|
await item.init();
|
|
97765
|
-
|
|
97766
|
-
|
|
98088
|
+
const meshes = [];
|
|
98089
|
+
item.iterateAllMeshes((mesh) => meshes.push(mesh));
|
|
98090
|
+
meshes.forEach((mesh, partIndex) => {
|
|
97767
98091
|
mesh.name = `mesh:${layer.name ?? index}`;
|
|
97768
|
-
mesh.renderOrder = index;
|
|
98092
|
+
mesh.renderOrder = index + partIndex / (meshes.length + 1) * 0.5;
|
|
97769
98093
|
for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
|
|
97770
98094
|
material.transparent = true;
|
|
97771
|
-
if (model.gui_light === "front" /* FRONT */ && material.uniforms?.SHADE) {
|
|
97772
|
-
material.uniforms.SHADE.value = false;
|
|
97773
|
-
}
|
|
97774
98095
|
}
|
|
97775
98096
|
});
|
|
97776
98097
|
return item;
|