@nodecraft/rendermite 1.6.7 → 1.7.0

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.
Files changed (44) hide show
  1. package/assets/builtin/mobheads/models/item/base/head_64_64_hat.json +31 -0
  2. package/assets/builtin/mobheads/models/item/player_skin.json +7 -0
  3. package/assets/builtin/renderchest/models/block/wall_sign.json +3 -3
  4. package/dist/{block-entities-XAynAVUE.js → block-entities-CPQeb5dV.js} +1 -1
  5. package/dist/blocks/block-entities.js +1 -1
  6. package/dist/blocks/blockstate-eval.js +1 -1
  7. package/dist/blocks/cli.js +1 -1
  8. package/dist/blocks/ender-storage.d.ts +1 -1
  9. package/dist/blocks/entities.d.ts +1 -1
  10. package/dist/blocks/entity-models.d.ts +24 -2
  11. package/dist/blocks/entity-models.js +2 -2
  12. package/dist/blocks/export.js +1 -1
  13. package/dist/blocks/geo-blocks.d.ts +1 -1
  14. package/dist/blocks/item-sprites.d.ts +1 -1
  15. package/dist/blocks/pack-format.d.ts +2 -2
  16. package/dist/blocks/pack-format.js +2 -1
  17. package/dist/blocks/sprite-sheet.d.ts +1 -1
  18. package/dist/{blockstate-eval-BRQ3NWY2.js → blockstate-eval-CV_LwUwj.js} +1 -1
  19. package/dist/{cli-FiMsJbQx.js → cli-DFIB9i9c.js} +1 -1
  20. package/dist/cli.js +2 -2
  21. package/dist/dynamic/generators.js +1 -1
  22. package/dist/entities/inherit.js +1 -1
  23. package/dist/entities/link.d.ts +1 -1
  24. package/dist/entities/model-bytecode.d.ts +16 -1
  25. package/dist/entities/model-bytecode.js +2 -2
  26. package/dist/entity-models-DUKiHpn1.js +406 -0
  27. package/dist/{export-CxocMT1x.js → export-DlXOK8_D.js} +5 -4
  28. package/dist/{generators-BCZVlWig.js → generators-D6giKoab.js} +1 -0
  29. package/dist/index.js +4 -4
  30. package/dist/{inherit-C5Ifg3SM.js → inherit-BYLi3Q28.js} +1 -1
  31. package/dist/{item-styles-DjYRdyHi.js → item-styles-BAeneY1R.js} +1 -1
  32. package/dist/{model-bytecode-BQKCLPze.js → model-bytecode-B43uSqet.js} +31 -2
  33. package/dist/output/item-styles.js +1 -1
  34. package/dist/pack-format-BP5dJMYY.js +10 -0
  35. package/dist/{pack-format-QcVFxG_b.d.ts → pack-format-D5IgQjcD.d.ts} +49 -1
  36. package/dist/pack.d.ts +1 -1
  37. package/dist/pack.js +1 -1
  38. package/dist/{pipeline-CjRcZB63.js → pipeline-CWRQQ9DM.js} +1 -1
  39. package/dist/render/pipeline.js +1 -1
  40. package/dist/{run-CGcHj_qq.js → run-CQXJCo8u.js} +2 -2
  41. package/dist/run.js +1 -1
  42. package/dist/workers/render-worker.js +1 -1
  43. package/package.json +1 -1
  44. package/dist/entity-models-DSZHxCx1.js +0 -127
