@nodecraft/rendermite 1.0.7 → 1.1.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 (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-Da2Kavba.js → pipeline-BVYj7OP0.js} +72 -19
  125. package/dist/{pipeline-HiA3DC71.d.ts → pipeline-CJNiQG-1.d.ts} +15 -5
  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-C6AP3Bn8.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,18 +1,19 @@
1
- import { a as defaultProperties } from "./definition-3MBm8ar_.js";
2
1
  import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
3
2
  import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-CkletR5K.js";
4
- import { r as resolveItem } from "./discovery-0SM0cTLw.js";
5
- import { s as toFloatTexture, t as blendPixel } from "./blend-D0XWgVQr.js";
6
- import { t as encodeAnimatedIcon } from "./encode-Df_tWzkl.js";
3
+ import { a as defaultProperties } from "./definition-ColsvWrH.js";
4
+ import { r as resolveItem } from "./discovery-B9aqV_Rz.js";
5
+ import { l as toFloatTexture, t as blendPixel } from "./blend-KXMclcHk.js";
6
+ import { t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
7
7
  import { a as builtinDynamicResources } from "./generators-BlG4KmtP.js";
8
- import { t as ModelLoader } from "./loader-B8NJO7pR.js";
9
- import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize } from "./renderer-gQW_I7YG.js";
10
- import { n as renderEntityFallback, r as spawnEggTints, t as renderDyedVariantFallback } from "./entity-fallback-D9QTGU9X.js";
11
- import { i as renderGeo, t as findGeoForItem } from "./geo-DHiWBa-C.js";
8
+ import { t as ModelLoader } from "./loader-DwkA9LR5.js";
9
+ import { a as renderModelFrames, i as renderModel, n as boxDownscale, r as pointResize } from "./renderer-oi1MSF3Y.js";
10
+ import { a as spawnEggTints, i as renderEntityFallback, n as dyedVariantTint, r as renderDyedVariantFallback, t as dyeVariantName } from "./entity-fallback-BnFMSHS6.js";
11
+ import { i as renderGeo, t as findGeoForItem } from "./geo-w9HHIrb5.js";
12
12
  import { t as legacyTintsForChain } from "./legacy-tints-B09J0Rxh.js";
13
- import { a as resolveTints } from "./tints-BtbHegpI.js";
14
- import { t as loadAtlasResolver } from "./registry-B9TcjVbs.js";
15
- import { n as TextureLoader } from "./loader-CfXMxcEV.js";
13
+ import { a as resolveTints } from "./tints-3VI_2SNy.js";
14
+ import { t as loadAtlasResolver } from "./registry-DS5PZ57l.js";
15
+ import { n as defaultBlockStateModel, t as blockStateTransform } from "./blockstate-CdstnW2-.js";
16
+ import { n as TextureLoader } from "./loader-Lb0ZeILz.js";
16
17
  import path from "node:path";
17
18
  import { mkdir, writeFile } from "node:fs/promises";
18
19
  //#region src/render/pipeline.ts
