diff options
Diffstat (limited to 'src/modinfo.cpp')
| -rw-r--r-- | src/modinfo.cpp | 181 |
1 files changed, 137 insertions, 44 deletions
diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 1c6139f6..c1974152 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -110,15 +110,16 @@ QString ModInfo::getContentTypeName(int contentType) case CONTENT_INI: return tr("INI files"); case CONTENT_MODGROUP: return tr("ModGroup files"); - default: throw MyException(tr("invalid content type %1").arg(contentType)); + default: throw MyException(tr("invalid content type: %1").arg(contentType)); } } -void ModInfo::createFromOverwrite(PluginContainer *pluginContainer) +void ModInfo::createFromOverwrite(PluginContainer *pluginContainer, + MOShared::DirectoryEntry **directoryStructure) { QMutexLocker locker(&s_Mutex); - s_Collection.push_back(ModInfo::Ptr(new ModInfoOverwrite(pluginContainer))); + s_Collection.push_back(ModInfo::Ptr(new ModInfoOverwrite(pluginContainer, directoryStructure))); } unsigned int ModInfo::getNumMods() @@ -133,7 +134,7 @@ ModInfo::Ptr ModInfo::getByIndex(unsigned int index) QMutexLocker locker(&s_Mutex); if (index >= s_Collection.size() && index != ULONG_MAX) { - throw MyException(tr("invalid mod index %1").arg(index)); + throw MyException(tr("invalid mod index: %1").arg(index)); } if (index == ULONG_MAX) return s_Collection[ModInfo::getIndex("Overwrite")]; return s_Collection[index]; @@ -144,20 +145,35 @@ std::vector<ModInfo::Ptr> ModInfo::getByModID(QString game, int modID) { QMutexLocker locker(&s_Mutex); - auto iter = s_ModsByModID.find(std::pair<QString, int>(game, modID)); - if (iter == s_ModsByModID.end()) { + std::vector<unsigned int> match; + for (auto iter : s_ModsByModID) { + if (iter.first.second == modID) { + if (iter.first.first.compare(game, Qt::CaseInsensitive) == 0) { + match.insert(match.end(), iter.second.begin(), iter.second.end()); + } + } + } + if (match.empty()) { return std::vector<ModInfo::Ptr>(); } std::vector<ModInfo::Ptr> result; - for (auto idxIter = iter->second.begin(); idxIter != iter->second.end(); ++idxIter) { - result.push_back(getByIndex(*idxIter)); + for (auto iter : match) { + result.push_back(getByIndex(iter)); } return result; } +ModInfo::Ptr ModInfo::getByName(const QString &name) +{ + QMutexLocker locker(&s_Mutex); + + return s_Collection[ModInfo::getIndex(name)]; +} + + bool ModInfo::removeMod(unsigned int index) { QMutexLocker locker(&s_Mutex); @@ -248,7 +264,7 @@ void ModInfo::updateFromDisc(const QString &modDirectory, } } - createFromOverwrite(pluginContainer); + createFromOverwrite(pluginContainer, directoryStructure); std::sort(s_Collection.begin(), s_Collection.end(), ModInfo::ByName); @@ -277,59 +293,136 @@ ModInfo::ModInfo(PluginContainer *pluginContainer) } -void ModInfo::checkChunkForUpdate(PluginContainer *pluginContainer, const std::vector<int> &modIDs, QObject *receiver, QString gameName) +bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver) { - if (modIDs.size() != 0) { - NexusInterface::instance(pluginContainer)->requestUpdates(modIDs, receiver, QVariant(), gameName, QString()); + bool updatesAvailable = true; + + QDateTime earliest = QDateTime::currentDateTimeUtc(); + QDateTime latest; + std::set<QString> games; + for (auto mod : s_Collection) { + if (mod->canBeUpdated()) { + if (mod->getLastNexusUpdate() < earliest) + earliest = mod->getLastNexusUpdate(); + if (mod->getLastNexusUpdate() > latest) + latest = mod->getLastNexusUpdate(); + games.insert(mod->getGameName().toLower()); + } } -} + if (latest < QDateTime::currentDateTimeUtc().addDays(-30)) { + std::set<std::pair<QString, int>> organizedGames; + for (auto mod : s_Collection) { + if (mod->canBeUpdated()) { + organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID())); + } + } + + if (organizedGames.empty()) { + qWarning("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests."); + updatesAvailable = false; + } -int ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver) -{ - // technically this should be 255 but those requests can take nexus fairly long, produce - // large output and may have been the cause of issue #1166 - static const int chunkSize = 64; + for (auto game : organizedGames) { + NexusInterface::instance(pluginContainer)->requestUpdates(game.second, receiver, QVariant(), game.first, QString()); + } + } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-30)) { + for (auto gameName : games) + NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(true), QString()); + } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-7)) { + for (auto gameName : games) + NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::MONTH, receiver, QVariant(false), QString()); + } else if (earliest < QDateTime::currentDateTimeUtc().addDays(-1)) { + for (auto gameName : games) + NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::WEEK, receiver, QVariant(false), QString()); + } else { + for (auto gameName : games) + NexusInterface::instance(pluginContainer)->requestUpdateInfo(gameName, NexusInterface::UpdatePeriod::DAY, receiver, QVariant(false), QString()); + } - int result = 0; - std::vector<int> modIDs; + return updatesAvailable; +} - // Normally this would be the managed game but MO2 is only uploaded to the Skyrim SE site right now - IPluginGame const *game = pluginContainer->managedGame("Skyrim Special Edition"); - if (game && game->nexusModOrganizerID()) { - modIDs.push_back(game->nexusModOrganizerID()); - checkChunkForUpdate(pluginContainer, modIDs, receiver, game->gameShortName()); - modIDs.clear(); +std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVariantList updateData, bool addOldMods, bool markUpdated) +{ + std::set<QSharedPointer<ModInfo>> finalMods; + for (QVariant result : updateData) { + QVariantMap update = result.toMap(); + std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(finalMods, finalMods.end()), [=](QSharedPointer<ModInfo> info) -> bool { + if (info->getNexusID() == update["mod_id"].toInt() && info->getGameName().compare(gameName, Qt::CaseInsensitive) == 0) + if (info->getLastNexusUpdate().addSecs(-3600) < QDateTime::fromSecsSinceEpoch(update["latest_file_update"].toInt(), Qt::UTC)) + return true; + return false; + }); } - std::multimap<QString, QSharedPointer<ModInfo>> organizedGames; - for (auto mod : s_Collection) { - if (mod->canBeUpdated()) { - organizedGames.insert(std::pair<QString, QSharedPointer<ModInfo>>(mod->getGameName(), mod)); + if (addOldMods) + for (auto mod : s_Collection) + if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addDays(-30) && mod->getGameName().compare(gameName, Qt::CaseInsensitive) == 0) + finalMods.insert(mod); + + if (markUpdated) { + std::set<QSharedPointer<ModInfo>> updates; + std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(updates, updates.end()), [=](QSharedPointer<ModInfo> info) -> bool { + if (info->getGameName().compare(gameName, Qt::CaseInsensitive) == 0 && info->canBeUpdated()) + return true; + return false; + }); + std::set<QSharedPointer<ModInfo>> diff; + std::set_difference(updates.begin(), updates.end(), finalMods.begin(), finalMods.end(), std::inserter(diff, diff.end())); + for (auto skipped : diff) { + skipped->setLastNexusUpdate(QDateTime::currentDateTimeUtc()); } } + return finalMods; +} + +void ModInfo::manualUpdateCheck(PluginContainer *pluginContainer, QObject *receiver, std::multimap<QString, int> IDs) +{ + std::vector<QSharedPointer<ModInfo>> mods; + std::set<std::pair<QString, int>> organizedGames; - QString currentGame = ""; - for (auto game : organizedGames) { - if (currentGame != game.first) { - if (currentGame != "") { - checkChunkForUpdate(pluginContainer, modIDs, receiver, currentGame); - modIDs.clear(); + for (auto ID : IDs) { + for (auto matchedMod : getByModID(ID.first, ID.second)) { + bool alreadyMatched = false; + for (auto mod : mods) { + if (mod == matchedMod) { + alreadyMatched = true; + break; + } } - currentGame = game.first; - } - modIDs.push_back(game.second->getNexusID()); - if (modIDs.size() >= chunkSize) { - checkChunkForUpdate(pluginContainer, modIDs, receiver, currentGame); - modIDs.clear(); + if (!alreadyMatched) + mods.push_back(matchedMod); } } + mods.erase( + std::remove_if(mods.begin(), mods.end(), [](ModInfo::Ptr mod) -> bool { return mod->getNexusID() <= 0; }), + mods.end() + ); + for (auto mod : mods) { + mod->setLastNexusUpdate(QDateTime()); + } - checkChunkForUpdate(pluginContainer, modIDs, receiver, currentGame); + std::sort(mods.begin(), mods.end(), [](QSharedPointer<ModInfo> a, QSharedPointer<ModInfo> b) -> bool { + return a->getLastNexusUpdate() < b->getLastNexusUpdate(); + }); - return result; + if (mods.size()) { + qInfo("Checking updates for %d mods...", mods.size()); + + for (auto mod : mods) { + organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID())); + } + + for (auto game : organizedGames) { + NexusInterface::instance(pluginContainer)->requestUpdates(game.second, receiver, QVariant(), game.first, QString()); + } + } else { + qInfo("None of the selected mods can be updated."); + } } + void ModInfo::setVersion(const VersionInfo &version) { m_Version = version; |
