cyclops-infobook-html 4.0.1 → 5.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/README.md +23 -2
- package/bin/compress-icons.d.ts +2 -0
- package/bin/compress-icons.js +47 -0
- package/bin/generate-icons.d.ts +2 -0
- package/bin/generate-icons.js +68 -0
- package/bin/generate-infobook-html.js +16 -8
- package/bin/generate-mod-metadata.js +15 -7
- package/index.d.ts +2 -0
- package/index.js +39 -24
- package/lib/icon/IconsCompressor.d.ts +18 -0
- package/lib/icon/IconsCompressor.js +81 -0
- package/lib/icon/IconsGenerator.d.ts +128 -0
- package/lib/icon/IconsGenerator.js +597 -0
- package/lib/infobook/FileWriter.d.ts +1 -2
- package/lib/infobook/FileWriter.js +21 -6
- package/lib/infobook/IFileWriter.d.ts +1 -2
- package/lib/infobook/IInfoAppendix.d.ts +1 -1
- package/lib/infobook/InfoBookInitializer.js +10 -2
- package/lib/infobook/appendix/InfoBookAppendixAd.d.ts +1 -1
- package/lib/infobook/appendix/InfoBookAppendixAd.js +13 -2
- package/lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe.d.ts +1 -1
- package/lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe.js +13 -4
- package/lib/infobook/appendix/InfoBookAppendixHandlerAdvancementRewards.js +14 -5
- package/lib/infobook/appendix/InfoBookAppendixHandlerCraftingRecipe.d.ts +1 -1
- package/lib/infobook/appendix/InfoBookAppendixHandlerCraftingRecipe.js +39 -28
- package/lib/infobook/appendix/InfoBookAppendixHandlerImage.js +13 -4
- package/lib/infobook/appendix/InfoBookAppendixHandlerKeybinding.js +12 -3
- package/lib/infobook/appendix/InfoBookAppendixHandlerSmeltingRecipe.d.ts +1 -1
- package/lib/infobook/appendix/InfoBookAppendixHandlerSmeltingRecipe.js +16 -5
- package/lib/infobook/appendix/InfoBookAppendixHandlerTextfield.js +11 -2
- package/lib/infobook/appendix/InfoBookAppendixTagIndex.d.ts +1 -1
- package/lib/infobook/appendix/InfoBookAppendixTagIndex.js +31 -20
- package/lib/modloader/ModLoader.d.ts +2 -3
- package/lib/modloader/ModLoader.js +56 -48
- package/lib/parse/XmlInfoBookParser.js +2 -2
- package/lib/resource/ResourceHandler.d.ts +2 -1
- package/lib/resource/ResourceHandler.js +7 -3
- package/lib/resource/ResourceLoader.d.ts +5 -5
- package/lib/resource/ResourceLoader.js +37 -28
- package/lib/serialize/HtmlInfoBookSerializer.d.ts +2 -2
- package/lib/serialize/HtmlInfoBookSerializer.js +80 -65
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -13,11 +13,12 @@ This tool is the basis for the following mod-specific plugins:
|
|
|
13
13
|
|
|
14
14
|
## Usage
|
|
15
15
|
|
|
16
|
-
This tool allows Cyclops infobooks to be exported as an HTML website in
|
|
16
|
+
This tool allows Cyclops infobooks to be exported as an HTML website in four phases:
|
|
17
17
|
|
|
18
18
|
1. Metadata generation: A preparation step for generating all required metadata that is needed for serializing the infobook to HTML.
|
|
19
19
|
2. Icon generation: Exporting item and block icons to PNG files.
|
|
20
20
|
3. HTML generation: Serialization to HTML based on the infook XML and metadata.
|
|
21
|
+
4. Icon compression: Optionally compress icons within the output directory.
|
|
21
22
|
|
|
22
23
|
### 1. Metadata Generation
|
|
23
24
|
|
|
@@ -64,13 +65,28 @@ If you want to re-download the mods without re-installing Forge, you can run `ge
|
|
|
64
65
|
|
|
65
66
|
### 2. Icon Generation
|
|
66
67
|
|
|
67
|
-
This phase
|
|
68
|
+
This phase can be done manually using the [Icon Exporter mod](https://github.com/CyclopsMC/IconExporter), or automatically.
|
|
69
|
+
|
|
70
|
+
#### Manual icon generation
|
|
68
71
|
|
|
69
72
|
Simply create a modpack with all the mods that were downloaded in the previous step (including the Item Exporter mod),
|
|
70
73
|
start a world, and run the `/iconexporter export 64` command.
|
|
71
74
|
|
|
72
75
|
Next, copy the resulting contents of `icon-exports-x64` to `icons` in your project directory.
|
|
73
76
|
|
|
77
|
+
#### Automatic icon generation
|
|
78
|
+
|
|
79
|
+
The `generate-icons` command can be executed,
|
|
80
|
+
which will cause a Headless Minecraft instance to be downloaded and started,
|
|
81
|
+
and the Icon Exporter mod to be ran.
|
|
82
|
+
|
|
83
|
+
When running this on a headless machine, you should have `xvfb` installed and running.
|
|
84
|
+
For example:
|
|
85
|
+
```
|
|
86
|
+
$ sudo apt-get install -y xvfb
|
|
87
|
+
$ xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" generate-icons
|
|
88
|
+
```
|
|
89
|
+
|
|
74
90
|
### 3. HTML Generation
|
|
75
91
|
|
|
76
92
|
Before you start this phase, make sure the following files and directories are present:
|
|
@@ -130,6 +146,11 @@ Before you start this phase, make sure the following files and directories are p
|
|
|
130
146
|
This phase can be started by executing `generate-cyclops-infobook-html config.json /output`.
|
|
131
147
|
Afterwards, the contents of `/output` can be hosted on any Web server.
|
|
132
148
|
|
|
149
|
+
### 4. Icon Compression
|
|
150
|
+
|
|
151
|
+
Using the `compress-icons` command, icons within the `output/` directory will be compressed.
|
|
152
|
+
This is recommended when deploying the output to a web server.
|
|
153
|
+
|
|
133
154
|
### Plugins
|
|
134
155
|
|
|
135
156
|
Optionally, plugins can be loaded to for example add support for non-default appendix handlers.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const minimist = require("minimist");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const IconsCompressor_1 = require("../lib/icon/IconsCompressor");
|
|
17
|
+
// Process CLI args
|
|
18
|
+
const args = minimist(process.argv.slice(2));
|
|
19
|
+
if (args.help || args._.length < 1) {
|
|
20
|
+
printUsage();
|
|
21
|
+
}
|
|
22
|
+
function run(outputDir) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const iconsDir = (0, path_1.resolve)(outputDir, 'assets', 'icon');
|
|
25
|
+
if (!fs.existsSync(iconsDir)) {
|
|
26
|
+
process.stderr.write(`Icons directory not found: ${iconsDir}\n`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const compressor = new IconsCompressor_1.IconsCompressor(iconsDir);
|
|
30
|
+
yield compressor.compress();
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function printUsage() {
|
|
34
|
+
process.stdout.write(`compress-icons Losslessly compress PNG icons in the HTML output directory
|
|
35
|
+
Usage:
|
|
36
|
+
compress-icons /path/to/output
|
|
37
|
+
Options:
|
|
38
|
+
--help print this help message
|
|
39
|
+
`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
run(args._[0]).catch((e) => {
|
|
43
|
+
// tslint:disable-next-line:no-console
|
|
44
|
+
console.error(e);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=compress-icons.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const minimist = require("minimist");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const IconsGenerator_1 = require("../lib/icon/IconsGenerator");
|
|
17
|
+
// Process CLI args
|
|
18
|
+
const args = minimist(process.argv.slice(2));
|
|
19
|
+
if (args.help || args._.length < 1) {
|
|
20
|
+
printUsage();
|
|
21
|
+
}
|
|
22
|
+
function run(configPath) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
25
|
+
if (!config.minecraft) {
|
|
26
|
+
process.stderr.write('Missing "minecraft" field in config\n');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
if (!config.neoforge && !config.forge) {
|
|
30
|
+
process.stderr.write('Missing "neoforge" or "forge" field in config\n');
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
const generator = new IconsGenerator_1.IconsGenerator({
|
|
34
|
+
modsDir: (0, path_1.join)(process.cwd(), args['mods-dir'] || (0, path_1.join)('server', 'mods')),
|
|
35
|
+
iconsDir: (0, path_1.join)(process.cwd(), args['icons-dir'] || 'icon'),
|
|
36
|
+
workDir: (0, path_1.join)(process.cwd(), args['work-dir'] || 'headlessmc'),
|
|
37
|
+
minecraftVersion: config.minecraft,
|
|
38
|
+
neoforgeVersion: config.neoforge || config.forge,
|
|
39
|
+
githubToken: args['github-token'] || process.env.GITHUB_TOKEN,
|
|
40
|
+
iconExporterVersion: args['icon-exporter-version'],
|
|
41
|
+
headlessMcVersion: args['headlessmc-version'],
|
|
42
|
+
launchTimeoutMs: args.timeout ? parseInt(args.timeout, 10) * 1000 : undefined,
|
|
43
|
+
});
|
|
44
|
+
yield generator.generate();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function printUsage() {
|
|
48
|
+
process.stdout.write(`generate-icons Download IconExporter and HeadlessMC, launches Minecraft headlessly, and exports item icons
|
|
49
|
+
Usage:
|
|
50
|
+
generate-icons /path/to/modpack.json
|
|
51
|
+
Options:
|
|
52
|
+
--help print this help message
|
|
53
|
+
--mods-dir directory containing mod JARs (default: server/mods)
|
|
54
|
+
--icons-dir output directory for icons (default: icons)
|
|
55
|
+
--work-dir working directory for HeadlessMC (default: headlessmc)
|
|
56
|
+
--github-token GitHub token for downloading from GitHub Packages
|
|
57
|
+
--icon-exporter-version version of the IconExporter artifact (default: 1.4.0-174)
|
|
58
|
+
--headlessmc-version version of HeadlessMC to use (default: 2.8.0)
|
|
59
|
+
--timeout timeout in seconds for the full icon generation (default: 1800)
|
|
60
|
+
`);
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
run(args._[0]).catch((e) => {
|
|
64
|
+
// tslint:disable-next-line:no-console
|
|
65
|
+
console.error(e);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
|
68
|
+
//# sourceMappingURL=generate-icons.js.map
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
3
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
13
|
const fs = require("fs");
|
|
6
14
|
const minimist = require("minimist");
|
|
7
15
|
const path_1 = require("path");
|
|
@@ -26,7 +34,7 @@ Options:
|
|
|
26
34
|
process.exit(1);
|
|
27
35
|
}
|
|
28
36
|
function create() {
|
|
29
|
-
return
|
|
37
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
38
|
// Create infobook from config
|
|
31
39
|
const config = JSON.parse(fs.readFileSync(args._[0], "utf8"));
|
|
32
40
|
// Override baseUrl
|
|
@@ -43,18 +51,18 @@ function create() {
|
|
|
43
51
|
process.stderr.write('Could not find a "mod_assets" folder, make sure to create one with generate-mod-metadata.\n');
|
|
44
52
|
process.exit(1);
|
|
45
53
|
}
|
|
46
|
-
// Check if
|
|
47
|
-
if (!fs.existsSync('
|
|
48
|
-
process.stderr.write('Could not find a "
|
|
54
|
+
// Check if icon are available
|
|
55
|
+
if (!fs.existsSync('icon')) {
|
|
56
|
+
process.stderr.write('Could not find a "icon" folder, make sure to create one with output from the IconExporter mod.\n');
|
|
49
57
|
process.exit(1);
|
|
50
58
|
}
|
|
51
59
|
// Read resources
|
|
52
60
|
const resourceLoader = new ResourceLoader_1.ResourceLoader();
|
|
53
|
-
yield resourceLoader.loadIcons('
|
|
61
|
+
yield resourceLoader.loadIcons('icon');
|
|
54
62
|
yield resourceLoader.loadItemTranslationKeys('registries');
|
|
55
63
|
yield resourceLoader.loadFluidTranslationKeys('registries');
|
|
56
64
|
yield resourceLoader.loadKeybindings(config.keybindings);
|
|
57
|
-
yield resourceLoader.loadAll(process.cwd(), 'mod_assets');
|
|
65
|
+
yield resourceLoader.loadAll(process.cwd(), 'mod_assets', config.excludedModLanguages || []);
|
|
58
66
|
// Setup infobook loader
|
|
59
67
|
const infoBookInitializer = new InfoBookInitializer_1.InfoBookInitializer(config);
|
|
60
68
|
infoBookInitializer.registerAppendixHandler('advancement_rewards', new InfoBookAppendixHandlerAdvancementRewards_1.InfoBookAppendixHandlerAdvancementRewards(resourceLoader.getResourceHandler()));
|
|
@@ -68,7 +76,7 @@ function create() {
|
|
|
68
76
|
const headSuffixGetters = [];
|
|
69
77
|
if (config.plugins) {
|
|
70
78
|
for (const pluginPath of config.plugins) {
|
|
71
|
-
const plugin = require(path_1.join(process.cwd(), pluginPath));
|
|
79
|
+
const plugin = require((0, path_1.join)(process.cwd(), pluginPath));
|
|
72
80
|
plugin.load(infoBookInitializer, resourceLoader, config);
|
|
73
81
|
if (plugin.assetsPath) {
|
|
74
82
|
assetsPaths.push(plugin.assetsPath);
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
3
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
13
|
const fs = require("fs");
|
|
6
14
|
const minimist = require("minimist");
|
|
7
15
|
const path_1 = require("path");
|
|
@@ -12,12 +20,12 @@ if (args.help || args._.length !== 2) {
|
|
|
12
20
|
printUsage();
|
|
13
21
|
}
|
|
14
22
|
function run(command, configPath) {
|
|
15
|
-
return
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
16
24
|
// Create mod loader
|
|
17
25
|
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
18
26
|
const modLoader = new ModLoader_1.ModLoader({
|
|
19
27
|
mods: config.mods,
|
|
20
|
-
path: path_1.join(process.cwd(), 'server'),
|
|
28
|
+
path: (0, path_1.join)(process.cwd(), 'server'),
|
|
21
29
|
loader: 'forge' in config ? { versionForge: config.forge } : { versionNeoForge: config.neoforge },
|
|
22
30
|
versionMinecraft: config.minecraft,
|
|
23
31
|
});
|
|
@@ -30,11 +38,11 @@ function run(command, configPath) {
|
|
|
30
38
|
break;
|
|
31
39
|
case 'extractmc':
|
|
32
40
|
yield modLoader.extractMinecraftAssets();
|
|
33
|
-
yield modLoader.copyModAssets(path_1.join(process.cwd(), 'mod_assets'));
|
|
41
|
+
yield modLoader.copyModAssets((0, path_1.join)(process.cwd(), 'mod_assets'));
|
|
34
42
|
break;
|
|
35
43
|
case 'extractmods':
|
|
36
44
|
yield modLoader.extractModsAssets();
|
|
37
|
-
yield modLoader.copyModAssets(path_1.join(process.cwd(), 'mod_assets'));
|
|
45
|
+
yield modLoader.copyModAssets((0, path_1.join)(process.cwd(), 'mod_assets'));
|
|
38
46
|
break;
|
|
39
47
|
case 'generate':
|
|
40
48
|
if (!modLoader.isForgeInstalled()) {
|
|
@@ -63,10 +71,10 @@ function run(command, configPath) {
|
|
|
63
71
|
if (lastError) {
|
|
64
72
|
throw lastError;
|
|
65
73
|
}
|
|
66
|
-
yield modLoader.copyRegistries(path_1.join(process.cwd(), 'registries'));
|
|
74
|
+
yield modLoader.copyRegistries((0, path_1.join)(process.cwd(), 'registries'));
|
|
67
75
|
yield modLoader.extractMinecraftAssets();
|
|
68
76
|
yield modLoader.extractModsAssets();
|
|
69
|
-
yield modLoader.copyModAssets(path_1.join(process.cwd(), 'mod_assets'));
|
|
77
|
+
yield modLoader.copyModAssets((0, path_1.join)(process.cwd(), 'mod_assets'));
|
|
70
78
|
break;
|
|
71
79
|
default:
|
|
72
80
|
printUsage();
|
package/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export * from "./lib/icon/IconsCompressor";
|
|
2
|
+
export * from "./lib/icon/IconsGenerator";
|
|
1
3
|
export * from "./lib/infobook/appendix/IInfoBookAppendixHandler";
|
|
2
4
|
export * from "./lib/infobook/appendix/InfoBookAppendixAd";
|
|
3
5
|
export * from "./lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe";
|
package/index.js
CHANGED
|
@@ -1,27 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
2
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
__exportStar(require("./lib/icon/IconsCompressor"), exports);
|
|
18
|
+
__exportStar(require("./lib/icon/IconsGenerator"), exports);
|
|
19
|
+
__exportStar(require("./lib/infobook/appendix/IInfoBookAppendixHandler"), exports);
|
|
20
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixAd"), exports);
|
|
21
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerAbstractRecipe"), exports);
|
|
22
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerAdvancementRewards"), exports);
|
|
23
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerCraftingRecipe"), exports);
|
|
24
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerSmeltingRecipe"), exports);
|
|
25
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerImage"), exports);
|
|
26
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixHandlerKeybinding"), exports);
|
|
27
|
+
__exportStar(require("./lib/infobook/appendix/InfoBookAppendixTagIndex"), exports);
|
|
28
|
+
__exportStar(require("./lib/infobook/FileWriter"), exports);
|
|
29
|
+
__exportStar(require("./lib/infobook/IFileWriter"), exports);
|
|
30
|
+
__exportStar(require("./lib/infobook/IFluid"), exports);
|
|
31
|
+
__exportStar(require("./lib/infobook/IInfoAppendix"), exports);
|
|
32
|
+
__exportStar(require("./lib/infobook/IInfoBook"), exports);
|
|
33
|
+
__exportStar(require("./lib/infobook/IInfobookPlugin"), exports);
|
|
34
|
+
__exportStar(require("./lib/infobook/IInfoSection"), exports);
|
|
35
|
+
__exportStar(require("./lib/infobook/IItem"), exports);
|
|
36
|
+
__exportStar(require("./lib/infobook/InfoBookInitializer"), exports);
|
|
37
|
+
__exportStar(require("./lib/modloader/ModLoader"), exports);
|
|
38
|
+
__exportStar(require("./lib/parse/XmlInfoBookParser"), exports);
|
|
39
|
+
__exportStar(require("./lib/resource/ResourceHandler"), exports);
|
|
40
|
+
__exportStar(require("./lib/resource/ResourceLoader"), exports);
|
|
41
|
+
__exportStar(require("./lib/serialize/HtmlInfoBookSerializer"), exports);
|
|
27
42
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Losslessly compresses PNG icon files using OptiPNG.
|
|
3
|
+
* Mimics how ImgBot compresses images: lossless PNG compression at optimization level 7
|
|
4
|
+
* with metadata stripping.
|
|
5
|
+
*/
|
|
6
|
+
export declare class IconsCompressor {
|
|
7
|
+
private readonly iconsDir;
|
|
8
|
+
constructor(iconsDir: string);
|
|
9
|
+
/**
|
|
10
|
+
* Compress all PNG files in the icon directory using OptiPNG.
|
|
11
|
+
*/
|
|
12
|
+
compress(): Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Get the path to the optipng binary from optipng-bin package.
|
|
15
|
+
* Uses require.resolve to find the package root, then constructs the vendor binary path.
|
|
16
|
+
*/
|
|
17
|
+
getOptipngPath(): string;
|
|
18
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.IconsCompressor = void 0;
|
|
13
|
+
const child_process_1 = require("child_process");
|
|
14
|
+
const fs = require("fs");
|
|
15
|
+
const path_1 = require("path");
|
|
16
|
+
const util_1 = require("util");
|
|
17
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
18
|
+
/**
|
|
19
|
+
* Losslessly compresses PNG icon files using OptiPNG.
|
|
20
|
+
* Mimics how ImgBot compresses images: lossless PNG compression at optimization level 7
|
|
21
|
+
* with metadata stripping.
|
|
22
|
+
*/
|
|
23
|
+
class IconsCompressor {
|
|
24
|
+
constructor(iconsDir) {
|
|
25
|
+
if (!iconsDir) {
|
|
26
|
+
throw new Error('Missing iconsDir argument');
|
|
27
|
+
}
|
|
28
|
+
this.iconsDir = iconsDir;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compress all PNG files in the icon directory using OptiPNG.
|
|
32
|
+
*/
|
|
33
|
+
compress() {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
const optipngPath = this.getOptipngPath();
|
|
36
|
+
if (!fs.existsSync(optipngPath)) {
|
|
37
|
+
throw new Error(`OptiPNG binary not found at: ${optipngPath}. Ensure optipng-bin is installed.`);
|
|
38
|
+
}
|
|
39
|
+
const files = yield fs.promises.readdir(this.iconsDir);
|
|
40
|
+
const pngFiles = files.filter((f) => f.endsWith('.png'));
|
|
41
|
+
if (pngFiles.length === 0) {
|
|
42
|
+
process.stdout.write(`No PNG files found in ${this.iconsDir}\n`);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
process.stdout.write(`Compressing ${pngFiles.length} icons in ${this.iconsDir}...\n`);
|
|
46
|
+
let compressed = 0;
|
|
47
|
+
let errors = 0;
|
|
48
|
+
let totalSavedBytes = 0;
|
|
49
|
+
for (const file of pngFiles) {
|
|
50
|
+
const filePath = (0, path_1.join)(this.iconsDir, file);
|
|
51
|
+
const sizeBefore = fs.statSync(filePath).size;
|
|
52
|
+
try {
|
|
53
|
+
yield execFileAsync(optipngPath, ['-o7', '-strip', 'all', '-quiet', filePath]);
|
|
54
|
+
const sizeAfter = fs.statSync(filePath).size;
|
|
55
|
+
totalSavedBytes += sizeBefore - sizeAfter;
|
|
56
|
+
compressed++;
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
process.stderr.write(`Warning: failed to compress ${file}: ${err}\n`);
|
|
60
|
+
errors++;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const savedKb = (totalSavedBytes / 1024).toFixed(1);
|
|
64
|
+
process.stdout.write(`Compressed ${compressed} icons (saved ${savedKb} KB)` +
|
|
65
|
+
(errors > 0 ? `, ${errors} errors` : '') +
|
|
66
|
+
`\n`);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get the path to the optipng binary from optipng-bin package.
|
|
71
|
+
* Uses require.resolve to find the package root, then constructs the vendor binary path.
|
|
72
|
+
*/
|
|
73
|
+
getOptipngPath() {
|
|
74
|
+
const indexPath = require.resolve('optipng-bin');
|
|
75
|
+
const pkgRoot = (0, path_1.dirname)(indexPath);
|
|
76
|
+
const binaryName = process.platform === 'win32' ? 'optipng.exe' : 'optipng';
|
|
77
|
+
return (0, path_1.join)(pkgRoot, 'vendor', binaryName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.IconsCompressor = IconsCompressor;
|
|
81
|
+
//# sourceMappingURL=IconsCompressor.js.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates icons using the IconExporter mod and HeadlessMC.
|
|
3
|
+
* This class downloads HeadlessMC and the IconExporter mod, sets up a headless
|
|
4
|
+
* Minecraft client with NeoForge and all specified mods, launches the game,
|
|
5
|
+
* runs the iconexporter export command, and copies the resulting icons.
|
|
6
|
+
*/
|
|
7
|
+
export declare class IconsGenerator {
|
|
8
|
+
private static readonly HEADLESSMC_JAR;
|
|
9
|
+
private static readonly ICONEXPORTER_JAR;
|
|
10
|
+
private static readonly HMC_GAME_SUBDIR;
|
|
11
|
+
private static readonly HMC_CONFIG_SUBDIR;
|
|
12
|
+
private static readonly ICON_EXPORT_SUBDIR;
|
|
13
|
+
private static readonly DEFAULT_ICON_SIZE;
|
|
14
|
+
private static readonly HMC_SPECIFICS_REPO;
|
|
15
|
+
private readonly modsDir;
|
|
16
|
+
private readonly iconsDir;
|
|
17
|
+
private readonly workDir;
|
|
18
|
+
private readonly minecraftVersion;
|
|
19
|
+
private readonly neoforgeVersion;
|
|
20
|
+
private readonly githubToken;
|
|
21
|
+
private readonly iconExporterArtifact;
|
|
22
|
+
private readonly iconExporterVersion;
|
|
23
|
+
private readonly headlessMcVersion;
|
|
24
|
+
private readonly launchTimeoutMs;
|
|
25
|
+
constructor(args: IIconsGeneratorArgs);
|
|
26
|
+
/**
|
|
27
|
+
* Run the full icon generation pipeline.
|
|
28
|
+
*/
|
|
29
|
+
generate(): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Download the HeadlessMC launcher jar.
|
|
32
|
+
*/
|
|
33
|
+
downloadHeadlessMc(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Download the IconExporter mod from GitHub Maven packages.
|
|
36
|
+
*/
|
|
37
|
+
downloadIconExporter(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Set up the game directory with mods and options.
|
|
40
|
+
*/
|
|
41
|
+
setupGameDirectory(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Write the HeadlessMC configuration file.
|
|
44
|
+
*/
|
|
45
|
+
writeHmcConfig(): void;
|
|
46
|
+
/**
|
|
47
|
+
* Run the Minecraft client using HeadlessMC and export icons.
|
|
48
|
+
*/
|
|
49
|
+
runGameAndExportIcons(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Copy exported icons to the output icons directory.
|
|
52
|
+
*/
|
|
53
|
+
copyIcons(): Promise<void>;
|
|
54
|
+
/**
|
|
55
|
+
* Parse the HeadlessMC `gui` command output and find the numeric button ID for a given
|
|
56
|
+
* button text label. HeadlessMC's `click` command requires a numeric id, not the text.
|
|
57
|
+
* The gui table format is:
|
|
58
|
+
* id text x y w h on type
|
|
59
|
+
* 0 Multiplayer 140 123 200 20 1 Button
|
|
60
|
+
* 1 Singleplayer 140 99 200 20 1 Button
|
|
61
|
+
* Columns are separated by two or more spaces.
|
|
62
|
+
*/
|
|
63
|
+
findButtonIdByText(guiOutput: string, buttonText: string): number | null;
|
|
64
|
+
/**
|
|
65
|
+
* Determine if the Minecraft game has fully loaded based on log output.
|
|
66
|
+
*/
|
|
67
|
+
isGameFullyLoaded(output: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Determine if the HeadlessMC launcher is ready to accept commands based on its startup output.
|
|
70
|
+
* In non-TTY mode HeadlessMC does not print a '>' prompt, so we detect readiness from the
|
|
71
|
+
* version-table header or the DefaultCommandLineProvider warning it prints on startup.
|
|
72
|
+
*/
|
|
73
|
+
isHeadlessMcReady(output: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Download the hmc-specifics mod from GitHub Releases into the given mods directory.
|
|
76
|
+
* This avoids relying on HeadlessMC's built-in `-specifics` auto-download which checks
|
|
77
|
+
* the GitHub API without authentication and can hit rate limits.
|
|
78
|
+
*/
|
|
79
|
+
downloadHmcSpecifics(modsDir: string): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Download a file from a URL to a destination path.
|
|
82
|
+
*/
|
|
83
|
+
downloadFile(url: string, destPath: string, headers?: Record<string, string>): Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
export type IGameState = 'waiting_for_prompt' | 'game_launching' | 'checking_screen' | 'navigating_singleplayer' | 'creating_world' | 'exporting_icons' | 'quitting';
|
|
86
|
+
export interface IIconsGeneratorArgs {
|
|
87
|
+
/**
|
|
88
|
+
* Directory containing mod JARs to include in the client (usually server/mods).
|
|
89
|
+
*/
|
|
90
|
+
modsDir: string;
|
|
91
|
+
/**
|
|
92
|
+
* Directory where icons will be written.
|
|
93
|
+
*/
|
|
94
|
+
iconsDir: string;
|
|
95
|
+
/**
|
|
96
|
+
* Working directory for HeadlessMC and game files.
|
|
97
|
+
*/
|
|
98
|
+
workDir: string;
|
|
99
|
+
/**
|
|
100
|
+
* Minecraft version (e.g., "1.21.1").
|
|
101
|
+
*/
|
|
102
|
+
minecraftVersion: string;
|
|
103
|
+
/**
|
|
104
|
+
* NeoForge version (e.g., "21.1.210").
|
|
105
|
+
*/
|
|
106
|
+
neoforgeVersion: string;
|
|
107
|
+
/**
|
|
108
|
+
* GitHub token for downloading from GitHub Packages.
|
|
109
|
+
* Falls back to GITHUB_TOKEN environment variable.
|
|
110
|
+
*/
|
|
111
|
+
githubToken?: string;
|
|
112
|
+
/**
|
|
113
|
+
* Maven artifact ID for IconExporter (default: iconexporter-{minecraftVersion}-neoforge).
|
|
114
|
+
*/
|
|
115
|
+
iconExporterArtifact?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Version of the IconExporter artifact to download (e.g., "1.4.0-174").
|
|
118
|
+
*/
|
|
119
|
+
iconExporterVersion?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Version of HeadlessMC to download (e.g., "2.8.0").
|
|
122
|
+
*/
|
|
123
|
+
headlessMcVersion?: string;
|
|
124
|
+
/**
|
|
125
|
+
* Timeout in milliseconds for the full game launch and icon export (default: 30 minutes).
|
|
126
|
+
*/
|
|
127
|
+
launchTimeoutMs?: number;
|
|
128
|
+
}
|