Validate battle save event keys

This commit is contained in:
2026-07-05 11:50:56 +09:00
parent 288fb839d1
commit c02a29e9cc
3 changed files with 43 additions and 13 deletions

View File

@@ -77,11 +77,13 @@ type BattleSaveValidationOptions = {
validItemIds?: ReadonlySet<string>;
validEquipmentItemIds?: ReadonlySet<string>;
validEquipmentSlotItems?: Partial<Record<EquipmentSlot, ReadonlySet<string>>>;
validTriggeredBattleEventIds?: ReadonlySet<string>;
};
const unitDirections = new Set<UnitDirection>(['south', 'east', 'north', 'west']);
const maxBattleLogEntries = 10;
const maxBattleLogEntryLength = 96;
const maxTriggeredBattleEventLength = 96;
const defaultBattleSaveArrayLimit = 128;
const maxStatusKindsPerUnit = 2;
@@ -140,7 +142,7 @@ export function isValidBattleSaveState(state: unknown, options: BattleSaveValida
!isOptionalStatusArray(state.battleStatuses, options) ||
!isOptionalStatsRecord(state.battleStats, options) ||
!isOptionalEnemyUsableUseKeyArray(state.enemyUsableUseKeys, state.battleId, options) ||
!isOptionalStringArray(state.triggeredBattleEvents)
!isOptionalTriggeredBattleEventArray(state.triggeredBattleEvents, options)
) {
return false;
}
@@ -176,10 +178,6 @@ function isBattleStatusKind(value: unknown): value is BattleSaveStatusKind {
return value === 'burn' || value === 'confusion';
}
function isStringArray(value: unknown) {
return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
}
function isUnitIdArray(value: unknown, options: BattleSaveValidationOptions) {
return (
Array.isArray(value) &&
@@ -189,10 +187,6 @@ function isUnitIdArray(value: unknown, options: BattleSaveValidationOptions) {
);
}
function isOptionalStringArray(value: unknown) {
return value === undefined || isStringArray(value);
}
function isBattleLog(value: unknown) {
return (
Array.isArray(value) &&
@@ -409,6 +403,22 @@ function isOptionalEnemyUsableUseKeyArray(value: unknown, battleId: string, opti
);
}
function isOptionalTriggeredBattleEventArray(value: unknown, options: BattleSaveValidationOptions) {
return (
value === undefined ||
(Array.isArray(value) &&
value.length <= triggeredBattleEventLimit(options) &&
hasUniqueStrings(value) &&
value.every(
(eventId) =>
typeof eventId === 'string' &&
eventId.length > 0 &&
eventId.length <= maxTriggeredBattleEventLength &&
(!options.validTriggeredBattleEventIds || options.validTriggeredBattleEventIds.has(eventId))
))
);
}
function isEnemyUsableUseKey(value: unknown, battleId: string, options: BattleSaveValidationOptions) {
if (typeof value !== 'string') {
return false;
@@ -447,6 +457,10 @@ function enemyUsableUseKeyLimit(options: BattleSaveValidationOptions) {
return defaultBattleSaveArrayLimit;
}
function triggeredBattleEventLimit(options: BattleSaveValidationOptions) {
return options.validTriggeredBattleEventIds?.size ?? defaultBattleSaveArrayLimit;
}
function hasUniqueStrings(values: unknown[]) {
return new Set(values.filter((entry) => typeof entry === 'string')).size === values.length;
}