orbit/dev/exit-gate-shot.mjs

131 lines
4.9 KiB
JavaScript

/**
* Dev-only: boot GameScene, set a DESTINATION (a far star), and open the
* MAP console's CURRENT SYSTEM tab so a headless screenshot shows:
* · the ROUTE EXIT GATE circled in orange (the gate the player should
* path out of the system from to reach the destination),
* · an orange line from the ship to that gate ("path out of the system").
*
* node dev/server.mjs 8084
* node dev/shot-firefox.mjs \
* "http://127.0.0.1:8084/dev/exit-gate-shot.html" \
* "window.__EXIT_GATE ? window.__EXIT_GATE.ready : null" \
* EXIT_GATE.png 40000
*
* The report (top-left) lists console errors + the exit-gate state.
*/
import Phaser from '../js/vendor/phaser.js';
import { config } from '../js/config/Config.js';
import { ConfigLoader } from '../js/config/ConfigLoader.js';
import { createGameConfig } from '../js/config/GameConfig.js';
import { GameScene } from '../js/scenes/GameScene.js';
const data = await ConfigLoader.load();
config.init(data);
const errors = [];
const origErr = console.error.bind(console);
console.error = (...a) => { errors.push(a.map(String).join(' ')); origErr(...a); };
window.addEventListener('error', (e) => errors.push(String(e.message)));
window.addEventListener('unhandledrejection', (e) => errors.push(`rejection: ${e.reason}`));
const gameConfig = createGameConfig();
gameConfig.scene = [GameScene];
const game = new Phaser.Game(gameConfig);
window.game = game;
const report = document.createElement('pre');
report.id = 'report';
report.style.cssText = 'position:fixed;left:10px;top:10px;z-index:9999;max-width:70%;margin:0;padding:8px 12px;font:13px/1.5 monospace;color:#eaf6ff;background:rgba(6,20,16,0.92);border:1px solid #1b3a5a;white-space:pre-wrap;';
document.body.appendChild(report);
const setReport = (lines) => { report.textContent = (Array.isArray(lines) ? lines : [lines]).join('\n'); };
setReport('booting…');
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function waitScene() {
for (let i = 0; i < 100; i++) {
const s = game.scene.getScene('GameScene');
if (s && s.ship && s.mapWindow) return s;
await sleep(100);
}
throw new Error('GameScene never booted');
}
try {
const s = await waitScene();
await sleep(800);
// Pick a FAR destination (a multi-hop route, so the exit gate is the
// route's next gate in the CURRENT system).
const sysId = s.systemRecord.id;
const records = s.galaxy.records;
const cur = records.find((r) => r.id === sysId);
const others = records.filter((r) => r.id !== sysId);
others.sort((a, b) => {
const da = Math.hypot(a.x - cur.x, a.y - cur.y);
const db = Math.hypot(b.x - cur.x, b.y - cur.y);
return db - da;
});
const dest = others[2] ?? others[0];
if (!dest) throw new Error('no destination candidate');
const destContent = s.galaxy.contentOf(dest.id);
const destPlanet = (destContent.planets ?? [])[0];
const destObjId = destPlanet?.name ?? null;
// Set the destination.
s.setDestination(dest.id, destObjId);
await sleep(400);
// Discover the exit gate (the route's next gate in the CURRENT system)
// so it's drawn on the chart.
const exitGate = s.routeNextGate();
if (exitGate) {
let known = s.discovery.bySystem.get(sysId);
if (!known) { known = new Set(); s.discovery.bySystem.set(sysId, known); }
s.discovery.check(sysId, exitGate.x, exitGate.y, [{ id: exitGate.discoveryId, x: exitGate.x, y: exitGate.y, radius: 100 }]);
}
await sleep(300);
// Open the MAP console's CURRENT SYSTEM tab (the default mode).
s.mapWindow._switchMode('currentSystem');
s.mapWindow.open();
await sleep(1600);
// Collect the state for the report.
const chartSnap = s.mapChartSnapshot();
const exitInfo = chartSnap?.routeExitGate;
const exitObj = (chartSnap?.objects ?? []).find((o) => o?.id === exitInfo?.id);
window.__EXIT_GATE = {
ready: true,
errors,
destSystem: dest.id,
destName: dest.name,
exitGateId: exitInfo?.id,
exitGateName: exitInfo?.name,
exitGateDiscovered: exitObj?.discovered,
exitGateX: exitInfo?.x,
exitGateY: exitInfo?.y,
shipX: chartSnap?.ship?.x,
shipY: chartSnap?.ship?.y,
destinationId: chartSnap?.destinationId,
};
const lines = [
`DESTINATION: ${dest.name} (${dest.id})`,
`EXIT GATE: ${exitInfo?.name ?? 'null'} (${exitInfo?.id ?? 'null'})`,
`EXIT GATE DISCOVERED: ${exitObj?.discovered}`,
`EXIT GATE POS: (${exitInfo?.x?.toFixed(0)}, ${exitInfo?.y?.toFixed(0)})`,
`SHIP POS: (${chartSnap?.ship?.x?.toFixed(0)}, ${chartSnap?.ship?.y?.toFixed(0)})`,
`DESTINATION IN CURRENT SYS: ${chartSnap?.destinationId ?? 'no (route exit gate shown)'}`,
`ERRORS: ${errors.length ? errors.join(' | ') : 'none'}`,
];
setReport(lines);
console.log('EXIT GATE READY', JSON.stringify(window.__EXIT_GATE, null, 2));
} catch (e) {
const lines = ['FATAL: ' + (e?.message ?? e), ...errors];
setReport(lines);
window.__EXIT_GATE = { ready: true, errors: [...errors, String(e?.message ?? e)] };
}