Files
MineGeo/scripts/proof.mjs

114 lines
4.1 KiB
JavaScript

import { readFile, writeFile, mkdir, copyFile } from "node:fs/promises";
import { existsSync } from "node:fs";
import { createHash } from "node:crypto";
import { spawn } from "node:child_process";
import { gunzipSync } from "node:zlib";
import { renderSnapshot } from "../renderer/render.mjs";
import { prepareAssets } from "./assets.mjs";
const directory = ".cache/paper-proof";
await mkdir(`${directory}/plugins`, { recursive: true });
const jar = `${directory}/paper.jar`;
if (!existsSync(jar)) {
const builds = await (
await fetch(
"https://fill.papermc.io/v3/projects/paper/versions/1.21.11/builds",
{ headers: { "User-Agent": "MineGeo/0.1 local development" } },
)
).json();
const build = builds.find((b) => b.channel === "STABLE");
const download = build.downloads["server:default"];
const bytes = Buffer.from(await (await fetch(download.url)).arrayBuffer());
if (
createHash("sha256").update(bytes).digest("hex") !==
download.checksums.sha256
)
throw new Error("Paper checksum mismatch");
await writeFile(jar, bytes);
}
await copyFile(
"minecraft/plugin/build/libs/minegeo-plugin-1.21.11.jar",
`${directory}/plugins/minegeo.jar`,
);
// This disposable loopback-only server exists solely for the requested integration test.
await writeFile(`${directory}/eula.txt`, "eula=true\n");
await writeFile(
`${directory}/server.properties`,
"server-ip=127.0.0.1\nserver-port=25579\nonline-mode=true\nlevel-seed=928341\nview-distance=5\nsimulation-distance=2\nspawn-protection=0\nenable-rcon=false\nmax-players=1\n",
);
if (!existsSync(`${directory}/plugins/MineGeo/export/terrain.json.gz`)) {
await new Promise((resolve, reject) => {
const child = spawn("java", ["-Xmx2G", "-jar", "paper.jar", "--nogui"], {
cwd: directory,
stdio: ["pipe", "pipe", "pipe"],
});
let ready = false,
exported = false,
buffer = "";
const timer = setTimeout(() => {
child.stdin.write("stop\n");
reject(new Error("Paper proof timed out"));
}, 240000);
process.once("SIGINT", () => child.stdin.write("stop\n"));
const output = (data) => {
const text = data.toString();
process.stdout.write(text);
buffer = (buffer + text).slice(-20000);
if (!ready && buffer.includes("Done (")) {
ready = true;
// The fixture explicitly generates its test area before export. The production
// plugin never generates chunks. No player connects during this test.
child.stdin.write("forceload add -48 -48 47 47\n");
setTimeout(
() =>
child.stdin.write(
"fill -47 99 -47 47 99 47 minecraft:grass_block\nfill -6 100 -6 6 103 6 minecraft:stone_bricks\nfill -5 104 -5 5 105 5 minecraft:oak_planks\nfill 16 100 16 24 100 24 minecraft:water\nminegeo area world -48 -48 48 48\nminegeo export Paper Proof\n",
),
12000,
);
}
if (!exported && buffer.includes("Export complete:")) {
exported = true;
child.stdin.write("stop\n");
}
if (!exported && text.includes("Export failed:"))
child.stdin.write("stop\n");
};
child.stdout.on("data", output);
child.stderr.on("data", output);
child.on("exit", (code) => {
clearTimeout(timer);
exported
? resolve()
: reject(new Error(`Paper exited ${code} without an export`));
});
});
}
const source = `${directory}/plugins/MineGeo/export`;
const manifest = JSON.parse(await readFile(`${source}/manifest.json`, "utf8"));
const terrain = JSON.parse(
gunzipSync(await readFile(`${source}/terrain.json.gz`)).toString(),
);
await prepareAssets();
const report = await renderSnapshot(
terrain,
manifest.viewpoints,
"public/generated/paper-proof",
{ size: 1024 },
);
await mkdir(".data/fixtures", { recursive: true });
await copyFile(`${source}/manifest.json`, ".data/fixtures/paper-proof.json");
await writeFile(
"artifacts-renderer-proof.json",
JSON.stringify(
{
...report,
source: "real Paper 1.21.11 terrain snapshot",
bounds: manifest.bounds,
viewpoints: manifest.viewpoints.length,
},
null,
2,
),
);
console.log("RENDERER PROOF:", JSON.stringify(report));