Validate camp reward data
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
"measure:performance": "node scripts/measure-performance.mjs",
|
"measure:performance": "node scripts/measure-performance.mjs",
|
||||||
"verify:battle-data": "node scripts/verify-battle-scenario-data.mjs",
|
"verify:battle-data": "node scripts/verify-battle-scenario-data.mjs",
|
||||||
"verify:campaign-data": "node scripts/verify-campaign-flow-data.mjs",
|
"verify:campaign-data": "node scripts/verify-campaign-flow-data.mjs",
|
||||||
|
"verify:camp-rewards": "node scripts/verify-camp-reward-data.mjs",
|
||||||
"verify:story-assets": "node scripts/verify-story-asset-data.mjs",
|
"verify:story-assets": "node scripts/verify-story-asset-data.mjs",
|
||||||
"verify:story-images": "node scripts/verify-story-image-asset-data.mjs",
|
"verify:story-images": "node scripts/verify-story-image-asset-data.mjs",
|
||||||
"verify:visual-assets": "node scripts/verify-visual-asset-data.mjs",
|
"verify:visual-assets": "node scripts/verify-visual-asset-data.mjs",
|
||||||
|
|||||||
74
scripts/verify-camp-reward-data.mjs
Normal file
74
scripts/verify-camp-reward-data.mjs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
|
||||||
|
const sourcePath = 'src/game/scenes/CampScene.ts';
|
||||||
|
const source = readFileSync(sourcePath, 'utf8');
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
const itemRewardArrays = collectItemRewardArrays(source);
|
||||||
|
itemRewardArrays.forEach(({ body, index, offset }) => validateItemRewards(body, index, offset));
|
||||||
|
validateNumericProperties('gold', { min: 1, max: 20000 });
|
||||||
|
validateNumericProperties('bondExp', { min: 0, max: 200 });
|
||||||
|
validateNumericProperties('rewardExp', { min: 1, max: 200 });
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new Error(`Camp reward data verification failed:\n${errors.map((error) => `- ${error}`).join('\n')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Verified ${itemRewardArrays.length} camp item reward lists and camp reward numeric fields.`);
|
||||||
|
|
||||||
|
function collectItemRewardArrays(text) {
|
||||||
|
return [...text.matchAll(/itemRewards:\s*\[([\s\S]*?)\]/g)].map((match, index) => ({
|
||||||
|
body: match[1],
|
||||||
|
index,
|
||||||
|
offset: match.index ?? 0
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateItemRewards(body, index, offset) {
|
||||||
|
const entries = [...body.matchAll(/'((?:\\'|[^'])*)'/g)].map((match) => match[1].replace(/\\'/g, "'"));
|
||||||
|
if (entries.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const labels = new Set();
|
||||||
|
entries.forEach((reward, rewardIndex) => {
|
||||||
|
const parsed = parseRewardLabel(reward);
|
||||||
|
if (!parsed.label) {
|
||||||
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}][${rewardIndex}] has an empty parsed label`);
|
||||||
|
}
|
||||||
|
if (!Number.isInteger(parsed.amount) || parsed.amount < 1) {
|
||||||
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}][${rewardIndex}] has invalid amount ${parsed.amount}`);
|
||||||
|
}
|
||||||
|
if (labels.has(parsed.label)) {
|
||||||
|
errors.push(`${sourcePath}:${lineNumber(offset)} itemRewards[${index}] has duplicate label "${parsed.label}"`);
|
||||||
|
}
|
||||||
|
labels.add(parsed.label);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateNumericProperties(propertyName, { min, max }) {
|
||||||
|
const pattern = new RegExp(`${propertyName}:\\s*(-?\\d+)`, 'g');
|
||||||
|
for (const match of source.matchAll(pattern)) {
|
||||||
|
const value = Number(match[1]);
|
||||||
|
if (!Number.isInteger(value) || value < min || value > max) {
|
||||||
|
errors.push(`${sourcePath}:${lineNumber(match.index ?? 0)} ${propertyName} has out-of-range value ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseRewardLabel(reward) {
|
||||||
|
const normalized = String(reward).replace(/\s+/g, ' ').trim();
|
||||||
|
const match = normalized.match(/^(.*?)(?:\s*[+xX]?\s*(\d+))$/);
|
||||||
|
if (!match) {
|
||||||
|
return { label: normalized, amount: 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: match[1].trim() || normalized,
|
||||||
|
amount: Number(match[2] ?? 1)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function lineNumber(offset) {
|
||||||
|
return source.slice(0, offset).split(/\r?\n/).length;
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ let browser;
|
|||||||
try {
|
try {
|
||||||
runCommand('node', ['scripts/verify-campaign-flow-data.mjs']);
|
runCommand('node', ['scripts/verify-campaign-flow-data.mjs']);
|
||||||
runCommand('node', ['scripts/verify-battle-scenario-data.mjs']);
|
runCommand('node', ['scripts/verify-battle-scenario-data.mjs']);
|
||||||
|
runCommand('node', ['scripts/verify-camp-reward-data.mjs']);
|
||||||
runCommand('node', ['scripts/verify-story-asset-data.mjs']);
|
runCommand('node', ['scripts/verify-story-asset-data.mjs']);
|
||||||
runCommand('node', ['scripts/verify-story-image-asset-data.mjs']);
|
runCommand('node', ['scripts/verify-story-image-asset-data.mjs']);
|
||||||
runCommand('node', ['scripts/verify-visual-asset-data.mjs']);
|
runCommand('node', ['scripts/verify-visual-asset-data.mjs']);
|
||||||
|
|||||||
Reference in New Issue
Block a user