Normalize malformed campaign bonds
This commit is contained in:
@@ -69,7 +69,11 @@ try {
|
||||
activeSaveSlot: '2',
|
||||
gold: '410',
|
||||
roster: { corrupted: true },
|
||||
bonds: { corrupted: true },
|
||||
bonds: [
|
||||
{ id: 'broken-bond', title: 'Broken Bond', unitIds: { corrupted: true }, level: 3, exp: 12, battleExp: 2 },
|
||||
{ id: 'oath-bond', title: 'Oath Bond', unitIds: ['liu-bei', 'guan-yu'], level: '2', exp: '14', battleExp: '5' },
|
||||
9
|
||||
],
|
||||
completedCampDialogues: ['dialogue-a', 17, 'dialogue-a', ''],
|
||||
completedCampVisits: 'visit-a',
|
||||
inventory: { bean: '3', wine: -2, empty: 0 },
|
||||
@@ -86,7 +90,14 @@ try {
|
||||
assert(malformed.step === 'third-camp', `Expected malformed save progress to survive: ${JSON.stringify(malformed)}`);
|
||||
assert(malformed.activeSaveSlot === 2 && malformed.gold === 410, `Expected malformed numeric fields to normalize: ${JSON.stringify(malformed)}`);
|
||||
assert(Array.isArray(malformed.roster) && malformed.roster.length === 0, `Expected malformed roster to reset to an array: ${JSON.stringify(malformed)}`);
|
||||
assert(Array.isArray(malformed.bonds) && malformed.bonds.length === 0, `Expected malformed bonds to reset to an array: ${JSON.stringify(malformed)}`);
|
||||
assert(
|
||||
Array.isArray(malformed.bonds) &&
|
||||
malformed.bonds.length === 1 &&
|
||||
malformed.bonds[0].id === 'oath-bond' &&
|
||||
malformed.bonds[0].level === 2 &&
|
||||
malformed.bonds[0].unitIds.length === 2,
|
||||
`Expected malformed bond entries to be filtered while valid bonds normalize: ${JSON.stringify(malformed)}`
|
||||
);
|
||||
assert(
|
||||
malformed.completedCampDialogues.length === 1 &&
|
||||
malformed.completedCampDialogues[0] === 'dialogue-a' &&
|
||||
@@ -203,7 +214,7 @@ try {
|
||||
const fallback = loadCampaignState();
|
||||
assert(fallback.step === 'second-camp' && fallback.activeSaveSlot === 2, `Expected valid slotted save fallback: ${JSON.stringify(fallback)}`);
|
||||
|
||||
console.log('Verified campaign save normalization, malformed-field recovery, unknown-step/report/history recovery, unsupported-version rejection, and slotted fallback.');
|
||||
console.log('Verified campaign save normalization, malformed-field/bond recovery, unknown-step/report/history recovery, unsupported-version rejection, and slotted fallback.');
|
||||
} finally {
|
||||
await server.close();
|
||||
}
|
||||
|
||||
@@ -802,8 +802,12 @@ function normalizeCampaignState(state: Partial<CampaignState>): CampaignState {
|
||||
normalized.step = normalizeCampaignStep(normalized.step);
|
||||
normalized.activeSaveSlot = normalizeSlot(normalized.activeSaveSlot);
|
||||
normalized.gold = normalizeNonNegativeInteger(normalized.gold);
|
||||
normalized.roster = arrayOrEmpty<UnitData>(normalized.roster).map(cloneUnit);
|
||||
normalized.bonds = arrayOrEmpty<CampBondSnapshot>(normalized.bonds).map(cloneBondSnapshot);
|
||||
normalized.roster = arrayOrEmpty<unknown>(normalized.roster)
|
||||
.filter(isPlainObject)
|
||||
.map((unit) => cloneUnit(unit as UnitData));
|
||||
normalized.bonds = arrayOrEmpty<unknown>(normalized.bonds)
|
||||
.map(normalizeCampBondSnapshot)
|
||||
.filter((bond): bond is CampBondSnapshot => Boolean(bond));
|
||||
normalized.completedCampDialogues = uniqueStrings(normalized.completedCampDialogues);
|
||||
normalized.completedCampVisits = uniqueStrings(normalized.completedCampVisits);
|
||||
normalized.inventory = normalizeInventory(normalized.inventory);
|
||||
@@ -933,6 +937,33 @@ function normalizeFirstBattleReport(report: unknown): FirstBattleReport | undefi
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeCampBondSnapshot(value: unknown): CampBondSnapshot | undefined {
|
||||
if (!isPlainObject(value)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const unitIds = arrayOrEmpty<unknown>(value.unitIds).filter((unitId): unitId is string => typeof unitId === 'string' && unitId.length > 0);
|
||||
if (
|
||||
typeof value.id !== 'string' ||
|
||||
value.id.length === 0 ||
|
||||
typeof value.title !== 'string' ||
|
||||
value.title.length === 0 ||
|
||||
unitIds.length < 2
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
...(value as CampBondSnapshot),
|
||||
id: value.id,
|
||||
title: value.title,
|
||||
unitIds: [unitIds[0], unitIds[1]] as [string, string],
|
||||
level: normalizeNonNegativeInteger(value.level),
|
||||
exp: normalizeNonNegativeInteger(value.exp),
|
||||
battleExp: normalizeNonNegativeInteger(value.battleExp)
|
||||
};
|
||||
}
|
||||
|
||||
function reserveTrainingFocusDefinition(focusId?: string) {
|
||||
const normalizedId = normalizeReserveTrainingFocusId(focusId);
|
||||
return campaignReserveTrainingFocusDefinitions.find((focus) => focus.id === normalizedId) ?? campaignReserveTrainingFocusDefinitions[0];
|
||||
|
||||
Reference in New Issue
Block a user