Add .mrpack exporter (tools/export-mrpack.mjs) and install docs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5b807d0600
commit
36760f1716
@@ -0,0 +1,72 @@
|
||||
// Exports this packwiz pack as a Modrinth modpack (.mrpack) for Modrinth App / Prism "Import".
|
||||
// node tools/export-mrpack.mjs → dist/CreateRP-<version>.mrpack
|
||||
// Mods are referenced by their Modrinth CDN URL (sha1/sha512/size from the Modrinth API);
|
||||
// config/ goes into overrides/. Zipping uses Windows' bsdtar (tar -a) or `zip` on Linux.
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { execFileSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const UA = { 'User-Agent': 'Pinecraft-CreateRP/mrpack-export' };
|
||||
const field = (toml, key) => (toml.match(new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, 'm')) || [])[1];
|
||||
|
||||
const pack = fs.readFileSync(path.join(root, 'pack.toml'), 'utf8');
|
||||
const packName = field(pack, 'name');
|
||||
const packVersion = field(pack, 'version');
|
||||
const mc = field(pack, 'minecraft');
|
||||
const neoforge = field(pack, 'neoforge');
|
||||
|
||||
const metas = fs.readdirSync(path.join(root, 'mods')).filter(f => f.endsWith('.pw.toml')).map(f => {
|
||||
const t = fs.readFileSync(path.join(root, 'mods', f), 'utf8');
|
||||
return { file: f, filename: field(t, 'filename'), side: field(t, 'side') || 'both', url: field(t, 'url'), versionId: field(t, 'version') };
|
||||
});
|
||||
|
||||
// sha1/sha512/size per version from Modrinth (batched)
|
||||
const versionInfo = {};
|
||||
const ids = metas.map(m => m.versionId).filter(Boolean);
|
||||
for (let i = 0; i < ids.length; i += 100) {
|
||||
const chunk = ids.slice(i, i + 100);
|
||||
const res = await fetch('https://api.modrinth.com/v2/versions?ids=' + encodeURIComponent(JSON.stringify(chunk)), { headers: UA });
|
||||
for (const v of await res.json()) versionInfo[v.id] = v;
|
||||
}
|
||||
|
||||
const files = metas.map(m => {
|
||||
const v = versionInfo[m.versionId];
|
||||
const f = v?.files.find(x => x.url === m.url) || v?.files.find(x => x.filename === m.filename);
|
||||
if (!f) throw new Error(`no Modrinth file for ${m.file}`);
|
||||
return {
|
||||
path: `mods/${f.filename}`,
|
||||
hashes: { sha1: f.hashes.sha1, sha512: f.hashes.sha512 },
|
||||
env: { client: m.side === 'server' ? 'unsupported' : 'required', server: m.side === 'client' ? 'unsupported' : 'required' },
|
||||
downloads: [f.url],
|
||||
fileSize: f.size
|
||||
};
|
||||
}).sort((a, b) => a.path.localeCompare(b.path));
|
||||
|
||||
const index = {
|
||||
formatVersion: 1,
|
||||
game: 'minecraft',
|
||||
versionId: packVersion,
|
||||
name: packName,
|
||||
summary: 'Клієнтська збірка сервера Create RP',
|
||||
files,
|
||||
dependencies: { minecraft: mc, neoforge }
|
||||
};
|
||||
|
||||
// staging dir → zip
|
||||
const stage = path.join(root, 'dist', '.stage');
|
||||
fs.rmSync(stage, { recursive: true, force: true });
|
||||
fs.mkdirSync(path.join(stage, 'overrides'), { recursive: true });
|
||||
fs.writeFileSync(path.join(stage, 'modrinth.index.json'), JSON.stringify(index, null, 2));
|
||||
fs.cpSync(path.join(root, 'config'), path.join(stage, 'overrides', 'config'), { recursive: true });
|
||||
|
||||
const out = path.join(root, 'dist', `CreateRP-${packVersion}.mrpack`);
|
||||
fs.rmSync(out, { force: true });
|
||||
if (process.platform === 'win32') {
|
||||
execFileSync('C:\\Windows\\System32\\tar.exe', ['--format', 'zip', '-c', '-f', out, '-C', stage, 'modrinth.index.json', 'overrides']);
|
||||
} else {
|
||||
execFileSync('zip', ['-qr', out, 'modrinth.index.json', 'overrides'], { cwd: stage });
|
||||
}
|
||||
fs.rmSync(stage, { recursive: true, force: true });
|
||||
console.log(`${out}: ${files.length} mods, ${(fs.statSync(out).size / 1024).toFixed(0)} KiB`);
|
||||
Reference in New Issue
Block a user