@nodecraft/rendermite 1.5.0 → 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 (83) hide show
  1. package/README.md +2 -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 +1 -1
  12. package/dist/blocks/obj-mesh.js +1 -1
  13. package/dist/blocks/pack-format.d.ts +2 -2
  14. package/dist/blocks/sprite-sheet.d.ts +1 -1
  15. package/dist/classfile-BwaQjnUM.d.ts +51 -0
  16. package/dist/classfile-CAhS5qNf.js +255 -0
  17. package/dist/{cli-DMTaIbDI.js → cli-BSKnXBPr.js} +24 -4
  18. package/dist/cli.js +4 -4
  19. package/dist/entities/classfile.d.ts +2 -0
  20. package/dist/entities/classfile.js +2 -0
  21. package/dist/entities/geo-model.d.ts +13 -0
  22. package/dist/entities/geo-model.js +2 -0
  23. package/dist/entities/inherit.d.ts +29 -0
  24. package/dist/entities/inherit.js +2 -0
  25. package/dist/entities/jar-classes.d.ts +26 -0
  26. package/dist/entities/jar-classes.js +2 -0
  27. package/dist/entities/link.d.ts +71 -0
  28. package/dist/entities/link.js +2 -0
  29. package/dist/entities/mappings.d.ts +2 -0
  30. package/dist/entities/mappings.js +2 -0
  31. package/dist/entities/merge.d.ts +18 -0
  32. package/dist/entities/merge.js +2 -0
  33. package/dist/entities/model-bytecode.d.ts +31 -0
  34. package/dist/entities/model-bytecode.js +2 -0
  35. package/dist/entities/model-code.d.ts +2 -0
  36. package/dist/entities/model-code.js +2 -0
  37. package/dist/entities/model.d.ts +2 -0
  38. package/dist/entities/model.js +1 -0
  39. package/dist/entities-DvmA9fEV.js +175 -0
  40. package/dist/{entity-fallback-DutR9Hdz.js → entity-fallback-Bth0fa7m.js} +1 -1
  41. package/dist/entity-geo-B2CkuMWx.js +100 -0
  42. package/dist/entity-models-B6-0r2gR.js +123 -0
  43. package/dist/entity-models-c2HpfdWV.d.ts +49 -0
  44. package/dist/{export-wvt0Fryo.d.ts → export-D8fLC1wS.d.ts} +22 -1
  45. package/dist/{export-sadR0pWp.js → export-DT_drDoI.js} +93 -1
  46. package/dist/geo-CmjrXu0G.d.ts +59 -0
  47. package/dist/{geo-BC8jtG5Q.js → geo-Desq-gRC.js} +6 -5
  48. package/dist/geo-model-Bo1gpEwX.js +163 -0
  49. package/dist/index.d.ts +1 -1
  50. package/dist/index.js +8 -8
  51. package/dist/inherit-KkDsM2N_.js +77 -0
  52. package/dist/jar-classes-Bj15hjdr.js +75 -0
  53. package/dist/link-Bm5oQYh6.js +331 -0
  54. package/dist/mappings-BEPVaiwE.js +139 -0
  55. package/dist/mappings-DxX4KoZl.d.ts +75 -0
  56. package/dist/merge-3HkeQ_6A.js +46 -0
  57. package/dist/model-PnQ4gV0-.d.ts +49 -0
  58. package/dist/model-bytecode-C1nw2G8O.js +732 -0
  59. package/dist/model-code-B7jSFQqd.d.ts +16 -0
  60. package/dist/model-code-BKMEMXxF.js +49 -0
  61. package/dist/mods/prepare.js +1 -1
  62. package/dist/{obj-BaGvPUbb.js → obj-CJHEHpki.js} +5 -5
  63. package/dist/{obj-mesh-CazmV8ya.js → obj-mesh-JwPkZEWL.js} +1 -1
  64. package/dist/{pack-format-oRExIeD3.d.ts → pack-format-QcVFxG_b.d.ts} +100 -1
  65. package/dist/pack.d.ts +1 -1
  66. package/dist/{pipeline-AAfohoHU.js → pipeline-BUIMzMzg.js} +4 -4
  67. package/dist/render/entity-fallback.js +1 -1
  68. package/dist/render/face.js +1 -1
  69. package/dist/render/geo.d.ts +2 -54
  70. package/dist/render/geo.js +2 -2
  71. package/dist/render/obj.js +1 -1
  72. package/dist/render/pipeline.js +1 -1
  73. package/dist/render/renderer.js +1 -1
  74. package/dist/resources/descriptor.js +1 -1
  75. package/dist/{run-UKgVb-kW.js → run-BQJkqc5f.js} +2 -2
  76. package/dist/run.js +1 -1
  77. package/dist/versions/prepare.js +1 -1
  78. package/dist/workers/render-worker.js +2 -2
  79. package/package.json +1 -1
  80. package/dist/{descriptor-D7VKgeGT.js → descriptor-JyXhfd-c.js} +1 -1
  81. package/dist/{face-CMJ3b3Ae.js → face-B2JjWT46.js} +1 -1
  82. package/dist/{prepare-8LswFoS-.js → prepare-D49Gu4Lv.js} +1 -1
  83. package/dist/{prepare-B_tRy9lB.js → prepare-Myd_ec4v.js} +1 -1