@@ -0,0 +1,31 @@
1
+ {
2
+ "__comment": "A 64x64 head that also draws the skin's own hat layer, for the player head. Same box as head_64_64, but the outer element is bound to the head sheet at the hat unwrap (texOffs 32,0) rather than to an empty sprite. On a default skin that region is fully transparent, so this draws exactly what head_64_64 did; on a real player's skin it is the hat, which is the half of a head that a consumer swapping in a fetched skin would otherwise lose. East/west and up/down are swapped against the game's own box unwrap for the same reason head_64_64 swaps them: the entity renderer draws through a scale(-1, -1, 1) that a block model has no equivalent of.",
3
+ "parent": "mobheads:item/base/head_display",
4
+ "texture_size": [64, 64],
5
+ "elements": [
6
+ {
7
+ "from": [4, 4, 4],
8
+ "to": [12, 12, 12],
9
+ "faces": {
10
+ "north": {"uv": [2, 2, 4, 4], "texture": "#texture"},
11
+ "east": {"uv": [0, 2, 2, 4], "texture": "#texture"},
12
+ "south": {"uv": [6, 2, 8, 4], "texture": "#texture"},
13
+ "west": {"uv": [4, 2, 6, 4], "texture": "#texture"},
14
+ "up": {"uv": [2, 0, 4, 2], "rotation": 180, "texture": "#texture"},
15
+ "down": {"uv": [4, 0, 6, 2], "texture": "#texture"}
16
+ }
17
+ },
18
+ {
19
+ "from": [3.5, 3.5, 3.5],
20
+ "to": [12.5, 12.5, 12.5],
21
+ "faces": {
22
+ "north": {"uv": [10, 2, 12, 4], "texture": "#texture"},
23
+ "east": {"uv": [8, 2, 10, 4], "texture": "#texture"},
24
+ "south": {"uv": [14, 2, 16, 4], "texture": "#texture"},
25
+ "west": {"uv": [12, 2, 14, 4], "texture": "#texture"},
26
+ "up": {"uv": [10, 0, 12, 2], "rotation": 180, "texture": "#texture"},
27
+ "down": {"uv": [12, 0, 14, 2], "texture": "#texture"}
28
+ }
29
+ }
30
+ ]
31
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "__comment": "The player head as a block pack wants it: the same head as mobheads:item/player, plus the skin's own hat layer. Kept apart from the item model because the icon renderer samples a hair outside a face's rect at a silhouette edge, and the extra box — transparent on a default skin — still fringes the icon with a few pixels of whatever sits next to the hat unwrap. A block pack is drawn by a GPU from the geometry rather than by that rasterizer, so it takes the hat and the icon does not.",
3
+ "parent": "mobheads:item/base/head_64_64_hat",
4
+ "textures": {
5
+ "texture": "minecraft:entity/player/wide/steve"
6
+ }
7
+ }
@@ -1,11 +1,11 @@
1
1
  {
2
- "__comment": "Wall sign: the same board as the standing sign with no post, sitting against the block behind it. Authored facing north, so the blockstate's facing rotates it from there.",
2
+ "__comment": "Wall sign: the same board as the standing sign with no post, sitting against the block behind it. Authored facing north, so the blockstate's facing rotates it from there. The block it hangs on is the one it faces AWAY from, so the board is at the far z: authored north, it sits against the south neighbour. Putting it at z 0 instead drew every wall sign in a world a full block clear of its wall.",
3
3
  "texture_size": [64, 32],
4
4
  "elements": [
5
5
  {
6
6
  "name": "board",
7
- "from": [0, 4.5, 0],
8
- "to": [16, 12.5, 1.5],
7
+ "from": [0, 4.5, 14.5],
8
+ "to": [16, 12.5, 16],
9
9
  "faces": {
10
10
  "north": { "uv": [0.5, 1, 6.5, 7], "texture": "#texture" },
11
11
  "east": { "uv": [6.5, 1, 7, 7], "texture": "#texture" },
@@ -288,7 +288,7 @@ async function skullGeometry(blockId, context) {
288
288
  } : { kind: "rotation16" }
289
289
  };
290
290
  };
291
- const parts = mob.split("_");
291
+ const parts = (mob === "player" ? "player_skin" : mob).split("_");
292
292
  for (let keep = parts.length; keep >= 1 && keep >= parts.length - 2; keep--) {
293
293
  const model = `mobheads:item/${parts.slice(0, keep).join("_")}`;
294
294
  const resolved = await context.models.load(model).catch(() => null);
@@ -1,2 +1,2 @@
1
- import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "../block-entities-XAynAVUE.js";
1
+ import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "../block-entities-CPQeb5dV.js";
2
2
  export { INVISIBLE_BLOCKS, blockEntityGeometry, synthesizeVariants };
@@ -1,2 +1,2 @@
1
- import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "../blockstate-eval-BRQ3NWY2.js";
1
+ import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "../blockstate-eval-CV_LwUwj.js";
2
2
  export { BlockStateError, collectModels, evaluateBlockState, matchesCondition, parseBlockState, weightedVariantIndex };
@@ -1,2 +1,2 @@
1
- import { t as runBlocksCli } from "../cli-FiMsJbQx.js";
1
+ import { t as runBlocksCli } from "../cli-DFIB9i9c.js";
2
2
  export { runBlocksCli };
@@ -1,5 +1,5 @@
1
1
  import { a as ResourceManager } from "../manager-exOIcdyx.js";
2
- import { f as BlockPackModel } from "../pack-format-QcVFxG_b.js";
2
+ import { f as BlockPackModel } from "../pack-format-D5IgQjcD.js";
3
3
  //#region src/blocks/ender-storage.d.ts
4
4
  /**
5
5
  * Ender Storage feeds this OBJ through CodeChickenLib's `swapYZ`, translates it almost exactly onto
@@ -1,6 +1,6 @@
1
1
  import { a as ResourceManager } from "../manager-exOIcdyx.js";
2
2
  import { i as TextureLoader } from "../loader-DUlx29PC.js";
3
- import { x as EntityPackEntry } from "../pack-format-QcVFxG_b.js";
3
+ import { S as EntityPackEntry } from "../pack-format-D5IgQjcD.js";
4
4
  //#region src/blocks/entities.d.ts
5
5
  interface EntityPackResult {
6
6
  entities: Record<string, EntityPackEntry>;
@@ -1,6 +1,8 @@
1
1
  import { a as ResourceManager } from "../manager-exOIcdyx.js";
2
- import { S as EntityPackModel } from "../pack-format-QcVFxG_b.js";
2
+ import { C as EntityPackModel, T as EquipmentPack } from "../pack-format-D5IgQjcD.js";
3
3
  import { t as ClassSource } from "../jar-classes-CSRrPAUy.js";
4
+ import { t as Mappings } from "../mappings-DxX4KoZl.js";
5
+ import { t as ModelCode } from "../model-code-BY44ao27.js";
4
6
  //#region src/blocks/entity-models.d.ts
5
7
  interface EntityGeometryResult {
6
8
  /** Model id (the class it came from) → geometry. */
@@ -9,6 +11,8 @@ interface EntityGeometryResult {
9
11
  modelOf: Map<string, string>;
10
12
  /** Entity sheets the models address, to be stitched into the pack's own atlas. */
11
13
  spriteIds: Set<string>;
14
+ /** Worn armour, where the version's classes described any. */
15
+ equipment: EquipmentPack | null;
12
16
  failures: Array<{
13
17
  id: string;
14
18
  reason: string;
@@ -41,5 +45,23 @@ interface CollectEntityGeometryOptions {
41
45
  * per entity.
42
46
  */
43
47
  declare function collectEntityGeometry(options: CollectEntityGeometryOptions): Promise<EntityGeometryResult>;
48
+ /**
49
+ * Reads the authored armour-trim atlas and names every generated worn sheet.
50
+ *
51
+ * The texture loader already resolves `paletted_permutations`; this only records the generated
52
+ * sprite ids so the normal entity-atlas stitcher asks it for those pixels. Copies are visited from
53
+ * lowest to highest precedence, matching atlas source resolution when packs extend the vanilla file.
54
+ */
55
+ declare function collectArmourTrims(resources: ResourceManager, spriteIds: Set<string>): Promise<EquipmentPack['trims']>;
56
+ /**
57
+ * Worn armour for the pack: one humanoid mesh, the sheets each material is drawn with, and which
58
+ * item is which.
59
+ *
60
+ * Materials are discovered from the sheets the version actually ships rather than listed, so a
61
+ * version that adds one — copper, in the 26 line — needs no edit here. The item ids are the one part
62
+ * the assets cannot answer, since nothing in them maps `iron_helmet` to `iron`: they follow the
63
+ * game's own naming, and each is confirmed against a real item model before being claimed.
64
+ */
65
+ declare function collectEquipment(names: readonly string[], mappings: Mappings, read: (internal: string) => Promise<Uint8Array | null>, code: ModelCode, resources: ResourceManager | undefined, models: Record<string, EntityPackModel>, spriteIds: Set<string>): Promise<EquipmentPack | null>;
44
66
  //#endregion
45
- export { CollectEntityGeometryOptions, EntityGeometryResult, collectEntityGeometry };
67
+ export { CollectEntityGeometryOptions, EntityGeometryResult, collectArmourTrims, collectEntityGeometry, collectEquipment };
@@ -1,2 +1,2 @@
1
- import { t as collectEntityGeometry } from "../entity-models-DSZHxCx1.js";
2
- export { collectEntityGeometry };
1
+ import { n as collectEntityGeometry, r as collectEquipment, t as collectArmourTrims } from "../entity-models-DUKiHpn1.js";
2
+ export { collectArmourTrims, collectEntityGeometry, collectEquipment };
@@ -1,2 +1,2 @@
1
- import { t as exportBlockPack } from "../export-CxocMT1x.js";
1
+ import { t as exportBlockPack } from "../export-DlXOK8_D.js";
2
2
  export { exportBlockPack };
@@ -1,5 +1,5 @@
1
1
  import { a as ResourceManager } from "../manager-exOIcdyx.js";
2
- import { f as BlockPackModel } from "../pack-format-QcVFxG_b.js";
2
+ import { f as BlockPackModel } from "../pack-format-D5IgQjcD.js";
3
3
  //#region src/blocks/geo-blocks.d.ts
4
4
  interface GeoBlockOverride {
5
5
  model: BlockPackModel;
@@ -1,7 +1,7 @@
1
1
  import { a as ResourceManager } from "../manager-exOIcdyx.js";
2
2
  import { i as TextureLoader } from "../loader-DUlx29PC.js";
3
3
  import { t as ModelLoader } from "../loader-DSir1-P0.js";
4
- import { w as ItemPackEntry } from "../pack-format-QcVFxG_b.js";
4
+ import { D as ItemPackEntry } from "../pack-format-D5IgQjcD.js";
5
5
  //#region src/blocks/item-sprites.d.ts
6
6
  interface ItemSpriteFailure {
7
7
  id: string;
@@ -1,2 +1,2 @@
1
- import { C as EntityPackPart, S as EntityPackModel, T as ItemPackLayer, _ as BlockPackTintsFile, a as BlockPackBlockStatesFile, b as EntityPackCubeFace, c as BlockPackEntityModelsFile, d as BlockPackMetaFile, f as BlockPackModel, g as BlockPackSpriteFrame, h as BlockPackSprite, i as BlockPackBlockState, l as BlockPackFace, m as BlockPackRenderLayer, n as BlockPackAtlasPage, o as BlockPackElement, p as BlockPackModelsFile, r as BlockPackBiomesFile, s as BlockPackEntitiesFile, t as BlockPackAtlasFile, u as BlockPackItemsFile, v as BlockPackVariant, w as ItemPackEntry, x as EntityPackEntry, y as EntityPackCube } from "../pack-format-QcVFxG_b.js";
2
- export { BlockPackAtlasFile, BlockPackAtlasPage, BlockPackBiomesFile, BlockPackBlockState, BlockPackBlockStatesFile, BlockPackElement, BlockPackEntitiesFile, BlockPackEntityModelsFile, BlockPackFace, BlockPackItemsFile, BlockPackMetaFile, BlockPackModel, BlockPackModelsFile, BlockPackRenderLayer, BlockPackSprite, BlockPackSpriteFrame, BlockPackTintsFile, BlockPackVariant, EntityPackCube, EntityPackCubeFace, EntityPackEntry, EntityPackModel, EntityPackPart, ItemPackEntry, ItemPackLayer };
1
+ import { C as EntityPackModel, D as ItemPackEntry, E as EquipmentSlot, O as ItemPackLayer, S as EntityPackEntry, T as EquipmentPack, _ as BlockPackTintsFile, a as BlockPackBlockStatesFile, b as EntityPackCube, c as BlockPackEntityModelsFile, d as BlockPackMetaFile, f as BlockPackModel, g as BlockPackSpriteFrame, h as BlockPackSprite, i as BlockPackBlockState, l as BlockPackFace, m as BlockPackRenderLayer, n as BlockPackAtlasPage, o as BlockPackElement, p as BlockPackModelsFile, r as BlockPackBiomesFile, s as BlockPackEntitiesFile, t as BlockPackAtlasFile, u as BlockPackItemsFile, v as BlockPackVariant, w as EntityPackPart, x as EntityPackCubeFace, y as EQUIPMENT_SLOTS } from "../pack-format-D5IgQjcD.js";
2
+ export { BlockPackAtlasFile, BlockPackAtlasPage, BlockPackBiomesFile, BlockPackBlockState, BlockPackBlockStatesFile, BlockPackElement, BlockPackEntitiesFile, BlockPackEntityModelsFile, BlockPackFace, BlockPackItemsFile, BlockPackMetaFile, BlockPackModel, BlockPackModelsFile, BlockPackRenderLayer, BlockPackSprite, BlockPackSpriteFrame, BlockPackTintsFile, BlockPackVariant, EQUIPMENT_SLOTS, EntityPackCube, EntityPackCubeFace, EntityPackEntry, EntityPackModel, EntityPackPart, EquipmentPack, EquipmentSlot, ItemPackEntry, ItemPackLayer };
@@ -1 +1,2 @@
1
- export {};
1
+ import { t as EQUIPMENT_SLOTS } from "../pack-format-BP5dJMYY.js";
2
+ export { EQUIPMENT_SLOTS };
@@ -1,6 +1,6 @@
1
1
  import { i as TextureLoader, r as Texture } from "../loader-DUlx29PC.js";
2
2
  import { i as PackedPage } from "../atlas-pack-D8745_wo.js";
3
- import { h as BlockPackSprite, m as BlockPackRenderLayer } from "../pack-format-QcVFxG_b.js";
3
+ import { h as BlockPackSprite, m as BlockPackRenderLayer } from "../pack-format-D5IgQjcD.js";
4
4
  //#region src/blocks/sprite-sheet.d.ts
5
5
  /**
6
6
  * Vanilla's own id for the missing-texture sprite. A face whose texture does
@@ -243,7 +243,7 @@ const JAVA_MASK = (1n << 48n) - 1n;
243
243
  function weightedVariantIndex(weights, blockX, blockY, blockZ) {
244
244
  if (weights.length <= 1) return 0;
245
245
  const total = weights.reduce((sum, weight) => sum + weight, 0);
246
- let seed = BigInt(blockX) * 3129871n ^ BigInt(blockZ) * 116129781n ^ BigInt(blockY);
246
+ let seed = BigInt(Math.imul(blockX, 3129871)) ^ BigInt(blockZ) * 116129781n ^ BigInt(blockY);
247
247
  seed = seed * seed * 42317861n + seed * 11n;
248
248
  seed = BigInt.asIntN(64, seed) >> 16n;
249
249
  let state = (BigInt.asUintN(64, seed) ^ JAVA_MULTIPLIER) & JAVA_MASK;
@@ -1,6 +1,6 @@
1
1
  import { n as builtinPackPath } from "./builtin-WkWjATeh.js";
2
2
  import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-BNibYkmI.js";
3
- import { t as exportBlockPack } from "./export-CxocMT1x.js";
3
+ import { t as exportBlockPack } from "./export-DlXOK8_D.js";
4
4
  import { n as layeredClasses, t as JarClassReader } from "./jar-classes-3GVCJZT7.js";
5
5
  import { n as prepareModResources } from "./prepare-Myd_ec4v.js";
6
6
  import { t as downloadClientJar } from "./download-1wAfrGKx.js";
package/dist/cli.js CHANGED
@@ -6,8 +6,8 @@ import { t as curatedModelOverrides } from "./models-CZjCOjs4.js";
6
6
  import { n as harvestTintOverrides, t as curatedTintOverrides } from "./tints-BspVCz2G.js";
7
7
  import { t as downloadClientJar } from "./download-1wAfrGKx.js";
8
8
  import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-D49Gu4Lv.js";
9
- import { t as runBlocksCli } from "./cli-FiMsJbQx.js";
10
- import { t as run } from "./run-CGcHj_qq.js";
9
+ import { t as runBlocksCli } from "./cli-DFIB9i9c.js";
10
+ import { t as run } from "./run-CQXJCo8u.js";
11
11
  import path from "node:path";
12
12
  import os from "node:os";
13
13
  import { parseArgs } from "node:util";
@@ -1,2 +1,2 @@
1
- import { a as builtinDynamicResources, i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "../generators-BCZVlWig.js";
1
+ import { a as builtinDynamicResources, i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "../generators-D6giKoab.js";
2
2
  export { ARMOR_ITEM_TYPES, POTTERY_SHERDS, TRIM_DARKER_MATERIALS, TRIM_MATERIALS, builtinDynamicResources };
@@ -1,2 +1,2 @@
1
- import { n as extractInheritedModel, t as ancestryOf } from "../inherit-C5Ifg3SM.js";
1
+ import { n as extractInheritedModel, t as ancestryOf } from "../inherit-BYLi3Q28.js";
2
2
  export { ancestryOf, extractInheritedModel };
@@ -1,5 +1,5 @@
1
- import { t as ClassFile } from "../classfile-BdLIk4Pe.js";
2
1
  import { t as Mappings } from "../mappings-DxX4KoZl.js";
2
+ import { t as ClassFile } from "../classfile-BdLIk4Pe.js";
3
3
  //#region src/entities/link.d.ts
4
4
  /**
5
5
  * Entity types whose renderer or model is not named after them. Values are class simple names to look
@@ -25,7 +25,22 @@ interface Following {
25
25
  * Defaults to true, which is right when the caller has no way to tell the two apart.
26
26
  */
27
27
  isModelCode?: boolean;
28
+ /**
29
+ * Which of the class's methods may build the model. Defaults to everything but the armour meshes,
30
+ * which build the armour *worn on* this model rather than the model — see `ARMOUR_MESH`.
31
+ *
32
+ * `extractArmourMesh` passes the opposite, since that is exactly what it is after.
33
+ */
34
+ methods?: (name: string) => boolean;
28
35
  }
36
+ /**
37
+ * The armour a humanoid wears, as its own mesh. Empty where the class builds none.
38
+ *
39
+ * The baby form is skipped rather than competing: it has more boxes than the adult's — a separate
40
+ * head and body where the adult reuses the humanoid's — so the fullest-mesh rule would always pick
41
+ * it, and every suit of armour in the world would come out child-sized.
42
+ */
43
+ declare function extractArmourMesh(bytes: Uint8Array, following: Following): ExtractedModel;
29
44
  declare function extractModel(bytes: Uint8Array, following?: Following): ExtractedModel;
30
45
  //#endregion
31
- export { Following, extractModel };
46
+ export { Following, extractArmourMesh, extractModel };
@@ -1,2 +1,2 @@
1
- import { t as extractModel } from "../model-bytecode-BQKCLPze.js";
2
- export { extractModel };
1
+ import { n as extractModel, t as extractArmourMesh } from "../model-bytecode-B43uSqet.js";
2
+ export { extractArmourMesh, extractModel };
@@ -0,0 +1,406 @@
1
+ import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
+ import { t as findGeoForEntity } from "./entity-geo-DbTtMlPL.js";
3
+ import { t as EQUIPMENT_SLOTS } from "./pack-format-BP5dJMYY.js";
4
+ import { n as extractModel, t as extractArmourMesh } from "./model-bytecode-B43uSqet.js";
5
+ import { n as extractInheritedModel, t as ancestryOf } from "./inherit-BYLi3Q28.js";
6
+ import { a as linkEntityModel, i as classReader, r as buildModelNameIndex } from "./link-5GmBLTzk.js";
7
+ import { s as resolveMappings, t as MappingsUnavailableError } from "./mappings-BEPVaiwE.js";
8
+ import { n as loadModelCode } from "./model-code-1Vuk-zj_.js";
9
+ //#region src/blocks/entity-models.ts
10
+ /**
11
+ * Entity geometry for the pack: link each entity to the class that builds it, read that class's
12
+ * bytecode, and stitch the sheets those models are drawn with.
13
+ *
14
+ * The pieces all live in `src/entities/` — this is the part that knows what a *pack* wants. Which is
15
+ * mostly two things the extractor does not care about: several entities share one model (every zombie
16
+ * in the game is a `HumanoidModel`), so models are keyed by class and pointed at rather than copied;
17
+ * and the `uv` values in a model address the entity's own sheet, so those sheets have to be in an
18
+ * atlas the consumer can sample.
19
+ *
20
+ * Needs the *code*, not just the assets. An `--assets` folder has none, and a pack exported from one
21
+ * carries no entity geometry — which is the honest answer rather than a silent gap.
22
+ */
23
+ function countCubes(part) {
24
+ return part.cubes.length + part.children.reduce((sum, child) => sum + countCubes(child), 0);
25
+ }
26
+ /** Drops the internal shape into the pack's, omitting what is at its default. */
27
+ function toPackPart(part) {
28
+ return {
29
+ name: part.name,
30
+ pivot: [...part.pivot],
31
+ rotation: [...part.rotation],
32
+ cubes: part.cubes.map((cube) => {
33
+ return {
34
+ origin: [...cube.origin],
35
+ size: [...cube.size],
36
+ uv: [...cube.uv],
37
+ ...cube.inflate !== 0 && { inflate: cube.inflate },
38
+ ...cube.mirror && { mirror: true },
39
+ ...cube.faces && { faces: cube.faces }
40
+ };
41
+ }),
42
+ children: part.children.map((child) => toPackPart(child))
43
+ };
44
+ }
45
+ /**
46
+ * Recovers geometry for as many of `entityIds` as the code describes.
47
+ *
48
+ * Mappings are resolved once: downloaded for an obfuscated jar, and the identity for one that is not
49
+ * (from the 26 line the client ships in the clear, and a mod jar never was obfuscated). A version that
50
+ * is obfuscated *and* unmapped — 1.13.x — yields nothing, with the reason recorded once rather than
51
+ * per entity.
52
+ */
53
+ async function collectEntityGeometry(options) {
54
+ const { classes, entityIds } = options;
55
+ const models = {};
56
+ const modelOf = /* @__PURE__ */ new Map();
57
+ const spriteIds = /* @__PURE__ */ new Set();
58
+ const failures = [];
59
+ const names = await classes.list();
60
+ let mappings;
61
+ try {
62
+ ({mappings} = await resolveMappings(options.version, options.cacheDir, async () => names));
63
+ } catch (err) {
64
+ failures.push({
65
+ id: options.version,
66
+ reason: err instanceof MappingsUnavailableError ? `no entity geometry: ${err.message}` : `no entity geometry: mappings could not be loaded (${err.message})`
67
+ });
68
+ return {
69
+ models,
70
+ modelOf,
71
+ spriteIds,
72
+ equipment: null,
73
+ failures
74
+ };
75
+ }
76
+ const code = await loadModelCode(names, async (internal) => await classes.read(internal), (internal) => mappings.originalOf.get(internal) ?? internal);
77
+ const extracted = /* @__PURE__ */ new Map();
78
+ const geometryOf = async (internal) => {
79
+ if (!extracted.has(internal)) extracted.set(internal, await extractInheritedModel(internal, async (name) => await classes.read(name), code));
80
+ return extracted.get(internal) ?? null;
81
+ };
82
+ const context = {
83
+ mappings,
84
+ read: classReader(async (internal) => await classes.read(internal)),
85
+ hasGeometry: async (internal) => {
86
+ const model = await geometryOf(internal);
87
+ return model !== null && model.parts.reduce((sum, part) => sum + countCubes(part), 0) > 0;
88
+ },
89
+ nameIndex: buildModelNameIndex(names)
90
+ };
91
+ const geoFor = async (entityId) => {
92
+ if (!options.resources) return null;
93
+ const [namespace, name] = entityId.includes(":") ? entityId.split(":") : ["minecraft", entityId];
94
+ return await findGeoForEntity(options.resources, namespace, name);
95
+ };
96
+ let done = 0;
97
+ for (const entityId of [...entityIds].toSorted((left, right) => left.localeCompare(right))) {
98
+ options.onProgress?.(++done, entityIds.length);
99
+ const link = await linkEntityModel(entityId, context);
100
+ const guessed = link?.route === "vanilla-name";
101
+ const found = link && !guessed ? {
102
+ id: link.className,
103
+ model: await geometryOf(link.obfuscated)
104
+ } : await geoFor(entityId) ?? (link ? {
105
+ id: link.className,
106
+ model: await geometryOf(link.obfuscated)
107
+ } : null);
108
+ if (!found?.model) continue;
109
+ const { id: modelId, model } = found;
110
+ if (!models[modelId]) models[modelId] = {
111
+ textureSize: [...model.textureSize],
112
+ parts: model.parts.map((part) => toPackPart(part)),
113
+ ...model.notes.length > 0 && { notes: [...model.notes] }
114
+ };
115
+ modelOf.set(entityId, modelId);
116
+ const texture = options.textureOf.get(entityId);
117
+ if (texture) spriteIds.add(texture);
118
+ else failures.push({
119
+ id: entityId,
120
+ reason: `geometry recovered from ${modelId} but no entity texture resolved`
121
+ });
122
+ }
123
+ return {
124
+ models,
125
+ modelOf,
126
+ spriteIds,
127
+ equipment: await collectEquipment(names, mappings, async (internal) => await classes.read(internal), code, options.resources, models, spriteIds),
128
+ failures
129
+ };
130
+ }
131
+ /**
132
+ * How much each armour layer grows the wearer's boxes by, in pixels.
133
+ *
134
+ * Not recovered from the code: the game passes these into the mesh builder from its renderers, so
135
+ * following them means interpreting a renderer, which the extractor deliberately refuses to do. They
136
+ * have been 1.0 and 0.5 since armour got its second layer, and getting them wrong only makes the two
137
+ * layers fight rather than losing the shape.
138
+ */
139
+ const ARMOUR_INFLATE = {
140
+ outer: 1,
141
+ inner: .5
142
+ };
143
+ /** Which parts a slot lights up, and which layer it is drawn on. */
144
+ const ARMOUR_SLOTS = {
145
+ head: {
146
+ parts: ["head", "hat"],
147
+ layer: "outer"
148
+ },
149
+ chest: {
150
+ parts: [
151
+ "body",
152
+ "right_arm",
153
+ "left_arm"
154
+ ],
155
+ layer: "outer"
156
+ },
157
+ legs: {
158
+ parts: [
159
+ "body",
160
+ "right_leg",
161
+ "left_leg"
162
+ ],
163
+ layer: "inner"
164
+ },
165
+ feet: {
166
+ parts: ["right_leg", "left_leg"],
167
+ layer: "outer"
168
+ }
169
+ };
170
+ /**
171
+ * Where each layer's sheets live, across the two layouts the game has used.
172
+ *
173
+ * 1.21.2 moved armour under `entity/equipment/` and dropped the `_layer_N` suffix for a folder per
174
+ * layer. Both are matched rather than switched on a version, so a resource pack or a mod following
175
+ * either convention is found the same way.
176
+ */
177
+ const ARMOUR_SHEETS = [
178
+ {
179
+ layer: "outer",
180
+ prefix: "entity/equipment/humanoid/",
181
+ suffix: ""
182
+ },
183
+ {
184
+ layer: "inner",
185
+ prefix: "entity/equipment/humanoid_leggings/",
186
+ suffix: ""
187
+ },
188
+ {
189
+ layer: "outer",
190
+ prefix: "models/armor/",
191
+ suffix: "_layer_1"
192
+ },
193
+ {
194
+ layer: "inner",
195
+ prefix: "models/armor/",
196
+ suffix: "_layer_2"
197
+ }
198
+ ];
199
+ /** The item name a material takes, where it is not simply the material's own. */
200
+ const ARMOUR_ITEM_PREFIX = {
201
+ gold: "golden",
202
+ turtle_scute: "turtle"
203
+ };
204
+ /** Suffix per slot, as every vanilla armour item is named. */
205
+ const ARMOUR_ITEM_PIECE = {
206
+ head: "helmet",
207
+ chest: "chestplate",
208
+ legs: "leggings",
209
+ feet: "boots"
210
+ };
211
+ /** The layer and world pattern id named by one of the paths in the armour-trim atlas. */
212
+ function trimSheet(locator) {
213
+ const name = locator.path.split("/").at(-1)?.replace(/\.png$/, "");
214
+ if (!name) return null;
215
+ if (locator.path.includes("/humanoid_leggings/")) return {
216
+ layer: "inner",
217
+ pattern: new ResourceLocator(locator.namespace, name).toString()
218
+ };
219
+ if (locator.path.includes("/humanoid/")) return {
220
+ layer: "outer",
221
+ pattern: new ResourceLocator(locator.namespace, name).toString()
222
+ };
223
+ if (locator.path.includes("trims/models/armor/")) {
224
+ const leggings = name.endsWith("_leggings");
225
+ const pattern = leggings ? name.slice(0, -9) : name;
226
+ return {
227
+ layer: leggings ? "inner" : "outer",
228
+ pattern: new ResourceLocator(locator.namespace, pattern).toString()
229
+ };
230
+ }
231
+ return null;
232
+ }
233
+ /** The registry id represented by a palette or pattern texture. */
234
+ function trimId(locator) {
235
+ const name = locator.path.split("/").at(-1)?.replace(/\.png$/, "");
236
+ return name ? new ResourceLocator(locator.namespace, name).toString() : null;
237
+ }
238
+ /**
239
+ * Reads the authored armour-trim atlas and names every generated worn sheet.
240
+ *
241
+ * The texture loader already resolves `paletted_permutations`; this only records the generated
242
+ * sprite ids so the normal entity-atlas stitcher asks it for those pixels. Copies are visited from
243
+ * lowest to highest precedence, matching atlas source resolution when packs extend the vanilla file.
244
+ */
245
+ async function collectArmourTrims(resources, spriteIds) {
246
+ const patterns = {};
247
+ const darker = {};
248
+ for (const namespace of await resources.listNamespaces()) {
249
+ const atlas = new ResourceLocator(namespace, "armor_trims");
250
+ const copies = await resources.getAllResources("atlas", atlas);
251
+ for (const raw of copies.toReversed()) {
252
+ let sources;
253
+ try {
254
+ sources = JSON.parse(raw.toString("utf8")).sources ?? [];
255
+ } catch {
256
+ continue;
257
+ }
258
+ for (const source of sources) {
259
+ if (String(source.type ?? "").replace(/^minecraft:/, "") !== "paletted_permutations" || !Array.isArray(source.textures) || !source.permutations) continue;
260
+ const separator = source.separator ?? "_";
261
+ for (const texture of source.textures) {
262
+ const base = ResourceLocator.tryParse(texture.replace(/\.png$/, ""));
263
+ if (!base) continue;
264
+ const sheet = trimSheet(base);
265
+ if (!sheet) continue;
266
+ const { layer, pattern } = sheet;
267
+ for (const [permutation, paletteName] of Object.entries(source.permutations)) {
268
+ const palette = ResourceLocator.tryParse(paletteName.replace(/\.png$/, ""));
269
+ const material = palette && trimId(palette);
270
+ if (!material) continue;
271
+ const sprite = new ResourceLocator(base.namespace, `${base.path}${separator}${permutation}`).toString();
272
+ patterns[pattern] ??= {};
273
+ patterns[pattern][material] = {
274
+ ...patterns[pattern][material],
275
+ [layer]: sprite
276
+ };
277
+ spriteIds.add(sprite);
278
+ if (material.endsWith("_darker")) {
279
+ const plain = material.slice(0, -7);
280
+ darker[plain] = material;
281
+ }
282
+ }
283
+ }
284
+ }
285
+ }
286
+ }
287
+ return {
288
+ patterns,
289
+ darker
290
+ };
291
+ }
292
+ /**
293
+ * The class holding the humanoid armour shape, across the three places the game has kept it.
294
+ *
295
+ * A dedicated `HumanoidArmorModel` is armour throughout, so the whole class is read. From the 26 line
296
+ * it folded into `HumanoidModel` as a set of `create*ArmorMesh` factories beside the humanoid's own,
297
+ * which is what `extractArmourMesh` picks out. Failing both, the humanoid itself is the right shape —
298
+ * armour has never been anything but the wearer, grown.
299
+ */
300
+ async function armourGeometry(names, mappings, read, code) {
301
+ const find = (simple) => names.find((name) => (mappings.originalOf.get(name) ?? name).endsWith(`/${simple}`) || (mappings.originalOf.get(name) ?? name).endsWith(`.${simple}`));
302
+ for (const route of [
303
+ {
304
+ simple: "HumanoidArmorModel",
305
+ armourOnly: false
306
+ },
307
+ {
308
+ simple: "HumanoidModel",
309
+ armourOnly: true
310
+ },
311
+ {
312
+ simple: "HumanoidModel",
313
+ armourOnly: false
314
+ },
315
+ {
316
+ simple: "BipedModel",
317
+ armourOnly: false
318
+ }
319
+ ]) {
320
+ const internal = find(route.simple);
321
+ const bytes = internal ? await read(internal) : null;
322
+ if (!internal || !bytes) continue;
323
+ const { ancestors } = await ancestryOf(internal, read);
324
+ const resolve = (name) => ancestors.get(name) ?? code.resolve(name);
325
+ const model = route.armourOnly ? extractArmourMesh(bytes, {
326
+ resolve,
327
+ isModelCode: true
328
+ }) : extractModel(bytes, {
329
+ resolve,
330
+ isModelCode: true
331
+ });
332
+ if (model.parts.reduce((sum, part) => sum + countCubes(part), 0) > 0) return {
333
+ className: mappings.originalOf.get(internal) ?? internal,
334
+ model
335
+ };
336
+ }
337
+ return null;
338
+ }
339
+ /**
340
+ * Worn armour for the pack: one humanoid mesh, the sheets each material is drawn with, and which
341
+ * item is which.
342
+ *
343
+ * Materials are discovered from the sheets the version actually ships rather than listed, so a
344
+ * version that adds one — copper, in the 26 line — needs no edit here. The item ids are the one part
345
+ * the assets cannot answer, since nothing in them maps `iron_helmet` to `iron`: they follow the
346
+ * game's own naming, and each is confirmed against a real item model before being claimed.
347
+ */
348
+ async function collectEquipment(names, mappings, read, code, resources, models, spriteIds) {
349
+ if (!resources) return null;
350
+ const found = await armourGeometry(names, mappings, read, code);
351
+ if (!found) return null;
352
+ const materials = {};
353
+ const dyeable = [];
354
+ const textures = await resources.listResources("texture", "minecraft");
355
+ for (const { layer, prefix, suffix } of ARMOUR_SHEETS) for (const locator of textures) {
356
+ if (!locator.path.startsWith(prefix)) continue;
357
+ const name = locator.path.slice(prefix.length);
358
+ const overlay = name.endsWith("_overlay");
359
+ const bare = overlay ? name.slice(0, -8) : name;
360
+ if (!bare.endsWith(suffix)) continue;
361
+ const material = bare.slice(0, bare.length - suffix.length);
362
+ if (material.length === 0 || material.includes("/")) continue;
363
+ const id = `minecraft:${material}`;
364
+ if (overlay) {
365
+ if (!dyeable.includes(id)) dyeable.push(id);
366
+ continue;
367
+ }
368
+ materials[id] = {
369
+ ...materials[id],
370
+ [layer]: locator.toString()
371
+ };
372
+ spriteIds.add(locator.toString());
373
+ }
374
+ if (Object.keys(materials).length === 0) return null;
375
+ const items = {};
376
+ for (const material of Object.keys(materials)) {
377
+ const bare = material.slice(10);
378
+ const prefix = ARMOUR_ITEM_PREFIX[bare] ?? bare;
379
+ for (const slot of EQUIPMENT_SLOTS) {
380
+ const id = `minecraft:${prefix}_${ARMOUR_ITEM_PIECE[slot]}`;
381
+ if (await resources.hasResource("model", new ResourceLocator("minecraft", `item/${prefix}_${ARMOUR_ITEM_PIECE[slot]}`))) items[id] = {
382
+ material,
383
+ slot
384
+ };
385
+ }
386
+ }
387
+ const trims = await collectArmourTrims(resources, spriteIds);
388
+ const modelKey = `${found.className}#armor`;
389
+ models[modelKey] = {
390
+ textureSize: [...found.model.textureSize],
391
+ parts: found.model.parts.map((part) => toPackPart(part)),
392
+ ...found.model.notes.length > 0 && { notes: [...found.model.notes] }
393
+ };
394
+ return {
395
+ model: modelKey,
396
+ inflate: { ...ARMOUR_INFLATE },
397
+ slots: Object.fromEntries(EQUIPMENT_SLOTS.map((slot) => [slot, [...ARMOUR_SLOTS[slot].parts]])),
398
+ layerOf: Object.fromEntries(EQUIPMENT_SLOTS.map((slot) => [slot, ARMOUR_SLOTS[slot].layer])),
399
+ materials,
400
+ items,
401
+ dyeable,
402
+ trims
403
+ };
404
+ }
405
+ //#endregion
406
+ export { collectEntityGeometry as n, collectEquipment as r, collectArmourTrims as t };
@@ -1,11 +1,11 @@
1
1
  import { r as buildBiomeClimates } from "./biomes-5ZwYxMYe.js";
2
2
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
3
- import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "./block-entities-XAynAVUE.js";
4
- import { a as parseBlockState, n as collectModels } from "./blockstate-eval-BRQ3NWY2.js";
3
+ import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "./block-entities-CPQeb5dV.js";
4
+ import { a as parseBlockState, n as collectModels } from "./blockstate-eval-CV_LwUwj.js";
5
5
  import { a as salvageJson, i as resolveTexture, t as ModelLoader } from "./loader-C-NuJaEi.js";
6
6
  import { t as enderStorageBlockModel } from "./ender-storage-C8i6Rxlq.js";
7
7
  import { t as collectEntities } from "./entities-DubtdM11.js";
8
- import { t as collectEntityGeometry } from "./entity-models-DSZHxCx1.js";
8
+ import { n as collectEntityGeometry } from "./entity-models-DUKiHpn1.js";
9
9
  import { t as geoBlockModel } from "./geo-blocks-BcSEBhko.js";
10
10
  import { n as discoverItems } from "./discovery-CD0QqxSF.js";
11
11
  import { t as collectItemSprites } from "./item-sprites-CnCH8YFv.js";
@@ -822,7 +822,8 @@ async function exportBlockPack(options) {
822
822
  };
823
823
  }),
824
824
  sprites: sortedByKey(sheet.sprites),
825
- models: sortedByKey(geometry.models)
825
+ models: sortedByKey(geometry.models),
826
+ ...geometry.equipment && { equipment: geometry.equipment }
826
827
  };
827
828
  for (const [id, entry] of Object.entries(collected.entities)) if (entry.texture && sheet.missing.has(entry.texture)) delete collected.entities[id].texture;
828
829
  }
@@ -22,6 +22,7 @@ const TRIM_MATERIALS = [
22
22
  ];
23
23
  /** Materials with a darker variant used when the trim matches the armor metal. */
24
24
  const TRIM_DARKER_MATERIALS = /* @__PURE__ */ new Set([
25
+ "copper",
25
26
  "iron",
26
27
  "gold",
27
28
  "diamond",
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { i as parseBiomeClimate, n as VANILLA_BIOME_CLIMATES, r as buildBiomeClimates, t as DEFAULT_WATER_COLOR } from "./biomes-5ZwYxMYe.js";
2
2
  import { n as ResourceLocator, t as InvalidResourceLocatorError } from "./locator-COMEtEn9.js";
3
- import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "./blockstate-eval-BRQ3NWY2.js";
3
+ import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "./blockstate-eval-CV_LwUwj.js";
4
4
  import { c as toByteTexture, l as toFloatTexture } from "./blend-KXMclcHk.js";
5
5
  import { c as lightsForProfile, r as LightingProfile } from "./lighting--5myudVu.js";
6
6
  import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, t as ModelLoader } from "./loader-C-NuJaEi.js";
@@ -14,13 +14,13 @@ import { n as buildBlockTints, t as UNREGISTERED_TINTS } from "./tints-Cl0r-Ol3.
14
14
  import { o as createAtlasResolver, s as parseAtlasSources, t as AtlasSourceError } from "./sources-BlUriDCs.js";
15
15
  import { n as LayeredResourceManager, r as ResourceKind, t as FolderResourceManager } from "./manager-BNibYkmI.js";
16
16
  import { n as TextureLoader, r as TextureResolutionError, t as AnimatedTexture } from "./loader-C18GpurU.js";
17
- import { t as exportBlockPack } from "./export-CxocMT1x.js";
17
+ import { t as exportBlockPack } from "./export-DlXOK8_D.js";
18
18
  import { n as UnsafeJarError, r as isUnsafeEntryPath, t as JarResourceManager } from "./jar-W2cV2ZVO.js";
19
19
  import { n as prepareModResources } from "./prepare-Myd_ec4v.js";
20
20
  import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-D49Gu4Lv.js";
21
21
  import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
22
- import { a as builtinDynamicResources } from "./generators-BCZVlWig.js";
22
+ import { a as builtinDynamicResources } from "./generators-D6giKoab.js";
23
23
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
24
24
  import { n as itemClass, t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
25
- import { t as run } from "./run-CGcHj_qq.js";
25
+ import { t as run } from "./run-CQXJCo8u.js";
26
26
  export { AnimatedTexture, AtlasSourceError, BlockStateError, DEFAULT_WATER_COLOR, DYE_COLORS, FolderResourceManager, InvalidItemDefinitionError, InvalidResourceLocatorError, InvalidTinterDefinitionError, ItemRenderError, ItemResolutionError, JarResourceManager, LayeredResourceManager, LightingProfile, ModelLoader, ModelResolutionError, ObjMeshError, ResourceKind, ResourceLocator, TextureLoader, TextureResolutionError, UNKNOWN_MODEL, UNREGISTERED_TINTS, UnsafeJarError, VANILLA_BIOME_CLIMATES, boxDownscale, buildBiomeClimates, buildBlockTints, buildObjMesh, builtinDynamicResources, collectModels, compareVersions, createAtlasResolver, defaultProperties, discoverItems, encodeAnimatedIcon, encodeIcon, eraForVersion, evaluateBlockState, evaluateItemModel, exportBlockPack, generateStylesheet, isUnsafeEntryPath, itemClass, lightsForProfile, matchesCondition, minifyStylesheet, packAtlas, parseAtlasSources, parseBiomeClimate, parseBlockState, parseTintValue, pointResize, prepareModResources, prepareVersionResources, renderModel, renderModelFrames, resolveItem, resolveTexture, resolveTint, resolveTints, run, salvageJson, toByteTexture, toFloatTexture, weightedVariantIndex };
@@ -1,6 +1,6 @@
1
1
  import { t as parseClassFile } from "./classfile-Bo7FUrrD.js";
2
2
  import { a as mergeModels, i as dedupeCubes } from "./merge-DeHruviG.js";
3
- import { t as extractModel } from "./model-bytecode-BQKCLPze.js";
3
+ import { n as extractModel } from "./model-bytecode-B43uSqet.js";
4
4
  //#region src/entities/inherit.ts
5
5
  /**
6
6
  * A model class read together with its ancestors.
@@ -1,4 +1,4 @@
1
- import { i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "./generators-BCZVlWig.js";
1
+ import { i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "./generators-D6giKoab.js";
2
2
  //#region src/output/item-styles.ts
3
3
  /**
4
4
  * Per-item CSS style classification, ported from upstream's ItemStyleGenerators
@@ -790,17 +790,46 @@ function toPart(handle) {
790
790
  children: handle.children.map((child) => toPart(child))
791
791
  };
792
792
  }
793
+ /**
794
+ * A method that builds the *armour worn on* a model rather than the model itself.
795
+ *
796
+ * The 26 line moved the armour meshes onto the models that wear them, so `HumanoidModel` now offers
797
+ * `createBaseArmorMesh` and `createBabyArmorMesh` beside its own `createMesh`. A baby's armour has
798
+ * more boxes than the humanoid does, so the fullest-mesh rule below picked it, and every player,
799
+ * zombie and armour stand in the pack came out as a set of leggings: a `waist` and an `inner_body`
800
+ * at knee height where the mob should have been.
801
+ *
802
+ * Matched by name, which is exact on a jar Mojang no longer obfuscates and harmless on one they did,
803
+ * where no method is named anything at all.
804
+ */
805
+ const ARMOUR_MESH = /armou?r/i;
806
+ /** The baby form of an armour mesh, which is a scaled duplicate of the one worn by an adult. */
807
+ const BABY_MESH = /baby/i;
808
+ /**
809
+ * The armour a humanoid wears, as its own mesh. Empty where the class builds none.
810
+ *
811
+ * The baby form is skipped rather than competing: it has more boxes than the adult's — a separate
812
+ * head and body where the adult reuses the humanoid's — so the fullest-mesh rule would always pick
813
+ * it, and every suit of armour in the world would come out child-sized.
814
+ */
815
+ function extractArmourMesh(bytes, following) {
816
+ return extractModel(bytes, {
817
+ ...following,
818
+ methods: (name) => ARMOUR_MESH.test(name) && !BABY_MESH.test(name)
819
+ });
820
+ }
793
821
  function extractModel(bytes, following) {
794
822
  const classFile = parseClassFile(bytes);
795
823
  const notes = [];
796
824
  const candidates = [];
797
825
  const outward = following?.isModelCode ?? true;
826
+ const wanted = following?.methods ?? ((name) => !ARMOUR_MESH.test(name));
798
827
  const own = (internalName) => {
799
828
  if (internalName === classFile.thisClass) return classFile;
800
829
  return outward ? following?.resolve(internalName) ?? null : null;
801
830
  };
802
831
  for (const method of classFile.methods) {
803
- if (!method.code) continue;
832
+ if (!method.code || !wanted(method.name)) continue;
804
833
  const shared = newShared(own);
805
834
  let ok;
806
835
  try {
@@ -841,4 +870,4 @@ function extractModel(bytes, following) {
841
870
  return model;
842
871
  }
843
872
  //#endregion
844
- export { extractModel as t };
873
+ export { extractModel as n, extractArmourMesh as t };
@@ -1,2 +1,2 @@
1
- import { t as classifyItemStyle } from "../item-styles-DjYRdyHi.js";
1
+ import { t as classifyItemStyle } from "../item-styles-BAeneY1R.js";
2
2
  export { classifyItemStyle };
@@ -0,0 +1,10 @@
1
+ //#region src/blocks/pack-format.ts
2
+ /** The armour slots the game dresses a humanoid in, in the order it layers them. */
3
+ const EQUIPMENT_SLOTS = [
4
+ "feet",
5
+ "legs",
6
+ "chest",
7
+ "head"
8
+ ];
9
+ //#endregion
10
+ export { EQUIPMENT_SLOTS as t };
@@ -252,6 +252,54 @@ interface BlockPackEntityModelsFile {
252
252
  pages: BlockPackAtlasPage[];
253
253
  sprites: Record<string, BlockPackSprite>;
254
254
  models: Record<string, EntityPackModel>;
255
+ /** Worn armour, when the version's classes described any. Absent otherwise. */
256
+ equipment?: EquipmentPack;
257
+ }
258
+ /** The armour slots the game dresses a humanoid in, in the order it layers them. */
259
+ declare const EQUIPMENT_SLOTS: readonly ["feet", "legs", "chest", "head"];
260
+ type EquipmentSlot = typeof EQUIPMENT_SLOTS[number];
261
+ /**
262
+ * Worn armour: one humanoid-shaped mesh, the two sizes it is drawn at, and a sheet per material.
263
+ *
264
+ * Armour is not geometry of its own — it is the wearer's own humanoid shape grown by a fixed amount,
265
+ * which is why one mesh dresses a player, a zombie and an armour stand alike. The leggings are the
266
+ * *inner* layer and everything else the *outer*, drawn a little larger so the two never fight.
267
+ *
268
+ * Everything a consumer needs to decide what to draw is stated here rather than derived, in keeping
269
+ * with the rest of the pack: which parts a slot lights up, which sheet a material uses, and which
270
+ * material an item is made of.
271
+ */
272
+ interface EquipmentPack {
273
+ /** Key into `models`, holding the humanoid armour shape. */
274
+ model: string;
275
+ /** How much each layer grows the wearer's boxes by, in pixels. */
276
+ inflate: {
277
+ inner: number;
278
+ outer: number;
279
+ };
280
+ /** Parts each slot shows. A slot lights up some of the one mesh rather than owning geometry. */
281
+ slots: Record<EquipmentSlot, string[]>;
282
+ /** Which layer a slot is drawn on, which decides the sheet as well as the size. */
283
+ layerOf: Record<EquipmentSlot, 'inner' | 'outer'>;
284
+ /** Sprite ids per material and layer, into this file's own `sprites`. */
285
+ materials: Record<string, Partial<Record<'inner' | 'outer', string>>>;
286
+ /**
287
+ * The armour items themselves. Keyed by item id because that is what a world writes into an
288
+ * entity's `equipment` compound, and nothing in the assets maps one to the other.
289
+ */
290
+ items: Record<string, {
291
+ material: string;
292
+ slot: EquipmentSlot;
293
+ }>;
294
+ /** Materials whose sheet is greyscale and takes the item's own dye colour. */
295
+ dyeable: string[];
296
+ /** Worn armour-trim sheets generated from the version's armour-trim atlas. */
297
+ trims: {
298
+ /** Sprite ids per pattern and material, into this file's own `sprites`. */
299
+ patterns: Record<string, Record<string, Partial<Record<'inner' | 'outer', string>>>>;
300
+ /** Material a trim falls back to when it matches the armour it is on. */
301
+ darker: Record<string, string>;
302
+ };
255
303
  }
256
304
  /** `meta.json`, written last because it hashes every other file. */
257
305
  interface BlockPackMetaFile {
@@ -277,4 +325,4 @@ interface BlockPackMetaFile {
277
325
  hashes: Record<string, string>;
278
326
  }
279
327
  //#endregion
280
- export { EntityPackPart as C, EntityPackModel as S, ItemPackLayer as T, BlockPackTintsFile as _, BlockPackBlockStatesFile as a, EntityPackCubeFace as b, BlockPackEntityModelsFile as c, BlockPackMetaFile as d, BlockPackModel as f, BlockPackSpriteFrame as g, BlockPackSprite as h, BlockPackBlockState as i, BlockPackFace as l, BlockPackRenderLayer as m, BlockPackAtlasPage as n, BlockPackElement as o, BlockPackModelsFile as p, BlockPackBiomesFile as r, BlockPackEntitiesFile as s, BlockPackAtlasFile as t, BlockPackItemsFile as u, BlockPackVariant as v, ItemPackEntry as w, EntityPackEntry as x, EntityPackCube as y };
328
+ export { EntityPackModel as C, ItemPackEntry as D, EquipmentSlot as E, ItemPackLayer as O, EntityPackEntry as S, EquipmentPack as T, BlockPackTintsFile as _, BlockPackBlockStatesFile as a, EntityPackCube as b, BlockPackEntityModelsFile as c, BlockPackMetaFile as d, BlockPackModel as f, BlockPackSpriteFrame as g, BlockPackSprite as h, BlockPackBlockState as i, BlockPackFace as l, BlockPackRenderLayer as m, BlockPackAtlasPage as n, BlockPackElement as o, BlockPackModelsFile as p, BlockPackBiomesFile as r, BlockPackEntitiesFile as s, BlockPackAtlasFile as t, BlockPackItemsFile as u, BlockPackVariant as v, EntityPackPart as w, EntityPackCubeFace as x, EQUIPMENT_SLOTS as y };
package/dist/pack.d.ts CHANGED
@@ -2,5 +2,5 @@ import { n as BiomeClimatePack, t as BiomeClimate } from "./biomes-CJDJQqJb.js";
2
2
  import { a as BlockStateMultipartCase, d as matchesCondition, n as BlockProperties, o as BlockStateVariantCase, p as weightedVariantIndex, r as BlockStateDefinition, s as MultipartCondition, t as BlockModelVariant, u as evaluateBlockState } from "./blockstate-eval-BzznRcVY.js";
3
3
  import { n as ObjMesh, t as MeshGroup } from "./obj-mesh-ydhVfLKs.js";
4
4
  import { n as BlockTintPack, t as BlockTint } from "./tints-DoBv5S9v.js";
5
- import { _ as BlockPackTintsFile, a as BlockPackBlockStatesFile, d as BlockPackMetaFile, f as BlockPackModel, g as BlockPackSpriteFrame, h as BlockPackSprite, i as BlockPackBlockState, l as BlockPackFace, m as BlockPackRenderLayer, n as BlockPackAtlasPage, o as BlockPackElement, p as BlockPackModelsFile, r as BlockPackBiomesFile, t as BlockPackAtlasFile, v as BlockPackVariant } from "./pack-format-QcVFxG_b.js";
5
+ import { _ as BlockPackTintsFile, a as BlockPackBlockStatesFile, d as BlockPackMetaFile, f as BlockPackModel, g as BlockPackSpriteFrame, h as BlockPackSprite, i as BlockPackBlockState, l as BlockPackFace, m as BlockPackRenderLayer, n as BlockPackAtlasPage, o as BlockPackElement, p as BlockPackModelsFile, r as BlockPackBiomesFile, t as BlockPackAtlasFile, v as BlockPackVariant } from "./pack-format-D5IgQjcD.js";
6
6
  export { type BiomeClimate, type BiomeClimatePack, type BlockModelVariant, type BlockPackAtlasFile, type BlockPackAtlasPage, type BlockPackBiomesFile, type BlockPackBlockState, type BlockPackBlockStatesFile, type BlockPackElement, type BlockPackFace, type BlockPackMetaFile, type BlockPackModel, type BlockPackModelsFile, type BlockPackRenderLayer, type BlockPackSprite, type BlockPackSpriteFrame, type BlockPackTintsFile, type BlockPackVariant, type BlockProperties, type BlockStateDefinition, type BlockStateMultipartCase, type BlockStateVariantCase, type BlockTint, type BlockTintPack, type MeshGroup, type MultipartCondition, type ObjMesh, evaluateBlockState, matchesCondition, weightedVariantIndex };
package/dist/pack.js CHANGED
@@ -1,2 +1,2 @@
1
- import { i as matchesCondition, o as weightedVariantIndex, r as evaluateBlockState } from "./blockstate-eval-BRQ3NWY2.js";
1
+ import { i as matchesCondition, o as weightedVariantIndex, r as evaluateBlockState } from "./blockstate-eval-CV_LwUwj.js";
2
2
  export { evaluateBlockState, matchesCondition, weightedVariantIndex };
@@ -10,7 +10,7 @@ import { t as loadAtlasResolver } from "./registry-DlduyjtM.js";
10
10
  import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-BNibYkmI.js";
11
11
  import { n as TextureLoader } from "./loader-C18GpurU.js";
12
12
  import { t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
13
- import { a as builtinDynamicResources } from "./generators-BCZVlWig.js";
13
+ import { a as builtinDynamicResources } from "./generators-D6giKoab.js";
14
14
  import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "./entity-fallback-BRMFKPlM.js";
15
15
  import { t as legacyTintsForChain } from "./legacy-tints-l-541wgI.js";
16
16
  import { n as defaultBlockStateModel, t as blockStateTransform } from "./blockstate-DVb8Mhxc.js";
@@ -1,2 +1,2 @@
1
- import { t as ItemPipeline } from "../pipeline-CjRcZB63.js";
1
+ import { t as ItemPipeline } from "../pipeline-CWRQQ9DM.js";
2
2
  export { ItemPipeline };
@@ -3,10 +3,10 @@ import { n as discoverItems } from "./discovery-CD0QqxSF.js";
3
3
  import { n as LayeredResourceManager } from "./manager-BNibYkmI.js";
4
4
  import { t as curatedModelOverrides } from "./models-CZjCOjs4.js";
5
5
  import { r as encodeRasterAsset } from "./encode-LR9wxigC.js";
6
- import { t as classifyItemStyle } from "./item-styles-DjYRdyHi.js";
6
+ import { t as classifyItemStyle } from "./item-styles-BAeneY1R.js";
7
7
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
8
8
  import { t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
9
- import { t as ItemPipeline } from "./pipeline-CjRcZB63.js";
9
+ import { t as ItemPipeline } from "./pipeline-CWRQQ9DM.js";
10
10
  import { t as describeResources } from "./descriptor-JyXhfd-c.js";
11
11
  import { t as WorkerRenderPool } from "./pool-CKGp1qup.js";
12
12
  import path from "node:path";
package/dist/run.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { o as evaluateItemModel } from "./definition-ColsvWrH.js";
2
- import { t as run } from "./run-CGcHj_qq.js";
2
+ import { t as run } from "./run-CQXJCo8u.js";
3
3
  export { evaluateItemModel, run };
@@ -1,4 +1,4 @@
1
- import { t as ItemPipeline } from "../pipeline-CjRcZB63.js";
1
+ import { t as ItemPipeline } from "../pipeline-CWRQQ9DM.js";
2
2
  import { n as restoreResources } from "../descriptor-JyXhfd-c.js";
3
3
  import sharp from "sharp";
4
4
  import { parentPort, workerData } from "node:worker_threads";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodecraft/rendermite",
3
- "version": "1.6.7",
3
+ "version": "1.7.0",
4
4
  "description": "Minecraft item icon renderer: renders inventory-identical item icons from vanilla and modded assets across game versions, outputting optimized PNG/WebP/AVIF plus CSS and a JSON item library.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,127 +0,0 @@
1
- import { t as findGeoForEntity } from "./entity-geo-DbTtMlPL.js";
2
- import { n as extractInheritedModel } from "./inherit-C5Ifg3SM.js";
3
- import { a as linkEntityModel, i as classReader, r as buildModelNameIndex } from "./link-5GmBLTzk.js";
4
- import { s as resolveMappings, t as MappingsUnavailableError } from "./mappings-BEPVaiwE.js";
5
- import { n as loadModelCode } from "./model-code-1Vuk-zj_.js";
6
- //#region src/blocks/entity-models.ts
7
- /**
8
- * Entity geometry for the pack: link each entity to the class that builds it, read that class's
9
- * bytecode, and stitch the sheets those models are drawn with.
10
- *
11
- * The pieces all live in `src/entities/` — this is the part that knows what a *pack* wants. Which is
12
- * mostly two things the extractor does not care about: several entities share one model (every zombie
13
- * in the game is a `HumanoidModel`), so models are keyed by class and pointed at rather than copied;
14
- * and the `uv` values in a model address the entity's own sheet, so those sheets have to be in an
15
- * atlas the consumer can sample.
16
- *
17
- * Needs the *code*, not just the assets. An `--assets` folder has none, and a pack exported from one
18
- * carries no entity geometry — which is the honest answer rather than a silent gap.
19
- */
20
- function countCubes(part) {
21
- return part.cubes.length + part.children.reduce((sum, child) => sum + countCubes(child), 0);
22
- }
23
- /** Drops the internal shape into the pack's, omitting what is at its default. */
24
- function toPackPart(part) {
25
- return {
26
- name: part.name,
27
- pivot: [...part.pivot],
28
- rotation: [...part.rotation],
29
- cubes: part.cubes.map((cube) => {
30
- return {
31
- origin: [...cube.origin],
32
- size: [...cube.size],
33
- uv: [...cube.uv],
34
- ...cube.inflate !== 0 && { inflate: cube.inflate },
35
- ...cube.mirror && { mirror: true },
36
- ...cube.faces && { faces: cube.faces }
37
- };
38
- }),
39
- children: part.children.map((child) => toPackPart(child))
40
- };
41
- }
42
- /**
43
- * Recovers geometry for as many of `entityIds` as the code describes.
44
- *
45
- * Mappings are resolved once: downloaded for an obfuscated jar, and the identity for one that is not
46
- * (from the 26 line the client ships in the clear, and a mod jar never was obfuscated). A version that
47
- * is obfuscated *and* unmapped — 1.13.x — yields nothing, with the reason recorded once rather than
48
- * per entity.
49
- */
50
- async function collectEntityGeometry(options) {
51
- const { classes, entityIds } = options;
52
- const models = {};
53
- const modelOf = /* @__PURE__ */ new Map();
54
- const spriteIds = /* @__PURE__ */ new Set();
55
- const failures = [];
56
- const names = await classes.list();
57
- let mappings;
58
- try {
59
- ({mappings} = await resolveMappings(options.version, options.cacheDir, async () => names));
60
- } catch (err) {
61
- failures.push({
62
- id: options.version,
63
- reason: err instanceof MappingsUnavailableError ? `no entity geometry: ${err.message}` : `no entity geometry: mappings could not be loaded (${err.message})`
64
- });
65
- return {
66
- models,
67
- modelOf,
68
- spriteIds,
69
- failures
70
- };
71
- }
72
- const code = await loadModelCode(names, async (internal) => await classes.read(internal), (internal) => mappings.originalOf.get(internal) ?? internal);
73
- const extracted = /* @__PURE__ */ new Map();
74
- const geometryOf = async (internal) => {
75
- if (!extracted.has(internal)) extracted.set(internal, await extractInheritedModel(internal, async (name) => await classes.read(name), code));
76
- return extracted.get(internal) ?? null;
77
- };
78
- const context = {
79
- mappings,
80
- read: classReader(async (internal) => await classes.read(internal)),
81
- hasGeometry: async (internal) => {
82
- const model = await geometryOf(internal);
83
- return model !== null && model.parts.reduce((sum, part) => sum + countCubes(part), 0) > 0;
84
- },
85
- nameIndex: buildModelNameIndex(names)
86
- };
87
- const geoFor = async (entityId) => {
88
- if (!options.resources) return null;
89
- const [namespace, name] = entityId.includes(":") ? entityId.split(":") : ["minecraft", entityId];
90
- return await findGeoForEntity(options.resources, namespace, name);
91
- };
92
- let done = 0;
93
- for (const entityId of [...entityIds].toSorted((left, right) => left.localeCompare(right))) {
94
- options.onProgress?.(++done, entityIds.length);
95
- const link = await linkEntityModel(entityId, context);
96
- const guessed = link?.route === "vanilla-name";
97
- const found = link && !guessed ? {
98
- id: link.className,
99
- model: await geometryOf(link.obfuscated)
100
- } : await geoFor(entityId) ?? (link ? {
101
- id: link.className,
102
- model: await geometryOf(link.obfuscated)
103
- } : null);
104
- if (!found?.model) continue;
105
- const { id: modelId, model } = found;
106
- if (!models[modelId]) models[modelId] = {
107
- textureSize: [...model.textureSize],
108
- parts: model.parts.map((part) => toPackPart(part)),
109
- ...model.notes.length > 0 && { notes: [...model.notes] }
110
- };
111
- modelOf.set(entityId, modelId);
112
- const texture = options.textureOf.get(entityId);
113
- if (texture) spriteIds.add(texture);
114
- else failures.push({
115
- id: entityId,
116
- reason: `geometry recovered from ${modelId} but no entity texture resolved`
117
- });
118
- }
119
- return {
120
- models,
121
- modelOf,
122
- spriteIds,
123
- failures
124
- };
125
- }
126
- //#endregion
127
- export { collectEntityGeometry as t };