@nodecraft/rendermite 1.1.4 → 1.2.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 (127) hide show
  1. package/README.md +27 -2
  2. package/assets/builtin/renderchest/models/block/banner_standing.json +225 -0
  3. package/assets/builtin/renderchest/models/block/banner_wall.json +155 -0
  4. package/assets/builtin/renderchest/models/block/bed_foot.json +44 -0
  5. package/assets/builtin/renderchest/models/block/bed_head.json +44 -0
  6. package/assets/builtin/renderchest/models/block/chest_left.json +182 -0
  7. package/assets/builtin/renderchest/models/block/chest_right.json +182 -0
  8. package/assets/builtin/renderchest/models/block/copper_golem_statue.json +709 -0
  9. package/assets/builtin/renderchest/models/block/fluid.json +83 -0
  10. package/assets/builtin/renderchest/models/block/fluid_tinted.json +89 -0
  11. package/assets/builtin/renderchest/models/block/hanging_sign.json +54 -0
  12. package/assets/builtin/renderchest/models/block/standing_sign.json +32 -0
  13. package/assets/builtin/renderchest/models/block/wall_sign.json +19 -0
  14. package/dist/atlas/registry.js +1 -1
  15. package/dist/atlas/sources.js +1 -1
  16. package/dist/atlas-pack-CoOih7By.js +130 -0
  17. package/dist/atlas-pack-DRTrWcSU.d.ts +41 -0
  18. package/dist/block-entities-BbS1kv0m.js +481 -0
  19. package/dist/blocks/atlas-pack.d.ts +2 -0
  20. package/dist/blocks/atlas-pack.js +2 -0
  21. package/dist/blocks/block-entities.d.ts +93 -0
  22. package/dist/blocks/block-entities.js +2 -0
  23. package/dist/blocks/blockstate-eval.d.ts +2 -0
  24. package/dist/blocks/blockstate-eval.js +2 -0
  25. package/dist/blocks/cli.d.ts +9 -0
  26. package/dist/blocks/cli.js +2 -0
  27. package/dist/blocks/export.d.ts +2 -0
  28. package/dist/blocks/export.js +2 -0
  29. package/dist/blocks/obj-mesh.d.ts +2 -0
  30. package/dist/blocks/obj-mesh.js +2 -0
  31. package/dist/blocks/tints.d.ts +2 -0
  32. package/dist/blocks/tints.js +2 -0
  33. package/dist/{blockstate-CdstnW2-.js → blockstate-DVb8Mhxc.js} +1 -1
  34. package/dist/blockstate-eval-Ckjlyxn4.js +231 -0
  35. package/dist/blockstate-eval-DDArZs1P.d.ts +107 -0
  36. package/dist/cli-D7_oUuPT.js +161 -0
  37. package/dist/cli.js +9 -7
  38. package/dist/{descriptor-DWebtkI1.js → descriptor-BVIoEpPO.js} +3 -3
  39. package/dist/{discovery-B9aqV_Rz.js → discovery-CsZu08re.js} +1 -1
  40. package/dist/dynamic/generators.js +1 -1
  41. package/dist/{entity-fallback-Cu22uEIK.js → entity-fallback-DNO0Ta9C.js} +3 -155
  42. package/dist/entity-textures-DFRIVdF1.js +209 -0
  43. package/dist/export-BIpqNU3H.d.ts +44 -0
  44. package/dist/export-DxREy3qA.js +701 -0
  45. package/dist/{face-cQ-pVHoe.d.ts → face-BKwkeTps.d.ts} +1 -1
  46. package/dist/{fluid-bucket-BzoLofB_.js → fluid-bucket-B-I4ZYHl.js} +1 -1
  47. package/dist/{generators-BlG4KmtP.js → generators-BCZVlWig.js} +1 -1
  48. package/dist/{geo-w9HHIrb5.js → geo-BguldlU-.js} +5 -5
  49. package/dist/{geometry-w0yQbzDZ.d.ts → geometry-Bkur58Vi.d.ts} +1 -1
  50. package/dist/index.d.ts +10 -5
  51. package/dist/index.js +21 -16
  52. package/dist/{item-styles-upgEO1yP.js → item-styles-DjYRdyHi.js} +1 -1
  53. package/dist/items/blockstate.js +1 -1
  54. package/dist/items/discovery.js +1 -1
  55. package/dist/{jar-D9z-X7tA.js → jar-5aLDI0nT.js} +2 -2
  56. package/dist/{legacy-reshape-C05SfAPR.js → legacy-reshape-CcdstKyI.js} +2 -2
  57. package/dist/{legacy-tints-B09J0Rxh.js → legacy-tints-l-541wgI.js} +1 -1
  58. package/dist/{loader-CWsTZgrk.js → loader-BvLcevlN.js} +100 -9
  59. package/dist/{loader-Lb0ZeILz.js → loader-C18GpurU.js} +1 -1
  60. package/dist/{loader-DD83d80u.d.ts → loader-C_1_amsq.d.ts} +18 -1
  61. package/dist/{locator-ycZzh_6z.js → locator-COMEtEn9.js} +23 -1
  62. package/dist/{manager-CkletR5K.js → manager-CYbAkWuT.js} +2 -2
  63. package/dist/models/loader.d.ts +1 -1
  64. package/dist/models/loader.js +1 -1
  65. package/dist/models/types.d.ts +1 -1
  66. package/dist/{models-BKxGkPS7.js → models-CQwcTZcg.js} +1 -1
  67. package/dist/mods/models.js +1 -1
  68. package/dist/mods/prepare.js +1 -1
  69. package/dist/mods/synthesize.js +1 -1
  70. package/dist/mods/tints.js +1 -1
  71. package/dist/{renderer-DB1Oe7xs.js → obj-BEjq3_Ao.js} +234 -234
  72. package/dist/obj-mesh-C6Sp4Ysc.d.ts +41 -0
  73. package/dist/obj-mesh-CiHiqrlm.js +97 -0
  74. package/dist/output/item-styles.js +1 -1
  75. package/dist/{pipeline-Bp6amYz_.d.ts → pipeline-BDvXcw20.d.ts} +1 -1
  76. package/dist/{pipeline-CgJaVpoL.js → pipeline-DRMsBiod.js} +14 -14
  77. package/dist/{prepare-D56Z-9cg.js → prepare-B8oPdGYz.js} +5 -5
  78. package/dist/{prepare-Cc8QZ3j0.js → prepare-C95vjt_o.js} +5 -5
  79. package/dist/{registry-DS5PZ57l.js → registry-DlduyjtM.js} +2 -2
  80. package/dist/render/entity-fallback.d.ts +3 -3
  81. package/dist/render/entity-fallback.js +1 -1
  82. package/dist/render/face.d.ts +1 -1
  83. package/dist/render/face.js +1 -1
  84. package/dist/render/fluid-bucket.js +1 -1
  85. package/dist/render/geo.d.ts +2 -2
  86. package/dist/render/geo.js +1 -1
  87. package/dist/render/geometry.d.ts +1 -1
  88. package/dist/render/legacy-tints.d.ts +1 -1
  89. package/dist/render/legacy-tints.js +1 -1
  90. package/dist/render/obj.d.ts +10 -3
  91. package/dist/render/obj.js +2 -2
  92. package/dist/render/pipeline.d.ts +1 -1
  93. package/dist/render/pipeline.js +1 -1
  94. package/dist/render/renderer.d.ts +1 -1
  95. package/dist/render/renderer.js +1 -1
  96. package/dist/render/tints.d.ts +1 -1
  97. package/dist/render/tints.js +1 -1
  98. package/dist/{renderer-C79EQDSn.d.ts → renderer-U20hnhbi.d.ts} +2 -2
  99. package/dist/resources/descriptor.js +1 -1
  100. package/dist/resources/entity-textures.d.ts +51 -0
  101. package/dist/resources/entity-textures.js +2 -0
  102. package/dist/resources/jar.js +1 -1
  103. package/dist/resources/locator.js +1 -1
  104. package/dist/resources/manager.js +1 -1
  105. package/dist/resources/synthetic.js +1 -1
  106. package/dist/{run-uq8_hUx9.d.ts → run-CvIqiZ6T.d.ts} +1 -1
  107. package/dist/{run-U9pM9wKU.js → run-D2S_W5As.js} +7 -7
  108. package/dist/run.d.ts +1 -1
  109. package/dist/run.js +1 -1
  110. package/dist/{sources-Bxk-WOzH.js → sources-BlUriDCs.js} +1 -1
  111. package/dist/{synthesize-3Q0aaOnK.js → synthesize-jTjVjPAt.js} +2 -2
  112. package/dist/{synthetic-ZAUjXT7E.js → synthetic-rc9BPT4P.js} +0 -0
  113. package/dist/textures/loader.js +1 -1
  114. package/dist/tints-2k3ZhkY3.d.ts +41 -0
  115. package/dist/{tints-3VI_2SNy.js → tints-B3WQcPtx.js} +1 -1
  116. package/dist/{tints-Do9Sh3dg.d.ts → tints-DqhgFi8a.d.ts} +1 -1
  117. package/dist/tints-a9FWZLma.js +176 -0
  118. package/dist/{tints-CebmvjmP.js → tints-nxtGrqv5.js} +3 -3
  119. package/dist/{types-DpRSF9Vj.d.ts → types-qlp3I8_-.d.ts} +11 -0
  120. package/dist/versions/download.js +1 -1
  121. package/dist/versions/legacy-reshape.js +1 -1
  122. package/dist/versions/prepare.js +1 -1
  123. package/dist/workers/render-worker.d.ts +1 -1
  124. package/dist/workers/render-worker.js +2 -2
  125. package/package.json +1 -1
  126. package/dist/{download-D9aARBFp.js → download-1wAfrGKx.js} +1 -1
  127. package/dist/{face-CMJ3b3Ae.js → face-CKHboPfh.js} +1 -1
