@nodecraft/rendermite 1.0.7 → 1.1.1

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 (171) hide show
  1. package/assets/README.md +6 -2
  2. package/assets/builtin/renderchest/models/item/trident.json +372 -0
  3. package/assets/builtin-legacy/renderchest/models/item/trident.json +372 -0
  4. package/assets/mod-models/README.md +130 -0
  5. package/assets/mod-models/ad_astra/models/item/tier_1_rocket.json +4559 -0
  6. package/assets/mod-models/ad_astra/models/item/tier_1_rover.json +6021 -0
  7. package/assets/mod-models/ad_astra/models/item/tier_2_rocket.json +6832 -0
  8. package/assets/mod-models/ad_astra/models/item/tier_3_rocket.json +8522 -0
  9. package/assets/mod-models/ad_astra/models/item/tier_4_rocket.json +7498 -0
  10. package/assets/mod-models/botania/models/item/avatar.json +574 -0
  11. package/assets/mod-models/botania/models/item/bellows.json +423 -0
  12. package/assets/mod-models/botania/models/item/brewery.json +894 -0
  13. package/assets/mod-models/botania/models/item/corporea_index.json +349 -0
  14. package/assets/mod-models/botania/models/item/gaia_pylon.json +1057 -0
  15. package/assets/mod-models/botania/models/item/hourglass.json +502 -0
  16. package/assets/mod-models/botania/models/item/mana_pylon.json +741 -0
  17. package/assets/mod-models/botania/models/item/natura_pylon.json +1057 -0
  18. package/assets/mod-models/botania/models/item/teru_teru_bozu.json +347 -0
  19. package/assets/mod-models/mekanism/models/item/atomic_disassembler.json +1391 -0
  20. package/assets/mod-models/mekanism/models/item/flamethrower.json +1926 -0
  21. package/assets/mod-models/mekanism/models/item/free_runners.json +595 -0
  22. package/assets/mod-models/mekanism/models/item/jetpack.json +1767 -0
  23. package/assets/mod-models/mekanism/models/item/scuba_mask.json +2305 -0
  24. package/assets/mod-models/mekanism/models/item/scuba_tank.json +833 -0
  25. package/assets/mod-tints/README.md +19 -0
  26. package/assets/mod-tints/mysticalagriculture/items/absorption_i_augment.json +16 -0
  27. package/assets/mod-tints/mysticalagriculture/items/absorption_ii_augment.json +16 -0
  28. package/assets/mod-tints/mysticalagriculture/items/absorption_iii_augment.json +16 -0
  29. package/assets/mod-tints/mysticalagriculture/items/absorption_iv_augment.json +16 -0
  30. package/assets/mod-tints/mysticalagriculture/items/absorption_v_augment.json +16 -0
  31. package/assets/mod-tints/mysticalagriculture/items/attack_aoe_i_augment.json +16 -0
  32. package/assets/mod-tints/mysticalagriculture/items/attack_aoe_ii_augment.json +16 -0
  33. package/assets/mod-tints/mysticalagriculture/items/attack_aoe_iii_augment.json +16 -0
  34. package/assets/mod-tints/mysticalagriculture/items/blindness_resistance_augment.json +16 -0
  35. package/assets/mod-tints/mysticalagriculture/items/fire_resistance_augment.json +16 -0
  36. package/assets/mod-tints/mysticalagriculture/items/flight_augment.json +16 -0
  37. package/assets/mod-tints/mysticalagriculture/items/haste_i_augment.json +16 -0
  38. package/assets/mod-tints/mysticalagriculture/items/haste_ii_augment.json +16 -0
  39. package/assets/mod-tints/mysticalagriculture/items/haste_iii_augment.json +16 -0
  40. package/assets/mod-tints/mysticalagriculture/items/health_boost_i_augment.json +16 -0
  41. package/assets/mod-tints/mysticalagriculture/items/health_boost_ii_augment.json +16 -0
  42. package/assets/mod-tints/mysticalagriculture/items/health_boost_iii_augment.json +16 -0
  43. package/assets/mod-tints/mysticalagriculture/items/health_boost_iv_augment.json +16 -0
  44. package/assets/mod-tints/mysticalagriculture/items/health_boost_v_augment.json +16 -0
  45. package/assets/mod-tints/mysticalagriculture/items/hunger_resistance_augment.json +16 -0
  46. package/assets/mod-tints/mysticalagriculture/items/jump_boost_i_augment.json +16 -0
  47. package/assets/mod-tints/mysticalagriculture/items/jump_boost_ii_augment.json +16 -0
  48. package/assets/mod-tints/mysticalagriculture/items/jump_boost_iii_augment.json +16 -0
  49. package/assets/mod-tints/mysticalagriculture/items/luck_i_augment.json +16 -0
  50. package/assets/mod-tints/mysticalagriculture/items/luck_ii_augment.json +16 -0
  51. package/assets/mod-tints/mysticalagriculture/items/luck_iii_augment.json +16 -0
  52. package/assets/mod-tints/mysticalagriculture/items/mining_aoe_i_augment.json +16 -0
  53. package/assets/mod-tints/mysticalagriculture/items/mining_aoe_ii_augment.json +16 -0
  54. package/assets/mod-tints/mysticalagriculture/items/mining_aoe_iii_augment.json +16 -0
  55. package/assets/mod-tints/mysticalagriculture/items/mining_aoe_iv_augment.json +16 -0
  56. package/assets/mod-tints/mysticalagriculture/items/mining_fatigue_resistance_augment.json +16 -0
  57. package/assets/mod-tints/mysticalagriculture/items/nausea_resistance_augment.json +16 -0
  58. package/assets/mod-tints/mysticalagriculture/items/night_vision_augment.json +16 -0
  59. package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_i_augment.json +16 -0
  60. package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_ii_augment.json +16 -0
  61. package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_iii_augment.json +16 -0
  62. package/assets/mod-tints/mysticalagriculture/items/pathing_aoe_iv_augment.json +16 -0
  63. package/assets/mod-tints/mysticalagriculture/items/poison_resistance_augment.json +16 -0
  64. package/assets/mod-tints/mysticalagriculture/items/slow_falling_augment.json +16 -0
  65. package/assets/mod-tints/mysticalagriculture/items/slowness_resistance_augment.json +16 -0
  66. package/assets/mod-tints/mysticalagriculture/items/speed_i_augment.json +16 -0
  67. package/assets/mod-tints/mysticalagriculture/items/speed_ii_augment.json +16 -0
  68. package/assets/mod-tints/mysticalagriculture/items/speed_iii_augment.json +16 -0
  69. package/assets/mod-tints/mysticalagriculture/items/step_assist_augment.json +16 -0
  70. package/assets/mod-tints/mysticalagriculture/items/strength_i_augment.json +16 -0
  71. package/assets/mod-tints/mysticalagriculture/items/strength_ii_augment.json +16 -0
  72. package/assets/mod-tints/mysticalagriculture/items/strength_iii_augment.json +16 -0
  73. package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_i_augment.json +16 -0
  74. package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_ii_augment.json +16 -0
  75. package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_iii_augment.json +16 -0
  76. package/assets/mod-tints/mysticalagriculture/items/tilling_aoe_iv_augment.json +16 -0
  77. package/assets/mod-tints/mysticalagriculture/items/water_breathing_augment.json +16 -0
  78. package/assets/mod-tints/mysticalagriculture/items/weakness_resistance_augment.json +16 -0
  79. package/assets/mod-tints/mysticalagriculture/items/wither_resistance_augment.json +16 -0
  80. package/dist/atlas/registry.js +1 -1
  81. package/dist/blend-8lnfxtLe.d.ts +79 -0
  82. package/dist/blend-KXMclcHk.js +199 -0
  83. package/dist/blockstate-CdstnW2-.js +104 -0
  84. package/dist/{builtin-caYjESh0.js → builtin-WkWjATeh.js} +5 -1
  85. package/dist/builtin.d.ts +3 -1
  86. package/dist/builtin.js +2 -2
  87. package/dist/cli.js +5 -3
  88. package/dist/{compose-lWPrB7wh.js → compose-BGsNFR12.js} +1 -1
  89. package/dist/{definition-3MBm8ar_.js → definition-ColsvWrH.js} +20 -1
  90. package/dist/{definition-BwX6Xxv0.d.ts → definition-ricL7Jqf.d.ts} +2 -0
  91. package/dist/{discovery-0SM0cTLw.js → discovery-B9aqV_Rz.js} +13 -3
  92. package/dist/{discovery-wiJBGryo.d.ts → discovery-BPSUtdm4.d.ts} +1 -1
  93. package/dist/{encode-CaSK8-mi.d.ts → encode-DNcXXvYe.d.ts} +1 -1
  94. package/dist/{encode-Df_tWzkl.js → encode-LR9wxigC.js} +1 -1
  95. package/dist/{entity-fallback-D9QTGU9X.js → entity-fallback-BnFMSHS6.js} +180 -10
  96. package/dist/{face-Cl1O4m2i.js → face-CMJ3b3Ae.js} +44 -18
  97. package/dist/face-cQ-pVHoe.d.ts +44 -0
  98. package/dist/{fluid-bucket-D-GpUQjg.js → fluid-bucket-BzoLofB_.js} +7 -2
  99. package/dist/{geo-DHiWBa-C.js → geo-w9HHIrb5.js} +87 -13
  100. package/dist/{geometry-uIDha8S4.js → geometry-Bi-Bf5rb.js} +7 -1
  101. package/dist/{geometry-BSVmKx5b.d.ts → geometry-w0yQbzDZ.d.ts} +5 -1
  102. package/dist/index.d.ts +9 -9
  103. package/dist/index.js +10 -10
  104. package/dist/items/blockstate.d.ts +23 -0
  105. package/dist/items/blockstate.js +2 -0
  106. package/dist/items/definition.d.ts +1 -1
  107. package/dist/items/definition.js +1 -1
  108. package/dist/items/discovery.d.ts +1 -1
  109. package/dist/items/discovery.js +1 -1
  110. package/dist/{loader-D22zZME7.d.ts → loader-DD83d80u.d.ts} +2 -1
  111. package/dist/{loader-B8NJO7pR.js → loader-DwkA9LR5.js} +267 -15
  112. package/dist/{loader-CfXMxcEV.js → loader-Lb0ZeILz.js} +19 -7
  113. package/dist/models/loader.d.ts +1 -1
  114. package/dist/models/loader.js +1 -1
  115. package/dist/models/types.d.ts +1 -1
  116. package/dist/models-BKxGkPS7.js +18 -0
  117. package/dist/mods/models.d.ts +5 -0
  118. package/dist/mods/models.js +2 -0
  119. package/dist/mods/prepare.d.ts +1 -1
  120. package/dist/mods/prepare.js +1 -1
  121. package/dist/mods/tints.js +1 -1
  122. package/dist/output/encode.d.ts +1 -1
  123. package/dist/output/encode.js +1 -1
  124. package/dist/{pipeline-HiA3DC71.d.ts → pipeline-Bp6amYz_.d.ts} +17 -5
  125. package/dist/{pipeline-Da2Kavba.js → pipeline-zu_ZjnNc.js} +85 -21
  126. package/dist/{prepare-BESRrh6K.js → prepare-D56Z-9cg.js} +7 -2
  127. package/dist/{prepare-CPxO0kKz.d.ts → prepare-Dce7-HAe.d.ts} +8 -0
  128. package/dist/{rasterizer-B9ZGJI3-.d.ts → rasterizer-BSQHEhJ-.d.ts} +4 -2
  129. package/dist/{rasterizer-76qO8TDh.js → rasterizer-DcVJzkxz.js} +13 -5
  130. package/dist/{registry-B9TcjVbs.js → registry-DS5PZ57l.js} +8 -1
  131. package/dist/render/blend.d.ts +2 -2
  132. package/dist/render/blend.js +2 -2
  133. package/dist/render/compose.d.ts +2 -2
  134. package/dist/render/compose.js +1 -1
  135. package/dist/render/entity-fallback.d.ts +19 -5
  136. package/dist/render/entity-fallback.js +2 -2
  137. package/dist/render/face.d.ts +2 -2
  138. package/dist/render/face.js +2 -2
  139. package/dist/render/fluid-bucket.js +1 -1
  140. package/dist/render/geo.d.ts +3 -3
  141. package/dist/render/geo.js +1 -1
  142. package/dist/render/geometry.d.ts +1 -1
  143. package/dist/render/geometry.js +1 -1
  144. package/dist/render/legacy-tints.d.ts +1 -1
  145. package/dist/render/obj.d.ts +5 -3
  146. package/dist/render/obj.js +1 -1
  147. package/dist/render/pipeline.d.ts +1 -1
  148. package/dist/render/pipeline.js +1 -1
  149. package/dist/render/rasterizer.d.ts +1 -1
  150. package/dist/render/rasterizer.js +1 -1
  151. package/dist/render/renderer.d.ts +1 -1
  152. package/dist/render/renderer.js +1 -1
  153. package/dist/render/tints.d.ts +1 -1
  154. package/dist/render/tints.js +1 -1
  155. package/dist/{renderer-B20ssjRm.d.ts → renderer-C79EQDSn.d.ts} +3 -3
  156. package/dist/{renderer-gQW_I7YG.js → renderer-oi1MSF3Y.js} +21 -10
  157. package/dist/{run-B0qPw3zf.js → run-D87zIGfr.js} +3 -3
  158. package/dist/{run-CT3VtFqg.d.ts → run-uq8_hUx9.d.ts} +1 -1
  159. package/dist/run.d.ts +2 -2
  160. package/dist/run.js +2 -2
  161. package/dist/textures/loader.js +1 -1
  162. package/dist/{tints-BtbHegpI.js → tints-3VI_2SNy.js} +107 -1
  163. package/dist/{tints-B8UJmZMu.js → tints-CebmvjmP.js} +2 -2
  164. package/dist/{tints-BH9l0ND0.d.ts → tints-Do9Sh3dg.d.ts} +2 -2
  165. package/dist/{types-COGbtA1t.d.ts → types-DpRSF9Vj.d.ts} +8 -0
  166. package/dist/workers/render-worker.d.ts +1 -1
  167. package/dist/workers/render-worker.js +1 -1
  168. package/package.json +1 -1
  169. package/dist/blend-CEHoJ7tM.d.ts +0 -37
  170. package/dist/blend-D0XWgVQr.js +0 -102
  171. package/dist/face-C49L66sQ.d.ts +0 -30
