@nodecraft/rendermite 1.5.0 → 1.6.1
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 +2 -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 +45 -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 +1 -1
- package/dist/blocks/obj-mesh.js +1 -1
- package/dist/blocks/pack-format.d.ts +2 -2
- package/dist/blocks/sprite-sheet.d.ts +1 -1
- package/dist/classfile-BdLIk4Pe.d.ts +67 -0
- package/dist/classfile-Bo7FUrrD.js +287 -0
- package/dist/{cli-DMTaIbDI.js → cli-D2KJc_yl.js} +28 -4
- package/dist/cli.js +4 -4
- 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 +2 -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-DutR9Hdz.js → entity-fallback-Bth0fa7m.js} +1 -1
- package/dist/entity-geo-B2CkuMWx.js +100 -0
- package/dist/entity-models-_EZ3PVtN.js +127 -0
- package/dist/{export-wvt0Fryo.d.ts → export-B8tPsf4K.d.ts} +22 -1
- package/dist/{export-sadR0pWp.js → export-BfEIwSxY.js} +93 -1
- package/dist/geo-CmjrXu0G.d.ts +59 -0
- package/dist/{geo-BC8jtG5Q.js → geo-Desq-gRC.js} +6 -5
- package/dist/geo-model-Bo1gpEwX.js +163 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +8 -8
- package/dist/inherit-ByHjOJX3.js +77 -0
- package/dist/jar-classes-CSRrPAUy.d.ts +41 -0
- package/dist/jar-classes-DCtELr1i.js +102 -0
- package/dist/link-5GmBLTzk.js +355 -0
- package/dist/mappings-BEPVaiwE.js +139 -0
- package/dist/mappings-DxX4KoZl.d.ts +75 -0
- package/dist/merge-NDYxpmL8.js +48 -0
- package/dist/model-PnQ4gV0-.d.ts +49 -0
- package/dist/model-bytecode-gWy5_uCj.js +742 -0
- package/dist/model-code-1Vuk-zj_.js +49 -0
- package/dist/model-code-BY44ao27.d.ts +16 -0
- package/dist/mods/prepare.js +1 -1
- package/dist/{obj-BaGvPUbb.js → obj-CJHEHpki.js} +5 -5
- package/dist/{obj-mesh-CazmV8ya.js → obj-mesh-JwPkZEWL.js} +1 -1
- package/dist/{pack-format-oRExIeD3.d.ts → pack-format-QcVFxG_b.d.ts} +100 -1
- package/dist/pack.d.ts +1 -1
- package/dist/{pipeline-AAfohoHU.js → pipeline-BUIMzMzg.js} +4 -4
- 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-UKgVb-kW.js → run-BQJkqc5f.js} +2 -2
- package/dist/run.js +1 -1
- package/dist/versions/prepare.js +1 -1
- package/dist/workers/render-worker.js +2 -2
- package/package.json +1 -1
- package/dist/{descriptor-D7VKgeGT.js → descriptor-JyXhfd-c.js} +1 -1
- package/dist/{face-CMJ3b3Ae.js → face-B2JjWT46.js} +1 -1
- package/dist/{prepare-8LswFoS-.js → prepare-D49Gu4Lv.js} +1 -1
- 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-_EZ3PVtN.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-
|
|
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 {
|
|
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,
|
|
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-B8tPsf4K.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
|
|
9
|
-
import {
|
|
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-
|
|
17
|
+
import { t as exportBlockPack } from "./export-BfEIwSxY.js";
|
|
18
18
|
import { n as UnsafeJarError, r as isUnsafeEntryPath, t as JarResourceManager } from "./jar-W2cV2ZVO.js";
|
|
19
|
-
import { n as prepareModResources } from "./prepare-
|
|
20
|
-
import { a as prepareVersionResources, i as eraForVersion, r as compareVersions } from "./prepare-
|
|
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-
|
|
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-Bo7FUrrD.js";
|
|
2
|
+
import { i as mergeModels } from "./merge-NDYxpmL8.js";
|
|
3
|
+
import { t as extractModel } from "./model-bytecode-gWy5_uCj.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,41 @@
|
|
|
1
|
+
//#region src/entities/jar-classes.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Reading `.class` entries out of a jar.
|
|
4
|
+
*
|
|
5
|
+
* `JarResourceManager` deliberately indexes only `assets/` and `data/` — it is a *resource* manager,
|
|
6
|
+
* and a class file is not a resource. But entity geometry lives in the code (see
|
|
7
|
+
* `docs/entity-geometry.md`), so the extractor needs the other half of the archive, and it needs it
|
|
8
|
+
* by internal class name rather than by resource locator.
|
|
9
|
+
*
|
|
10
|
+
* Same shape as the resource manager for the same reason: index the central directory once, then read
|
|
11
|
+
* entries on demand. A client jar holds around eight thousand classes and the extractor touches a
|
|
12
|
+
* hundred of them.
|
|
13
|
+
*/
|
|
14
|
+
/** What the extractor reads code out of: one jar, or several layered into one view. */
|
|
15
|
+
interface ClassSource {
|
|
16
|
+
list: () => Promise<string[]>;
|
|
17
|
+
read: (internalName: string) => Promise<Uint8Array | null>;
|
|
18
|
+
close: () => Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Several jars as one class view, first match winning — the same layering the resource managers use.
|
|
22
|
+
*
|
|
23
|
+
* A modded export needs this, and needed it before cross-jar linking did: the class source used to be
|
|
24
|
+
* the client jar alone, so a mod's own model classes were never read and its mobs came out as boxes
|
|
25
|
+
* however good the interpreter was. Layered, one view holds both, which is also what lets a mod entity
|
|
26
|
+
* link to a *vanilla* model — `ars_nouveau:summon_horse` is the game's own horse.
|
|
27
|
+
*/
|
|
28
|
+
declare function layeredClasses(sources: readonly ClassSource[]): ClassSource;
|
|
29
|
+
/** Reads class files out of one jar, by internal name. */
|
|
30
|
+
declare class JarClassReader {
|
|
31
|
+
private readonly jarPath;
|
|
32
|
+
private index;
|
|
33
|
+
constructor(jarPath: string);
|
|
34
|
+
private getIndex;
|
|
35
|
+
/** Every class in the jar, for a sweep that does not know what it is looking for. */
|
|
36
|
+
list(): Promise<string[]>;
|
|
37
|
+
read(internalName: string): Promise<Uint8Array | null>;
|
|
38
|
+
close(): Promise<void>;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { JarClassReader as n, layeredClasses as r, ClassSource as t };
|
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
/**
|
|
17
|
+
* Several jars as one class view, first match winning — the same layering the resource managers use.
|
|
18
|
+
*
|
|
19
|
+
* A modded export needs this, and needed it before cross-jar linking did: the class source used to be
|
|
20
|
+
* the client jar alone, so a mod's own model classes were never read and its mobs came out as boxes
|
|
21
|
+
* however good the interpreter was. Layered, one view holds both, which is also what lets a mod entity
|
|
22
|
+
* link to a *vanilla* model — `ars_nouveau:summon_horse` is the game's own horse.
|
|
23
|
+
*/
|
|
24
|
+
function layeredClasses(sources) {
|
|
25
|
+
return {
|
|
26
|
+
list: async () => {
|
|
27
|
+
const names = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const source of sources) for (const name of await source.list()) names.add(name);
|
|
29
|
+
return [...names];
|
|
30
|
+
},
|
|
31
|
+
read: async (internalName) => {
|
|
32
|
+
for (const source of sources) {
|
|
33
|
+
const bytes = await source.read(internalName);
|
|
34
|
+
if (bytes) return bytes;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
},
|
|
38
|
+
close: async () => {
|
|
39
|
+
for (const source of sources) await source.close();
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Reads class files out of one jar, by internal name. */
|
|
44
|
+
var JarClassReader = class {
|
|
45
|
+
jarPath;
|
|
46
|
+
index = null;
|
|
47
|
+
constructor(jarPath) {
|
|
48
|
+
this.jarPath = jarPath;
|
|
49
|
+
}
|
|
50
|
+
getIndex() {
|
|
51
|
+
this.index ??= (async () => {
|
|
52
|
+
const zip = await openZip(this.jarPath);
|
|
53
|
+
return await new Promise((resolve, reject) => {
|
|
54
|
+
const entries = /* @__PURE__ */ new Map();
|
|
55
|
+
zip.on("entry", (entry) => {
|
|
56
|
+
if (isUnsafeEntryPath(entry.fileName)) {
|
|
57
|
+
zip.close();
|
|
58
|
+
reject(new UnsafeJarError(`Unsafe entry in ${this.jarPath}: ${entry.fileName}`));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (entry.fileName.endsWith(".class")) entries.set(entry.fileName.slice(0, -6), entry);
|
|
62
|
+
zip.readEntry();
|
|
63
|
+
});
|
|
64
|
+
zip.on("end", () => resolve({
|
|
65
|
+
zip,
|
|
66
|
+
entries
|
|
67
|
+
}));
|
|
68
|
+
zip.on("error", reject);
|
|
69
|
+
zip.readEntry();
|
|
70
|
+
});
|
|
71
|
+
})();
|
|
72
|
+
return this.index;
|
|
73
|
+
}
|
|
74
|
+
/** Every class in the jar, for a sweep that does not know what it is looking for. */
|
|
75
|
+
async list() {
|
|
76
|
+
return (await this.getIndex()).entries.keys().toArray();
|
|
77
|
+
}
|
|
78
|
+
async read(internalName) {
|
|
79
|
+
const index = await this.getIndex();
|
|
80
|
+
const entry = index.entries.get(internalName.replaceAll(".", "/"));
|
|
81
|
+
if (!entry) return null;
|
|
82
|
+
return await new Promise((resolve, reject) => {
|
|
83
|
+
index.zip.openReadStream(entry, (err, stream) => {
|
|
84
|
+
if (err) {
|
|
85
|
+
reject(err);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const chunks = [];
|
|
89
|
+
stream.on("data", (chunk) => {
|
|
90
|
+
chunks.push(chunk);
|
|
91
|
+
});
|
|
92
|
+
stream.on("end", () => resolve(new Uint8Array(Buffer.concat(chunks))));
|
|
93
|
+
stream.on("error", reject);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async close() {
|
|
98
|
+
if (this.index) (await this.index).zip.close();
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
//#endregion
|
|
102
|
+
export { layeredClasses as n, JarClassReader as t };
|