@poe2-toolkit/tree-extractor 0.1.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/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/atlas.d.ts +30 -0
- package/dist/atlas.d.ts.map +1 -0
- package/dist/atlas.js +48 -0
- package/dist/atlas.js.map +1 -0
- package/dist/buildCentre.d.ts +17 -0
- package/dist/buildCentre.d.ts.map +1 -0
- package/dist/buildCentre.js +71 -0
- package/dist/buildCentre.js.map +1 -0
- package/dist/buildGraphics.d.ts +42 -0
- package/dist/buildGraphics.d.ts.map +1 -0
- package/dist/buildGraphics.js +124 -0
- package/dist/buildGraphics.js.map +1 -0
- package/dist/buildTree.d.ts +77 -0
- package/dist/buildTree.d.ts.map +1 -0
- package/dist/buildTree.js +299 -0
- package/dist/buildTree.js.map +1 -0
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +67 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/psg.d.ts +52 -0
- package/dist/psg.d.ts.map +1 -0
- package/dist/psg.js +83 -0
- package/dist/psg.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Vladislav Rajtmajer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# @poe2-toolkit/tree-extractor
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@poe2-toolkit/tree-extractor)
|
|
4
|
+
[](#)
|
|
5
|
+
[](#)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Builds the **Path of Exile 2 passive tree** — the node data and the sprite
|
|
9
|
+
atlases — straight from the official GGPK / patch server, in the shape
|
|
10
|
+
[`@poe2-toolkit/tree-core`](../poe2-tree-core) consumes.
|
|
11
|
+
|
|
12
|
+
It is source-agnostic: it never downloads anything itself. You hand it a
|
|
13
|
+
[`@poe2-toolkit/ggpk`](../poe2-ggpk) source and it returns the data, ready to use or to
|
|
14
|
+
write wherever you publish it.
|
|
15
|
+
|
|
16
|
+
**Code only.** This package ships no game data and no art. Everything it produces
|
|
17
|
+
is read from the patch server at run time and handed back to you; nothing from
|
|
18
|
+
the game is bundled or stored here.
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install @poe2-toolkit/tree-extractor @poe2-toolkit/ggpk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Node 18+. ESM only. TypeScript types are included.
|
|
27
|
+
|
|
28
|
+
## The contract
|
|
29
|
+
|
|
30
|
+
The library **returns formatted data** — it performs no I/O of its own beyond
|
|
31
|
+
what the source serves, and it never writes to disk. You decide what to do with
|
|
32
|
+
the result.
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { createCdnSource } from '@poe2-toolkit/ggpk';
|
|
36
|
+
import { extractTree } from '@poe2-toolkit/tree-extractor';
|
|
37
|
+
|
|
38
|
+
const source = await createCdnSource({
|
|
39
|
+
patch: '4.5.3.1.7',
|
|
40
|
+
tablesDir: './tables/English',
|
|
41
|
+
cacheDir: './.cache',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const { data, graphics, centre } = await extractTree(source);
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`extractTree(source)` returns a `TreeBundle`:
|
|
48
|
+
|
|
49
|
+
| Field | Type | What it is |
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
| `data` | `TreeExport` | The `data.json` payload — `@poe2-toolkit/tree-core`'s normalize input (nodes, groups, classes, jewel slots, attribute choices). |
|
|
52
|
+
| `graphics` | `GraphicsResult` | The four sprite atlases (`skills`, `skills-disabled`, `frame`, `mastery-effect-active`), each a packed PNG plus its frame-map, with a report of what packed or was skipped. |
|
|
53
|
+
| `centre` | `Record<string, Buffer>` | Centre art keyed by output name (`portrait-ranger`, `ascendancy-deadeye`, `ring-static`, …), each a PNG buffer. |
|
|
54
|
+
|
|
55
|
+
The individual steps are exported too, if you only need one:
|
|
56
|
+
`buildTree(source)`, `buildGraphics(source, data)`, `buildCentre(source)`.
|
|
57
|
+
|
|
58
|
+
## CLI: write the bundle to disk
|
|
59
|
+
|
|
60
|
+
When you do want files, the bundled CLI writes the whole bundle to a
|
|
61
|
+
**configurable output directory** — nothing is written inside the package:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
poe2-tree-extract \
|
|
65
|
+
--patch 4.5.3.1.7 \
|
|
66
|
+
--tables ./tables/English \
|
|
67
|
+
--cache ./.cache \
|
|
68
|
+
--out ./out/tree
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It writes `data.json`, the four atlases as `assets/<name>.png` + `<name>.json`,
|
|
72
|
+
and the centre art as `centre/<name>.png`. Output is PNG + JSON; converting the
|
|
73
|
+
PNGs to WebP for the web is a separate publish step left to you.
|
|
74
|
+
|
|
75
|
+
## How it works
|
|
76
|
+
|
|
77
|
+
- **Data** comes from GGPK tables (`PassiveSkills`, `PassiveSkillMasteryGroups`,
|
|
78
|
+
`Characters`, `Ascendancy`, …) joined to the `.psg` passive-graph geometry,
|
|
79
|
+
with stat lines rendered through `@poe2-toolkit/ggpk`'s stat-description engine.
|
|
80
|
+
- **Sprites** are decoded from GGPK DDS art and packed into atlases keyed exactly
|
|
81
|
+
as the renderer expects. A sprite the source cannot serve is skipped and
|
|
82
|
+
reported — never pulled from a vendored asset.
|
|
83
|
+
|
|
84
|
+
Released PoE2 classes and ascendancies only; the GGPK's leftover PoE1 placeholder
|
|
85
|
+
classes are filtered out from the data.
|
|
86
|
+
|
|
87
|
+
## Attributions and legal
|
|
88
|
+
|
|
89
|
+
This is an unofficial, fan-made project, **not** affiliated with, endorsed by, or
|
|
90
|
+
sponsored by Grinding Gear Games. "Path of Exile 2" is a trademark of Grinding
|
|
91
|
+
Gear Games, and all game content, data, and art are their property. This package
|
|
92
|
+
ships code only and stores nothing derived from the game. Thank you to Grinding
|
|
93
|
+
Gear Games for making Path of Exile 2.
|
|
94
|
+
|
|
95
|
+
GGPK access is provided by [`@poe2-toolkit/ggpk`](../poe2-ggpk), which builds on
|
|
96
|
+
[`pathofexile-dat`](https://github.com/SnosMe/poe-dat-viewer) (MIT, © SnosMe).
|
|
97
|
+
Full attribution is in the repository [NOTICE](../../NOTICE.md).
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/atlas.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shelf bin-packer: composites decoded sprites into one sheet and emits the
|
|
3
|
+
* frame-map the renderer reads (`{ frames: { key: { frame: { x, y, w, h } } } }`).
|
|
4
|
+
*/
|
|
5
|
+
/** A decoded sprite to place in an atlas, keyed by its renderer atlas key. */
|
|
6
|
+
export interface AtlasSprite {
|
|
7
|
+
key: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
rgba: Uint8Array;
|
|
11
|
+
}
|
|
12
|
+
/** One placed sprite's pixel rect inside the packed sheet. */
|
|
13
|
+
export interface AtlasFrame {
|
|
14
|
+
frame: {
|
|
15
|
+
x: number;
|
|
16
|
+
y: number;
|
|
17
|
+
w: number;
|
|
18
|
+
h: number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** A packed atlas: its PNG bytes and the frame-map keyed by sprite key. */
|
|
22
|
+
export interface PackedAtlas {
|
|
23
|
+
png: Buffer;
|
|
24
|
+
frames: Record<string, AtlasFrame>;
|
|
25
|
+
}
|
|
26
|
+
/** Pack sprites into a single sheet, tallest-first, wrapping at `maxWidth`. */
|
|
27
|
+
export declare function packAtlas(sprites: AtlasSprite[], maxWidth?: number): PackedAtlas;
|
|
28
|
+
/** Grayscale (luminance) copy, alpha preserved — the dimmed/inactive look. */
|
|
29
|
+
export declare function desaturate(rgba: Uint8Array): Uint8Array;
|
|
30
|
+
//# sourceMappingURL=atlas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas.d.ts","sourceRoot":"","sources":["../src/atlas.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,8DAA8D;AAC9D,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD;AAED,2EAA2E;AAC3E,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACpC;AAKD,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,QAAQ,SAAO,GAAG,WAAW,CAoC9E;AAED,8EAA8E;AAC9E,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAUvD"}
|
package/dist/atlas.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shelf bin-packer: composites decoded sprites into one sheet and emits the
|
|
3
|
+
* frame-map the renderer reads (`{ frames: { key: { frame: { x, y, w, h } } } }`).
|
|
4
|
+
*/
|
|
5
|
+
import { encodePng } from '@poe2-toolkit/ggpk';
|
|
6
|
+
/** Transparent gutter so neighbours never bleed under bilinear sampling. */
|
|
7
|
+
const PAD = 1;
|
|
8
|
+
/** Pack sprites into a single sheet, tallest-first, wrapping at `maxWidth`. */
|
|
9
|
+
export function packAtlas(sprites, maxWidth = 2048) {
|
|
10
|
+
// Tallest-first shelf packing keeps rows tight and the sheet near-square.
|
|
11
|
+
const sorted = [...sprites].sort((a, b) => b.height - a.height);
|
|
12
|
+
let x = 0, y = 0, shelfHeight = 0, sheetWidth = 0;
|
|
13
|
+
const placed = [];
|
|
14
|
+
for (const sprite of sorted) {
|
|
15
|
+
if (x + sprite.width + PAD > maxWidth && x > 0) {
|
|
16
|
+
x = 0;
|
|
17
|
+
y += shelfHeight + PAD;
|
|
18
|
+
shelfHeight = 0;
|
|
19
|
+
}
|
|
20
|
+
placed.push({ sprite, x, y });
|
|
21
|
+
x += sprite.width + PAD;
|
|
22
|
+
shelfHeight = Math.max(shelfHeight, sprite.height);
|
|
23
|
+
sheetWidth = Math.max(sheetWidth, x);
|
|
24
|
+
}
|
|
25
|
+
const sheetHeight = y + shelfHeight;
|
|
26
|
+
const sheet = new Uint8Array(sheetWidth * sheetHeight * 4);
|
|
27
|
+
const frames = {};
|
|
28
|
+
for (const { sprite, x: sx, y: sy } of placed) {
|
|
29
|
+
for (let row = 0; row < sprite.height; row++) {
|
|
30
|
+
const src = row * sprite.width * 4;
|
|
31
|
+
const dst = ((sy + row) * sheetWidth + sx) * 4;
|
|
32
|
+
sheet.set(sprite.rgba.subarray(src, src + sprite.width * 4), dst);
|
|
33
|
+
}
|
|
34
|
+
frames[sprite.key] = { frame: { x: sx, y: sy, w: sprite.width, h: sprite.height } };
|
|
35
|
+
}
|
|
36
|
+
return { png: encodePng(sheetWidth, sheetHeight, sheet), frames };
|
|
37
|
+
}
|
|
38
|
+
/** Grayscale (luminance) copy, alpha preserved — the dimmed/inactive look. */
|
|
39
|
+
export function desaturate(rgba) {
|
|
40
|
+
const out = new Uint8Array(rgba.length);
|
|
41
|
+
for (let i = 0; i < rgba.length; i += 4) {
|
|
42
|
+
const lum = Math.round(0.299 * rgba[i] + 0.587 * rgba[i + 1] + 0.114 * rgba[i + 2]);
|
|
43
|
+
out[i] = out[i + 1] = out[i + 2] = lum;
|
|
44
|
+
out[i + 3] = rgba[i + 3];
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=atlas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas.js","sourceRoot":"","sources":["../src/atlas.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the tree's centre art from GGPK: per-class portraits (real PoE2
|
|
3
|
+
* classes only — those with a released ascendancy), per-ascendancy portraits
|
|
4
|
+
* (released only), and the two hub-ring sprites. All decoded to PNG.
|
|
5
|
+
*
|
|
6
|
+
* Like the rest of the rewrite this is GGPK-only: art the source cannot serve is
|
|
7
|
+
* skipped, never pulled from a vendored GGG sheet.
|
|
8
|
+
*/
|
|
9
|
+
import type { GgpkImageSource, GgpkSource } from '@poe2-toolkit/ggpk';
|
|
10
|
+
/** A source able to both read tables and fetch images. */
|
|
11
|
+
export type CentreSource = GgpkSource & GgpkImageSource;
|
|
12
|
+
/**
|
|
13
|
+
* Build the centre art. Returns a map of output name (without extension, e.g.
|
|
14
|
+
* `portrait-ranger`, `ascendancy-deadeye`, `ring-static`) to its PNG bytes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buildCentre(source: CentreSource): Promise<Record<string, Buffer>>;
|
|
17
|
+
//# sourceMappingURL=buildCentre.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildCentre.d.ts","sourceRoot":"","sources":["../src/buildCentre.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAC,eAAe,EAAE,UAAU,EAAC,MAAM,oBAAoB,CAAC;AAKpE,0DAA0D;AAC1D,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,eAAe,CAAC;AAuBxD;;;GAGG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoDvF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extracts the tree's centre art from GGPK: per-class portraits (real PoE2
|
|
3
|
+
* classes only — those with a released ascendancy), per-ascendancy portraits
|
|
4
|
+
* (released only), and the two hub-ring sprites. All decoded to PNG.
|
|
5
|
+
*
|
|
6
|
+
* Like the rest of the rewrite this is GGPK-only: art the source cannot serve is
|
|
7
|
+
* skipped, never pulled from a vendored GGG sheet.
|
|
8
|
+
*/
|
|
9
|
+
import { encodePng } from '@poe2-toolkit/ggpk';
|
|
10
|
+
/** The hub-ring sprites, by output name and UIImages logical name. */
|
|
11
|
+
const RING = [
|
|
12
|
+
{ out: 'ring-static', name: 'Art/2DArt/UIImages/InGame/PassiveTree/PassiveTreeMainCircle' },
|
|
13
|
+
{ out: 'ring-active', name: 'Art/2DArt/UIImages/InGame/PassiveTree/PassiveTreeMainCircleActive2' },
|
|
14
|
+
];
|
|
15
|
+
function isReleased(asc) {
|
|
16
|
+
return Boolean(asc.Name) && !asc.Name.includes('[DNT') && !asc.Disabled;
|
|
17
|
+
}
|
|
18
|
+
/** Decode a DDS path to a PNG buffer, or `null` if the source can't serve it. */
|
|
19
|
+
async function emit(source, ddsPath) {
|
|
20
|
+
if (!ddsPath?.toLowerCase().endsWith('.dds')) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
const img = await source.dds(ddsPath);
|
|
24
|
+
return img ? encodePng(img.width, img.height, img.rgba) : null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build the centre art. Returns a map of output name (without extension, e.g.
|
|
28
|
+
* `portrait-ranger`, `ascendancy-deadeye`, `ring-static`) to its PNG bytes.
|
|
29
|
+
*/
|
|
30
|
+
export async function buildCentre(source) {
|
|
31
|
+
const Characters = (await source.table('Characters'));
|
|
32
|
+
const Ascendancy = (await source.table('Ascendancy'));
|
|
33
|
+
const out = {};
|
|
34
|
+
// Real PoE2 classes only: the ones with a released ascendancy. GGPK still
|
|
35
|
+
// carries 4 PoE1 placeholder classes whose ascendancies are all [DNT-UNUSED].
|
|
36
|
+
const realClassIndex = new Set();
|
|
37
|
+
for (const asc of Ascendancy) {
|
|
38
|
+
if (isReleased(asc) && asc.Character != null) {
|
|
39
|
+
realClassIndex.add(asc.Character);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const [index, character] of Characters.entries()) {
|
|
43
|
+
if (!realClassIndex.has(index)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const png = await emit(source, character.PassiveTreeImage);
|
|
47
|
+
if (png) {
|
|
48
|
+
out[`portrait-${character.Name.toLowerCase()}`] = png;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const asc of Ascendancy) {
|
|
52
|
+
if (!isReleased(asc)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
const slug = asc.Name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
|
|
56
|
+
const png = await emit(source, asc.PassiveTreeImage);
|
|
57
|
+
if (png) {
|
|
58
|
+
out[`ascendancy-${slug}`] = png;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
// Hub ring: static ornate circle + active-class edge marker.
|
|
62
|
+
for (const { out: name, name: logical } of RING) {
|
|
63
|
+
const ref = await source.resolveSprite(logical);
|
|
64
|
+
const png = ref ? await emit(source, ref.path) : null;
|
|
65
|
+
if (png) {
|
|
66
|
+
out[name] = png;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=buildCentre.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildCentre.js","sourceRoot":"","sources":["../src/buildCentre.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the passive-tree sprite atlases from GGPK art, in the shape the
|
|
3
|
+
* renderer reads: skill icons (`skills` + desaturated `skills-disabled`), node
|
|
4
|
+
* frames (`frame`), and mastery effect patterns (`mastery-effect-active`).
|
|
5
|
+
* Atlas keys mirror the engine's `spriteKeys`. Source: GGPK only.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the legacy script this has no GGG-export fallback: a sprite the source
|
|
8
|
+
* cannot serve is skipped and reported, never pulled from a vendored asset.
|
|
9
|
+
*/
|
|
10
|
+
import type { GgpkImageSource, GgpkSource } from '@poe2-toolkit/ggpk';
|
|
11
|
+
import type { PackedAtlas } from './atlas.js';
|
|
12
|
+
import type { TreeExport } from './buildTree.js';
|
|
13
|
+
/** The four atlases this build produces, keyed by atlas name. */
|
|
14
|
+
export interface TreeAtlases {
|
|
15
|
+
skills: PackedAtlas;
|
|
16
|
+
'skills-disabled': PackedAtlas;
|
|
17
|
+
frame: PackedAtlas;
|
|
18
|
+
'mastery-effect-active': PackedAtlas;
|
|
19
|
+
}
|
|
20
|
+
/** Per-atlas counts of sprites packed and sources missing, for reporting. */
|
|
21
|
+
export interface GraphicsReport {
|
|
22
|
+
skills: {
|
|
23
|
+
packed: number;
|
|
24
|
+
missing: number;
|
|
25
|
+
};
|
|
26
|
+
frames: {
|
|
27
|
+
packed: number;
|
|
28
|
+
};
|
|
29
|
+
masteryEffects: {
|
|
30
|
+
packed: number;
|
|
31
|
+
missing: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** The build's atlases plus a report of what was packed or skipped. */
|
|
35
|
+
export interface GraphicsResult {
|
|
36
|
+
atlases: TreeAtlases;
|
|
37
|
+
report: GraphicsReport;
|
|
38
|
+
}
|
|
39
|
+
/** A source able to both read tables and fetch images. */
|
|
40
|
+
export type GraphicsSource = GgpkSource & GgpkImageSource;
|
|
41
|
+
export declare function buildGraphics(source: GraphicsSource, tree: TreeExport): Promise<GraphicsResult>;
|
|
42
|
+
//# sourceMappingURL=buildGraphics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildGraphics.d.ts","sourceRoot":"","sources":["../src/buildGraphics.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAc,WAAW,EAAC,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAc,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D,iEAAiE;AACjE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,WAAW,CAAC;IACpB,iBAAiB,EAAE,WAAW,CAAC;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,uBAAuB,EAAE,WAAW,CAAC;CACtC;AAED,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,cAAc,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,cAAc,CAAC;CACxB;AAcD,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,eAAe,CAAC;AAmB1D,wBAAsB,aAAa,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CA0HrG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the passive-tree sprite atlases from GGPK art, in the shape the
|
|
3
|
+
* renderer reads: skill icons (`skills` + desaturated `skills-disabled`), node
|
|
4
|
+
* frames (`frame`), and mastery effect patterns (`mastery-effect-active`).
|
|
5
|
+
* Atlas keys mirror the engine's `spriteKeys`. Source: GGPK only.
|
|
6
|
+
*
|
|
7
|
+
* Unlike the legacy script this has no GGG-export fallback: a sprite the source
|
|
8
|
+
* cannot serve is skipped and reported, never pulled from a vendored asset.
|
|
9
|
+
*/
|
|
10
|
+
import { desaturate, packAtlas } from './atlas.js';
|
|
11
|
+
/** Engine variant prefix for a node's skill icon (mirrors `iconKeyFor`). */
|
|
12
|
+
function variantOf(node) {
|
|
13
|
+
if (node.isMastery) {
|
|
14
|
+
return null; // masteries render as their effect pattern
|
|
15
|
+
}
|
|
16
|
+
if (node.isKeystone) {
|
|
17
|
+
return 'keystone';
|
|
18
|
+
}
|
|
19
|
+
if (node.isNotable) {
|
|
20
|
+
return 'notable';
|
|
21
|
+
}
|
|
22
|
+
return 'normal';
|
|
23
|
+
}
|
|
24
|
+
export async function buildGraphics(source, tree) {
|
|
25
|
+
// --- skill icons: skills (active) + skills-disabled (desaturated) ----------
|
|
26
|
+
// icon-path -> variant; first node wins, same icon shares a variant.
|
|
27
|
+
const wanted = new Map();
|
|
28
|
+
for (const node of Object.values(tree.nodes)) {
|
|
29
|
+
const variant = variantOf(node);
|
|
30
|
+
if (variant && node.icon && !wanted.has(`${variant}:${node.icon}`)) {
|
|
31
|
+
wanted.set(`${variant}:${node.icon}`, { variant, icon: node.icon });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// +attribute choice icons (Str/Dex/Int) — shown on the node once an attribute
|
|
35
|
+
// is picked; not a node's own icon, so add them explicitly.
|
|
36
|
+
for (const override of Object.values(tree.skillOverrides)) {
|
|
37
|
+
const icon = override.icon;
|
|
38
|
+
if (typeof icon === 'string' && icon && !wanted.has(`normal:${icon}`)) {
|
|
39
|
+
wanted.set(`normal:${icon}`, { variant: 'normal', icon });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const active = [];
|
|
43
|
+
const inactive = [];
|
|
44
|
+
let iconsMissing = 0;
|
|
45
|
+
for (const { variant, icon } of wanted.values()) {
|
|
46
|
+
const img = await source.dds(icon);
|
|
47
|
+
if (!img) {
|
|
48
|
+
iconsMissing += 1;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
active.push({ key: `${variant}Active:${icon}`, width: img.width, height: img.height, rgba: img.rgba });
|
|
52
|
+
inactive.push({ key: `${variant}Inactive:${icon}`, width: img.width, height: img.height, rgba: desaturate(img.rgba) });
|
|
53
|
+
}
|
|
54
|
+
// --- node frames: frame atlas ----------------------------------------------
|
|
55
|
+
// The UIArt "Character" row drives the main tree, "Ascendancy" the disc frames.
|
|
56
|
+
// NodeFrameArt Normal/CanAllocate/Active map to the renderer's states.
|
|
57
|
+
const UIArt = (await source.table('PassiveSkillTreeUIArt'));
|
|
58
|
+
const NodeFrameArt = (await source.table('PassiveSkillTreeNodeFrameArt'));
|
|
59
|
+
const mainUi = UIArt.find((r) => r.Id === 'Character');
|
|
60
|
+
const ascUi = UIArt.find((r) => r.Id === 'Ascendancy');
|
|
61
|
+
const frameSprites = [];
|
|
62
|
+
const addFrame = async (key, frameArtIndex, state) => {
|
|
63
|
+
const art = frameArtIndex != null ? NodeFrameArt[frameArtIndex] : undefined;
|
|
64
|
+
const path = art?.[state];
|
|
65
|
+
const img = path ? await source.uiSprite(path) : null;
|
|
66
|
+
if (img) {
|
|
67
|
+
frameSprites.push({ key, width: img.width, height: img.height, rgba: img.rgba });
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
// Main-tree frames (engine keys from frameKeyFor).
|
|
71
|
+
await addFrame('KeystoneFrameUnallocated', mainUi?.KeystoneFrame, 'Normal');
|
|
72
|
+
await addFrame('KeystoneFrameCanAllocate', mainUi?.KeystoneFrame, 'CanAllocate');
|
|
73
|
+
await addFrame('KeystoneFrameAllocated', mainUi?.KeystoneFrame, 'Active');
|
|
74
|
+
await addFrame('NotableFrameUnallocated', mainUi?.NotableFrame, 'Normal');
|
|
75
|
+
await addFrame('NotableFrameCanAllocate', mainUi?.NotableFrame, 'CanAllocate');
|
|
76
|
+
await addFrame('NotableFrameAllocated', mainUi?.NotableFrame, 'Active');
|
|
77
|
+
await addFrame('JewelFrameUnallocated', mainUi?.JewelFrame, 'Normal');
|
|
78
|
+
await addFrame('JewelFrameCanAllocate', mainUi?.JewelFrame, 'CanAllocate');
|
|
79
|
+
await addFrame('JewelFrameAllocated', mainUi?.JewelFrame, 'Active');
|
|
80
|
+
await addFrame('PSSkillFrame', mainUi?.PassiveFrame, 'Normal');
|
|
81
|
+
await addFrame('PSSkillFrameHighlighted', mainUi?.PassiveFrame, 'CanAllocate');
|
|
82
|
+
await addFrame('PSSkillFrameActive', mainUi?.PassiveFrame, 'Active');
|
|
83
|
+
// Ascendancy disc frames.
|
|
84
|
+
await addFrame('AscendancyFrameNormalUnallocated', ascUi?.PassiveFrame, 'Normal');
|
|
85
|
+
await addFrame('AscendancyFrameNormalAllocated', ascUi?.PassiveFrame, 'Active');
|
|
86
|
+
await addFrame('AscendancyFrameNotableUnallocated', ascUi?.NotableFrame, 'Normal');
|
|
87
|
+
await addFrame('AscendancyFrameNotableAllocated', ascUi?.NotableFrame, 'Active');
|
|
88
|
+
await addFrame('AscendancyStartNode', ascUi?.AscendancyStart, 'Active');
|
|
89
|
+
// --- mastery effect patterns: mastery-effect-active atlas ------------------
|
|
90
|
+
// Renderer keys them `masteryEffectActive:<ActiveEffectImage>.png`.
|
|
91
|
+
const effectImages = new Set();
|
|
92
|
+
for (const node of Object.values(tree.nodes)) {
|
|
93
|
+
if (node.activeEffectImage) {
|
|
94
|
+
effectImages.add(node.activeEffectImage);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const masterySprites = [];
|
|
98
|
+
let masteryMissing = 0;
|
|
99
|
+
for (const path of effectImages) {
|
|
100
|
+
const img = await source.uiSprite(path);
|
|
101
|
+
if (!img) {
|
|
102
|
+
masteryMissing += 1;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
masterySprites.push({ key: `masteryEffectActive:${path}.png`, width: img.width, height: img.height, rgba: img.rgba });
|
|
106
|
+
}
|
|
107
|
+
// Patterns are large (~775²); a wide sheet keeps both dimensions under webp's
|
|
108
|
+
// 16383px cap.
|
|
109
|
+
const atlases = {
|
|
110
|
+
'skills': packAtlas(active),
|
|
111
|
+
'skills-disabled': packAtlas(inactive),
|
|
112
|
+
'frame': packAtlas(frameSprites),
|
|
113
|
+
'mastery-effect-active': packAtlas(masterySprites, 6000),
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
atlases,
|
|
117
|
+
report: {
|
|
118
|
+
skills: { packed: active.length, missing: iconsMissing },
|
|
119
|
+
frames: { packed: frameSprites.length },
|
|
120
|
+
masteryEffects: { packed: masterySprites.length, missing: masteryMissing },
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=buildGraphics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildGraphics.js","sourceRoot":"","sources":["../src/buildGraphics.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the passive-tree `data.json` from GGPK tables + the `.psg` graph, in
|
|
3
|
+
* the shape `@poe2-toolkit/tree-core`'s `normalizeGggTree` expects. Source of truth:
|
|
4
|
+
* GGPK only.
|
|
5
|
+
*
|
|
6
|
+
* Linkage (verified): a node's `skill` = PassiveSkillGraphId; the `.psg` keys
|
|
7
|
+
* nodes by the same id; PassiveSkills rows join by PassiveSkillGraphId.
|
|
8
|
+
* Positions are computed from group centre + orbit radius + orbit index (radii
|
|
9
|
+
* derived from the live tree, exact). Stats render via the passive + base
|
|
10
|
+
* stat-description files.
|
|
11
|
+
*/
|
|
12
|
+
import type { GgpkSource } from '@poe2-toolkit/ggpk';
|
|
13
|
+
/** A tree node as serialized to `data.json` (graph node, or data-only override). */
|
|
14
|
+
export interface ExportNode {
|
|
15
|
+
skill: number;
|
|
16
|
+
name: string;
|
|
17
|
+
icon: string;
|
|
18
|
+
stats: string[];
|
|
19
|
+
group?: number;
|
|
20
|
+
orbit?: number;
|
|
21
|
+
orbitIndex?: number;
|
|
22
|
+
x?: number;
|
|
23
|
+
y?: number;
|
|
24
|
+
out?: number[];
|
|
25
|
+
in?: number[];
|
|
26
|
+
isNotable?: true;
|
|
27
|
+
isKeystone?: true;
|
|
28
|
+
isJewelSocket?: true;
|
|
29
|
+
isMastery?: true;
|
|
30
|
+
isGenericAttribute?: true;
|
|
31
|
+
isAscendancyStart?: true;
|
|
32
|
+
activeEffectImage?: string;
|
|
33
|
+
ascendancyId?: string;
|
|
34
|
+
classStartIndex?: number[];
|
|
35
|
+
flavourText?: unknown;
|
|
36
|
+
}
|
|
37
|
+
export interface ExportAscendancy {
|
|
38
|
+
id: string;
|
|
39
|
+
name: string;
|
|
40
|
+
offsetX: number;
|
|
41
|
+
offsetY: number;
|
|
42
|
+
}
|
|
43
|
+
export interface ExportClass {
|
|
44
|
+
name: string;
|
|
45
|
+
base_str: number;
|
|
46
|
+
base_dex: number;
|
|
47
|
+
base_int: number;
|
|
48
|
+
ascendancies: ExportAscendancy[];
|
|
49
|
+
overridePairs: Record<number, number>;
|
|
50
|
+
}
|
|
51
|
+
export interface ExportGroup {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
orbits: number[];
|
|
55
|
+
nodes: number[];
|
|
56
|
+
}
|
|
57
|
+
/** The full `data.json` payload. */
|
|
58
|
+
export interface TreeExport {
|
|
59
|
+
tree: string;
|
|
60
|
+
classes: ExportClass[];
|
|
61
|
+
groups: Record<number, ExportGroup>;
|
|
62
|
+
nodes: Record<number, ExportNode>;
|
|
63
|
+
edges: never[];
|
|
64
|
+
skillOverrides: Record<number, Record<string, unknown>>;
|
|
65
|
+
jewelSlots: number[];
|
|
66
|
+
min_x: number;
|
|
67
|
+
min_y: number;
|
|
68
|
+
max_x: number;
|
|
69
|
+
max_y: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build the passive-tree export. All data comes from the supplied
|
|
73
|
+
* {@link GgpkSource}; this function performs no I/O of its own beyond what the
|
|
74
|
+
* source serves.
|
|
75
|
+
*/
|
|
76
|
+
export declare function buildTree(source: GgpkSource): Promise<TreeExport>;
|
|
77
|
+
//# sourceMappingURL=buildTree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildTree.d.ts","sourceRoot":"","sources":["../src/buildTree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAC,UAAU,EAAY,MAAM,oBAAoB,CAAC;AA+C9D,oFAAoF;AACpF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACd,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,kBAAkB,CAAC,EAAE,IAAI,CAAC;IAC1B,iBAAiB,CAAC,EAAE,IAAI,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,gBAAgB;IAAG,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AAEhG,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,WAAW;IAAG,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE;AAExF,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAaD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAqUvE"}
|