feat: 시즌 번호 필드 추가 및 메타 데이터 처리 로직 개선
This commit is contained in:
@@ -34,6 +34,7 @@ export interface ScenarioInstallOptions {
|
||||
joinMode?: 'full' | 'onlyRandom';
|
||||
autorunUser?: ScenarioAutorunOptions | null;
|
||||
preopenAt?: Date | null;
|
||||
season?: number;
|
||||
}
|
||||
|
||||
export interface ScenarioSeedOptions {
|
||||
@@ -254,6 +255,10 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
|
||||
lastTurnTime: formatDateTime(now),
|
||||
};
|
||||
|
||||
if (typeof install?.season === 'number' && Number.isFinite(install.season)) {
|
||||
worldMeta.season = Math.floor(install.season);
|
||||
}
|
||||
|
||||
const integrationSeed = process.env[INTEGRATION_WORLD_SEED_ENV];
|
||||
if (typeof integrationSeed === 'string' && integrationSeed.trim().length > 0) {
|
||||
worldMeta.hiddenSeed = integrationSeed.trim();
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from 'node:path';
|
||||
import { TRPCError } from '@trpc/server';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { resolvePostgresConfigFromEnv } from '@sammo-ts/infra';
|
||||
import { createGamePostgresConnector, resolvePostgresConfigFromEnv } from '@sammo-ts/infra';
|
||||
|
||||
import { procedure, router } from './trpc.js';
|
||||
import { listScenarioPreviews, resolveGitCommitSha } from './scenario/scenarioCatalog.js';
|
||||
@@ -329,6 +329,20 @@ const readMetaObject = (value: unknown): Record<string, unknown> => {
|
||||
return value as Record<string, unknown>;
|
||||
};
|
||||
|
||||
const readMetaNumber = (meta: Record<string, unknown>, key: string): number | null => {
|
||||
const raw = meta[key];
|
||||
if (typeof raw === 'number' && Number.isFinite(raw)) {
|
||||
return Math.floor(raw);
|
||||
}
|
||||
if (typeof raw === 'string') {
|
||||
const parsed = Number(raw);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return Math.floor(parsed);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const applyMetaPatch = (
|
||||
meta: Record<string, unknown>,
|
||||
patch: Record<string, unknown | null | undefined>
|
||||
@@ -850,6 +864,22 @@ export const adminRouter = router({
|
||||
schema: updatedProfile.profile,
|
||||
}).url;
|
||||
const resourcesRoot = path.resolve(process.cwd(), 'resources');
|
||||
const profileMeta = readMetaObject(updatedProfile.meta);
|
||||
const nextSeasonIdx = readMetaNumber(profileMeta, 'nextSeasonIdx');
|
||||
let baseSeason: number | null = null;
|
||||
const connector = createGamePostgresConnector({ url: databaseUrl });
|
||||
try {
|
||||
await connector.connect();
|
||||
const row = await connector.prisma.worldState.findFirst({
|
||||
select: { meta: true },
|
||||
});
|
||||
if (row) {
|
||||
baseSeason = readMetaNumber(readMetaObject(row.meta), 'season');
|
||||
}
|
||||
} finally {
|
||||
await connector.disconnect();
|
||||
}
|
||||
const season = nextSeasonIdx ?? baseSeason ?? 1;
|
||||
|
||||
await seedProfileDatabase({
|
||||
databaseUrl,
|
||||
@@ -866,6 +896,7 @@ export const adminRouter = router({
|
||||
showImgLevel: input.install.showImgLevel,
|
||||
tournamentTrig: input.install.tournamentTrig,
|
||||
joinMode: input.install.joinMode,
|
||||
season,
|
||||
autorunUser: input.install.autorunUser
|
||||
? {
|
||||
limitMinutes: input.install.autorunUser.limitMinutes,
|
||||
|
||||
@@ -113,6 +113,20 @@ interface GatewayAdminActionResult {
|
||||
|
||||
const normalizeMeta = (value: unknown): Record<string, unknown> => (isRecord(value) ? value : {});
|
||||
|
||||
const readMetaNumber = (meta: Record<string, unknown>, key: string): number | null => {
|
||||
const raw = meta[key];
|
||||
if (typeof raw === 'number' && Number.isFinite(raw)) {
|
||||
return Math.floor(raw);
|
||||
}
|
||||
if (typeof raw === 'string') {
|
||||
const parsed = Number(raw);
|
||||
if (Number.isFinite(parsed)) {
|
||||
return Math.floor(parsed);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const normalizeStatus = (value: unknown): GatewayAdminActionStatus | null => {
|
||||
if (typeof value === 'string') {
|
||||
return value as GatewayAdminActionStatus;
|
||||
@@ -615,6 +629,10 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
|
||||
if (!seedInfo.scenarioId) {
|
||||
return { status: 'FAILED', detail: 'scenarioId is missing' };
|
||||
}
|
||||
const profileMeta = normalizeMeta(profile.meta);
|
||||
const nextSeasonIdx = readMetaNumber(profileMeta, 'nextSeasonIdx');
|
||||
const baseSeason = readMetaNumber(normalizeMeta(seedInfo.meta), 'season');
|
||||
const season = nextSeasonIdx ?? baseSeason ?? 1;
|
||||
const seedTime =
|
||||
openAt ??
|
||||
(action.scheduledAt && action.action === 'RESET_SCHEDULED' ? new Date(action.scheduledAt) : this.now());
|
||||
@@ -650,7 +668,10 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
|
||||
scenarioId: seedInfo.scenarioId,
|
||||
tickSeconds: seedInfo.tickSeconds,
|
||||
now: seedTime,
|
||||
installOptions: installOptions ?? undefined,
|
||||
installOptions: {
|
||||
...(installOptions ?? {}),
|
||||
season,
|
||||
},
|
||||
scenarioOptions: { scenarioRoot: path.join(resourceRoot, 'scenario') },
|
||||
mapOptions: { mapRoot: path.join(resourceRoot, 'map') },
|
||||
unitSetOptions: { unitSetRoot: path.join(resourceRoot, 'unitset') },
|
||||
@@ -685,18 +706,19 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
|
||||
private async resolveResetSeedInfo(
|
||||
profile: GatewayProfileRecord,
|
||||
overrides?: { scenarioId?: number | null; tickSeconds?: number }
|
||||
): Promise<{ databaseUrl: string; scenarioId: number | null; tickSeconds?: number }> {
|
||||
): Promise<{ databaseUrl: string; scenarioId: number | null; tickSeconds?: number; meta: Record<string, unknown> } > {
|
||||
const databaseUrl = resolvePostgresConfigFromEnv({
|
||||
env: this.processConfig.baseEnv ?? process.env,
|
||||
schema: profile.profile,
|
||||
}).url;
|
||||
let scenarioId = overrides?.scenarioId ?? parseScenarioId(profile.scenario);
|
||||
let tickSeconds: number | undefined = overrides?.tickSeconds;
|
||||
let meta: Record<string, unknown> = {};
|
||||
const connector = createGamePostgresConnector({ url: databaseUrl });
|
||||
await connector.connect();
|
||||
try {
|
||||
const row = await connector.prisma.worldState.findFirst({
|
||||
select: { scenarioCode: true, tickSeconds: true },
|
||||
select: { scenarioCode: true, tickSeconds: true, meta: true },
|
||||
});
|
||||
if (row) {
|
||||
if (scenarioId === null) {
|
||||
@@ -708,11 +730,12 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
|
||||
if (tickSeconds === undefined && typeof row.tickSeconds === 'number' && Number.isFinite(row.tickSeconds)) {
|
||||
tickSeconds = row.tickSeconds;
|
||||
}
|
||||
meta = normalizeMeta(row.meta);
|
||||
}
|
||||
} finally {
|
||||
await connector.disconnect();
|
||||
}
|
||||
return { databaseUrl, scenarioId, tickSeconds };
|
||||
return { databaseUrl, scenarioId, tickSeconds, meta };
|
||||
}
|
||||
|
||||
private async runBuildCommands(
|
||||
|
||||
Reference in New Issue
Block a user