mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Some code refactoring.
This commit is contained in:
@@ -50,7 +50,6 @@ set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/globals.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/generators.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/sort.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/graph.cpp")
|
||||
|
||||
set (LOOT_GUI_SRC ${LOOT_SRC}
|
||||
|
||||
@@ -30,9 +30,12 @@
|
||||
#include "parsers.h"
|
||||
#include "streams.h"
|
||||
#include "generators.h"
|
||||
#include "graph.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -714,4 +717,53 @@ namespace loot {
|
||||
throw error(error::path_write_fail, lc::translate("Could not create LOOT folder for game. Details:").str() + " " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::list<Plugin> Game::Sort(const unsigned int language, std::function<void(const std::string&)> progressCallback) {
|
||||
//Create a plugin graph containing the plugin and masterlist data.
|
||||
loot::PluginGraph graph;
|
||||
|
||||
progressCallback("Building plugin graph...");
|
||||
BOOST_LOG_TRIVIAL(info) << "Merging masterlist, userlist into plugin list, evaluating conditions and checking for install validity.";
|
||||
for (const auto &plugin : this->plugins) {
|
||||
vertex_t v = boost::add_vertex(plugin.second, graph);
|
||||
list<loot::Plugin>::iterator pos;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[v].Name() << "\"";
|
||||
|
||||
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
|
||||
pos = std::find(this->masterlist.plugins.begin(), this->masterlist.plugins.end(), graph[v]);
|
||||
|
||||
if (pos != this->masterlist.plugins.end()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
|
||||
graph[v].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
|
||||
pos = std::find(this->userlist.plugins.begin(), this->userlist.plugins.end(), graph[v]);
|
||||
|
||||
if (pos != this->userlist.plugins.end() && pos->Enabled()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
|
||||
graph[v].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
//Now that items are merged, evaluate any conditions they have.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
|
||||
try {
|
||||
graph[v].EvalAllConditions(*this, language);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << graph[v].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
|
||||
list<Message> messages(graph[v].Messages());
|
||||
messages.push_back(loot::Message(loot::Message::error, (boost::format(lc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % graph[v].Name() % e.what()).str()));
|
||||
graph[v].Messages(messages);
|
||||
}
|
||||
|
||||
//Also check install validity.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
|
||||
graph[v].CheckInstallValidity(*this);
|
||||
}
|
||||
|
||||
// Now add edges and sort.
|
||||
progressCallback("Adding edges to plugin graph and performing topological sort...");
|
||||
return loot::Sort(graph);
|
||||
}
|
||||
}
|
||||
|
||||
+79
-67
@@ -22,6 +22,7 @@
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "error.h"
|
||||
#include "graph.h"
|
||||
#include "streams.h"
|
||||
#include "helpers.h"
|
||||
@@ -36,45 +37,47 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace lc = boost::locale;
|
||||
|
||||
namespace loot {
|
||||
|
||||
cycle_detector::cycle_detector() {}
|
||||
struct cycle_detector : public boost::dfs_visitor<> {
|
||||
cycle_detector() {}
|
||||
|
||||
void cycle_detector::tree_edge(edge_t e, const PluginGraph& g) {
|
||||
vertex_t source = boost::source(e, g);
|
||||
std::list<std::string> trail;
|
||||
|
||||
string name = g[source].Name();
|
||||
inline void tree_edge(edge_t e, const PluginGraph& g) {
|
||||
vertex_t source = boost::source(e, g);
|
||||
|
||||
// Check if the plugin already exists in the recorded trail.
|
||||
auto it = find(trail.begin(), trail.end(), name);
|
||||
string name = g[source].Name();
|
||||
|
||||
if (it != trail.end()) {
|
||||
// Erase everything from this position onwards, as it doesn't
|
||||
// contribute to a forward-cycle.
|
||||
trail.erase(it, trail.end());
|
||||
// Check if the plugin already exists in the recorded trail.
|
||||
auto it = find(trail.begin(), trail.end(), name);
|
||||
|
||||
if (it != trail.end()) {
|
||||
// Erase everything from this position onwards, as it doesn't
|
||||
// contribute to a forward-cycle.
|
||||
trail.erase(it, trail.end());
|
||||
}
|
||||
|
||||
trail.push_back(name);
|
||||
}
|
||||
|
||||
trail.push_back(name);
|
||||
}
|
||||
inline void back_edge(edge_t e, const PluginGraph& g) {
|
||||
vertex_t vSource = boost::source(e, g);
|
||||
vertex_t vTarget = boost::target(e, g);
|
||||
|
||||
void cycle_detector::back_edge(edge_t e, const PluginGraph& g) {
|
||||
vertex_t vSource = boost::source(e, g);
|
||||
vertex_t vTarget = boost::target(e, g);
|
||||
trail.push_back(g[vSource].Name());
|
||||
list<string>::iterator it = find(trail.begin(), trail.end(), g[vTarget].Name());
|
||||
string backCycle;
|
||||
for (list<string>::iterator endIt = trail.end(); it != endIt; ++it) {
|
||||
backCycle += *it + ", ";
|
||||
}
|
||||
backCycle.erase(backCycle.length() - 2);
|
||||
|
||||
trail.push_back(g[vSource].Name());
|
||||
list<string>::iterator it = find(trail.begin(), trail.end(), g[vTarget].Name());
|
||||
string backCycle;
|
||||
for (list<string>::iterator endIt = trail.end(); it != endIt; ++it) {
|
||||
backCycle += *it + ", ";
|
||||
BOOST_LOG_TRIVIAL(error) << "Cyclic interaction detected between plugins \"" << g[vSource].Name() << "\" and \"" << g[vTarget].Name() << "\". Back cycle: " << backCycle;
|
||||
|
||||
throw loot::error(loot::error::sorting_error, (boost::format(boost::locale::translate("Cyclic interaction detected between plugins \"%1%\" and \"%2%\". Back cycle: %3%")) % g[vSource].Name() % g[vTarget].Name() % backCycle).str());
|
||||
}
|
||||
backCycle.erase(backCycle.length() - 2);
|
||||
|
||||
BOOST_LOG_TRIVIAL(error) << "Cyclic interaction detected between plugins \"" << g[vSource].Name() << "\" and \"" << g[vTarget].Name() << "\". Back cycle: " << backCycle;
|
||||
|
||||
throw loot::error(loot::error::sorting_error, (boost::format(lc::translate("Cyclic interaction detected between plugins \"%1%\" and \"%2%\". Back cycle: %3%")) % g[vSource].Name() % g[vTarget].Name() % backCycle).str());
|
||||
}
|
||||
};
|
||||
|
||||
bool GetVertexByName(const PluginGraph& graph, const std::string& name, vertex_t& vertex) {
|
||||
vertex_it vit, vit_end;
|
||||
@@ -90,34 +93,7 @@ namespace loot {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<Plugin> Sort(const PluginGraph& graph) {
|
||||
|
||||
//Topological sort requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
|
||||
|
||||
map<vertex_t, size_t> index_map;
|
||||
boost::associative_property_map< map<vertex_t, size_t> > v_index_map(index_map);
|
||||
size_t i=0;
|
||||
BGL_FORALL_VERTICES(v, graph, PluginGraph)
|
||||
put(v_index_map, v, i++);
|
||||
|
||||
//Now we can sort.
|
||||
|
||||
std::list<vertex_t> sortedVertices;
|
||||
boost::topological_sort(graph, std::front_inserter(sortedVertices), boost::vertex_index_map(v_index_map));
|
||||
|
||||
/* Sorting now evaluates conditions inside the graph, so existing plugins list is missing
|
||||
data present in the graph, so we need to swap the two lists. */
|
||||
BOOST_LOG_TRIVIAL(info) << "Calculated order: ";
|
||||
list<Plugin> plugins;
|
||||
for (const auto &vertex: sortedVertices) {
|
||||
BOOST_LOG_TRIVIAL(info) << '\t' << graph[vertex].Name();
|
||||
plugins.push_back(graph[vertex]);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
void CheckForCycles(const PluginGraph& graph) {
|
||||
|
||||
//Depth-first search requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
|
||||
|
||||
map<vertex_t, size_t> index_map;
|
||||
@@ -130,7 +106,26 @@ namespace loot {
|
||||
boost::depth_first_search(graph, visitor(vis).vertex_index_map(v_index_map));
|
||||
}
|
||||
|
||||
void AddSpecificEdges(PluginGraph& graph, std::map<std::string, int>& overriddenPriorities) {
|
||||
bool EdgeCreatesCycle(PluginGraph& graph, vertex_t u, vertex_t v) {
|
||||
//A cycle is created when adding the edge (u,v) if there already exists a path from v to u, so check for that using a breadth-first search.
|
||||
|
||||
//Breadth-first search requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
|
||||
|
||||
map<vertex_t, size_t> index_map;
|
||||
boost::associative_property_map< map<vertex_t, size_t> > v_index_map(index_map);
|
||||
size_t i = 0;
|
||||
BGL_FORALL_VERTICES(v, graph, PluginGraph)
|
||||
put(v_index_map, v, i++);
|
||||
|
||||
map<vertex_t, vertex_t> predecessor_map;
|
||||
boost::associative_property_map< map<vertex_t, vertex_t> > v_predecessor_map(predecessor_map);
|
||||
|
||||
boost::breadth_first_search(graph, v, visitor(boost::make_bfs_visitor(boost::record_predecessors(v_predecessor_map, boost::on_tree_edge()))).vertex_index_map(v_index_map));
|
||||
|
||||
return predecessor_map.find(u) != predecessor_map.end();
|
||||
}
|
||||
|
||||
void AddSpecificEdges(PluginGraph& graph) {
|
||||
//Add edges for all relationships that aren't overlaps or priority differences.
|
||||
loot::vertex_it vit, vitend;
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
@@ -224,7 +219,6 @@ namespace loot {
|
||||
//Set the current plugin's priority to parentPlugin.
|
||||
if (parentPriority > 0 && graph[*vit].Priority() < parentPriority) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Overriding priority for " << graph[*vit].Name() << " from " << graph[*vit].Priority() << " to " << parentPriority;
|
||||
overriddenPriorities.insert(pair<string, int>(graph[*vit].Name(), graph[*vit].Priority()));
|
||||
graph[*vit].Priority(parentPriority);
|
||||
}
|
||||
|
||||
@@ -236,7 +230,7 @@ namespace loot {
|
||||
|
||||
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding priority difference edges to vertex for \"" << graph[*vit].Name() << "\".";
|
||||
//Priority differences should only be taken account between plugins that conflict.
|
||||
//Priority differences should only be taken account between plugins that conflict.
|
||||
//However, an exception is made for plugins that contain only a header record,
|
||||
//as they are for loading BSAs, and in Skyrim that means the resources they load can
|
||||
//be affected by load order.
|
||||
@@ -244,7 +238,7 @@ namespace loot {
|
||||
loot::vertex_it vit2, vitend2;
|
||||
for (boost::tie(vit2, vitend2) = boost::vertices(graph); vit2 != vitend2; ++vit2) {
|
||||
|
||||
if (graph[*vit].Priority() == graph[*vit2].Priority()
|
||||
if (graph[*vit].Priority() == graph[*vit2].Priority()
|
||||
|| (abs(graph[*vit].Priority()) < max_priority && abs(graph[*vit2].Priority()) < max_priority
|
||||
&& !graph[*vit].FormIDs().empty() && !graph[*vit2].FormIDs().empty() && !graph[*vit].DoFormIDsOverlap(graph[*vit2])
|
||||
)
|
||||
@@ -327,22 +321,40 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
|
||||
bool EdgeCreatesCycle(PluginGraph& graph, vertex_t u, vertex_t v) {
|
||||
//A cycle is created when adding the edge (u,v) if there already exists a path from v to u, so check for that using a breadth-first search.
|
||||
std::list<Plugin> Sort(PluginGraph& graph) {
|
||||
|
||||
//Breadth-first search requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
|
||||
//Now add the interactions between plugins to the graph as edges.
|
||||
BOOST_LOG_TRIVIAL(info) << "Adding edges to plugin graph.";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding non-overlap edges.";
|
||||
AddSpecificEdges(graph);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding priority edges.";
|
||||
AddPriorityEdges(graph);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding overlap edges.";
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Checking to see if the graph is cyclic.";
|
||||
CheckForCycles(graph);
|
||||
|
||||
//Topological sort requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
|
||||
map<vertex_t, size_t> index_map;
|
||||
boost::associative_property_map< map<vertex_t, size_t> > v_index_map(index_map);
|
||||
size_t i=0;
|
||||
BGL_FORALL_VERTICES(v, graph, PluginGraph)
|
||||
put(v_index_map, v, i++);
|
||||
|
||||
map<vertex_t, vertex_t> predecessor_map;
|
||||
boost::associative_property_map< map<vertex_t, vertex_t> > v_predecessor_map(predecessor_map);
|
||||
//Now we can sort.
|
||||
BOOST_LOG_TRIVIAL(info) << "Performing a topological sort.";
|
||||
list<vertex_t> sortedVertices;
|
||||
boost::topological_sort(graph, std::front_inserter(sortedVertices), boost::vertex_index_map(v_index_map));
|
||||
|
||||
boost::breadth_first_search(graph, v, visitor(boost::make_bfs_visitor(boost::record_predecessors(v_predecessor_map, boost::on_tree_edge()))).vertex_index_map(v_index_map));
|
||||
|
||||
return predecessor_map.find(u) != predecessor_map.end();
|
||||
// Output a plugin list using the sorted vertices.
|
||||
BOOST_LOG_TRIVIAL(info) << "Calculated order: ";
|
||||
list<Plugin> plugins;
|
||||
for (const auto &vertex: sortedVertices) {
|
||||
BOOST_LOG_TRIVIAL(info) << '\t' << graph[vertex].Name();
|
||||
plugins.push_back(graph[vertex]);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-25
@@ -26,9 +26,6 @@
|
||||
#define __LOOT_GRAPH__
|
||||
|
||||
#include "metadata.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
@@ -43,28 +40,7 @@ namespace loot {
|
||||
typedef boost::graph_traits<PluginGraph>::edge_descriptor edge_t;
|
||||
typedef boost::graph_traits<PluginGraph>::edge_iterator edge_it;
|
||||
|
||||
struct cycle_detector : public boost::dfs_visitor<> {
|
||||
cycle_detector();
|
||||
|
||||
std::list<std::string> trail;
|
||||
|
||||
void tree_edge(edge_t e, const PluginGraph& g);
|
||||
void back_edge(edge_t e, const PluginGraph& g);
|
||||
};
|
||||
|
||||
bool GetVertexByName(const PluginGraph& graph, const std::string& name, vertex_t& vertex);
|
||||
|
||||
std::list<Plugin> Sort(const PluginGraph& graph);
|
||||
|
||||
void CheckForCycles(const PluginGraph& graph);
|
||||
|
||||
void AddSpecificEdges(PluginGraph& graph, std::map<std::string, int>& overriddenPriorities);
|
||||
|
||||
void AddPriorityEdges(PluginGraph& graph);
|
||||
|
||||
void AddOverlapEdges(PluginGraph& graph);
|
||||
|
||||
bool EdgeCreatesCycle(PluginGraph& graph, vertex_t u, vertex_t v);
|
||||
std::list<Plugin> Sort(PluginGraph& graph);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2014 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "game.h"
|
||||
#include "helpers.h"
|
||||
#include "graph.h"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
using boost::format;
|
||||
|
||||
namespace loc = boost::locale;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace loot {
|
||||
|
||||
std::list<Plugin> Game::Sort(const unsigned int language, std::function<void(const std::string&)> progressCallback) {
|
||||
//Create a plugin graph containing the plugin and masterlist data.
|
||||
loot::PluginGraph graph;
|
||||
|
||||
progressCallback("Building plugin graph...");
|
||||
BOOST_LOG_TRIVIAL(info) << "Merging masterlist, userlist into plugin list, evaluating conditions and checking for install validity.";
|
||||
for (const auto &plugin : this->plugins) {
|
||||
vertex_t v = boost::add_vertex(plugin.second, graph);
|
||||
list<loot::Plugin>::iterator pos;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[v].Name() << "\"";
|
||||
|
||||
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
|
||||
pos = std::find(this->masterlist.plugins.begin(), this->masterlist.plugins.end(), graph[v]);
|
||||
|
||||
if (pos != this->masterlist.plugins.end()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
|
||||
graph[v].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
|
||||
pos = std::find(this->userlist.plugins.begin(), this->userlist.plugins.end(), graph[v]);
|
||||
|
||||
if (pos != this->userlist.plugins.end() && pos->Enabled()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
|
||||
graph[v].MergeMetadata(*pos);
|
||||
}
|
||||
|
||||
//Now that items are merged, evaluate any conditions they have.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
|
||||
try {
|
||||
graph[v].EvalAllConditions(*this, language);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << graph[v].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
|
||||
list<Message> messages(graph[v].Messages());
|
||||
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % graph[v].Name() % e.what()).str()));
|
||||
graph[v].Messages(messages);
|
||||
}
|
||||
|
||||
//Also check install validity.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
|
||||
graph[v].CheckInstallValidity(*this);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Building the plugin dependency graph...";
|
||||
|
||||
//Now add the interactions between plugins to the graph as edges.
|
||||
std::map<std::string, int> overriddenPriorities;
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding non-overlap edges.";
|
||||
loot::AddSpecificEdges(graph, overriddenPriorities);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding priority edges.";
|
||||
loot::AddPriorityEdges(graph);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Adding overlap edges.";
|
||||
loot::AddOverlapEdges(graph);
|
||||
|
||||
progressCallback("Checking for graph cycles...");
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Checking to see if the graph is cyclic.";
|
||||
loot::CheckForCycles(graph);
|
||||
|
||||
for (const auto &overriddenPriority : overriddenPriorities) {
|
||||
vertex_t vertex;
|
||||
if (loot::GetVertexByName(graph, overriddenPriority.first, vertex)) {
|
||||
graph[vertex].Priority(overriddenPriority.second);
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Performing a topological sort.";
|
||||
progressCallback("Performing topological sort...");
|
||||
return loot::Sort(graph);
|
||||
}
|
||||
}
|
||||
@@ -188,8 +188,6 @@ namespace loot {
|
||||
//Sort plugins into their load order.
|
||||
list<Plugin> plugins = g_app_state.CurrentGame().Sort(language, [](const string& message){});
|
||||
|
||||
map<string, uint32_t> crcs;
|
||||
list<string> loadOrder;
|
||||
YAML::Node node;
|
||||
for (const auto &plugin : plugins) {
|
||||
node["loadOrder"].push_back(plugin.Name());
|
||||
|
||||
Reference in New Issue
Block a user