@@ -1,5 +1,6 @@
1
- import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
- import { i as renderModel } from "./renderer-DB1Oe7xs.js";
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";
3
+ import { c as renderModel } from "./obj-BEjq3_Ao.js";
3
4
  //#region src/render/entity-fallback.ts
4
5
  /**
5
6
  * Heuristic rendering for mod items that parent `builtin/entity` — chests,
@@ -10,60 +11,6 @@ import { i as renderModel } from "./renderer-DB1Oe7xs.js";
10
11
  * chest icon for a chest item beats no icon, but nothing here ever guesses
11
12
  * across item kinds.
12
13
  */
13
- /** Tokens too generic to identify a texture on their own. */
14
- const FILLER_TOKENS = /* @__PURE__ */ new Set([
15
- "chest",
16
- "chests",
17
- "crate",
18
- "crates",
19
- "trapped",
20
- "big",
21
- "small",
22
- "the",
23
- "of"
24
- ]);
25
- /** Double-chest halves, lid states, boat sheets, seasonal skins — never icon textures. */
26
- const SKIP_TOKENS = /* @__PURE__ */ new Set([
27
- "left",
28
- "right",
29
- "open",
30
- "opened",
31
- "christmas",
32
- "boat",
33
- "raft",
34
- "minecart"
35
- ]);
36
- function tokens(name) {
37
- return name.split(/[./_]/).filter((token) => token.length > 1);
38
- }
39
- /**
40
- * Find the mod's own chest sheet for a chest-like item by token overlap over
41
- * the FULL texture path — mods keep variant sheets in per-wood directories
42
- * (quark's `quark_variant_chests/acacia/normal.png`), not just under entity/.
43
- */
44
- async function findChestTexture(resources, namespace, itemName) {
45
- const wanted = tokens(itemName).filter((token) => !FILLER_TOKENS.has(token));
46
- const wantTrapped = itemName.includes("trapped");
47
- let best = null;
48
- let bestScore = 0;
49
- let bestNoise = Infinity;
50
- for (const locator of await resources.listResources("texture", namespace)) {
51
- if (!locator.path.includes("chest") && !locator.path.includes("crate")) continue;
52
- const candidate = tokens(locator.path);
53
- if (candidate.some((token) => SKIP_TOKENS.has(token))) continue;
54
- if (wantTrapped !== (candidate.includes("trapped") || candidate.includes("trap"))) continue;
55
- let score = 0;
56
- for (const token of wanted) if (candidate.includes(token)) score++;
57
- if (locator.path.endsWith(`/${itemName}`) || locator.path.endsWith(`/${itemName}_0`)) score++;
58
- if (wanted.length > 0 && score === 0) continue;
59
- if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
60
- best = locator;
61
- bestScore = score;
62
- bestNoise = candidate.length;
63
- }
64
- }
65
- return best;
66
- }
67
14
  /**
68
15
  * An item's English display name, slugified, or null. Mods do not always put the
69
16
  * kind in the id — lootr's Loot Chest is `lootr_inventory` — and the lang file is
@@ -95,74 +42,7 @@ const WHITE_BANNER = {
95
42
  g: 252 / 255,
96
43
  b: 251 / 255
97
44
  };
98
- /** Vanilla DyeColor diffuse colors, keyed by the dye name mods prefix with. */
99
- const DYE_COLORS = {
100
- white: 16383998,
101
- orange: 16351261,
102
- magenta: 13061821,
103
- light_blue: 3847130,
104
- yellow: 16701501,
105
- lime: 8439583,
106
- pink: 15961002,
107
- gray: 4673362,
108
- light_gray: 10329495,
109
- cyan: 1481884,
110
- purple: 8991416,
111
- blue: 3949738,
112
- brown: 8606770,
113
- green: 6192150,
114
- red: 11546150,
115
- black: 1908001
116
- };
117
45
  const DYE_PREFIX = new RegExp(`^(${Object.keys(DYE_COLORS).join("|")})_(.+)$`);
