@nodecraft/rendermite 1.0.4 → 1.0.6
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 +5 -0
- package/assets/README.md +3 -0
- package/assets/mod-tints/README.md +38 -0
- package/assets/mod-tints/advanced_ae/items/quantum_boots.json +16 -0
- package/assets/mod-tints/advanced_ae/items/quantum_chestplate.json +16 -0
- package/assets/mod-tints/advanced_ae/items/quantum_helmet.json +16 -0
- package/assets/mod-tints/advanced_ae/items/quantum_leggings.json +16 -0
- package/dist/atlas/registry.d.ts +3 -3
- package/dist/atlas/sources.d.ts +1 -1
- package/dist/{blend-Qvrn6YgK.d.ts → blend-CyDIxCne.d.ts} +1 -1
- package/dist/{builtin-C8GZEN40.js → builtin-caYjESh0.js} +5 -1
- package/dist/builtin.d.ts +3 -1
- package/dist/builtin.js +2 -2
- package/dist/cache-Cr2ON3RQ.js +66 -0
- package/dist/cli.js +40 -7
- package/dist/compose-CQCb2LVv.js +104 -0
- package/dist/descriptor-DWebtkI1.js +26 -0
- package/dist/{discovery-D89pVVJA.d.ts → discovery-wiJBGryo.d.ts} +1 -1
- package/dist/dynamic/generators.d.ts +1 -1
- package/dist/dynamic/generators.js +1 -1
- package/dist/{encode-3u49i-eD.js → encode-D6dQu2dJ.js} +16 -4
- package/dist/{encode-C5kdAm45.d.ts → encode-DaNQF28M.d.ts} +1 -1
- package/dist/{entity-fallback-CdCVEG6X.js → entity-fallback-BRCeGKBT.js} +1 -1
- package/dist/{face-CpVdnf-w.d.ts → face-BIYg14TE.d.ts} +10 -4
- package/dist/{face-D-N1amV4.js → face-DmCiHUd5.js} +23 -10
- package/dist/{generators-CcVRG30y.js → generators-BlG4KmtP.js} +1 -1
- package/dist/{generators-CCB8h0mP.d.ts → generators-DhRov4RB.d.ts} +1 -1
- package/dist/{geo-u8rndjLA.js → geo-Diky41Tw.js} +7 -4
- package/dist/index.d.ts +14 -14
- package/dist/index.js +13 -13
- package/dist/{item-styles-DJ3LWZS2.js → item-styles-upgEO1yP.js} +1 -1
- package/dist/items/discovery.d.ts +1 -1
- package/dist/items/discovery.js +1 -1
- package/dist/{jar-6T3xdgaL.d.ts → jar-CFkA-VgT.d.ts} +2 -1
- package/dist/{jar-Bt3i0ls4.js → jar-D9z-X7tA.js} +12 -12
- package/dist/{legacy-reshape-CewShfF3.js → legacy-reshape-C05SfAPR.js} +1 -1
- package/dist/{loader-A-BZa8J4.js → loader-B8NJO7pR.js} +12 -3
- package/dist/{loader-CBzn3Koc.js → loader-CfXMxcEV.js} +37 -7
- package/dist/{loader-C-6QN3xv.d.ts → loader-D22zZME7.d.ts} +2 -2
- package/dist/{loader-TFFNV4Jl.d.ts → loader-Myy22TDL.d.ts} +8 -2
- package/dist/{manager-dfI7b9N4.js → manager-CkletR5K.js} +29 -2
- package/dist/{manager-CoZaeQTu.d.ts → manager-Cv1NeFyF.d.ts} +28 -1
- package/dist/models/loader.d.ts +1 -1
- package/dist/models/loader.js +1 -1
- package/dist/mods/prepare.d.ts +1 -1
- package/dist/mods/prepare.js +1 -1
- package/dist/mods/synthesize.d.ts +2 -2
- package/dist/mods/synthesize.js +1 -1
- package/dist/mods/tints.d.ts +28 -0
- package/dist/mods/tints.js +2 -0
- package/dist/output/encode.d.ts +1 -1
- package/dist/output/encode.js +1 -1
- package/dist/output/item-styles.js +1 -1
- package/dist/pipeline-BIk1RRIp.js +221 -0
- package/dist/pipeline-zq-yU3Te.d.ts +58 -0
- package/dist/pool-CKGp1qup.js +131 -0
- package/dist/{prepare-Bvc5ve2m.js → prepare-BESRrh6K.js} +33 -5
- package/dist/{prepare-DnnGGv9k.d.ts → prepare-CPxO0kKz.d.ts} +8 -1
- package/dist/{prepare-DROxBZp1.js → prepare-Cc8QZ3j0.js} +4 -4
- package/dist/{prepare-wfWtaz_X.d.ts → prepare-Cs6QDqie.d.ts} +1 -1
- package/dist/{rasterizer-BHWDrmGz.js → rasterizer-76qO8TDh.js} +42 -4
- package/dist/{rasterizer-Dh35qXbn.d.ts → rasterizer-yqJkicm1.d.ts} +21 -2
- package/dist/render/blend.d.ts +1 -1
- package/dist/render/compose.d.ts +2 -2
- package/dist/render/compose.js +1 -1
- package/dist/render/entity-fallback.d.ts +6 -6
- package/dist/render/entity-fallback.js +1 -1
- package/dist/render/face.d.ts +2 -2
- package/dist/render/face.js +1 -1
- package/dist/render/fluid-bucket.d.ts +2 -2
- package/dist/render/geo.d.ts +4 -4
- package/dist/render/geo.js +1 -1
- package/dist/render/legacy-tints.d.ts +2 -2
- package/dist/render/obj.d.ts +5 -5
- package/dist/render/obj.js +1 -1
- package/dist/render/pipeline.d.ts +2 -0
- package/dist/render/pipeline.js +2 -0
- package/dist/render/rasterizer.d.ts +2 -2
- package/dist/render/rasterizer.js +2 -2
- package/dist/render/renderer.d.ts +2 -2
- package/dist/render/renderer.js +1 -1
- package/dist/render/tints.d.ts +1 -1
- package/dist/{renderer-BeOinVC8.js → renderer-CjT19tHd.js} +131 -54
- package/dist/{renderer-nbMCw1Pl.d.ts → renderer-DVsZHAvf.d.ts} +23 -6
- package/dist/resources/cache.d.ts +30 -0
- package/dist/resources/cache.js +2 -0
- package/dist/resources/descriptor.d.ts +2 -0
- package/dist/resources/descriptor.js +2 -0
- package/dist/resources/jar.d.ts +1 -1
- package/dist/resources/jar.js +1 -1
- package/dist/resources/manager.d.ts +1 -1
- package/dist/resources/manager.js +1 -1
- package/dist/resources/synthetic.d.ts +1 -1
- package/dist/resources/synthetic.js +1 -1
- package/dist/resources/zip-reader.d.ts +5 -0
- package/dist/resources/zip-reader.js +2 -0
- package/dist/run-BnICOF4I.js +209 -0
- package/dist/{run-BlSZw9Qk.d.ts → run-CKUtynTy.d.ts} +12 -2
- package/dist/run.d.ts +1 -1
- package/dist/run.js +1 -1
- package/dist/{sources-DH9dk3KF.d.ts → sources-B9X9w3qP.d.ts} +1 -1
- package/dist/{synthesize-CRgSEmEp.js → synthesize-3Q0aaOnK.js} +1 -1
- package/dist/{synthetic-CDsj--li.d.ts → synthetic-Qk-BSUXO.d.ts} +5 -1
- package/dist/{synthetic-DC2bSnGe.js → synthetic-ZAUjXT7E.js} +0 -0
- package/dist/textures/loader.d.ts +1 -1
- package/dist/textures/loader.js +1 -1
- package/dist/tints-B8UJmZMu.js +83 -0
- package/dist/{tints-txt-8xI5.d.ts → tints-DLBExVWN.d.ts} +2 -2
- package/dist/versions/legacy-reshape.d.ts +1 -1
- package/dist/versions/legacy-reshape.js +1 -1
- package/dist/versions/prepare.d.ts +1 -1
- package/dist/versions/prepare.js +1 -1
- package/dist/workers/pool.d.ts +36 -5
- package/dist/workers/pool.js +2 -67
- package/dist/workers/render-worker.d.ts +15 -0
- package/dist/workers/render-worker.js +40 -0
- package/dist/zip-reader-BSbJKUT1.js +156 -0
- package/package.json +4 -2
- package/dist/compose-qjhyBvnS.js +0 -41
- package/dist/run-DI-cB38y.js +0 -316
- package/dist/{discovery-iph0P2F2.js → discovery-0SM0cTLw.js} +1 -1
package/README.md
CHANGED
|
@@ -75,6 +75,11 @@ Benchmarked against PHP renderchest v5.1.0 on the same machine, rendering the sa
|
|
|
75
75
|
| renderchest (docker, 8 workers) | 210s | 1,573 | 33 | ~449/min |
|
|
76
76
|
| rendermite (one Node process, pool 8) | 22.9s | 2,065 | 0 | ~5,410/min |
|
|
77
77
|
|
|
78
|
+
That comparison is a fixed point in time; rendermite has since roughly halved its own wall
|
|
79
|
+
time again (worker threads, a faster compositor, bounded animations). Run `npm run bench` for
|
|
80
|
+
current numbers on your machine — CI runs the same suite and comments the delta on pull
|
|
81
|
+
requests.
|
|
82
|
+
|
|
78
83
|
## Testing
|
|
79
84
|
|
|
80
85
|
```sh
|
package/assets/README.md
CHANGED
|
@@ -15,3 +15,6 @@ generators).
|
|
|
15
15
|
|
|
16
16
|
Layout is `<namespace>/<models|textures|items|atlases>/…` (no `assets/` nesting) — mount with
|
|
17
17
|
`FolderResourceManager` above the version's own assets.
|
|
18
|
+
|
|
19
|
+
`mod-tints/` is ours rather than vendored: curated item definitions for mod items that
|
|
20
|
+
register their tint colors in client code. See `mod-tints/README.md`.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Curated mod tint overrides
|
|
2
|
+
|
|
3
|
+
Item definitions for mod items whose tint colors are registered in client Java code and
|
|
4
|
+
therefore appear in no release's asset JSON. Layout is `<namespace>/items/<id>.json`, the
|
|
5
|
+
vanilla 1.21.4+ item-definition format, mounted with `FolderResourceManager` (see
|
|
6
|
+
`src/mods/tints.ts`). Nothing in the renderer special-cases these files.
|
|
7
|
+
|
|
8
|
+
## Precedence
|
|
9
|
+
|
|
10
|
+
This pack layers **above** the mod jars, unlike harvested overrides (which layer below so a
|
|
11
|
+
mod's own data always wins). Curated entries exist because the mod ships no usable data in
|
|
12
|
+
any release, and in the modern era the mod's own definition is typically an unrenderable
|
|
13
|
+
code-driven model type that would shadow the override. Delete an entry once the mod ships a
|
|
14
|
+
release that states the tint as data: the harvester will then source it authoritatively.
|
|
15
|
+
|
|
16
|
+
## Adding an entry
|
|
17
|
+
|
|
18
|
+
Every entry needs its provenance recorded below, because these values are the only ones in
|
|
19
|
+
the project that cannot be traced to a jar. Hold a slot open with
|
|
20
|
+
`{"type": "minecraft:constant", "value": -1}` when a layer takes no tint. Values are signed
|
|
21
|
+
ARGB ints, matching vanilla's own definition files.
|
|
22
|
+
|
|
23
|
+
## Entries
|
|
24
|
+
|
|
25
|
+
### `advanced_ae` quantum armor (helmet, chestplate, leggings, boots)
|
|
26
|
+
|
|
27
|
+
`#7110a5` on layer 1, sourced by eye and **not** verifiable against any jar. Checked:
|
|
28
|
+
|
|
29
|
+
- 1.21.1 models are `layer0: <piece>_base` + `layer1: <piece>_tint`, and both textures are
|
|
30
|
+
fully grayscale, so nothing renders colored without an external value.
|
|
31
|
+
- The 26.1.x definitions use `"type": "advanced_ae:quantum_armor"` with no `tints` at all.
|
|
32
|
+
- `0x7110A5` appears in no class constant pool in AdvancedAE 1.21.1, AdvancedAE 26.1.7, or
|
|
33
|
+
AE2 1.21.1.
|
|
34
|
+
|
|
35
|
+
The mod's own `quantum_crafter_terminal_part` tints with `ae2:color` (`color: fluix`), so
|
|
36
|
+
these pieces are very likely AE2's fluix purple. Teaching `resolveTint` the `ae2:color`
|
|
37
|
+
palette would replace these four files with a sourced value and cover ~116 other AE2-family
|
|
38
|
+
items that currently resolve no tint at all.
|
package/dist/atlas/registry.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as ResourceLocator } from "../locator-jDbdUeTd.js";
|
|
2
|
-
import { a as ResourceManager } from "../manager-
|
|
3
|
-
import { r as Texture } from "../loader-
|
|
4
|
-
import { t as AtlasResolver } from "../sources-
|
|
2
|
+
import { a as ResourceManager } from "../manager-Cv1NeFyF.js";
|
|
3
|
+
import { r as Texture } from "../loader-Myy22TDL.js";
|
|
4
|
+
import { t as AtlasResolver } from "../sources-B9X9w3qP.js";
|
|
5
5
|
//#region src/atlas/registry.d.ts
|
|
6
6
|
declare function loadAtlasResolver(resources: ResourceManager, loadTexture: (locator: ResourceLocator) => Promise<Texture | null>, onWarning?: (message: string) => void): Promise<AtlasResolver>;
|
|
7
7
|
//#endregion
|
package/dist/atlas/sources.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as HasTexture, c as SingleAtlasSource, d as parseAtlasSources, i as DirectoryAtlasSource, l as UnstitchAtlasSource, n as AtlasSource, o as PalettedPermutationsSource, r as AtlasSourceError, s as ResolvedSprite, t as AtlasResolver, u as createAtlasResolver } from "../sources-
|
|
1
|
+
import { a as HasTexture, c as SingleAtlasSource, d as parseAtlasSources, i as DirectoryAtlasSource, l as UnstitchAtlasSource, n as AtlasSource, o as PalettedPermutationsSource, r as AtlasSourceError, s as ResolvedSprite, t as AtlasResolver, u as createAtlasResolver } from "../sources-B9X9w3qP.js";
|
|
2
2
|
export { AtlasResolver, AtlasSource, AtlasSourceError, DirectoryAtlasSource, HasTexture, PalettedPermutationsSource, ResolvedSprite, SingleAtlasSource, UnstitchAtlasSource, createAtlasResolver, parseAtlasSources };
|
|
@@ -12,5 +12,9 @@ function builtinPackPath(era) {
|
|
|
12
12
|
function bedCompatPath() {
|
|
13
13
|
return path.join(assetsRoot, "builtin-bed-compat");
|
|
14
14
|
}
|
|
15
|
+
/** Curated tint overrides for mod items that register their colors in code. */
|
|
16
|
+
function modTintPackPath() {
|
|
17
|
+
return path.join(assetsRoot, "mod-tints");
|
|
18
|
+
}
|
|
15
19
|
//#endregion
|
|
16
|
-
export { builtinPackPath as n, bedCompatPath as t };
|
|
20
|
+
export { builtinPackPath as n, modTintPackPath as r, bedCompatPath as t };
|
package/dist/builtin.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
//#region src/builtin.d.ts
|
|
2
2
|
declare function builtinPackPath(era: 'modern' | 'legacy'): string;
|
|
3
3
|
declare function bedCompatPath(): string;
|
|
4
|
+
/** Curated tint overrides for mod items that register their colors in code. */
|
|
5
|
+
declare function modTintPackPath(): string;
|
|
4
6
|
//#endregion
|
|
5
|
-
export { bedCompatPath, builtinPackPath };
|
|
7
|
+
export { bedCompatPath, builtinPackPath, modTintPackPath };
|
package/dist/builtin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-
|
|
2
|
-
export { bedCompatPath, builtinPackPath };
|
|
1
|
+
import { n as builtinPackPath, r as modTintPackPath, t as bedCompatPath } from "./builtin-caYjESh0.js";
|
|
2
|
+
export { bedCompatPath, builtinPackPath, modTintPackPath };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region src/resources/cache.ts
|
|
2
|
+
/**
|
|
3
|
+
* Least-recently-used map used by the model and texture loaders. Their caches
|
|
4
|
+
* were unbounded, which is fine for one namespace and not fine for a run that
|
|
5
|
+
* walks thousands of them in a single process — resident memory only ever grew.
|
|
6
|
+
*/
|
|
7
|
+
var LruCache = class {
|
|
8
|
+
entries = /* @__PURE__ */ new Map();
|
|
9
|
+
maxEntries;
|
|
10
|
+
weigh;
|
|
11
|
+
maxWeight;
|
|
12
|
+
weights = /* @__PURE__ */ new Map();
|
|
13
|
+
weight = 0;
|
|
14
|
+
constructor(maxEntries, options = {}) {
|
|
15
|
+
this.maxEntries = Math.max(1, maxEntries);
|
|
16
|
+
this.maxWeight = options.maxWeight ?? Infinity;
|
|
17
|
+
this.weigh = options.weigh ?? (() => 0);
|
|
18
|
+
}
|
|
19
|
+
evict() {
|
|
20
|
+
while (this.entries.size > this.maxEntries || this.weight > this.maxWeight && this.entries.size > 1) {
|
|
21
|
+
const oldest = this.entries.keys().next();
|
|
22
|
+
if (oldest.done) return;
|
|
23
|
+
this.weight -= this.weights.get(oldest.value) ?? 0;
|
|
24
|
+
this.weights.delete(oldest.value);
|
|
25
|
+
this.entries.delete(oldest.value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
get size() {
|
|
29
|
+
return this.entries.size;
|
|
30
|
+
}
|
|
31
|
+
get(key) {
|
|
32
|
+
const value = this.entries.get(key);
|
|
33
|
+
if (value !== void 0) {
|
|
34
|
+
this.entries.delete(key);
|
|
35
|
+
this.entries.set(key, value);
|
|
36
|
+
}
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
set(key, value) {
|
|
40
|
+
if (this.entries.has(key)) {
|
|
41
|
+
this.weight -= this.weights.get(key) ?? 0;
|
|
42
|
+
this.entries.delete(key);
|
|
43
|
+
}
|
|
44
|
+
this.entries.set(key, value);
|
|
45
|
+
this.weights.set(key, 0);
|
|
46
|
+
this.evict();
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Record a value's real cost once it is known. Loaders cache promises, so the
|
|
50
|
+
* weight of a decoded texture only exists after it resolves.
|
|
51
|
+
*/
|
|
52
|
+
settle(key, value) {
|
|
53
|
+
if (!this.entries.has(key)) return;
|
|
54
|
+
const size = this.weigh(value);
|
|
55
|
+
this.weight += size - (this.weights.get(key) ?? 0);
|
|
56
|
+
this.weights.set(key, size);
|
|
57
|
+
this.evict();
|
|
58
|
+
}
|
|
59
|
+
clear() {
|
|
60
|
+
this.entries.clear();
|
|
61
|
+
this.weights.clear();
|
|
62
|
+
this.weight = 0;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
//#endregion
|
|
66
|
+
export { LruCache as t };
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-
|
|
3
|
-
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-
|
|
4
|
-
import { t as
|
|
5
|
-
import { t as
|
|
2
|
+
import { n as builtinPackPath, t as bedCompatPath } from "./builtin-caYjESh0.js";
|
|
3
|
+
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-CkletR5K.js";
|
|
4
|
+
import { n as harvestTintOverrides, t as curatedTintOverrides } from "./tints-B8UJmZMu.js";
|
|
5
|
+
import { t as JarResourceManager } from "./jar-D9z-X7tA.js";
|
|
6
|
+
import { t as run } from "./run-BnICOF4I.js";
|
|
6
7
|
import { t as downloadClientJar } from "./download-D9aARBFp.js";
|
|
7
|
-
import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-
|
|
8
|
+
import { a as prepareVersionResources, i as eraForVersion, n as GEOMETRY_DONOR_VERSIONS } from "./prepare-Cc8QZ3j0.js";
|
|
8
9
|
import path from "node:path";
|
|
9
10
|
import os from "node:os";
|
|
10
11
|
import { parseArgs } from "node:util";
|
|
@@ -30,6 +31,10 @@ const { values } = parseArgs({ options: {
|
|
|
30
31
|
short: "m",
|
|
31
32
|
multiple: true
|
|
32
33
|
},
|
|
34
|
+
"tint-donor": {
|
|
35
|
+
type: "string",
|
|
36
|
+
multiple: true
|
|
37
|
+
},
|
|
33
38
|
"namespace": {
|
|
34
39
|
type: "string",
|
|
35
40
|
short: "n",
|
|
@@ -83,6 +88,10 @@ const { values } = parseArgs({ options: {
|
|
|
83
88
|
"builtin": { type: "string" },
|
|
84
89
|
"cache-dir": { type: "string" },
|
|
85
90
|
"concurrency": { type: "string" },
|
|
91
|
+
"workers": {
|
|
92
|
+
type: "string",
|
|
93
|
+
short: "w"
|
|
94
|
+
},
|
|
86
95
|
"help": {
|
|
87
96
|
type: "boolean",
|
|
88
97
|
short: "h",
|
|
@@ -101,6 +110,7 @@ Input:
|
|
|
101
110
|
-v, --version <ver> download + prepare a vanilla version (1.2.5 … latest)
|
|
102
111
|
-a, --assets <dir> asset root (repeatable, first wins), <namespace>/ children
|
|
103
112
|
-m, --mod <jar> mod jar layered under vanilla (repeatable)
|
|
113
|
+
--tint-donor <jar> 1.21.4+ jar of a loaded mod, read for its tints (repeatable)
|
|
104
114
|
|
|
105
115
|
Options:
|
|
106
116
|
-n, --namespace <ns> namespace to render (repeatable, default: minecraft)
|
|
@@ -116,7 +126,8 @@ Options:
|
|
|
116
126
|
--lighting-profile modern (default) | legacy (matches published corpus)
|
|
117
127
|
--builtin <dir> override the builtin pack (defaults per era)
|
|
118
128
|
--cache-dir <dir> jar download cache (default ~/.rendermite)
|
|
119
|
-
--concurrency <n> in-flight items (default 8)
|
|
129
|
+
--concurrency <n> in-flight items per thread (default 8)
|
|
130
|
+
-w, --workers <n> render threads (default: one per core, less one)
|
|
120
131
|
`);
|
|
121
132
|
process.exit(values.help ? 0 : 1);
|
|
122
133
|
}
|
|
@@ -147,7 +158,28 @@ if (values.version) {
|
|
|
147
158
|
resources = managers.length === 1 ? managers[0] : new LayeredResourceManager(managers);
|
|
148
159
|
builtin ??= builtinPackPath("modern");
|
|
149
160
|
}
|
|
150
|
-
if (values
|
|
161
|
+
if (values["tint-donor"]?.length && !values.mod?.length) {
|
|
162
|
+
console.error("--tint-donor needs --mod: donors are read for the tints of loaded mods.");
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
if (values.mod?.length) {
|
|
166
|
+
const base = new LayeredResourceManager([
|
|
167
|
+
resources,
|
|
168
|
+
curatedTintOverrides(),
|
|
169
|
+
...values.mod.map((jar) => new JarResourceManager(jar))
|
|
170
|
+
]);
|
|
171
|
+
resources = base;
|
|
172
|
+
if (values["tint-donor"]?.length) {
|
|
173
|
+
const donorJars = values["tint-donor"].map((jar) => new JarResourceManager(jar));
|
|
174
|
+
const harvest = await harvestTintOverrides({
|
|
175
|
+
donors: new LayeredResourceManager(donorJars),
|
|
176
|
+
target: base
|
|
177
|
+
});
|
|
178
|
+
await Promise.all(donorJars.map((jar) => jar.close().catch(() => {})));
|
|
179
|
+
console.log(`Harvested tints for ${harvest.harvested} items from ${donorJars.length} donor jars`);
|
|
180
|
+
if (harvest.harvested > 0) resources = new LayeredResourceManager([base, harvest.overrides]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
151
183
|
const result = await run({
|
|
152
184
|
resources,
|
|
153
185
|
builtin,
|
|
@@ -161,6 +193,7 @@ const result = await run({
|
|
|
161
193
|
gif: values.gif,
|
|
162
194
|
avif: values.avif,
|
|
163
195
|
concurrency: values.concurrency ? Number(values.concurrency) : void 0,
|
|
196
|
+
workers: values.workers ? Number(values.workers) : void 0,
|
|
164
197
|
lightingProfile: values["lighting-profile"] === "legacy" ? "legacy" : "modern",
|
|
165
198
|
itemList: values["item-list"],
|
|
166
199
|
onProgress: (done, total, id, error) => {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { t as blendPixel } from "./blend-CHP2-j9U.js";
|
|
2
|
+
//#region src/render/compose.ts
|
|
3
|
+
/**
|
|
4
|
+
* Per-pixel painter's compositing, mirroring upstream Model::combineFaceImages:
|
|
5
|
+
* at each pixel, faces sorted ascending by that pixel's depth value (0 where the
|
|
6
|
+
* rasterizer never wrote depth — the overdraw band relies on sorting beneath),
|
|
7
|
+
* then source-over blended in that order when alpha > 0.
|
|
8
|
+
*
|
|
9
|
+
* Upstream re-sorts one persistent array, so each pixel's sort is really a
|
|
10
|
+
* stable partition: faces the pixel misses keep their order, faces with depth
|
|
11
|
+
* move to the end in depth order. That reordering is invariant under taking
|
|
12
|
+
* subsets, so instead of touching every face at every pixel we keep a rank per
|
|
13
|
+
* face (a moved face gets a fresh, higher rank) and visit only the faces whose
|
|
14
|
+
* bounding box contains the pixel. Same order, same pixels, sublinear in faces.
|
|
15
|
+
*/
|
|
16
|
+
function combineFaceBuffers(width, height, faces) {
|
|
17
|
+
const out = new Float64Array(width * height * 4);
|
|
18
|
+
const count = faces.length;
|
|
19
|
+
if (count === 0) return {
|
|
20
|
+
width,
|
|
21
|
+
height,
|
|
22
|
+
data: out
|
|
23
|
+
};
|
|
24
|
+
const rowCounts = new Int32Array(height + 1);
|
|
25
|
+
for (const face of faces) {
|
|
26
|
+
const endY = Math.min(face.y + face.height, height);
|
|
27
|
+
for (let y = Math.max(face.y, 0); y < endY; y++) rowCounts[y]++;
|
|
28
|
+
}
|
|
29
|
+
const rowStart = new Int32Array(height + 1);
|
|
30
|
+
for (let y = 0; y < height; y++) rowStart[y + 1] = rowStart[y] + rowCounts[y];
|
|
31
|
+
const cursor = [...rowStart];
|
|
32
|
+
const rowFaces = new Int32Array(rowStart[height]);
|
|
33
|
+
for (let index = 0; index < count; index++) {
|
|
34
|
+
const face = faces[index];
|
|
35
|
+
const endY = Math.min(face.y + face.height, height);
|
|
36
|
+
for (let y = Math.max(face.y, 0); y < endY; y++) rowFaces[cursor[y]++] = index;
|
|
37
|
+
}
|
|
38
|
+
const rank = new Float64Array(count);
|
|
39
|
+
for (let index = 0; index < count; index++) rank[index] = index;
|
|
40
|
+
let nextRank = count;
|
|
41
|
+
const flat = new Int32Array(count);
|
|
42
|
+
const flatRank = new Float64Array(count);
|
|
43
|
+
const deep = new Int32Array(count);
|
|
44
|
+
const deepDepth = new Float64Array(count);
|
|
45
|
+
const deepRank = new Float64Array(count);
|
|
46
|
+
for (let y = 0; y < height; y++) {
|
|
47
|
+
const start = rowStart[y];
|
|
48
|
+
const end = rowStart[y + 1];
|
|
49
|
+
if (start === end) continue;
|
|
50
|
+
for (let x = 0; x < width; x++) {
|
|
51
|
+
let flatCount = 0;
|
|
52
|
+
let deepCount = 0;
|
|
53
|
+
for (let slot = start; slot < end; slot++) {
|
|
54
|
+
const index = rowFaces[slot];
|
|
55
|
+
const face = faces[index];
|
|
56
|
+
const localX = x - face.x;
|
|
57
|
+
if (localX < 0 || localX >= face.width) continue;
|
|
58
|
+
const localPixel = (y - face.y) * face.width + localX;
|
|
59
|
+
const depth = face.depths[localPixel];
|
|
60
|
+
if (depth > 0) {
|
|
61
|
+
let slotIndex = deepCount++;
|
|
62
|
+
while (slotIndex > 0 && (deepDepth[slotIndex - 1] > depth || deepDepth[slotIndex - 1] === depth && deepRank[slotIndex - 1] > rank[index])) {
|
|
63
|
+
deep[slotIndex] = deep[slotIndex - 1];
|
|
64
|
+
deepDepth[slotIndex] = deepDepth[slotIndex - 1];
|
|
65
|
+
deepRank[slotIndex] = deepRank[slotIndex - 1];
|
|
66
|
+
slotIndex--;
|
|
67
|
+
}
|
|
68
|
+
deep[slotIndex] = index;
|
|
69
|
+
deepDepth[slotIndex] = depth;
|
|
70
|
+
deepRank[slotIndex] = rank[index];
|
|
71
|
+
} else {
|
|
72
|
+
let slotIndex = flatCount++;
|
|
73
|
+
while (slotIndex > 0 && flatRank[slotIndex - 1] > rank[index]) {
|
|
74
|
+
flat[slotIndex] = flat[slotIndex - 1];
|
|
75
|
+
flatRank[slotIndex] = flatRank[slotIndex - 1];
|
|
76
|
+
slotIndex--;
|
|
77
|
+
}
|
|
78
|
+
flat[slotIndex] = index;
|
|
79
|
+
flatRank[slotIndex] = rank[index];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (flatCount === 0 && deepCount === 0) continue;
|
|
83
|
+
const offset = (y * width + x) * 4;
|
|
84
|
+
for (let i = 0; i < flatCount; i++) blendFace(out, offset, faces[flat[i]], x, y);
|
|
85
|
+
for (let i = 0; i < deepCount; i++) {
|
|
86
|
+
const index = deep[i];
|
|
87
|
+
blendFace(out, offset, faces[index], x, y);
|
|
88
|
+
rank[index] = nextRank++;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
width,
|
|
94
|
+
height,
|
|
95
|
+
data: out
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function blendFace(out, offset, face, x, y) {
|
|
99
|
+
const faceOffset = ((y - face.y) * face.width + (x - face.x)) * 4;
|
|
100
|
+
const alpha = face.colors[faceOffset + 3];
|
|
101
|
+
if (alpha > 0) blendPixel(out, offset, face.colors[faceOffset], face.colors[faceOffset + 1], face.colors[faceOffset + 2], alpha);
|
|
102
|
+
}
|
|
103
|
+
//#endregion
|
|
104
|
+
export { combineFaceBuffers as t };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { n as LayeredResourceManager, t as FolderResourceManager } from "./manager-CkletR5K.js";
|
|
2
|
+
import { n as MapResourceManager, t as KindFilteredResourceManager } from "./synthetic-ZAUjXT7E.js";
|
|
3
|
+
import { t as JarResourceManager } from "./jar-D9z-X7tA.js";
|
|
4
|
+
//#region src/resources/descriptor.ts
|
|
5
|
+
/**
|
|
6
|
+
* Serializable descriptions of a resource tree, so the same layered tree can be
|
|
7
|
+
* rebuilt inside a worker thread. Managers describe themselves; a tree
|
|
8
|
+
* containing anything that cannot (a consumer's own ResourceManager) describes
|
|
9
|
+
* as null, and the caller renders in-process rather than silently dropping
|
|
10
|
+
* layers.
|
|
11
|
+
*/
|
|
12
|
+
function describeResources(manager) {
|
|
13
|
+
const describable = manager;
|
|
14
|
+
return typeof describable.describe === "function" ? describable.describe() : null;
|
|
15
|
+
}
|
|
16
|
+
function restoreResources(descriptor) {
|
|
17
|
+
switch (descriptor.kind) {
|
|
18
|
+
case "folder": return new FolderResourceManager(descriptor.root);
|
|
19
|
+
case "jar": return new JarResourceManager(descriptor.path);
|
|
20
|
+
case "map": return MapResourceManager.fromEntries(descriptor.entries);
|
|
21
|
+
case "layered": return new LayeredResourceManager(descriptor.layers.map((layer) => restoreResources(layer)));
|
|
22
|
+
case "kindFiltered": return new KindFilteredResourceManager(restoreResources(descriptor.inner), descriptor.kinds);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { restoreResources as n, describeResources as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ResourceManager } from "./manager-
|
|
1
|
+
import { a as ResourceManager } from "./manager-Cv1NeFyF.js";
|
|
2
2
|
import { i as ItemRenderInstruction, r as ItemProperties } from "./definition-BwX6Xxv0.js";
|
|
3
3
|
//#region src/items/discovery.d.ts
|
|
4
4
|
declare class ItemResolutionError extends Error {}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as TRIM_DARKER_MATERIALS, i as POTTERY_SHERDS, n as DynamicItem, o as TRIM_MATERIALS, r as DynamicResources, s as builtinDynamicResources, t as ARMOR_ITEM_TYPES } from "../generators-
|
|
1
|
+
import { a as TRIM_DARKER_MATERIALS, i as POTTERY_SHERDS, n as DynamicItem, o as TRIM_MATERIALS, r as DynamicResources, s as builtinDynamicResources, t as ARMOR_ITEM_TYPES } from "../generators-DhRov4RB.js";
|
|
2
2
|
export { ARMOR_ITEM_TYPES, DynamicItem, DynamicResources, POTTERY_SHERDS, TRIM_DARKER_MATERIALS, TRIM_MATERIALS, builtinDynamicResources };
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as builtinDynamicResources, i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "../generators-
|
|
1
|
+
import { a as builtinDynamicResources, i as TRIM_MATERIALS, n as POTTERY_SHERDS, r as TRIM_DARKER_MATERIALS, t as ARMOR_ITEM_TYPES } from "../generators-BlG4KmtP.js";
|
|
2
2
|
export { ARMOR_ITEM_TYPES, POTTERY_SHERDS, TRIM_DARKER_MATERIALS, TRIM_MATERIALS, builtinDynamicResources };
|
|
@@ -6,6 +6,17 @@ import sharp from "sharp";
|
|
|
6
6
|
* separate optimization step is needed: lossless everywhere, strictly-smaller
|
|
7
7
|
* candidates only.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* Lossless WebP effort for single-frame icons. Measured across 1.12.2–1.21.8
|
|
11
|
+
* vanilla, effort 2 is 0.1–1.9% SMALLER than effort 6 for static icons at 2.8×
|
|
12
|
+
* the speed — libvips' higher efforts search predictors that rarely pay off on
|
|
13
|
+
* 64px sprites. Animations are the opposite (up to 21% larger on one item), so
|
|
14
|
+
* they keep effort 6 below.
|
|
15
|
+
*/
|
|
16
|
+
const STATIC_WEBP_EFFORT = 2;
|
|
17
|
+
const ANIMATED_WEBP_EFFORT = 6;
|
|
18
|
+
/** Frames encoded concurrently when assembling an animation's pages. */
|
|
19
|
+
const PAGE_ENCODE_BATCH = 8;
|
|
9
20
|
/** Losslessly transcode an existing PNG resource into the formats referenced by generated CSS. */
|
|
10
21
|
async function encodeRasterAsset(source, formats) {
|
|
11
22
|
const image = sharp(source);
|
|
@@ -37,19 +48,20 @@ async function encodeRasterAsset(source, formats) {
|
|
|
37
48
|
async function encodeAnimatedIcon(frames, delaysMs, options = {}) {
|
|
38
49
|
if (frames.length === 1) return encodeIcon(frames[0], options);
|
|
39
50
|
const { width, height } = frames[0];
|
|
40
|
-
const pages =
|
|
51
|
+
const pages = [];
|
|
52
|
+
for (let start = 0; start < frames.length; start += PAGE_ENCODE_BATCH) pages.push(...await Promise.all(frames.slice(start, start + PAGE_ENCODE_BATCH).map((frame) => {
|
|
41
53
|
const bytes = toByteTexture(frame);
|
|
42
54
|
return sharp(Buffer.from(bytes.data.buffer, bytes.data.byteOffset, bytes.data.length), { raw: {
|
|
43
55
|
width,
|
|
44
56
|
height,
|
|
45
57
|
channels: 4
|
|
46
58
|
} }).png({ compressionLevel: 0 }).toBuffer();
|
|
47
|
-
}));
|
|
59
|
+
})));
|
|
48
60
|
const animated = () => sharp(pages, { join: { animated: true } });
|
|
49
61
|
const result = { png: (await encodeIcon(frames[0], { webp: false })).png };
|
|
50
62
|
if (options.webp !== false) result.webp = await animated().webp({
|
|
51
63
|
lossless: true,
|
|
52
|
-
effort:
|
|
64
|
+
effort: ANIMATED_WEBP_EFFORT,
|
|
53
65
|
loop: 0,
|
|
54
66
|
delay: delaysMs
|
|
55
67
|
}).toBuffer();
|
|
@@ -96,7 +108,7 @@ async function encodeIcon(texture, options = {}) {
|
|
|
96
108
|
}).toBuffer() };
|
|
97
109
|
if (options.webp !== false) result.webp = await raw.clone().webp({
|
|
98
110
|
lossless: true,
|
|
99
|
-
effort:
|
|
111
|
+
effort: STATIC_WEBP_EFFORT
|
|
100
112
|
}).toBuffer();
|
|
101
113
|
if (options.avif) result.avif = await raw.clone().avif({
|
|
102
114
|
lossless: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as ResourceLocator } from "./locator-ycZzh_6z.js";
|
|
2
|
-
import { i as renderModel } from "./renderer-
|
|
2
|
+
import { i as renderModel } from "./renderer-CjT19tHd.js";
|
|
3
3
|
//#region src/render/entity-fallback.ts
|
|
4
4
|
/**
|
|
5
5
|
* Heuristic rendering for mod items that parent `builtin/entity` — chests,
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { t as FloatTexture } from "./blend-
|
|
1
|
+
import { t as FloatTexture } from "./blend-CyDIxCne.js";
|
|
2
2
|
import { t as Mat4 } from "./vector-DRKRi4--.js";
|
|
3
3
|
import { n as FaceGeometry } from "./geometry-BSVmKx5b.js";
|
|
4
4
|
import { r as LightSource } from "./lighting-3FGRC3Af.js";
|
|
5
|
-
import {
|
|
5
|
+
import { n as FaceBuffer } from "./rasterizer-yqJkicm1.js";
|
|
6
6
|
//#region src/render/face.d.ts
|
|
7
7
|
interface TintColor {
|
|
8
8
|
r: number;
|
|
@@ -17,8 +17,14 @@ interface RenderableFace {
|
|
|
17
17
|
/** Untransformed model-space max Z — upstream's stable pre-sort key. */
|
|
18
18
|
maxZ: number;
|
|
19
19
|
}
|
|
20
|
+
/** Tinted + darkened textures keyed by source texture, then by shading params. */
|
|
21
|
+
type FaceShadeCache = WeakMap<FloatTexture, Map<string, FloatTexture>>;
|
|
20
22
|
declare function faceMaxZ(geometry: FaceGeometry): number;
|
|
21
23
|
/** Returns null when the face is culled, degenerate, or has a zero-area UV. */
|
|
22
|
-
declare function renderFace(face: RenderableFace, width: number, height: number, transformation: Mat4
|
|
24
|
+
declare function renderFace(face: RenderableFace, width: number, height: number, transformation: Mat4,
|
|
25
|
+
/** Reused across a model's faces; cleared here, compacted before return. */
|
|
26
|
+
scratch?: FaceBuffer,
|
|
27
|
+
/** Shared tint/shade results for one model render. */
|
|
28
|
+
shadeCache?: FaceShadeCache): FaceBuffer | null;
|
|
23
29
|
//#endregion
|
|
24
|
-
export { renderFace as i,
|
|
30
|
+
export { renderFace as a, faceMaxZ as i, RenderableFace as n, TintColor as r, FaceShadeCache as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { c as normalize, g as transformVector, h as transformDirection, m as sub, r as dot, t as cross } from "./vector-CCxLae_T.js";
|
|
2
2
|
import { a as tintTexture, n as cloneFloatTexture, r as darkenTexture } from "./blend-CHP2-j9U.js";
|
|
3
|
-
import { a as
|
|
3
|
+
import { a as drawTexturedTriangle, i as createFaceBuffer, n as clearFaceBuffer, o as phpRound, r as compactFaceBuffer, t as RowCursor } from "./rasterizer-76qO8TDh.js";
|
|
4
4
|
//#region src/render/face.ts
|
|
5
5
|
/**
|
|
6
6
|
* Face rendering: cull, transform, project, tint, darken, rasterize — a faithful
|
|
@@ -18,7 +18,7 @@ function faceNormal(v0, v1, v2) {
|
|
|
18
18
|
return normalize(normal);
|
|
19
19
|
}
|
|
20
20
|
/** Returns null when the face is culled, degenerate, or has a zero-area UV. */
|
|
21
|
-
function renderFace(face, width, height, transformation) {
|
|
21
|
+
function renderFace(face, width, height, transformation, scratch, shadeCache) {
|
|
22
22
|
const { geometry } = face;
|
|
23
23
|
const uvWidth = geometry.uv2[0] - geometry.uv1[0];
|
|
24
24
|
const uvHeight = geometry.uv2[1] - geometry.uv1[1];
|
|
@@ -49,13 +49,25 @@ function renderFace(face, width, height, transformation) {
|
|
|
49
49
|
y: phpRound(height - ((v[1] - .5) * height + height / 2))
|
|
50
50
|
};
|
|
51
51
|
});
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
const absU1 = geometry.uv1[0] * face.texture.width;
|
|
53
|
+
const absV1 = geometry.uv1[1] * face.texture.height;
|
|
54
|
+
const absU2 = geometry.uv2[0] * face.texture.width;
|
|
55
|
+
const absV2 = geometry.uv2[1] * face.texture.height;
|
|
56
|
+
const tint = geometry.tintIndex !== null ? face.tint : null;
|
|
57
|
+
const darkness = 1 - face.light.lightLevelForNormal(shadeDirection);
|
|
58
|
+
const shadeKey = `${tint ? `${tint.r},${tint.g},${tint.b}` : "-"}|${darkness}|${absU1},${absV1},${absU2},${absV2}`;
|
|
59
|
+
let byKey = shadeCache?.get(face.texture);
|
|
60
|
+
let texture = byKey?.get(shadeKey);
|
|
61
|
+
if (!texture) {
|
|
62
|
+
texture = cloneFloatTexture(face.texture);
|
|
63
|
+
if (tint) tintTexture(texture, tint.r, tint.g, tint.b);
|
|
64
|
+
darkenTexture(texture, darkness, absU1, absV1, absU2, absV2);
|
|
65
|
+
if (shadeCache) {
|
|
66
|
+
byKey ??= /* @__PURE__ */ new Map();
|
|
67
|
+
byKey.set(shadeKey, texture);
|
|
68
|
+
shadeCache.set(face.texture, byKey);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
59
71
|
const uvs = [
|
|
60
72
|
[geometry.uv1[0], geometry.uv1[1]],
|
|
61
73
|
[geometry.uv1[0] + uvWidth, geometry.uv1[1]],
|
|
@@ -67,7 +79,8 @@ function renderFace(face, width, height, transformation) {
|
|
|
67
79
|
const last = uvs.pop();
|
|
68
80
|
if (last) uvs.unshift(last);
|
|
69
81
|
}
|
|
70
|
-
const buffer = createFaceBuffer(width, height);
|
|
82
|
+
const buffer = scratch ?? createFaceBuffer(width, height);
|
|
83
|
+
clearFaceBuffer(buffer);
|
|
71
84
|
const depths = [
|
|
72
85
|
linearDepth(v0[2]),
|
|
73
86
|
linearDepth(v1[2]),
|