refacto: Keeping entrypoints clean and making files by purpose
This commit is contained in:
128
server/db/gameDb.js
Normal file
128
server/db/gameDb.js
Normal file
@@ -0,0 +1,128 @@
|
||||
import { pool } from "./pools.js";
|
||||
import { loadConfigFile, getConfig } from "../configLoader.js";
|
||||
import { computeWorldSeedState } from "../worldSeed.js";
|
||||
|
||||
let lastSeedSlot = null;
|
||||
|
||||
// ── Schema ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function initGameSchema() {
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS grid_cells (
|
||||
id SERIAL PRIMARY KEY,
|
||||
world_seed TEXT NOT NULL,
|
||||
x SMALLINT NOT NULL CHECK (x >= 0 AND x < 100),
|
||||
y SMALLINT NOT NULL CHECK (y >= 0 AND y < 100),
|
||||
exploitable BOOLEAN NOT NULL,
|
||||
has_planet BOOLEAN NOT NULL,
|
||||
planet_json JSONB,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
UNIQUE (world_seed, x, y)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_grid_cells_seed ON grid_cells (world_seed);
|
||||
`);
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS team_cooldowns (
|
||||
world_seed TEXT NOT NULL,
|
||||
team TEXT NOT NULL CHECK (team IN ('blue', 'red')),
|
||||
last_reveal TIMESTAMPTZ,
|
||||
PRIMARY KEY (world_seed, team)
|
||||
);
|
||||
`);
|
||||
await pool.query(`
|
||||
ALTER TABLE grid_cells ADD COLUMN IF NOT EXISTS discovered_by TEXT;
|
||||
UPDATE grid_cells SET discovered_by = 'blue' WHERE discovered_by IS NULL;
|
||||
ALTER TABLE grid_cells ALTER COLUMN discovered_by SET DEFAULT 'blue';
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM pg_constraint WHERE conname = 'grid_cells_discovered_by_check'
|
||||
) THEN
|
||||
ALTER TABLE grid_cells ADD CONSTRAINT grid_cells_discovered_by_check
|
||||
CHECK (discovered_by IN ('blue', 'red'));
|
||||
END IF;
|
||||
END $$;
|
||||
ALTER TABLE grid_cells ALTER COLUMN discovered_by SET NOT NULL;
|
||||
`);
|
||||
}
|
||||
|
||||
// ── World-seed epoch ──────────────────────────────────────────────────────────
|
||||
|
||||
export async function ensureSeedEpoch() {
|
||||
loadConfigFile();
|
||||
const rot = getConfig().databaseWipeoutIntervalSeconds;
|
||||
const { seedSlot, worldSeed } = computeWorldSeedState(rot);
|
||||
if (lastSeedSlot === null) {
|
||||
lastSeedSlot = seedSlot;
|
||||
return worldSeed;
|
||||
}
|
||||
if (seedSlot !== lastSeedSlot) {
|
||||
await pool.query("TRUNCATE grid_cells RESTART IDENTITY");
|
||||
await pool.query("DELETE FROM team_cooldowns WHERE world_seed != $1", [worldSeed]);
|
||||
console.log(`[world] Slot ${lastSeedSlot} → ${seedSlot}; grid wiped, old cooldowns cleared.`);
|
||||
lastSeedSlot = seedSlot;
|
||||
}
|
||||
return worldSeed;
|
||||
}
|
||||
|
||||
// ── Grid cells ────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getGridCells(worldSeed) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
|
||||
FROM grid_cells WHERE world_seed = $1`,
|
||||
[worldSeed]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
|
||||
export async function insertCell(seed, x, y, exploitable, hasPlanet, planetJson, team) {
|
||||
const { rows } = await pool.query(
|
||||
`INSERT INTO grid_cells (world_seed, x, y, exploitable, has_planet, planet_json, discovered_by)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
ON CONFLICT (world_seed, x, y) DO NOTHING
|
||||
RETURNING x, y, exploitable, has_planet, planet_json, discovered_by`,
|
||||
[seed, x, y, exploitable, hasPlanet, planetJson, team]
|
||||
);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
export async function getExistingCell(seed, x, y) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT x, y, exploitable, has_planet, planet_json, discovered_by
|
||||
FROM grid_cells WHERE world_seed = $1 AND x = $2 AND y = $3`,
|
||||
[seed, x, y]
|
||||
);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
// ── Team cooldowns ────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getTeamCooldown(worldSeed, team) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT last_reveal FROM team_cooldowns WHERE world_seed = $1 AND team = $2`,
|
||||
[worldSeed, team]
|
||||
);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
export async function upsertTeamCooldown(worldSeed, team) {
|
||||
await pool.query(
|
||||
`INSERT INTO team_cooldowns (world_seed, team, last_reveal)
|
||||
VALUES ($1, $2, NOW())
|
||||
ON CONFLICT (world_seed, team) DO UPDATE SET last_reveal = NOW()`,
|
||||
[worldSeed, team]
|
||||
);
|
||||
}
|
||||
|
||||
// ── Scores ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function getScores(worldSeed) {
|
||||
const { rows } = await pool.query(
|
||||
`SELECT discovered_by, COUNT(*) AS cnt
|
||||
FROM grid_cells WHERE world_seed = $1
|
||||
GROUP BY discovered_by`,
|
||||
[worldSeed]
|
||||
);
|
||||
return rows;
|
||||
}
|
||||
Reference in New Issue
Block a user