mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
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:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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_);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user