1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-02 00:10:22 +02:00

Mod version verification system

This commit is contained in:
nordsoft 2022-09-13 02:01:43 +04:00
parent 2d063bf19b
commit 2d4239d039
3 changed files with 128 additions and 4 deletions

View File

@ -532,6 +532,47 @@ JsonNode addMeta(JsonNode config, std::string meta)
return config;
}
CModInfo::Version CModInfo::Version::GameVersion()
{
return Version(GameConstants::VCMI_VERSION_MAJOR, GameConstants::VCMI_VERSION_MINOR, GameConstants::VCMI_VERSION_PATCH);
}
CModInfo::Version CModInfo::Version::fromString(std::string from)
{
int major = 0, minor = 0, patch = 0;
try
{
auto pointPos = from.find('.');
major = std::stoi(from.substr(0, pointPos));
from = from.substr(pointPos);
pointPos = from.find('.');
minor = std::stoi(from.substr(0, pointPos));
patch = std::stoi(from.substr(pointPos));
}
catch(const std::invalid_argument & e)
{
return Version();
}
return Version(major, minor, patch);
}
std::string CModInfo::Version::toString() const
{
return std::to_string(major) + '.' + std::to_string(minor) + '.' + std::to_string(patch);
}
bool CModInfo::Version::compatible(const Version & other, bool checkMinor, bool checkPatch) const
{
return (major == other.major &&
(!checkMinor || minor >= other.minor) &&
(!checkPatch || minor > other.minor || (minor == other.minor && patch >= other.patch)));
}
bool CModInfo::Version::isNull() const
{
return major == 0 && minor == 0 && patch == 0;
}
CModInfo::CModInfo():
checksum(0),
enabled(false),
@ -551,6 +592,12 @@ CModInfo::CModInfo(std::string identifier,const JsonNode & local, const JsonNode
validation(PENDING),
config(addMeta(config, identifier))
{
version = Version::fromString(config["version"].String());
if(!config["compatibility"].isNull())
{
vcmiCompatibleMin = Version::fromString(config["compatibility"]["min"].String());
vcmiCompatibleMax = Version::fromString(config["compatibility"]["max"].String());
}
loadLocalData(local);
}
@ -601,6 +648,10 @@ void CModInfo::loadLocalData(const JsonNode & data)
validated = data["validated"].Bool();
checksum = strtol(data["checksum"].String().c_str(), nullptr, 16);
}
//check compatibility
enabled &= vcmiCompatibleMin.isNull() || Version::GameVersion().compatible(vcmiCompatibleMin);
enabled &= vcmiCompatibleMax.isNull() || vcmiCompatibleMax.compatible(Version::GameVersion());
if (enabled)
validation = validated ? PASSED : PENDING;

View File

@ -177,6 +177,30 @@ public:
FAILED,
PASSED
};
struct Version
{
int major = 0;
int minor = 0;
int patch = 0;
Version() = default;
Version(int mj, int mi, int p): major(mj), minor(mi), patch(p) {}
static Version GameVersion();
static Version fromString(std::string from);
std::string toString() const;
bool compatible(const Version & other, bool checkMinor = false, bool checkPatch = false) const;
bool isNull() const;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & major;
h & minor;
h & patch;
}
};
/// identifier, identical to name of folder with mod
std::string identifier;
@ -184,6 +208,12 @@ public:
/// human-readable strings
std::string name;
std::string description;
/// version of the mod
Version version;
///The vcmi versions compatible with the mod
Version vcmiCompatibleMin, vcmiCompatibleMax;
/// list of mods that should be loaded before this one
std::set <TModID> dependencies;
@ -210,7 +240,8 @@ public:
static std::string getModDir(std::string name);
static std::string getModFile(std::string name);
template <typename Handler> void serialize(Handler &h, const int version)
//TODO: remove as soon as backward compatilibity for versions earlier 806 is not preserved.
template <typename Handler> void serialize(Handler &h, const int ver)
{
h & identifier;
h & description;
@ -256,6 +287,13 @@ class DLL_LINKAGE CModHandler
void loadMods(std::string path, std::string parent, const JsonNode & modSettings, bool enableMods);
void loadOneMod(std::string modName, std::string parent, const JsonNode & modSettings, bool enableMods);
public:
class Incompatibility: public std::logic_error
{
public:
Incompatibility(const std::string & w): std::logic_error(w)
{}
};
CIdentifierStorage identifiers;
@ -336,8 +374,43 @@ public:
template <typename Handler> void serialize(Handler &h, const int version)
{
h & allMods;
h & activeMods;
if(version < 806)
{
h & allMods; //don't serialize mods
h & activeMods;
}
else
{
if(h.saving)
{
h & activeMods;
for(auto & m : activeMods)
h & allMods[m].version;
}
else
{
std::vector<TModID> newActiveMods;
h & newActiveMods;
for(auto & m : newActiveMods)
{
if(!allMods.count(m))
throw Incompatibility(m + " unkown mod");
CModInfo::Version mver;
h & mver;
if(!allMods[m].version.isNull() && !mver.isNull() && !allMods[m].version.compatible(mver))
{
std::string err = allMods[m].name +
": version needed " + mver.toString() +
"but you have installed " + allMods[m].version.toString();
throw Incompatibility(err);
}
allMods[m].enabled = true;
}
std::swap(activeMods, newActiveMods);
}
}
h & settings;
h & modules;
h & identifiers;

View File

@ -12,7 +12,7 @@
#include "../ConstTransitivePtr.h"
#include "../GameConstants.h"
const ui32 SERIALIZATION_VERSION = 805;
const ui32 SERIALIZATION_VERSION = 806;
const ui32 MINIMAL_SERIALIZATION_VERSION = 805;
const std::string SAVEGAME_MAGIC = "VCMISVG";