Use the order of plugins given when sorting as the current load order

To allow for more flexibility when sorting, e.g. to use a load order
that isn't the current load order as if it was (e.g. sorting from a
backed-up load order).
This commit is contained in:
Oliver Hamlet
2019-11-05 20:46:48 +00:00
parent cf0067c414
commit 06617c2706
7 changed files with 44 additions and 34 deletions
+2 -1
View File
@@ -118,7 +118,8 @@ public:
* applied to the load order used by the game. This function does
* not load or evaluate the masterlist or userlist.
* @param plugins
* A vector of filenames of the plugins to sort.
* A vector of filenames of the plugins to sort, in their current
* load order.
* @returns A vector of the given plugin filenames in their sorted load
* order.
*/
+1 -1
View File
@@ -221,7 +221,7 @@ std::vector<std::string> Game::SortPlugins(
LoadPlugins(plugins, false);
// Sort plugins into their load order.
return loot::SortPlugins(*this);
return loot::SortPlugins(*this, plugins);
}
void Game::LoadCurrentLoadOrderState() {
+14 -11
View File
@@ -126,7 +126,9 @@ std::vector<std::string> PluginGraph::TopologicalSort() const {
std::map<vertex_t, size_t> indexMap;
auto vertexIndexMap = vertex_map_t(indexMap);
size_t i = 0;
BGL_FORALL_VERTICES(v, graph_, RawPluginGraph) { put(vertexIndexMap, v, i++); }
BGL_FORALL_VERTICES(v, graph_, RawPluginGraph) {
put(vertexIndexMap, v, i++);
}
list<vertex_t> sortedVertices;
auto logger = getLogger();
@@ -167,7 +169,8 @@ std::vector<std::string> PluginGraph::TopologicalSort() const {
return plugins;
}
void PluginGraph::AddPluginVertices(Game& game) {
void PluginGraph::AddPluginVertices(Game& game,
const std::vector<std::string>& loadOrder) {
// The resolution of tie-breaks in the plugin graph may be dependent
// on the order in which vertices are iterated over, as an earlier tie
// break resolution may cause a potential later tie break to instead
@@ -191,8 +194,6 @@ void PluginGraph::AddPluginVertices(Game& game) {
// full plugin objects then sorting them.
std::map<std::string, std::vector<std::string>> groupPlugins;
auto loadOrder = game.GetLoadOrder();
auto loadedPlugins = game.GetCache()->GetPlugins();
for (const auto& plugin : loadedPlugins) {
auto masterlistMetadata =
@@ -282,14 +283,16 @@ void PluginGraph::CheckForCycles() const {
std::map<vertex_t, size_t> indexMap;
auto vertexIndexMap = vertex_map_t(indexMap);
size_t i = 0;
BGL_FORALL_VERTICES(v, graph_, RawPluginGraph) { put(vertexIndexMap, v, i++); }
BGL_FORALL_VERTICES(v, graph_, RawPluginGraph) {
put(vertexIndexMap, v, i++);
}
boost::depth_first_search(
graph_, visitor(CycleDetector()).vertex_index_map(vertexIndexMap));
}
bool PluginGraph::EdgeCreatesCycle(const vertex_t& fromVertex,
const vertex_t& toVertex) {
const vertex_t& toVertex) {
if (pathsCache_.count(GraphPath(toVertex, fromVertex)) != 0) {
return true;
}
@@ -346,8 +349,8 @@ bool PluginGraph::EdgeCreatesCycle(const vertex_t& fromVertex,
}
void PluginGraph::AddEdge(const vertex_t& fromVertex,
const vertex_t& toVertex,
EdgeType edgeType) {
const vertex_t& toVertex,
EdgeType edgeType) {
auto graphPath = GraphPath(fromVertex, toVertex);
if (pathsCache_.count(graphPath) != 0) {
@@ -357,9 +360,9 @@ void PluginGraph::AddEdge(const vertex_t& fromVertex,
auto logger = getLogger();
if (logger) {
logger->trace("Adding {} edge from \"{}\" to \"{}\".",
describeEdgeType(edgeType),
graph_[fromVertex].GetName(),
graph_[toVertex].GetName());
describeEdgeType(edgeType),
graph_[fromVertex].GetName(),
graph_[toVertex].GetName());
}
boost::add_edge(fromVertex, toVertex, edgeType, graph_);
+1 -1
View File
@@ -83,7 +83,7 @@ public:
size_t CountVertices() const;
void CheckForCycles() const;
void AddPluginVertices(Game& game);
void AddPluginVertices(Game& game, const std::vector<std::string>& loadOrder);
void AddSpecificEdges();
void AddHardcodedPluginEdges(Game& game);
void AddGroupEdges(const std::unordered_set<Group>& groups);
+5 -3
View File
@@ -28,10 +28,12 @@
#include "api/sorting/plugin_graph.h"
namespace loot {
std::vector<std::string> SortPlugins(Game& game) {
std::vector<std::string> SortPlugins(
Game& game,
const std::vector<std::string>& loadOrder) {
PluginGraph graph;
graph.AddPluginVertices(game);
graph.AddPluginVertices(game, loadOrder);
// If there aren't any vertices, exit early, because sorting assumes
// there is at least one plugin.
@@ -41,7 +43,7 @@ std::vector<std::string> SortPlugins(Game& game) {
auto logger = getLogger();
if (logger) {
logger->info("Current load order: ");
for (const auto& plugin : game.GetLoadOrder()) {
for (const auto& plugin : loadOrder) {
logger->info("\t\t{}", plugin);
}
}
+2 -1
View File
@@ -31,7 +31,8 @@
#include "api/game/game.h"
namespace loot {
std::vector<std::string> SortPlugins(Game& game);
std::vector<std::string> SortPlugins(Game& game,
const std::vector<std::string>& loadOrder);
}
#endif
@@ -132,7 +132,7 @@ INSTANTIATE_TEST_CASE_P(,
GameType::fo4));
TEST_P(PluginSortTest, sortingWithNoLoadedPluginsShouldReturnAnEmptyList) {
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_TRUE(sorted.empty());
}
@@ -145,7 +145,7 @@ TEST_P(PluginSortTest,
// Check stability by running the sort 100 times.
for (int i = 0; i < 100; i++) {
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
ASSERT_EQ(expectedSortedOrder, sorted) << " for sort " << i;
}
}
@@ -182,7 +182,7 @@ TEST_P(PluginSortTest, sortingShouldResolveGroupsAsTransitiveLoadAfterSets) {
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -193,7 +193,7 @@ TEST_P(PluginSortTest, sortingShouldThrowIfAPluginHasAGroupThatDoesNotExist) {
plugin.SetGroup("group1");
game_.GetDatabase()->SetPluginUserMetadata(plugin);
EXPECT_THROW(SortPlugins(game_), UndefinedGroupError);
EXPECT_THROW(SortPlugins(game_, game_.GetLoadOrder()), UndefinedGroupError);
}
TEST_P(PluginSortTest,
@@ -225,7 +225,7 @@ TEST_P(PluginSortTest,
expectedSortedOrder.insert(expectedSortedOrder.begin() + 3, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -269,7 +269,7 @@ TEST_P(
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -309,7 +309,7 @@ TEST_P(
expectedSortedOrder.insert(expectedSortedOrder.begin() + 3, masterFile);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -334,7 +334,7 @@ TEST_P(
game_.GetDatabase()->SetPluginUserMetadata(plugin);
try {
SortPlugins(game_);
SortPlugins(game_, game_.GetLoadOrder());
FAIL();
} catch (CyclicInteractionError &e) {
ASSERT_EQ(3, e.GetCycle().size());
@@ -348,8 +348,9 @@ TEST_P(
}
}
TEST_P(PluginSortTest,
sortingShouldNotIgnoreIntermediatePluginsInAMultiGroupCycleIfTheEarlierPluginIsNotAMasterAndTheLaterIs) {
TEST_P(
PluginSortTest,
sortingShouldNotIgnoreIntermediatePluginsInAMultiGroupCycleIfTheEarlierPluginIsNotAMasterAndTheLaterIs) {
ASSERT_NO_THROW(loadInstalledPlugins(game_, false));
GenerateMasterlist();
@@ -383,7 +384,7 @@ TEST_P(PluginSortTest,
expectedSortedOrder.insert(expectedSortedOrder.begin() + 1, masterFile);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -421,7 +422,7 @@ TEST_P(
expectedSortedOrder.insert(expectedSortedOrder.begin() + 2, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -453,7 +454,7 @@ TEST_P(PluginSortTest,
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -485,7 +486,7 @@ TEST_P(PluginSortTest,
expectedSortedOrder.insert(expectedSortedOrder.begin() + 5, blankEsl);
}
std::vector<std::string> sorted = SortPlugins(game_);
std::vector<std::string> sorted = SortPlugins(game_, game_.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -516,7 +517,8 @@ TEST_P(PluginSortTest,
blankDifferentPluginDependentEsp,
});
std::vector<std::string> sorted = SortPlugins(newGame);
std::vector<std::string> sorted =
SortPlugins(newGame, newGame.GetLoadOrder());
EXPECT_EQ(expectedSortedOrder, sorted);
}
@@ -526,7 +528,8 @@ TEST_P(PluginSortTest, sortingShouldThrowIfACyclicInteractionIsEncountered) {
plugin.SetLoadAfterFiles({File(blankMasterDependentEsm)});
game_.GetDatabase()->SetPluginUserMetadata(plugin);
EXPECT_THROW(SortPlugins(game_), CyclicInteractionError);
EXPECT_THROW(SortPlugins(game_, game_.GetLoadOrder()),
CyclicInteractionError);
}
}
}