@@ -2,12 +2,18 @@ import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
2
2
  import { t as LruCache } from "./cache-Cr2ON3RQ.js";
3
3
  //#region src/models/loader.ts
4
4
  var ModelResolutionError = class extends Error {};
5
+ /** Override redirects to follow before giving up; cycles are the reason. */
6
+ const MAX_OVERRIDE_REDIRECTS = 4;
5
7
  const MAX_PARENT_DEPTH = 64;
6
8
  const MAX_TEXTURE_REF_DEPTH = 16;
7
9
  /** Forge's generated-item aliases are injected by the loader, not shipped as resources. */
8
10
  const MODEL_PARENT_ALIASES = {
9
11
  "forge:item/default": "minecraft:item/generated",
10
- "forge:item/default-tool": "minecraft:item/handheld"
12
+ "forge:item/default-tool": "minecraft:item/handheld",
13
+ "forge:block/default": "minecraft:block/block",
14
+ "neoforge:block/default": "minecraft:block/block",
15
+ "neoforge:item/default": "minecraft:item/generated",
16
+ "neoforge:item/default-tool": "minecraft:item/handheld"
11
17
  };
12
18
  /**
13
19
  * Per-mod synthesizers for loaders whose geometry lives entirely in Java but
@@ -19,6 +25,15 @@ const MODEL_PARENT_ALIASES = {
19
25
  */
