From 0893657ec2944e36cfbe5a2ebd2b3787a0fe1239 Mon Sep 17 00:00:00 2001 From: Illustar0 Date: Wed, 21 Oct 2026 13:38:45 +0800 Subject: [PATCH 1/2] fix: skip disabled plugins when enforcing locked load order - Stop disabled locked plugins from flip-flopping around the plugin that holds their index on every refresh, which also rewrote the plugin lists each time - Stop a disabled plugin's lock from hiding an enabled plugin's lock on the same index - Keep the lock so it applies again once the plugin is re-enabled --- src/pluginlist.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 021b5f5bf..d2e295255 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -923,10 +923,17 @@ void PluginList::refreshLoadOrder() syncLoadOrder(); // set priorities according to locked load order std::map lockedLoadOrder; - std::for_each(m_LockedOrder.begin(), m_LockedOrder.end(), - [&lockedLoadOrder](const std::pair& ele) { - lockedLoadOrder[ele.second] = ele.first; - }); + for (const auto& [name, loadOrder] : m_LockedOrder) { + // a disabled plugin has no load order to enforce; placing it anyway makes it + // flip around the plugin holding its index on every refresh, and it would also + // take the slot of an enabled plugin locked to the same index. The lock is + // kept and applies again once the plugin is enabled. + auto nameIter = m_ESPsByName.find(name); + if (nameIter != m_ESPsByName.end() && !m_ESPs[nameIter->second].enabled) { + continue; + } + lockedLoadOrder[loadOrder] = name; + } int targetPrio = 0; bool savePluginsList = false; From 3e0d3248ba99470a1d14821efad0db4b352ff02b Mon Sep 17 00:00:00 2001 From: Illustar0 Date: Wed, 21 Oct 2026 13:46:18 +0800 Subject: [PATCH 2/2] fix: ignore locks of missing plugins when enforcing locked load order - Stop the lock of a plugin that is no longer present from hiding an enabled plugin's lock on the same index, which left that lock silently ineffective - Keep the lock so it applies again once the plugin is back and enabled --- src/pluginlist.cpp | 53 ++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index d2e295255..ab1184e4d 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -921,46 +921,43 @@ void PluginList::refreshLoadOrder() { ChangeBracket layoutChange(this); syncLoadOrder(); - // set priorities according to locked load order - std::map lockedLoadOrder; + // set priorities according to locked load order, maps load order to plugin index + std::map lockedLoadOrder; for (const auto& [name, loadOrder] : m_LockedOrder) { - // a disabled plugin has no load order to enforce; placing it anyway makes it - // flip around the plugin holding its index on every refresh, and it would also - // take the slot of an enabled plugin locked to the same index. The lock is - // kept and applies again once the plugin is enabled. + // only present, enabled plugins have a load order to enforce; the locks of the + // others are kept and apply again once the plugin is back and enabled + // + // placing a disabled plugin anyway makes it flip around the plugin holding its + // index on every refresh, and leaving any of them in would take the slot of an + // enabled plugin locked to the same index auto nameIter = m_ESPsByName.find(name); - if (nameIter != m_ESPsByName.end() && !m_ESPs[nameIter->second].enabled) { + if (nameIter == m_ESPsByName.end() || !m_ESPs[nameIter->second].enabled) { continue; } - lockedLoadOrder[loadOrder] = name; + lockedLoadOrder[loadOrder] = nameIter->second; } int targetPrio = 0; bool savePluginsList = false; // this is guaranteed to iterate from lowest key (load order) to highest for (auto iter = lockedLoadOrder.begin(); iter != lockedLoadOrder.end(); ++iter) { - auto nameIter = m_ESPsByName.find(iter->second); - if (nameIter != m_ESPsByName.end()) { - // locked esp exists - - // find the location to insert at - while ((targetPrio < static_cast(m_ESPs.size() - 1)) && - (m_ESPs[m_ESPsByPriority[targetPrio]].loadOrder < iter->first)) { - ++targetPrio; - } + // find the location to insert at + while ((targetPrio < static_cast(m_ESPs.size() - 1)) && + (m_ESPs[m_ESPsByPriority[targetPrio]].loadOrder < iter->first)) { + ++targetPrio; + } - if (static_cast(targetPrio) >= m_ESPs.size()) { - continue; - } + if (static_cast(targetPrio) >= m_ESPs.size()) { + continue; + } - int temp = targetPrio; - int index = nameIter->second; - if (m_ESPs[index].priority != temp) { - setPluginPriority(index, temp); - m_ESPs[index].loadOrder = iter->first; - syncLoadOrder(); - savePluginsList = true; - } + int temp = targetPrio; + int index = iter->second; + if (m_ESPs[index].priority != temp) { + setPluginPriority(index, temp); + m_ESPs[index].loadOrder = iter->first; + syncLoadOrder(); + savePluginsList = true; } } if (savePluginsList) {