@nodecraft/rendermite 1.6.1 → 1.6.3

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 (33) hide show
  1. package/dist/{block-entities-xv3bQpEX.js → block-entities-XAynAVUE.js} +1 -1
  2. package/dist/blocks/block-entities.js +1 -1
  3. package/dist/blocks/cli.js +1 -1
  4. package/dist/blocks/entities.js +1 -1
  5. package/dist/blocks/entity-models.js +1 -1
  6. package/dist/blocks/export.js +1 -1
  7. package/dist/{cli-D2KJc_yl.js → cli-B2-DjSYI.js} +2 -2
  8. package/dist/cli.js +2 -2
  9. package/dist/entities/inherit.js +1 -1
  10. package/dist/entities/jar-classes.js +1 -1
  11. package/dist/entities/merge.d.ts +16 -1
  12. package/dist/entities/merge.js +2 -2
  13. package/dist/entities/model-bytecode.js +1 -1
  14. package/dist/{entities-DvmA9fEV.js → entities-DubtdM11.js} +6 -2
  15. package/dist/{entity-fallback-Bth0fa7m.js → entity-fallback-BcJWh91-.js} +1 -1
  16. package/dist/{entity-models-_EZ3PVtN.js → entity-models-D_QGok9j.js} +1 -1
  17. package/dist/{entity-textures-DFRIVdF1.js → entity-textures-4XXT8jVI.js} +25 -2
  18. package/dist/{export-BfEIwSxY.js → export-BFcXFTX6.js} +27 -3
  19. package/dist/index.js +2 -2
  20. package/dist/{inherit-ByHjOJX3.js → inherit-C5Ifg3SM.js} +3 -3
  21. package/dist/{jar-classes-DCtELr1i.js → jar-classes-3GVCJZT7.js} +13 -3
  22. package/dist/merge-DeHruviG.js +109 -0
  23. package/dist/{model-bytecode-gWy5_uCj.js → model-bytecode-BQKCLPze.js} +139 -37
  24. package/dist/{pipeline-BUIMzMzg.js → pipeline-7rvL6vx1.js} +1 -1
  25. package/dist/render/entity-fallback.js +1 -1
  26. package/dist/render/pipeline.js +1 -1
  27. package/dist/resources/entity-textures.d.ts +13 -1
  28. package/dist/resources/entity-textures.js +2 -2
  29. package/dist/{run-BQJkqc5f.js → run-BXAqZ5qY.js} +1 -1
  30. package/dist/run.js +1 -1
  31. package/dist/workers/render-worker.js +1 -1
  32. package/package.json +1 -1
  33. package/dist/merge-NDYxpmL8.js +0 -48
@@ -1,5 +1,5 @@
1
1
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
- import { a as findChestTexture, c as findFluidStill, i as findBedTexture, l as findMobTexture, n as HEAD_LAYOUTS, o as findEntityTexture, r as coversSheet, s as findFluidSibling, t as DYE_COLORS } from "./entity-textures-DFRIVdF1.js";
2
+ import { a as findBedTexture, c as findFluidSibling, i as coversSheet, l as findFluidStill, n as HEAD_LAYOUTS, o as findChestTexture, s as findEntityTexture, t as DYE_COLORS, u as findMobTexture } from "./entity-textures-4XXT8jVI.js";
3
3
  //#region src/blocks/block-entities.ts
4
4
  /**
5
5
  * Geometry for blocks the game draws from Java rather than from a model.
@@ -1,2 +1,2 @@
1
- import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "../block-entities-xv3bQpEX.js";
1
+ import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "../block-entities-XAynAVUE.js";
2
2
  export { INVISIBLE_BLOCKS, blockEntityGeometry, synthesizeVariants };
@@ -1,2 +1,2 @@
1
- import { t as runBlocksCli } from "../cli-D2KJc_yl.js";
1
+ import { t as runBlocksCli } from "../cli-B2-DjSYI.js";
2
2
  export { runBlocksCli };
@@ -1,2 +1,2 @@
1
- import { n as entityTypesOf, t as collectEntities } from "../entities-DvmA9fEV.js";
1
+ import { n as entityTypesOf, t as collectEntities } from "../entities-DubtdM11.js";
2
2
  export { collectEntities, entityTypesOf };
@@ -1,2 +1,2 @@
1
- import { t as collectEntityGeometry } from "../entity-models-_EZ3PVtN.js";
1
+ import { t as collectEntityGeometry } from "../entity-models-D_QGok9j.js";
2
2
  export { collectEntityGeometry };
@@ -1,2 +1,2 @@
1
- import { t as exportBlockPack } from "../export-BfEIwSxY.js";
1
+ import { t as exportBlockPack } from "../export-BFcXFTX6.js";
2
2
  export { exportBlockPack };
@@ -1,7 +1,7 @@
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-BfEIwSxY.js";
4
- import { n as layeredClasses, t as JarClassReader } from "./jar-classes-DCtELr1i.js";
3
+ import { t as exportBlockPack } from "./export-BFcXFTX6.js";
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";
7
7
  import { a as prepareVersionResources, r as compareVersions } from "./prepare-D49Gu4Lv.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-D2KJc_yl.js";
10
- import { t as run } from "./run-BQJkqc5f.js";
9
+ import { t as runBlocksCli } from "./cli-B2-DjSYI.js";
10
+ import { t as run } from "./run-BXAqZ5qY.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 { n as extractInheritedModel, t as ancestryOf } from "../inherit-ByHjOJX3.js";
1
+ import { n as extractInheritedModel, t as ancestryOf } from "../inherit-C5Ifg3SM.js";
2
2
  export { ancestryOf, extractInheritedModel };
@@ -1,2 +1,2 @@
1
- import { n as layeredClasses, t as JarClassReader } from "../jar-classes-DCtELr1i.js";
1
+ import { n as layeredClasses, t as JarClassReader } from "../jar-classes-3GVCJZT7.js";
2
2
  export { JarClassReader, layeredClasses };
@@ -12,7 +12,22 @@ declare function slotsOf(parts: Part[]): {
12
12
  declare function buildsOwnMesh(model: ExtractedModel): boolean;
13
13
  /** `base` plus the parts of `extra` that `base` does not name. */
