Recover malformed first battle reports

This commit is contained in:
2026-07-05 10:01:06 +09:00
parent fa78f82ce2
commit 4be59e5c80
2 changed files with 162 additions and 6 deletions

View File

@@ -1051,11 +1051,107 @@ function normalizeFirstBattleReport(report: unknown): FirstBattleReport | undefi
return undefined;
}
try {
return cloneReport(report as FirstBattleReport);
} catch {
if (
typeof report.battleId !== 'string' ||
report.battleId.length === 0 ||
(report.outcome !== 'victory' && report.outcome !== 'defeat')
) {
return undefined;
}
const battleTitle =
typeof report.battleTitle === 'string' && report.battleTitle.length > 0
? report.battleTitle
: battleScenarios[report.battleId as BattleScenarioId]?.title;
if (!battleTitle) {
return undefined;
}
return {
battleId: report.battleId,
battleTitle,
outcome: report.outcome,
turnNumber: normalizeNonNegativeInteger(report.turnNumber),
rewardGold: normalizeNonNegativeInteger(report.rewardGold),
defeatedEnemies: normalizeNonNegativeInteger(report.defeatedEnemies),
totalEnemies: normalizeNonNegativeInteger(report.totalEnemies),
objectives: arrayOrEmpty<unknown>(report.objectives)
.map(normalizeBattleObjectiveSnapshot)
.filter((objective): objective is BattleObjectiveSnapshot => Boolean(objective)),
units: arrayOrEmpty<unknown>(report.units)
.map(normalizeBattleReportUnitSnapshot)
.filter((unit): unit is UnitData => Boolean(unit)),
bonds: arrayOrEmpty<unknown>(report.bonds)
.map(normalizeCampBondSnapshot)
.filter((bond): bond is CampBondSnapshot => Boolean(bond)),
mvp: normalizeCampMvpSnapshot(report.mvp),
itemRewards: uniqueStrings(report.itemRewards),
campaignRewards: cloneCampaignRewardSnapshot(
isPlainObject(report.campaignRewards) ? report.campaignRewards as CampaignRewardSnapshot : undefined
),
completedCampDialogues: uniqueStrings(report.completedCampDialogues),
completedCampVisits: uniqueStrings(report.completedCampVisits),
createdAt: typeof report.createdAt === 'string' && report.createdAt.length > 0 ? report.createdAt : new Date().toISOString()
};
}
function normalizeBattleReportUnitSnapshot(value: unknown): UnitData | undefined {
if (
!isPlainObject(value) ||
typeof value.id !== 'string' ||
value.id.length === 0 ||
typeof value.name !== 'string' ||
value.name.length === 0 ||
(value.faction !== 'ally' && value.faction !== 'enemy')
) {
return undefined;
}
const stats = recordOrEmpty(value.stats);
const hp = normalizeNonNegativeInteger(value.hp);
const maxHp = Math.max(hp, normalizeNonNegativeInteger(value.maxHp));
return {
id: value.id,
name: value.name,
faction: value.faction,
className: typeof value.className === 'string' ? value.className : '',
classKey: typeof value.classKey === 'string' ? value.classKey as UnitData['classKey'] : 'infantry',
level: normalizeNonNegativeInteger(value.level),
exp: normalizeNonNegativeInteger(value.exp),
hp,
maxHp,
attack: normalizeNonNegativeInteger(value.attack),
move: normalizeNonNegativeInteger(value.move),
stats: {
might: normalizeNonNegativeInteger(stats.might),
intelligence: normalizeNonNegativeInteger(stats.intelligence),
leadership: normalizeNonNegativeInteger(stats.leadership),
agility: normalizeNonNegativeInteger(stats.agility),
luck: normalizeNonNegativeInteger(stats.luck)
},
equipment: recordOrEmpty(value.equipment) as UnitData['equipment'],
x: normalizeNonNegativeInteger(value.x),
y: normalizeNonNegativeInteger(value.y)
};
}
function normalizeCampMvpSnapshot(value: unknown): CampMvpSnapshot | undefined {
if (
!isPlainObject(value) ||
typeof value.unitId !== 'string' ||
value.unitId.length === 0 ||
typeof value.name !== 'string' ||
value.name.length === 0
) {
return undefined;
}
return {
unitId: value.unitId,
name: value.name,
damageDealt: normalizeNonNegativeInteger(value.damageDealt),
defeats: normalizeNonNegativeInteger(value.defeats)
};
}
function normalizeCampBondSnapshot(value: unknown): CampBondSnapshot | undefined {