diff options
Diffstat (limited to 'src/profile.cpp')
| -rw-r--r-- | src/profile.cpp | 200 |
1 files changed, 123 insertions, 77 deletions
diff --git a/src/profile.cpp b/src/profile.cpp index bb3a11e2..098cff6e 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -230,14 +230,13 @@ void Profile::doWriteModlist() return; } - for (std::map<int, unsigned int>::const_reverse_iterator iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++ ) { + for (auto iter = m_ModIndexByPriority.crbegin(); iter != m_ModIndexByPriority.crend(); iter++) { // the priority order was inverted on load so it has to be inverted again unsigned int index = iter->second; if (index != UINT_MAX) { ModInfo::Ptr modInfo = ModInfo::getByIndex(index); - std::vector<ModInfo::EFlag> flags = modInfo->getFlags(); - if ((modInfo->getFixedPriority() == INT_MIN)) { - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) != flags.end()) { + if (!modInfo->isFixedPriority()) { + if (modInfo->isForeign()) { file->write("*"); } else if (m_ModStatus[index].m_Enabled) { file->write("+"); @@ -270,10 +269,9 @@ void Profile::createTweakedIniFile() return; } - for (int i = getPriorityMinimum(); i < getPriorityMinimum() + (int)numRegularMods(); ++i) { - unsigned int idx = modIndexByPriority(i); - if (m_ModStatus[idx].m_Enabled) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx); + for (auto& [priority, index] : m_ModIndexByPriority) { + if (m_ModStatus[index].m_Enabled) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(index); mergeTweaks(modInfo, tweakedIni); } } @@ -368,6 +366,38 @@ void Profile::renameModInList(QFile &modList, const QString &oldName, const QStr void Profile::refreshModStatus() { + // this function refreshes mod status (enabled/disabled) and priority + // using the profile mod list file and the mods in the mods folder using + // the following steps + // + // 1) the mod list file is read and mods status/priority are updated by + // considering the content of the file (for status) and the order (for + // priority), missing or invalid mods are discarded (with a warning) + // 2) the priority are reversed to match the plugin list (highest wins) + // since the mod list is written in reverse order + // 3) at the same time, new mods (not in the mod list file) are added + // - foreign mods are given low priority (below 0) + // - regular mods are given high priority (above mods from the mod list) + // 4) the priority are shifted to ensure that the minimum priority is 0 + // 5) the priority of backups are computed such that the first backup is + // above all regular mods + // + // in the context of the profile, "regular mods" means a mod whose priority + // can be set by the user (i.e. not a backup or overwrite) + // + // this method ensures that the mods priority is as follow + // + // 0 mod1 + // 1 mod2 + // ... + // K-1 modK (K = m_NumRegularMods) + // K backup1 + // K+1 backup2 + // ... + // N-2 backupX + // N-1 overwrite (N = number of mods) + // + writeModlistNow(true); // if there are pending changes write them first QFile file(getModlistFileName()); @@ -387,6 +417,8 @@ void Profile::refreshModStatus() int index = 0; while (!file.atEnd()) { QByteArray line = file.readLine().trimmed(); + + // find the mod name and the enabled status bool enabled = true; QString modName; if (line.length() == 0) { @@ -398,89 +430,106 @@ void Profile::refreshModStatus() } else if (line.at(0) == '-') { enabled = false; modName = QString::fromUtf8(line.mid(1).trimmed().constData()); - } else if ((line.at(0) == '+') - || (line.at(0) == '*')) { + } else if (line.at(0) == '+' || line.at(0) == '*') { modName = QString::fromUtf8(line.mid(1).trimmed().constData()); } else { modName = QString::fromUtf8(line.trimmed().constData()); } - if (modName.size() > 0) { - QString lookupName = modName; - if (modName.compare("overwrite", Qt::CaseInsensitive) == 0) { - warnAboutOverwrite = true; - } - if (namesRead.find(lookupName) != namesRead.end()) { - continue; - } else { - namesRead.insert(lookupName); - } - unsigned int modIndex = ModInfo::getIndex(lookupName); - if (modIndex != UINT_MAX) { - ModInfo::Ptr info = ModInfo::getByIndex(modIndex); - if ((modIndex < m_ModStatus.size()) - && (info->getFixedPriority() == INT_MIN)) { - m_ModStatus[modIndex].m_Enabled = enabled; - if (m_ModStatus[modIndex].m_Priority == -1) { - if (static_cast<size_t>(index) >= m_ModStatus.size()) { - throw MyException(tr("invalid mod index: %1").arg(index)); - } - m_ModStatus[modIndex].m_Priority = index++; - } - } else { - log::warn( - "no mod state for \"{}\" (profile \"{}\")", - modName, m_Directory.path()); - // need to rewrite the modlist to fix this - modStatusModified = true; + + if (modName.isEmpty()) { + continue; + } + + if (modName.compare("overwrite", Qt::CaseInsensitive) == 0) { + warnAboutOverwrite = true; + } + + // check if the name was already read + if (namesRead.find(modName) != namesRead.end()) { + continue; + } + namesRead.insert(modName); + + unsigned int modIndex = ModInfo::getIndex(modName); + if (modIndex == UINT_MAX) { + log::debug( + "mod not found: \"{}\" (profile \"{}\")", + modName, m_Directory.path()); + // need to rewrite the modlist to fix this + modStatusModified = true; + continue; + } + + // find the mod and check that this is a regular mod (and not a backup) + ModInfo::Ptr info = ModInfo::getByIndex(modIndex); + if (modIndex < m_ModStatus.size() && !info->isFixedPriority()) { + m_ModStatus[modIndex].m_Enabled = enabled; + if (m_ModStatus[modIndex].m_Priority == -1) { + if (static_cast<size_t>(index) >= m_ModStatus.size()) { + throw Exception(tr("invalid mod index: %1").arg(index)); } - } else { - log::debug( - "mod not found: \"{}\" (profile \"{}\")", - modName, m_Directory.path()); - // need to rewrite the modlist to fix this - modStatusModified = true; + m_ModStatus[modIndex].m_Priority = index++; } + } else { + log::warn( + "no mod state for \"{}\" (profile \"{}\")", + modName, m_Directory.path()); + // need to rewrite the modlist to fix this + modStatusModified = true; } - } - int numKnownMods = index; + } // while (!file.atEnd()) + file.close(); + + const int numKnownMods = index; int topInsert = 0; - // invert priority order to match that of the pluginlist. Also - // give priorities to mods not referenced in the profile + // invert priority order to match that of the pluginlist, also + // give priorities to mods not referenced in the profile and + // count the number of regular mods + m_NumRegularMods = 0; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast<int>(i)); if (modInfo->alwaysEnabled()) { m_ModStatus[i].m_Enabled = true; } - if (modInfo->getFixedPriority() == INT_MAX) { + if (modInfo->isOverwrite()) { + m_ModStatus[i].m_Priority = m_ModStatus.size() - 1; continue; } if (m_ModStatus[i].m_Priority != -1) { m_ModStatus[i].m_Priority = numKnownMods - m_ModStatus[i].m_Priority - 1; + ++m_NumRegularMods; } else { if (static_cast<size_t>(index) >= m_ModStatus.size()) { - throw MyException(tr("invalid mod index: %1").arg(index)); + throw Exception(tr("invalid mod index: %1").arg(index)); } - if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) { + + // skip backups on purpose to avoid inserting backups in-between + // regular mods + if (modInfo->isForeign()) { m_ModStatus[i].m_Priority = --topInsert; - } else { + ++m_NumRegularMods; + } else if (!modInfo->isBackup()) { m_ModStatus[i].m_Priority = index++; + ++m_NumRegularMods; } + // also, mark the mod-list as changed modStatusModified = true; } } - // to support insertion of new mods at the top we may now have mods with negative priority. shift them all up - // to align priority with 0 + + // to support insertion of new mods at the top we may now have mods with negative priority, + // so shift them all up to align priority with 0 if (topInsert < 0) { int offset = topInsert * -1; for (size_t i = 0; i < m_ModStatus.size(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast<unsigned int>(i)); - if (modInfo->getFixedPriority() == INT_MAX) { + if (modInfo->isFixedPriority()) { continue; } @@ -488,7 +537,15 @@ void Profile::refreshModStatus() } } - file.close(); + // set the backups priority + int backupPriority = m_NumRegularMods; + for (size_t i = 0; i < m_ModStatus.size(); ++i) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(static_cast<unsigned int>(i)); + if (modInfo->isBackup()) { + m_ModStatus[i].m_Priority = backupPriority++; + } + } + updateIndices(); // User has a mod named some variation of "overwrite". Tell them about it. @@ -519,17 +576,10 @@ void Profile::dumpModStatus() const void Profile::updateIndices() { - m_NumRegularMods = 0; m_ModIndexByPriority.clear(); for (unsigned int i = 0; i < m_ModStatus.size(); ++i) { int priority = m_ModStatus[i].m_Priority; - if (priority == INT_MIN) { - // don't assign this to mapping at all, it's probably the overwrite mod - continue; - } else { - ++m_NumRegularMods; - m_ModIndexByPriority[priority] = i; - } + m_ModIndexByPriority[priority] = i; } } @@ -631,27 +681,21 @@ int Profile::getModPriority(unsigned int index) const } -void Profile::setModPriority(unsigned int index, int &newPriority) +bool Profile::setModPriority(unsigned int index, int &newPriority) { - if (m_ModStatus.at(index).m_Overwrite) { - // can't change priority of the overwrite - return; + if (ModInfo::getByIndex(index)->isFixedPriority()) { + // can't change priority of overwrite/backups + return false; } + newPriority = std::clamp(newPriority, 0, static_cast<int>(m_NumRegularMods) - 1); + int oldPriority = m_ModStatus.at(index).m_Priority; int lastPriority = INT_MIN; if (newPriority == oldPriority) { // nothing to do - return; - } - - // we need to put the mod before backups - auto it = std::find_if(m_ModIndexByPriority.begin(), m_ModIndexByPriority.end(), [](auto&& p) { - return ModInfo::getByIndex(p.second)->isBackup(); - }); - if (it != m_ModIndexByPriority.end() && it->first <= newPriority) { - newPriority = it->first - 1; + return false; } for (auto& [priority, index] : m_ModIndexByPriority) { @@ -669,6 +713,8 @@ void Profile::setModPriority(unsigned int index, int &newPriority) updateIndices(); m_ModListWriter.write(); + + return true; } Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin) |