14
14
  declare function mergeModels(base: ExtractedModel, extra: ExtractedModel): ExtractedModel;
15
+ /**
16
+ * Drops boxes that land exactly where one already is.
17
+ *
18
+ * A model builder's branches are all taken, because they turn on a constructor argument this cannot
19
+ * know — a `CubeDeformation`, a baby-variant flag — so a model that builds one shape *or* another
20
+ * emits both. Where the two arms differ, that is the honest answer and the model says so in a note.
21
+ * Where they agree, it is four legs drawn twice in the same place: `HorseModel` builds
22
+ * `left_hind_leg` and `left_hind_baby_leg` at identical coordinates, and two coplanar boxes are
23
+ * exactly what z-fighting is.
24
+ *
25
+ * Keyed on the accumulated pivot and rotation rather than on evaluated corners, since duplicates come
26
+ * from one builder running twice and land on identical frames. The first is kept: a builder states the
27
+ * ordinary shape before the variant.
28
+ */
29
+ declare function dedupeCubes(model: ExtractedModel): ExtractedModel;
15
30
  declare function countCubes(part: Part): number;
16
31
  declare function cubesOf(model: ExtractedModel): number;
17
32
  //#endregion
18
- export { buildsOwnMesh, countCubes, cubesOf, mergeModels, slotsOf };
33
+ export { buildsOwnMesh, countCubes, cubesOf, dedupeCubes, mergeModels, slotsOf };
@@ -1,2 +1,2 @@
1
- import { a as slotsOf, i as mergeModels, n as countCubes, r as cubesOf, t as buildsOwnMesh } from "../merge-NDYxpmL8.js";
2
- export { buildsOwnMesh, countCubes, cubesOf, mergeModels, slotsOf };
1
+ import { a as mergeModels, i as dedupeCubes, n as countCubes, o as slotsOf, r as cubesOf, t as buildsOwnMesh } from "../merge-DeHruviG.js";
2
+ export { buildsOwnMesh, countCubes, cubesOf, dedupeCubes, mergeModels, slotsOf };
@@ -1,2 +1,2 @@
1
- import { t as extractModel } from "../model-bytecode-gWy5_uCj.js";
1
+ import { t as extractModel } from "../model-bytecode-BQKCLPze.js";
2
2
  export { extractModel };
@@ -1,5 +1,5 @@
1
1
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
- import { l as findMobTexture, u as tokens } from "./entity-textures-DFRIVdF1.js";
2
+ import { d as isOverlayPath, f as tokens, u as findMobTexture } from "./entity-textures-4XXT8jVI.js";
3
3
  //#region src/blocks/entities.ts
4
4
  /**
5
5
  * The entity registry, and one colour per entity.
@@ -125,13 +125,17 @@ async function findVariantTexture(resources, namespace, name) {
125
125
  if (!locator.path.startsWith("entity/")) continue;
126
126
  const leaf = locator.path.split("/").at(-1) ?? "";
127
127
  if (tokens(leaf).some((token) => NOT_THE_MOB.has(token))) continue;
128
+ if (isOverlayPath(locator.path)) continue;
128
129
  const candidate = tokens(locator.path);
129
130
  let score = 0;
130
131
  for (const token of wanted) if (candidate.includes(token)) score += 2;
131
132
  if (squashed !== name && candidate.includes(squashed)) score += wanted.length * 2;
132
133
  if (score === 0) continue;
134
+ const folder = locator.path.split("/").slice(1, -1);
135
+ const inFamily = folder.length > 0 && folder.flatMap((segment) => tokens(segment)).every((token) => wanted.includes(token));
136
+ const named = tokens(leaf).some((token) => wanted.includes(token));
133
137
  const depth = locator.path.split("/").length;
134
- score = score * 10 - depth - candidate.length;
138
+ score = (inFamily ? 1e3 : 0) + score * 10 + (named ? 5 : 0) - depth - candidate.length;
135
139
  if (score > bestScore) {
136
140
  best = locator;
137
141
  bestScore = score;
@@ -1,5 +1,5 @@
1
1
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
- import { a as findChestTexture, i as findBedTexture, l as findMobTexture, n as HEAD_LAYOUTS, o as findEntityTexture, r as coversSheet, t as DYE_COLORS, u as tokens } from "./entity-textures-DFRIVdF1.js";
2
+ import { a as findBedTexture, f as tokens, i as coversSheet, n as HEAD_LAYOUTS, o as findChestTexture, s as findEntityTexture, t as DYE_COLORS, u as findMobTexture } from "./entity-textures-4XXT8jVI.js";
3
3
  import { c as renderModel } from "./obj-CJHEHpki.js";
4
4
  //#region src/render/entity-fallback.ts
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { t as findGeoForEntity } from "./entity-geo-B2CkuMWx.js";
2
- import { n as extractInheritedModel } from "./inherit-ByHjOJX3.js";
2
+ import { n as extractInheritedModel } from "./inherit-C5Ifg3SM.js";
3
3
  import { a as linkEntityModel, i as classReader, r as buildModelNameIndex } from "./link-5GmBLTzk.js";
4
4
  import { s as resolveMappings, t as MappingsUnavailableError } from "./mappings-BEPVaiwE.js";
5
5
  import { n as loadModelCode } from "./model-code-1Vuk-zj_.js";
@@ -68,6 +68,29 @@ const HEAD_LAYOUTS = {
68
68
  * live at entity/<mob>.png or entity/<mob>/<mob>.png depending on the mod, and a
69
69
  * head only ever wants the base skin — never a blink or armour overlay.
70
70
  */
