@nodecraft/rendermite 1.1.3 → 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-BPfpBZyZ.js → run-D2S_W5As.js} +10 -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
@@ -0,0 +1,481 @@
1
+ import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
+ import { a as findChestTexture, c as findFluidStill, i as findBedTexture, l as findMobTexture, n as HEAD_LAYOUTS, o as findEntityTexture, r as coversSheet, s as findFluidSibling, t as DYE_COLORS } from "./entity-textures-DFRIVdF1.js";
3
+ //#region src/blocks/block-entities.ts
4
+ /**
5
+ * Geometry for blocks the game draws from Java rather than from a model.
6
+ *
7
+ * A chest's blockstate is `{"variants":{"":{"model":"block/chest"}}}` and that
8
+ * model has no elements: the shape, the facing, and the pairing of a double
9
+ * chest all live in a block entity renderer. Same for beds, banners, shulker
10
+ * boxes, skulls and signs — 137 of vanilla's 1,107 blocks. A world viewer
11
+ * reading only the assets would put a hole where every chest is.
12
+ *
13
+ * rendermite already vendors box geometry for most of these, because the icon
14
+ * pipeline has the same problem and solved it years ago (`src/builtin.ts`,
15
+ * `assets/builtin/`). This maps it onto blocks and synthesises the orientation
16
+ * variants vanilla's blockstate file does not carry — the consumer knows the
17
+ * block's real property map from the chunk, so it can pick.
18
+ *
19
+ * Everything here is a curated approximation, and the pack says so: each
20
+ * substituted block lands in the failures sidecar, and the emitted model is
21
+ * named `rendermite:block/…` so it is never mistaken for something a jar
22
+ * shipped.
23
+ */
24
+ /**
25
+ * Blocks that export empty because the game genuinely draws nothing for them,
26
+ * or draws something no model format can express. Kept apart from the blocks
27
+ * that came out empty by accident, so a consumer can tell a deliberate hole
28
+ * from a gap in this exporter.
29
+ */
30
+ const INVISIBLE_BLOCKS = {
31
+ "minecraft:air": "nothing to draw",
32
+ "minecraft:cave_air": "nothing to draw",
33
+ "minecraft:void_air": "nothing to draw",
34
+ "minecraft:barrier": "only drawn while the player holds one",
35
+ "minecraft:light": "only drawn while the player holds one",
36
+ "minecraft:structure_void": "only drawn inside the structure block UI",
37
+ "minecraft:moving_piston": "a placeholder; the moving block is drawn by the piston",
38
+ "minecraft:end_portal": "a shader effect, not geometry",
39
+ "minecraft:end_gateway": "a shader effect, not geometry"
40
+ };
41
+ /** Clockwise from north, matching how a blockstate's `y` rotates a model. */
42
+ const FACING_DEGREES = {
43
+ north: 0,
44
+ east: 90,
45
+ south: 180,
46
+ west: 270
47
+ };
48
+ /** `facing6` for a shulker box: `up` is the shape as authored. */
49
+ const FACING6_ROTATION = {
50
+ up: {
51
+ x: 0,
52
+ y: 0
53
+ },
54
+ down: {
55
+ x: 180,
56
+ y: 0
57
+ },
58
+ north: {
59
+ x: 270,
60
+ y: 0
61
+ },
62
+ south: {
63
+ x: 90,
64
+ y: 0
65
+ },
66
+ east: {
67
+ x: 90,
68
+ y: 90
69
+ },
70
+ west: {
71
+ x: 90,
72
+ y: 270
73
+ }
74
+ };
75
+ /**
76
+ * The blockstate cases to emit for a substituted block. One per orientation the
77
+ * block can be placed in, so a consumer holding the real property map from the
78
+ * chunk finds the case the game would have used.
79
+ */
80
+ function synthesizeVariants(orient) {
81
+ switch (orient.kind) {
82
+ case "fixed": return [{
83
+ when: {},
84
+ x: 0,
85
+ y: 0
86
+ }];
87
+ case "facing": {
88
+ const authored = FACING_DEGREES[orient.authored];
89
+ return Object.entries(FACING_DEGREES).map(([facing, degrees]) => {
90
+ return {
91
+ when: { facing },
92
+ x: 0,
93
+ y: (degrees - authored + 360) % 360
94
+ };
95
+ });
96
+ }
97
+ case "facing6": return Object.entries(FACING6_ROTATION).map(([facing, rotation]) => {
98
+ return {
99
+ when: { facing },
100
+ x: rotation.x,
101
+ y: rotation.y
102
+ };
103
+ });
104
+ case "rotation16": return Array.from({ length: 16 }, (_, step) => {
105
+ return {
106
+ when: { rotation: String(step) },
107
+ x: 0,
108
+ y: Math.round(step * 22.5)
109
+ };
110
+ });
111
+ }
112
+ }
113
+ const CHEST_VARIANTS = {
114
+ "minecraft:chest": "chest",
115
+ "minecraft:trapped_chest": "trapped_chest",
116
+ "minecraft:ender_chest": "ender_chest",
117
+ "minecraft:copper_chest": "copper_chest",
118
+ "minecraft:exposed_copper_chest": "exposed_copper_chest",
119
+ "minecraft:weathered_copper_chest": "weathered_copper_chest",
120
+ "minecraft:oxidized_copper_chest": "oxidized_copper_chest",
121
+ "minecraft:waxed_copper_chest": "copper_chest",
122
+ "minecraft:waxed_exposed_copper_chest": "exposed_copper_chest",
123
+ "minecraft:waxed_weathered_copper_chest": "weathered_copper_chest",
124
+ "minecraft:waxed_oxidized_copper_chest": "oxidized_copper_chest"
125
+ };
126
+ /** Base entity sheet per chest variant, which the double halves suffix. */
127
+ const CHEST_SHEETS = {
128
+ chest: "minecraft:entity/chest/normal",
129
+ trapped_chest: "minecraft:entity/chest/trapped",
130
+ ender_chest: "minecraft:entity/chest/ender",
131
+ copper_chest: "minecraft:entity/chest/copper",
132
+ exposed_copper_chest: "minecraft:entity/chest/copper_exposed",
133
+ weathered_copper_chest: "minecraft:entity/chest/copper_weathered",
134
+ oxidized_copper_chest: "minecraft:entity/chest/copper_oxidized"
135
+ };
136
+ /** Where a skull's block name does not match the mobheads model's. */
137
+ const SKULL_MOBS = { dragon: "ender_dragon" };
138
+ const FLUID_SPRITES = {
139
+ "minecraft:water": {
140
+ sprite: "minecraft:block/water_still",
141
+ tinted: true
142
+ },
143
+ "minecraft:bubble_column": {
144
+ sprite: "minecraft:block/water_still",
145
+ tinted: true
146
+ },
147
+ "minecraft:lava": {
148
+ sprite: "minecraft:block/lava_still",
149
+ tinted: false
150
+ }
151
+ };
152
+ const SHULKER_COLOURS = new Set(Object.keys(DYE_COLORS));
153
+ /**
154
+ * The vendored chest is authored with its latch on the south face, so a
155
+ * `facing=south` chest needs no rotation. Verified by rendering, not by
156
+ * reading the model.
157
+ */
158
+ const CHEST_AUTHORED = {
159
+ kind: "facing",
160
+ authored: "south"
161
+ };
162
+ /**
163
+ * Two chests placed side by side become one double chest: each keeps its own
164
+ * block but takes a `type` of `left` or `right`, and the game swaps in a wider
165
+ * box on a wider sheet so the pair reads as a single container with one lock on
166
+ * the seam. Drawing two singles instead leaves a visible join and two lids.
167
+ *
168
+ * The halves are only offered where the sheets exist — an ender chest never
169
+ * doubles and ships none — and the exporter drops a shape it cannot bind.
170
+ */
171
+ async function chestGeometry(blockId, context) {
172
+ const [namespace, name] = blockId.split(":", 2);
173
+ const variant = CHEST_VARIANTS[blockId];
174
+ const searchable = /chest|crate/.test(name) && !name.includes("chestplate");
175
+ const found = variant === void 0 && searchable ? await findChestTexture(context.resources, namespace, name) : null;
176
+ const sheet = variant === void 0 ? found?.toString() : CHEST_SHEETS[variant];
177
+ if (sheet === void 0) return null;
178
+ const single = variant === void 0 ? {
179
+ model: "renderchest:item/chest",
180
+ textures: { texture: sheet }
181
+ } : { model: `renderchest:item/chest/${variant}` };
182
+ const [left, right] = await Promise.all([halfSheet(sheet, "left", context), halfSheet(sheet, "right", context)]);
183
+ if (left === null || right === null) return {
184
+ shapes: [single],
185
+ orient: CHEST_AUTHORED
186
+ };
187
+ return {
188
+ shapes: [
189
+ {
190
+ ...single,
191
+ when: { type: "single" }
192
+ },
193
+ {
194
+ model: "renderchest:block/chest_left",
195
+ when: { type: "left" },
196
+ textures: { texture: left }
197
+ },
198
+ {
199
+ model: "renderchest:block/chest_right",
200
+ when: { type: "right" },
201
+ textures: { texture: right }
202
+ }
203
+ ],
204
+ orient: CHEST_AUTHORED
205
+ };
206
+ }
207
+ /**
208
+ * The wider sheet for one half of a double chest. Vanilla suffixes the base
209
+ * name (`normal` → `normal_left`); quark files the halves beside it instead
210
+ * (`acacia/normal` → `acacia/left`). Both are common enough to try.
211
+ */
212
+ async function halfSheet(sheet, side, context) {
213
+ const base = ResourceLocator.parse(sheet);
214
+ const sibling = base.path.includes("/") ? `${base.path.slice(0, base.path.lastIndexOf("/"))}/${side}` : side;
215
+ for (const path of [`${base.path}_${side}`, sibling]) {
216
+ const candidate = new ResourceLocator(base.namespace, path);
217
+ if (await context.resources.hasResource("texture", candidate)) return candidate.toString();
218
+ }
219
+ return null;
220
+ }
221
+ /**
222
+ * A banner's colour is a tint over one greyscale sheet, not 16 textures, so the
223
+ * two forms share a model each and the tint table carries the dye.
224
+ */
225
+ async function bannerGeometry(blockId, context) {
226
+ const [namespace, name] = blockId.split(":", 2);
227
+ const wall = name.endsWith("_wall_banner");
228
+ if (!wall && !name.endsWith("_banner")) return null;
229
+ const own = new ResourceLocator(namespace, "entity/banner/base");
230
+ const texture = namespace !== "minecraft" && await context.resources.hasResource("texture", own) ? own.toString() : "minecraft:entity/banner/base";
231
+ return {
232
+ shapes: [{ model: `renderchest:block/banner_${wall ? "wall" : "standing"}` }],
233
+ textures: { texture },
234
+ orient: wall ? {
235
+ kind: "facing",
236
+ authored: "south"
237
+ } : { kind: "rotation16" }
238
+ };
239
+ }
240
+ /**
241
+ * The vendored heads were authored against current vanilla, which files an
242
+ * entity sheet under its own mob folder (`entity/bat/bat`). Older versions keep
243
+ * them flat (`entity/bat`), so a binding that does not resolve is looked up
244
+ * again by name rather than left to export as magenta. The variable it is bound
245
+ * to is whatever the model called it, which is why the map is read rather than
246
+ * a name assumed.
247
+ */
248
+ async function rebindMissingSheets(bindings, context, mob) {
249
+ const fixes = {};
250
+ for (const [name, value] of Object.entries(bindings)) {
251
+ const locator = ResourceLocator.tryParse(value);
252
+ if (locator === null || await context.resources.hasResource("texture", locator)) continue;
253
+ const leaf = locator.path.split("/").pop() ?? "";
254
+ const found = await findMobTexture(context.resources, locator.namespace, leaf) ?? await findMobTexture(context.resources, locator.namespace, mob);
255
+ if (found !== null) fixes[name] = found.toString();
256
+ }
257
+ return Object.keys(fixes).length > 0 ? fixes : void 0;
258
+ }
259
+ /**
260
+ * Skulls reuse the mobheads geometry the icon pipeline already vendors, which
261
+ * is centred in the block for an item's hand. A block wants it on the floor or
262
+ * against a wall, which is a translation rather than 90 more models.
263
+ */
264
+ async function skullGeometry(blockId, context) {
265
+ const [namespace, name] = blockId.split(":", 2);
266
+ const match = /^(.+?)_(?:wall_)?(?:skull|head)$/.exec(name);
267
+ if (match === null) return null;
268
+ const mob = SKULL_MOBS[match[1]] ?? match[1];
269
+ const wall = name.includes("_wall_");
270
+ const place = (model, textures) => {
271
+ return {
272
+ shapes: [{
273
+ model,
274
+ textures,
275
+ translate: wall ? [
276
+ 0,
277
+ 0,
278
+ 4
279
+ ] : [
280
+ 0,
281
+ -4,
282
+ 0
283
+ ]
284
+ }],
285
+ orient: wall ? {
286
+ kind: "facing",
287
+ authored: "north"
288
+ } : { kind: "rotation16" }
289
+ };
290
+ };
291
+ const parts = mob.split("_");
292
+ for (let keep = parts.length; keep >= 1 && keep >= parts.length - 2; keep--) {
293
+ const model = `mobheads:item/${parts.slice(0, keep).join("_")}`;
294
+ const resolved = await context.models.load(model).catch(() => null);
295
+ if (resolved !== null) return place(model, await rebindMissingSheets(resolved.textures, context, mob));
296
+ }
297
+ const sheet = await findMobTexture(context.resources, namespace, mob);
298
+ const skin = sheet === null ? null : await context.textures.load(sheet).catch(() => null);
299
+ const base = skin === null ? void 0 : HEAD_LAYOUTS[`${skin.width}x${skin.height}`];
300
+ return sheet !== null && base !== void 0 ? place(`mobheads:item/base/${base}`, { texture: sheet.toString() }) : null;
301
+ }
302
+ /**
303
+ * 26.2's copper golem statue, which the game draws entirely from Java: an empty
304
+ * variant on a model with only a particle texture, and no entity geometry data
305
+ * in the jar either. `renderchest:block/copper_golem_statue` was authored from
306
+ * the sheet's own unwrap for it.
307
+ *
308
+ * `copper_golem_pose` picks between standing, sitting, running and star, which
309
+ * differ by limb rotations nothing in the assets records. Keying only on
310
+ * `facing` means every pose draws the standing statue rather than a hole.
311
+ */
312
+ async function copperGolemGeometry(blockId, context) {
313
+ const name = blockId.split(":", 2)[1];
314
+ const match = /^(?:waxed_)?(exposed_|weathered_|oxidized_)?copper_golem_statue$/.exec(name);
315
+ if (match === null) return null;
316
+ const stage = match[1] === void 0 ? "" : `_${match[1].slice(0, -1)}`;
317
+ const sheet = new ResourceLocator("minecraft", `entity/copper_golem/copper_golem${stage}`);
318
+ if (!await context.resources.hasResource("texture", sheet)) return null;
319
+ return {
320
+ shapes: [{ model: "renderchest:block/copper_golem_statue" }],
321
+ textures: {
322
+ texture: sheet.toString(),
323
+ eyes: `minecraft:entity/copper_golem/copper_golem_eyes${stage}`
324
+ },
325
+ orient: {
326
+ kind: "facing",
327
+ authored: "north"
328
+ }
329
+ };
330
+ }
331
+ /**
332
+ * A fluid's surface height and flow direction come from its neighbours, which
333
+ * no pack can carry, so the block is a plain culled cube: right wherever the
334
+ * fluid is enclosed, two pixels tall at an open surface. The still and flow
335
+ * sprites are in the atlas for a consumer that meshes fluids properly.
336
+ */
337
+ async function fluidGeometry(blockId, context) {
338
+ const [namespace, name] = blockId.split(":", 2);
339
+ const known = FLUID_SPRITES[blockId];
340
+ const found = known === void 0 ? await findFluidStill(context.resources, namespace, name) : null;
341
+ const still = known === void 0 ? found : ResourceLocator.parse(known.sprite);
342
+ if (still === null) return null;
343
+ const flow = await findFluidSibling(context.resources, still, ["_flow", "_flowing"]);
344
+ const overlay = await findFluidSibling(context.resources, still, ["_overlay"]);
345
+ return {
346
+ shapes: [{ model: `renderchest:block/fluid${known?.tinted ? "_tinted" : ""}` }],
347
+ textures: {
348
+ still: still.toString(),
349
+ flow: (flow ?? still).toString()
350
+ },
351
+ orient: { kind: "fixed" },
352
+ fluid: overlay === null ? {} : { overlay: overlay.toString() }
353
+ };
354
+ }
355
+ async function shulkerGeometry(blockId, context) {
356
+ const [namespace, name] = blockId.split(":", 2);
357
+ if (!name.includes("shulker") || name.includes("shell")) return null;
358
+ if (name === "shulker_box") return {
359
+ shapes: [{ model: "renderchest:item/shulker_box" }],
360
+ textures: { texture: "minecraft:entity/shulker/shulker" },
361
+ orient: { kind: "facing6" }
362
+ };
363
+ const colour = name.endsWith("_shulker_box") ? name.slice(0, -12) : null;
364
+ if (colour !== null && SHULKER_COLOURS.has(colour) && namespace === "minecraft") return {
365
+ shapes: [{ model: `renderchest:item/shulker_box/${name}` }],
366
+ orient: { kind: "facing6" }
367
+ };
368
+ const candidate = await findEntityTexture(context.resources, namespace, name, "shulker");
369
+ return {
370
+ shapes: [{
371
+ model: "renderchest:item/shulker_box",
372
+ textures: { texture: candidate !== null && await coversSheet(context.textures, candidate) ? candidate.toString() : "minecraft:entity/shulker/shulker" }
373
+ }],
374
+ orient: { kind: "facing6" }
375
+ };
376
+ }
377
+ /**
378
+ * Signs are the largest family the game draws in code — 48 blocks in vanilla —
379
+ * and nothing was vendored for them, so `block/standing_sign` and
380
+ * `block/wall_sign` were authored against the entity sheet's own box unwrap.
381
+ *
382
+ * The wood is read off the block name rather than listed, so a mod that follows
383
+ * the same convention gets its signs for free; the exporter only substitutes
384
+ * once it has checked the texture is really there.
385
+ */
386
+ async function signGeometry(blockId, context) {
387
+ const [namespace, name] = blockId.split(":", 2);
388
+ if (name !== "sign" && !name.endsWith("_sign")) return null;
389
+ let wood = name === "sign" ? "" : name.slice(0, -5);
390
+ const peel = (token) => {
391
+ if (wood !== token && !wood.endsWith(`_${token}`)) return false;
392
+ wood = wood.slice(0, Math.max(0, wood.length - token.length - 1));
393
+ return true;
394
+ };
395
+ const hanging = peel("hanging");
396
+ const wall = peel("wall");
397
+ const model = hanging ? "hanging_sign" : wall ? "wall_sign" : "standing_sign";
398
+ const conventional = new ResourceLocator(namespace, wood.length === 0 ? "entity/sign" : `entity/signs/${hanging ? "hanging/" : ""}${wood}`);
399
+ const found = await context.resources.hasResource("texture", conventional) ? conventional : await findEntityTexture(context.resources, namespace, `${wood}_${hanging ? "hanging_" : ""}sign`, "sign");
400
+ if (found === null) return null;
401
+ return {
402
+ shapes: [{ model: `renderchest:block/${model}` }],
403
+ textures: { texture: found.toString() },
404
+ orient: wall ? {
405
+ kind: "facing",
406
+ authored: "north"
407
+ } : { kind: "rotation16" }
408
+ };
409
+ }
410
+ /** Every dye a bed comes in; the sheet is named for it. */
411
+ const BED_COLOURS = SHULKER_COLOURS;
412
+ /**
413
+ * A bed is two blocks with a model each, and `BedRenderer` draws both halves
414
+ * from one entity model spanning them. `part` picks the half and `facing`
415
+ * orients it, so the two multiply into eight cases.
416
+ */
417
+ async function bedGeometry(blockId, context) {
418
+ const [namespace, name] = blockId.split(":", 2);
419
+ if (name !== "bed" && !name.endsWith("_bed")) return null;
420
+ const colour = name === "bed" ? "" : name.slice(0, -4);
421
+ const conventional = new ResourceLocator(namespace, `entity/bed/${colour}`);
422
+ const found = BED_COLOURS.has(colour) && await context.resources.hasResource("texture", conventional) ? conventional : await findBedTexture(context.resources, namespace, name);
423
+ if (found === null) return null;
424
+ return {
425
+ shapes: [{
426
+ when: { part: "head" },
427
+ model: "renderchest:block/bed_head"
428
+ }, {
429
+ when: { part: "foot" },
430
+ model: "renderchest:block/bed_foot"
431
+ }],
432
+ textures: { texture: found.toString() },
433
+ orient: {
434
+ kind: "facing",
435
+ authored: "north"
436
+ }
437
+ };
438
+ }
439
+ /** Blocks with one shape and nothing to orient by. */
440
+ const FIXED = {
441
+ "minecraft:conduit": {
442
+ shapes: [{ model: "renderchest:item/conduit" }],
443
+ orient: { kind: "fixed" }
444
+ },
445
+ "minecraft:decorated_pot": {
446
+ shapes: [{ model: "renderchest:item/decorated_pot" }],
447
+ textures: {
448
+ base: "minecraft:entity/decorated_pot/decorated_pot_base",
449
+ north: "minecraft:entity/decorated_pot/decorated_pot_side",
450
+ south: "minecraft:entity/decorated_pot/decorated_pot_side",
451
+ west: "minecraft:entity/decorated_pot/decorated_pot_side",
452
+ east: "minecraft:entity/decorated_pot/decorated_pot_side"
453
+ },
454
+ orient: { kind: "fixed" }
455
+ }
456
+ };
457
+ /**
458
+ * The vendored geometry for a block the game draws in code, or null when there
459
+ * is none and the block stays empty.
460
+ */
461
+ async function blockEntityGeometry(blockId, context) {
462
+ const fixed = FIXED[blockId];
463
+ if (fixed !== void 0) return fixed;
464
+ const families = [
465
+ chestGeometry,
466
+ shulkerGeometry,
467
+ signGeometry,
468
+ bedGeometry,
469
+ bannerGeometry,
470
+ copperGolemGeometry,
471
+ skullGeometry,
472
+ fluidGeometry
473
+ ];
474
+ for (const family of families) {
475
+ const geometry = await family(blockId, context);
476
+ if (geometry !== null) return geometry;
477
+ }
478
+ return null;
479
+ }
480
+ //#endregion
481
+ export { blockEntityGeometry as n, synthesizeVariants as r, INVISIBLE_BLOCKS as t };
@@ -0,0 +1,2 @@
1
+ import { a as PackedRect, i as PackedPage, n as PackOptions, o as packAtlas, r as PackedAtlas, t as PackEntry } from "../atlas-pack-DRTrWcSU.js";
2
+ export { PackEntry, PackOptions, PackedAtlas, PackedPage, PackedRect, packAtlas };
@@ -0,0 +1,2 @@
1
+ import { t as packAtlas } from "../atlas-pack-CoOih7By.js";
2
+ export { packAtlas };
@@ -0,0 +1,93 @@
1
+ import { a as ResourceManager } from "../manager-Cv1NeFyF.js";
2
+ import { i as TextureLoader } from "../loader-Myy22TDL.js";
3
+ import { t as ModelLoader } from "../loader-C_1_amsq.js";
4
+ //#region src/blocks/block-entities.d.ts
5
+ /**
6
+ * What the table is allowed to look at. The vanilla families are a lookup, but
7
+ * a mod's chest or mob head is only findable by searching its own assets, so
8
+ * the table needs the pack in hand rather than just the block's name.
9
+ */
10
+ interface GeometryContext {
11
+ resources: ResourceManager;
12
+ textures: TextureLoader;
13
+ models: ModelLoader;
14
+ }
15
+ /** How a block's own properties turn into a rotation of the vendored model. */
16
+ type Orientation =
17
+ /** One shape, no property to read. */
18
+ {
19
+ kind: 'fixed';
20
+ } |
21
+ /**
22
+ * `facing` around the vertical axis. `authored` is the direction the
23
+ * vendored model already points, so the rest are offsets from it.
24
+ */
25
+ {
26
+ kind: 'facing';
27
+ authored: 'north' | 'south' | 'east' | 'west';
28
+ } |
29
+ /** `facing` in all six directions, as a shulker box has. */
30
+ {
31
+ kind: 'facing6';
32
+ } |
33
+ /** `rotation` 0–15 in 22.5 degree steps, as a standing banner or skull has. */
34
+ {
35
+ kind: 'rotation16';
36
+ };
37
+ interface BlockEntityShape {
38
+ /** Vendored model drawn in place of the empty one. */
39
+ model: string;
40
+ /**
41
+ * A further property split, multiplied with the orientation. A bed is two
42
+ * blocks with a model each, told apart by `part`.
43
+ */
44
+ when?: Record<string, string>;
45
+ /** Bindings for this shape alone, merged over the geometry's own. */
46
+ textures?: Record<string, string>;
47
+ /**
48
+ * Offset applied to the model's elements, in model units. Lets a skull reuse
49
+ * the mobheads geometry, which is centred for an item's hand rather than
50
+ * sat on the floor or hung on a wall.
51
+ */
52
+ translate?: [number, number, number];
53
+ }
54
+ interface BlockEntityGeometry {
55
+ /** Usually one; more where a property picks between shapes. */
56
+ shapes: BlockEntityShape[];
57
+ /** Texture variables to bind where the vendored model leaves them open. */
58
+ textures?: Record<string, string>;
59
+ orient: Orientation;
60
+ /**
61
+ * Marks the substitute as a stand-in for a fluid, whose real surface the
62
+ * consumer has to mesh from neighbours. The emitted model says so, and names
63
+ * the sheets to mesh it with.
64
+ */
65
+ fluid?: {
66
+ overlay?: string;
67
+ };
68
+ }
69
+ /**
70
+ * Blocks that export empty because the game genuinely draws nothing for them,
71
+ * or draws something no model format can express. Kept apart from the blocks
72
+ * that came out empty by accident, so a consumer can tell a deliberate hole
73
+ * from a gap in this exporter.
74
+ */
75
+ declare const INVISIBLE_BLOCKS: Record<string, string>;
76
+ interface SynthesizedVariant {
77
+ when: Record<string, string>;
78
+ x: number;
79
+ y: number;
80
+ }
81
+ /**
82
+ * The blockstate cases to emit for a substituted block. One per orientation the
83
+ * block can be placed in, so a consumer holding the real property map from the
84
+ * chunk finds the case the game would have used.
85
+ */
86
+ declare function synthesizeVariants(orient: Orientation): SynthesizedVariant[];
87
+ /**
88
+ * The vendored geometry for a block the game draws in code, or null when there
89
+ * is none and the block stays empty.
90
+ */
91
+ declare function blockEntityGeometry(blockId: string, context: GeometryContext): Promise<BlockEntityGeometry | null>;
92
+ //#endregion
93
+ export { BlockEntityGeometry, BlockEntityShape, GeometryContext, INVISIBLE_BLOCKS, Orientation, SynthesizedVariant, blockEntityGeometry, synthesizeVariants };
@@ -0,0 +1,2 @@
1
+ import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "../block-entities-BbS1kv0m.js";
2
+ export { INVISIBLE_BLOCKS, blockEntityGeometry, synthesizeVariants };
@@ -0,0 +1,2 @@
1
+ import { a as BlockStateMultipartCase, c as ParseBlockStateOptions, d as matchesCondition, f as parseBlockState, i as BlockStateError, l as collectModels, n as BlockProperties, o as BlockStateVariantCase, p as weightedVariantIndex, r as BlockStateDefinition, s as MultipartCondition, t as BlockModelVariant, u as evaluateBlockState } from "../blockstate-eval-DDArZs1P.js";
2
+ export { BlockModelVariant, BlockProperties, BlockStateDefinition, BlockStateError, BlockStateMultipartCase, BlockStateVariantCase, MultipartCondition, ParseBlockStateOptions, collectModels, evaluateBlockState, matchesCondition, parseBlockState, weightedVariantIndex };
@@ -0,0 +1,2 @@
1
+ import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "../blockstate-eval-Ckjlyxn4.js";
2
+ export { BlockStateError, collectModels, evaluateBlockState, matchesCondition, parseBlockState, weightedVariantIndex };
@@ -0,0 +1,9 @@
1
+ //#region src/blocks/cli.d.ts
2
+ /**
3
+ * `rendermite blocks` — the block pack export, mirroring the icon CLI's input
4
+ * handling (download a version's jar, or read asset folders, plus mod jars) but
5
+ * emitting geometry and an atlas instead of icons.
6
+ */
7
+ declare function runBlocksCli(argv: string[]): Promise<number>;
8
+ //#endregion
9
+ export { runBlocksCli };
@@ -0,0 +1,2 @@
1
+ import { t as runBlocksCli } from "../cli-D7_oUuPT.js";
2
+ export { runBlocksCli };
@@ -0,0 +1,2 @@
1
+ import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "../export-BIpqNU3H.js";
2
+ export { BlockPackFailure, BlockPackResult, ExportBlockPackOptions, exportBlockPack };
@@ -0,0 +1,2 @@
1
+ import { t as exportBlockPack } from "../export-DxREy3qA.js";
2
+ export { exportBlockPack };
@@ -0,0 +1,2 @@
1
+ import { i as buildObjMesh, n as ObjMesh, r as ObjMeshError, t as MeshGroup } from "../obj-mesh-C6Sp4Ysc.js";
2
+ export { MeshGroup, ObjMesh, ObjMeshError, buildObjMesh };
@@ -0,0 +1,2 @@
1
+ import { n as buildObjMesh, t as ObjMeshError } from "../obj-mesh-CiHiqrlm.js";
2
+ export { ObjMeshError, buildObjMesh };
@@ -0,0 +1,2 @@
1
+ import { i as buildBlockTints, n as BlockTintPack, r as BuiltBlockTints, t as BlockTint } from "../tints-2k3ZhkY3.js";
2
+ export { BlockTint, BlockTintPack, BuiltBlockTints, buildBlockTints };
@@ -0,0 +1,2 @@
1
+ import { t as buildBlockTints } from "../tints-a9FWZLma.js";
2
+ export { buildBlockTints };
@@ -1,4 +1,4 @@
1
- import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
1
+ import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
2
  import { _ as translation, d as rotationY, s as multiply, u as rotationX } from "./vector-CCxLae_T.js";
3
3
  //#region src/items/blockstate.ts
4
4
  /**