1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-06 09:09:40 +02:00

Merge pull request #929 from Nordsoft91/branch-merge-versioning

Mods versioning [part 3]
This commit is contained in:
Andrii Danylchenko
2022-09-22 14:56:20 +03:00
committed by GitHub
11 changed files with 453 additions and 157 deletions

View File

@@ -12,29 +12,53 @@
#include "../../lib/JsonNode.h"
#include "../../lib/filesystem/CFileInputStream.h"
#include "../../lib/GameConstants.h"
namespace
{
bool isCompatible(const QString & verMin, const QString & verMax)
{
const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch
QVersionNumber vcmiVersion(GameConstants::VCMI_VERSION_MAJOR,
GameConstants::VCMI_VERSION_MINOR,
GameConstants::VCMI_VERSION_PATCH);
auto versionMin = QVersionNumber::fromString(verMin);
auto versionMax = QVersionNumber::fromString(verMax);
auto buildVersion = [maxSections](QVersionNumber & ver)
{
if(ver.segmentCount() < maxSections)
{
auto segments = ver.segments();
for(int i = segments.size() - 1; i < maxSections; ++i)
segments.append(0);
ver = QVersionNumber(segments);
}
};
if(!versionMin.isNull())
{
buildVersion(versionMin);
if(vcmiVersion < versionMin)
return false;
}
if(!versionMax.isNull())
{
buildVersion(versionMax);
if(vcmiVersion > versionMax)
return false;
}
return true;
}
}
bool CModEntry::compareVersions(QString lesser, QString greater)
{
static const int maxSections = 3; // versions consist from up to 3 sections, major.minor.patch
QStringList lesserList = lesser.split(".");
QStringList greaterList = greater.split(".");
assert(lesserList.size() <= maxSections);
assert(greaterList.size() <= maxSections);
for(int i = 0; i < maxSections; i++)
{
if(greaterList.size() <= i) // 1.1.1 > 1.1
return false;
if(lesserList.size() <= i) // 1.1 < 1.1.1
return true;
if(lesserList[i].toInt() != greaterList[i].toInt())
return lesserList[i].toInt() < greaterList[i].toInt(); // 1.1 < 1.2
}
return false;
auto versionLesser = QVersionNumber::fromString(lesser);
auto versionGreater = QVersionNumber::fromString(greater);
return versionLesser < versionGreater;
}
QString CModEntry::sizeToString(double size)
@@ -92,6 +116,15 @@ bool CModEntry::isUpdateable() const
return false;
}
bool CModEntry::isCompatible() const
{
if(!isInstalled())
return false;
auto compatibility = localData["compatibility"].toMap();
return ::isCompatible(compatibility["min"].toString(), compatibility["max"].toString());
}
bool CModEntry::isEssential() const
{
return getValue("storedLocaly").toBool();
@@ -102,6 +135,11 @@ bool CModEntry::isInstalled() const
return !localData.isEmpty();
}
bool CModEntry::isValid() const
{
return !localData.isEmpty() || !repository.isEmpty();
}
int CModEntry::getModStatus() const
{
int status = 0;
@@ -193,7 +231,11 @@ static QVariant getValue(QVariant input, QString path)
QString remainder = "/" + path.section('/', 2, -1);
entryName.remove(0, 1);
return getValue(input.toMap().value(entryName), remainder);
QMap<QString, QString> keyNormalize;
for(auto & key : input.toMap().keys())
keyNormalize[key.toLower()] = key;
return getValue(input.toMap().value(keyNormalize[entryName]), remainder);
}
else
{
@@ -203,6 +245,7 @@ static QVariant getValue(QVariant input, QString path)
CModEntry CModList::getMod(QString modname) const
{
modname = modname.toLower();
QVariantMap repo;
QVariantMap local = localModList[modname].toMap();
QVariantMap settings;
@@ -246,14 +289,14 @@ CModEntry CModList::getMod(QString modname) const
QVariant repoVal = getValue(entry, path);
if(repoVal.isValid())
{
if(repo.empty())
auto repoValMap = repoVal.toMap();
auto compatibility = repoValMap["compatibility"].toMap();
if(isCompatible(compatibility["min"].toString(), compatibility["max"].toString()))
{
repo = repoVal.toMap();
}
else
{
if(CModEntry::compareVersions(repo["version"].toString(), repoVal.toMap()["version"].toString()))
repo = repoVal.toMap();
if(repo.empty() || CModEntry::compareVersions(repo["version"].toString(), repoValMap["version"].toString()))
{
repo = repoValMap;
}
}
}
}
@@ -297,12 +340,12 @@ QVector<QString> CModList::getModList() const
{
for(auto it = repo.begin(); it != repo.end(); it++)
{
knownMods.insert(it.key());
knownMods.insert(it.key().toLower());
}
}
for(auto it = localModList.begin(); it != localModList.end(); it++)
{
knownMods.insert(it.key());
knownMods.insert(it.key().toLower());
}
for(auto entry : knownMods)

View File

@@ -51,6 +51,10 @@ public:
bool isInstalled() const;
// vcmi essential files
bool isEssential() const;
// checks if verison is compatible with vcmi
bool isCompatible() const;
// returns if has any data
bool isValid() const;
// see ModStatus enum
int getModStatus() const;

View File

@@ -245,6 +245,7 @@ bool CModFilterModel::filterMatchesThis(const QModelIndex & source) const
{
CModEntry mod = base->getMod(source.data(ModRoles::ModNameRole).toString());
return (mod.getModStatus() & filterMask) == filteredType &&
mod.isValid() &&
QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
}

View File

@@ -169,6 +169,10 @@ bool CModManager::canEnableMod(QString modname)
if(!mod.isInstalled())
return addError(modname, "Mod must be installed first");
//check for compatibility
if(!mod.isCompatible())
return addError(modname, "Mod is not compatible, please update VCMI and checkout latest mod revisions");
for(auto modEntry : mod.getValue("depends").toStringList())
{
if(!modList->hasMod(modEntry)) // required mod is not available