71
+ /**
72
+ * Directories that hold an *overlay* rather than a mob.
73
+ *
74
+ * Matched as whole path segments rather than as tokens, because a token would take `chest_boat` out
75
+ * along with `chest`. A trader llama is the case that needed it: its sheet is filed as
76
+ * `entity/llama/decor/trader_llama`, whose leaf is exactly the mob's name — so a search by name found
77
+ * the carpet it wears, which is a few opaque pixels on a transparent sheet, and the llama underneath
78
+ * came out invisible on most of its faces.
79
+ */
80
+ const OVERLAY_DIRECTORIES = /* @__PURE__ */ new Set([
81
+ "decor",
82
+ "armor",
83
+ "markings",
84
+ "glow",
85
+ "eyes",
86
+ "overlay",
87
+ "saddle",
88
+ "harness"
89
+ ]);
90
+ /** Whether a texture is filed inside one of those, whatever the file itself is called. */
91
+ function isOverlayPath(path) {
92
+ return path.split("/").slice(0, -1).some((segment) => OVERLAY_DIRECTORIES.has(segment));
93
+ }
71
94
  async function findMobTexture(resources, namespace, mob) {
72
95
  for (const source of [namespace, "minecraft"]) {
73
96
  for (const candidate of [`entity/${mob}`, `entity/${mob}/${mob}`]) {
@@ -77,7 +100,7 @@ async function findMobTexture(resources, namespace, mob) {
77
100
  let best = null;
78
101
  for (const locator of await resources.listResources("texture", source)) {
79
102
  const leaf = locator.path.split("/").pop();
80
- if (!locator.path.startsWith("entity/") || leaf !== mob) continue;
103
+ if (!locator.path.startsWith("entity/") || leaf !== mob || isOverlayPath(locator.path)) continue;
81
104
  if (best === null || locator.path.length < best.path.length) best = locator;
82
105
  }
83
106
  if (best) return best;
@@ -206,4 +229,4 @@ async function findFluidSibling(resources, still, suffixes) {
206
229
  return null;
207
230
  }
208
231
  //#endregion
209
- export { findChestTexture as a, findFluidStill as c, findBedTexture as i, findMobTexture as l, HEAD_LAYOUTS as n, findEntityTexture as o, coversSheet as r, findFluidSibling as s, DYE_COLORS as t, tokens as u };
232
+ export { findBedTexture as a, findFluidSibling as c, isOverlayPath as d, tokens as f, coversSheet as i, findFluidStill as l, HEAD_LAYOUTS as n, findChestTexture as o, OVERLAY_DIRECTORIES as r, findEntityTexture as s, DYE_COLORS as t, findMobTexture as u };
@@ -1,9 +1,9 @@
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-xv3bQpEX.js";
3
+ import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "./block-entities-XAynAVUE.js";
4
4
  import { a as parseBlockState, n as collectModels } from "./blockstate-eval-BRQ3NWY2.js";
5
- import { t as collectEntities } from "./entities-DvmA9fEV.js";
6
- import { t as collectEntityGeometry } from "./entity-models-_EZ3PVtN.js";
5
+ import { t as collectEntities } from "./entities-DubtdM11.js";
6
+ import { t as collectEntityGeometry } from "./entity-models-D_QGok9j.js";
7
7
  import { n as discoverItems } from "./discovery-CD0QqxSF.js";
8
8
  import { a as salvageJson, i as resolveTexture, t as ModelLoader } from "./loader-C-NuJaEi.js";
9
9
  import { t as collectItemSprites } from "./item-sprites-G-yikdfV.js";
@@ -70,6 +70,29 @@ const FLUID_SUFFIX = /_(?:still|flow|flowing)$/;
70
70
  /** Sampled where water meets a non-opaque neighbour; matches no suffix. */
71
71
  const EXTRA_FLUID_SPRITES = ["minecraft:block/water_overlay"];
72
72
  /**
73
+ * Sprites selected by block-entity NBT rather than by a JSON blockstate/model graph.
74
+ *
75
+ * AE2's cable bus is assembled in Java from a saved cable plus zero or more face parts. Its JSON
76
+ * models are therefore unreachable from `collectModels`, even though a consumer has enough NBT to
77
+ * reconstruct it. Keep the small, stable texture vocabulary in the atlas for that renderer.
78
+ */
79
+ const DYNAMIC_BLOCK_ENTITY_SPRITES = { ae2: [
80
+ "ae2:part/cable/glass/transparent",
81
+ "ae2:part/cable/covered/transparent",
82
+ "ae2:part/cable/smart/transparent",
83
+ "ae2:part/cable/dense_covered/transparent",
84
+ "ae2:part/cable/dense_smart/transparent",
85
+ "ae2:part/storage_bus",
86
+ "ae2:part/storage_bus_back",
87
+ "ae2:part/storage_bus_sides",
88
+ "ae2:part/import_bus",
89
+ "ae2:part/import_bus_sides",
90
+ "ae2:part/export_bus",
91
+ "ae2:part/export_bus_sides",
92
+ "ae2:part/monitor_back",
93
+ "ae2:part/monitor_sides_status"
94
+ ] };
95
+ /**
73
96
  * Vanilla's `BlockElement.uvsByFace`: the UV a face gets when the model states
74
97
  * none. Deliberately not `render/geometry.ts`'s auto-UVs — those are in the
75
98
  * rasterizer's own unflipped convention, and the pack has to speak the same
@@ -575,6 +598,7 @@ async function exportBlockPack(options) {
575
598
  }
576
599
  for (const namespace of namespaces) for (const locator of await resources.listResources("texture", namespace)) if (FLUID_SUFFIX.test(locator.path)) spriteIds.add(locator.toString());
577
600
  for (const extra of EXTRA_FLUID_SPRITES) if (await resources.hasResource("texture", ResourceLocator.parse(extra))) spriteIds.add(extra);
601
+ for (const namespace of namespaces) for (const extra of DYNAMIC_BLOCK_ENTITY_SPRITES[namespace] ?? []) if (await resources.hasResource("texture", ResourceLocator.parse(extra))) spriteIds.add(extra);
578
602
  const sheet = await buildSpriteSheet(spriteIds, textures, {
579
603
  padding: options.padding,
580
604
  maxPageSize: options.maxPageSize,
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ 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-BfEIwSxY.js";
17
+ import { t as exportBlockPack } from "./export-BFcXFTX6.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";
@@ -22,5 +22,5 @@ import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
22
22
  import { a as builtinDynamicResources } from "./generators-BCZVlWig.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-BQJkqc5f.js";
25
+ import { t as run } from "./run-BXAqZ5qY.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
- import { i as mergeModels } from "./merge-NDYxpmL8.js";
3
- import { t as extractModel } from "./model-bytecode-gWy5_uCj.js";
2
+ import { a as mergeModels, i as dedupeCubes } from "./merge-DeHruviG.js";
3
+ import { t as extractModel } from "./model-bytecode-BQKCLPze.js";
4
4
  //#region src/entities/inherit.ts
5
5
  /**
6
6
  * A model class read together with its ancestors.
@@ -71,7 +71,7 @@ async function extractInheritedModel(internalName, read, code) {
71
71
  });
72
72
  model = mergeModels(model, inheritedModel);
73
73
  }
74
- return model;
74
+ return dedupeCubes(model);
75
75
  }
76
76
  //#endregion
77
77
  export { extractInheritedModel as n, ancestryOf as t };
@@ -25,18 +25,28 @@ function layeredClasses(sources) {
25
25
  return {
26
26
  list: async () => {
27
27
  const names = /* @__PURE__ */ new Set();
28
- for (const source of sources) for (const name of await source.list()) names.add(name);
28
+ for (const source of sources) try {
29
+ for (const name of await source.list()) names.add(name);
30
+ } catch {
31
+ continue;
32
+ }
29
33
  return [...names];
30
34
  },
31
35
  read: async (internalName) => {
32
- for (const source of sources) {
36
+ for (const source of sources) try {
33
37
  const bytes = await source.read(internalName);
34
38
  if (bytes) return bytes;
39
+ } catch {
40
+ continue;
35
41
  }
36
42
  return null;
37
43
  },
38
44
  close: async () => {
39
- for (const source of sources) await source.close();
45
+ for (const source of sources) try {
46
+ await source.close();
47
+ } catch {
48
+ continue;
49
+ }
40
50
  }
41
51
  };
42
52
  }
@@ -0,0 +1,109 @@
1
+ //#region src/entities/merge.ts
2
+ /** A root the interpreter had to invent, because a `MeshDefinition`'s root part is anonymous. */
3
+ const SYNTHETIC_ROOT = /^part\d+$/;
4
+ /**
5
+ * Where a piece's parts sit: at the top, or inside the one anonymous root a `MeshDefinition` makes.
6
+ * Both merge into the same list of named slots and only one of them is nested.
7
+ */
8
+ function slotsOf(parts) {
9
+ const [only] = parts;
10
+ if (parts.length === 1 && only.cubes.length === 0 && SYNTHETIC_ROOT.test(only.name)) return {
11
+ container: only,
12
+ slots: only.children
13
+ };
14
+ return {
15
+ container: null,
16
+ slots: parts
17
+ };
18
+ }
19
+ /** True when this piece built its own mesh rather than adding to one it was handed. */
20
+ function buildsOwnMesh(model) {
21
+ return slotsOf(model.parts).container !== null;
22
+ }
23
+ /** `base` plus the parts of `extra` that `base` does not name. */
24
+ function mergeModels(base, extra) {
25
+ const target = slotsOf(base.parts);
26
+ const source = slotsOf(extra.parts);
27
+ const named = new Set(target.slots.map((part) => part.name));
28
+ const missing = source.slots.filter((part) => !named.has(part.name));
29
+ if (missing.length === 0) return base;
30
+ const parts = target.container ? [{
31
+ ...target.container,
32
+ children: [...target.container.children, ...missing]
33
+ }] : [...target.slots, ...missing];
34
+ const notes = [.../* @__PURE__ */ new Set([...base.notes, ...extra.notes])].filter((note) => parts.length > 1 || !note.includes("disconnected roots"));
35
+ return {
36
+ textureSize: base.textureSize[0] === 64 && base.textureSize[1] === 32 ? extra.textureSize : base.textureSize,
37
+ parts,
38
+ notes
39
+ };
40
+ }
41
+ /**
42
+ * Drops boxes that land exactly where one already is.
43
+ *
44
+ * A model builder's branches are all taken, because they turn on a constructor argument this cannot
45
+ * know — a `CubeDeformation`, a baby-variant flag — so a model that builds one shape *or* another
46
+ * emits both. Where the two arms differ, that is the honest answer and the model says so in a note.
47
+ * Where they agree, it is four legs drawn twice in the same place: `HorseModel` builds
48
+ * `left_hind_leg` and `left_hind_baby_leg` at identical coordinates, and two coplanar boxes are
49
+ * exactly what z-fighting is.
50
+ *
51
+ * Keyed on the accumulated pivot and rotation rather than on evaluated corners, since duplicates come
52
+ * from one builder running twice and land on identical frames. The first is kept: a builder states the
53
+ * ordinary shape before the variant.
54
+ */
55
+ function dedupeCubes(model) {
56
+ const seen = /* @__PURE__ */ new Set();
57
+ const round = (value) => value.toFixed(4);
58
+ const walk = (part, pivot, rotation) => {
59
+ const at = [
60
+ pivot[0] + part.pivot[0],
61
+ pivot[1] + part.pivot[1],
62
+ pivot[2] + part.pivot[2]
63
+ ];
64
+ const spun = [
65
+ rotation[0] + part.rotation[0],
66
+ rotation[1] + part.rotation[1],
67
+ rotation[2] + part.rotation[2]
68
+ ];
69
+ const cubes = part.cubes.filter((cube) => {
70
+ const key = [
71
+ ...at.map(round),
72
+ ...spun.map(round),
73
+ ...cube.origin.map(round),
74
+ ...cube.size.map(round),
75
+ ...cube.uv.map(round),
76
+ round(cube.inflate)
77
+ ].join("|");
78
+ if (seen.has(key)) return false;
79
+ seen.add(key);
80
+ return true;
81
+ });
82
+ const children = part.children.map((child) => walk(child, at, spun)).filter((child) => child.cubes.length > 0 || child.children.length > 0);
83
+ return {
84
+ ...part,
85
+ cubes,
86
+ children
87
+ };
88
+ };
89
+ return {
90
+ ...model,
91
+ parts: model.parts.map((part) => walk(part, [
92
+ 0,
93
+ 0,
94
+ 0
95
+ ], [
96
+ 0,
97
+ 0,
98
+ 0
99
+ ])).filter((part) => part.cubes.length > 0 || part.children.length > 0)
100
+ };
101
+ }
102
+ function countCubes(part) {
103
+ return part.cubes.length + part.children.reduce((total, child) => total + countCubes(child), 0);
104
+ }
105
+ function cubesOf(model) {
106
+ return model.parts.reduce((total, part) => total + countCubes(part), 0);
107
+ }
108
+ //#endregion
109
+ export { mergeModels as a, dedupeCubes as i, countCubes as n, slotsOf as o, cubesOf as r, buildsOwnMesh as t };
@@ -1,5 +1,5 @@
1
1
  import { t as parseClassFile } from "./classfile-Bo7FUrrD.js";
2
- import { i as mergeModels, r as cubesOf, t as buildsOwnMesh } from "./merge-NDYxpmL8.js";
2
+ import { a as mergeModels, r as cubesOf, t as buildsOwnMesh } from "./merge-DeHruviG.js";
3
3
  //#region src/entities/model-bytecode.ts
4
4
  /**
5
5
  * Abstract interpretation of a boxy-model builder, enough to recover the geometry.
@@ -43,6 +43,28 @@ const NUMERIC = /* @__PURE__ */ new Set([
43
43
  "B",
44
44
  "C"
45
45
  ]);
46
+ /**
47
+ * Whether a conditional jump is taken, for the opcodes that compare numbers.
48
+ *
49
+ * The single-operand forms (`ifeq` … `ifle`) test against zero and the two-operand forms (`if_icmpeq`
50
+ * …) against each other, so both reduce to the sign of `left - right`.
51
+ */
52
+ function compare(op, left, right) {
53
+ const difference = left - right;
54
+ switch (op) {
55
+ case 153:
56
+ case 159: return difference === 0;
57
+ case 154:
58
+ case 160: return difference !== 0;
59
+ case 155:
60
+ case 161: return difference < 0;
61
+ case 156:
62
+ case 162: return difference >= 0;
63
+ case 157:
64
+ case 163: return difference > 0;
65
+ default: return difference <= 0;
66
+ }
67
+ }
46
68
  /** Every entity sheet is a power of two, at least 16 in each direction. A texture offset rarely is. */
47
69
  function isSheetSize(width, height) {
48
70
  const power = (value) => value >= 16 && (value & value - 1) === 0;
@@ -109,6 +131,18 @@ const TEXTURE_HEIGHT_FIELDS = /* @__PURE__ */ new Set(["texHeight", "textureHeig
109
131
  const MAX_INLINE_DEPTH = 5;
110
132
  /** Frames per method. A model spends a handful; the cap is there so a strange jar cannot spend all day. */
111
133
  const INLINE_BUDGET = 96;
134
+ /**
135
+ * Instructions per extraction, shared across every frame.
136
+ *
137
+ * A model builder is a few hundred instructions and the longest vanilla loop runs a few thousand, so
138
+ * this is two orders of magnitude of headroom — and it is what makes following a backward goto safe: a
139
+ * loop whose bound cannot be worked out stops here instead of spinning.
140
+ */
141
+ const STEP_BUDGET = 2e5;
142
+ /** Elements tracked per array. A table of segment sizes is a handful; nothing here needs thousands. */
143
+ const MAX_ARRAY = 1024;
144
+ /** Times round a loop. Vanilla's longest builds sixteen segments, so this is generous by four times. */
145
+ const MAX_ITERATIONS = 64;
112
146
  /** How far up a hierarchy to look for an inherited method, which is as deep as a model hierarchy goes. */
113
147
  const MAX_METHOD_HOPS = 6;
114
148
  function newShared(resolve) {
@@ -120,7 +154,10 @@ function newShared(resolve) {
120
154
  branched: false,
121
155
  nextHandle: 1,
122
156
  resolve,
123
- budget: INLINE_BUDGET
157
+ budget: INLINE_BUDGET,
158
+ statics: /* @__PURE__ */ new Map(),
159
+ initialised: /* @__PURE__ */ new Set(),
160
+ steps: STEP_BUDGET
124
161
  };
125
162
  }
126
163
  /** The method a call names, looked up where the JVM would look: the owner, then up its ancestors. */
@@ -143,6 +180,8 @@ var Interpreter = class Interpreter {
143
180
  locals = /* @__PURE__ */ new Map();
144
181
  shared;
145
182
  depth;
183
+ /** How many times each backward jump has been taken, so an undecidable loop cannot spin. */
184
+ loops = /* @__PURE__ */ new Map();
146
185
  /** What this frame returned, for the caller that inlined it. */
147
186
  returned = null;
148
187
  constructor(shared, depth = 0) {
@@ -171,6 +210,19 @@ var Interpreter = class Interpreter {
171
210
  }
172
211
  }
173
212
  /**
213
+ * Runs a class's `<clinit>` once, so its static tables can be read.
214
+ *
215
+ * Only for model code, and only once per class per extraction: the point is a table of numbers, and
216
+ * anything else a static initialiser does is of no interest here.
217
+ */
218
+ initialise(owner) {
219
+ if (this.shared.initialised.has(owner) || this.depth >= MAX_INLINE_DEPTH) return;
220
+ this.shared.initialised.add(owner);
221
+ const target = findMethod(this.shared.resolve, owner, "<clinit>", "()V");
222
+ if (!target) return;
223
+ new Interpreter(this.shared, this.depth + 1).run(target.code, target.classFile);
224
+ }
225
+ /**
174
226
  * Interprets a call into the model's own code, with the arguments it was actually given.
175
227
  *
176
228
  * This is what makes an inherited part come out right. `CowModel` calls `super(12, 0)` and the legs
@@ -189,6 +241,10 @@ var Interpreter = class Interpreter {
189
241
  frame.seed(receiver, descriptor, args);
190
242
  return frame.run(target.code, target.classFile) ? frame.returned : null;
191
243
  }
244
+ /** Records a note once, since every candidate method would otherwise repeat it. */
245
+ note(message) {
246
+ if (!this.shared.notes.includes(message)) this.shared.notes.push(message);
247
+ }
192
248
  pop() {
193
249
  return this.stack.pop() ?? { kind: "unknown" };
194
250
  }
@@ -218,6 +274,11 @@ var Interpreter = class Interpreter {
218
274
  const first = named ? 1 : 0;
219
275
  if (target && (named || floats >= 6 && args.length >= 6 && NUMERIC.has(args[0]) && NUMERIC.has(args[5]))) {
220
276
  const extra = args.slice(first + 6);
277
+ const floatAt = extra.findIndex((arg) => arg === "F" || arg === "D");
278
+ const deformed = taken.find((value) => value.kind === "object" && value.handle.deformation !== void 0);
279
+ let inflate = target.pendingInflate;
280
+ if (floatAt !== -1) inflate = this.number(taken[first + 6 + floatAt]);
281
+ else if (deformed?.kind === "object") inflate = deformed.handle.deformation ?? 0;
221
282
  target.cubes.push({
222
283
  origin: [
223
284
  numbers[first],
@@ -230,7 +291,7 @@ var Interpreter = class Interpreter {
230
291
  numbers[first + 5]
231
292
  ],
232
293
  uv: [...target.pendingUv],
233
- inflate: extra.some((arg) => NUMERIC.has(arg)) ? this.number(taken[first + 6]) : target.pendingInflate,
294
+ inflate,
234
295
  mirror: target.pendingMirror || extra.includes("Z") && this.number(taken[args.length - 1]) === 1
235
296
  });
236
297
  this.push(returns === "V" ? null : receiver);
@@ -348,6 +409,11 @@ var Interpreter = class Interpreter {
348
409
  this.push(returns === "V" ? null : receiver);
349
410
  return;
350
411
  }
412
+ if (args.length === 0 && target && returns === `L${owner};`) {
413
+ target.pendingMirror = true;
414
+ this.push(receiver);
415
+ return;
416
+ }
351
417
  if (args.length === 0 && returns.startsWith("L")) {
352
418
  if (target) {
353
419
  target.isRoot = true;
@@ -371,6 +437,10 @@ var Interpreter = class Interpreter {
371
437
  run(code, constants) {
372
438
  let at = 0;
373
439
  while (at < code.length) {
440
+ if (this.shared.steps-- <= 0) {
441
+ this.note("ran past the step budget, so the shape is only as far as it got");
442
+ return false;
443
+ }
374
444
  const op = code[at++];
375
445
  switch (true) {
376
446
  case op === 1:
@@ -443,9 +513,10 @@ var Interpreter = class Interpreter {
443
513
  this.locals.set((op - 59) % 4, this.pop());
444
514
  break;
445
515
  case ARRAY_LOADS.has(op): {
446
- this.pop();
516
+ const index = this.pop();
447
517
  const array = this.pop();
448
- this.push(array.kind === "array" ? array.items[0] ?? { kind: "unknown" } : { kind: "unknown" });
518
+ const at = index.kind === "number" ? index.value : 0;
519
+ this.push(array.kind === "array" ? array.items[at] ?? { kind: "unknown" } : { kind: "unknown" });
449
520
  break;
450
521
  }
451
522
  case op >= 120 && op <= 131:
@@ -465,18 +536,19 @@ var Interpreter = class Interpreter {
465
536
  });
466
537
  break;
467
538
  case op === 191: return true;
468
- case op === 190:
469
- this.pop();
470
- this.push({
539
+ case op === 190: {
540
+ const array = this.pop();
541
+ this.push(array.kind === "array" ? {
471
542
  kind: "number",
472
- value: 0
473
- });
543
+ value: array.items.length
544
+ } : { kind: "unknown" });
474
545
  break;
546
+ }
475
547
  case ARRAY_STORES.has(op): {
476
548
  const value = this.pop();
477
- this.pop();
549
+ const index = this.pop();
478
550
  const array = this.pop();
479
- if (array.kind === "array") array.items.push(value);
551
+ if (array.kind === "array") array.items[index.kind === "number" ? index.value : array.items.length] = value;
480
552
  break;
481
553
  }
482
554
  case op === 87:
@@ -531,20 +603,36 @@ var Interpreter = class Interpreter {
531
603
  });
532
604
  break;
533
605
  case op >= 133 && op <= 147: break;
534
- case op === 132:
606
+ case op === 132: {
607
+ const slot = code[at];
608
+ const step = code[at + 1] << 24 >> 24;
535
609
  at += 2;
610
+ this.locals.set(slot, {
611
+ kind: "number",
612
+ value: this.number(this.locals.get(slot) ?? { kind: "unknown" }) + step
613
+ });
536
614
  break;
615
+ }
537
616
  case RETURNS.has(op):
538
617
  if (op !== 177) this.returned = this.pop();
539
618
  return true;
540
- case op === 178:
619
+ case op === 178: {
620
+ const index = code[at] << 8 | code[at + 1];
541
621
  at += 2;
542
- this.push({ kind: "unknown" });
622
+ const reference = constants.reference(index);
623
+ const key = reference ? `${reference.owner}.${reference.name}` : "";
624
+ if (reference && !this.shared.statics.has(key)) this.initialise(reference.owner);
625
+ this.push(this.shared.statics.get(key) ?? { kind: "unknown" });
543
626
  break;
544
- case op === 179:
627
+ }
628
+ case op === 179: {
629
+ const index = code[at] << 8 | code[at + 1];
545
630
  at += 2;
546
- this.pop();
631
+ const value = this.pop();
632
+ const reference = constants.reference(index);
633
+ if (reference) this.shared.statics.set(`${reference.owner}.${reference.name}`, value);
547
634
  break;
635
+ }
548
636
  case op === 180: {
549
637
  const index = code[at] << 8 | code[at + 1];
550
638
  at += 2;
@@ -580,6 +668,7 @@ var Interpreter = class Interpreter {
580
668
  const taken = [];
581
669
  for (let count = 0; count < args.length; count++) taken.unshift(this.pop());
582
670
  const objectRef = this.pop();
671
+ if (objectRef.kind === "object" && args.length > 0 && args.length <= 3 && args.every((arg) => arg === "F")) objectRef.handle.deformation = Math.max(...taken.map((value) => this.number(value)));
583
672
  if (objectRef.kind === "object" && args.length >= 2 && args.at(-1) === "I" && args.at(-2) === "I") {
584
673
  objectRef.handle.pendingUv = [this.number(taken[args.length - 2]), this.number(taken[args.length - 1])];
585
674
  objectRef.handle.uvFromConstructor = true;
@@ -597,22 +686,18 @@ var Interpreter = class Interpreter {
597
686
  handle: this.handle()
598
687
  });
599
688
  break;
600
- case op === 188:
601
- at += 1;
602
- this.pop();
603
- this.push({
604
- kind: "array",
605
- items: []
606
- });
607
- break;
608
- case op === 189:
609
- at += 2;
610
- this.pop();
689
+ case op === 188 || op === 189: {
690
+ at += op === 188 ? 1 : 2;
691
+ const length = this.pop();
692
+ const size = length.kind === "number" ? Math.min(Math.max(length.value, 0), MAX_ARRAY) : 0;
611
693
  this.push({
612
694
  kind: "array",
613
- items: []
695
+ items: Array.from({ length: size }, () => {
696
+ return { kind: "unknown" };
697
+ })
614
698
  });
615
699
  break;
700
+ }
616
701
  case op === 192:
617
702
  at += 2;
618
703
  break;
@@ -633,10 +718,20 @@ var Interpreter = class Interpreter {
633
718
  break;
634
719
  }
635
720
  case op >= 153 && op <= 166: {
636
- const comparisons = op >= 159 ? 2 : 1;
637
- for (let count = 0; count < comparisons; count++) this.pop();
721
+ const twoOperands = op >= 159;
722
+ const right = this.pop();
723
+ const left = twoOperands ? this.pop() : {
724
+ kind: "number",
725
+ value: 0
726
+ };
727
+ const offset = (code[at] << 8 | code[at + 1]) << 16 >> 16;
638
728
  at += 2;
639
- this.shared.branched = true;
729
+ const decided = left.kind === "number" && right.kind === "number" && op <= 164 ? compare(op, twoOperands ? left.value : right.value, twoOperands ? right.value : 0) : null;
730
+ if (decided === null) {
731
+ this.shared.branched = true;
732
+ break;
733
+ }
734
+ if (decided) at += offset - 3;
640
735
  break;
641
736
  }
642
737
  case op === 198 || op === 199:
@@ -646,12 +741,19 @@ var Interpreter = class Interpreter {
646
741
  break;
647
742
  case op === 167: {
648
743
  const offset = (code[at] << 8 | code[at + 1]) << 16 >> 16;
649
- if (offset <= 0) {
650
- this.shared.notes.push("backward goto: the builder loops, so its geometry is not recoverable");
651
- return false;
744
+ at += 2;
745
+ if (offset > 0) {
746
+ at += offset - 3;
747
+ break;
652
748
  }
653
- at += offset - 1;
654
- this.shared.branched = true;
749
+ const site = at - 3;
750
+ const round = (this.loops.get(site) ?? 0) + 1;
751
+ this.loops.set(site, round);
752
+ if (round > MAX_ITERATIONS) {
753
+ this.note(`a loop at ${site} went round more than ${MAX_ITERATIONS} times, so the shape is only as far as it got`);
754
+ break;
755
+ }
756
+ at += offset - 3;
655
757
  break;
656
758
  }
657
759
  case op >= 148 && op <= 152:
@@ -11,7 +11,7 @@ import { n as LayeredResourceManager, t as FolderResourceManager } from "./manag
11
11
  import { n as TextureLoader } from "./loader-C18GpurU.js";
12
12
  import { t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
13
13
  import { a as builtinDynamicResources } from "./generators-BCZVlWig.js";
14
- import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "./entity-fallback-Bth0fa7m.js";
14
+ import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "./entity-fallback-BcJWh91-.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";
17
17
  import path from "node:path";
@@ -1,2 +1,2 @@
1
- import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "../entity-fallback-Bth0fa7m.js";
1
+ import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "../entity-fallback-BcJWh91-.js";
2
2
  export { dyeVariantName, dyedVariantTint, renderDyedVariantFallback, renderEntityFallback, spawnEggTints };
@@ -1,2 +1,2 @@
1
- import { t as ItemPipeline } from "../pipeline-BUIMzMzg.js";
1
+ import { t as ItemPipeline } from "../pipeline-7rvL6vx1.js";
2
2
  export { ItemPipeline };
@@ -12,6 +12,18 @@ declare const HEAD_LAYOUTS: Record<string, string>;
12
12
  * live at entity/<mob>.png or entity/<mob>/<mob>.png depending on the mod, and a
13
13
  * head only ever wants the base skin — never a blink or armour overlay.
14
14
  */
15
+ /**
16
+ * Directories that hold an *overlay* rather than a mob.
17
+ *
18
+ * Matched as whole path segments rather than as tokens, because a token would take `chest_boat` out
19
+ * along with `chest`. A trader llama is the case that needed it: its sheet is filed as
20
+ * `entity/llama/decor/trader_llama`, whose leaf is exactly the mob's name — so a search by name found
21
+ * the carpet it wears, which is a few opaque pixels on a transparent sheet, and the llama underneath
22
+ * came out invisible on most of its faces.
23
+ */
24
+ declare const OVERLAY_DIRECTORIES: Set<string>;
25
+ /** Whether a texture is filed inside one of those, whatever the file itself is called. */
26
+ declare function isOverlayPath(path: string): boolean;
15
27
  declare function findMobTexture(resources: ResourceManager, namespace: string, mob: string): Promise<ResourceLocator | null>;
16
28
  /**
17
29
  * Find the mod's own chest sheet for a chest-like item by token overlap over
@@ -48,4 +60,4 @@ declare function findFluidStill(resources: ResourceManager, namespace: string, b
48
60
  */
49
61
  declare function findFluidSibling(resources: ResourceManager, still: ResourceLocator, suffixes: string[]): Promise<ResourceLocator | null>;
50
62
  //#endregion
51
- export { DYE_COLORS, HEAD_LAYOUTS, coversSheet, findBedTexture, findChestTexture, findEntityTexture, findFluidSibling, findFluidStill, findMobTexture, tokens };
63
+ export { DYE_COLORS, HEAD_LAYOUTS, OVERLAY_DIRECTORIES, coversSheet, findBedTexture, findChestTexture, findEntityTexture, findFluidSibling, findFluidStill, findMobTexture, isOverlayPath, tokens };
@@ -1,2 +1,2 @@
1
- import { a as findChestTexture, c as findFluidStill, i as findBedTexture, l as findMobTexture, n as HEAD_LAYOUTS, o as findEntityTexture, r as coversSheet, s as findFluidSibling, t as DYE_COLORS, u as tokens } from "../entity-textures-DFRIVdF1.js";
2
- export { DYE_COLORS, HEAD_LAYOUTS, coversSheet, findBedTexture, findChestTexture, findEntityTexture, findFluidSibling, findFluidStill, findMobTexture, tokens };
1
+ import { a as findBedTexture, c as findFluidSibling, d as isOverlayPath, f as tokens, i as coversSheet, l as findFluidStill, n as HEAD_LAYOUTS, o as findChestTexture, r as OVERLAY_DIRECTORIES, s as findEntityTexture, t as DYE_COLORS, u as findMobTexture } from "../entity-textures-4XXT8jVI.js";
2
+ export { DYE_COLORS, HEAD_LAYOUTS, OVERLAY_DIRECTORIES, coversSheet, findBedTexture, findChestTexture, findEntityTexture, findFluidSibling, findFluidStill, findMobTexture, isOverlayPath, tokens };
@@ -6,7 +6,7 @@ import { r as encodeRasterAsset } from "./encode-LR9wxigC.js";
6
6
  import { t as classifyItemStyle } from "./item-styles-DjYRdyHi.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-BUIMzMzg.js";
9
+ import { t as ItemPipeline } from "./pipeline-7rvL6vx1.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-BQJkqc5f.js";
2
+ import { t as run } from "./run-BXAqZ5qY.js";
3
3
  export { evaluateItemModel, run };
@@ -1,4 +1,4 @@
1
- import { t as ItemPipeline } from "../pipeline-BUIMzMzg.js";
1
+ import { t as ItemPipeline } from "../pipeline-7rvL6vx1.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.1",
3
+ "version": "1.6.3",
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,48 +0,0 @@
1
- //#region src/entities/merge.ts
2
- /** A root the interpreter had to invent, because a `MeshDefinition`'s root part is anonymous. */
3
- const SYNTHETIC_ROOT = /^part\d+$/;
4
- /**
5
- * Where a piece's parts sit: at the top, or inside the one anonymous root a `MeshDefinition` makes.
6
- * Both merge into the same list of named slots and only one of them is nested.
7
- */
8
- function slotsOf(parts) {
9
- const [only] = parts;
10
- if (parts.length === 1 && only.cubes.length === 0 && SYNTHETIC_ROOT.test(only.name)) return {
11
- container: only,
12
- slots: only.children
13
- };
14
- return {
15
- container: null,
16
- slots: parts
17
- };
18
- }
19
- /** True when this piece built its own mesh rather than adding to one it was handed. */
20
- function buildsOwnMesh(model) {
21
- return slotsOf(model.parts).container !== null;
22
- }
23
- /** `base` plus the parts of `extra` that `base` does not name. */
24
- function mergeModels(base, extra) {
25
- const target = slotsOf(base.parts);
26
- const source = slotsOf(extra.parts);
27
- const named = new Set(target.slots.map((part) => part.name));
28
- const missing = source.slots.filter((part) => !named.has(part.name));
29
- if (missing.length === 0) return base;
30
- const parts = target.container ? [{
31
- ...target.container,
32
- children: [...target.container.children, ...missing]
33
- }] : [...target.slots, ...missing];
34
- const notes = [.../* @__PURE__ */ new Set([...base.notes, ...extra.notes])].filter((note) => parts.length > 1 || !note.includes("disconnected roots"));
35
- return {
36
- textureSize: base.textureSize[0] === 64 && base.textureSize[1] === 32 ? extra.textureSize : base.textureSize,
37
- parts,
38
- notes
39
- };
40
- }
41
- function countCubes(part) {
42
- return part.cubes.length + part.children.reduce((total, child) => total + countCubes(child), 0);
43
- }
44
- function cubesOf(model) {
45
- return model.parts.reduce((total, part) => total + countCubes(part), 0);
46
- }
47
- //#endregion
48
- export { slotsOf as a, mergeModels as i, countCubes as n, cubesOf as r, buildsOwnMesh as t };