orbit/dev/smoke-game.mjs

120 lines
4.9 KiB
JavaScript

/**
* Dev-only smoke test: boots the game directly into the GameScene
* (skipping the menu), so the flight scene can be screenshotted/checked
* without clicking "New Game".
*
* python3 -m http.server 8080
* firefox --headless --screenshot shot.png \
* --window-size=1280,720 http://localhost:8080/dev/test-game.html
*
* Dev hooks (URL params, dev only — ignored by the game itself):
* ?ship=<x>,<y> teleport the ship to a world position after boot
* (screenshots of far-off states — e.g. the off-screen
* compass arrows pointing back at the home world).
* ?near=<px> fly the ship to <px> (edge-to-edge) from the first
* system planet — screenshots the discovery moment
* (rim ping + toast) with the world in view.
* ?tethers=x,y,level;x,y,level add dev tethers (union-boundary tests)
* ?homeLevel=<n> set the home tether's level (bigger/smaller range)
* ?seed=<seed> use a DETERMINISTIC dev galaxy (same seed ⇒ same
* system, planets, asteroid clusters) — reproducible shots
* ?report=1 paint console errors (or "SMOKE OK") on the canvas
*/
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 gameConfig = createGameConfig();
const params = typeof location !== 'undefined' ? new URLSearchParams(location.search) : null;
const shipParam = params ? params.get('ship') : null;
const nearParam = params ? params.get('near') : null;
const tethersParam = params ? params.get('tethers') : null;
const homeLevelParam = params ? params.get('homeLevel') : null;
const seedParam = params ? params.get('seed') : null;
// Deterministic dev galaxy for reproducible screenshots (GameScene.
// ensureGalaxy reads this when the registry is empty).
if (seedParam && typeof globalThis !== 'undefined') globalThis.__ORBIT_DEV_SEED = seedParam;
// Dev: capture console errors + uncaught exceptions for ?report=1.
const __errors = [];
if (typeof window !== 'undefined') {
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)));
}
gameConfig.scene = [GameScene];
const game = new Phaser.Game(gameConfig);
window.game = game;
console.info('smoke: game booted into GameScene');
if (shipParam) {
const [sx, sy] = shipParam.split(',').map(Number);
if (Number.isFinite(sx) && Number.isFinite(sy)) {
setTimeout(() => {
const s = game.scene.getScene('GameScene');
s.ship.setPosition(sx, sy);
s.cameras.main.setScroll(sx - s.scale.width / 2, sy - s.scale.height / 2);
console.info(`smoke: ship teleported to (${sx}, ${sy})`);
}, 500);
}
}
if (tethersParam || homeLevelParam) {
setTimeout(() => {
const s = game.scene.getScene('GameScene');
if (homeLevelParam) {
const home = s.tetherField.tethers[0];
if (home) s.tetherField.setLevel(home.id, Number(homeLevelParam) || 1);
}
if (tethersParam) {
tethersParam.split(';').forEach((triple, i) => {
const [tx, ty, tl] = triple.split(',').map(Number);
if (Number.isFinite(tx) && Number.isFinite(ty)) {
s.tetherField.add('dev' + i, tx, ty, Number.isFinite(tl) ? tl : 1, 'dev');
}
});
}
console.info(`smoke: dev tethers ready (homeLevel=${homeLevelParam ?? '—'}, extra=${tethersParam ?? '—'})`);
}, 600);
}
if (params && params.get('report') === '1') {
// After boot, paint any captured console errors onto the canvas so a
// headless screenshot shows whether the scene is healthy.
setTimeout(() => {
const s = game.scene.getScene('GameScene');
if (!s) return;
const msg = __errors.length === 0
? 'SMOKE OK — no console errors'
: __errors.slice(0, 3).join('\n');
s.add.text(16, 690, msg, {
fontFamily: 'monospace',
fontSize: '12px',
color: __errors.length === 0 ? '#7ce8a4' : '#ff2d6f',
align: 'left',
}).setOrigin(0, 1).setScrollFactor(0).setDepth(9000);
}, 3000);
}
if (nearParam) {
const px = Number(nearParam) || 400;
setTimeout(() => {
const s = game.scene.getScene('GameScene');
const p = s.systemPlanets[0];
if (!p) return;
// Place the ship on the planet→origin axis, `px` (edge-to-edge) off
// the rim — inside the discovery distance, with the world in view.
const ang = Math.atan2(-p.y, -p.x);
const sx = p.x + Math.cos(ang) * (p.radius + px);
const sy = p.y + Math.sin(ang) * (p.radius + px);
s.ship.setPosition(sx, sy);
s.cameras.main.setScroll(sx - s.scale.width / 2, sy - s.scale.height / 2);
console.info(`smoke: ship parked ${px}px off ${p.discoveryName}'s rim`);
}, 500);
}