From e07340b531231360b4cef80126d7496259242894 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sat, 21 Sep 2024 15:34:33 +0000 Subject: [PATCH] Added validation of game settings Should detect invalid config in all sources of settings - vcmi config, mods, random map templates --- config/schemas/gameSettings.json | 151 +++++++++++++++++++++++++++++++ config/schemas/mod.json | 7 +- config/schemas/template.json | 4 +- lib/GameSettings.cpp | 2 + 4 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 config/schemas/gameSettings.json diff --git a/config/schemas/gameSettings.json b/config/schemas/gameSettings.json new file mode 100644 index 000000000..64e75dac2 --- /dev/null +++ b/config/schemas/gameSettings.json @@ -0,0 +1,151 @@ +{ + "type" : "object", + "$schema" : "http://json-schema.org/draft-04/schema", + "title" : "VCMI game settings format", + "description" : "Format used to define game settings in VCMI", + "additionalProperties" : false, + "properties" : { + "textData" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "heroClass" : { "type" : "number" }, + "artifact" : { "type" : "number" }, + "creature" : { "type" : "number" }, + "faction" : { "type" : "number" }, + "hero" : { "type" : "number" }, + "spell" : { "type" : "number" }, + "object" : { "type" : "number" }, + "terrain" : { "type" : "number" }, + "river" : { "type" : "number" }, + "road" : { "type" : "number" } + } + }, + "mapFormat" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "restorationOfErathia" : { "type" : "object" }, + "armageddonsBlade" : { "type" : "object" }, + "shadowOfDeath" : { "type" : "object" }, + "chronicles" : { "type" : "object" }, + "jsonVCMI" : { "type" : "object" }, + "hornOfTheAbyss" : { "type" : "object" }, + "inTheWakeOfGods" : { "type" : "object" } + } + }, + "heroes" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "perPlayerOnMapCap" : { "type" : "number" }, + "perPlayerTotalCap" : { "type" : "number" }, + "retreatOnWinWithoutTroops" : { "type" : "boolean" }, + "startingStackChances" : { "type" : "array" }, + "backpackSize" : { "type" : "number" }, + "tavernInvite" : { "type" : "boolean" }, + "minimalPrimarySkills" : { "type" : "array" } + } + }, + "towns" : { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "buildingsPerTurnCap" : { "type" : "number" }, + "startingDwellingChances" : { "type" : "array" } + } + }, + "combat": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "goodMoraleDice" : { "type" : "array" }, + "badMoraleDice" : { "type" : "array" }, + "goodLuckDice" : { "type" : "array" }, + "badLuckDice" : { "type" : "array" }, + "backpackSize" : { "type" : "number" }, + "attackPointDamageFactor" : { "type" : "number" }, + "attackPointDamageFactorCap" : { "type" : "number" }, + "defensePointDamageFactor" : { "type" : "number" }, + "defensePointDamageFactorCap" : { "type" : "number" }, + "oneHexTriggersObstacles" : { "type" : "boolean" }, + "layouts" : { "type" : "object" } + } + }, + "creatures": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "weeklyGrowthPercent" : { "type" : "number" }, + "weeklyGrowthCap" : { "type" : "number" }, + "dailyStackExperience" : { "type" : "number" }, + "allowRandomSpecialWeeks" : { "type" : "boolean" }, + "allowAllForDoubleMonth" : { "type" : "boolean" } + } + }, + "dwellings": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "accumulateWhenNeutral" : { "type" : "boolean" }, + "accumulateWhenOwned" : { "type" : "boolean" }, + "mergeOnRecruit" : { "type" : "boolean" } + } + }, + "markets": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "blackMarketRestockPeriod" : { "type" : "number" } + } + }, + "banks": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "showGuardsComposition" : { "type" : "boolean" } + } + }, + "modules": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "stackExperience" : { "type" : "boolean" }, + "stackArtifact" : { "type" : "boolean" }, + "commanders" : { "type" : "boolean" } + } + }, + "pathfinder": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "ignoreGuards" : { "type" : "boolean" }, + "useBoat" : { "type" : "boolean" }, + "useMonolithTwoWay" : { "type" : "boolean" }, + "useMonolithOneWayUnique" : { "type" : "boolean" }, + "useMonolithOneWayRandom" : { "type" : "boolean" }, + "useWhirlpool" : { "type" : "boolean" }, + "originalFlyRules" : { "type" : "boolean" } + } + }, + "spells": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "dimensionDoorOnlyToUncoveredTiles" : { "type" : "boolean" }, + "dimensionDoorExposesTerrainType" : { "type" : "boolean" }, + "dimensionDoorFailureSpendsPoints" : { "type" : "boolean" }, + "dimensionDoorTriggersGuards" : { "type" : "boolean" }, + "dimensionDoorTournamentRulesLimit" : { "type" : "boolean" } + } + }, + "bonuses": { + "type" : "object", + "additionalProperties" : false, + "properties" : { + "global" : { "type" : "object" }, + "perHero" : { "type" : "object" } + } + }, + } +} diff --git a/config/schemas/mod.json b/config/schemas/mod.json index e9ca88dd2..5c09ef74c 100644 --- a/config/schemas/mod.json +++ b/config/schemas/mod.json @@ -124,12 +124,7 @@ "settings" : { "type" : "object", "description" : "List of changed game settings by mod", - "additionalProperties" : { - "type" : "object", - "properties" : { - "type" : "object" - } - } + "$ref" : "gameSettings.json" }, "filesystem" : { "type" : "object", diff --git a/config/schemas/template.json b/config/schemas/template.json index aa43e4fbd..fc185815c 100644 --- a/config/schemas/template.json +++ b/config/schemas/template.json @@ -134,9 +134,7 @@ "settings" : { "description" : "List of changed game settings by template", "type" : "object", - "additionalProperties" : { - "type" : "object" - } + "$ref" : "gameSettings.json" }, "name" : { "description" : "Optional name - useful to have several template variations with same name", diff --git a/lib/GameSettings.cpp b/lib/GameSettings.cpp index 56c60055e..8248159ae 100644 --- a/lib/GameSettings.cpp +++ b/lib/GameSettings.cpp @@ -104,6 +104,8 @@ const std::vector GameSettings::settingProperties = void GameSettings::loadBase(const JsonNode & input) { + JsonUtils::validate(input, "vcmi:gameSettings", input.getModScope()); + for(const auto & option : settingProperties) { const JsonNode & optionValue = input[option.group][option.key];