mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-22 03:39:45 +02:00
Added an option to configure validation level in launcher
This commit is contained in:
parent
3e3f842fbe
commit
66fdad145c
@ -3,7 +3,7 @@
|
|||||||
{
|
{
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"$schema" : "http://json-schema.org/draft-04/schema",
|
"$schema" : "http://json-schema.org/draft-04/schema",
|
||||||
"required" : [ "general", "video", "adventure", "battle", "input", "server", "logging", "launcher", "lobby", "gameTweaks" ],
|
"required" : [ "general", "video", "adventure", "battle", "input", "server", "logging", "launcher", "lobby", "gameTweaks", "mods" ],
|
||||||
"definitions" : {
|
"definitions" : {
|
||||||
"logLevelEnum" : {
|
"logLevelEnum" : {
|
||||||
"type" : "string",
|
"type" : "string",
|
||||||
@ -149,6 +149,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"mods" : {
|
||||||
|
"type" : "object",
|
||||||
|
"additionalProperties" : false,
|
||||||
|
"default" : {},
|
||||||
|
"required" : [
|
||||||
|
"validation"
|
||||||
|
],
|
||||||
|
"properties" : {
|
||||||
|
"validation" : {
|
||||||
|
"type" : "string",
|
||||||
|
"enum" : [ "off", "basic", "full" ],
|
||||||
|
"default" : "basic"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"video" : {
|
"video" : {
|
||||||
"type" : "object",
|
"type" : "object",
|
||||||
"additionalProperties" : false,
|
"additionalProperties" : false,
|
||||||
|
@ -182,6 +182,13 @@ void CSettingsView::loadSettings()
|
|||||||
else
|
else
|
||||||
ui->buttonFontScalable->setChecked(true);
|
ui->buttonFontScalable->setChecked(true);
|
||||||
|
|
||||||
|
if (settings["mods"]["validation"].String() == "off")
|
||||||
|
ui->buttonValidationOff->setChecked(true);
|
||||||
|
else if (settings["mods"]["validation"].String() == "basic")
|
||||||
|
ui->buttonValidationBasic->setChecked(true);
|
||||||
|
else
|
||||||
|
ui->buttonValidationFull->setChecked(true);
|
||||||
|
|
||||||
loadToggleButtonSettings();
|
loadToggleButtonSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -791,3 +798,21 @@ void CSettingsView::on_buttonFontOriginal_clicked(bool checked)
|
|||||||
Settings node = settings.write["video"]["fontsType"];
|
Settings node = settings.write["video"]["fontsType"];
|
||||||
node->String() = "original";
|
node->String() = "original";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSettingsView::on_buttonValidationOff_clicked(bool checked)
|
||||||
|
{
|
||||||
|
Settings node = settings.write["mods"]["validation"];
|
||||||
|
node->String() = "off";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSettingsView::on_buttonValidationBasic_clicked(bool checked)
|
||||||
|
{
|
||||||
|
Settings node = settings.write["mods"]["validation"];
|
||||||
|
node->String() = "basic";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSettingsView::on_buttonValidationFull_clicked(bool checked)
|
||||||
|
{
|
||||||
|
Settings node = settings.write["mods"]["validation"];
|
||||||
|
node->String() = "full";
|
||||||
|
}
|
||||||
|
@ -83,19 +83,20 @@ private slots:
|
|||||||
void on_sliderToleranceDistanceController_valueChanged(int value);
|
void on_sliderToleranceDistanceController_valueChanged(int value);
|
||||||
void on_lineEditGameLobbyHost_textChanged(const QString &arg1);
|
void on_lineEditGameLobbyHost_textChanged(const QString &arg1);
|
||||||
void on_spinBoxNetworkPortLobby_valueChanged(int arg1);
|
void on_spinBoxNetworkPortLobby_valueChanged(int arg1);
|
||||||
|
|
||||||
void on_sliderControllerSticksAcceleration_valueChanged(int value);
|
void on_sliderControllerSticksAcceleration_valueChanged(int value);
|
||||||
|
|
||||||
void on_sliderControllerSticksSensitivity_valueChanged(int value);
|
void on_sliderControllerSticksSensitivity_valueChanged(int value);
|
||||||
|
|
||||||
//void on_buttonTtfFont_toggled(bool value);
|
|
||||||
|
|
||||||
void on_sliderScalingFont_valueChanged(int value);
|
void on_sliderScalingFont_valueChanged(int value);
|
||||||
|
|
||||||
void on_buttonFontAuto_clicked(bool checked);
|
void on_buttonFontAuto_clicked(bool checked);
|
||||||
void on_buttonFontScalable_clicked(bool checked);
|
void on_buttonFontScalable_clicked(bool checked);
|
||||||
void on_buttonFontOriginal_clicked(bool checked);
|
void on_buttonFontOriginal_clicked(bool checked);
|
||||||
|
|
||||||
|
|
||||||
|
void on_buttonValidationOff_clicked(bool checked);
|
||||||
|
|
||||||
|
void on_buttonValidationBasic_clicked(bool checked);
|
||||||
|
|
||||||
|
void on_buttonValidationFull_clicked(bool checked);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::CSettingsView * ui;
|
Ui::CSettingsView * ui;
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@
|
|||||||
#include "../mapObjects/CRewardableObject.h"
|
#include "../mapObjects/CRewardableObject.h"
|
||||||
#include "../texts/CGeneralTextHandler.h"
|
#include "../texts/CGeneralTextHandler.h"
|
||||||
#include "../IGameCallback.h"
|
#include "../IGameCallback.h"
|
||||||
|
#include "../CConfigHandler.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -25,7 +26,8 @@ void CRewardableConstructor::initTypeData(const JsonNode & config)
|
|||||||
if (!config["name"].isNull())
|
if (!config["name"].isNull())
|
||||||
VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String());
|
VLC->generaltexth->registerString( config.getModScope(), getNameTextID(), config["name"].String());
|
||||||
|
|
||||||
JsonUtils::validate(config, "vcmi:rewardable", getJsonKey());
|
if (settings["mods"]["validation"].String() != "off")
|
||||||
|
JsonUtils::validate(config, "vcmi:rewardable", getJsonKey());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "ModIncompatibility.h"
|
#include "ModIncompatibility.h"
|
||||||
|
|
||||||
#include "../CCreatureHandler.h"
|
#include "../CCreatureHandler.h"
|
||||||
|
#include "../CConfigHandler.h"
|
||||||
#include "../CStopWatch.h"
|
#include "../CStopWatch.h"
|
||||||
#include "../GameSettings.h"
|
#include "../GameSettings.h"
|
||||||
#include "../ScriptHandler.h"
|
#include "../ScriptHandler.h"
|
||||||
@ -339,25 +340,28 @@ void CModHandler::loadModFilesystems()
|
|||||||
for(std::string & modName : activeMods)
|
for(std::string & modName : activeMods)
|
||||||
CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
|
CResourceHandler::addFilesystem("data", modName, modFilesystems[modName]);
|
||||||
|
|
||||||
for(std::string & leftModName : activeMods)
|
if (settings["mods"]["validation"].String() == "full")
|
||||||
{
|
{
|
||||||
for(std::string & rightModName : activeMods)
|
for(std::string & leftModName : activeMods)
|
||||||
{
|
{
|
||||||
if (leftModName == rightModName)
|
for(std::string & rightModName : activeMods)
|
||||||
continue;
|
|
||||||
|
|
||||||
if (getModDependencies(leftModName).count(rightModName) || getModDependencies(rightModName).count(leftModName))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto & filter = [](const ResourcePath &path){return path.getType() != EResType::DIRECTORY;};
|
|
||||||
|
|
||||||
std::unordered_set<ResourcePath> leftResources = modFilesystems[leftModName]->getFilteredFiles(filter);
|
|
||||||
std::unordered_set<ResourcePath> rightResources = modFilesystems[rightModName]->getFilteredFiles(filter);
|
|
||||||
|
|
||||||
for (auto const & leftFile : leftResources)
|
|
||||||
{
|
{
|
||||||
if (rightResources.count(leftFile))
|
if (leftModName == rightModName)
|
||||||
logMod->warn("Potential confict detected between '%s' and '%s': both mods add file '%s'", leftModName, rightModName, leftFile.getOriginalName());
|
continue;
|
||||||
|
|
||||||
|
if (getModDependencies(leftModName).count(rightModName) || getModDependencies(rightModName).count(leftModName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const auto & filter = [](const ResourcePath &path){return path.getType() != EResType::DIRECTORY;};
|
||||||
|
|
||||||
|
std::unordered_set<ResourcePath> leftResources = modFilesystems[leftModName]->getFilteredFiles(filter);
|
||||||
|
std::unordered_set<ResourcePath> rightResources = modFilesystems[rightModName]->getFilteredFiles(filter);
|
||||||
|
|
||||||
|
for (auto const & leftFile : leftResources)
|
||||||
|
{
|
||||||
|
if (rightResources.count(leftFile))
|
||||||
|
logMod->warn("Potential confict detected between '%s' and '%s': both mods add file '%s'", leftModName, rightModName, leftFile.getOriginalName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,8 +512,8 @@ void CModHandler::load()
|
|||||||
|
|
||||||
content->loadCustom();
|
content->loadCustom();
|
||||||
|
|
||||||
// for(const TModID & modName : activeMods)
|
for(const TModID & modName : activeMods)
|
||||||
// loadTranslation(modName);
|
loadTranslation(modName);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
for(const TModID & modName : activeMods)
|
for(const TModID & modName : activeMods)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
#include "../BattleFieldHandler.h"
|
#include "../BattleFieldHandler.h"
|
||||||
#include "../CArtHandler.h"
|
#include "../CArtHandler.h"
|
||||||
#include "../CCreatureHandler.h"
|
#include "../CCreatureHandler.h"
|
||||||
|
#include "../CConfigHandler.h"
|
||||||
#include "../entities/faction/CTownHandler.h"
|
#include "../entities/faction/CTownHandler.h"
|
||||||
#include "../texts/CGeneralTextHandler.h"
|
#include "../texts/CGeneralTextHandler.h"
|
||||||
#include "../CHeroHandler.h"
|
#include "../CHeroHandler.h"
|
||||||
@ -79,7 +80,7 @@ bool ContentTypeHandler::preloadModData(const std::string & modName, const std::
|
|||||||
logMod->trace("Patching object %s (%s) from %s", objectName, remoteName, modName);
|
logMod->trace("Patching object %s (%s) from %s", objectName, remoteName, modName);
|
||||||
JsonNode & remoteConf = modData[remoteName].patches[objectName];
|
JsonNode & remoteConf = modData[remoteName].patches[objectName];
|
||||||
|
|
||||||
if (!remoteConf.isNull())
|
if (!remoteConf.isNull() && settings["mods"]["validation"].String() != "off")
|
||||||
JsonUtils::detectConflicts(conflictList, remoteConf, entry.second, objectName);
|
JsonUtils::detectConflicts(conflictList, remoteConf, entry.second, objectName);
|
||||||
|
|
||||||
JsonUtils::merge(remoteConf, entry.second);
|
JsonUtils::merge(remoteConf, entry.second);
|
||||||
@ -162,67 +163,70 @@ void ContentTypeHandler::loadCustom()
|
|||||||
|
|
||||||
void ContentTypeHandler::afterLoadFinalization()
|
void ContentTypeHandler::afterLoadFinalization()
|
||||||
{
|
{
|
||||||
for (auto const & data : modData)
|
if (settings["mods"]["validation"].String() != "off")
|
||||||
{
|
{
|
||||||
if (data.second.modData.isNull())
|
for (auto const & data : modData)
|
||||||
{
|
{
|
||||||
for (auto node : data.second.patches.Struct())
|
if (data.second.modData.isNull())
|
||||||
logMod->warn("Mod '%s' have added patch for object '%s' from mod '%s', but this mod was not loaded or has no new objects.", node.second.getModScope(), node.first, data.first);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto & otherMod : modData)
|
|
||||||
{
|
|
||||||
if (otherMod.first == data.first)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (otherMod.second.modData.isNull())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for(auto & otherObject : otherMod.second.modData.Struct())
|
|
||||||
{
|
{
|
||||||
if (data.second.modData.Struct().count(otherObject.first))
|
for (auto node : data.second.patches.Struct())
|
||||||
|
logMod->warn("Mod '%s' have added patch for object '%s' from mod '%s', but this mod was not loaded or has no new objects.", node.second.getModScope(), node.first, data.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto & otherMod : modData)
|
||||||
|
{
|
||||||
|
if (otherMod.first == data.first)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (otherMod.second.modData.isNull())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for(auto & otherObject : otherMod.second.modData.Struct())
|
||||||
{
|
{
|
||||||
logMod->warn("Mod '%s' have added object with name '%s' that is also available in mod '%s'", data.first, otherObject.first, otherMod.first);
|
if (data.second.modData.Struct().count(otherObject.first))
|
||||||
logMod->warn("Two objects with same name were loaded. Please use form '%s:%s' if mod '%s' needs to modify this object instead", otherMod.first, otherObject.first, data.first);
|
{
|
||||||
|
logMod->warn("Mod '%s' have added object with name '%s' that is also available in mod '%s'", data.first, otherObject.first, otherMod.first);
|
||||||
|
logMod->warn("Two objects with same name were loaded. Please use form '%s:%s' if mod '%s' needs to modify this object instead", otherMod.first, otherObject.first, data.first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& [conflictPath, conflictModData] : conflictList.Struct())
|
for (const auto& [conflictPath, conflictModData] : conflictList.Struct())
|
||||||
{
|
|
||||||
std::set<std::string> conflictingMods;
|
|
||||||
std::set<std::string> resolvedConflicts;
|
|
||||||
|
|
||||||
for (auto const & conflictModData : conflictModData.Struct())
|
|
||||||
conflictingMods.insert(conflictModData.first);
|
|
||||||
|
|
||||||
for (auto const & modID : conflictingMods)
|
|
||||||
resolvedConflicts.merge(VLC->modh->getModDependencies(modID));
|
|
||||||
|
|
||||||
vstd::erase_if(conflictingMods, [&resolvedConflicts](const std::string & entry){ return resolvedConflicts.count(entry);});
|
|
||||||
|
|
||||||
if (conflictingMods.size() < 2)
|
|
||||||
continue; // all conflicts were resolved - either via compatibility patch (mod that depends on 2 conflicting mods) or simple mod that depends on another one
|
|
||||||
|
|
||||||
bool allEqual = true;
|
|
||||||
|
|
||||||
for (auto const & modID : conflictingMods)
|
|
||||||
{
|
{
|
||||||
if (conflictModData[modID] != conflictModData[*conflictingMods.begin()])
|
std::set<std::string> conflictingMods;
|
||||||
|
std::set<std::string> resolvedConflicts;
|
||||||
|
|
||||||
|
for (auto const & conflictModData : conflictModData.Struct())
|
||||||
|
conflictingMods.insert(conflictModData.first);
|
||||||
|
|
||||||
|
for (auto const & modID : conflictingMods)
|
||||||
|
resolvedConflicts.merge(VLC->modh->getModDependencies(modID));
|
||||||
|
|
||||||
|
vstd::erase_if(conflictingMods, [&resolvedConflicts](const std::string & entry){ return resolvedConflicts.count(entry);});
|
||||||
|
|
||||||
|
if (conflictingMods.size() < 2)
|
||||||
|
continue; // all conflicts were resolved - either via compatibility patch (mod that depends on 2 conflicting mods) or simple mod that depends on another one
|
||||||
|
|
||||||
|
bool allEqual = true;
|
||||||
|
|
||||||
|
for (auto const & modID : conflictingMods)
|
||||||
{
|
{
|
||||||
allEqual = false;
|
if (conflictModData[modID] != conflictModData[*conflictingMods.begin()])
|
||||||
break;
|
{
|
||||||
|
allEqual = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allEqual)
|
||||||
|
continue; // conflict still present, but all mods use the same value for conflicting entry - permit it
|
||||||
|
|
||||||
|
logMod->warn("Potential confict in '%s'", conflictPath);
|
||||||
|
|
||||||
|
for (auto const & modID : conflictingMods)
|
||||||
|
logMod->warn("Mod '%s' - value set to %s", modID, conflictModData[modID].toCompactString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allEqual)
|
|
||||||
continue; // conflict still present, but all mods use the same value for conflicting entry - permit it
|
|
||||||
|
|
||||||
logMod->warn("Potential confict in '%s'", conflictPath);
|
|
||||||
|
|
||||||
for (auto const & modID : conflictingMods)
|
|
||||||
logMod->warn("Mod '%s' - value set to %s", modID, conflictModData[modID].toCompactString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handler->afterLoadFinalization();
|
handler->afterLoadFinalization();
|
||||||
@ -288,7 +292,7 @@ void CContentHandler::afterLoadFinalization()
|
|||||||
|
|
||||||
void CContentHandler::preloadData(CModInfo & mod)
|
void CContentHandler::preloadData(CModInfo & mod)
|
||||||
{
|
{
|
||||||
bool validate = (mod.validation != CModInfo::PASSED);
|
bool validate = validateMod(mod);
|
||||||
|
|
||||||
// print message in format [<8-symbols checksum>] <modname>
|
// print message in format [<8-symbols checksum>] <modname>
|
||||||
auto & info = mod.getVerificationInfo();
|
auto & info = mod.getVerificationInfo();
|
||||||
@ -305,7 +309,7 @@ void CContentHandler::preloadData(CModInfo & mod)
|
|||||||
|
|
||||||
void CContentHandler::load(CModInfo & mod)
|
void CContentHandler::load(CModInfo & mod)
|
||||||
{
|
{
|
||||||
bool validate = (mod.validation != CModInfo::PASSED);
|
bool validate = validateMod(mod);
|
||||||
|
|
||||||
if (!loadMod(mod.identifier, validate))
|
if (!loadMod(mod.identifier, validate))
|
||||||
mod.validation = CModInfo::FAILED;
|
mod.validation = CModInfo::FAILED;
|
||||||
@ -326,4 +330,18 @@ const ContentTypeHandler & CContentHandler::operator[](const std::string & name)
|
|||||||
return handlers.at(name);
|
return handlers.at(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CContentHandler::validateMod(const CModInfo & mod) const
|
||||||
|
{
|
||||||
|
if (settings["mods"]["validation"].String() == "full")
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (mod.validation == CModInfo::PASSED)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (settings["mods"]["validation"].String() == "off")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@ -58,6 +58,7 @@ class DLL_LINKAGE CContentHandler
|
|||||||
|
|
||||||
std::map<std::string, ContentTypeHandler> handlers;
|
std::map<std::string, ContentTypeHandler> handlers;
|
||||||
|
|
||||||
|
bool validateMod(const CModInfo & mod) const;
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user