@@ -2,10 +2,12 @@ import { r as buildBiomeClimates } from "./biomes-5ZwYxMYe.js";
2
2
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
3
3
  import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "./block-entities-xv3bQpEX.js";
4
4
  import { a as parseBlockState, n as collectModels } from "./blockstate-eval-BRQ3NWY2.js";
5
+ import { t as collectEntities } from "./entities-DvmA9fEV.js";
6
+ import { t as collectEntityGeometry } from "./entity-models-B6-0r2gR.js";
5
7
  import { n as discoverItems } from "./discovery-CD0QqxSF.js";
6
8
  import { a as salvageJson, i as resolveTexture, t as ModelLoader } from "./loader-C-NuJaEi.js";
7
9
  import { t as collectItemSprites } from "./item-sprites-G-yikdfV.js";
8
- import { n as buildObjMesh } from "./obj-mesh-CazmV8ya.js";
10
+ import { n as buildObjMesh } from "./obj-mesh-JwPkZEWL.js";
9
11
  import { n as buildSpriteSheet, t as MISSING_SPRITE } from "./sprite-sheet-LQAEtGkp.js";
10
12
  import { n as buildBlockTints, t as UNREGISTERED_TINTS } from "./tints-Cl0r-Ol3.js";
11
13
  import { t as loadAtlasResolver } from "./registry-DlduyjtM.js";
@@ -682,6 +684,84 @@ async function exportBlockPack(options) {
682
684
  };
683
685
  }
684
686
  }
