Files
2026-10-12 01:39:58 -07:00

65 lines
3.0 KiB
JavaScript

// Builds the on-console payload.
//
// node scripts/build-payload.mjs host for this computer (testing against the mock)
// node scripts/build-payload.mjs ps5 payload/cheatspecter.elf (needs PS5_PAYLOAD_SDK)
//
// With CS_PAYLOAD_OUT set to a folder, the PS5 build is written there instead
// and the ELFs in payload/ are left as they are: a way to check that the
// payload still compiles and links for the console without replacing the
// build that ships.
//
// Both embed the built web app from dist/, so run `npm run build` first; the
// npm scripts `payload:host` and `payload` do that for you.
import fs from 'node:fs';
import path from 'node:path';
import { execFileSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const target = process.argv[2] ?? 'ps5';
const payload = path.join(root, 'payload');
const assets = path.join(payload, 'build/assets.c');
const sources = [...['main.c', 'engine.c', 'dbgclient.c', 'json.c', 'pad.c'].map((f) => path.join(payload, 'src', f)), assets];
const flags = ['-O2', '-Wall', '-Wextra', `-I${path.join(payload, 'src')}`];
const run = (cmd, args) => execFileSync(cmd, args, { stdio: 'inherit' });
if (!fs.existsSync(path.join(root, 'dist/index.html'))) {
console.error('The web app is not built yet. Run: npm run build');
process.exit(1);
}
run(process.execPath, [path.join(root, 'scripts/embed-assets.mjs'), path.join(root, 'dist'), assets]);
if (target === 'host') {
const out = path.join(payload, 'build/cheatspecter-host');
run(process.env.CC ?? 'cc', [...flags, '-o', out, ...sources, '-lpthread']);
console.log(`Built ${path.relative(root, out)}`);
} else if (target === 'ps5') {
const sdk = process.env.PS5_PAYLOAD_SDK;
if (!sdk) {
console.error('Set PS5_PAYLOAD_SDK to your ps5-payload-sdk install, e.g. /opt/ps5-payload-sdk');
process.exit(1);
}
const elsewhere = process.env.CS_PAYLOAD_OUT;
if (elsewhere) fs.mkdirSync(elsewhere, { recursive: true });
const out = path.join(elsewhere || payload, 'cheatspecter.elf');
run(path.join(sdk, 'bin/prospero-clang'), [...flags, '-o', out, ...sources, '-lkernel_sys', '-lSceSystemService', '-lSceUserService']);
if (elsewhere) {
console.log(`Built ${out} (a check build; payload/ was not touched)`);
} else {
// Payload managers read the version from the file name ("name-v1.2.3.elf"),
// so the build is also written under one. Older versioned copies are removed.
const { version } = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
const versioned = path.join(payload, `cheatspecter-v${version}.elf`);
for (const f of fs.readdirSync(payload)) {
if (/^cheatspecter-v[\d.]+\.elf$/.test(f)) fs.rmSync(path.join(payload, f));
}
fs.copyFileSync(out, versioned);
console.log(`Built ${path.relative(root, out)} and ${path.relative(root, versioned)}`);
}
} else {
console.error('Usage: build-payload.mjs host|ps5');
process.exit(1);
}