Release Healer Man 0.1.7
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env node
|
||||
import { access, mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { analyzeGlbFile } from "./glb-performance.mjs";
|
||||
|
||||
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
|
||||
const baselineFile = path.join(
|
||||
projectRoot,
|
||||
"scripts/asset-pipeline/environment-performance-baseline.json",
|
||||
);
|
||||
const defaultRoots = [
|
||||
path.join(projectRoot, "public/assets/game/manastorm"),
|
||||
path.join(projectRoot, "src/assets/game/dungeons"),
|
||||
];
|
||||
const defaultThresholds = {
|
||||
maxEstimatedDrawCalls: 1_500,
|
||||
maxUnbatchedDrawCallSavings: 250,
|
||||
};
|
||||
|
||||
async function exists(file) {
|
||||
try {
|
||||
await access(file);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function collectVisualGlbs(root, files = []) {
|
||||
if (!await exists(root)) return files;
|
||||
const entry = await stat(root);
|
||||
if (entry.isFile()) {
|
||||
if (/(?:^|[-_])visual\.glb$/i.test(path.basename(root))) files.push(root);
|
||||
return files;
|
||||
}
|
||||
for (const child of await readdir(root, { withFileTypes: true })) {
|
||||
const target = path.join(root, child.name);
|
||||
if (child.isDirectory()) await collectVisualGlbs(target, files);
|
||||
else if (/(?:^|[-_])visual\.glb$/i.test(child.name)) files.push(target);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
function projectPath(file) {
|
||||
return path.relative(projectRoot, file).split(path.sep).join("/");
|
||||
}
|
||||
|
||||
function exceeds(report, limits) {
|
||||
return report.estimatedDrawCalls > limits.maxEstimatedDrawCalls
|
||||
|| report.unbatchedDrawCallSavings > limits.maxUnbatchedDrawCallSavings;
|
||||
}
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const writeBaseline = args.includes("--write-baseline");
|
||||
const roots = args.filter((argument) => argument !== "--write-baseline")
|
||||
.map((argument) => path.resolve(projectRoot, argument));
|
||||
const files = [...new Set((await Promise.all(
|
||||
(roots.length ? roots : defaultRoots).map((root) => collectVisualGlbs(root)),
|
||||
)).flat())].sort();
|
||||
const reports = await Promise.all(files.map(async (file) => ({
|
||||
file: projectPath(file),
|
||||
byteLength: (await stat(file)).size,
|
||||
...(await analyzeGlbFile(file)),
|
||||
})));
|
||||
|
||||
if (writeBaseline) {
|
||||
const baseline = {
|
||||
schemaVersion: 1,
|
||||
thresholds: defaultThresholds,
|
||||
exceptions: Object.fromEntries(
|
||||
reports
|
||||
.filter((report) => exceeds(report, defaultThresholds))
|
||||
.map((report) => [report.file, {
|
||||
maxEstimatedDrawCalls: Math.max(defaultThresholds.maxEstimatedDrawCalls, report.estimatedDrawCalls),
|
||||
maxUnbatchedDrawCallSavings: Math.max(
|
||||
defaultThresholds.maxUnbatchedDrawCallSavings,
|
||||
report.unbatchedDrawCallSavings,
|
||||
),
|
||||
}]),
|
||||
),
|
||||
};
|
||||
await mkdir(path.dirname(baselineFile), { recursive: true });
|
||||
await writeFile(baselineFile, `${JSON.stringify(baseline, null, 2)}\n`, "utf8");
|
||||
console.log(`Wrote ${Object.keys(baseline.exceptions).length} performance exceptions to ${projectPath(baselineFile)}.`);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (!await exists(baselineFile)) {
|
||||
throw new Error(`Missing ${projectPath(baselineFile)}. Run this script with --write-baseline.`);
|
||||
}
|
||||
const baseline = JSON.parse(await readFile(baselineFile, "utf8"));
|
||||
const thresholds = { ...defaultThresholds, ...baseline.thresholds };
|
||||
const regressions = reports.filter((report) => {
|
||||
const limits = { ...thresholds, ...baseline.exceptions?.[report.file] };
|
||||
return exceeds(report, limits);
|
||||
});
|
||||
const debt = reports.filter((report) => exceeds(report, thresholds));
|
||||
const top = [...reports]
|
||||
.sort((left, right) => right.estimatedDrawCalls - left.estimatedDrawCalls)
|
||||
.slice(0, 12)
|
||||
.map((report) => ({
|
||||
asset: report.file,
|
||||
calls: report.estimatedDrawCalls,
|
||||
avoidable: report.unbatchedDrawCallSavings,
|
||||
gpuBatches: report.gpuInstanceBatches,
|
||||
nodes: report.nodes,
|
||||
}));
|
||||
|
||||
console.table(top);
|
||||
console.log(JSON.stringify({
|
||||
status: regressions.length ? "blocked" : "green",
|
||||
assets: reports.length,
|
||||
knownBudgetExceptions: debt.length,
|
||||
regressions: regressions.map((report) => ({
|
||||
file: report.file,
|
||||
estimatedDrawCalls: report.estimatedDrawCalls,
|
||||
unbatchedDrawCallSavings: report.unbatchedDrawCallSavings,
|
||||
})),
|
||||
}, null, 2));
|
||||
if (regressions.length) process.exitCode = 1;
|
||||
Reference in New Issue
Block a user