feat: add ranking and hall of fame features

- Implemented new routes for Best General and Hall of Fame views in the frontend.
- Created BestGeneralView and HallOfFameView components to display rankings based on game data.
- Added new database models for RankData and HallOfFame to store ranking information.
- Introduced ranking types and hall of fame types in common types for better type safety.
- Developed ranking router to handle fetching of best general and hall of fame data.
- Updated database schema with migrations to include new tables for rank data and hall of fame.
- Enhanced the main view with links to the new ranking features.
This commit is contained in:
2026-01-29 18:18:35 +00:00
parent 19c359d0b2
commit 9fff671c2f
16 changed files with 1217 additions and 2 deletions
@@ -35,6 +35,7 @@ export interface ScenarioInstallOptions {
autorunUser?: ScenarioAutorunOptions | null;
preopenAt?: Date | null;
season?: number;
serverId?: string;
}
export interface ScenarioSeedOptions {
@@ -258,6 +259,9 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
if (typeof install?.season === 'number' && Number.isFinite(install.season)) {
worldMeta.season = Math.floor(install.season);
}
if (typeof install?.serverId === 'string' && install.serverId.trim()) {
worldMeta.serverId = install.serverId.trim();
}
const integrationSeed = process.env[INTEGRATION_WORLD_SEED_ENV];
if (typeof integrationSeed === 'string' && integrationSeed.trim().length > 0) {
@@ -304,6 +308,43 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
},
});
if (typeof worldMeta.serverId === 'string' && worldMeta.serverId) {
await prisma.gameHistory.upsert({
where: { serverId: worldMeta.serverId },
create: {
serverId: worldMeta.serverId,
date: now,
winnerNation: null,
map: scenario.config.environment.mapName ?? null,
season:
typeof worldMeta.season === 'number' && Number.isFinite(worldMeta.season)
? Math.floor(worldMeta.season)
: 1,
scenario: options.scenarioId,
scenarioName: String(seed.scenarioMeta?.title ?? ''),
env: asJson({
config: scenarioConfig,
meta: worldMeta,
}),
},
update: {
date: now,
winnerNation: null,
map: scenario.config.environment.mapName ?? null,
season:
typeof worldMeta.season === 'number' && Number.isFinite(worldMeta.season)
? Math.floor(worldMeta.season)
: 1,
scenario: options.scenarioId,
scenarioName: String(seed.scenarioMeta?.title ?? ''),
env: asJson({
config: scenarioConfig,
meta: worldMeta,
}),
},
});
}
if (seed.nations.length > 0) {
await prisma.nation.createMany({
data: seed.nations.map((nation) => ({