@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.
- package/README.md +3 -0
- package/dist/blocks/cli.js +1 -1
- package/dist/blocks/entities.d.ts +30 -0
- package/dist/blocks/entities.js +2 -0
- package/dist/blocks/entity-geo.d.ts +18 -0
- package/dist/blocks/entity-geo.js +2 -0
- package/dist/blocks/entity-models.d.ts +2 -0
- package/dist/blocks/entity-models.js +2 -0
- package/dist/blocks/export.d.ts +1 -1
- package/dist/blocks/export.js +1 -1
- package/dist/blocks/item-sprites.d.ts +34 -0
- package/dist/blocks/item-sprites.js +2 -0
- package/dist/blocks/obj-mesh.js +1 -1
- package/dist/blocks/pack-format.d.ts +2 -2
- package/dist/blocks/sprite-sheet.d.ts +59 -0
- package/dist/blocks/sprite-sheet.js +2 -0
- package/dist/classfile-BwaQjnUM.d.ts +51 -0
- package/dist/classfile-CAhS5qNf.js +255 -0
- package/dist/{cli-DqJtT-Ms.js → cli-BSKnXBPr.js} +31 -4
- package/dist/cli.js +5 -5
- package/dist/{discovery-CsZu08re.js → discovery-CD0QqxSF.js} +1 -1
- package/dist/{discovery-C5ZR4aoG.d.ts → discovery-Cmir3QfC.d.ts} +8 -1
- package/dist/entities/classfile.d.ts +2 -0
- package/dist/entities/classfile.js +2 -0
- package/dist/entities/geo-model.d.ts +13 -0
- package/dist/entities/geo-model.js +2 -0
- package/dist/entities/inherit.d.ts +29 -0
- package/dist/entities/inherit.js +2 -0
- package/dist/entities/jar-classes.d.ts +26 -0
- package/dist/entities/jar-classes.js +2 -0
- package/dist/entities/link.d.ts +71 -0
- package/dist/entities/link.js +2 -0
- package/dist/entities/mappings.d.ts +2 -0
- package/dist/entities/mappings.js +2 -0
- package/dist/entities/merge.d.ts +18 -0
- package/dist/entities/merge.js +2 -0
- package/dist/entities/model-bytecode.d.ts +31 -0
- package/dist/entities/model-bytecode.js +2 -0
- package/dist/entities/model-code.d.ts +2 -0
- package/dist/entities/model-code.js +2 -0
- package/dist/entities/model.d.ts +2 -0
- package/dist/entities/model.js +1 -0
- package/dist/entities-DvmA9fEV.js +175 -0
- package/dist/{entity-fallback-BTkM8j0V.js → entity-fallback-Bth0fa7m.js} +1 -1
- package/dist/entity-geo-B2CkuMWx.js +100 -0
- package/dist/entity-models-B6-0r2gR.js +123 -0
- package/dist/entity-models-c2HpfdWV.d.ts +49 -0
- package/dist/{export-Bllg8Fw7.d.ts → export-D8fLC1wS.d.ts} +30 -1
- package/dist/{export-kMoMes_a.js → export-DT_drDoI.js} +182 -160
- package/dist/geo-CmjrXu0G.d.ts +59 -0
- package/dist/{geo-BguldlU-.js → geo-Desq-gRC.js} +5 -4
- package/dist/geo-model-Bo1gpEwX.js +163 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- package/dist/inherit-KkDsM2N_.js +77 -0
- package/dist/item-sprites-G-yikdfV.js +126 -0
- package/dist/items/discovery.d.ts +2 -2
- package/dist/items/discovery.js +2 -2
- package/dist/jar-classes-Bj15hjdr.js +75 -0
- package/dist/link-Bm5oQYh6.js +331 -0
- package/dist/mappings-BEPVaiwE.js +139 -0
- package/dist/mappings-DxX4KoZl.d.ts +75 -0
- package/dist/merge-3HkeQ_6A.js +46 -0
- package/dist/model-PnQ4gV0-.d.ts +49 -0
- package/dist/model-bytecode-C1nw2G8O.js +732 -0
- package/dist/model-code-B7jSFQqd.d.ts +16 -0
- package/dist/model-code-BKMEMXxF.js +49 -0
- package/dist/mods/prepare.js +1 -1
- package/dist/mods/tints.js +1 -1
- package/dist/{obj-bvs3gwex.js → obj-CJHEHpki.js} +4 -4
- package/dist/{obj-mesh-rnYbSbpv.js → obj-mesh-JwPkZEWL.js} +1 -1
- package/dist/pack-format-QcVFxG_b.d.ts +280 -0
- package/dist/pack.d.ts +1 -1
- package/dist/{pipeline-B8e6x8Hh.js → pipeline-BUIMzMzg.js} +6 -6
- package/dist/{prepare-C9gjqQTt.js → prepare-Myd_ec4v.js} +2 -2
- package/dist/render/entity-fallback.js +1 -1
- package/dist/render/face.js +1 -1
- package/dist/render/geo.d.ts +2 -54
- package/dist/render/geo.js +2 -2
- package/dist/render/obj.js +1 -1
- package/dist/render/pipeline.js +1 -1
- package/dist/render/renderer.js +1 -1
- package/dist/resources/descriptor.js +1 -1
- package/dist/{run-B_JAUbXe.js → run-BQJkqc5f.js} +3 -3
- package/dist/run.js +1 -1
- package/dist/sprite-sheet-LQAEtGkp.js +185 -0
- package/dist/versions/prepare.js +1 -1
- package/dist/workers/render-worker.js +2 -2
- package/package.json +1 -1
- package/dist/pack-format-BVC_B-ZW.d.ts +0 -140
- package/dist/{descriptor-D7VKgeGT.js → descriptor-JyXhfd-c.js} +1 -1
- package/dist/{face-CKHboPfh.js → face-B2JjWT46.js} +1 -1
- package/dist/{prepare-8LswFoS-.js → prepare-D49Gu4Lv.js} +1 -1
- 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 {
|
|
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
|
|
9
|
-
import {
|
|
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-
|
|
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-
|
|
18
|
-
import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-
|
|
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 {
|
|
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
|
|
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 };
|
package/dist/items/discovery.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as discoverItems, r as
|
|
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 };
|