687
+ let entityPack = null;
688
+ let entityModelPack = null;
689
+ let entityPages = [];
690
+ if (options.entities ?? true) {
691
+ const collected = await collectEntities({
692
+ resources,
693
+ textures,
694
+ namespaces,
695
+ onProgress: (count, total) => report("entities", count, total)
696
+ });
697
+ for (const failure of collected.failures) failures.push({
698
+ id: failure.id,
699
+ kind: "entity",
700
+ reason: failure.reason
701
+ });
702
+ if (options.classes) {
703
+ const textureOf = /* @__PURE__ */ new Map();
704
+ for (const [id, entry] of Object.entries(collected.entities)) if (entry.texture) textureOf.set(id, entry.texture);
705
+ const geometry = await collectEntityGeometry({
706
+ version,
707
+ cacheDir: options.cacheDir ?? output,
708
+ classes: options.classes,
709
+ entityIds: Object.keys(collected.entities),
710
+ textureOf,
711
+ resources,
712
+ onProgress: (count, total) => report("entity geometry", count, total)
713
+ });
714
+ for (const failure of geometry.failures) failures.push({
715
+ id: failure.id,
716
+ kind: "entity",
717
+ reason: failure.reason
718
+ });
719
+ for (const [id, model] of geometry.modelOf) collected.entities[id].model = model;
720
+ if (Object.keys(geometry.models).length > 0) {
721
+ const sheet = await buildSpriteSheet(geometry.spriteIds, textures, {
722
+ padding: options.padding,
723
+ maxPageSize: options.maxPageSize,
724
+ onProgress: (count, total) => report("entity sprites", count, total)
725
+ });
726
+ for (const failure of sheet.failures) failures.push({
727
+ id: failure.id,
728
+ kind: "sprite",
729
+ reason: failure.reason
730
+ });
731
+ const sheetSizes = /* @__PURE__ */ new Map();
732
+ for (const [id, model] of geometry.modelOf) {
733
+ const sprite = sheet.sprites[collected.entities[id].texture ?? ""];
734
+ if (sprite) {
735
+ const sizes = sheetSizes.get(model) ?? /* @__PURE__ */ new Set();
736
+ sizes.add(`${sprite.w}x${sprite.h}`);
737
+ sheetSizes.set(model, sizes);
738
+ }
739
+ }
740
+ for (const [model, sizes] of sheetSizes) {
741
+ const [only] = [...sizes];
742
+ if (sizes.size === 1) {
743
+ const [width, height] = only.split("x").map(Number);
744
+ geometry.models[model].textureSize = [width, height];
745
+ }
746
+ }
747
+ entityPages = sheet.pages;
748
+ entityModelPack = {
749
+ padding: sheet.padding,
750
+ pages: entityPages.map((page, index) => {
751
+ return {
752
+ file: `entity-atlas-${index}.png`,
753
+ width: page.width,
754
+ height: page.height
755
+ };
756
+ }),
757
+ sprites: sortedByKey(sheet.sprites),
758
+ models: sortedByKey(geometry.models)
759
+ };
760
+ for (const [id, entry] of Object.entries(collected.entities)) if (entry.texture && sheet.missing.has(entry.texture)) delete collected.entities[id].texture;
761
+ }
762
+ }
763
+ if (Object.keys(collected.entities).length > 0) entityPack = sortedByKey(collected.entities);
764
+ }
685
765
  await mkdir(output, { recursive: true });
686
766
  const hashes = {};
687
767
  let writtenFiles = 0;
@@ -717,6 +797,16 @@ async function exportBlockPack(options) {
717
797
  } }).png({ compressionLevel: 9 }).toBuffer());
718
798
  }
719
799
  if (itemPack) await emit("items.json", JSON.stringify(itemPack));
800
+ if (entityPack) await emit("entities.json", JSON.stringify(entityPack));
801
+ for (const [index, page] of entityPages.entries()) {
802
+ const raw = Buffer.from(page.data.buffer, page.data.byteOffset, page.data.byteLength);
803
+ await emit(`entity-atlas-${index}.png`, await sharp(raw, { raw: {
804
+ width: page.width,
805
+ height: page.height,
806
+ channels: 4
807
+ } }).png({ compressionLevel: 9 }).toBuffer());
808
+ }
809
+ if (entityModelPack) await emit("entity-models.json", JSON.stringify(entityModelPack));
720
810
  for (const file of tints.files) await emit(file.path, file.data);
