aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-11 04:14:44 -0500
committerSulfurNitride <SulfurNitride@users.noreply.github.com>2026-03-11 04:14:44 -0500
commit0dc7f137e96bf171a73f0822b4de1bbd5d9478a2 (patch)
tree55e30639ae2e0e442323bb688ce0547734773679
parentbf553c6568146ac2d104c06135e27f140b5782b8 (diff)
Fix LOOT ambiguous load order: use loadorder.txt as canonical order
Instead of prepending base ESMs to plugins.txt (wrong order), generate plugins.txt from loadorder.txt with active/inactive markers from the original plugins.txt. This ensures both files agree on plugin order. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
-rw-r--r--src/src/loot.cpp49
1 files changed, 23 insertions, 26 deletions
diff --git a/src/src/loot.cpp b/src/src/loot.cpp
index 75ecbbc..3204689 100644
--- a/src/src/loot.cpp
+++ b/src/src/loot.cpp
@@ -1366,49 +1366,46 @@ static bool launchLootGui(QWidget* parent, OrganizerCore& core)
QFile::copy(profileLoadOrder, lootLoadOrder);
}
if (QFile::exists(profilePlugins) && QFile::exists(profileLoadOrder)) {
- // Build a set of plugins already in plugins.txt (case-insensitive).
+ // Build a set of active plugins from plugins.txt (case-insensitive).
QFile pluginsFile(profilePlugins);
- QSet<QString> pluginsListed;
- QStringList pluginsLines;
+ QSet<QString> activePlugins;
if (pluginsFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&pluginsFile);
while (!in.atEnd()) {
- QString line = in.readLine();
- pluginsLines.append(line);
- QString name = line.trimmed();
- if (name.startsWith('*'))
- name = name.mid(1);
- if (!name.isEmpty() && !name.startsWith('#'))
- pluginsListed.insert(name.toLower());
+ QString line = in.readLine().trimmed();
+ if (line.startsWith('*'))
+ line = line.mid(1);
+ if (!line.isEmpty() && !line.startsWith('#'))
+ activePlugins.insert(line.toLower());
}
pluginsFile.close();
}
- // Read loadorder.txt to find plugins not in plugins.txt (base ESMs).
+ // Use loadorder.txt as the canonical order. Mark each plugin as
+ // active (*) or inactive based on plugins.txt. Base game ESMs that
+ // aren't in plugins.txt are always active.
QFile loFile(profileLoadOrder);
- QStringList missingPlugins;
- if (loFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QFile outFile(lootPlugins);
+ if (loFile.open(QIODevice::ReadOnly | QIODevice::Text) &&
+ outFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
QTextStream in(&loFile);
+ QTextStream out(&outFile);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line.isEmpty() || line.startsWith('#'))
continue;
- if (!pluginsListed.contains(line.toLower())) {
- // Base game ESMs are always active — mark with *.
- missingPlugins.append("*" + line);
+ bool active = activePlugins.contains(line.toLower());
+ // Base game ESMs (not in plugins.txt) are implicitly active.
+ if (!active && !activePlugins.isEmpty() &&
+ (line.endsWith(".esm", Qt::CaseInsensitive) ||
+ line.endsWith(".esl", Qt::CaseInsensitive))) {
+ // Check if it's missing from plugins.txt entirely (base game file).
+ if (!activePlugins.contains(line.toLower()))
+ active = true;
}
+ out << (active ? "*" : "") << line << "\n";
}
loFile.close();
- }
-
- // Write merged plugins.txt: missing base ESMs first, then original.
- QFile outFile(lootPlugins);
- if (outFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
- QTextStream out(&outFile);
- for (const auto& line : missingPlugins)
- out << line << "\n";
- for (const auto& line : pluginsLines)
- out << line << "\n";
outFile.close();
}
} else if (QFile::exists(profilePlugins)) {