fix(engine): 서버 재개 시 게임 시계를 Ref 기준으로 보정한다

짧은 중단은 순서대로 따라잡고 장기 중단은 턴 간격별 Ref 한도를 넘어선 완전 턴을 일괄 이동한다. 장수와 미완료 경매 시각을 같은 트랜잭션에서 저장하고 표시 시각 지연을 복구한다.
This commit is contained in:
2026-08-23 02:00:45 +00:00
parent ade543f936
commit eaf7ef8c22
10 changed files with 596 additions and 47 deletions
+23 -1
View File
@@ -379,7 +379,7 @@ export const summarizeRealtimeReadModelChanges = (
lobbyGeneralIds,
reservedGeneralIds,
recordGeneralIds,
worldChanged: false,
worldChanged: changes.realtimeBacklogShiftTicks > 0,
globalRecordsChanged,
worldHistoryChanged,
contactsChanged,
@@ -1078,6 +1078,7 @@ export const createDatabaseTurnHooks = async (
let persistedVisibleLogs: PersistedVisibleLogRow[] = [];
let visibleLogFloor = directLogFloor;
const {
realtimeBacklogShiftTicks,
accessScoreResetGeneralIds,
generals,
cities,
@@ -1161,6 +1162,27 @@ export const createDatabaseTurnHooks = async (
data: worldStateUpdate,
});
if (realtimeBacklogShiftTicks > 0) {
const deltaTicks = BigInt(realtimeBacklogShiftTicks);
const deltaSeconds = (realtimeBacklogShiftTicks / GAME_TICKS_PER_TURN) * state.tickSeconds;
await prisma.$executeRaw(
GamePrisma.sql`
UPDATE general
SET turn_tick = CASE WHEN turn_tick IS NULL THEN NULL ELSE turn_tick + ${deltaTicks} END,
turn_time = turn_time + (${deltaSeconds} * INTERVAL '1 second')
`
);
await prisma.$executeRaw(
GamePrisma.sql`
UPDATE auction
SET close_tick = CASE WHEN close_tick IS NULL THEN NULL ELSE close_tick + ${deltaTicks} END,
close_at = close_at + (${deltaSeconds} * INTERVAL '1 second'),
updated_at = NOW()
WHERE status = 'OPEN'
`
);
}
if (
state.tickSeconds !== persistedTickSeconds &&
commandCompletion?.result.type !== 'updateRuntimeSettings'