@nodecraft/rendermite 1.4.1 → 1.6.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 (94) hide show
  1. package/README.md +3 -0
  2. package/dist/blocks/cli.js +1 -1
  3. package/dist/blocks/entities.d.ts +30 -0
  4. package/dist/blocks/entities.js +2 -0
  5. package/dist/blocks/entity-geo.d.ts +18 -0
  6. package/dist/blocks/entity-geo.js +2 -0
  7. package/dist/blocks/entity-models.d.ts +2 -0
  8. package/dist/blocks/entity-models.js +2 -0
  9. package/dist/blocks/export.d.ts +1 -1
  10. package/dist/blocks/export.js +1 -1
  11. package/dist/blocks/item-sprites.d.ts +34 -0
  12. package/dist/blocks/item-sprites.js +2 -0
  13. package/dist/blocks/obj-mesh.js +1 -1
  14. package/dist/blocks/pack-format.d.ts +2 -2
  15. package/dist/blocks/sprite-sheet.d.ts +59 -0
  16. package/dist/blocks/sprite-sheet.js +2 -0
  17. package/dist/classfile-BwaQjnUM.d.ts +51 -0
  18. package/dist/classfile-CAhS5qNf.js +255 -0
  19. package/dist/{cli-DqJtT-Ms.js → cli-BSKnXBPr.js} +31 -4
  20. package/dist/cli.js +5 -5
  21. package/dist/{discovery-CsZu08re.js → discovery-CD0QqxSF.js} +1 -1
  22. package/dist/{discovery-C5ZR4aoG.d.ts → discovery-Cmir3QfC.d.ts} +8 -1
  23. package/dist/entities/classfile.d.ts +2 -0
  24. package/dist/entities/classfile.js +2 -0
  25. package/dist/entities/geo-model.d.ts +13 -0
  26. package/dist/entities/geo-model.js +2 -0
  27. package/dist/entities/inherit.d.ts +29 -0
  28. package/dist/entities/inherit.js +2 -0
  29. package/dist/entities/jar-classes.d.ts +26 -0
  30. package/dist/entities/jar-classes.js +2 -0
  31. package/dist/entities/link.d.ts +71 -0
  32. package/dist/entities/link.js +2 -0
  33. package/dist/entities/mappings.d.ts +2 -0
  34. package/dist/entities/mappings.js +2 -0
  35. package/dist/entities/merge.d.ts +18 -0
  36. package/dist/entities/merge.js +2 -0
  37. package/dist/entities/model-bytecode.d.ts +31 -0
  38. package/dist/entities/model-bytecode.js +2 -0
  39. package/dist/entities/model-code.d.ts +2 -0
  40. package/dist/entities/model-code.js +2 -0
  41. package/dist/entities/model.d.ts +2 -0
  42. package/dist/entities/model.js +1 -0
  43. package/dist/entities-DvmA9fEV.js +175 -0
  44. package/dist/{entity-fallback-BTkM8j0V.js → entity-fallback-Bth0fa7m.js} +1 -1
  45. package/dist/entity-geo-B2CkuMWx.js +100 -0
  46. package/dist/entity-models-B6-0r2gR.js +123 -0
  47. package/dist/entity-models-c2HpfdWV.d.ts +49 -0
  48. package/dist/{export-Bllg8Fw7.d.ts → export-D8fLC1wS.d.ts} +30 -1
  49. package/dist/{export-kMoMes_a.js → export-DT_drDoI.js} +182 -160
  50. package/dist/geo-CmjrXu0G.d.ts +59 -0
  51. package/dist/{geo-BguldlU-.js → geo-Desq-gRC.js} +5 -4
  52. package/dist/geo-model-Bo1gpEwX.js +163 -0
  53. package/dist/index.d.ts +2 -2
  54. package/dist/index.js +10 -10
  55. package/dist/inherit-KkDsM2N_.js +77 -0
  56. package/dist/item-sprites-G-yikdfV.js +126 -0
  57. package/dist/items/discovery.d.ts +2 -2
  58. package/dist/items/discovery.js +2 -2
  59. package/dist/jar-classes-Bj15hjdr.js +75 -0
  60. package/dist/link-Bm5oQYh6.js +331 -0
  61. package/dist/mappings-BEPVaiwE.js +139 -0
  62. package/dist/mappings-DxX4KoZl.d.ts +75 -0
  63. package/dist/merge-3HkeQ_6A.js +46 -0
  64. package/dist/model-PnQ4gV0-.d.ts +49 -0
  65. package/dist/model-bytecode-C1nw2G8O.js +732 -0
  66. package/dist/model-code-B7jSFQqd.d.ts +16 -0
  67. package/dist/model-code-BKMEMXxF.js +49 -0
  68. package/dist/mods/prepare.js +1 -1
  69. package/dist/mods/tints.js +1 -1
  70. package/dist/{obj-bvs3gwex.js → obj-CJHEHpki.js} +4 -4
  71. package/dist/{obj-mesh-rnYbSbpv.js → obj-mesh-JwPkZEWL.js} +1 -1
  72. package/dist/pack-format-QcVFxG_b.d.ts +280 -0
  73. package/dist/pack.d.ts +1 -1
  74. package/dist/{pipeline-B8e6x8Hh.js → pipeline-BUIMzMzg.js} +6 -6
  75. package/dist/{prepare-C9gjqQTt.js → prepare-Myd_ec4v.js} +2 -2
  76. package/dist/render/entity-fallback.js +1 -1
  77. package/dist/render/face.js +1 -1
  78. package/dist/render/geo.d.ts +2 -54
  79. package/dist/render/geo.js +2 -2
  80. package/dist/render/obj.js +1 -1
  81. package/dist/render/pipeline.js +1 -1
  82. package/dist/render/renderer.js +1 -1
  83. package/dist/resources/descriptor.js +1 -1
  84. package/dist/{run-B_JAUbXe.js → run-BQJkqc5f.js} +3 -3
  85. package/dist/run.js +1 -1
  86. package/dist/sprite-sheet-LQAEtGkp.js +185 -0
  87. package/dist/versions/prepare.js +1 -1
  88. package/dist/workers/render-worker.js +2 -2
  89. package/package.json +1 -1
  90. package/dist/pack-format-BVC_B-ZW.d.ts +0 -140
  91. package/dist/{descriptor-D7VKgeGT.js → descriptor-JyXhfd-c.js} +1 -1
  92. package/dist/{face-CKHboPfh.js → face-B2JjWT46.js} +1 -1
  93. package/dist/{prepare-8LswFoS-.js → prepare-D49Gu4Lv.js} +1 -1
  94. package/dist/{tints-C1tT6pKk.js → tints-BspVCz2G.js} +1 -1