20
26
  const MOD_LOADER_HANDLERS = {
21
27
  "immersiveengineering:conf_sides": flattenConfSides,
28
+ "mekanism:energy_cube": flattenEnergyCube,
29
+ "mekanism:transmitter": restrictTransmitterToUnconnected,
30
+ "botania:floating_flower": composeFloatingFlower,
31
+ "tconstruct:tool": layerToolParts,
32
+ "modern_industrialization:machine": composeMachine,
33
+ "modern_industrialization:use_block_model": imitateBlockModel,
34
+ "sophisticatedstorage:barrel": flattenStorageBarrel,
35
+ "sophisticatedstorage:limited_barrel": flattenStorageBarrel,
36
+ "sophisticatedstorage:simple_composite": mergeCompositeParts,
22
37
  "immersiveengineering:models/conveyor": flattenConveyor
23
38
  };
24
39
  /**
@@ -34,25 +49,26 @@ const MOD_LOADER_HANDLERS = {
34
49
  function flattenLoaderModel(json, depth = 0) {
35
50
  const loader = extractLoaderType(json);
36
51
  if (!loader || depth > 8) return json;
37
- if (/obj$/i.test(loader)) {
38
- const extended = json;
39
- if (typeof extended.model === "string") {
40
- const marked = withoutLoader(json);
41
- marked.objModel = {
42
- model: extended.model,
43
- flipV: extended.flip_v ?? extended.flip_V ?? false
44
- };
45
- delete marked.model;
46
- return marked;
47
- }
48
- return json;
52
+ const objCandidate = json;
53
+ const objReference = typeof objCandidate.model === "string" && (/obj$/i.test(loader) || /\.obj(?:$|\.)/i.test(objCandidate.model)) ? objCandidate.model : null;
54
+ if (objReference !== null) {
55
+ const marked = withoutLoader(json);
56
+ marked.objModel = {
57
+ model: objReference,
58
+ flipV: objCandidate.flip_v ?? objCandidate.flip_V ?? false
59
+ };
60
+ delete marked.model;
61
+ const objHandler = MOD_LOADER_HANDLERS[loader];
62
+ return objHandler ? objHandler(marked) : marked;
49
63
  }
64
+ if (/obj$/i.test(loader)) return json;
50
65
  const handler = MOD_LOADER_HANDLERS[loader];
51
66
  if (handler) return handler(json);
52
67
  const extended = json;
53
68
  if (extended.perspectives?.gui && typeof extended.perspectives.gui === "object") return flattenLoaderModel(extended.perspectives.gui, depth + 1);
54
69
  if (extended.base && typeof extended.base === "object") return flattenLoaderModel(extended.base, depth + 1);
55
70
  if (typeof extended.childModel === "string") return { parent: extended.childModel };
71
+ if (typeof extended.delegate === "string") return { parent: extended.delegate };
56
72
  if (extended.children && typeof extended.children === "object") {
57
73
  const children = Object.values(extended.children);
58
74
  const inline = children.filter((child) => typeof child === "object" && child !== null);
@@ -67,13 +83,27 @@ function flattenLoaderModel(json, depth = 0) {
67
83
  if (first && typeof first === "object") return flattenLoaderModel(first, depth + 1);
68
84
  }
69
85
  if (extended.inner_model && typeof extended.inner_model === "object") return flattenLoaderModel(extended.inner_model, depth + 1);
86
+ for (const value of Object.values(json)) {
87
+ const nested = value;
88
+ if (typeof nested !== "object" || nested === null || Array.isArray(nested)) continue;
89
+ if (nested.parent !== void 0 || Array.isArray(nested.elements)) return flattenLoaderModel(nested, depth + 1);
90
+ }
70
91
  if (/fluid_container|bucket/i.test(loader)) {
71
92
  const fluid = json.fluid;
72
93
  const bucket = { parent: "minecraft:item/bucket" };
73
94
  if (typeof fluid === "string" && fluid.length > 0 && !fluid.endsWith(":empty")) bucket.fluidContained = fluid;
74
95
  return bucket;
75
96
  }
76
- return withoutLoader(json);
97
+ const stripped = withoutLoader(json);
98
+ const sprite = stripped.textures?.texture;
99
+ if (typeof sprite === "string" && stripped.textures?.layer0 === void 0) return {
100
+ ...stripped,
101
+ textures: {
102
+ ...stripped.textures,
103
+ layer0: sprite
104
+ }
105
+ };
106
+ return stripped;
77
107
  }
78
108
  /** IE conveyor types whose belt texture is not simply `block/conveyor/<type>`. */
