refactor: 턴 경계와 12턴 묶음을 보존하는 2배속 복구 구현
This commit is contained in:
@@ -571,7 +571,10 @@ const cancelGameInTransaction = async (
|
||||
return { ...resultFromPersisted(created), alreadyApplied: false };
|
||||
};
|
||||
|
||||
export const cancelGame = async (request: GameCancellationRequest): Promise<GameCancellationResult> => {
|
||||
export const cancelGame = async (
|
||||
request: GameCancellationRequest,
|
||||
connectorFactory: typeof createGamePostgresConnector = createGamePostgresConnector
|
||||
): Promise<GameCancellationResult> => {
|
||||
if (!request.reason.trim()) throw new Error('Game cancellation reason is required.');
|
||||
if (!GAME_CANCELLATION_HISTORY_MODES.includes(request.historyMode)) throw new Error('Invalid history mode.');
|
||||
if (!GAME_CANCELLATION_GENERAL_MODES.includes(request.generalMode)) throw new Error('Invalid general mode.');
|
||||
@@ -580,7 +583,7 @@ export const cancelGame = async (request: GameCancellationRequest): Promise<Game
|
||||
earnedPoint: 0,
|
||||
earnedPointRetentionPercent: request.earnedPointRetentionPercent,
|
||||
});
|
||||
const connector = createGamePostgresConnector({ url: request.databaseUrl });
|
||||
const connector = connectorFactory({ url: request.databaseUrl });
|
||||
await connector.connect();
|
||||
try {
|
||||
return await connector.prisma.$transaction(
|
||||
|
||||
@@ -68,6 +68,8 @@ export interface ScenarioSeedOptions {
|
||||
generalPoolOptions?: GeneralPoolLoaderOptions;
|
||||
resetTables?: boolean;
|
||||
now?: Date;
|
||||
/** 실제 설치 시각. now는 예약된 게임 달력 기준일일 수 있다. */
|
||||
wallNow?: Date;
|
||||
tickSeconds?: number;
|
||||
gameClockMode?: GameClockMode;
|
||||
installOptions?: ScenarioInstallOptions;
|
||||
@@ -244,8 +246,14 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
|
||||
const gameClockMode = options.gameClockMode ?? 'realtime';
|
||||
// A realtime season prepared before its formal opening must not consume
|
||||
// wall time while users are only allowed to edit reserved commands.
|
||||
const initialClockWallAnchor = install?.openAt && install.openAt.getTime() > now.getTime() ? install.openAt : now;
|
||||
const initialClockPhase = resolveInitialClockPhase(gameClockMode, now, initialClockWallAnchor);
|
||||
const wallNow = gameClockMode === 'manual' ? now : (options.wallNow ?? now);
|
||||
const requestedOpening = install?.openAt && install.openAt.getTime() > wallNow.getTime() ? install.openAt : wallNow;
|
||||
const openingFloor = cutTurn(requestedOpening, turnTermMinutes);
|
||||
const initialClockWallAnchor =
|
||||
gameClockMode === 'manual'
|
||||
? requestedOpening
|
||||
: new Date(openingFloor.getTime() + (openingFloor < requestedOpening ? tickSeconds * 1_000 : 0));
|
||||
const initialClockPhase = resolveInitialClockPhase(gameClockMode, wallNow, initialClockWallAnchor);
|
||||
const initialClock = new GameClock({
|
||||
baseTime: startState.startTime,
|
||||
tick: 0,
|
||||
@@ -317,7 +325,7 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
|
||||
develcost: (startState.currentYear - (scenario.startYear ?? startState.currentYear) + 10) * 2,
|
||||
starttime: formatDateTime(startState.startTime),
|
||||
turntime: formatDateTime(now),
|
||||
opentime: formatDateTime(now),
|
||||
opentime: formatDateTime(initialClockWallAnchor),
|
||||
lastTurnTime: formatDateTime(now),
|
||||
};
|
||||
|
||||
@@ -344,7 +352,7 @@ export const seedScenarioToDatabase = async (options: ScenarioSeedOptions): Prom
|
||||
}
|
||||
|
||||
worldMeta.hiddenSeed = hiddenSeed;
|
||||
worldMeta.seededAtWall = now.toISOString();
|
||||
worldMeta.seededAtWall = wallNow.toISOString();
|
||||
worldMeta.scheduledOpenAtWall = initialClockWallAnchor.toISOString();
|
||||
worldMeta.projectedGameDateAtOpening = initialClock.baseTime.toISOString();
|
||||
worldMeta.calendarStart = startState.startTime.toISOString();
|
||||
|
||||
Reference in New Issue
Block a user