fix: 지난 플레이 전투 자료를 보존한다
통일·장수 삭제·게임 취소 archive에 전투 집계와 숙련도, 전투 결과를 저장한다. 개인 기록과 전투 상세는 보존 대상에서 제외하고 기존 Core snapshot도 정규화한다.
This commit is contained in:
@@ -143,7 +143,9 @@ type ActiveGeneral = {
|
||||
|
||||
const buildActiveGeneralArchive = (
|
||||
general: ActiveGeneral,
|
||||
ranks: Record<string, number>,
|
||||
history: string[],
|
||||
battleResults: string[],
|
||||
cancellation: { id: string; at: Date; reason: string }
|
||||
): InputJsonValue =>
|
||||
asJson({
|
||||
@@ -190,9 +192,14 @@ const buildActiveGeneralArchive = (
|
||||
},
|
||||
},
|
||||
lastTurn: general.lastTurn,
|
||||
meta: general.meta,
|
||||
meta: {
|
||||
...asRecord(general.meta),
|
||||
...Object.fromEntries(Object.entries(ranks).map(([key, value]) => [`rank_${key}`, value])),
|
||||
},
|
||||
penalty: general.penalty,
|
||||
history,
|
||||
records: { battleResult: battleResults },
|
||||
availability: { battleResultLogs: true },
|
||||
abandonedGame: {
|
||||
cancellationId: cancellation.id,
|
||||
cancelledAt: cancellation.at.toISOString(),
|
||||
@@ -266,14 +273,14 @@ const cancelGameInTransaction = async (
|
||||
]);
|
||||
|
||||
const activeIds = activeGenerals.map((general) => general.id);
|
||||
const [resolvedRankRows, resolvedHistoryLogs] = await Promise.all([
|
||||
const [resolvedRankRows, resolvedRecordLogs] = await Promise.all([
|
||||
activeIds.length ? prisma.rankData.findMany({ where: { generalId: { in: activeIds } } }) : [],
|
||||
activeIds.length
|
||||
? prisma.logEntry.findMany({
|
||||
where: {
|
||||
generalId: { in: activeIds },
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.HISTORY,
|
||||
category: { in: [LogCategory.HISTORY, LogCategory.BATTLE_BRIEF] },
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
})
|
||||
@@ -293,11 +300,19 @@ const cancelGameInTransaction = async (
|
||||
ranksByGeneral.set(row.generalId, ranks);
|
||||
}
|
||||
const logsByGeneral = new Map<number, string[]>();
|
||||
for (const row of resolvedHistoryLogs) {
|
||||
const battleResultsByGeneral = new Map<number, string[]>();
|
||||
for (const row of resolvedRecordLogs) {
|
||||
if (row.generalId === null) continue;
|
||||
const logs = logsByGeneral.get(row.generalId) ?? [];
|
||||
const target =
|
||||
row.category === LogCategory.HISTORY
|
||||
? logsByGeneral
|
||||
: row.category === LogCategory.BATTLE_BRIEF
|
||||
? battleResultsByGeneral
|
||||
: null;
|
||||
if (!target) continue;
|
||||
const logs = target.get(row.generalId) ?? [];
|
||||
logs.push(row.text);
|
||||
logsByGeneral.set(row.generalId, logs);
|
||||
target.set(row.generalId, logs);
|
||||
}
|
||||
|
||||
const participantUsers = new Set<string>();
|
||||
@@ -464,7 +479,9 @@ const cancelGameInTransaction = async (
|
||||
turnTime: general.turnTime,
|
||||
data: buildActiveGeneralArchive(
|
||||
general as ActiveGeneral,
|
||||
ranksByGeneral.get(general.id) ?? {},
|
||||
logsByGeneral.get(general.id) ?? [],
|
||||
battleResultsByGeneral.get(general.id) ?? [],
|
||||
abandonment
|
||||
),
|
||||
},
|
||||
@@ -477,7 +494,9 @@ const cancelGameInTransaction = async (
|
||||
turnTime: general.turnTime,
|
||||
data: buildActiveGeneralArchive(
|
||||
general as ActiveGeneral,
|
||||
ranksByGeneral.get(general.id) ?? {},
|
||||
logsByGeneral.get(general.id) ?? [],
|
||||
battleResultsByGeneral.get(general.id) ?? [],
|
||||
abandonment
|
||||
),
|
||||
},
|
||||
|
||||
@@ -286,24 +286,37 @@ const archiveDeletedGeneral = async (
|
||||
): Promise<void> => {
|
||||
const serverId =
|
||||
typeof worldMeta.serverId === 'string' && worldMeta.serverId.trim() ? worldMeta.serverId.trim() : 'default';
|
||||
const history = await prisma.logEntry.findMany({
|
||||
where: {
|
||||
generalId: event.generalId,
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.HISTORY,
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
select: { text: true },
|
||||
});
|
||||
const archivedMeta = { ...asRecord(event.before.meta) };
|
||||
const [recordRows, rankRows] = await Promise.all([
|
||||
prisma.logEntry.findMany({
|
||||
where: {
|
||||
generalId: event.generalId,
|
||||
scope: LogScope.GENERAL,
|
||||
category: { in: [LogCategory.HISTORY, LogCategory.BATTLE_BRIEF] },
|
||||
},
|
||||
orderBy: { id: 'desc' },
|
||||
select: { category: true, text: true },
|
||||
}),
|
||||
prisma.rankData.findMany({
|
||||
where: { generalId: event.generalId },
|
||||
select: { type: true, value: true },
|
||||
}),
|
||||
]);
|
||||
const archivedMeta = {
|
||||
...asRecord(event.before.meta),
|
||||
...Object.fromEntries(rankRows.map((row) => [`rank_${row.type}`, row.value])),
|
||||
};
|
||||
delete archivedMeta.inheritRandomUnique;
|
||||
delete archivedMeta.inheritSpecificSpecialWar;
|
||||
const history = recordRows.filter((row) => row.category === LogCategory.HISTORY).map((row) => row.text);
|
||||
const battleResults = recordRows.filter((row) => row.category === LogCategory.BATTLE_BRIEF).map((row) => row.text);
|
||||
const data = {
|
||||
...event.before,
|
||||
meta: archivedMeta,
|
||||
turnTime: event.before.turnTime.toISOString(),
|
||||
recentWarTime: event.before.recentWarTime?.toISOString() ?? null,
|
||||
history: history.map((entry) => entry.text),
|
||||
history,
|
||||
records: { battleResult: battleResults },
|
||||
availability: { battleResultLogs: true },
|
||||
};
|
||||
await prisma.oldGeneral.upsert({
|
||||
where: { by_no: { serverId, generalNo: event.generalId } },
|
||||
|
||||
@@ -531,29 +531,44 @@ export const persistUnificationFinalization = async (
|
||||
});
|
||||
|
||||
const archiveGenerals = [...neutralGenerals, ...winnerGenerals];
|
||||
const generalHistoryRows = archiveGenerals.length
|
||||
const generalRecordRows = archiveGenerals.length
|
||||
? await transaction.logEntry.findMany({
|
||||
where: {
|
||||
generalId: { in: archiveGenerals.map((general) => general.id) },
|
||||
scope: LogScope.GENERAL,
|
||||
category: LogCategory.HISTORY,
|
||||
category: { in: [LogCategory.HISTORY, LogCategory.BATTLE_BRIEF] },
|
||||
},
|
||||
orderBy: { id: 'asc' },
|
||||
select: { generalId: true, text: true },
|
||||
select: { generalId: true, category: true, text: true },
|
||||
})
|
||||
: [];
|
||||
const historyByGeneral = new Map<number, string[]>();
|
||||
for (const row of generalHistoryRows) {
|
||||
const battleResultsByGeneral = new Map<number, string[]>();
|
||||
for (const row of generalRecordRows) {
|
||||
if (row.generalId === null) continue;
|
||||
const history = historyByGeneral.get(row.generalId) ?? [];
|
||||
history.push(row.text);
|
||||
historyByGeneral.set(row.generalId, history);
|
||||
const target =
|
||||
row.category === LogCategory.HISTORY
|
||||
? historyByGeneral
|
||||
: row.category === LogCategory.BATTLE_BRIEF
|
||||
? battleResultsByGeneral
|
||||
: null;
|
||||
if (!target) continue;
|
||||
const records = target.get(row.generalId) ?? [];
|
||||
records.push(row.text);
|
||||
target.set(row.generalId, records);
|
||||
}
|
||||
for (const general of archiveGenerals) {
|
||||
const ranks = ranksByGeneral.get(general.id) ?? {};
|
||||
const data = {
|
||||
...general,
|
||||
meta: {
|
||||
...asRecord(general.meta),
|
||||
...Object.fromEntries(Object.entries(ranks).map(([key, value]) => [`rank_${key}`, value])),
|
||||
},
|
||||
turnTime: general.turnTime.toISOString(),
|
||||
history: historyByGeneral.get(general.id) ?? [],
|
||||
records: { battleResult: [...(battleResultsByGeneral.get(general.id) ?? [])].reverse() },
|
||||
availability: { battleResultLogs: true },
|
||||
generationKey: input.generationKey,
|
||||
};
|
||||
await transaction.oldGeneral.upsert({
|
||||
|
||||
Reference in New Issue
Block a user