118
- /** Skin sheet sizes the mobheads pack has base geometry for. */
119
- const HEAD_LAYOUTS = {
120
- "64x32": "head_64_32",
121
- "64x64": "head_64_64",
122
- "32x32": "head_32_32"
123
- };
124
- /**
125
- * The entity sheet for a mob, preferring a file named exactly after it. Sheets
126
- * live at entity/<mob>.png or entity/<mob>/<mob>.png depending on the mod, and a
127
- * head only ever wants the base skin — never a blink or armour overlay.
128
- */
129
- async function findMobTexture(resources, namespace, mob) {
130
- for (const source of [namespace, "minecraft"]) {
131
- for (const candidate of [`entity/${mob}`, `entity/${mob}/${mob}`]) {
132
- const locator = new ResourceLocator(source, candidate);
133
- if (await resources.hasResource("texture", locator)) return locator;
134
- }
135
- let best = null;
136
- for (const locator of await resources.listResources("texture", source)) {
137
- const leaf = locator.path.split("/").pop();
138
- if (!locator.path.startsWith("entity/") || leaf !== mob) continue;
139
- if (best === null || locator.path.length < best.path.length) best = locator;
140
- }
141
- if (best) return best;
142
- }
143
- return null;
144
- }
145
- /** Find a full modded bed entity sheet, preferring every distinguishing item-name token. */
146
- async function findBedTexture(resources, namespace, itemName) {
147
- const wanted = tokens(itemName).filter((token) => token !== "bed");
148
- const hasDye = wanted.some((token) => Object.hasOwn(DYE_COLORS, token));
149
- let best = null;
150
- let bestScore = 0;
151
- let bestNoise = Infinity;
152
- for (const locator of await resources.listResources("texture", namespace)) {
153
- if (!locator.path.startsWith("entity/") || !locator.path.includes("bed")) continue;
154
- const candidate = tokens(locator.path);
155
- let score = hasDye ? 0 : candidate.includes("undyed") ? 1 : 0;
156
- for (const token of wanted) if (candidate.includes(token)) score++;
157
- if (score === 0) continue;
158
- if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
159
- best = locator;
160
- bestScore = score;
161
- bestNoise = candidate.length;
162
- }
163
- }
164
- return best;
165
- }
166
46
  /** The dye name a `<dye>_<thing>` mod item is prefixed with, or null. */
