Cap campaign save string lists
This commit is contained in:
@@ -207,7 +207,7 @@ try {
|
|||||||
{ id: 'oath-bond', title: 'Oath Bond', unitIds: ['liu-bei', 'guan-yu'], level: '2', exp: '14', battleExp: '5' },
|
{ id: 'oath-bond', title: 'Oath Bond', unitIds: ['liu-bei', 'guan-yu'], level: '2', exp: '14', battleExp: '5' },
|
||||||
9
|
9
|
||||||
],
|
],
|
||||||
completedCampDialogues: ['dialogue-a', 17, 'dialogue-a', ''],
|
completedCampDialogues: ['dialogue-a', 17, 'dialogue-a', '', 'x'.repeat(97)],
|
||||||
completedCampVisits: 'visit-a',
|
completedCampVisits: 'visit-a',
|
||||||
inventory: { bean: '3', ' bean ': '4', ['\uCF69']: '200', [' \uCF69 ']: '20', wine: -2, empty: 0 },
|
inventory: { bean: '3', ' bean ': '4', ['\uCF69']: '200', [' \uCF69 ']: '20', wine: -2, empty: 0 },
|
||||||
selectedSortieUnitIds: { corrupted: true },
|
selectedSortieUnitIds: { corrupted: true },
|
||||||
@@ -256,6 +256,27 @@ try {
|
|||||||
`Expected malformed inventory and sortie assignments to normalize: ${JSON.stringify(malformed)}`
|
`Expected malformed inventory and sortie assignments to normalize: ${JSON.stringify(malformed)}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
storage.clear();
|
||||||
|
storage.set(
|
||||||
|
campaignStorageKey,
|
||||||
|
JSON.stringify({
|
||||||
|
version: 1,
|
||||||
|
updatedAt: '2026-07-03T12:30:00.000Z',
|
||||||
|
step: 'third-camp',
|
||||||
|
activeSaveSlot: 1,
|
||||||
|
completedCampDialogues: Array.from({ length: 140 }, (_, index) => `dialogue-${index}`),
|
||||||
|
completedCampVisits: ['visit-a', 'x'.repeat(97), 'visit-a']
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const cappedStringLists = loadCampaignState();
|
||||||
|
assert(
|
||||||
|
cappedStringLists.completedCampDialogues.length === 128 &&
|
||||||
|
cappedStringLists.completedCampDialogues[0] === 'dialogue-0' &&
|
||||||
|
cappedStringLists.completedCampDialogues[127] === 'dialogue-127' &&
|
||||||
|
cappedStringLists.completedCampVisits.length === 1,
|
||||||
|
`Expected campaign string lists to filter long entries and cap excessive saves: ${JSON.stringify(cappedStringLists)}`
|
||||||
|
);
|
||||||
|
|
||||||
storage.clear();
|
storage.clear();
|
||||||
storage.set(
|
storage.set(
|
||||||
campaignStorageKey,
|
campaignStorageKey,
|
||||||
@@ -459,9 +480,9 @@ try {
|
|||||||
{ id: 'broken-bond', title: 'Broken Bond', unitIds: ['liu-bei'] }
|
{ id: 'broken-bond', title: 'Broken Bond', unitIds: ['liu-bei'] }
|
||||||
],
|
],
|
||||||
mvp: { unitId: 'liu-bei', name: 'Liu Bei', damageDealt: '88', defeats: '2' },
|
mvp: { unitId: 'liu-bei', name: 'Liu Bei', damageDealt: '88', defeats: '2' },
|
||||||
itemRewards: ['Bean', 'Bean', 10],
|
itemRewards: ['Bean', 'Bean', 10, 'x'.repeat(97)],
|
||||||
campaignRewards: {
|
campaignRewards: {
|
||||||
supplies: [' Bean ', 'Bean', 20],
|
supplies: [' Bean ', 'Bean', 20, 'x'.repeat(97)],
|
||||||
equipment: [' Iron Sword ', 'Iron Sword'],
|
equipment: [' Iron Sword ', 'Iron Sword'],
|
||||||
reputation: ['Village Thanks', ' Village Thanks '],
|
reputation: ['Village Thanks', ' Village Thanks '],
|
||||||
recruits: [{ unitId: ' guan-yu ', name: ' Guan Yu ' }, { unitId: '', name: 'Broken' }],
|
recruits: [{ unitId: ' guan-yu ', name: ' Guan Yu ' }, { unitId: '', name: 'Broken' }],
|
||||||
@@ -555,7 +576,8 @@ try {
|
|||||||
equipment: ['Iron Sword'],
|
equipment: ['Iron Sword'],
|
||||||
reputation: 'Fame',
|
reputation: 'Fame',
|
||||||
recruits: [{ unitId: 'test-recruit', name: 'Test Recruit' }, { broken: true }],
|
recruits: [{ unitId: 'test-recruit', name: 'Test Recruit' }, { broken: true }],
|
||||||
unlocks: { corrupted: true }
|
unlocks: { corrupted: true },
|
||||||
|
note: 'x'.repeat(181)
|
||||||
},
|
},
|
||||||
objectives: [
|
objectives: [
|
||||||
{
|
{
|
||||||
@@ -633,7 +655,8 @@ try {
|
|||||||
assert(
|
assert(
|
||||||
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.itemRewards.length === 1 &&
|
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.itemRewards.length === 1 &&
|
||||||
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.campaignRewards?.equipment[0] === 'Iron Sword' &&
|
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.campaignRewards?.equipment[0] === 'Iron Sword' &&
|
||||||
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.campaignRewards?.recruits.length === 1,
|
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.campaignRewards?.recruits.length === 1 &&
|
||||||
|
malformedHistory.battleHistory['first-battle-zhuo-commandery']?.campaignRewards?.note === undefined,
|
||||||
`Expected nested battle history rewards to normalize: ${JSON.stringify(malformedHistory)}`
|
`Expected nested battle history rewards to normalize: ${JSON.stringify(malformedHistory)}`
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|||||||
@@ -266,6 +266,10 @@ const campaignInventoryCaps: Record<string, number> = {
|
|||||||
['\uD0C1\uC8FC']: 80
|
['\uD0C1\uC8FC']: 80
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const maxCampaignStringListEntries = 128;
|
||||||
|
const maxCampaignStringListLength = 96;
|
||||||
|
const maxCampaignRewardNoteLength = 180;
|
||||||
|
|
||||||
export const campaignReserveTrainingFocusDefinitions: CampaignReserveTrainingFocusDefinition[] = [
|
export const campaignReserveTrainingFocusDefinitions: CampaignReserveTrainingFocusDefinition[] = [
|
||||||
{
|
{
|
||||||
id: 'balanced',
|
id: 'balanced',
|
||||||
@@ -881,9 +885,9 @@ function uniqueStrings(value: unknown): string[] {
|
|||||||
arrayOrEmpty<unknown>(value)
|
arrayOrEmpty<unknown>(value)
|
||||||
.filter((entry): entry is string => typeof entry === 'string')
|
.filter((entry): entry is string => typeof entry === 'string')
|
||||||
.map((entry) => entry.trim())
|
.map((entry) => entry.trim())
|
||||||
.filter((entry) => entry.length > 0)
|
.filter((entry) => entry.length > 0 && entry.length <= maxCampaignStringListLength)
|
||||||
)
|
)
|
||||||
];
|
].slice(0, maxCampaignStringListEntries);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizedRosterUnitIds(roster: UnitData[]) {
|
function normalizedRosterUnitIds(roster: UnitData[]) {
|
||||||
@@ -1532,6 +1536,7 @@ function cloneCampaignRewardSnapshot(rewards?: CampaignRewardSnapshot): Campaign
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rewardRecord = recordOrEmpty(rewards);
|
const rewardRecord = recordOrEmpty(rewards);
|
||||||
|
const note = typeof rewardRecord.note === 'string' ? rewardRecord.note.trim() : '';
|
||||||
return {
|
return {
|
||||||
supplies: uniqueStrings(rewardRecord.supplies),
|
supplies: uniqueStrings(rewardRecord.supplies),
|
||||||
equipment: uniqueStrings(rewardRecord.equipment),
|
equipment: uniqueStrings(rewardRecord.equipment),
|
||||||
@@ -1550,7 +1555,7 @@ function cloneCampaignRewardSnapshot(rewards?: CampaignRewardSnapshot): Campaign
|
|||||||
title: typeof unlock.title === 'string' ? unlock.title.trim() : ''
|
title: typeof unlock.title === 'string' ? unlock.title.trim() : ''
|
||||||
}))
|
}))
|
||||||
.filter((unlock) => unlock.battleId && unlock.title),
|
.filter((unlock) => unlock.battleId && unlock.title),
|
||||||
note: typeof rewardRecord.note === 'string' && rewardRecord.note.trim().length > 0 ? rewardRecord.note.trim() : undefined
|
note: note.length > 0 && note.length <= maxCampaignRewardNoteLength ? note : undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user