@@ -58,15 +59,54 @@ var ItemPipeline = class ItemPipeline {
58
59
  async spriteFallback(id) {
59
60
  const { size, quality } = this.settings;
60
61
  const locator = ResourceLocator.parse(id);
62
+ const draw = (texture) => {
63
+ const upscaled = pointResize(toFloatTexture(texture), size * quality, size * quality);
64
+ return quality === 1 ? upscaled : boxDownscale(upscaled, quality);
65
+ };
61
66
  for (const directory of ["item", "items"]) {
62
67
  const texture = await this.textures.load(new ResourceLocator(locator.namespace, `${directory}/${locator.path}`));
63
- if (texture) {
64
- const upscaled = pointResize(toFloatTexture(texture), size * quality, size * quality);
65
- return quality === 1 ? upscaled : boxDownscale(upscaled, quality);
68
+ if (texture) return draw(texture);
69
+ }
70
+ const leaf = locator.path.split("/").pop();
71
+ const candidates = await this.resources.listResources("texture", locator.namespace);
72
+ for (const prefix of [/^items?\//, /^blocks?\//]) {
73
+ let best = null;
74
+ for (const candidate of candidates) {
75
+ if (!prefix.test(candidate.path) || candidate.path.split("/").pop() !== leaf) continue;
76
+ if (best === null || candidate.path.length < best.path.length) best = candidate;
66
77
  }
78
+ const nested = best ? await this.textures.load(best) : null;
79
+ if (nested) return draw(nested);
67
80
  }
68
81
  return null;
69
82
  }
83
+ /**
84
+ * A blockstate-named block model, drawn the way a block-entity item renderer
85
+ * draws it. The renderer runs inside the *item's* display transform, which the
86
+ * block model does not carry — a block model that never chains to
87
+ * `minecraft:block/block` has no gui transform at all and would otherwise fill
88
+ * the frame flat-on (mekanism:block/fluid_tank).
89
+ */
90
+ async renderStatedBlock(stated, id) {
91
+ const { size, quality, lightingProfile } = this.settings;
92
+ const { resources, models, textures } = this;
93
+ const blockModel = await models.load(stated.model);
94
+ const itemDisplay = await resolveItem(resources, id, defaultProperties()).then(async ([instruction]) => {
95
+ if (!instruction) return null;
96
+ return (await models.load(instruction.model)).display;
97
+ }).catch(() => null);
98
+ const model = itemDisplay?.gui ? {
99
+ ...blockModel,
100
+ display: itemDisplay
101
+ } : blockModel;
102
+ return renderModel(model, textures, {
103
+ size,
104
+ quality,
105
+ lightingProfile,
106
+ resources,
107
+ itemTransform: blockStateTransform(stated)
108
+ });
109
+ }
70
110
  /** Render an item's frames from its own model, without any fallback. */
71
111
  async renderFrames(id) {
72
112
  const { size, quality, lightingProfile, animation } = this.settings;
@@ -75,9 +115,18 @@ var ItemPipeline = class ItemPipeline {
75
115
  let frames;
76
116
  let delaysMs;
77
117
  if (instructions.length === 1) {
78
- const model = await models.load(instructions[0].model);
118
+ const loaded = await models.load(instructions[0].model);
119
+ const model = instructions[0].fluid ? {
120
+ ...loaded,
121
+ fluid: instructions[0].fluid
122
+ } : loaded;
79
123
  let tints = instructions[0].tints.length > 0 ? await resolveTints(instructions[0].tints, { textures }) : await legacyTintsForChain(model.chain, textures);
80
124
  if (!tints && model.chain.some((entry) => entry.endsWith("item/template_spawn_egg"))) tints = await spawnEggTints(id, resources, textures).catch(() => null);
125
+ if (!tints) {
126
+ const dye = dyeVariantName(id);
127
+ const dyed = dye !== null && Object.values(model.textures).some((texture) => texture.includes(dye)) ? null : dyedVariantTint(id);
128
+ tints = dyed === null ? null : [dyed];
129
+ }
81
130
  tints ??= [];
82
131
  const result = await renderModelFrames(model, textures, {
83
132
  size,
@@ -118,9 +167,11 @@ var ItemPipeline = class ItemPipeline {
118
167
  };
119
168
  }
120
169
  /**
121
- * Frames for an item, falling back through the same-name block model,
122
- * GeckoLib geometry, builtin entity geometry, dyed variants, and finally the
123
- * flat sprite. Rethrows the item's own error when nothing draws it.
170
+ * Frames for an item that its own model cannot draw. The first step is not a
171
+ * guess: a BlockItem's blockstate names the model the game's own block-entity
172
+ * item renderers draw, so that is consulted before the same-name heuristic.
173
+ * After it come GeckoLib geometry, builtin entity geometry, dyed variants and
174
+ * finally the flat sprite. Rethrows the item's own error when nothing draws it.
124
175
  */
125
176
  async renderFramesWithFallback(id) {
126
177
  try {
@@ -131,8 +182,10 @@ var ItemPipeline = class ItemPipeline {
131
182
  } catch (err) {
132
183
  const { size, quality, lightingProfile, builtin } = this.settings;
133
184
  const { resources, models, textures } = this;
185
+ const stated = await defaultBlockStateModel(resources, id).catch(() => null);
186
+ const statedRender = stated ? await this.renderStatedBlock(stated, id).catch(() => null) : null;
134
187
  const blockLocator = ResourceLocator.parse(id);
135
- const blockRender = await models.load(new ResourceLocator(blockLocator.namespace, `block/${blockLocator.path}`)).then((model) => renderModel(model, textures, {
188
+ const blockRender = statedRender ?? await models.load(new ResourceLocator(blockLocator.namespace, `block/${blockLocator.path}`)).then((model) => renderModel(model, textures, {
136
189
  size,
137
190
  quality,
138
191
  lightingProfile,
@@ -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;
@@ -41,12 +41,22 @@ declare class ItemPipeline {
41
41
  * no icon; the fallback is recorded so it is never a silent substitution.
42
42
  */
43
43
  private spriteFallback;
44
+ /**
45
+ * A blockstate-named block model, drawn the way a block-entity item renderer
46
+ * draws it. The renderer runs inside the *item's* display transform, which the
47
+ * block model does not carry — a block model that never chains to
48
+ * `minecraft:block/block` has no gui transform at all and would otherwise fill
49
+ * the frame flat-on (mekanism:block/fluid_tank).
50
+ */
51
+ private renderStatedBlock;
44
52
  /** Render an item's frames from its own model, without any fallback. */
45
53
  renderFrames(id: string): Promise<RenderedFrames>;
46
54
  /**
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.
55
+ * Frames for an item that its own model cannot draw. The first step is not a
56
+ * guess: a BlockItem's blockstate names the model the game's own block-entity
57
+ * item renderers draw, so that is consulted before the same-name heuristic.
58
+ * After it come GeckoLib geometry, builtin entity geometry, dyed variants and
59
+ * finally the flat sprite. Rethrows the item's own error when nothing draws it.
50
60
  */
51
61
  renderFramesWithFallback(id: string): Promise<RenderedFrames & {
52
62
  usedFallback: boolean;