167
47
  function dyeVariantName(id) {
168
48
  const locator = ResourceLocator.tryParse(id);
@@ -394,38 +274,6 @@ async function renderEntityFallback(id, models, textures, resources, options) {
394
274
  return null;
395
275
  }
396
276
  /**
397
- * Whether a sheet is a whole skin rather than an overlay. Vanilla's shulker
398
- * covers 44% of its sheet; a tier trim covers under 5%.
399
- */
400
- async function coversSheet(textures, locator) {
401
- const texture = await textures.load(locator).catch(() => null);
402
- if (!texture) return false;
403
- let opaque = 0;
404
- for (let offset = 3; offset < texture.data.length; offset += 4) if (texture.data[offset] > 16) opaque++;
405
- return opaque / (texture.width * texture.height) > .2;
406
- }
407
- /**
408
- * A mod's entity sheet for a kind, preferring the one its item name points at.
409
- * Not restricted to `entity/`: lootr files its whole-skin sheets straight under
410
- * `textures/` (`lootr:shulker`), and the caller gates on coverage anyway.
411
- */
412
- async function findEntityTexture(resources, namespace, itemName, kind) {
413
- const wanted = tokens(itemName).filter((token) => token !== kind && token !== "box");
414
- let best = null;
415
- let bestScore = -1;
416
- for (const locator of await resources.listResources("texture", namespace)) {
417
- if (!locator.path.includes(kind)) continue;
418
- const candidate = tokens(locator.path);
419
- let score = locator.path.startsWith("entity/") ? 1 : 0;
420
- for (const token of wanted) if (candidate.includes(token)) score += 2;
421
- if (score > bestScore) {
422
- best = locator;
423
- bestScore = score;
424
- }
425
- }
426
- return best;
427
- }
428
- /**
429
277
  * A trident's entity sheet. Vanilla's is `entity/trident` (32×32) and mods
430
278
  * that reuse the vanilla model ship the same path under their own namespace;
431
279
  * a mod that names its sheet after the item instead (an `iron_trident` with
@@ -0,0 +1,209 @@
1
+ import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
+ //#region src/resources/entity-textures.ts
3
+ /**
4
+ * Finding a mod's own entity sheet for a thing the game draws in Java.
5
+ *
6
+ * A chest, a mob head, a bed or a shulker box carries no texture in its model,
7
+ * and mods put theirs wherever they like: quark nests variant chests under
8
+ * `quark_variant_chests/acacia/normal`, lootr files whole skins straight under
9
+ * `textures/`. So the sheet is searched for by token overlap with the block or
10
+ * item name rather than assumed from a path.
11
+ *
12
+ * Shared by the icon renderer's `builtin/entity` fallback and the block pack's
13
+ * substitution table, which are the same problem seen from two directions.
14
+ */
15
+ /** Tokens too generic to identify a texture on their own. */
16
+ const FILLER_TOKENS = /* @__PURE__ */ new Set([
17
+ "chest",
18
+ "chests",
19
+ "crate",
20
+ "crates",
21
+ "trapped",
22
+ "big",
23
+ "small",
24
+ "the",
25
+ "of"
26
+ ]);
27
+ /** Double-chest halves, lid states, boat sheets, seasonal skins — never icon textures. */
28
+ const SKIP_TOKENS = /* @__PURE__ */ new Set([
29
+ "left",
30
+ "right",
31
+ "open",
32
+ "opened",
33
+ "christmas",
34
+ "boat",
35
+ "raft",
36
+ "minecart"
37
+ ]);
38
+ function tokens(name) {
39
+ return name.split(/[./_]/).filter((token) => token.length > 1);
40
+ }
41
+ /** Vanilla DyeColor diffuse colors, keyed by the dye name mods prefix with. */
42
+ const DYE_COLORS = {
43
+ white: 16383998,
44
+ orange: 16351261,
45
+ magenta: 13061821,
46
+ light_blue: 3847130,
47
+ yellow: 16701501,
48
+ lime: 8439583,
49
+ pink: 15961002,
50
+ gray: 4673362,
51
+ light_gray: 10329495,
52
+ cyan: 1481884,
53
+ purple: 8991416,
54
+ blue: 3949738,
55
+ brown: 8606770,
56
+ green: 6192150,
57
+ red: 11546150,
58
+ black: 1908001
59
+ };
60
+ /** Skin sheet sizes the mobheads pack has base geometry for. */
61
+ const HEAD_LAYOUTS = {
62
+ "64x32": "head_64_32",
63
+ "64x64": "head_64_64",
64
+ "32x32": "head_32_32"
65
+ };
66
+ /**
67
+ * The entity sheet for a mob, preferring a file named exactly after it. Sheets
68
+ * live at entity/<mob>.png or entity/<mob>/<mob>.png depending on the mod, and a
69
+ * head only ever wants the base skin — never a blink or armour overlay.
70
+ */
71
+ async function findMobTexture(resources, namespace, mob) {
72
+ for (const source of [namespace, "minecraft"]) {
73
+ for (const candidate of [`entity/${mob}`, `entity/${mob}/${mob}`]) {
74
+ const locator = new ResourceLocator(source, candidate);
75
+ if (await resources.hasResource("texture", locator)) return locator;
76
+ }
77
+ let best = null;
78
+ for (const locator of await resources.listResources("texture", source)) {
79
+ const leaf = locator.path.split("/").pop();
80
+ if (!locator.path.startsWith("entity/") || leaf !== mob) continue;
81
+ if (best === null || locator.path.length < best.path.length) best = locator;
82
+ }
83
+ if (best) return best;
84
+ }
85
+ return null;
86
+ }
87
+ /**
88
+ * Find the mod's own chest sheet for a chest-like item by token overlap over
89
+ * the FULL texture path — mods keep variant sheets in per-wood directories
90
+ * (quark's `quark_variant_chests/acacia/normal.png`), not just under entity/.
91
+ */
92
+ async function findChestTexture(resources, namespace, itemName) {
93
+ const wanted = tokens(itemName).filter((token) => !FILLER_TOKENS.has(token));
94
+ const wantTrapped = itemName.includes("trapped");
95
+ let best = null;
96
+ let bestScore = 0;
97
+ let bestNoise = Infinity;
98
+ for (const locator of await resources.listResources("texture", namespace)) {
99
+ if (!locator.path.includes("chest") && !locator.path.includes("crate")) continue;
100
+ const candidate = tokens(locator.path);
101
+ if (candidate.some((token) => SKIP_TOKENS.has(token))) continue;
102
+ if (wantTrapped !== (candidate.includes("trapped") || candidate.includes("trap"))) continue;
103
+ let score = 0;
104
+ for (const token of wanted) if (candidate.includes(token)) score++;
105
+ if (locator.path.endsWith(`/${itemName}`) || locator.path.endsWith(`/${itemName}_0`)) score++;
106
+ if (wanted.length > 0 && score === 0) continue;
107
+ if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
108
+ best = locator;
109
+ bestScore = score;
110
+ bestNoise = candidate.length;
111
+ }
112
+ }
113
+ return best;
114
+ }
115
+ /** Find a full modded bed entity sheet, preferring every distinguishing item-name token. */
116
+ async function findBedTexture(resources, namespace, itemName) {
117
+ const wanted = tokens(itemName).filter((token) => token !== "bed");
118
+ const hasDye = wanted.some((token) => Object.hasOwn(DYE_COLORS, token));
119
+ let best = null;
120
+ let bestScore = 0;
121
+ let bestNoise = Infinity;
122
+ for (const locator of await resources.listResources("texture", namespace)) {
123
+ if (!locator.path.startsWith("entity/") || !locator.path.includes("bed")) continue;
124
+ const candidate = tokens(locator.path);
125
+ let score = hasDye ? 0 : candidate.includes("undyed") ? 1 : 0;
126
+ for (const token of wanted) if (candidate.includes(token)) score++;
127
+ if (score === 0) continue;
128
+ if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
129
+ best = locator;
130
+ bestScore = score;
131
+ bestNoise = candidate.length;
132
+ }
133
+ }
134
+ return best;
135
+ }
136
+ /**
137
+ * Whether a sheet is a whole skin rather than an overlay. Vanilla's shulker
138
+ * covers 44% of its sheet; a tier trim covers under 5%.
139
+ */
140
+ async function coversSheet(textures, locator) {
141
+ const texture = await textures.load(locator).catch(() => null);
142
+ if (!texture) return false;
143
+ let opaque = 0;
144
+ for (let offset = 3; offset < texture.data.length; offset += 4) if (texture.data[offset] > 16) opaque++;
145
+ return opaque / (texture.width * texture.height) > .2;
146
+ }
147
+ /**
148
+ * A mod's entity sheet for a kind, preferring the one its item name points at.
149
+ * Not restricted to `entity/`: lootr files its whole-skin sheets straight under
150
+ * `textures/` (`lootr:shulker`), and the caller gates on coverage anyway.
151
+ */
152
+ async function findEntityTexture(resources, namespace, itemName, kind) {
153
+ const wanted = tokens(itemName).filter((token) => token !== kind && token !== "box");
154
+ let best = null;
155
+ let bestScore = -1;
156
+ for (const locator of await resources.listResources("texture", namespace)) {
157
+ if (!locator.path.includes(kind)) continue;
158
+ const candidate = tokens(locator.path);
159
+ let score = locator.path.startsWith("entity/") ? 1 : 0;
160
+ for (const token of wanted) if (candidate.includes(token)) score += 2;
161
+ if (score > bestScore) {
162
+ best = locator;
163
+ bestScore = score;
164
+ }
165
+ }
166
+ return best;
167
+ }
168
+ /**
169
+ * The still sprite for a fluid block. A fluid's two frames are `<name>_still`
170
+ * and `<name>_flow` by a convention every loader follows, but where they live
171
+ * is up to the mod — Create puts them under `fluid/`, Immersive Engineering
172
+ * under `block/fluid/`, Mekanism under `liquid/` — and the block is named for
173
+ * the fluid with a suffix the mod picks.
174
+ */
175
+ async function findFluidStill(resources, namespace, blockName) {
176
+ const wanted = tokens(blockName.replace(/_?(?:fluid|liquid|block|source)$/, "")).filter((token) => token !== "fluid" && token !== "liquid" && token !== "block");
177
+ if (wanted.length === 0) return null;
178
+ let best = null;
179
+ let bestScore = 0;
180
+ let bestNoise = Infinity;
181
+ for (const locator of await resources.listResources("texture", namespace)) {
182
+ if (!locator.path.endsWith("_still")) continue;
183
+ const candidate = tokens(locator.path.slice(0, -6));
184
+ const score = wanted.filter((token) => candidate.includes(token)).length;
185
+ if (score < wanted.length) continue;
186
+ if (best === null || score > bestScore || score === bestScore && candidate.length < bestNoise) {
187
+ best = locator;
188
+ bestScore = score;
189
+ bestNoise = candidate.length;
190
+ }
191
+ }
192
+ return best;
193
+ }
194
+ /**
195
+ * A sheet filed beside a fluid's still one — its flow frames, or the overlay
196
+ * drawn where it meets a solid face. Vanilla and most mods spell flow `_flow`;
197
+ * some spell it `_flowing`. Only water has an overlay, and deriving it as a
198
+ * sibling is what keeps lava from borrowing water's.
199
+ */
200
+ async function findFluidSibling(resources, still, suffixes) {
201
+ const base = still.path.slice(0, -6);
202
+ for (const suffix of suffixes) {
203
+ const candidate = new ResourceLocator(still.namespace, base + suffix);
204
+ if (await resources.hasResource("texture", candidate)) return candidate;
205
+ }
206
+ return null;
207
+ }
208
+ //#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 };
@@ -0,0 +1,44 @@
1
+ import { a as ResourceManager } from "./manager-Cv1NeFyF.js";
2
+ //#region src/blocks/export.d.ts
3
+ interface ExportBlockPackOptions {
4
+ resources: ResourceManager;
5
+ /** Directory the pack is written into; the pack *is* the directory. */
6
+ output: string;
7
+ /** Recorded in meta.json. One version per pack, immutable once published. */
8
+ version: string;
9
+ namespaces?: string[];
10
+ /**
11
+ * Path to the vendored builtin pack (`src/builtin.ts`'s `builtinPackPath`).
12
+ * Layered *under* the input so it only supplies the `renderchest:` and
13
+ * `mobheads:` namespaces nothing else has, never shadowing a real one. It is
14
+ * what gives chests, shulker boxes and the rest a shape; without it those
15
+ * blocks stay empty and are recorded as such.
16
+ */
17
+ builtin?: string;
18
+ /** Edge-extended border per sprite side (default 4). */
19
+ padding?: number;
20
+ /** Ceiling on an atlas page's dimensions (default 4096). */
21
+ maxPageSize?: number;
22
+ onProgress?: (stage: string, done: number, total: number) => void;
23
+ }
24
+ interface BlockPackFailure {
25
+ id: string;
26
+ /**
27
+ * `intentional` is not a failure: it marks a block that is empty because the
28
+ * game draws nothing for it. Filter it out to get the real gaps.
29
+ */
30
+ kind: 'blockstate' | 'model' | 'texture' | 'sprite' | 'geometry' | 'tint' | 'intentional';
31
+ reason: string;
32
+ }
33
+ interface BlockPackResult {
34
+ blocks: number;
35
+ models: number;
36
+ sprites: number;
37
+ pages: number;
38
+ /** Files actually written — the only trustworthy success signal. */
39
+ writtenFiles: number;
40
+ failures: BlockPackFailure[];
41
+ }
42
+ declare function exportBlockPack(options: ExportBlockPackOptions): Promise<BlockPackResult>;
43
+ //#endregion
44
+ export { exportBlockPack as i, BlockPackResult as n, ExportBlockPackOptions as r, BlockPackFailure as t };