Recover legacy campaign saves

This commit is contained in:
2026-07-05 08:58:58 +09:00
parent 5a76eb07ad
commit d92d5f9061
5 changed files with 152 additions and 16 deletions

View File

@@ -0,0 +1,91 @@
import { createServer } from 'vite';
const storage = new Map();
globalThis.window = {
localStorage: {
getItem(key) {
return storage.has(key) ? storage.get(key) : null;
},
setItem(key, value) {
storage.set(key, String(value));
},
removeItem(key) {
storage.delete(key);
},
clear() {
storage.clear();
}
}
};
const server = await createServer({
logLevel: 'error',
server: { middlewareMode: true },
appType: 'custom'
});
try {
const { campaignStorageKey, loadCampaignState } = await server.ssrLoadModule('/src/game/state/campaignState.ts');
storage.clear();
const empty = loadCampaignState();
assert(empty.version === 1 && empty.step === 'new', `Expected empty storage to create initial campaign state: ${JSON.stringify(empty)}`);
storage.clear();
storage.set(
campaignStorageKey,
JSON.stringify({
updatedAt: '2026-07-01T00:00:00.000Z',
step: 'first-camp',
activeSaveSlot: 1,
gold: 180,
inventory: { bean: 2 },
completedCampDialogues: ['bond-a', 'bond-a'],
completedCampVisits: ['visit-a', 'visit-a']
})
);
const legacy = loadCampaignState();
assert(legacy.version === 1, `Expected legacy save without version to normalize to v1: ${JSON.stringify(legacy)}`);
assert(legacy.step === 'first-camp' && legacy.gold === 180, `Expected legacy save progress to survive: ${JSON.stringify(legacy)}`);
assert(Array.isArray(legacy.roster) && Array.isArray(legacy.bonds), `Expected legacy save arrays to be restored: ${JSON.stringify(legacy)}`);
assert(
legacy.completedCampDialogues.length === 1 && legacy.completedCampVisits.length === 1,
`Expected legacy save duplicate completion flags to be deduped: ${JSON.stringify(legacy)}`
);
assert(
Array.isArray(legacy.selectedSortieUnitIds) &&
typeof legacy.sortieFormationAssignments === 'object' &&
typeof legacy.sortieItemAssignments === 'object',
`Expected modern sortie fields to be restored: ${JSON.stringify(legacy)}`
);
storage.clear();
storage.set(campaignStorageKey, JSON.stringify({ version: 99, step: 'sixty-sixth-camp' }));
const unsupported = loadCampaignState();
assert(unsupported.step === 'new', `Expected unsupported future save version to be ignored: ${JSON.stringify(unsupported)}`);
storage.clear();
storage.set(campaignStorageKey, JSON.stringify({ version: 99, step: 'sixty-sixth-camp' }));
storage.set(
`${campaignStorageKey}:slot-2`,
JSON.stringify({
version: 1,
updatedAt: '2026-07-02T00:00:00.000Z',
step: 'second-camp',
activeSaveSlot: 2,
gold: 260
})
);
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, legacy recovery, unsupported-version rejection, and slotted fallback.');
} finally {
await server.close();
}
function assert(condition, message) {
if (!condition) {
throw new Error(message);
}
}