@@ -0,0 +1,163 @@
1
+ //#region src/entities/geo-model.ts
2
+ /** Where a `ModelPart`'s origin sits above the feet, in pixels: 1.5 blocks. */
3
+ const FEET = 24;
4
+ const DEGREES = Math.PI / 180;
5
+ /** A cycle in `parent` links would otherwise walk forever; no real model nests anywhere near this. */
6
+ const MAX_DEPTH = 32;
7
+ const vec3 = (values) => [
8
+ values?.[0] ?? 0,
9
+ values?.[1] ?? 0,
10
+ values?.[2] ?? 0
11
+ ];
12
+ /** A bedrock point in `ModelPart` space. */
13
+ const toJava = (point) => [
14
+ point[0],
15
+ FEET - point[1],
16
+ point[2]
17
+ ];
18
+ /** `-0` is what negating an unrotated bone leaves behind, and it has no business in a pack file. */
19
+ const noMinusZero = (value) => value === 0 ? 0 : value;
20
+ const toJavaRotation = (rotation) => {
21
+ const [pitch, yaw, roll] = vec3(rotation);
22
+ return [
23
+ noMinusZero(pitch * DEGREES),
24
+ noMinusZero(-yaw * DEGREES),
25
+ noMinusZero(-roll * DEGREES)
26
+ ];
27
+ };
28
+ const FACES = [
29
+ "north",
30
+ "south",
31
+ "east",
32
+ "west",
33
+ "up",
34
+ "down"
35
+ ];
36
+ /** Bedrock's per-face rects, which have no equivalent in a Java box unwrap. */
37
+ function faceRects(cube, size) {
38
+ if (!cube.uv || Array.isArray(cube.uv)) return;
39
+ const faces = {};
40
+ for (const face of FACES) {
41
+ const entry = cube.uv[face];
42
+ if (entry?.uv) faces[face] = {
43
+ uv: [entry.uv[0], entry.uv[1]],
44
+ size: [entry.uv_size?.[0] ?? size[0], entry.uv_size?.[1] ?? size[1]]
45
+ };
46
+ }
47
+ return Object.keys(faces).length > 0 ? faces : void 0;
48
+ }
49
+ /**
50
+ * One bedrock cube, in the space of the part that owns it.
51
+ *
52
+ * `pivot` is the *bone's* pivot in bedrock space: a cube's box is stated in absolute coordinates, and a
53
+ * `ModelPart`'s is stated relative to where the part pivots. The y flip swaps which corner is the
54
+ * minimum, so the origin is measured from the far side of the box.
55
+ */
56
+ function toCube(cube, pivot) {
57
+ if (!cube.origin || !cube.size) return null;
58
+ const stated = vec3(cube.origin);
59
+ const extent = vec3(cube.size);
60
+ const origin = stated.map((value, axis) => Math.min(value, value + extent[axis]));
61
+ const size = extent.map((value) => Math.abs(value));
62
+ const rects = faceRects(cube, size);
63
+ const uv = Array.isArray(cube.uv) ? cube.uv : [];
64
+ return {
65
+ origin: [
66
+ origin[0] - pivot[0],
67
+ pivot[1] - origin[1] - size[1],
68
+ origin[2] - pivot[2]
69
+ ],
70
+ size,
71
+ uv: [uv[0] ?? 0, uv[1] ?? 0],
72
+ inflate: cube.inflate ?? 0,
73
+ mirror: cube.mirror ?? false,
74
+ ...rects && { faces: rects }
75
+ };
76
+ }
77
+ /**
78
+ * Converts one parsed `.geo.json` into a model.
79
+ *
80
+ * Bones are a flat list joined by `parent` name, so the tree is rebuilt here. A bone whose parent is
81
+ * missing becomes a root rather than being dropped, and a cube carrying its own rotation becomes a part
82
+ * of its own: `Cube` has nowhere to put a rotation, and 18% of the corpus's cubes have one.
83
+ */
84
+ function geoToModel(geo) {
85
+ const bones = geo.bones;
86
+ const byName = /* @__PURE__ */ new Map();
87
+ for (const bone of bones) if (bone.name) byName.set(bone.name, bone);
88
+ const notes = [];
89
+ const parts = /* @__PURE__ */ new Map();
90
+ const pivots = /* @__PURE__ */ new Map();
91
+ for (const bone of bones) {
92
+ const pivot = vec3(bone.pivot);
93
+ pivots.set(bone, pivot);
94
+ const cubes = [];
95
+ const rotated = [];
96
+ for (const cube of bone.cubes ?? []) {
97
+ if (cube.rotation?.some((value) => value !== 0) && cube.pivot) {
98
+ const cubePivot = vec3(cube.pivot);
99
+ const converted = toCube(cube, cubePivot);
100
+ if (converted) rotated.push({
101
+ name: `${bone.name ?? "bone"}_cube${rotated.length + 1}`,
102
+ pivot: subtract(toJava(cubePivot), toJava(pivot)),
103
+ rotation: toJavaRotation(cube.rotation),
104
+ cubes: [converted],
105
+ children: []
106
+ });
107
+ continue;
108
+ }
109
+ const converted = toCube(cube, pivot);
110
+ if (converted) cubes.push(converted);
111
+ }
112
+ parts.set(bone, {
113
+ name: bone.name ?? `bone${parts.size + 1}`,
114
+ pivot: [
115
+ 0,
116
+ 0,
117
+ 0
118
+ ],
119
+ rotation: toJavaRotation(bone.rotation),
120
+ cubes,
121
+ children: rotated
122
+ });
123
+ }
124
+ const roots = [];
125
+ for (const bone of bones) {
126
+ const part = parts.get(bone);
127
+ const parent = bone.parent ? byName.get(bone.parent) : void 0;
128
+ if (parent && parent !== bone && depthOf(bone, byName) < MAX_DEPTH) {
129
+ part.pivot = subtract(toJava(pivots.get(bone)), toJava(pivots.get(parent)));
130
+ parts.get(parent).children.push(part);
131
+ continue;
132
+ }
133
+ if (bone.parent && !parent) notes.push(`${bone.name ?? "a bone"} names a parent the file does not define, so it hangs from the model root`);
134
+ part.pivot = toJava(pivots.get(bone));
135
+ roots.push(part);
136
+ }
137
+ return {
138
+ textureSize: [geo.textureWidth, geo.textureHeight],
139
+ parts: roots,
140
+ notes
141
+ };
142
+ }
143
+ function subtract(left, right) {
144
+ return [
145
+ left[0] - right[0],
146
+ left[1] - right[1],
147
+ left[2] - right[2]
148
+ ];
149
+ }
150
+ /** How far a bone sits from its root, which is also the cycle check. */
151
+ function depthOf(bone, byName) {
152
+ const seen = /* @__PURE__ */ new Set();
153
+ let current = bone;
154
+ let depth = 0;
155
+ while (current && !seen.has(current) && depth < MAX_DEPTH) {
156
+ seen.add(current);
157
+ current = current.parent ? byName.get(current.parent) : void 0;
158
+ depth++;
159
+ }
160
+ return depth;
161
+ }
162
+ //#endregion
163
+ export { geoToModel as t };
package/dist/index.d.ts CHANGED
@@ -6,15 +6,15 @@ import { a as PackedRect, i as PackedPage, n as PackOptions, o as packAtlas, r a
6
6
  import { a as buildBiomeClimates, i as VANILLA_BIOME_CLIMATES, n as BiomeClimatePack, o as parseBiomeClimate, r as DEFAULT_WATER_COLOR, t as BiomeClimate } from "./biomes-CJDJQqJb.js";
7
7
  import { a as resolveTexture, n as ModelResolutionError, o as salvageJson, r as ResolvedModel, t as ModelLoader } from "./loader-DSir1-P0.js";
8
8
  import { a as BlockStateMultipartCase, 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-BzznRcVY.js";
9
- import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "./export-Bllg8Fw7.js";
10
9
  import { i as buildObjMesh, n as ObjMesh, r as ObjMeshError, t as MeshGroup } from "./obj-mesh-ydhVfLKs.js";
11
10
  import { a as buildBlockTints, i as UNREGISTERED_TINTS, n as BlockTintPack, t as BlockTint } from "./tints-DoBv5S9v.js";
11
+ import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "./export-D8fLC1wS.js";
12
12
  import { s as builtinDynamicResources } from "./generators-BnIzAftW.js";
13
13
  import { d as toFloatTexture, n as FloatTexture, u as toByteTexture } from "./blend-eT64Z6qm.js";
14
14
  import { a as LightingProfileName, i as LightingProfile, r as LightSource, u as lightsForProfile } from "./lighting-3FGRC3Af.js";
15
15
  import { a as RenderedFrames, c as renderModel, i as RenderOptions, l as renderModelFrames, o as boxDownscale, r as ItemRenderError, s as pointResize } from "./renderer-C_DFi8DF.js";
16
16
  import { c as defaultProperties, i as ItemRenderInstruction, l as evaluateItemModel, n as InvalidItemDefinitionError, o as TintDefinition, r as ItemProperties, s as UNKNOWN_MODEL } from "./definition-ricL7Jqf.js";
17
- import { a as resolveItem, i as discoverItems, n as ItemDiscoveryOptions, r as ItemResolutionError, t as DiscoveredItem } from "./discovery-C5ZR4aoG.js";
17
+ import { i as discoverItems, n as ItemDiscoveryOptions, o as resolveItem, r as ItemResolutionError, t as DiscoveredItem } from "./discovery-Cmir3QfC.js";
18
18
  import { a as resolveTint, i as parseTintValue, n as InvalidTinterDefinitionError, o as resolveTints, t as DYE_COLORS } from "./tints-6z6ysGUs.js";
19
19
  import { i as EncodedIcon, n as EncodeOptions, o as encodeAnimatedIcon, r as EncodedAnimatedIcon, s as encodeIcon, t as AnimatedEncodeOptions } from "./encode-Cf8hI5OY.js";
20
20
  import { t as minifyStylesheet } from "./minify-CIV6enbr.js";
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
- import { t as packAtlas } from "./atlas-pack-CoOih7By.js";
2
1
  import { i as parseBiomeClimate, n as VANILLA_BIOME_CLIMATES, r as buildBiomeClimates, t as DEFAULT_WATER_COLOR } from "./biomes-5ZwYxMYe.js";
3
2
  import { n as ResourceLocator, t as InvalidResourceLocatorError } from "./locator-COMEtEn9.js";
4
3
  import { a as parseBlockState, i as matchesCondition, n as collectModels, o as weightedVariantIndex, r as evaluateBlockState, t as BlockStateError } from "./blockstate-eval-BRQ3NWY2.js";
5
4
  import { c as toByteTexture, l as toFloatTexture } from "./blend-KXMclcHk.js";
6
5
  import { c as lightsForProfile, r as LightingProfile } from "./lighting--5myudVu.js";
6
+ import { a as defaultProperties, i as UNKNOWN_MODEL, n as InvalidItemDefinitionError, o as evaluateItemModel } from "./definition-ColsvWrH.js";
7
+ import { i as resolveItem, n as discoverItems, t as ItemResolutionError } from "./discovery-CD0QqxSF.js";
7
8
  import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, t as ModelLoader } from "./loader-C-NuJaEi.js";
8
- import { a as ItemRenderError, c as renderModel, l as renderModelFrames, o as boxDownscale, s as pointResize } from "./obj-bvs3gwex.js";
9
- import { n as buildObjMesh, t as ObjMeshError } from "./obj-mesh-rnYbSbpv.js";
9
+ import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "./tints-B3WQcPtx.js";
10
+ import { a as ItemRenderError, c as renderModel, l as renderModelFrames, o as boxDownscale, s as pointResize } from "./obj-CJHEHpki.js";
11
+ import { n as buildObjMesh, t as ObjMeshError } from "./obj-mesh-JwPkZEWL.js";
12
+ import { t as packAtlas } from "./atlas-pack-CoOih7By.js";
10
13
  import { n as buildBlockTints, t as UNREGISTERED_TINTS } from "./tints-Cl0r-Ol3.js";
11
14
  import { o as createAtlasResolver, s as parseAtlasSources, t as AtlasSourceError } from "./sources-BlUriDCs.js";
12
15
  import { n as LayeredResourceManager, r as ResourceKind, t as FolderResourceManager } from "./manager-BNibYkmI.js";
13
16
  import { n as TextureLoader, r as TextureResolutionError, t as AnimatedTexture } from "./loader-C18GpurU.js";
14
- import { t as exportBlockPack } from "./export-kMoMes_a.js";
15
- import { a as defaultProperties, i as UNKNOWN_MODEL, n as InvalidItemDefinitionError, o as evaluateItemModel } from "./definition-ColsvWrH.js";
17
+ import { t as exportBlockPack } from "./export-DT_drDoI.js";
16
18
  import { n as UnsafeJarError, r as isUnsafeEntryPath, t as JarResourceManager } from "./jar-W2cV2ZVO.js";
17
- import { n as prepareModResources } from "./prepare-C9gjqQTt.js";
18
- import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-8LswFoS-.js";
19
- import { n as discoverItems, r as resolveItem, t as ItemResolutionError } from "./discovery-CsZu08re.js";
19
+ import { n as prepareModResources } from "./prepare-Myd_ec4v.js";
20
+ import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-D49Gu4Lv.js";
20
21
  import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
21
22
  import { a as builtinDynamicResources } from "./generators-BCZVlWig.js";
22
23
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
23
24
  import { n as itemClass, t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
24
- import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "./tints-B3WQcPtx.js";
25
- import { t as run } from "./run-B_JAUbXe.js";
25
+ import { t as run } from "./run-BQJkqc5f.js";
26
26
  export { AnimatedTexture, AtlasSourceError, BlockStateError, DEFAULT_WATER_COLOR, DYE_COLORS, FolderResourceManager, InvalidItemDefinitionError, InvalidResourceLocatorError, InvalidTinterDefinitionError, ItemRenderError, ItemResolutionError, JarResourceManager, LayeredResourceManager, LightingProfile, ModelLoader, ModelResolutionError, ObjMeshError, ResourceKind, ResourceLocator, TextureLoader, TextureResolutionError, UNKNOWN_MODEL, UNREGISTERED_TINTS, UnsafeJarError, VANILLA_BIOME_CLIMATES, boxDownscale, buildBiomeClimates, buildBlockTints, buildObjMesh, builtinDynamicResources, collectModels, compareVersions, createAtlasResolver, defaultProperties, discoverItems, encodeAnimatedIcon, encodeIcon, eraForVersion, evaluateBlockState, evaluateItemModel, exportBlockPack, generateStylesheet, isUnsafeEntryPath, itemClass, lightsForProfile, matchesCondition, minifyStylesheet, packAtlas, parseAtlasSources, parseBiomeClimate, parseBlockState, parseTintValue, pointResize, prepareModResources, prepareVersionResources, renderModel, renderModelFrames, resolveItem, resolveTexture, resolveTint, resolveTints, run, salvageJson, toByteTexture, toFloatTexture, weightedVariantIndex };
@@ -0,0 +1,77 @@
1
+ import { t as parseClassFile } from "./classfile-CAhS5qNf.js";
2
+ import { i as mergeModels } from "./merge-3HkeQ_6A.js";
3
+ import { t as extractModel } from "./model-bytecode-C1nw2G8O.js";
4
+ //#region src/entities/inherit.ts
5
+ /**
6
+ * A model class read together with its ancestors.
7
+ *
8
+ * Model code leans on its superclass everywhere. Before 1.17 a model's parts were fields assigned in
9
+ * the constructor and a subclass overrode the two or three it cared about, leaving the rest to
10
+ * `super()`; `CowModel` declares a head with horns and a body, and its four legs belong to
11
+ * `QuadrupedModel`. It did not end with the old API either: 26.2's `PigModel` still starts from
12
+ * `QuadrupedModel.createBodyMesh(6, …)` and only replaces the head.
13
+ *
14
+ * So the interpreter is handed the chain and follows calls into it, arguments and all. What it cannot
15
+ * follow — a builder that loops, a frame past the budget — the name merge below still salvages, one
16
+ * class at a time.
17
+ */
18
+ /** `java/lang/Object` ends the walk; the cap is for a jar whose hierarchy has a cycle in it. */
19
+ const MAX_ANCESTORS = 8;
20
+ /** Reads a class and everything it inherits from that the jar still holds. */
21
+ async function ancestryOf(internalName, read) {
22
+ const ancestors = /* @__PURE__ */ new Map();
23
+ const chain = [];
24
+ let next = internalName.replaceAll(".", "/");
25
+ for (let depth = 0; next && depth < MAX_ANCESTORS && !ancestors.has(next); depth++) {
26
+ const bytes = await read(next);
27
+ if (!bytes) break;
28
+ let classFile;
29
+ try {
30
+ classFile = parseClassFile(bytes);
31
+ } catch {
32
+ break;
33
+ }
34
+ ancestors.set(next, classFile);
35
+ chain.push({
36
+ internalName: next,
37
+ bytes
38
+ });
39
+ next = classFile.superClass;
40
+ }
41
+ return {
42
+ ancestors,
43
+ chain
44
+ };
45
+ }
46
+ /**
47
+ * Geometry for one class, with the code it builds on available and its ancestors' parts filled in.
48
+ *
49
+ * `code` widens what a call may be followed into beyond the ancestors, which some models need: the
50
+ * witch's body is the villager's, and a donkey's chest comes from the saddle model. Without it those
51
+ * models still come out, minus the piece the other class holds.
52
+ *
53
+ * Every ancestor is merged rather than only the first with boxes, because a deep hierarchy splits
54
+ * several ways: 1.16.5's sheep overrides a head in `SheepFurModel` and takes its legs from
55
+ * `QuadrupedModel` two hops up.
56
+ */
57
+ async function extractInheritedModel(internalName, read, code) {
58
+ const { ancestors, chain } = await ancestryOf(internalName, read);
59
+ const [own, ...inherited] = chain;
60
+ if (!own) return null;
61
+ const resolve = (name) => ancestors.get(name) ?? code?.resolve(name) ?? null;
62
+ const following = (name) => !code || code.resolve(name) !== null;
63
+ let model = extractModel(own.bytes, {
64
+ resolve,
65
+ isModelCode: following(own.internalName)
66
+ });
67
+ for (const ancestor of inherited) {
68
+ const inheritedModel = extractModel(ancestor.bytes, {
69
+ resolve,
70
+ isModelCode: following(ancestor.internalName)
71
+ });
72
+ model = mergeModels(model, inheritedModel);
73
+ }
74
+ return model;
75
+ }
76
+ //#endregion
77
+ export { extractInheritedModel as n, ancestryOf as t };
@@ -0,0 +1,126 @@
1
+ import { i as resolveItem, r as langRegistry } from "./discovery-CD0QqxSF.js";
2
+ import { i as resolveTexture } from "./loader-C-NuJaEi.js";
3
+ import { a as resolveTints } from "./tints-B3WQcPtx.js";
4
+ //#region src/blocks/item-sprites.ts
5
+ /**
6
+ * Flat item sprites, for the items a world holds that are not blocks.
7
+ *
8
+ * A dropped stack is the commonest entity in a played-in world, and the game
9
+ * draws it from the *item* model rather than the block one. Most of the time that
10
+ * item model is a block's, and a consumer with the block pack already has what it
11
+ * needs. The rest — a lead, a handful of charcoal, an arrow, a mod's seed — are
12
+ * `item/generated`: a stack of flat sprites the client extrudes into a thin slab,
13
+ * with no geometry stated anywhere because `ItemModelGenerator` builds it in code.
14
+ *
15
+ * So this exports the only thing there is to export: the ordered layer sprites,
16
+ * and which of them the item tints. The consumer does the extruding.
17
+ *
18
+ * Deliberately *not* filtered to non-block ids. Whether an item is flat is decided
19
+ * by asking what its own model resolves to, which is also what the game asks —
20
+ * and it gets `minecraft:wheat` right, where the item is a flat sheaf and the
21
+ * block of the same id is a crop cross.
22
+ */
23
+ /** The builtin parent whose geometry the client generates from flat layers. */
24
+ const GENERATED = "builtin/generated";
25
+ /** `layer0`, `layer1`, … in the order the client stacks them. */
26
+ const LAYER_NAME = /^layer(\d+)$/;
27
+ /** `{ r, g, b }` in 0–1 as `#rrggbb`, matching how the tint pack writes a colour. */
28
+ function hex(color) {
29
+ return `#${[
30
+ color.r,
31
+ color.g,
32
+ color.b
33
+ ].map((channel) => Math.round(Math.max(0, Math.min(1, channel)) * 255).toString(16).padStart(2, "0")).join("")}`;
34
+ }
35
+ /**
36
+ * The layers of one generated model, in draw order.
37
+ *
38
+ * Sorted by the number in the name rather than by key order: a mod that writes
39
+ * `layer1` before `layer0` still stacks the way the client stacks it, and a chain
40
+ * that merged its parent's textures has no reliable order at all.
41
+ */
42
+ function layersOf(textures) {
43
+ const layers = [];
44
+ for (const name of Object.keys(textures)) {
45
+ const match = LAYER_NAME.exec(name);
46
+ if (match) layers.push({
47
+ index: Number(match[1]),
48
+ reference: `#${name}`
49
+ });
50
+ }
51
+ return layers.toSorted((left, right) => left.index - right.index);
52
+ }
53
+ async function collectItemSprites(options) {
54
+ const { resources, models, textures, blocks, itemIds } = options;
55
+ const items = {};
56
+ const spriteIds = /* @__PURE__ */ new Set();
57
+ const failures = [];
58
+ let done = 0;
59
+ const translated = /* @__PURE__ */ new Map();
60
+ for (const namespace of options.namespaces) translated.set(namespace, await langRegistry(resources, namespace));
61
+ const report = (id, reason) => {
62
+ const divider = id.indexOf(":");
63
+ const gate = translated.get(id.slice(0, divider));
64
+ if (gate === void 0 || gate === null || gate.has(id.slice(divider + 1).replaceAll("/", "."))) failures.push({
65
+ id,
66
+ reason
67
+ });
68
+ };
69
+ for (const id of [...itemIds].toSorted((left, right) => left.localeCompare(right))) {
70
+ options.onProgress?.(++done, itemIds.length);
71
+ let instructions;
72
+ try {
73
+ instructions = await resolveItem(resources, id);
74
+ } catch (err) {
75
+ if (!blocks.has(id)) report(id, err.message);
76
+ continue;
77
+ }
78
+ const layers = [];
79
+ let flat = true;
80
+ for (const instruction of instructions) {
81
+ let model;
82
+ try {
83
+ model = await models.load(instruction.model);
84
+ } catch (err) {
85
+ flat = false;
86
+ if (!blocks.has(id)) report(id, `model ${instruction.model} did not load: ${err.message}`);
87
+ break;
88
+ }
89
+ if (model.builtinParent !== GENERATED) {
90
+ flat = false;
91
+ break;
92
+ }
93
+ const tints = await resolveTints(instruction.tints, { textures });
94
+ for (const layer of layersOf(model.textures)) {
95
+ const sprite = resolveTexture(model, layer.reference);
96
+ if (!sprite) {
97
+ report(id, `${layer.reference} resolves to no texture; layer dropped`);
98
+ continue;
99
+ }
100
+ const tint = tints[layer.index];
101
+ layers.push({
102
+ sprite: sprite.toString(),
103
+ ...instruction.tints[layer.index] !== void 0 && { tintindex: layer.index },
104
+ ...tint && { tint: hex(tint) }
105
+ });
106
+ spriteIds.add(sprite.toString());
107
+ }
108
+ }
109
+ if (!flat) {
110
+ if (!blocks.has(id)) report(id, "item model is not a flat sprite stack and the pack describes no block of this id");
111
+ continue;
112
+ }
113
+ if (layers.length === 0) {
114
+ report(id, "generated item model states no layers");
115
+ continue;
116
+ }
117
+ items[id] = { layers };
118
+ }
119
+ return {
120
+ items,
121
+ spriteIds,
122
+ failures
123
+ };
124
+ }
125
+ //#endregion
126
+ export { collectItemSprites as t };
@@ -1,2 +1,2 @@
1
- import { a as resolveItem, i as discoverItems, n as ItemDiscoveryOptions, r as ItemResolutionError, t as DiscoveredItem } from "../discovery-C5ZR4aoG.js";
2
- export { DiscoveredItem, ItemDiscoveryOptions, ItemResolutionError, discoverItems, resolveItem };
1
+ import { a as langRegistry, i as discoverItems, n as ItemDiscoveryOptions, o as resolveItem, r as ItemResolutionError, t as DiscoveredItem } from "../discovery-Cmir3QfC.js";
2
+ export { DiscoveredItem, ItemDiscoveryOptions, ItemResolutionError, discoverItems, langRegistry, resolveItem };
@@ -1,2 +1,2 @@
1
- import { n as discoverItems, r as resolveItem, t as ItemResolutionError } from "../discovery-CsZu08re.js";
2
- export { ItemResolutionError, discoverItems, resolveItem };
1
+ import { i as resolveItem, n as discoverItems, r as langRegistry, t as ItemResolutionError } from "../discovery-CD0QqxSF.js";
2
+ export { ItemResolutionError, discoverItems, langRegistry, resolveItem };
@@ -0,0 +1,75 @@
1
+ import { t as openZip } from "./zip-reader-BSbJKUT1.js";
2
+ import { n as UnsafeJarError, r as isUnsafeEntryPath } from "./jar-W2cV2ZVO.js";
3
+ //#region src/entities/jar-classes.ts
4
+ /**
5
+ * Reading `.class` entries out of a jar.
6
+ *
7
+ * `JarResourceManager` deliberately indexes only `assets/` and `data/` — it is a *resource* manager,
8
+ * and a class file is not a resource. But entity geometry lives in the code (see
9
+ * `docs/entity-geometry.md`), so the extractor needs the other half of the archive, and it needs it
10
+ * by internal class name rather than by resource locator.
11
+ *
12
+ * Same shape as the resource manager for the same reason: index the central directory once, then read
13
+ * entries on demand. A client jar holds around eight thousand classes and the extractor touches a
14
+ * hundred of them.
15
+ */
16
+ /** Reads class files out of one jar, by internal name. */
17
+ var JarClassReader = class {
18
+ jarPath;
19
+ index = null;
20
+ constructor(jarPath) {
21
+ this.jarPath = jarPath;
22
+ }
23
+ getIndex() {
24
+ this.index ??= (async () => {
25
+ const zip = await openZip(this.jarPath);
26
+ return await new Promise((resolve, reject) => {
27
+ const entries = /* @__PURE__ */ new Map();
28
+ zip.on("entry", (entry) => {
29
+ if (isUnsafeEntryPath(entry.fileName)) {
30
+ zip.close();
31
+ reject(new UnsafeJarError(`Unsafe entry in ${this.jarPath}: ${entry.fileName}`));
32
+ return;
33
+ }
34
+ if (entry.fileName.endsWith(".class")) entries.set(entry.fileName.slice(0, -6), entry);
35
+ zip.readEntry();
36
+ });
37
+ zip.on("end", () => resolve({
38
+ zip,
39
+ entries
40
+ }));
41
+ zip.on("error", reject);
42
+ zip.readEntry();
43
+ });
44
+ })();
45
+ return this.index;
46
+ }
47
+ /** Every class in the jar, for a sweep that does not know what it is looking for. */
48
+ async list() {
49
+ return (await this.getIndex()).entries.keys().toArray();
50
+ }
51
+ async read(internalName) {
52
+ const index = await this.getIndex();
53
+ const entry = index.entries.get(internalName.replaceAll(".", "/"));
54
+ if (!entry) return null;
55
+ return await new Promise((resolve, reject) => {
56
+ index.zip.openReadStream(entry, (err, stream) => {
57
+ if (err) {
58
+ reject(err);
59
+ return;
60
+ }
61
+ const chunks = [];
62
+ stream.on("data", (chunk) => {
63
+ chunks.push(chunk);
64
+ });
65
+ stream.on("end", () => resolve(new Uint8Array(Buffer.concat(chunks))));
66
+ stream.on("error", reject);
67
+ });
68
+ });
69
+ }
70
+ async close() {
71
+ if (this.index) (await this.index).zip.close();
72
+ }
73
+ };
74
+ //#endregion
75
+ export { JarClassReader as t };