minerender 2.1.0-alpha.59 → 2.1.0-alpha.60

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.
@@ -1133,6 +1133,26 @@ var init_Materials = __esm({
1133
1133
  }
1134
1134
  });
1135
1135
 
1136
+ // src/model/Model.ts
1137
+ function isDoubleArray(obj) {
1138
+ return Array.isArray(obj) && obj.length === 2;
1139
+ }
1140
+ function isTripleArray(obj) {
1141
+ return Array.isArray(obj) && obj.length === 3;
1142
+ }
1143
+ function isQuadArray(obj) {
1144
+ return Array.isArray(obj) && obj.length === 4;
1145
+ }
1146
+ var ITEM_GENERATED, BUILTIN_GENERATED, BUILTIN_ENTITY, DEFAULT_ELEMENTS;
1147
+ var init_Model = __esm({
1148
+ "src/model/Model.ts"() {
1149
+ ITEM_GENERATED = "item/generated";
1150
+ BUILTIN_GENERATED = "builtin/generated";
1151
+ BUILTIN_ENTITY = "builtin/entity";
1152
+ DEFAULT_ELEMENTS = [];
1153
+ }
1154
+ });
1155
+
1136
1156
  // ../../node_modules/ts-deepmerge/dist/index.js
1137
1157
  var require_dist = __commonJS({
1138
1158
  "../../node_modules/ts-deepmerge/dist/index.js"(exports) {
@@ -1391,6 +1411,7 @@ var init_DisplayTransforms = __esm({
1391
1411
  var import_ts_deepmerge, ModelMerger;
1392
1412
  var init_ModelMerger = __esm({
1393
1413
  "src/model/ModelMerger.ts"() {
1414
+ init_Model();
1394
1415
  init_Models();
1395
1416
  import_ts_deepmerge = __toESM(require_dist());
1396
1417
  init_AssetKey();
@@ -1416,6 +1437,7 @@ var init_ModelMerger = __esm({
1416
1437
  }
1417
1438
  const models = [];
1418
1439
  const parentKey = AssetKey.parse("models", model.parent);
1440
+ if (parentKey.namespace === "minecraft" && parentKey.getFullPath() === BUILTIN_ENTITY) return models;
1419
1441
  parentKey.root = model.key?.root;
1420
1442
  const parentModel = await Models.getRaw(parentKey);
1421
1443
  if (parentModel) {
@@ -1482,12 +1504,12 @@ var init_Models = __esm({
1482
1504
  const result = await AssetLoader.getFirst([itemKey, key], "json" /* JSON */);
1483
1505
  if (!result) return void 0;
1484
1506
  if (result.key.assetType !== "items") return { ...result.asset, key };
1485
- const reference = this.defaultItemModel(result.asset.model, key);
1486
- const modelKey = AssetKey.parse("models", reference);
1507
+ const selected = this.defaultItemModel(result.asset.model, key);
1508
+ const modelKey = AssetKey.parse("models", selected.model);
1487
1509
  modelKey.root = key.root;
1488
1510
  const model2 = await this.getRaw(modelKey);
1489
- if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${reference}`);
1490
- return model2;
1511
+ if (!model2) throw new Error(`Item ${key.toNamespacedString()} references missing model ${selected.model}`);
1512
+ return selected.special ? { ...model2, special: selected.special } : model2;
1491
1513
  });
1492
1514
  return model ? { ...model, key: Object.assign(new AssetKey("", ""), model.key) } : void 0;
1493
1515
  }
@@ -1498,8 +1520,25 @@ var init_Models = __esm({
1498
1520
  }
1499
1521
  switch (node.type.replace(/^minecraft:/, "")) {
1500
1522
  case "model":
1501
- if (typeof node.model === "string" && node.model) return node.model;
1523
+ if (typeof node.model === "string" && node.model) return { model: node.model };
1502
1524
  break;
1525
+ case "special": {
1526
+ if (!node.base || !node.model || typeof node.model !== "object") break;
1527
+ const special = node.model;
1528
+ switch (special.type) {
1529
+ case "chest":
1530
+ case "minecraft:chest":
1531
+ case "bed":
1532
+ case "minecraft:bed":
1533
+ if (typeof special.texture === "string" && special.texture) return { model: node.base, special };
1534
+ break;
1535
+ case "head":
1536
+ case "minecraft:head":
1537
+ if (typeof special.kind === "string" && special.kind) return { model: node.base, special };
1538
+ break;
1539
+ }
1540
+ throw new Error(`Unsupported special item renderer ${special.type} for ${key.toNamespacedString()}`);
1541
+ }
1503
1542
  case "condition":
1504
1543
  return this.defaultItemModel(node.on_false, key);
1505
1544
  case "select": {
@@ -3098,6 +3137,102 @@ var init_UVMapper = __esm({
3098
3137
  }
3099
3138
  });
3100
3139
 
3140
+ // src/MinecraftCubeTexture.ts
3141
+ var MinecraftCubeTexture;
3142
+ var init_MinecraftCubeTexture = __esm({
3143
+ "src/MinecraftCubeTexture.ts"() {
3144
+ init_UVMapper();
3145
+ init_CubeFace();
3146
+ MinecraftCubeTexture = class {
3147
+ constructor(u, v, width, height) {
3148
+ this.u = u;
3149
+ this.v = v;
3150
+ this.width = width;
3151
+ this.height = height;
3152
+ }
3153
+ mapW(x) {
3154
+ return x / this.width;
3155
+ }
3156
+ mapH(x) {
3157
+ return 1 - x / this.height;
3158
+ }
3159
+ getUvEast(w, h, l) {
3160
+ return [
3161
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
3162
+ [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
3163
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
3164
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
3165
+ ];
3166
+ }
3167
+ getUvWest(w, h, l) {
3168
+ return [
3169
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
3170
+ [this.mapW(this.u), this.mapH(this.v + l + h)],
3171
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
3172
+ [this.mapW(this.u), this.mapH(this.v + l)]
3173
+ ];
3174
+ }
3175
+ getUvUp(w, h, l) {
3176
+ return [
3177
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)],
3178
+ [this.mapW(this.u + l + w + w), this.mapH(this.v + l)],
3179
+ [this.mapW(this.u + l + w), this.mapH(this.v)],
3180
+ [this.mapW(this.u + l + w + w), this.mapH(this.v)]
3181
+ ];
3182
+ }
3183
+ getUvDown(w, h, l) {
3184
+ return [
3185
+ [this.mapW(this.u + l), this.mapH(this.v)],
3186
+ [this.mapW(this.u + l + w), this.mapH(this.v)],
3187
+ [this.mapW(this.u + l), this.mapH(this.v + l)],
3188
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)]
3189
+ ];
3190
+ }
3191
+ getUvSouth(w, h, l) {
3192
+ return [
3193
+ [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l + h)],
3194
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
3195
+ [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)],
3196
+ [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
3197
+ ];
3198
+ }
3199
+ getUvNorth(w, h, l) {
3200
+ return [
3201
+ [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
3202
+ [this.mapW(this.u + l), this.mapH(this.v + l + h)],
3203
+ [this.mapW(this.u + l + w), this.mapH(this.v + l)],
3204
+ [this.mapW(this.u + l), this.mapH(this.v + l)]
3205
+ ];
3206
+ }
3207
+ getFaceUv(face, w, h, l) {
3208
+ switch (face) {
3209
+ case "east" /* EAST */:
3210
+ return this.getUvEast(w, h, l);
3211
+ case "west" /* WEST */:
3212
+ return this.getUvWest(w, h, l);
3213
+ case "up" /* UP */:
3214
+ return this.getUvUp(w, h, l);
3215
+ case "down" /* DOWN */:
3216
+ return this.getUvDown(w, h, l);
3217
+ case "south" /* SOUTH */:
3218
+ return this.getUvSouth(w, h, l);
3219
+ case "north" /* NORTH */:
3220
+ return this.getUvNorth(w, h, l);
3221
+ }
3222
+ }
3223
+ toUvArray(w, h, l, mirror = false) {
3224
+ const uv = [];
3225
+ for (let i = 0; i < CUBE_FACES.length; i++) {
3226
+ const face = mirror && i < 2 ? CUBE_FACES[1 - i] : CUBE_FACES[i];
3227
+ const corners = this.getFaceUv(face, w, h, l);
3228
+ UVMapper.setFaceUvInArray(uv, i * 4, mirror ? [corners[1], corners[0], corners[3], corners[2]] : corners);
3229
+ }
3230
+ return uv;
3231
+ }
3232
+ };
3233
+ }
3234
+ });
3235
+
3101
3236
  // src/error/MineRenderError.ts
3102
3237
  var MineRenderError;
3103
3238
  var init_MineRenderError = __esm({
@@ -3114,6 +3249,248 @@ var init_MineRenderError = __esm({
3114
3249
  }
3115
3250
  });
3116
3251
 
3252
+ // src/assets/Entities.ts
3253
+ var Entities;
3254
+ var init_Entities = __esm({
3255
+ "src/assets/Entities.ts"() {
3256
+ init_AssetKey();
3257
+ init_AssetLoader();
3258
+ init_source();
3259
+ init_Caching();
3260
+ init_Assets();
3261
+ init_MineRenderError();
3262
+ init_ModelTextures();
3263
+ Entities = class {
3264
+ static async getEntityList() {
3265
+ const collect = async (path) => {
3266
+ const prefix2 = path ? `${path}/` : "";
3267
+ const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
3268
+ const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
3269
+ if (!list) return [];
3270
+ const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
3271
+ const children = await Promise.all(list.directories.map((directory) => collect(`${prefix2}${directory}`)));
3272
+ return [...files, ...children.flat()];
3273
+ };
3274
+ return collect("");
3275
+ }
3276
+ static async getModelFile(modelKey) {
3277
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3278
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", isAssetKey(modelKey) ? modelKey.root : void 0);
3279
+ return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3280
+ }
3281
+ static async getLayerList(modelKey) {
3282
+ return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
3283
+ }
3284
+ /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
3285
+ static async getPassList(modelKey) {
3286
+ return (await this.getModelFile(modelKey))?.passes ?? [];
3287
+ }
3288
+ static async getEntity(modelKey, textureKey, options) {
3289
+ const model = await this.getModelFile(modelKey);
3290
+ if (!model) return void 0;
3291
+ const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
3292
+ const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
3293
+ if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
3294
+ draws.push(...passes);
3295
+ const names = [];
3296
+ const selected = draws.map((pass) => {
3297
+ const layer = model.layers[pass.layer];
3298
+ if (!layer) {
3299
+ throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
3300
+ }
3301
+ let name = pass.layer;
3302
+ for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
3303
+ names.push(name);
3304
+ return { name, layer, pass };
3305
+ });
3306
+ const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
3307
+ const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
3308
+ const textureLocation = pass.textureLocation ?? layer.textureLocation;
3309
+ let texture;
3310
+ if (override) {
3311
+ const path = isAssetKey(override) ? override.getFullPath() : override.path;
3312
+ 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);
3313
+ } else if (textureLocation !== void 0) {
3314
+ texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
3315
+ if (isAssetKey(modelKey)) texture.root = modelKey.root;
3316
+ } else {
3317
+ texture = await this.resolveTexture(modelKey);
3318
+ }
3319
+ const render = pass.render ?? layer.render;
3320
+ return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
3321
+ })));
3322
+ return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
3323
+ }
3324
+ /**
3325
+ * Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
3326
+ */
3327
+ static async getAnimations(modelKey) {
3328
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3329
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
3330
+ const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
3331
+ return file?.animations;
3332
+ }
3333
+ static async resolveTexture(modelKey) {
3334
+ const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
3335
+ const root = isAssetKey(modelKey) ? modelKey.root : void 0;
3336
+ const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json", root);
3337
+ return Caching.entityTextureCache.get(key.serialize(), async () => {
3338
+ const name = path.split("/").pop();
3339
+ for (const candidate of [path, `${path}/${name}`]) {
3340
+ const texture2 = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png", root);
3341
+ if (await ModelTextures.get(texture2)) return texture2;
3342
+ }
3343
+ const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json", root);
3344
+ const list = await AssetLoader.get(listKey, "list" /* LIST */);
3345
+ const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
3346
+ const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
3347
+ if (!file) return void 0;
3348
+ const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json", root);
3349
+ const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
3350
+ const assets = variant?.assets;
3351
+ const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
3352
+ if (typeof textureId !== "string") return void 0;
3353
+ const texture = AssetKey.parse("textures", textureId);
3354
+ texture.root = root;
3355
+ return texture;
3356
+ });
3357
+ }
3358
+ /** @deprecated Use getEntityList(); block entities share the entity dataset. */
3359
+ static getBlockList() {
3360
+ return this.getEntityList();
3361
+ }
3362
+ /** @deprecated Use getEntity(); block entities share the entity dataset. */
3363
+ static getBlock(modelKey, textureKey, options) {
3364
+ return this.getEntity(modelKey, textureKey, options);
3365
+ }
3366
+ };
3367
+ }
3368
+ });
3369
+
3370
+ // src/entity/EntityAnimation.ts
3371
+ function catmullRom(delta, p0, p1, p22, p32) {
3372
+ return 0.5 * (2 * p1 + (p22 - p0) * delta + (2 * p0 - 5 * p1 + 4 * p22 - p32) * delta * delta + (3 * p1 - p0 - 3 * p22 + p32) * delta * delta * delta);
3373
+ }
3374
+ function sampleEntityKeyframes(keyframes, time) {
3375
+ if (keyframes.length === 0) return [0, 0, 0];
3376
+ let low = 0, high = keyframes.length;
3377
+ while (low < high) {
3378
+ const middle = low + high >>> 1;
3379
+ if (time <= keyframes[middle].time) high = middle;
3380
+ else low = middle + 1;
3381
+ }
3382
+ const a = Math.max(0, low - 1);
3383
+ const b = Math.min(keyframes.length - 1, a + 1);
3384
+ const from = keyframes[a];
3385
+ const to = keyframes[b];
3386
+ const delta = a === b ? 0 : Math.min(1, Math.max(0, (time - from.time) / (to.time - from.time)));
3387
+ if (to.interpolation === "catmullrom") {
3388
+ const before = keyframes[Math.max(0, a - 1)].value;
3389
+ const after = keyframes[Math.min(keyframes.length - 1, b + 1)].value;
3390
+ return [0, 1, 2].map((i) => catmullRom(delta, before[i], from.value[i], to.value[i], after[i]));
3391
+ }
3392
+ const target = to.pre ?? to.value;
3393
+ return [0, 1, 2].map((i) => from.value[i] + (target[i] - from.value[i]) * delta);
3394
+ }
3395
+ function entityAnimationTime(animation, time, loop = animation.loop) {
3396
+ return loop && animation.length > 0 ? time % animation.length : time;
3397
+ }
3398
+ function sampleEntityAnimation(animation, time, loop = animation.loop) {
3399
+ const elapsed = entityAnimationTime(animation, time, loop);
3400
+ const pose = {};
3401
+ for (const [name, bone] of Object.entries(animation.bones)) {
3402
+ const sampled = pose[name] = {};
3403
+ for (const channel of ENTITY_ANIMATION_CHANNELS) {
3404
+ const keyframes = bone[channel];
3405
+ if (keyframes?.length) sampled[channel] = sampleEntityKeyframes(keyframes, elapsed);
3406
+ }
3407
+ }
3408
+ return pose;
3409
+ }
3410
+ var ENTITY_ANIMATION_CHANNELS;
3411
+ var init_EntityAnimation = __esm({
3412
+ "src/entity/EntityAnimation.ts"() {
3413
+ ENTITY_ANIMATION_CHANNELS = ["position", "rotation", "scale"];
3414
+ }
3415
+ });
3416
+
3417
+ // src/entity/scene/EntityAnimationPlayer.ts
3418
+ var ZERO, EntityAnimationPlayer;
3419
+ var init_EntityAnimationPlayer = __esm({
3420
+ "src/entity/scene/EntityAnimationPlayer.ts"() {
3421
+ init_EntityAnimation();
3422
+ ZERO = [0, 0, 0];
3423
+ EntityAnimationPlayer = class {
3424
+ constructor() {
3425
+ this.parts = [];
3426
+ this._time = 0;
3427
+ this.loop = false;
3428
+ this.speed = 1;
3429
+ }
3430
+ get animation() {
3431
+ return this._animation;
3432
+ }
3433
+ get time() {
3434
+ return this._time;
3435
+ }
3436
+ /**
3437
+ * Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
3438
+ * bones without a matching part are skipped.
3439
+ */
3440
+ play(layers, animation, options = {}) {
3441
+ this.stop();
3442
+ this._animation = animation;
3443
+ this._time = options.time ?? 0;
3444
+ this.loop = options.loop ?? animation.loop;
3445
+ this.speed = options.speed ?? 1;
3446
+ for (const layer of layers) {
3447
+ for (const bone of Object.keys(animation.bones)) {
3448
+ const object = layer.getObjectByName(`group:${bone}`);
3449
+ if (!object) continue;
3450
+ this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
3451
+ }
3452
+ }
3453
+ this.apply();
3454
+ }
3455
+ /** Restores the default poses. Returns whether an animation was active. */
3456
+ stop() {
3457
+ if (!this._animation) return false;
3458
+ for (const part of this.parts) {
3459
+ part.object.position.copy(part.position);
3460
+ part.object.rotation.copy(part.rotation);
3461
+ part.object.scale.copy(part.scale);
3462
+ }
3463
+ this.clear();
3464
+ return true;
3465
+ }
3466
+ /** Forgets the animation without touching the parts, for parts that no longer exist. */
3467
+ clear() {
3468
+ this.parts = [];
3469
+ this._animation = void 0;
3470
+ this._time = 0;
3471
+ }
3472
+ setTime(seconds) {
3473
+ if (!this._animation) return false;
3474
+ this._time = seconds;
3475
+ this.apply();
3476
+ return true;
3477
+ }
3478
+ advance(deltaSeconds) {
3479
+ return this.setTime(this._time + deltaSeconds * this.speed);
3480
+ }
3481
+ apply() {
3482
+ const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
3483
+ for (const part of this.parts) {
3484
+ const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
3485
+ part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
3486
+ part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
3487
+ part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
3488
+ }
3489
+ }
3490
+ };
3491
+ }
3492
+ });
3493
+
3117
3494
  // src/instance/InstanceReference.ts
3118
3495
  function isInstanceReference(obj) {
3119
3496
  return obj.isInstanceReference;
@@ -3611,6 +3988,242 @@ var init_SceneObject = __esm({
3611
3988
  }
3612
3989
  });
3613
3990
 
3991
+ // src/entity/scene/EntityObject.ts
3992
+ import { Color as Color3, Euler as Euler4, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
3993
+ function isEntityObject(obj) {
3994
+ return obj.isEntityObject;
3995
+ }
3996
+ var import_ts_deepmerge4, EntityObject;
3997
+ var init_EntityObject = __esm({
3998
+ "src/entity/scene/EntityObject.ts"() {
3999
+ init_SceneObject();
4000
+ init_Caching();
4001
+ import_ts_deepmerge4 = __toESM(require_dist());
4002
+ init_Ticker();
4003
+ init_model();
4004
+ init_ModelTextures();
4005
+ init_AssetKey();
4006
+ init_Materials();
4007
+ init_MinecraftCubeTexture();
4008
+ init_three();
4009
+ init_EntityAnimationPlayer();
4010
+ EntityObject = class _EntityObject extends SceneObject {
4011
+ constructor(entity, options) {
4012
+ super();
4013
+ this.entity = entity;
4014
+ this.isEntityObject = true;
4015
+ this.meshesCreated = false;
4016
+ this.geometries = /* @__PURE__ */ new Set();
4017
+ this.disposeWireframes = [];
4018
+ /** Scrolling materials are owned: their texture offset follows this entity's age. */
4019
+ this.scrollMaterials = [];
4020
+ /** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
4021
+ this.age = 0;
4022
+ this.animationPlayer = new EntityAnimationPlayer();
4023
+ this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
4024
+ this.addEventListener("added", () => this.updateScrollSubscription());
4025
+ this.addEventListener("removed", () => this.updateScrollSubscription());
4026
+ }
4027
+ static {
4028
+ this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
4029
+ }
4030
+ async init() {
4031
+ this.createMeshes();
4032
+ await this.applyTextures();
4033
+ }
4034
+ dispose() {
4035
+ super.dispose();
4036
+ }
4037
+ disposeAndRemoveAllChildren() {
4038
+ this.clearScrollMaterials();
4039
+ for (const geometry of this.geometries) geometry.dispose();
4040
+ this.geometries.clear();
4041
+ for (const dispose of this.disposeWireframes.splice(0)) dispose();
4042
+ this.animationPlayer.clear();
4043
+ super.disposeAndRemoveAllChildren();
4044
+ }
4045
+ clearScrollMaterials() {
4046
+ Ticker.remove(this.scrollTicker);
4047
+ this.scrollTicker = void 0;
4048
+ for (const { material } of this.scrollMaterials.splice(0)) {
4049
+ material.map?.dispose();
4050
+ material.dispose();
4051
+ }
4052
+ }
4053
+ updateScrollSubscription() {
4054
+ if (this.parent && this.scrollMaterials.length) {
4055
+ if (this.scrollTicker === void 0) {
4056
+ this.scrollTicker = Ticker.add(() => {
4057
+ this.age++;
4058
+ this.updateScroll();
4059
+ });
4060
+ }
4061
+ } else {
4062
+ Ticker.remove(this.scrollTicker);
4063
+ this.scrollTicker = void 0;
4064
+ }
4065
+ }
4066
+ /** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
4067
+ updateScroll() {
4068
+ for (const { offset, speed } of this.scrollMaterials) {
4069
+ offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
4070
+ }
4071
+ this.notifyDirty();
4072
+ }
4073
+ //<editor-fold desc="ANIMATION">
4074
+ /** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
4075
+ get animation() {
4076
+ return this.animationPlayer.animation;
4077
+ }
4078
+ /** Seconds since the animation started, before looping. */
4079
+ get animationTime() {
4080
+ return this.animationPlayer.time;
4081
+ }
4082
+ /**
4083
+ * Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
4084
+ * Parts of every layer are matched by name and their current pose is the default the offsets add to.
4085
+ * The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
4086
+ */
4087
+ playAnimation(animation, options) {
4088
+ this.createMeshes();
4089
+ const layers = Object.keys(this.entityLayers).map((name) => this.getLayerGroup(name)).filter((layer) => !!layer);
4090
+ this.animationPlayer.play(layers, animation, options);
4091
+ this.notifyDirty();
4092
+ }
4093
+ /** Stops the animation and restores the default pose. */
4094
+ stopAnimation() {
4095
+ if (this.animationPlayer.stop()) this.notifyDirty();
4096
+ }
4097
+ /** Poses the object at an explicit time in seconds. Has no effect without an animation. */
4098
+ setAnimationTime(seconds) {
4099
+ if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
4100
+ }
4101
+ /** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
4102
+ advanceAnimation(deltaSeconds) {
4103
+ if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
4104
+ }
4105
+ //</editor-fold>
4106
+ getLayerGroup(name) {
4107
+ return super.getGroupByName(`layer:${name}`);
4108
+ }
4109
+ getGroupByName(name, layerName) {
4110
+ return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
4111
+ }
4112
+ getMeshByName(name, layerName) {
4113
+ return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
4114
+ }
4115
+ get entityLayers() {
4116
+ return this.entity.layers ?? { main: this.entity };
4117
+ }
4118
+ getTextureKey(layer) {
4119
+ if (layer.texture) return layer.texture;
4120
+ const key = layer.key;
4121
+ return new AssetKey(
4122
+ key.namespace,
4123
+ isAssetKey(key) ? key.getFullPath() : key.path,
4124
+ "textures",
4125
+ "entity",
4126
+ "assets",
4127
+ ".png"
4128
+ );
4129
+ }
4130
+ async loadTextures(layer = this.entity) {
4131
+ return ModelTextures.get(this.getTextureKey(layer));
4132
+ }
4133
+ createMeshes(force = false) {
4134
+ if (this.meshesCreated && !force) return;
4135
+ const modelRoot = new Object3D3();
4136
+ const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
4137
+ if (transform) {
4138
+ for (const op of transform) {
4139
+ const matrix = new Matrix45();
4140
+ if ("scale" in op) matrix.makeScale(...op.scale);
4141
+ else if ("translate" in op) matrix.makeTranslation(...op.translate);
4142
+ else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
4143
+ modelRoot.matrix.multiply(matrix);
4144
+ }
4145
+ modelRoot.matrixAutoUpdate = false;
4146
+ } else if (this.options.flip ?? true) {
4147
+ modelRoot.scale.set(-1, -1, 1);
4148
+ }
4149
+ this.add(modelRoot);
4150
+ Object.entries(this.entityLayers).forEach(([name, layer], index) => {
4151
+ const group = this.createGroup(`layer:${name}`);
4152
+ modelRoot.add(group);
4153
+ const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
4154
+ this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
4155
+ });
4156
+ this.meshesCreated = true;
4157
+ }
4158
+ createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
4159
+ const anchor = this.createGroup(name);
4160
+ anchor.position.fromArray(part.pose.offset);
4161
+ anchor.rotation.set(...part.pose.rotation, "ZYX");
4162
+ anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
4163
+ parent.add(anchor);
4164
+ const size = part.texture ?? textureSize;
4165
+ for (const cube of part.cubes) {
4166
+ const [width, height, depth] = cube.size;
4167
+ const [growX, growY, growZ] = cube.grow ?? [0, 0, 0];
4168
+ const texture = new MinecraftCubeTexture(...cube.uv, ...size);
4169
+ const uv = size[0] === 0 || size[1] === 0 ? new Array(48).fill(0) : texture.toUvArray(width, height, depth, cube.mirror);
4170
+ const geometry = this._getBoxGeometryForDimensionsAndUv(
4171
+ width + growX * 2,
4172
+ height + growY * 2,
4173
+ depth + growZ * 2,
4174
+ uv
4175
+ ).clone();
4176
+ this.geometries.add(geometry);
4177
+ geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
4178
+ if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
4179
+ const index = Array.from(geometry.getIndex().array);
4180
+ geometry.setIndex(index.concat(index.slice().reverse()));
4181
+ }
4182
+ const mesh = this.createMesh(name, geometry, material);
4183
+ mesh.renderOrder = renderOrder;
4184
+ anchor.add(mesh);
4185
+ if (this.options.wireframe) this.disposeWireframes.push(addWireframeToMesh(geometry, mesh));
4186
+ }
4187
+ for (const [childName, child] of Object.entries(part.children)) {
4188
+ this.createPart(childName, child, anchor, size, material, renderOrder, inward);
4189
+ }
4190
+ }
4191
+ async applyTextures() {
4192
+ this.clearScrollMaterials();
4193
+ await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
4194
+ const mode = layer.render ?? layer.layer.render ?? "cutout";
4195
+ const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
4196
+ const scroll = Materials.entityModeScroll(mode);
4197
+ const assetKeyStr = this.getTextureKey(layer).serialize();
4198
+ const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}`;
4199
+ let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
4200
+ if (!mat) {
4201
+ const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
4202
+ const imageData = await this.loadTextures(layer);
4203
+ if (!imageData) return;
4204
+ const canvas = imageData.data.canvas;
4205
+ const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
4206
+ mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
4207
+ if (scroll) {
4208
+ this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
4209
+ }
4210
+ }
4211
+ this.getLayerGroup(name)?.traverse((object) => {
4212
+ if (isMesh(object)) object.material = mat;
4213
+ });
4214
+ }));
4215
+ if (!this.children.length) {
4216
+ this.clearScrollMaterials();
4217
+ } else if (this.scrollMaterials.length) {
4218
+ this.updateScroll();
4219
+ }
4220
+ this.updateScrollSubscription();
4221
+ this.notifyDirty();
4222
+ }
4223
+ };
4224
+ }
4225
+ });
4226
+
3614
4227
  // src/three/BufferGeometryUtils.js
3615
4228
  import {
3616
4229
  BufferAttribute as BufferAttribute4,
@@ -4199,8 +4812,121 @@ var init_ModelCulling = __esm({
4199
4812
  }
4200
4813
  });
4201
4814
 
4815
+ // src/model/SpecialItems.ts
4816
+ import { Matrix4 as Matrix48 } from "three";
4817
+ var SpecialItems;
4818
+ var init_SpecialItems = __esm({
4819
+ "src/model/SpecialItems.ts"() {
4820
+ init_AssetKey();
4821
+ init_Entities();
4822
+ SpecialItems = class {
4823
+ /** Resolves the static entity parts drawn by a special item renderer, in model units. */
4824
+ static async getParts(special, root) {
4825
+ const texture = (id, directory) => {
4826
+ const key = AssetKey.parse("textures", id);
4827
+ return new AssetKey(
4828
+ key.namespace,
4829
+ [directory, key.getFullPath()].filter(Boolean).join("/"),
4830
+ "textures",
4831
+ "entity",
4832
+ "assets",
4833
+ ".png",
4834
+ root
4835
+ );
4836
+ };
4837
+ const load = async (id, textureKey, transform, rotations = {}) => {
4838
+ const key = new AssetKey("minecraft", id, void 0, void 0, "entity-models", ".json", root);
4839
+ const model = await Entities.getEntity(key, textureKey, { layer: "main" });
4840
+ if (!model) throw new Error(`Missing entity model minecraft:${id} for special item ${special.type}`);
4841
+ return { model, transform, rotations };
4842
+ };
4843
+ switch (special.type) {
4844
+ case "minecraft:chest":
4845
+ case "chest": {
4846
+ const angle = -(special.openness ?? 0) * Math.PI / 2;
4847
+ const chest = await load("chest", texture(special.texture, "chest"), new Matrix48(), {
4848
+ lid: [angle, 0, 0],
4849
+ lock: [angle, 0, 0]
4850
+ });
4851
+ chest.model = { ...chest.model, render: "solid", layers: void 0 };
4852
+ return [chest];
4853
+ }
4854
+ case "minecraft:bed":
4855
+ case "bed": {
4856
+ const transform = new Matrix48().makeTranslation(0, 9, 0).multiply(new Matrix48().makeRotationX(Math.PI / 2)).multiply(new Matrix48().makeTranslation(8, 8, 8)).multiply(new Matrix48().makeRotationZ(Math.PI)).multiply(new Matrix48().makeTranslation(-8, -8, -8));
4857
+ const key = texture(special.texture, "bed");
4858
+ return Promise.all([
4859
+ load("bed_head", key, transform),
4860
+ load("bed_foot", key, new Matrix48().makeTranslation(0, 0, -16).multiply(transform))
4861
+ ]);
4862
+ }
4863
+ case "minecraft:head":
4864
+ case "head": {
4865
+ const models = {
4866
+ skeleton: "skeleton_skull",
4867
+ wither_skeleton: "wither_skeleton_skull",
4868
+ zombie: "zombie_head",
4869
+ creeper: "creeper_head",
4870
+ dragon: "dragon_skull",
4871
+ piglin: "piglin_head"
4872
+ };
4873
+ const id = Object.prototype.hasOwnProperty.call(models, special.kind) ? models[special.kind] : void 0;
4874
+ if (!id) throw new Error(`Unsupported special item head kind ${special.kind}`);
4875
+ const animation = (special.animation ?? 0) * Math.PI * 0.2;
4876
+ const rotations = { head: [0, Math.PI, 0] };
4877
+ if (special.kind === "dragon") rotations.jaw = [(Math.sin(animation) + 1) * 0.2, 0, 0];
4878
+ if (special.kind === "piglin") {
4879
+ rotations.left_ear = [0, 0, -(Math.cos(animation * 1.2) + 2.5) * 0.2];
4880
+ rotations.right_ear = [0, 0, (Math.cos(animation) + 2.5) * 0.2];
4881
+ }
4882
+ return [await load(
4883
+ id,
4884
+ special.texture ? texture(special.texture, "") : void 0,
4885
+ new Matrix48().makeTranslation(8, 0, 8).multiply(new Matrix48().makeScale(-1, -1, 1)),
4886
+ rotations
4887
+ )];
4888
+ }
4889
+ }
4890
+ }
4891
+ /** An owned material with model-preview shading; its entity texture remains shared. */
4892
+ static createMaterial(source, shade) {
4893
+ const material = source.clone();
4894
+ if (shade) {
4895
+ material.onBeforeCompile = (shader) => {
4896
+ shader.vertexShader = `varying float itemLight;
4897
+ ${shader.vertexShader}`.replace("#include <begin_vertex>", `
4898
+ #include <begin_vertex>
4899
+ vec3 N = inverseTransformDirection(normalMatrix * normal, viewMatrix);
4900
+ itemLight = (1.0 + N.y) * 0.25 - N.x * N.x * 0.15 + N.z * N.z * 0.05 + 0.5;
4901
+ `);
4902
+ shader.fragmentShader = `varying float itemLight;
4903
+ ${shader.fragmentShader}`.replace(
4904
+ "#include <color_fragment>",
4905
+ "#include <color_fragment>\ndiffuseColor.rgb *= itemLight;"
4906
+ );
4907
+ };
4908
+ material.customProgramCacheKey = () => "special-item-side";
4909
+ }
4910
+ return material;
4911
+ }
4912
+ };
4913
+ }
4914
+ });
4915
+
4916
+ // src/model/GuiLight.ts
4917
+ var GuiLight;
4918
+ var init_GuiLight = __esm({
4919
+ "src/model/GuiLight.ts"() {
4920
+ GuiLight = /* @__PURE__ */ ((GuiLight2) => {
4921
+ GuiLight2["FRONT"] = "front";
4922
+ GuiLight2["SIDE"] = "side";
4923
+ return GuiLight2;
4924
+ })(GuiLight || {});
4925
+ }
4926
+ });
4927
+
4202
4928
  // src/model/scene/ModelObject.ts
4203
- import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix48 } from "three";
4929
+ import { BoxGeometry as BoxGeometry5, BufferAttribute as BufferAttribute5, Color as Color8, Euler as Euler6, Matrix4 as Matrix49 } from "three";
4204
4930
  function isModelObject(obj) {
4205
4931
  return obj.isModelObject;
4206
4932
  }
@@ -4215,16 +4941,22 @@ var init_ModelObject = __esm({
4215
4941
  import_ts_deepmerge5 = __toESM(require_dist());
4216
4942
  init_log();
4217
4943
  init_CubeFace();
4944
+ init_DisplayPosition();
4218
4945
  init_DisplayTransforms();
4219
4946
  init_ModelCulling();
4947
+ init_SpecialItems();
4948
+ init_EntityObject();
4949
+ init_GuiLight();
4220
4950
  p7 = prefix("ModelObject");
4221
4951
  ModelObject = class _ModelObject extends SceneObject {
4222
4952
  constructor(originalModel, options) {
4223
4953
  super(options);
4224
4954
  this.originalModel = originalModel;
4225
4955
  this.isModelObject = true;
4956
+ this.specialMaterials = /* @__PURE__ */ new Map();
4226
4957
  this.meshesCreated = false;
4227
4958
  this.options = (0, import_ts_deepmerge5.default)({}, _ModelObject.DEFAULT_OPTIONS, options ?? {});
4959
+ if (originalModel.special) this.options.instanceMeshes = false;
4228
4960
  if (this.options.tints) this.options.tints = { ...this.options.tints };
4229
4961
  this.addEventListener("added", () => this.updateAnimationSubscription());
4230
4962
  this.addEventListener("removed", () => this.updateAnimationSubscription());
@@ -4233,6 +4965,39 @@ var init_ModelObject = __esm({
4233
4965
  this.DEFAULT_OPTIONS = (0, import_ts_deepmerge5.default)({}, SceneObject.DEFAULT_OPTIONS, {});
4234
4966
  }
4235
4967
  async init() {
4968
+ const special = this.originalModel.special;
4969
+ if (special) {
4970
+ const parts = await SpecialItems.getParts(special, this.originalModel.key?.root);
4971
+ const transform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : new Matrix49();
4972
+ transform.multiply(new Matrix49().makeTranslation(-8, -8, -8));
4973
+ try {
4974
+ for (const part of parts) {
4975
+ const object = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe });
4976
+ object.matrix.copy(transform).multiply(part.transform);
4977
+ object.matrixAutoUpdate = false;
4978
+ this.add(object);
4979
+ await object.init();
4980
+ object.iterateAllMeshes((mesh) => {
4981
+ const source = mesh.material;
4982
+ let material = this.specialMaterials.get(source);
4983
+ if (!material) {
4984
+ const front = this.options.displayPosition === "gui" /* GUI */ && this.originalModel.gui_light === "front" /* FRONT */;
4985
+ material = SpecialItems.createMaterial(source, !front);
4986
+ this.specialMaterials.set(source, material);
4987
+ }
4988
+ mesh.material = material;
4989
+ });
4990
+ for (const [name, rotation] of Object.entries(part.rotations)) {
4991
+ object.getGroupByName(name)?.rotation.set(...rotation, "ZYX");
4992
+ }
4993
+ }
4994
+ } catch (error) {
4995
+ this.disposeAndRemoveAllChildren();
4996
+ throw error;
4997
+ }
4998
+ this.notifyDirty();
4999
+ return;
5000
+ }
4236
5001
  await this.loadTextures();
4237
5002
  this.createMeshes();
4238
5003
  this.applyTextures();
@@ -4282,12 +5047,12 @@ var init_ModelObject = __esm({
4282
5047
  }
4283
5048
  elGeo.setAttribute("color", new BufferAttribute5(colors, 3));
4284
5049
  }
4285
- elGeo.applyMatrix4(new Matrix48().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
4286
- elGeo.applyMatrix4(new Matrix48().makeTranslation(el.from[0], el.from[1], el.from[2]));
5050
+ elGeo.applyMatrix4(new Matrix49().makeTranslation((el.to[0] - el.from[0]) / 2, (el.to[1] - el.from[1]) / 2, (el.to[2] - el.from[2]) / 2));
5051
+ elGeo.applyMatrix4(new Matrix49().makeTranslation(el.from[0], el.from[1], el.from[2]));
4287
5052
  if (el.rotation) {
4288
5053
  applyElementRotation(el.rotation, elGeo);
4289
5054
  }
4290
- elGeo.applyMatrix4(new Matrix48().makeTranslation(-8, -8, -8));
5055
+ elGeo.applyMatrix4(new Matrix49().makeTranslation(-8, -8, -8));
4291
5056
  if (displayTransform) DisplayTransforms.apply(elGeo, displayTransform);
4292
5057
  if (this.options.mergeMeshes) {
4293
5058
  allGeos.push(elGeo);
@@ -4377,6 +5142,8 @@ var init_ModelObject = __esm({
4377
5142
  this.atlasMaterial?.dispose();
4378
5143
  this.atlasTexture = void 0;
4379
5144
  this.atlasMaterial = void 0;
5145
+ for (const material of this.specialMaterials.values()) material.dispose();
5146
+ this.specialMaterials.clear();
4380
5147
  super.disposeAndRemoveAllChildren();
4381
5148
  }
4382
5149
  };
@@ -4727,96 +5494,8 @@ var Meshes = class _Meshes {
4727
5494
  }
4728
5495
  };
4729
5496
 
4730
- // src/MinecraftCubeTexture.ts
4731
- init_UVMapper();
4732
- init_CubeFace();
4733
- var MinecraftCubeTexture = class {
4734
- constructor(u, v, width, height) {
4735
- this.u = u;
4736
- this.v = v;
4737
- this.width = width;
4738
- this.height = height;
4739
- }
4740
- mapW(x) {
4741
- return x / this.width;
4742
- }
4743
- mapH(x) {
4744
- return 1 - x / this.height;
4745
- }
4746
- getUvEast(w, h, l) {
4747
- return [
4748
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
4749
- [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
4750
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)],
4751
- [this.mapW(this.u + l + w), this.mapH(this.v + l)]
4752
- ];
4753
- }
4754
- getUvWest(w, h, l) {
4755
- return [
4756
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
4757
- [this.mapW(this.u), this.mapH(this.v + l + h)],
4758
- [this.mapW(this.u + l), this.mapH(this.v + l)],
4759
- [this.mapW(this.u), this.mapH(this.v + l)]
4760
- ];
4761
- }
4762
- getUvUp(w, h, l) {
4763
- return [
4764
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
4765
- [this.mapW(this.u + l + w + w), this.mapH(this.v + l)],
4766
- [this.mapW(this.u + l + w), this.mapH(this.v)],
4767
- [this.mapW(this.u + l + w + w), this.mapH(this.v)]
4768
- ];
4769
- }
4770
- getUvDown(w, h, l) {
4771
- return [
4772
- [this.mapW(this.u + l), this.mapH(this.v)],
4773
- [this.mapW(this.u + l + w), this.mapH(this.v)],
4774
- [this.mapW(this.u + l), this.mapH(this.v + l)],
4775
- [this.mapW(this.u + l + w), this.mapH(this.v + l)]
4776
- ];
4777
- }
4778
- getUvSouth(w, h, l) {
4779
- return [
4780
- [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l + h)],
4781
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l + h)],
4782
- [this.mapW(this.u + l + w + l + w), this.mapH(this.v + l)],
4783
- [this.mapW(this.u + l + w + l), this.mapH(this.v + l)]
4784
- ];
4785
- }
4786
- getUvNorth(w, h, l) {
4787
- return [
4788
- [this.mapW(this.u + l + w), this.mapH(this.v + l + h)],
4789
- [this.mapW(this.u + l), this.mapH(this.v + l + h)],
4790
- [this.mapW(this.u + l + w), this.mapH(this.v + l)],
4791
- [this.mapW(this.u + l), this.mapH(this.v + l)]
4792
- ];
4793
- }
4794
- getFaceUv(face, w, h, l) {
4795
- switch (face) {
4796
- case "east" /* EAST */:
4797
- return this.getUvEast(w, h, l);
4798
- case "west" /* WEST */:
4799
- return this.getUvWest(w, h, l);
4800
- case "up" /* UP */:
4801
- return this.getUvUp(w, h, l);
4802
- case "down" /* DOWN */:
4803
- return this.getUvDown(w, h, l);
4804
- case "south" /* SOUTH */:
4805
- return this.getUvSouth(w, h, l);
4806
- case "north" /* NORTH */:
4807
- return this.getUvNorth(w, h, l);
4808
- }
4809
- }
4810
- toUvArray(w, h, l, mirror = false) {
4811
- const uv = [];
4812
- for (let i = 0; i < CUBE_FACES.length; i++) {
4813
- const face = mirror && i < 2 ? CUBE_FACES[1 - i] : CUBE_FACES[i];
4814
- const corners = this.getFaceUv(face, w, h, l);
4815
- UVMapper.setFaceUvInArray(uv, i * 4, mirror ? [corners[1], corners[0], corners[3], corners[2]] : corners);
4816
- }
4817
- return uv;
4818
- }
4819
- };
5497
+ // src/index.ts
5498
+ init_MinecraftCubeTexture();
4820
5499
 
4821
5500
  // src/SceneStats.ts
4822
5501
  var SceneStats = class {
@@ -4910,116 +5589,7 @@ var BlockEntities = class {
4910
5589
 
4911
5590
  // src/assets/index.ts
4912
5591
  init_BlockStates();
4913
-
4914
- // src/assets/Entities.ts
4915
- init_AssetKey();
4916
- init_AssetLoader();
4917
- init_source();
4918
- init_Caching();
4919
- init_Assets();
4920
- init_MineRenderError();
4921
- init_ModelTextures();
4922
- var Entities = class {
4923
- static async getEntityList() {
4924
- const collect = async (path) => {
4925
- const prefix2 = path ? `${path}/` : "";
4926
- const key = new AssetKey(DEFAULT_NAMESPACE, `${prefix2}_list`, void 0, void 0, "entity-models", ".json");
4927
- const list = await Caching.listAssetCache.get(key.serialize(), () => AssetLoader.get(key, "list" /* LIST */));
4928
- if (!list) return [];
4929
- const files = list.files.filter((file) => file.endsWith(".json") && file !== "_list.json").map((file) => `${prefix2}${file.slice(0, -5)}`);
4930
- const children = await Promise.all(list.directories.map((directory) => collect(`${prefix2}${directory}`)));
4931
- return [...files, ...children.flat()];
4932
- };
4933
- return collect("");
4934
- }
4935
- static async getModelFile(modelKey) {
4936
- const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4937
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
4938
- return Caching.entityModelCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4939
- }
4940
- static async getLayerList(modelKey) {
4941
- return Object.keys((await this.getModelFile(modelKey))?.layers ?? {});
4942
- }
4943
- /** The dataset's extra draws on top of `main`; their `when` labels are the states `EntityModelOptions.when` can enable. */
4944
- static async getPassList(modelKey) {
4945
- return (await this.getModelFile(modelKey))?.passes ?? [];
4946
- }
4947
- static async getEntity(modelKey, textureKey, options) {
4948
- const model = await this.getModelFile(modelKey);
4949
- if (!model) return void 0;
4950
- const passes = options?.layers || options?.layer !== void 0 ? [] : (model.passes ?? []).filter((pass) => pass.when === void 0 || options?.when?.includes(pass.when));
4951
- const draws = [...new Set(options?.layers ?? [options?.layer ?? "main"])].map((layer) => ({ layer }));
4952
- if (draws.length === 0) throw new MineRenderError(`Entity ${model.id} requires at least one layer`);
4953
- draws.push(...passes);
4954
- const names = [];
4955
- const selected = draws.map((pass) => {
4956
- const layer = model.layers[pass.layer];
4957
- if (!layer) {
4958
- throw new MineRenderError(`Entity ${model.id} has no layer "${pass.layer}". Available layers: ${Object.keys(model.layers).join(", ")}`);
4959
- }
4960
- let name = pass.layer;
4961
- for (let n = 2; names.includes(name); n++) name = `${pass.layer}#${n}`;
4962
- names.push(name);
4963
- return { name, layer, pass };
4964
- });
4965
- const layers = Object.fromEntries(await Promise.all(selected.map(async ({ name, layer, pass }, index) => {
4966
- const override = options?.textures?.[name] ?? (index === 0 ? textureKey : void 0);
4967
- const textureLocation = pass.textureLocation ?? layer.textureLocation;
4968
- let texture;
4969
- if (override) {
4970
- const path = isAssetKey(override) ? override.getFullPath() : override.path;
4971
- 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);
4972
- } else if (textureLocation !== void 0) {
4973
- texture = AssetKey.parse("textures", textureLocation.replace(/^([^:]+:)?textures\//, "$1"));
4974
- } else {
4975
- texture = await this.resolveTexture(modelKey);
4976
- }
4977
- const render = pass.render ?? layer.render;
4978
- return [name, { key: override ?? modelKey, texture, layer, ...render && { render }, ...pass.tint && { tint: pass.tint } }];
4979
- })));
4980
- return { ...layers[names[0]], id: model.id, layers, ...model.transform && { transform: model.transform } };
4981
- }
4982
- /**
4983
- * Vanilla's keyframe animations of a model by name, or undefined when the model or the selected version has none.
4984
- */
4985
- static async getAnimations(modelKey) {
4986
- const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4987
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models/animations", ".json");
4988
- const file = await Caching.entityAnimationCache.get(key.serialize(), () => AssetLoader.get(key, "json" /* JSON */));
4989
- return file?.animations;
4990
- }
4991
- static async resolveTexture(modelKey) {
4992
- const path = isAssetKey(modelKey) ? modelKey.getFullPath() : modelKey.path;
4993
- const key = new AssetKey(modelKey.namespace, path, void 0, void 0, "entity-models", ".json");
4994
- return Caching.entityTextureCache.get(key.serialize(), async () => {
4995
- const name = path.split("/").pop();
4996
- for (const candidate of [path, `${path}/${name}`]) {
4997
- const texture = new AssetKey(modelKey.namespace, candidate, "textures", "entity", "assets", ".png");
4998
- if (await ModelTextures.get(texture)) return texture;
4999
- }
5000
- const listKey = new AssetKey(modelKey.namespace, "_list", `${name}_variant`, void 0, "data", ".json");
5001
- const list = await AssetLoader.get(listKey, "list" /* LIST */);
5002
- const files = list?.files.filter((file2) => file2.endsWith(".json") && file2 !== "_list.json");
5003
- const file = files?.find((file2) => file2 === "temperate.json") ?? files?.[0];
5004
- if (!file) return void 0;
5005
- const variantKey = new AssetKey(modelKey.namespace, file.slice(0, -5), `${name}_variant`, void 0, "data", ".json");
5006
- const variant = await AssetLoader.get(variantKey, "json" /* JSON */);
5007
- const assets = variant?.assets;
5008
- const textureId = variant?.asset_id ?? (typeof assets?.wild === "string" ? assets.wild : Object.values(assets ?? {}).find((value) => typeof value === "string"));
5009
- return typeof textureId === "string" ? AssetKey.parse("textures", textureId) : void 0;
5010
- });
5011
- }
5012
- /** @deprecated Use getEntityList(); block entities share the entity dataset. */
5013
- static getBlockList() {
5014
- return this.getEntityList();
5015
- }
5016
- /** @deprecated Use getEntity(); block entities share the entity dataset. */
5017
- static getBlock(modelKey, textureKey, options) {
5018
- return this.getEntity(modelKey, textureKey, options);
5019
- }
5020
- };
5021
-
5022
- // src/assets/index.ts
5592
+ init_Entities();
5023
5593
  init_ModelTextures();
5024
5594
  init_Models();
5025
5595
  init_source();
@@ -5064,347 +5634,12 @@ function trimCanvas(source) {
5064
5634
  return canvas;
5065
5635
  }
5066
5636
 
5067
- // src/entity/EntityAnimation.ts
5068
- var ENTITY_ANIMATION_CHANNELS = ["position", "rotation", "scale"];
5069
- function catmullRom(delta, p0, p1, p22, p32) {
5070
- return 0.5 * (2 * p1 + (p22 - p0) * delta + (2 * p0 - 5 * p1 + 4 * p22 - p32) * delta * delta + (3 * p1 - p0 - 3 * p22 + p32) * delta * delta * delta);
5071
- }
5072
- function sampleEntityKeyframes(keyframes, time) {
5073
- if (keyframes.length === 0) return [0, 0, 0];
5074
- let low = 0, high = keyframes.length;
5075
- while (low < high) {
5076
- const middle = low + high >>> 1;
5077
- if (time <= keyframes[middle].time) high = middle;
5078
- else low = middle + 1;
5079
- }
5080
- const a = Math.max(0, low - 1);
5081
- const b = Math.min(keyframes.length - 1, a + 1);
5082
- const from = keyframes[a];
5083
- const to = keyframes[b];
5084
- const delta = a === b ? 0 : Math.min(1, Math.max(0, (time - from.time) / (to.time - from.time)));
5085
- if (to.interpolation === "catmullrom") {
5086
- const before = keyframes[Math.max(0, a - 1)].value;
5087
- const after = keyframes[Math.min(keyframes.length - 1, b + 1)].value;
5088
- return [0, 1, 2].map((i) => catmullRom(delta, before[i], from.value[i], to.value[i], after[i]));
5089
- }
5090
- const target = to.pre ?? to.value;
5091
- return [0, 1, 2].map((i) => from.value[i] + (target[i] - from.value[i]) * delta);
5092
- }
5093
- function entityAnimationTime(animation, time, loop = animation.loop) {
5094
- return loop && animation.length > 0 ? time % animation.length : time;
5095
- }
5096
- function sampleEntityAnimation(animation, time, loop = animation.loop) {
5097
- const elapsed = entityAnimationTime(animation, time, loop);
5098
- const pose = {};
5099
- for (const [name, bone] of Object.entries(animation.bones)) {
5100
- const sampled = pose[name] = {};
5101
- for (const channel of ENTITY_ANIMATION_CHANNELS) {
5102
- const keyframes = bone[channel];
5103
- if (keyframes?.length) sampled[channel] = sampleEntityKeyframes(keyframes, elapsed);
5104
- }
5105
- }
5106
- return pose;
5107
- }
5108
-
5109
- // src/entity/scene/EntityAnimationPlayer.ts
5110
- var ZERO = [0, 0, 0];
5111
- var EntityAnimationPlayer = class {
5112
- constructor() {
5113
- this.parts = [];
5114
- this._time = 0;
5115
- this.loop = false;
5116
- this.speed = 1;
5117
- }
5118
- get animation() {
5119
- return this._animation;
5120
- }
5121
- get time() {
5122
- return this._time;
5123
- }
5124
- /**
5125
- * Starts an animation on the named parts below each layer root. The current pose of a part becomes its default;
5126
- * bones without a matching part are skipped.
5127
- */
5128
- play(layers, animation, options = {}) {
5129
- this.stop();
5130
- this._animation = animation;
5131
- this._time = options.time ?? 0;
5132
- this.loop = options.loop ?? animation.loop;
5133
- this.speed = options.speed ?? 1;
5134
- for (const layer of layers) {
5135
- for (const bone of Object.keys(animation.bones)) {
5136
- const object = layer.getObjectByName(`group:${bone}`);
5137
- if (!object) continue;
5138
- this.parts.push({ bone, object, position: object.position.clone(), rotation: object.rotation.clone(), scale: object.scale.clone() });
5139
- }
5140
- }
5141
- this.apply();
5142
- }
5143
- /** Restores the default poses. Returns whether an animation was active. */
5144
- stop() {
5145
- if (!this._animation) return false;
5146
- for (const part of this.parts) {
5147
- part.object.position.copy(part.position);
5148
- part.object.rotation.copy(part.rotation);
5149
- part.object.scale.copy(part.scale);
5150
- }
5151
- this.clear();
5152
- return true;
5153
- }
5154
- /** Forgets the animation without touching the parts, for parts that no longer exist. */
5155
- clear() {
5156
- this.parts = [];
5157
- this._animation = void 0;
5158
- this._time = 0;
5159
- }
5160
- setTime(seconds) {
5161
- if (!this._animation) return false;
5162
- this._time = seconds;
5163
- this.apply();
5164
- return true;
5165
- }
5166
- advance(deltaSeconds) {
5167
- return this.setTime(this._time + deltaSeconds * this.speed);
5168
- }
5169
- apply() {
5170
- const pose = sampleEntityAnimation(this._animation, this._time, this.loop);
5171
- for (const part of this.parts) {
5172
- const { position = ZERO, rotation = ZERO, scale = ZERO } = pose[part.bone];
5173
- part.object.position.set(part.position.x + position[0], part.position.y + position[1], part.position.z + position[2]);
5174
- part.object.rotation.set(part.rotation.x + rotation[0], part.rotation.y + rotation[1], part.rotation.z + rotation[2], part.rotation.order);
5175
- part.object.scale.set(part.scale.x + scale[0], part.scale.y + scale[1], part.scale.z + scale[2]);
5176
- }
5177
- }
5178
- };
5637
+ // src/entity/index.ts
5638
+ init_EntityAnimation();
5179
5639
 
5180
- // src/entity/scene/EntityObject.ts
5181
- init_SceneObject();
5182
- init_Caching();
5183
- var import_ts_deepmerge4 = __toESM(require_dist());
5184
- init_Ticker();
5185
- init_model();
5186
- init_ModelTextures();
5187
- init_AssetKey();
5188
- init_Materials();
5189
- import { Color as Color3, Euler as Euler4, Matrix4 as Matrix45, Object3D as Object3D3 } from "three";
5190
- init_three();
5191
- var EntityObject = class _EntityObject extends SceneObject {
5192
- constructor(entity, options) {
5193
- super();
5194
- this.entity = entity;
5195
- this.isEntityObject = true;
5196
- this.meshesCreated = false;
5197
- this.geometries = /* @__PURE__ */ new Set();
5198
- this.disposeWireframes = [];
5199
- /** Scrolling materials are owned: their texture offset follows this entity's age. */
5200
- this.scrollMaterials = [];
5201
- /** Entity age in ticks, as vanilla's `ageInTicks`; drives the scrolling render modes. */
5202
- this.age = 0;
5203
- this.animationPlayer = new EntityAnimationPlayer();
5204
- this.options = (0, import_ts_deepmerge4.default)({}, _EntityObject.DEFAULT_OPTIONS, options ?? {});
5205
- this.addEventListener("added", () => this.updateScrollSubscription());
5206
- this.addEventListener("removed", () => this.updateScrollSubscription());
5207
- }
5208
- static {
5209
- this.DEFAULT_OPTIONS = (0, import_ts_deepmerge4.default)({}, SceneObject.DEFAULT_OPTIONS);
5210
- }
5211
- async init() {
5212
- this.createMeshes();
5213
- await this.applyTextures();
5214
- }
5215
- dispose() {
5216
- super.dispose();
5217
- }
5218
- disposeAndRemoveAllChildren() {
5219
- this.clearScrollMaterials();
5220
- for (const geometry of this.geometries) geometry.dispose();
5221
- this.geometries.clear();
5222
- for (const dispose of this.disposeWireframes.splice(0)) dispose();
5223
- this.animationPlayer.clear();
5224
- super.disposeAndRemoveAllChildren();
5225
- }
5226
- clearScrollMaterials() {
5227
- Ticker.remove(this.scrollTicker);
5228
- this.scrollTicker = void 0;
5229
- for (const { material } of this.scrollMaterials.splice(0)) {
5230
- material.map?.dispose();
5231
- material.dispose();
5232
- }
5233
- }
5234
- updateScrollSubscription() {
5235
- if (this.parent && this.scrollMaterials.length) {
5236
- if (this.scrollTicker === void 0) {
5237
- this.scrollTicker = Ticker.add(() => {
5238
- this.age++;
5239
- this.updateScroll();
5240
- });
5241
- }
5242
- } else {
5243
- Ticker.remove(this.scrollTicker);
5244
- this.scrollTicker = void 0;
5245
- }
5246
- }
5247
- /** Applies the entity age to the scrolling materials; the ticker calls this 20 times per second. */
5248
- updateScroll() {
5249
- for (const { offset, speed } of this.scrollMaterials) {
5250
- offset.set(this.age * speed[0] % 1, 0 - this.age * speed[1] % 1);
5251
- }
5252
- this.notifyDirty();
5253
- }
5254
- //<editor-fold desc="ANIMATION">
5255
- /** The animation started by {@link playAnimation}, until {@link stopAnimation} or disposal. */
5256
- get animation() {
5257
- return this.animationPlayer.animation;
5258
- }
5259
- /** Seconds since the animation started, before looping. */
5260
- get animationTime() {
5261
- return this.animationPlayer.time;
5262
- }
5263
- /**
5264
- * Poses the object from a keyframe animation of {@link Entities.getAnimations}, replacing the current one.
5265
- * Parts of every layer are matched by name and their current pose is the default the offsets add to.
5266
- * The object owns no clock: call {@link advanceAnimation} per frame, or {@link setAnimationTime}.
5267
- */
5268
- playAnimation(animation, options) {
5269
- this.createMeshes();
5270
- const layers = Object.keys(this.entityLayers).map((name) => this.getLayerGroup(name)).filter((layer) => !!layer);
5271
- this.animationPlayer.play(layers, animation, options);
5272
- this.notifyDirty();
5273
- }
5274
- /** Stops the animation and restores the default pose. */
5275
- stopAnimation() {
5276
- if (this.animationPlayer.stop()) this.notifyDirty();
5277
- }
5278
- /** Poses the object at an explicit time in seconds. Has no effect without an animation. */
5279
- setAnimationTime(seconds) {
5280
- if (this.animationPlayer.setTime(seconds)) this.notifyDirty();
5281
- }
5282
- /** Advances the animation by a frame delta in seconds, scaled by its speed. Has no effect without an animation. */
5283
- advanceAnimation(deltaSeconds) {
5284
- if (this.animationPlayer.advance(deltaSeconds)) this.notifyDirty();
5285
- }
5286
- //</editor-fold>
5287
- getLayerGroup(name) {
5288
- return super.getGroupByName(`layer:${name}`);
5289
- }
5290
- getGroupByName(name, layerName) {
5291
- return layerName === void 0 ? super.getGroupByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`group:${name}`);
5292
- }
5293
- getMeshByName(name, layerName) {
5294
- return layerName === void 0 ? super.getMeshByName(name) : this.getLayerGroup(layerName)?.getObjectByName(`mesh:${name}`);
5295
- }
5296
- get entityLayers() {
5297
- return this.entity.layers ?? { main: this.entity };
5298
- }
5299
- getTextureKey(layer) {
5300
- if (layer.texture) return layer.texture;
5301
- const key = layer.key;
5302
- return new AssetKey(
5303
- key.namespace,
5304
- isAssetKey(key) ? key.getFullPath() : key.path,
5305
- "textures",
5306
- "entity",
5307
- "assets",
5308
- ".png"
5309
- );
5310
- }
5311
- async loadTextures(layer = this.entity) {
5312
- return ModelTextures.get(this.getTextureKey(layer));
5313
- }
5314
- createMeshes(force = false) {
5315
- if (this.meshesCreated && !force) return;
5316
- const modelRoot = new Object3D3();
5317
- const transform = this.options.flip === void 0 ? this.entity.transform : void 0;
5318
- if (transform) {
5319
- for (const op of transform) {
5320
- const matrix = new Matrix45();
5321
- if ("scale" in op) matrix.makeScale(...op.scale);
5322
- else if ("translate" in op) matrix.makeTranslation(...op.translate);
5323
- else matrix.makeRotationFromEuler(new Euler4(...op.rotate, "ZYX"));
5324
- modelRoot.matrix.multiply(matrix);
5325
- }
5326
- modelRoot.matrixAutoUpdate = false;
5327
- } else if (this.options.flip ?? true) {
5328
- modelRoot.scale.set(-1, -1, 1);
5329
- }
5330
- this.add(modelRoot);
5331
- Object.entries(this.entityLayers).forEach(([name, layer], index) => {
5332
- const group = this.createGroup(`layer:${name}`);
5333
- modelRoot.add(group);
5334
- const inward = !Materials.entityModeCulls(layer.render ?? layer.layer.render);
5335
- this.createPart("root", layer.layer.root, group, layer.layer.texture, Materials.MISSING_TEXTURE, index, inward);
5336
- });
5337
- this.meshesCreated = true;
5338
- }
5339
- createPart(name, part, parent, textureSize, material, renderOrder, inward = true) {
5340
- const anchor = this.createGroup(name);
5341
- anchor.position.fromArray(part.pose.offset);
5342
- anchor.rotation.set(...part.pose.rotation, "ZYX");
5343
- anchor.scale.fromArray(part.pose.scale ?? [1, 1, 1]);
5344
- parent.add(anchor);
5345
- const size = part.texture ?? textureSize;
5346
- for (const cube of part.cubes) {
5347
- const [width, height, depth] = cube.size;
5348
- const [growX, growY, growZ] = cube.grow ?? [0, 0, 0];
5349
- const texture = new MinecraftCubeTexture(...cube.uv, ...size);
5350
- const uv = size[0] === 0 || size[1] === 0 ? new Array(48).fill(0) : texture.toUvArray(width, height, depth, cube.mirror);
5351
- const geometry = this._getBoxGeometryForDimensionsAndUv(
5352
- width + growX * 2,
5353
- height + growY * 2,
5354
- depth + growZ * 2,
5355
- uv
5356
- ).clone();
5357
- this.geometries.add(geometry);
5358
- geometry.translate(cube.origin[0] + width / 2, cube.origin[1] + height / 2, cube.origin[2] + depth / 2);
5359
- if (inward && Math.min(width + growX * 2, height + growY * 2, depth + growZ * 2) > 0) {
5360
- const index = Array.from(geometry.getIndex().array);
5361
- geometry.setIndex(index.concat(index.slice().reverse()));
5362
- }
5363
- const mesh = this.createMesh(name, geometry, material);
5364
- mesh.renderOrder = renderOrder;
5365
- anchor.add(mesh);
5366
- if (this.options.wireframe) this.disposeWireframes.push(addWireframeToMesh(geometry, mesh));
5367
- }
5368
- for (const [childName, child] of Object.entries(part.children)) {
5369
- this.createPart(childName, child, anchor, size, material, renderOrder, inward);
5370
- }
5371
- }
5372
- async applyTextures() {
5373
- this.clearScrollMaterials();
5374
- await Promise.all(Object.entries(this.entityLayers).map(async ([name, layer]) => {
5375
- const mode = layer.render ?? layer.layer.render ?? "cutout";
5376
- const tint = layer.tint === void 0 ? void 0 : this.options.tints?.[layer.tint];
5377
- const scroll = Materials.entityModeScroll(mode);
5378
- const assetKeyStr = this.getTextureKey(layer).serialize();
5379
- const keyStr = `entity:${mode}:${tint === void 0 ? "" : new Color3(tint).getHexString()}:${assetKeyStr}`;
5380
- let mat = scroll ? void 0 : Caching.materialCache.getIfPresent(keyStr);
5381
- if (!mat) {
5382
- const cachedAsset = Caching.textureAssetCache.getIfPresent(assetKeyStr);
5383
- const imageData = await this.loadTextures(layer);
5384
- if (!imageData) return;
5385
- const canvas = imageData.data.canvas;
5386
- const createMaterial = () => Materials.createEntityCanvasMaterial(canvas, mode, tint);
5387
- mat = !scroll && cachedAsset && Caching.textureAssetCache.getIfPresent(assetKeyStr) === cachedAsset ? Caching.materialCache.get(keyStr, createMaterial) : createMaterial();
5388
- if (scroll) {
5389
- this.scrollMaterials.push({ material: mat, offset: mat.map.offset, speed: scroll });
5390
- }
5391
- }
5392
- this.getLayerGroup(name)?.traverse((object) => {
5393
- if (isMesh(object)) object.material = mat;
5394
- });
5395
- }));
5396
- if (!this.children.length) {
5397
- this.clearScrollMaterials();
5398
- } else if (this.scrollMaterials.length) {
5399
- this.updateScroll();
5400
- }
5401
- this.updateScrollSubscription();
5402
- this.notifyDirty();
5403
- }
5404
- };
5405
- function isEntityObject(obj) {
5406
- return obj.isEntityObject;
5407
- }
5640
+ // src/entity/scene/index.ts
5641
+ init_EntityAnimationPlayer();
5642
+ init_EntityObject();
5408
5643
 
5409
5644
  // src/error/index.ts
5410
5645
  init_MineRenderError();
@@ -8033,16 +8268,8 @@ init_SceneObject();
8033
8268
  init_Materials();
8034
8269
  init_ModelObject();
8035
8270
  init_DisplayPosition();
8036
- import { Box2, Box3 as Box32, Mesh as Mesh7, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
8037
-
8038
- // src/model/GuiLight.ts
8039
- var GuiLight = /* @__PURE__ */ ((GuiLight2) => {
8040
- GuiLight2["FRONT"] = "front";
8041
- GuiLight2["SIDE"] = "side";
8042
- return GuiLight2;
8043
- })(GuiLight || {});
8044
-
8045
- // src/gui/scene/GuiObject.ts
8271
+ init_GuiLight();
8272
+ import { Box2, Box3 as Box32, Matrix4 as Matrix410, Mesh as Mesh7, PlaneGeometry as PlaneGeometry2, Vector2 as Vector23 } from "three";
8046
8273
  var GuiObject = class extends SceneObject {
8047
8274
  constructor(textureLayers, options) {
8048
8275
  super({ ...options, instanceMeshes: false, mergeMeshes: false });
@@ -8065,13 +8292,13 @@ var GuiObject = class extends SceneObject {
8065
8292
  const item = await this.createItem(layer, index);
8066
8293
  item.position.set(x + width2 / 2, -y - height2 / 2, 0);
8067
8294
  item.scale.set(width2 / 16, height2 / 16, width2 / 16);
8068
- item.updateMatrix();
8295
+ item.updateWorldMatrix(true, true);
8296
+ const inverse = this.matrixWorld.clone().invert();
8069
8297
  const bounds = new Box32();
8070
8298
  item.iterateAllMeshes((mesh2) => {
8071
8299
  mesh2.geometry.computeBoundingBox();
8072
- bounds.union(mesh2.geometry.boundingBox);
8300
+ bounds.union(mesh2.geometry.boundingBox.clone().applyMatrix4(new Matrix410().multiplyMatrices(inverse, mesh2.matrixWorld)));
8073
8301
  });
8074
- bounds.applyMatrix4(item.matrix);
8075
8302
  item.position.z = depth - bounds.min.z;
8076
8303
  depth += bounds.max.z - bounds.min.z + 0.01;
8077
8304
  this.bounds.expandByPoint(new Vector23(x, y));
@@ -8126,7 +8353,7 @@ var GuiObject = class extends SceneObject {
8126
8353
  this.add(item);
8127
8354
  await item.init();
8128
8355
  item.iterateAllMeshes((mesh) => {
8129
- this.geometries.add(mesh.geometry);
8356
+ if (!model.special) this.geometries.add(mesh.geometry);
8130
8357
  mesh.name = `mesh:${layer.name ?? index}`;
8131
8358
  mesh.renderOrder = index;
8132
8359
  for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
@@ -8584,26 +8811,12 @@ function isInstanceable(obj) {
8584
8811
  // src/model/index.ts
8585
8812
  init_DisplayPosition();
8586
8813
  init_DisplayTransforms();
8587
-
8588
- // src/model/Model.ts
8589
- var ITEM_GENERATED = "item/generated";
8590
- var BUILTIN_GENERATED = "builtin/generated";
8591
- var BUILTIN_ENTITY = "builtin/entity";
8592
- var DEFAULT_ELEMENTS = [];
8593
- function isDoubleArray(obj) {
8594
- return Array.isArray(obj) && obj.length === 2;
8595
- }
8596
- function isTripleArray(obj) {
8597
- return Array.isArray(obj) && obj.length === 3;
8598
- }
8599
- function isQuadArray(obj) {
8600
- return Array.isArray(obj) && obj.length === 4;
8601
- }
8602
-
8603
- // src/model/index.ts
8814
+ init_GuiLight();
8815
+ init_Model();
8604
8816
  init_ModelCulling();
8605
8817
  init_ModelGenerator();
8606
8818
  init_ModelMerger();
8819
+ init_SpecialItems();
8607
8820
 
8608
8821
  // src/model/block/BlockStateResolver.ts
8609
8822
  init_BlockStates();
@@ -8794,9 +9007,10 @@ var import_ts_deepmerge6 = __toESM(require_dist());
8794
9007
  init_MineRenderError();
8795
9008
  init_InstanceReference();
8796
9009
  init_AssetKey();
8797
- import { Euler as Euler8, Matrix4 as Matrix49, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
9010
+ import { Euler as Euler8, Matrix4 as Matrix411, Quaternion as Quaternion5, Vector3 as Vector311 } from "three";
8798
9011
  init_ModelCulling();
8799
9012
  init_FluidGeometry();
9013
+ init_Entities();
8800
9014
  var BlockObject = class _BlockObject extends SceneObject {
8801
9015
  constructor(blockState, options) {
8802
9016
  super(options);
@@ -8812,7 +9026,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8812
9026
  this._models = [];
8813
9027
  this._cullMask = 0;
8814
9028
  this._entities = [];
8815
- this._entityPlacement = new Matrix49();
9029
+ this._entityPlacement = new Matrix411();
8816
9030
  this._entityGeneration = 0;
8817
9031
  this.options = (0, import_ts_deepmerge6.default)({}, _BlockObject.DEFAULT_OPTIONS, options ?? {});
8818
9032
  }
@@ -8897,7 +9111,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8897
9111
  return true;
8898
9112
  }
8899
9113
  placeEntities() {
8900
- const matrix = new Matrix49().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
9114
+ const matrix = new Matrix411().makeTranslation(this.position.x - 8, this.position.y - 8, this.position.z - 8).multiply(this._entityPlacement);
8901
9115
  for (const entity of this._entities) {
8902
9116
  matrix.decompose(entity.position, entity.quaternion, entity.scale);
8903
9117
  }
@@ -8983,7 +9197,7 @@ var BlockObject = class _BlockObject extends SceneObject {
8983
9197
  () => new FluidModelObject2(kind, surface.sample, this.blockState.key, this.options)
8984
9198
  );
8985
9199
  const previous = this._fluidModel;
8986
- const matrix = previous ? this.getModelMatrix(previous) : new Matrix49().makeTranslation(...this.position.toArray());
9200
+ const matrix = previous ? this.getModelMatrix(previous) : new Matrix411().makeTranslation(...this.position.toArray());
8987
9201
  if (isInstanceReference(replacement)) replacement.setMatrix(matrix);
8988
9202
  else matrix.decompose(replacement.position, replacement.quaternion, replacement.scale);
8989
9203
  this._models = this._models.filter((model) => model !== previous);
@@ -9121,7 +9335,7 @@ var BlockObject = class _BlockObject extends SceneObject {
9121
9335
  setPositionRotationScaleAt(index, position, rotation, scale) {
9122
9336
  super.setPositionRotationScaleAt(index, position, rotation, scale);
9123
9337
  }
9124
- getMatrixAt(index, matrix = new Matrix49()) {
9338
+ getMatrixAt(index, matrix = new Matrix411()) {
9125
9339
  if (!this.isInstanced) throw new MineRenderError("Object is not instanced");
9126
9340
  const child = this._models[0];
9127
9341
  if (child && isModelObject(child)) {
@@ -11724,7 +11938,7 @@ init_util();
11724
11938
  init_Caching();
11725
11939
  init_CacheKey();
11726
11940
  init_MineRenderError();
11727
- import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial5, SRGBColorSpace as SRGBColorSpace5 } from "three";
11941
+ import { DataTexture as DataTexture2, DoubleSide as DoubleSide4, FrontSide as FrontSide2, MeshBasicMaterial as MeshBasicMaterial6, SRGBColorSpace as SRGBColorSpace5 } from "three";
11728
11942
 
11729
11943
  // src/skin/SkinImage.ts
11730
11944
  init_Caching();
@@ -11809,7 +12023,7 @@ var SkinTextures = class {
11809
12023
  texture.colorSpace = SRGBColorSpace5;
11810
12024
  texture.flipY = true;
11811
12025
  texture.needsUpdate = true;
11812
- return new MeshBasicMaterial5({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
12026
+ return new MeshBasicMaterial6({ map: texture, transparent, side: transparent ? DoubleSide4 : FrontSide2, alphaTest: transparent ? 0.1 : 0 });
11813
12027
  }
11814
12028
  static isSlim(image, scale) {
11815
12029
  for (const [x, y] of [[46, 52], [54, 20]]) {
@@ -12037,6 +12251,7 @@ var SkinObject = class extends SceneObject {
12037
12251
  };
12038
12252
 
12039
12253
  // src/renderer/MineRenderScene.ts
12254
+ init_EntityObject();
12040
12255
  var MineRenderScene = class _MineRenderScene extends Scene5 {
12041
12256
  constructor(options) {
12042
12257
  super();
@@ -12168,9 +12383,10 @@ function isMineRenderScene(obj) {
12168
12383
  import { AxesHelper as AxesHelper2, GridHelper, OrthographicCamera, PCFSoftShadowMap, PerspectiveCamera as PerspectiveCamera2, SRGBColorSpace as SRGBColorSpace6, Vector3 as Vector313, WebGLRenderer as WebGLRenderer2 } from "three";
12169
12384
  var import_ts_deepmerge9 = __toESM(require_dist());
12170
12385
  init_util();
12386
+ init_Model();
12387
+ init_three();
12171
12388
  import Stats from "stats.js";
12172
12389
  import { EffectComposer, RenderPass } from "postprocessing";
12173
- init_three();
12174
12390
 
12175
12391
  // src/three/OrbitControls.js
12176
12392
  import {
@@ -13674,6 +13890,7 @@ init_BlockStates();
13674
13890
  init_AssetKey();
13675
13891
 
13676
13892
  // src/world/MineRenderWorld.ts
13893
+ init_Model();
13677
13894
  import { Vector3 as Vector315 } from "three";
13678
13895
  init_BatchedExecutor();
13679
13896
  init_AssetKey();
@@ -13684,7 +13901,7 @@ init_CubeFace();
13684
13901
  init_AssetKey();
13685
13902
  init_Models();
13686
13903
  init_CubeFace();
13687
- import { Matrix4 as Matrix410, Vector3 as Vector314 } from "three";
13904
+ import { Matrix4 as Matrix412, Vector3 as Vector314 } from "three";
13688
13905
  init_ModelCulling();
13689
13906
  init_ModelObject();
13690
13907
  init_UVMapper();
@@ -13747,7 +13964,7 @@ var SectionModels = class {
13747
13964
  });
13748
13965
  await object.init();
13749
13966
  const geometry = object.children[0].geometry;
13750
- geometry.applyMatrix4(new Matrix410().makeRotationFromEuler(rotation));
13967
+ geometry.applyMatrix4(new Matrix412().makeRotationFromEuler(rotation));
13751
13968
  object.clear();
13752
13969
  const cullFaces = CUBE_FACES.map((face) => {
13753
13970
  const local = CUBE_FACES.findIndex((name) => name === atlas.model.elements[0].faces[face]?.cullface);
@@ -13994,6 +14211,9 @@ var MineRenderWorld = class {
13994
14211
  }
13995
14212
  };
13996
14213
 
14214
+ // src/world/Chunk.ts
14215
+ init_Model();
14216
+
13997
14217
  // src/world/SectionMesh.ts
13998
14218
  init_CanvasCompat();
13999
14219
  init_Materials();
@@ -14342,6 +14562,7 @@ export {
14342
14562
  SkinPart,
14343
14563
  SkinTextures,
14344
14564
  Skins,
14565
+ SpecialItems,
14345
14566
  StructureParser,
14346
14567
  TextureAtlas,
14347
14568
  TextureLoader,