721
811
  await emit("atlas.json", JSON.stringify({
722
812
  padding: sheet.padding,
@@ -741,6 +831,8 @@ async function exportBlockPack(options) {
741
831
  pages: sheet.pages.length,
742
832
  biomes: Object.keys(biomes.pack).length,
743
833
  items: Object.keys(itemPack?.items ?? {}).length,
834
+ entities: Object.keys(entityPack ?? {}).length,
835
+ entityModels: Object.keys(entityModelPack?.models ?? {}).length,
744
836
  failures: failures.length
745
837
  };
746
838
  await emit("meta.json", JSON.stringify({
@@ -0,0 +1,59 @@
1
+ import { n as ResourceLocator } from "./locator-jDbdUeTd.js";
2
+ import { a as ResourceManager } from "./manager-exOIcdyx.js";
3
+ import { i as TextureLoader } from "./loader-DUlx29PC.js";
4
+ import { n as FloatTexture } from "./blend-eT64Z6qm.js";
5
+ import { n as FaceGeometry } from "./geometry-Bkur58Vi.js";
6
+ import { i as RenderOptions } from "./renderer-C_DFi8DF.js";
7
+ //#region src/render/geo.d.ts
8
+ interface GeoCube {
9
+ origin?: number[];
10
+ size?: number[];
11
+ uv?: number[] | Record<string, {
12
+ uv: number[];
13
+ uv_size?: number[];
14
+ }>;
15
+ inflate?: number;
16
+ /** Bedrock mirrors a box's texture rather than its geometry, so only a consumer's UVs care. */
17
+ mirror?: boolean;
18
+ pivot?: number[];
19
+ rotation?: number[];
20
+ }
21
+ interface GeoBone {
22
+ name?: string;
23
+ parent?: string;
24
+ pivot?: number[];
25
+ rotation?: number[];
26
+ cubes?: GeoCube[];
27
+ }
28
+ interface GeoDescription {
29
+ texture_width?: number;
30
+ texture_height?: number;
31
+ }
32
+ interface GeoFile {
33
+ 'minecraft:geometry'?: Array<{
34
+ description?: GeoDescription;
35
+ bones?: GeoBone[];
36
+ }>;
37
+ [key: string]: unknown;
38
+ }
39
+ interface ParsedGeo {
40
+ textureWidth: number;
41
+ textureHeight: number;
42
+ bones: GeoBone[];
43
+ }
44
+ /** Handles both the modern (1.12+) and legacy (`geometry.name` keyed) layouts. */
45
+ declare function parseGeo(json: GeoFile): ParsedGeo | null;
46
+ /** Convert a parsed geo into face geometry, unit-cube fitted with gui pose. */
47
+ declare function geoToFaces(geo: ParsedGeo): FaceGeometry[];
48
+ /** Conventional locations GeckoLib mods keep item geometry and textures. */
49
+ declare function findGeoForItem(resources: ResourceManager, id: string): Promise<{
50
+ geo: ParsedGeo;
51
+ texture: ResourceLocator;
52
+ } | null>;
53
+ /** Name tokens, dropping the numeric suffixes mods use for shape variants. */
54
+ /** Tokens of a name, for the matches that need to see through a mod's own spelling of it. */
55
+ declare function nameTokens(name: string): string[];
56
+ /** Render a parsed geo with the standard block gui pose. */
57
+ declare function renderGeo(geo: ParsedGeo, texture: ResourceLocator, textures: TextureLoader, options: RenderOptions): Promise<FloatTexture | null>;
58
+ //#endregion
59
+ export { parseGeo as a, nameTokens as i, findGeoForItem as n, renderGeo as o, geoToFaces as r, ParsedGeo as t };
@@ -1,10 +1,10 @@
1
1
  import { n as ResourceLocator } from "./locator-COMEtEn9.js";
2
- import { n as displayMatrix } from "./vector-CCxLae_T.js";
3
2
  import { l as toFloatTexture } from "./blend-KXMclcHk.js";
4
- import { c as lightsForProfile } from "./lighting--5myudVu.js";
5
- import { i as createFaceBuffer } from "./rasterizer-DcVJzkxz.js";
6
3
  import { t as combineFaceBuffers } from "./compose-BGsNFR12.js";
7
- import { n as faceMaxZ, r as renderFace, t as createShadeCache } from "./face-CMJ3b3Ae.js";
4
+ import { i as createFaceBuffer } from "./rasterizer-DcVJzkxz.js";
5
+ import { n as displayMatrix } from "./vector-CCxLae_T.js";
6
+ import { n as faceMaxZ, r as renderFace, t as createShadeCache } from "./face-B2JjWT46.js";
7
+ import { c as lightsForProfile } from "./lighting--5myudVu.js";
8
8
  //#region src/render/geo.ts
9
9
  /**
10
10
  * Bedrock-format geometry (`.geo.json`) rendering, best-effort. GeckoLib mods
@@ -317,6 +317,7 @@ async function findGeoForItem(resources, id) {
317
317
  return null;
318
318
  }
319
319
  /** Name tokens, dropping the numeric suffixes mods use for shape variants. */
320
+ /** Tokens of a name, for the matches that need to see through a mod's own spelling of it. */
320
321
  function nameTokens(name) {
321
322
  return name.split(/[/_]/).filter((token) => token.length > 0 && !/^\d+$/.test(token));
322
323
  }
@@ -407,4 +408,4 @@ async function renderGeo(geo, texture, textures, options) {
407
408
  return combineFaceBuffers(renderSize, renderSize, buffers);
408
409
  }
409
410
  //#endregion
410
- export { renderGeo as i, geoToFaces as n, parseGeo as r, findGeoForItem as t };
411
+ export { renderGeo as a, parseGeo as i, geoToFaces as n, nameTokens as r, findGeoForItem as t };
@@ -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,9 +6,9 @@ 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-wvt0Fryo.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";
package/dist/index.js CHANGED
@@ -1,26 +1,26 @@
1
1
  import { i as parseBiomeClimate, n as VANILLA_BIOME_CLIMATES, r as buildBiomeClimates, t as DEFAULT_WATER_COLOR } from "./biomes-5ZwYxMYe.js";
2
2
  import { n as ResourceLocator, t as InvalidResourceLocatorError } from "./locator-COMEtEn9.js";
3
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";
4
+ import { c as toByteTexture, l as toFloatTexture } from "./blend-KXMclcHk.js";
5
+ import { c as lightsForProfile, r as LightingProfile } from "./lighting--5myudVu.js";
4
6
  import { a as defaultProperties, i as UNKNOWN_MODEL, n as InvalidItemDefinitionError, o as evaluateItemModel } from "./definition-ColsvWrH.js";
5
7
  import { i as resolveItem, n as discoverItems, t as ItemResolutionError } from "./discovery-CD0QqxSF.js";
6
8
  import { a as salvageJson, i as resolveTexture, n as ModelResolutionError, t as ModelLoader } from "./loader-C-NuJaEi.js";
7
9
  import { a as resolveTints, i as resolveTint, n as InvalidTinterDefinitionError, r as parseTintValue, t as DYE_COLORS } from "./tints-B3WQcPtx.js";
8
- import { c as toByteTexture, l as toFloatTexture } from "./blend-KXMclcHk.js";
9
- import { c as lightsForProfile, r as LightingProfile } from "./lighting--5myudVu.js";
10
- import { a as ItemRenderError, c as renderModel, l as renderModelFrames, o as boxDownscale, s as pointResize } from "./obj-BaGvPUbb.js";
11
- import { n as buildObjMesh, t as ObjMeshError } from "./obj-mesh-CazmV8ya.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
12
  import { t as packAtlas } from "./atlas-pack-CoOih7By.js";
13
13
  import { n as buildBlockTints, t as UNREGISTERED_TINTS } from "./tints-Cl0r-Ol3.js";
14
14
  import { o as createAtlasResolver, s as parseAtlasSources, t as AtlasSourceError } from "./sources-BlUriDCs.js";
15
15
  import { n as LayeredResourceManager, r as ResourceKind, t as FolderResourceManager } from "./manager-BNibYkmI.js";
16
16
  import { n as TextureLoader, r as TextureResolutionError, t as AnimatedTexture } from "./loader-C18GpurU.js";
17
- import { t as exportBlockPack } from "./export-sadR0pWp.js";
17
+ import { t as exportBlockPack } from "./export-DT_drDoI.js";
18
18
  import { n as UnsafeJarError, r as isUnsafeEntryPath, t as JarResourceManager } from "./jar-W2cV2ZVO.js";
19
- import { n as prepareModResources } from "./prepare-B_tRy9lB.js";
20
- import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-8LswFoS-.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";
21
21
  import { n as encodeIcon, t as encodeAnimatedIcon } from "./encode-LR9wxigC.js";
22
22
  import { a as builtinDynamicResources } from "./generators-BCZVlWig.js";
23
23
  import { t as minifyStylesheet } from "./minify-bjMRmr5J.js";
24
24
  import { n as itemClass, t as generateStylesheet } from "./stylesheet-CovT3B2S.js";
25
- import { t as run } from "./run-UKgVb-kW.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,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 };