79
109
  const CONVEYOR_BELTS = {
@@ -197,6 +227,186 @@ function flattenConfSides(json) {
197
227
  }
198
228
  };
199
229
  }
230
+ /**
231
+ * Mekanism's energy_cube loader keeps the body under `frame` and each side's
232
+ * connector and indicator under `<side>Port`/`<side>LEDs`, picking which sides
233
+ * show at runtime from the stack's stored side config. Every group is emitted:
234
+ * a cube with all its ports is what a configured cube looks like, and dropping
235
+ * them would leave the six faces blank.
236
+ */
237
+ function flattenEnergyCube(json) {
238
+ const elements = Object.entries(json).filter(([name, value]) => (name === "frame" || /(?:Port|LEDs)$/.test(name)) && Array.isArray(value)).flatMap(([, value]) => value);
239
+ if (elements.length === 0) return withoutLoader(json);
240
+ return {
241
+ ...withoutLoader(json),
242
+ elements
243
+ };
244
+ }
245
+ /**
246
+ * Mekanism's transmitter loader wraps one OBJ holding every connection state of
247
+ * a cable — each direction appears as `<direction>NONE`, `NORMAL`, `PUSH` and
248
+ * `PULL` objects, and the loader picks one per side from the neighbouring
249
+ * blocks. An item has no neighbours, so every side is NONE; drawing the lot
250
+ * gives a spiked ball of overlapping states.
251
+ */
252
+ function restrictTransmitterToUnconnected(json) {
253
+ const marked = json;
254
+ if (marked.objModel) marked.objModel.objects = [
255
+ "down",
256
+ "up",
257
+ "north",
258
+ "south",
259
+ "east",
260
+ "west"
261
+ ].map((side) => `${side}NONE`);
262
+ return marked;
263
+ }
264
+ /**
265
+ * Botania's floating flowers are a mystical island with a flower planted on it:
266
+ * the loader draws `botania:block/islands/island_<type>` under the model named
267
+ * by the `flower` key. The island type is stored per block and defaults to
268
+ * GRASS, which is what a freshly crafted one — and so the item — shows.
269
+ */
270
+ function composeFloatingFlower(json) {
271
+ const flower = json.flower;
272
+ const merges = ["botania:block/islands/island_grass"];
273
+ if (typeof flower?.parent === "string") merges.push(flower.parent);
274
+ const composed = {
275
+ ...withoutLoader(json),
276
+ mergeModels: merges
277
+ };
278
+ delete composed.flower;
279
+ return composed;
280
+ }
281
+ /**
282
+ * Tinkers' tool loader stacks one sprite per tool part — head, handle, binding
283
+ * and so on — tinting each by the material it was built from. The parts are
284
+ * declared in draw order, so laying them out as layer0..layerN reproduces the
285
+ * uncoloured tool. `large_*` duplicates are the broad-tool variants the item
286
+ * icon never uses, and `modifier_roots` are overlays for applied modifiers.
287
+ */
288
+ function layerToolParts(json) {
289
+ const stripped = withoutLoader(json);
290
+ const parts = Object.entries(stripped.textures ?? {}).filter(([name]) => !name.startsWith("large_") && name !== "particle" && !/^layer\d+$/.test(name));
291
+ if (parts.length === 0) return stripped;
292
+ const layers = Object.fromEntries(parts.map(([, value], index) => [`layer${index}`, value]));
293
+ return {
294
+ ...stripped,
295
+ parent: "minecraft:item/generated",
296
+ textures: {
297
+ ...stripped.textures,
298
+ ...layers
299
+ }
300
+ };
301
+ }
302
+ /**
303
+ * A casing that borrows another block's look states only the block id. Its
304
+ * model is that block's, under the conventional block/<path> name — which is
305
+ * where every casing MI does this for actually keeps it.
306
+ */
307
+ function imitateBlockModel(json) {
308
+ const block = json.block;
309
+ if (typeof block !== "string") return withoutLoader(json);
310
+ const locator = ResourceLocator.tryParse(block);
311
+ return locator === null ? withoutLoader(json) : { parent: `${locator.namespace}:block/${locator.path}` };
312
+ }
313
+ /**
314
+ * Which face each of MI's machine overlays belongs on. The rest of the
315
+ * vocabulary — `*_active`, `output`, `item_auto`, `fluid_auto` — is runtime
316
+ * state (running, or a configured auto-IO side) that a freshly crafted machine
317
+ * does not show, so the icon leaves them off.
318
+ */
319
+ const MACHINE_OVERLAY_FACES = {
320
+ front: ["north"],
321
+ top: ["up"],
322
+ bottom: ["down"],
323
+ side: [
324
+ "east",
325
+ "west",
326
+ "south"
327
+ ]
328
+ };
329
+ /**
330
+ * MI machines are a casing block wearing per-face overlays. The casing is named
331
+ * rather than inlined (`"casing": "lv"` ↔ machine_casing/lv), and the overlays
332
+ * are full texture ids, so the model becomes the casing merged in underneath a
333
+ * hair-inflated cube carrying the overlay faces.
334
+ */
335
+ function composeMachine(json) {
336
+ const extended = json;
337
+ const casing = typeof extended.casing === "string" ? extended.casing : null;
338
+ const overlays = extended.default_overlays ?? {};
339
+ const textures = {};
340
+ const faces = {};
341
+ for (const [name, directions] of Object.entries(MACHINE_OVERLAY_FACES)) {
342
+ const texture = overlays[name];
343
+ if (typeof texture !== "string") continue;
344
+ textures[name] = texture;
345
+ for (const direction of directions) faces[direction] = { texture: `#${name}` };
346
+ }
347
+ return {
348
+ parent: "minecraft:block/block",
349
+ textures,
350
+ elements: Object.keys(faces).length > 0 ? [{
351
+ from: [
352
+ -.01,
353
+ -.01,
354
+ -.01
355
+ ],
356
+ to: [
357
+ 16.01,
358
+ 16.01,
359
+ 16.01
360
+ ],
361
+ faces
362
+ }] : [],
363
+ ...casing !== null && { mergeModels: [`modern_industrialization:machine_casing/${casing}`] }
364
+ };
365
+ }
366
+ /**
367
+ * Sophisticated Storage composes its barrels from part models with two levels of
368
+ * texture indirection, but the tier part states the three textures a barrel
369
+ * actually wears under vanilla's own `top`/`side`/`bottom` names. Those names
370
+ * belong to `cube_bottom_top`, which is the shape a barrel is — the parts the
371
+ * loader adds on top are trim and the tintable core.
372
+ */
373
+ function flattenStorageBarrel(json) {
374
+ const extended = json;
375
+ const groups = [extended.partitioned_model_parts, extended.model_parts];
376
+ const textures = {};
377
+ const merges = [];
378
+ for (const group of groups) for (const part of Object.values(group ?? {})) {
379
+ Object.assign(textures, part.textures);
380
+ if (typeof part.model === "string") merges.push(part.model);
381
+ }
382
+ const flattened = withoutLoader(json);
383
+ delete flattened.model_parts;
384
+ delete flattened.partitioned_model_parts;
385
+ delete flattened.dynamic_part_models;
386
+ delete flattened.wood_overrides;
387
+ return {
388
+ ...flattened,
389
+ parent: flattened.parent ?? "minecraft:block/block",
390
+ textures: {
391
+ ...flattened.textures,
392
+ ...textures
393
+ },
394
+ ...merges.length > 0 && { mergeModels: merges }
395
+ };
396
+ }
397
+ /**
398
+ * A composite whose parts are named parent references rather than inline
399
+ * geometry — every part is drawn, so they all merge in.
400
+ */
401
+ function mergeCompositeParts(json) {
402
+ const parts = json.parts ?? {};
403
+ const merges = Object.values(parts).map((part) => part.parent).filter((parent) => typeof parent === "string");
404
+ return merges.length === 0 ? withoutLoader(json) : {
405
+ ...withoutLoader(json),
406
+ parts: void 0,
407
+ mergeModels: merges
408
+ };
409
+ }
200
410
  function extractLoaderType(json) {
201
411
  const record = json;
202
412
  if (typeof record.loader === "string") return record.loader;
@@ -286,7 +496,7 @@ var ModelLoader = class {
286
496
  }
287
497
  return flattenLoaderModel(json);
288
498
  }
