@nodecraft/rendermite 1.4.0 → 1.5.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 +1 -0
- package/dist/blocks/cli.js +1 -1
- 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/{cli-DqJtT-Ms.js → cli-DMTaIbDI.js} +9 -2
- package/dist/cli.js +3 -3
- package/dist/{discovery-CsZu08re.js → discovery-CD0QqxSF.js} +1 -1
- package/dist/{discovery-C5ZR4aoG.d.ts → discovery-Cmir3QfC.d.ts} +8 -1
- package/dist/{entity-fallback-BTkM8j0V.js → entity-fallback-DutR9Hdz.js} +1 -1
- package/dist/{export-kMoMes_a.js → export-sadR0pWp.js} +90 -160
- package/dist/{export-Bllg8Fw7.d.ts → export-wvt0Fryo.d.ts} +9 -1
- package/dist/{geo-BguldlU-.js → geo-BC8jtG5Q.js} +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- 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/mods/prepare.js +1 -1
- package/dist/mods/tints.js +1 -1
- package/dist/{obj-bvs3gwex.js → obj-BaGvPUbb.js} +3 -3
- package/dist/{obj-mesh-rnYbSbpv.js → obj-mesh-CazmV8ya.js} +1 -1
- package/dist/{pack-format-BVC_B-ZW.d.ts → pack-format-oRExIeD3.d.ts} +42 -1
- package/dist/pack.d.ts +1 -1
- package/dist/{pipeline-B8e6x8Hh.js → pipeline-AAfohoHU.js} +7 -7
- package/dist/{prepare-C9gjqQTt.js → prepare-B_tRy9lB.js} +1 -1
- package/dist/render/entity-fallback.js +1 -1
- package/dist/render/face.js +1 -1
- package/dist/render/geo.js +1 -1
- package/dist/render/obj.js +1 -1
- package/dist/render/pipeline.js +1 -1
- package/dist/render/renderer.js +1 -1
- package/dist/{run-B_JAUbXe.js → run-UKgVb-kW.js} +2 -2
- package/dist/run.js +1 -1
- package/dist/sprite-sheet-LQAEtGkp.js +185 -0
- package/dist/workers/render-worker.js +1 -1
- package/package.json +1 -1
- package/dist/{face-CKHboPfh.js → face-CMJ3b3Ae.js} +1 -1
- package/dist/{tints-C1tT6pKk.js → tints-BspVCz2G.js} +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,7 @@ blocks/1.21.8/
|
|
|
75
75
|
blockstates.json # block id -> variants/multipart, keys and predicates pre-parsed
|
|
76
76
|
tints.json # plains tints, colormaps, ramps, per-block tint semantics
|
|
77
77
|
colormap/*.png # the version's own grass/foliage/dry_foliage maps
|
|
78
|
+
items.json # flat item sprite stacks + their own atlas, for drawing dropped stacks
|
|
78
79
|
failures.json # anything not fully handled, with reasons, never silent
|
|
79
80
|
meta.json # version, counts, sha256 of every other file
|
|
80
81
|
```
|
package/dist/blocks/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as runBlocksCli } from "../cli-
|
|
1
|
+
import { t as runBlocksCli } from "../cli-DMTaIbDI.js";
|
|
2
2
|
export { runBlocksCli };
|
package/dist/blocks/export.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "../export-
|
|
1
|
+
import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "../export-wvt0Fryo.js";
|
|
2
2
|
export { BlockPackFailure, BlockPackResult, ExportBlockPackOptions, exportBlockPack };
|
package/dist/blocks/export.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as exportBlockPack } from "../export-
|
|
1
|
+
import { t as exportBlockPack } from "../export-sadR0pWp.js";
|
|
2
2
|
export { exportBlockPack };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { a as ResourceManager } from "../manager-exOIcdyx.js";
|
|
2
|
+
import { i as TextureLoader } from "../loader-DUlx29PC.js";
|
|
3
|
+
import { t as ModelLoader } from "../loader-DSir1-P0.js";
|
|
4
|
+
import { _ as ItemPackEntry } from "../pack-format-oRExIeD3.js";
|
|
5
|
+
//#region src/blocks/item-sprites.d.ts
|
|
6
|
+
interface ItemSpriteFailure {
|
|
7
|
+
id: string;
|
|
8
|
+
reason: string;
|
|
9
|
+
}
|
|
10
|
+
interface ItemSpriteResult {
|
|
11
|
+
/** Flat items only, by item id; anything absent is the consumer's block-model job. */
|
|
12
|
+
items: Record<string, ItemPackEntry>;
|
|
13
|
+
/** Sprite ids to pack, which is every layer of every entry. */
|
|
14
|
+
spriteIds: Set<string>;
|
|
15
|
+
failures: ItemSpriteFailure[];
|
|
16
|
+
}
|
|
17
|
+
interface CollectItemSpritesOptions {
|
|
18
|
+
resources: ResourceManager;
|
|
19
|
+
models: ModelLoader;
|
|
20
|
+
textures: TextureLoader;
|
|
21
|
+
namespaces: readonly string[];
|
|
22
|
+
/**
|
|
23
|
+
* Ids the pack describes as blocks. Only used to decide whether a non-flat item
|
|
24
|
+
* is worth reporting: a stone block item drawing from `blockstates.json` is the
|
|
25
|
+
* design, while one nothing describes is a gap somebody should hear about.
|
|
26
|
+
*/
|
|
27
|
+
blocks: ReadonlySet<string>;
|
|
28
|
+
/** Item ids to consider, as `discoverItems` yields them. */
|
|
29
|
+
itemIds: readonly string[];
|
|
30
|
+
onProgress?: (done: number, total: number) => void;
|
|
31
|
+
}
|
|
32
|
+
declare function collectItemSprites(options: CollectItemSpritesOptions): Promise<ItemSpriteResult>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { CollectItemSpritesOptions, ItemSpriteFailure, ItemSpriteResult, collectItemSprites };
|
package/dist/blocks/obj-mesh.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as buildObjMesh, t as ObjMeshError } from "../obj-mesh-
|
|
1
|
+
import { n as buildObjMesh, t as ObjMeshError } from "../obj-mesh-CazmV8ya.js";
|
|
2
2
|
export { ObjMeshError, buildObjMesh };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as BlockPackBlockStatesFile, c as
|
|
2
|
-
export { BlockPackAtlasFile, BlockPackAtlasPage, BlockPackBiomesFile, BlockPackBlockState, BlockPackBlockStatesFile, BlockPackElement, BlockPackFace, BlockPackMetaFile, BlockPackModel, BlockPackModelsFile, BlockPackRenderLayer, BlockPackSprite, BlockPackSpriteFrame, BlockPackTintsFile, BlockPackVariant };
|
|
1
|
+
import { _ as ItemPackEntry, a as BlockPackBlockStatesFile, c as BlockPackItemsFile, d as BlockPackModelsFile, f as BlockPackRenderLayer, g as BlockPackVariant, h as BlockPackTintsFile, i as BlockPackBlockState, l as BlockPackMetaFile, m as BlockPackSpriteFrame, n as BlockPackAtlasPage, o as BlockPackElement, p as BlockPackSprite, r as BlockPackBiomesFile, s as BlockPackFace, t as BlockPackAtlasFile, u as BlockPackModel, v as ItemPackLayer } from "../pack-format-oRExIeD3.js";
|
|
2
|
+
export { BlockPackAtlasFile, BlockPackAtlasPage, BlockPackBiomesFile, BlockPackBlockState, BlockPackBlockStatesFile, BlockPackElement, BlockPackFace, BlockPackItemsFile, BlockPackMetaFile, BlockPackModel, BlockPackModelsFile, BlockPackRenderLayer, BlockPackSprite, BlockPackSpriteFrame, BlockPackTintsFile, BlockPackVariant, ItemPackEntry, ItemPackLayer };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { i as TextureLoader, r as Texture } from "../loader-DUlx29PC.js";
|
|
2
|
+
import { i as PackedPage } from "../atlas-pack-D8745_wo.js";
|
|
3
|
+
import { f as BlockPackRenderLayer, p as BlockPackSprite } from "../pack-format-oRExIeD3.js";
|
|
4
|
+
//#region src/blocks/sprite-sheet.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Vanilla's own id for the missing-texture sprite. A face whose texture does
|
|
7
|
+
* not resolve is drawn by the game in black and magenta rather than skipped —
|
|
8
|
+
* Blockbench leaves `"texture": "#missing"` on unassigned faces and mods ship
|
|
9
|
+
* models naming textures they forgot to include. Dropping those faces would
|
|
10
|
+
* put holes in geometry the player can see, and would read as our bug rather
|
|
11
|
+
* than the mod's.
|
|
12
|
+
*/
|
|
13
|
+
declare const MISSING_SPRITE = "minecraft:missingno";
|
|
14
|
+
/** `MissingTextureAtlasSprite`: 16x16, black and magenta in 8px quarters. */
|
|
15
|
+
declare function missingTexture(): Texture;
|
|
16
|
+
/**
|
|
17
|
+
* Alpha decides the render layer: vanilla assets do not state cutout versus
|
|
18
|
+
* translucent (`render_type` is a loader extension adopted only recently), and
|
|
19
|
+
* inferring it covers mods for free.
|
|
20
|
+
*/
|
|
21
|
+
declare function inferRenderLayer(frames: Texture[]): BlockPackRenderLayer;
|
|
22
|
+
interface SpriteSheetFailure {
|
|
23
|
+
id: string;
|
|
24
|
+
reason: string;
|
|
25
|
+
}
|
|
26
|
+
interface BuildSpriteSheetOptions {
|
|
27
|
+
/** Edge-extended border per sprite side (default 4). */
|
|
28
|
+
padding?: number;
|
|
29
|
+
/** Ceiling on a page's dimensions (default 4096). */
|
|
30
|
+
maxPageSize?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Pack the black-and-magenta missing-texture sprite whether or not anything
|
|
33
|
+
* named it, and throw if it does not fit. What a consumer draws for something
|
|
34
|
+
* this pack does not describe at all; a guarantee worth its 256 pixels.
|
|
35
|
+
*/
|
|
36
|
+
includeMissing?: boolean;
|
|
37
|
+
onProgress?: (done: number, total: number) => void;
|
|
38
|
+
}
|
|
39
|
+
interface SpriteSheet {
|
|
40
|
+
pages: PackedPage[];
|
|
41
|
+
/** Ready for `atlas.json`, unsorted — the caller decides the key order. */
|
|
42
|
+
sprites: Record<string, BlockPackSprite>;
|
|
43
|
+
/**
|
|
44
|
+
* Ids that never loaded or never fit a page, so have no rect. A caller must
|
|
45
|
+
* not emit anything naming one of these; the block path rewrites those
|
|
46
|
+
* references to `MISSING_SPRITE`, and the item path drops the item.
|
|
47
|
+
*/
|
|
48
|
+
missing: Set<string>;
|
|
49
|
+
failures: SpriteSheetFailure[];
|
|
50
|
+
padding: number;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Loads every id, packs the frames, and returns the sheet plus everything that
|
|
54
|
+
* did not make it. Ids are packed in sorted order so an unchanged input produces
|
|
55
|
+
* a byte-identical atlas.
|
|
56
|
+
*/
|
|
57
|
+
declare function buildSpriteSheet(ids: Iterable<string>, textures: TextureLoader, options?: BuildSpriteSheetOptions): Promise<SpriteSheet>;
|
|
58
|
+
//#endregion
|
|
59
|
+
export { BuildSpriteSheetOptions, MISSING_SPRITE, SpriteSheet, SpriteSheetFailure, buildSpriteSheet, inferRenderLayer, missingTexture };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as builtinPackPath } from "./builtin-WkWjATeh.js";
|
|
2
2
|
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-BNibYkmI.js";
|
|
3
|
-
import { t as exportBlockPack } from "./export-
|
|
4
|
-
import { n as prepareModResources } from "./prepare-
|
|
3
|
+
import { t as exportBlockPack } from "./export-sadR0pWp.js";
|
|
4
|
+
import { n as prepareModResources } from "./prepare-B_tRy9lB.js";
|
|
5
5
|
import { t as downloadClientJar } from "./download-1wAfrGKx.js";
|
|
6
6
|
import { a as prepareVersionResources, r as compareVersions } from "./prepare-8LswFoS-.js";
|
|
7
7
|
import path from "node:path";
|
|
@@ -34,6 +34,7 @@ Options:
|
|
|
34
34
|
--max-page-size <px> atlas page ceiling (default 4096)
|
|
35
35
|
--builtin <dir> override the vendored geometry pack
|
|
36
36
|
--no-builtin do not substitute geometry for code-drawn blocks
|
|
37
|
+
--no-items do not export items.json (flat sprites for non-block items)
|
|
37
38
|
--cache-dir <dir> jar download cache (default ~/.rendermite)
|
|
38
39
|
`;
|
|
39
40
|
/**
|
|
@@ -93,6 +94,10 @@ async function runBlocksCli(argv) {
|
|
|
93
94
|
type: "boolean",
|
|
94
95
|
default: false
|
|
95
96
|
},
|
|
97
|
+
"no-items": {
|
|
98
|
+
type: "boolean",
|
|
99
|
+
default: false
|
|
100
|
+
},
|
|
96
101
|
"help": {
|
|
97
102
|
type: "boolean",
|
|
98
103
|
short: "h",
|
|
@@ -146,11 +151,13 @@ async function runBlocksCli(argv) {
|
|
|
146
151
|
namespaces,
|
|
147
152
|
padding: sizes.padding,
|
|
148
153
|
maxPageSize: sizes.maxPageSize,
|
|
154
|
+
items: !values["no-items"],
|
|
149
155
|
onProgress: (stage, done, total) => {
|
|
150
156
|
if (done === total || done % 250 === 0) console.log(`${stage}: ${done}/${total}`);
|
|
151
157
|
}
|
|
152
158
|
});
|
|
153
159
|
console.log(`\n${result.blocks} blocks, ${result.models} models, ${result.sprites} sprites across ${result.pages} atlas page(s); ${result.writtenFiles} files written.`);
|
|
160
|
+
console.log(result.items > 0 ? `${result.items} flat items described in items.json.` : "No flat item sprites exported.");
|
|
154
161
|
console.log(result.biomes > 0 ? `${result.biomes} biomes described in biomes.json.` : "No biomes to describe; biomes.json not written.");
|
|
155
162
|
console.log(`${result.failures.length} entries in failures.json.`);
|
|
156
163
|
return 0;
|
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-WkWjATeh.js";
|
|
3
3
|
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-BNibYkmI.js";
|
|
4
4
|
import { t as curatedModelOverrides } from "./models-CZjCOjs4.js";
|
|
5
|
-
import { n as harvestTintOverrides, t as curatedTintOverrides } from "./tints-
|
|
5
|
+
import { n as harvestTintOverrides, t as curatedTintOverrides } from "./tints-BspVCz2G.js";
|
|
6
6
|
import { t as JarResourceManager } from "./jar-W2cV2ZVO.js";
|
|
7
7
|
import { t as downloadClientJar } from "./download-1wAfrGKx.js";
|
|
8
8
|
import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-8LswFoS-.js";
|
|
9
|
-
import { t as runBlocksCli } from "./cli-
|
|
10
|
-
import { t as run } from "./run-
|
|
9
|
+
import { t as runBlocksCli } from "./cli-DMTaIbDI.js";
|
|
10
|
+
import { t as run } from "./run-UKgVb-kW.js";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import os from "node:os";
|
|
13
13
|
import { parseArgs } from "node:util";
|
|
@@ -99,4 +99,4 @@ async function resolveItem(resources, id, properties) {
|
|
|
99
99
|
throw new ItemResolutionError(`No item definition or item model for ${id}`);
|
|
100
100
|
}
|
|
101
101
|
//#endregion
|
|
102
|
-
export { discoverItems as n,
|
|
102
|
+
export { resolveItem as i, discoverItems as n, langRegistry as r, ItemResolutionError as t };
|
|
@@ -17,6 +17,13 @@ interface ItemDiscoveryOptions {
|
|
|
17
17
|
filterUntranslatedModels?: boolean;
|
|
18
18
|
}
|
|
19
19
|
declare function discoverItems(resources: ResourceManager, namespace: string, options?: ItemDiscoveryOptions): Promise<DiscoveredItem[]>;
|
|
20
|
+
/**
|
|
21
|
+
* Item/block names with a translation key in the namespace's en_us.json — the
|
|
22
|
+
* closest thing to the game's item registry a jar contains (datagen writes a
|
|
23
|
+
* key per registered item). Null (no gating) when the namespace has no modern
|
|
24
|
+
* lang file or no item/block keys: 1.7.10-era mods use unkeyed .lang files.
|
|
25
|
+
*/
|
|
26
|
+
declare function langRegistry(resources: ResourceManager, namespace: string): Promise<Set<string> | null>;
|
|
20
27
|
/**
|
|
21
28
|
* Resolve an item id to the models to render. Definitions are evaluated with
|
|
22
29
|
* static-icon properties; plain model items render the model with no tints
|
|
@@ -24,4 +31,4 @@ declare function discoverItems(resources: ResourceManager, namespace: string, op
|
|
|
24
31
|
*/
|
|
25
32
|
declare function resolveItem(resources: ResourceManager, id: string, properties?: ItemProperties): Promise<ItemRenderInstruction[]>;
|
|
26
33
|
//#endregion
|
|
27
|
-
export {
|
|
34
|
+
export { langRegistry as a, discoverItems as i, ItemDiscoveryOptions as n, resolveItem as o, ItemResolutionError as r, DiscoveredItem as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as ResourceLocator } from "./locator-COMEtEn9.js";
|
|
2
2
|
import { a as findChestTexture, i as findBedTexture, l as findMobTexture, n as HEAD_LAYOUTS, o as findEntityTexture, r as coversSheet, t as DYE_COLORS, u as tokens } from "./entity-textures-DFRIVdF1.js";
|
|
3
|
-
import { c as renderModel } from "./obj-
|
|
3
|
+
import { c as renderModel } from "./obj-BaGvPUbb.js";
|
|
4
4
|
//#region src/render/entity-fallback.ts
|
|
5
5
|
/**
|
|
6
6
|
* Heuristic rendering for mod items that parent `builtin/entity` — chests,
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { t as packAtlas } from "./atlas-pack-CoOih7By.js";
|
|
2
1
|
import { r as buildBiomeClimates } from "./biomes-5ZwYxMYe.js";
|
|
3
2
|
import { n as ResourceLocator } from "./locator-COMEtEn9.js";
|
|
4
3
|
import { n as blockEntityGeometry, r as synthesizeVariants, t as INVISIBLE_BLOCKS } from "./block-entities-xv3bQpEX.js";
|
|
5
4
|
import { a as parseBlockState, n as collectModels } from "./blockstate-eval-BRQ3NWY2.js";
|
|
5
|
+
import { n as discoverItems } from "./discovery-CD0QqxSF.js";
|
|
6
6
|
import { a as salvageJson, i as resolveTexture, t as ModelLoader } from "./loader-C-NuJaEi.js";
|
|
7
|
-
import {
|
|
7
|
+
import { t as collectItemSprites } from "./item-sprites-G-yikdfV.js";
|
|
8
|
+
import { n as buildObjMesh } from "./obj-mesh-CazmV8ya.js";
|
|
9
|
+
import { n as buildSpriteSheet, t as MISSING_SPRITE } from "./sprite-sheet-LQAEtGkp.js";
|
|
8
10
|
import { n as buildBlockTints, t as UNREGISTERED_TINTS } from "./tints-Cl0r-Ol3.js";
|
|
9
11
|
import { t as loadAtlasResolver } from "./registry-DlduyjtM.js";
|
|
10
12
|
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-BNibYkmI.js";
|
|
@@ -37,12 +39,6 @@ const RENDER_TYPES = {
|
|
|
37
39
|
translucent: "translucent",
|
|
38
40
|
translucent_moving_block: "translucent"
|
|
39
41
|
};
|
|
40
|
-
/**
|
|
41
|
-
* A sprite whose strip is longer than this exports as its first frame only.
|
|
42
|
-
* A broken `.mcmeta` can claim thousands of frames, and packing them would
|
|
43
|
-
* blow the atlas out for one texture.
|
|
44
|
-
*/
|
|
45
|
-
const MAX_FRAMES_PER_SPRITE = 256;
|
|
46
42
|
const FACE_DIRECTIONS = /* @__PURE__ */ new Set([
|
|
47
43
|
"down",
|
|
48
44
|
"up",
|
|
@@ -57,15 +53,6 @@ const CULLFACE_ALIASES = {
|
|
|
57
53
|
top: "up"
|
|
58
54
|
};
|
|
59
55
|
/**
|
|
60
|
-
* Vanilla's own id for the missing-texture sprite. A face whose texture does
|
|
61
|
-
* not resolve is drawn by the game in black and magenta rather than skipped —
|
|
62
|
-
* Blockbench leaves `"texture": "#missing"` on unassigned faces and mods ship
|
|
63
|
-
* models naming textures they forgot to include. Dropping those faces would
|
|
64
|
-
* put holes in geometry the player can see, and would read as our bug rather
|
|
65
|
-
* than the mod's.
|
|
66
|
-
*/
|
|
67
|
-
const MISSING_SPRITE = "minecraft:missingno";
|
|
68
|
-
/**
|
|
69
56
|
* Fluids are blocks in `blockstates.json` but the game meshes them in code, so
|
|
70
57
|
* their models state nothing and their textures would otherwise never reach the
|
|
71
58
|
* atlas — leaving a consumer that has to mesh fluids itself with no pixels to do
|
|
@@ -80,24 +67,6 @@ const MISSING_SPRITE = "minecraft:missingno";
|
|
|
80
67
|
const FLUID_SUFFIX = /_(?:still|flow|flowing)$/;
|
|
81
68
|
/** Sampled where water meets a non-opaque neighbour; matches no suffix. */
|
|
82
69
|
const EXTRA_FLUID_SPRITES = ["minecraft:block/water_overlay"];
|
|
83
|
-
/** `MissingTextureAtlasSprite`: 16x16, black and magenta in 8px quarters. */
|
|
84
|
-
function missingTexture() {
|
|
85
|
-
const size = 16;
|
|
86
|
-
const data = /* @__PURE__ */ new Uint8ClampedArray(1024);
|
|
87
|
-
for (let y = 0; y < size; y++) for (let x = 0; x < size; x++) {
|
|
88
|
-
const magenta = x < 8 !== y < 8;
|
|
89
|
-
const offset = (y * size + x) * 4;
|
|
90
|
-
data[offset] = magenta ? 248 : 0;
|
|
91
|
-
data[offset + 1] = 0;
|
|
92
|
-
data[offset + 2] = magenta ? 248 : 0;
|
|
93
|
-
data[offset + 3] = 255;
|
|
94
|
-
}
|
|
95
|
-
return {
|
|
96
|
-
width: size,
|
|
97
|
-
height: size,
|
|
98
|
-
data
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
70
|
/**
|
|
102
71
|
* Vanilla's `BlockElement.uvsByFace`: the UV a face gets when the model states
|
|
103
72
|
* none. Deliberately not `render/geometry.ts`'s auto-UVs — those are in the
|
|
@@ -144,20 +113,6 @@ function defaultFaceUv(direction, from, to) {
|
|
|
144
113
|
];
|
|
145
114
|
}
|
|
146
115
|
}
|
|
147
|
-
/**
|
|
148
|
-
* Alpha decides the render layer: vanilla assets do not state cutout versus
|
|
149
|
-
* translucent (`render_type` is a loader extension adopted only recently), and
|
|
150
|
-
* inferring it covers mods for free.
|
|
151
|
-
*/
|
|
152
|
-
function inferRenderLayer(frames) {
|
|
153
|
-
let sawHole = false;
|
|
154
|
-
for (const frame of frames) for (let offset = 3; offset < frame.data.length; offset += 4) {
|
|
155
|
-
const alpha = frame.data[offset];
|
|
156
|
-
if (alpha === 0) sawHole = true;
|
|
157
|
-
else if (alpha !== 255) return "translucent";
|
|
158
|
-
}
|
|
159
|
-
return sawHole ? "cutout" : "solid";
|
|
160
|
-
}
|
|
161
116
|
function sortedByKey(entries) {
|
|
162
117
|
return Object.fromEntries(Object.entries(entries).toSorted(([left], [right]) => left.localeCompare(right)));
|
|
163
118
|
}
|
|
@@ -261,7 +216,7 @@ async function itemModelSubstitute(blockId, resources, models) {
|
|
|
261
216
|
}
|
|
262
217
|
const { emitted, sprites, tintIndices } = bakeModel(item.toString(), resolved, []);
|
|
263
218
|
if (emitted.elements.length === 0) return null;
|
|
264
|
-
if ((await Promise.all([...sprites].map(async (sprite) => sprite !==
|
|
219
|
+
if ((await Promise.all([...sprites].map(async (sprite) => sprite !== "minecraft:missingno" && await resources.hasResource("texture", ResourceLocator.parse(sprite))))).includes(false)) return null;
|
|
265
220
|
return {
|
|
266
221
|
id: item.toString(),
|
|
267
222
|
emitted,
|
|
@@ -493,7 +448,7 @@ async function exportBlockPack(options) {
|
|
|
493
448
|
const substituteId = `rendermite:block/${ResourceLocator.parse(id).path}${suffix && `_${suffix}`}`;
|
|
494
449
|
const { emitted, sprites, tintIndices } = bakeModel(substituteId, bound, failures);
|
|
495
450
|
if (emitted.elements.length === 0) continue;
|
|
496
|
-
if ((await Promise.all([...sprites].map(async (sprite) => sprite !==
|
|
451
|
+
if ((await Promise.all([...sprites].map(async (sprite) => sprite !== "minecraft:missingno" && await resources.hasResource("texture", ResourceLocator.parse(sprite))))).includes(false)) {
|
|
497
452
|
failures.push({
|
|
498
453
|
id,
|
|
499
454
|
kind: "geometry",
|
|
@@ -618,87 +573,20 @@ async function exportBlockPack(options) {
|
|
|
618
573
|
}
|
|
619
574
|
for (const namespace of namespaces) for (const locator of await resources.listResources("texture", namespace)) if (FLUID_SUFFIX.test(locator.path)) spriteIds.add(locator.toString());
|
|
620
575
|
for (const extra of EXTRA_FLUID_SPRITES) if (await resources.hasResource("texture", ResourceLocator.parse(extra))) spriteIds.add(extra);
|
|
621
|
-
const
|
|
622
|
-
const missingSprites = /* @__PURE__ */ new Set();
|
|
623
|
-
done = 0;
|
|
624
|
-
for (const id of [...spriteIds].toSorted((left, right) => left.localeCompare(right))) {
|
|
625
|
-
report("sprites", ++done, spriteIds.size);
|
|
626
|
-
if (id === MISSING_SPRITE) continue;
|
|
627
|
-
let animated;
|
|
628
|
-
try {
|
|
629
|
-
animated = await textures.loadAnimated(ResourceLocator.parse(id));
|
|
630
|
-
} catch (err) {
|
|
631
|
-
failures.push({
|
|
632
|
-
id,
|
|
633
|
-
kind: "sprite",
|
|
634
|
-
reason: err.message
|
|
635
|
-
});
|
|
636
|
-
missingSprites.add(id);
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (!animated) {
|
|
640
|
-
failures.push({
|
|
641
|
-
id,
|
|
642
|
-
kind: "sprite",
|
|
643
|
-
reason: "texture not found"
|
|
644
|
-
});
|
|
645
|
-
missingSprites.add(id);
|
|
646
|
-
continue;
|
|
647
|
-
}
|
|
648
|
-
const overlong = animated.frameCount > MAX_FRAMES_PER_SPRITE;
|
|
649
|
-
if (overlong) failures.push({
|
|
650
|
-
id,
|
|
651
|
-
kind: "sprite",
|
|
652
|
-
reason: `${animated.frameCount} frames exceeds the ${MAX_FRAMES_PER_SPRITE} cap; exported static`
|
|
653
|
-
});
|
|
654
|
-
const starts = overlong ? [0] : animated.frameStartTicks();
|
|
655
|
-
const total = overlong ? 1 : animated.tickLength;
|
|
656
|
-
const sequence = starts.map((start, index) => {
|
|
657
|
-
return {
|
|
658
|
-
frame: animated.resolveFrame(start).frame,
|
|
659
|
-
time: (index + 1 < starts.length ? starts[index + 1] : total) - start
|
|
660
|
-
};
|
|
661
|
-
});
|
|
662
|
-
const frames = /* @__PURE__ */ new Map();
|
|
663
|
-
for (const entry of sequence) if (!frames.has(entry.frame)) frames.set(entry.frame, animated.frame(entry.frame));
|
|
664
|
-
loaded.push({
|
|
665
|
-
id,
|
|
666
|
-
frames,
|
|
667
|
-
sequence,
|
|
668
|
-
interpolate: animated.interpolated
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
spriteIds.add(MISSING_SPRITE);
|
|
672
|
-
loaded.push({
|
|
673
|
-
id: MISSING_SPRITE,
|
|
674
|
-
frames: /* @__PURE__ */ new Map([[0, missingTexture()]]),
|
|
675
|
-
sequence: [{
|
|
676
|
-
frame: 0,
|
|
677
|
-
time: 1
|
|
678
|
-
}],
|
|
679
|
-
interpolate: false
|
|
680
|
-
});
|
|
681
|
-
const packed = packAtlas(loaded.flatMap((sprite) => [...sprite.frames].map(([index, texture]) => {
|
|
682
|
-
return {
|
|
683
|
-
key: `${sprite.id}#${index}`,
|
|
684
|
-
texture
|
|
685
|
-
};
|
|
686
|
-
})), {
|
|
576
|
+
const sheet = await buildSpriteSheet(spriteIds, textures, {
|
|
687
577
|
padding: options.padding,
|
|
688
|
-
maxPageSize: options.maxPageSize
|
|
578
|
+
maxPageSize: options.maxPageSize,
|
|
579
|
+
includeMissing: true,
|
|
580
|
+
onProgress: (count, total) => report("sprites", count, total)
|
|
689
581
|
});
|
|
690
|
-
for (const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
missingSprites.add(id);
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
if (missingSprites.has(MISSING_SPRITE)) throw new Error("the missing-texture sprite does not fit an atlas page; maxPageSize is too small");
|
|
582
|
+
for (const failure of sheet.failures) failures.push({
|
|
583
|
+
id: failure.id,
|
|
584
|
+
kind: "sprite",
|
|
585
|
+
reason: failure.reason
|
|
586
|
+
});
|
|
587
|
+
const emittedSprites = sheet.sprites;
|
|
588
|
+
const missingSprites = sheet.missing;
|
|
589
|
+
spriteIds.add(MISSING_SPRITE);
|
|
702
590
|
if (missingSprites.size > 0) for (const model of Object.values(emittedModels)) {
|
|
703
591
|
for (const element of model.elements) for (const face of Object.values(element.faces)) if (missingSprites.has(face.sprite)) face.sprite = MISSING_SPRITE;
|
|
704
592
|
for (const group of model.mesh ?? []) if (missingSprites.has(group.sprite)) group.sprite = MISSING_SPRITE;
|
|
@@ -706,7 +594,7 @@ async function exportBlockPack(options) {
|
|
|
706
594
|
}
|
|
707
595
|
for (const [id, model] of Object.entries(emittedModels)) {
|
|
708
596
|
const sprites = [...model.elements.flatMap((element) => Object.values(element.faces).map((face) => face.sprite)), ...(model.mesh ?? []).map((group) => group.sprite)];
|
|
709
|
-
if (sprites.length > 0 && sprites.every((sprite) => sprite ===
|
|
597
|
+
if (sprites.length > 0 && sprites.every((sprite) => sprite === "minecraft:missingno")) failures.push({
|
|
710
598
|
id,
|
|
711
599
|
kind: "texture",
|
|
712
600
|
reason: "every face uses the missing-texture sprite; the model binds none of the textures it names"
|
|
@@ -717,32 +605,6 @@ async function exportBlockPack(options) {
|
|
|
717
605
|
reason: "model has no drawable elements"
|
|
718
606
|
});
|
|
719
607
|
}
|
|
720
|
-
const rects = new Map(packed.rects.map((rect) => [rect.key, rect]));
|
|
721
|
-
const emittedSprites = {};
|
|
722
|
-
for (const sprite of loaded) {
|
|
723
|
-
const first = rects.get(`${sprite.id}#${sprite.sequence[0].frame}`);
|
|
724
|
-
if (!first) continue;
|
|
725
|
-
const frames = [];
|
|
726
|
-
for (const entry of sprite.sequence) {
|
|
727
|
-
const rect = rects.get(`${sprite.id}#${entry.frame}`);
|
|
728
|
-
if (rect) frames.push({
|
|
729
|
-
page: rect.page,
|
|
730
|
-
x: rect.x,
|
|
731
|
-
y: rect.y,
|
|
732
|
-
time: entry.time
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
emittedSprites[sprite.id] = {
|
|
736
|
-
page: first.page,
|
|
737
|
-
x: first.x,
|
|
738
|
-
y: first.y,
|
|
739
|
-
w: first.width,
|
|
740
|
-
h: first.height,
|
|
741
|
-
layer: inferRenderLayer(sprite.frames.values().toArray()),
|
|
742
|
-
...frames.length === sprite.sequence.length && frames.length > 1 && { frames },
|
|
743
|
-
...sprite.interpolate && { interpolate: true }
|
|
744
|
-
};
|
|
745
|
-
}
|
|
746
608
|
const tints = await buildBlockTints(resources, textures);
|
|
747
609
|
for (const [block, references] of blockModels) {
|
|
748
610
|
const used = /* @__PURE__ */ new Set();
|
|
@@ -762,6 +624,64 @@ async function exportBlockPack(options) {
|
|
|
762
624
|
}
|
|
763
625
|
}
|
|
764
626
|
const biomes = await buildBiomeClimates(resources, namespaces);
|
|
627
|
+
let itemPack = null;
|
|
628
|
+
let itemPages = [];
|
|
629
|
+
if (options.items ?? true) {
|
|
630
|
+
const itemIds = [];
|
|
631
|
+
for (const namespace of namespaces) for (const item of await discoverItems(resources, namespace)) itemIds.push(item.id);
|
|
632
|
+
const collected = await collectItemSprites({
|
|
633
|
+
resources,
|
|
634
|
+
models,
|
|
635
|
+
textures,
|
|
636
|
+
namespaces,
|
|
637
|
+
blocks: new Set(Object.keys(blockStates)),
|
|
638
|
+
itemIds,
|
|
639
|
+
onProgress: (count, total) => report("items", count, total)
|
|
640
|
+
});
|
|
641
|
+
for (const failure of collected.failures) failures.push({
|
|
642
|
+
id: failure.id,
|
|
643
|
+
kind: "item",
|
|
644
|
+
reason: failure.reason
|
|
645
|
+
});
|
|
646
|
+
const itemSheet = await buildSpriteSheet(collected.spriteIds, textures, {
|
|
647
|
+
padding: options.padding,
|
|
648
|
+
maxPageSize: options.maxPageSize,
|
|
649
|
+
onProgress: (count, total) => report("item sprites", count, total)
|
|
650
|
+
});
|
|
651
|
+
for (const failure of itemSheet.failures) failures.push({
|
|
652
|
+
id: failure.id,
|
|
653
|
+
kind: "sprite",
|
|
654
|
+
reason: failure.reason
|
|
655
|
+
});
|
|
656
|
+
const items = {};
|
|
657
|
+
for (const [id, entry] of Object.entries(collected.items)) {
|
|
658
|
+
const lost = entry.layers.filter((layer) => itemSheet.missing.has(layer.sprite));
|
|
659
|
+
if (lost.length > 0) {
|
|
660
|
+
failures.push({
|
|
661
|
+
id,
|
|
662
|
+
kind: "item",
|
|
663
|
+
reason: `layer sprite ${lost.map((layer) => layer.sprite).join(", ")} has no atlas rect; item dropped`
|
|
664
|
+
});
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
items[id] = entry;
|
|
668
|
+
}
|
|
669
|
+
if (Object.keys(items).length > 0) {
|
|
670
|
+
itemPages = itemSheet.pages;
|
|
671
|
+
itemPack = {
|
|
672
|
+
padding: itemSheet.padding,
|
|
673
|
+
pages: itemPages.map((page, index) => {
|
|
674
|
+
return {
|
|
675
|
+
file: `item-atlas-${index}.png`,
|
|
676
|
+
width: page.width,
|
|
677
|
+
height: page.height
|
|
678
|
+
};
|
|
679
|
+
}),
|
|
680
|
+
sprites: sortedByKey(itemSheet.sprites),
|
|
681
|
+
items: sortedByKey(items)
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
}
|
|
765
685
|
await mkdir(output, { recursive: true });
|
|
766
686
|
const hashes = {};
|
|
767
687
|
let writtenFiles = 0;
|
|
@@ -774,7 +694,7 @@ async function exportBlockPack(options) {
|
|
|
774
694
|
writtenFiles++;
|
|
775
695
|
};
|
|
776
696
|
const pageFiles = [];
|
|
777
|
-
for (const [index, page] of
|
|
697
|
+
for (const [index, page] of sheet.pages.entries()) {
|
|
778
698
|
const file = `atlas-${index}.png`;
|
|
779
699
|
const raw = Buffer.from(page.data.buffer, page.data.byteOffset, page.data.byteLength);
|
|
780
700
|
await emit(file, await sharp(raw, { raw: {
|
|
@@ -788,9 +708,18 @@ async function exportBlockPack(options) {
|
|
|
788
708
|
height: page.height
|
|
789
709
|
});
|
|
790
710
|
}
|
|
711
|
+
for (const [index, page] of itemPages.entries()) {
|
|
712
|
+
const raw = Buffer.from(page.data.buffer, page.data.byteOffset, page.data.byteLength);
|
|
713
|
+
await emit(`item-atlas-${index}.png`, await sharp(raw, { raw: {
|
|
714
|
+
width: page.width,
|
|
715
|
+
height: page.height,
|
|
716
|
+
channels: 4
|
|
717
|
+
} }).png({ compressionLevel: 9 }).toBuffer());
|
|
718
|
+
}
|
|
719
|
+
if (itemPack) await emit("items.json", JSON.stringify(itemPack));
|
|
791
720
|
for (const file of tints.files) await emit(file.path, file.data);
|
|
792
721
|
await emit("atlas.json", JSON.stringify({
|
|
793
|
-
padding:
|
|
722
|
+
padding: sheet.padding,
|
|
794
723
|
pages: pageFiles,
|
|
795
724
|
sprites: sortedByKey(emittedSprites)
|
|
796
725
|
}));
|
|
@@ -809,8 +738,9 @@ async function exportBlockPack(options) {
|
|
|
809
738
|
blocks: Object.keys(blockStates).length,
|
|
810
739
|
models: Object.keys(emittedModels).length,
|
|
811
740
|
sprites: Object.keys(emittedSprites).length,
|
|
812
|
-
pages:
|
|
741
|
+
pages: sheet.pages.length,
|
|
813
742
|
biomes: Object.keys(biomes.pack).length,
|
|
743
|
+
items: Object.keys(itemPack?.items ?? {}).length,
|
|
814
744
|
failures: failures.length
|
|
815
745
|
};
|
|
816
746
|
await emit("meta.json", JSON.stringify({
|
|
@@ -19,6 +19,12 @@ interface ExportBlockPackOptions {
|
|
|
19
19
|
padding?: number;
|
|
20
20
|
/** Ceiling on an atlas page's dimensions (default 4096). */
|
|
21
21
|
maxPageSize?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Export `items.json` and its own atlas: the flat sprite stacks for items that
|
|
24
|
+
* are not blocks, which is what a world viewer draws a dropped stack of a lead
|
|
25
|
+
* or a handful of charcoal from. On by default.
|
|
26
|
+
*/
|
|
27
|
+
items?: boolean;
|
|
22
28
|
onProgress?: (stage: string, done: number, total: number) => void;
|
|
23
29
|
}
|
|
24
30
|
interface BlockPackFailure {
|
|
@@ -27,7 +33,7 @@ interface BlockPackFailure {
|
|
|
27
33
|
* `intentional` is not a failure: it marks a block that is empty because the
|
|
28
34
|
* game draws nothing for it. Filter it out to get the real gaps.
|
|
29
35
|
*/
|
|
30
|
-
kind: 'blockstate' | 'model' | 'texture' | 'sprite' | 'geometry' | 'tint' | 'biome' | 'intentional';
|
|
36
|
+
kind: 'blockstate' | 'model' | 'texture' | 'sprite' | 'geometry' | 'tint' | 'biome' | 'item' | 'intentional';
|
|
31
37
|
reason: string;
|
|
32
38
|
}
|
|
33
39
|
interface BlockPackResult {
|
|
@@ -37,6 +43,8 @@ interface BlockPackResult {
|
|
|
37
43
|
pages: number;
|
|
38
44
|
/** Biomes described in `biomes.json`; `0` means the file was not written. */
|
|
39
45
|
biomes: number;
|
|
46
|
+
/** Flat items described in `items.json`; `0` means the file was not written. */
|
|
47
|
+
items: number;
|
|
40
48
|
/** Files actually written — the only trustworthy success signal. */
|
|
41
49
|
writtenFiles: number;
|
|
42
50
|
failures: BlockPackFailure[];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { n as ResourceLocator } from "./locator-COMEtEn9.js";
|
|
2
|
-
import { l as toFloatTexture } from "./blend-KXMclcHk.js";
|
|
3
2
|
import { n as displayMatrix } from "./vector-CCxLae_T.js";
|
|
3
|
+
import { l as toFloatTexture } from "./blend-KXMclcHk.js";
|
|
4
4
|
import { c as lightsForProfile } from "./lighting--5myudVu.js";
|
|
5
5
|
import { i as createFaceBuffer } from "./rasterizer-DcVJzkxz.js";
|
|
6
6
|
import { t as combineFaceBuffers } from "./compose-BGsNFR12.js";
|
|
7
|
-
import { n as faceMaxZ, r as renderFace, t as createShadeCache } from "./face-
|
|
7
|
+
import { n as faceMaxZ, r as renderFace, t as createShadeCache } from "./face-CMJ3b3Ae.js";
|
|
8
8
|
//#region src/render/geo.ts
|
|
9
9
|
/**
|
|
10
10
|
* Bedrock-format geometry (`.geo.json`) rendering, best-effort. GeckoLib mods
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ 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-
|
|
9
|
+
import { i as exportBlockPack, n as BlockPackResult, r as ExportBlockPackOptions, t as BlockPackFailure } from "./export-wvt0Fryo.js";
|
|
10
10
|
import { i as buildObjMesh, n as ObjMesh, r as ObjMeshError, t as MeshGroup } from "./obj-mesh-ydhVfLKs.js";
|
|
11
11
|
import { a as buildBlockTints, i as UNREGISTERED_TINTS, n as BlockTintPack, t as BlockTint } from "./tints-DoBv5S9v.js";
|
|
12
12
|
import { s as builtinDynamicResources } from "./generators-BnIzAftW.js";
|
|
@@ -14,7 +14,7 @@ import { d as toFloatTexture, n as FloatTexture, u as toByteTexture } from "./bl
|
|
|
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";
|