diff --git a/src/api/sorting/plugin_sorter.cpp b/src/api/sorting/plugin_sorter.cpp index d3b92901..2ad6908c 100644 --- a/src/api/sorting/plugin_sorter.cpp +++ b/src/api/sorting/plugin_sorter.cpp @@ -551,6 +551,16 @@ void PluginSorter::AddGroupEdges() { toPlugin.GetName()); } + // If the earlier plugin is not a master and the later plugin is, + // don't ignore the plugin with the default group for all + // intermediate plugins, as some of those plugins may be masters + // that wouldn't be involved in the cycle, and any of those + // plugins that are not masters would have their own cycles + // detected anyway. + if (!fromPlugin.IsMaster() && toPlugin.IsMaster()) { + continue; + } + // The default group is a special case, as it's given to plugins // with no metadata. If a plugin in the default group causes // a cycle due to its group, ignore that plugin's group for all diff --git a/src/tests/api/internals/sorting/plugin_sorter_test.h b/src/tests/api/internals/sorting/plugin_sorter_test.h index 56c0a639..b1002ad3 100644 --- a/src/tests/api/internals/sorting/plugin_sorter_test.h +++ b/src/tests/api/internals/sorting/plugin_sorter_test.h @@ -164,11 +164,10 @@ TEST_P(PluginSorterTest, PluginMetadata()); EXPECT_TRUE(lightMaster.IsMaster()); - auto lightMasterEsp = - PluginSortingData(*dynamic_cast( - game_.GetPlugin(blankEslEsp).get()), - PluginMetadata(), - PluginMetadata()); + auto lightMasterEsp = PluginSortingData( + *dynamic_cast(game_.GetPlugin(blankEslEsp).get()), + PluginMetadata(), + PluginMetadata()); EXPECT_FALSE(lightMasterEsp.IsMaster()); } } @@ -394,6 +393,46 @@ TEST_P( } } +TEST_P(PluginSorterTest, + sortingShouldNotIgnoreIntermediatePluginsInAMultiGroupCycleIfTheEarlierPluginIsNotAMasterAndTheLaterIs) { + ASSERT_NO_THROW(loadInstalledPlugins(game_, false)); + + GenerateMasterlist(); + game_.GetDatabase()->LoadLists(masterlistPath_); + + PluginMetadata plugin(blankMasterDependentEsp); + plugin.SetGroup("earliest"); + game_.GetDatabase()->SetPluginUserMetadata(plugin); + + plugin = PluginMetadata(blankDifferentEsm); + plugin.SetGroup("earlier"); + game_.GetDatabase()->SetPluginUserMetadata(plugin); + + PluginSorter ps; + std::vector expectedSortedOrder({ + blankDifferentEsm, + blankEsm, + blankMasterDependentEsm, + blankDifferentMasterDependentEsm, + blankMasterDependentEsp, + blankEsp, + blankDifferentEsp, + blankDifferentMasterDependentEsp, + blankPluginDependentEsp, + blankDifferentPluginDependentEsp, + }); + + if (GetParam() == GameType::fo4 || GetParam() == GameType::tes5se) { + expectedSortedOrder.insert(expectedSortedOrder.begin(), masterFile); + expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl); + } else { + expectedSortedOrder.insert(expectedSortedOrder.begin() + 1, masterFile); + } + + std::vector sorted = ps.Sort(game_); + EXPECT_EQ(expectedSortedOrder, sorted); +} + TEST_P( PluginSorterTest, sortingShouldNotIgnorePluginsInTheSameGroupAsTheTargetPluginOfAGroupEdgeThatCausesACycleInIsolation) {