289
- async resolve(locator) {
499
+ async resolve(locator, overrideDepth = 0) {
290
500
  const chain = [];
291
501
  const seen = /* @__PURE__ */ new Set();
292
502
  let current = locator;
@@ -338,6 +548,22 @@ var ModelLoader = class {
338
548
  break;
339
549
  }
340
550
  }
551
+ for (const entry of chain) {
552
+ const merges = entry.json.mergeModels;
553
+ if (!merges) continue;
554
+ for (const reference of merges) {
555
+ const merged = await this.load(reference).catch(() => null);
556
+ if (!merged) continue;
557
+ elements = [...elements, ...merged.elements.map((element) => bindElementTextures(element, merged, textures))];
558
+ }
559
+ break;
560
+ }
561
+ if (obj === void 0 && elements.length === 0 && Object.keys(textures).length === 0) {
562
+ const overridden = chain.find((entry) => entry.json.overrides?.length)?.json.overrides;
563
+ const chosen = overridden && (overridden.findLast((entry) => Object.values(entry.predicate).every((value) => value <= 0)) ?? overridden[0]);
564
+ const target = chosen ? ResourceLocator.tryParse(chosen.model) : null;
565
+ if (target && overrideDepth < MAX_OVERRIDE_REDIRECTS && target.toString() !== locator.toString()) return this.resolve(target, overrideDepth + 1);
566
+ }
341
567
  const defaultLight = builtinParent === "builtin/generated" ? "front" : "side";
342
568
  return {
343
569
  obj,
@@ -365,6 +591,32 @@ var ModelLoader = class {
365
591
  }
366
592
  };
367
593
  /**
594
+ * Rewrite an element's face textures from the owning model's variables to
595
+ * concrete locators, so the element survives being merged into another model.
596
+ */
597
+ function bindElementTextures(element, model, owner) {
598
+ const rebound = {
599
+ ...model,
600
+ textures: {
601
+ ...model.textures,
602
+ ...owner
603
+ }
604
+ };
605
+ const faces = {};
606
+ for (const [direction, face] of Object.entries(element.faces)) {
607
+ if (!face) continue;
608
+ const bound = resolveTexture(rebound, face.texture) ?? resolveTexture(model, face.texture);
609
+ faces[direction] = bound ? {
610
+ ...face,
611
+ texture: bound.toString()
612
+ } : face;
613
+ }
614
+ return {
615
+ ...element,
616
+ faces
617
+ };
618
+ }
619
+ /**
368
620
  * Resolve a texture variable (`#layer0`) through the merged texture map to a locator.
369
621
  * Returns null for unresolved variables — the caller decides whether that fails the
370
622
  * item or just the face.
@@ -1,3 +1,4 @@
1
+ import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
1
2
  import { t as LruCache } from "./cache-Cr2ON3RQ.js";
2
3
  import sharp from "sharp";
3
4
  //#region src/textures/loader.ts
@@ -21,15 +22,20 @@ var AnimatedTexture = class {
21
22
  constructor(full, meta) {
22
23
  this.full = full;
23
24
  this.meta = meta;
24
- const metaWidth = meta?.animation?.width ?? 16;
25
- const metaHeight = meta?.animation?.height ?? 16;
25
+ if (!meta?.animation) {
26
+ const stacked = full.height > full.width && full.height % full.width === 0;
27
+ this.columns = 1;
28
+ this.frameWidth = full.width;
29
+ this.frameHeight = stacked ? full.width : full.height;
30
+ this.frameCount = 1;
31
+ return;
32
+ }
33
+ const metaWidth = meta.animation.width ?? 16;
34
+ const metaHeight = meta.animation.height ?? 16;
26
35
  this.columns = Math.max(1, Math.trunc(16 / metaWidth));
27
36
  this.frameWidth = Math.round(full.width * (metaWidth / 16));
28
37
  this.frameHeight = Math.round(this.frameWidth * (metaHeight / 16));
29
- const frames = meta?.animation?.frames;
30
- if (!meta?.animation) this.frameCount = 1;
31
- else if (frames?.length) this.frameCount = frames.length;
32
- else this.frameCount = Math.max(1, Math.round(full.height / this.frameHeight * this.columns));
38
+ this.frameCount = meta.animation.frames?.length || Math.max(1, Math.round(full.height / this.frameHeight * this.columns));
33
39
  }
34
40
  get interpolated() {
35
41
  return this.meta?.animation?.interpolate ?? false;
@@ -146,6 +152,7 @@ var TextureLoader = class {
146
152
  if (sprite?.kind === "pixels") return sprite.texture;
147
153
  if (sprite?.kind === "file") raw = await this.resources.getResource("texture", sprite.locator);
148
154
  }
155
+ if (raw === null) raw = await this.resources.getResource("raw", new ResourceLocator(locator.namespace, `${locator.path}.png`));
149
156
  if (raw === null) return null;
150
157
  let image;
151
158
  try {
@@ -190,7 +197,12 @@ var TextureLoader = class {
190
197
  const raw = await this.resources.getResource("texture", locator);
191
198
  let full = null;
192
199
  if (raw !== null) {
193
- const image = await sharp(raw).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
200
+ let image;
201
+ try {
202
+ image = await sharp(raw).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
203
+ } catch (err) {
204
+ throw new TextureResolutionError(`Failed to decode texture ${locator}: ${err.message}`);
205
+ }
194
206
  full = {
195
207
  width: image.info.width,
196
208
  height: image.info.height,
@@ -1,2 +1,2 @@
1
- import { a as resolveTexture, i as flattenLoaderModel, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "../loader-D22zZME7.js";
1
+ import { a as resolveTexture, i as flattenLoaderModel, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "../loader-DD83d80u.js";
2
2
  export { ModelLoader, ModelResolutionError, ResolvedModel, flattenLoaderModel, resolveTexture, salvageJson };
@@ -1,2 +1,2 @@
1
- import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, r as flattenLoaderModel, t as ModelLoader } from "../loader-B8NJO7pR.js";
1
+ import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, r as flattenLoaderModel, t as ModelLoader } from "../loader-DwkA9LR5.js";
2
2
  export { ModelLoader, ModelResolutionError, flattenLoaderModel, resolveTexture, salvageJson };
@@ -1,2 +1,2 @@
1
- import { a as FaceDirectionName, c as ModelJson, i as FaceDirection, l as Vec3, n as DisplayTransformJson, o as ModelElementJson, r as ElementRotationJson, s as ModelFaceJson, t as DisplayPosition, u as Vec4 } from "../types-COGbtA1t.js";
1
+ import { a as FaceDirectionName, c as ModelJson, i as FaceDirection, l as Vec3, n as DisplayTransformJson, o as ModelElementJson, r as ElementRotationJson, s as ModelFaceJson, t as DisplayPosition, u as Vec4 } from "../types-DpRSF9Vj.js";
2
2
  export { DisplayPosition, DisplayTransformJson, ElementRotationJson, FaceDirection, FaceDirectionName, ModelElementJson, ModelFaceJson, ModelJson, Vec3, Vec4 };
@@ -0,0 +1,18 @@
1
+ import { r as modModelPackPath } from "./builtin-WkWjATeh.js";
2
+ import { t as FolderResourceManager } from "./manager-CkletR5K.js";
3
+ //#region src/mods/models.ts
4
+ /**
5
+ * Geometry for mod items the game draws in code. A `builtin/entity` item model
6
+ * carries display transforms and nothing else — the boxes live in a Java class,
7
+ * so no fallback in the chain can find them and the item fails outright.
8
+ *
9
+ * `assets/mod-models/` ports that geometry to ordinary element models, keyed by
10
+ * the model path the mod's own item already resolves to. Hand-authored per item
11
+ * and layered ABOVE the mod jars, so it shadows the `builtin/entity` stub in
12
+ * every era (see assets/mod-models/README.md for per-item provenance).
13
+ */
14
+ function curatedModelOverrides() {
15
+ return new FolderResourceManager(modModelPackPath());
16
+ }
17
+ //#endregion
18
+ export { curatedModelOverrides as t };
@@ -0,0 +1,5 @@
1
+ import { a as ResourceManager } from "../manager-Cv1NeFyF.js";
2
+ //#region src/mods/models.d.ts
3
+ declare function curatedModelOverrides(): ResourceManager;
4
+ //#endregion
5
+ export { curatedModelOverrides };
@@ -0,0 +1,2 @@
1
+ import { t as curatedModelOverrides } from "../models-BKxGkPS7.js";
2
+ export { curatedModelOverrides };
@@ -1,2 +1,2 @@
1
- import { i as prepareModResources, n as ModPreparation, r as PrepareModsOptions, t as LOADER_NAMESPACES } from "../prepare-CPxO0kKz.js";
1
+ import { i as prepareModResources, n as ModPreparation, r as PrepareModsOptions, t as LOADER_NAMESPACES } from "../prepare-Dce7-HAe.js";
2
2
  export { LOADER_NAMESPACES, ModPreparation, PrepareModsOptions, prepareModResources };
@@ -1,2 +1,2 @@
1
- import { n as prepareModResources, t as LOADER_NAMESPACES } from "../prepare-BESRrh6K.js";
1
+ import { n as prepareModResources, t as LOADER_NAMESPACES } from "../prepare-D56Z-9cg.js";
2
2
  export { LOADER_NAMESPACES, prepareModResources };
@@ -1,2 +1,2 @@
1
- import { n as harvestTintOverrides, t as curatedTintOverrides } from "../tints-B8UJmZMu.js";
1
+ import { n as harvestTintOverrides, t as curatedTintOverrides } from "../tints-CebmvjmP.js";
2
2
  export { curatedTintOverrides, harvestTintOverrides };
@@ -1,2 +1,2 @@
1
- import { a as RasterAssetFormat, c as encodeRasterAsset, i as EncodedIcon, n as EncodeOptions, o as encodeAnimatedIcon, r as EncodedAnimatedIcon, s as encodeIcon, t as AnimatedEncodeOptions } from "../encode-CaSK8-mi.js";
1
+ import { a as RasterAssetFormat, c as encodeRasterAsset, i as EncodedIcon, n as EncodeOptions, o as encodeAnimatedIcon, r as EncodedAnimatedIcon, s as encodeIcon, t as AnimatedEncodeOptions } from "../encode-DNcXXvYe.js";
2
2
  export { AnimatedEncodeOptions, EncodeOptions, EncodedAnimatedIcon, EncodedIcon, RasterAssetFormat, encodeAnimatedIcon, encodeIcon, encodeRasterAsset };
@@ -1,2 +1,2 @@
1
- import { n as encodeIcon, r as encodeRasterAsset, t as encodeAnimatedIcon } from "../encode-Df_tWzkl.js";
1
+ import { n as encodeIcon, r as encodeRasterAsset, t as encodeAnimatedIcon } from "../encode-LR9wxigC.js";
2
2
  export { encodeAnimatedIcon, encodeIcon, encodeRasterAsset };
@@ -1,7 +1,7 @@
1
1
  import { a as ResourceManager } from "./manager-Cv1NeFyF.js";
2
- import { t as FloatTexture } from "./blend-CEHoJ7tM.js";
2
+ import { n as FloatTexture } from "./blend-8lnfxtLe.js";
3
3
  import { a as LightingProfileName } from "./lighting-3FGRC3Af.js";
4
- import { n as AnimationLimits } from "./renderer-B20ssjRm.js";
4
+ import { n as AnimationLimits } from "./renderer-C79EQDSn.js";
5
5
  //#region src/render/pipeline.d.ts
6
6
  interface PipelineSettings {
7
7
  builtin?: string;
@@ -40,13 +40,25 @@ declare class ItemPipeline {
40
40
  * pipeline's black-icon audit checked exactly this). A real sprite beats
41
41
  * no icon; the fallback is recorded so it is never a silent substitution.
42
42
  */
43
+ /** Whether the game draws this item from an entity model rather than a sprite. */
44
+ private isEntityDrawn;
43
45
  private spriteFallback;
46
+ /**
47
+ * A blockstate-named block model, drawn the way a block-entity item renderer
48
+ * draws it. The renderer runs inside the *item's* display transform, which the
49
+ * block model does not carry — a block model that never chains to
50
+ * `minecraft:block/block` has no gui transform at all and would otherwise fill
51
+ * the frame flat-on (mekanism:block/fluid_tank).
52
+ */
53
+ private renderStatedBlock;
44
54
  /** Render an item's frames from its own model, without any fallback. */
45
55
  renderFrames(id: string): Promise<RenderedFrames>;
46
56
  /**
47
- * Frames for an item, falling back through the same-name block model,
48
- * GeckoLib geometry, builtin entity geometry, dyed variants, and finally the
49
- * flat sprite. Rethrows the item's own error when nothing draws it.
57
+ * Frames for an item that its own model cannot draw. The first step is not a
58
+ * guess: a BlockItem's blockstate names the model the game's own block-entity
59
+ * item renderers draw, so that is consulted before the same-name heuristic.
60
+ * After it come GeckoLib geometry, builtin entity geometry, dyed variants and
61
+ * finally the flat sprite. Rethrows the item's own error when nothing draws it.
50
62
  */
51
63
  renderFramesWithFallback(id: string): Promise<RenderedFrames & {
52
64
  usedFallback: boolean;