Sorting tweaks.

* Removed unused functions.
* Tidied up edge addition.
* The plugin graph now stores plugin properties directly, rather than
pointing to plugins in an external container.
* The plugin graph is now used to hold the installed plugins from the
beginning of the sorting process. The plugins list is still built up in
case sorting the graph fails.
This commit is contained in:
WrinklyNinja
2013-09-09 17:09:49 +01:00
parent fc3f27a062
commit b8d2f9f81b
3 changed files with 127 additions and 203 deletions
+80 -132
View File
@@ -31,96 +31,13 @@
using namespace std;
namespace boss {
vertex_t GetPluginVertex(PluginGraph& graph, const Plugin& plugin, boost::unordered_map<std::string, vertex_t>& pluginVertexMap) {
vertex_t vertex;
string name = boost::to_lower_copy(plugin.Name());
boost::unordered_map<string, vertex_t>::iterator vertexMapIt = pluginVertexMap.find(name);
if (vertexMapIt == pluginVertexMap.end()) {
BOOST_LOG_TRIVIAL(trace) << "Vertex for \"" << name << "\" doesn't exist, creating one.";
Plugin p;
// vertex = boost::add_vertex(p, graph);
BOOST_LOG_TRIVIAL(trace) << "Adding vertex to map.";
pluginVertexMap.emplace(name, vertex);
} else
vertex = vertexMapIt->second;
return vertex;
}
//The map maps each plugin name to a vector of names of plugins that overlap with it and should load before it.
void CalcPluginOverlaps(const std::list<Plugin>& plugins, boost::unordered_map< std::string, std::vector<std::string> >& overlapMap) {
for (list<Plugin>::const_iterator it=plugins.begin(),
endit=plugins.end();
it != endit;
++it) {
list<Plugin>::const_iterator jt = it;
++jt;
for (; jt != endit; ++jt) {
BOOST_LOG_TRIVIAL(trace) << "Checking for FormID overlap between \"" << it->Name() << "\" and \"" << jt->Name() << "\".";
if (it->DoFormIDsOverlap(*jt)) {
std::string key;
std::string value;
//Priority values should override the number of override records as the deciding factor if they differ.
if (it->MustLoadAfter(*jt) || jt->MustLoadAfter(*it) || it->Priority() != jt->Priority())
continue;
if (it->NumOverrideFormIDs() >= jt->NumOverrideFormIDs()) {
key = jt->Name();
value = it->Name();
} else {
key = it->Name();
value = jt->Name();
}
boost::unordered_map< string, vector<string> >::iterator mapIt = overlapMap.find(key);
if (mapIt == overlapMap.end()) {
overlapMap.insert(pair<string, vector<string> >(key, vector<string>(1, value)));
} else {
mapIt->second.push_back(value);
}
}
}
}
}
void CalcPriorityMap(const std::list<Plugin>& plugins, boost::unordered_map< std::string, std::vector<std::string> >& priorityMap) {
for (list<Plugin>::const_iterator it=plugins.begin(),
endit=plugins.end();
it != endit;
++it) {
list<Plugin>::const_iterator jt = it;
++jt;
for (; jt != endit; ++jt) {
BOOST_LOG_TRIVIAL(trace) << "Checking for priority difference between \"" << it->Name() << "\" and \"" << jt->Name() << "\".";
if (it->MustLoadAfter(*jt) || jt->MustLoadAfter(*it) || it->Priority() == jt->Priority())
continue;
std::string key;
std::string value;
if (it->Priority() < jt->Priority()) {
key = jt->Name();
value = it->Name();
} else if (jt->Priority() < it->Priority()) {
key = it->Name();
value = jt->Name();
}
boost::unordered_map< string, vector<string> >::iterator mapIt = priorityMap.find(key);
if (mapIt == priorityMap.end()) {
priorityMap.insert(pair<string, vector<string> >(key, vector<string>(1, value)));
} else {
mapIt->second.push_back(value);
}
}
}
}
bool GetVertexByName(const PluginGraph& graph, const std::string& name, vertex_t& vertex) {
vertex_it vit, vit_end;
boost::tie(vit, vit_end) = boost::vertices(graph);
for (vit, vit_end; vit != vit_end; ++vit) {
if (boost::iequals(graph[*vit]->Name(), name)) {
// if (graph[*vit]->Name() == name) {
if (boost::iequals(graph[*vit].Name(), name)) {
vertex = *vit;
return true;
}
@@ -136,7 +53,7 @@ namespace boss {
boost::tie(vit, vit_end) = boost::vertices(graph);
for (vit, vit_end; vit != vit_end; ++vit) {
names.push_back(graph[*vit]->Name());
names.push_back(graph[*vit].Name());
}
//Also, writing the graph requires an index map, which std::list-based VertexList graphs don't have, so one needs to be built separately.
@@ -144,7 +61,7 @@ namespace boss {
map<vertex_t, string> index_map;
boost::associative_property_map< map<vertex_t, string> > v_index_map(index_map);
BGL_FORALL_VERTICES(v, graph, PluginGraph)
put(v_index_map, v, graph[v]->Name());
put(v_index_map, v, graph[v].Name());
//Now write graph to file.
boss::ofstream out(outpath);
@@ -170,8 +87,8 @@ namespace boss {
BOOST_LOG_TRIVIAL(info) << "Calculated order: ";
list<boss::Plugin> tempPlugins;
for (std::list<vertex_t>::iterator it = sortedVertices.begin(), endit = sortedVertices.end(); it != endit; ++it) {
BOOST_LOG_TRIVIAL(info) << '\t' << graph[*it]->Name();
tempPlugins.push_back(*graph[*it]);
BOOST_LOG_TRIVIAL(info) << '\t' << graph[*it].Name();
tempPlugins.push_back(graph[*it]);
}
plugins.swap(tempPlugins);
}
@@ -190,11 +107,11 @@ namespace boss {
boost::depth_first_search(graph, visitor(vis).vertex_index_map(v_index_map));
}
void AddNonOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector<std::string> >& priorityMap) {
void AddNonOverlapEdges(PluginGraph& graph) {
//First find the position of the first non-master.
boss::vertex_it vitFirstNonMaster, vit, vitend;
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
if (!graph[*vit]->IsMaster()) {
if (!graph[*vit].IsMaster()) {
vitFirstNonMaster = vit;
break;
}
@@ -204,107 +121,138 @@ namespace boss {
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
vertex_t parentVertex;
BOOST_LOG_TRIVIAL(trace) << "Adding non-overlap in-edges to vertex for \"" << graph[*vit]->Name() << "\".";
BOOST_LOG_TRIVIAL(trace) << "Adding non-overlap edges to vertex for \"" << graph[*vit].Name() << "\".";
if (graph[*vit]->IsMaster()) {
BOOST_LOG_TRIVIAL(trace) << "Adding out-edges for non-master plugins.";
BOOST_LOG_TRIVIAL(trace) << "Adding edges for master flag differences.";
for (boss::vertex_it vit2 = vitFirstNonMaster; vit2 != vitend; ++vit2) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[*vit]->Name() << "\" to \"" << graph[*vit2]->Name() << "\".";
boss::vertex_it vit2 = vit;
++vit2;
for (vit2,vitend; vit2 != vitend; ++vit2) {
if (!boost::edge(*vit, *vit2, graph).second) //To avoid duplicates (helps visualisation).
boost::add_edge(*vit, *vit2, graph);
if (graph[*vit].IsMaster() == graph[*vit2].IsMaster())
continue;
vertex_t vertex, parentVertex;
if (graph[*vit2].IsMaster()) {
parentVertex = *vit2;
vertex = *vit;
} else {
parentVertex = *vit;
vertex = *vit2;
}
if (!boost::edge(parentVertex, vertex, graph).second) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[vertex].Name() << "\".";
boost::add_edge(parentVertex, vertex, graph);
}
}
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for masters.";
vector<string> strVec(graph[*vit]->Masters());
vector<string> strVec(graph[*vit].Masters());
for (vector<string>::const_iterator it=strVec.begin(), itend=strVec.end(); it != itend; ++it) {
if (boss::GetVertexByName(graph, *it, parentVertex) &&
!boost::edge(parentVertex, *vit, graph).second) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\".";
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[*vit].Name() << "\".";
boost::add_edge(parentVertex, *vit, graph);
}
}
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for requirements.";
set<File> fileset(graph[*vit]->Reqs());
set<File> fileset(graph[*vit].Reqs());
for (set<File>::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) {
if (boss::IsPlugin(it->Name()) &&
boss::GetVertexByName(graph, it->Name(), parentVertex) &&
!boost::edge(parentVertex, *vit, graph).second) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\".";
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[*vit].Name() << "\".";
boost::add_edge(parentVertex, *vit, graph);
}
}
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for 'load after's.";
fileset = graph[*vit]->LoadAfter();
fileset = graph[*vit].LoadAfter();
for (set<File>::const_iterator it=fileset.begin(), itend=fileset.end(); it != itend; ++it) {
if (boss::IsPlugin(it->Name()) &&
boss::GetVertexByName(graph, it->Name(), parentVertex) &&
!boost::edge(parentVertex, *vit, graph).second) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\".";
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[*vit].Name() << "\".";
boost::add_edge(parentVertex, *vit, graph);
}
}
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for priority differences.";
boost::unordered_map< string, vector<string> >::const_iterator priorityIt = priorityMap.find(graph[*vit]->Name());
if (priorityIt != priorityMap.end()) {
for (vector<string>::const_iterator it=priorityIt->second.begin(), itend=priorityIt->second.end(); it != itend; ++it) {
if (boss::GetVertexByName(graph, *it, parentVertex) &&
!boost::edge(parentVertex, *vit, graph).second &&
!EdgeCreatesCycle(graph, parentVertex, *vit)) { //No edge going the other way, OK to add this edge.
BOOST_LOG_TRIVIAL(trace) << "Adding edges for priority differences.";
vit2 = vit;
++vit2;
for (vit2,vitend; vit2 != vitend; ++vit2) {
BOOST_LOG_TRIVIAL(trace) << "Checking for priority difference between \"" << graph[*vit].Name() << "\" and \"" << graph[*vit2].Name() << "\".";
if (graph[*vit].MustLoadAfter(graph[*vit2]) || graph[*vit2].MustLoadAfter(graph[*vit]) || graph[*vit].Priority() == graph[*vit2].Priority())
continue;
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\".";
vertex_t vertex, parentVertex;
if (graph[*vit].Priority() < graph[*vit2].Priority()) {
parentVertex = *vit2;
vertex = *vit;
} else {
parentVertex = *vit;
vertex = *vit2;
}
boost::add_edge(parentVertex, *vit, graph);
}
if (!boost::edge(parentVertex, vertex, graph).second &&
!EdgeCreatesCycle(graph, parentVertex, vertex)) { //No edge going the other way, OK to add this edge.
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[vertex].Name() << "\".";
boost::add_edge(parentVertex, vertex, graph);
}
}
}
}
void AddOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector<std::string> >& overlapMap) {
void AddOverlapEdges(PluginGraph& graph) {
boss::vertex_it vit, vitend;
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
vertex_t parentVertex;
BOOST_LOG_TRIVIAL(trace) << "Adding overlap in-edges to vertex for \"" << graph[*vit]->Name() << "\".";
BOOST_LOG_TRIVIAL(trace) << "Adding overlap edges to vertex for \"" << graph[*vit].Name() << "\".";
boss::vertex_it vit2 = vit;
++vit2;
for (vit2,vitend; vit2 != vitend; ++vit2) {
BOOST_LOG_TRIVIAL(trace) << "Checking for FormID overlap between \"" << graph[*vit].Name() << "\" and \"" << graph[*vit2].Name() << "\".";
//Now add any overlaps, except where an edge already exists between the two plugins, going the other way, since overlap-based edges have the lowest priority and are not a candidate for causing cyclic loop errors.
boost::unordered_map< string, vector<string> >::const_iterator overlapIt = overlapMap.find(graph[*vit]->Name());
if (overlapIt != overlapMap.end()) {
for (vector<string>::const_iterator it=overlapIt->second.begin(), itend=overlapIt->second.end(); it != itend; ++it) {
if (boss::GetVertexByName(graph, *it, parentVertex) &&
!boost::edge(parentVertex, *vit, graph).second &&
!EdgeCreatesCycle(graph, parentVertex, *vit)) { //No edge going the other way, OK to add this edge.
if (graph[*vit].DoFormIDsOverlap(graph[*vit2])) {
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex]->Name() << "\" to \"" << graph[*vit]->Name() << "\".";
if (graph[*vit].MustLoadAfter(graph[*vit2]) || graph[*vit2].MustLoadAfter(graph[*vit]) || graph[*vit].Priority() != graph[*vit2].Priority())
continue;
boost::add_edge(parentVertex, *vit, graph);
vertex_t vertex, parentVertex;
if (graph[*vit].NumOverrideFormIDs() >= graph[*vit2].NumOverrideFormIDs()) {
parentVertex = *vit2;
vertex = *vit;
} else {
parentVertex = *vit;
vertex = *vit2;
}
if (!boost::edge(parentVertex, vertex, graph).second &&
!EdgeCreatesCycle(graph, parentVertex, vertex)) { //No edge going the other way, OK to add this edge.
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << graph[parentVertex].Name() << "\" to \"" << graph[vertex].Name() << "\".";
boost::add_edge(parentVertex, vertex, graph);
}
}
}
}
}
void ClearEdges(PluginGraph& graph) {
edge_it it, itend;
for (boost::tie(it, itend) = boost::edges(graph); it != itend; ++it) {
boost::remove_edge(*it, graph);
}
}
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.
+4 -14
View File
@@ -35,7 +35,7 @@
namespace boss {
typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, std::list<boss::Plugin>::iterator> PluginGraph;
typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, boss::Plugin> PluginGraph;
typedef boost::graph_traits<PluginGraph>::vertex_descriptor vertex_t;
typedef boost::graph_traits<PluginGraph>::vertex_iterator vertex_it;
typedef boost::graph_traits<PluginGraph>::edge_descriptor edge_t;
@@ -48,18 +48,10 @@ namespace boss {
vertex_t vSource = boost::source(e, g);
vertex_t vTarget = boost::target(e, g);
throw boss::error(boss::error::sorting_error, "Back edge detected between plugins \"" + g[vSource]->Name() + "\" and \"" + g[vTarget]->Name() + "\".");
throw boss::error(boss::error::sorting_error, "Back edge detected between plugins \"" + g[vSource].Name() + "\" and \"" + g[vTarget].Name() + "\".");
}
};
//Gets the vertex for the plugin if it exists, or creates one if it doesn't.
vertex_t GetPluginVertex(PluginGraph& graph, const Plugin& plugin, boost::unordered_map<std::string, vertex_t>& pluginVertexMap);
//The map maps each plugin name to a vector of names of plugins that overlap with it and should load before it.
void CalcPluginOverlaps(const std::list<Plugin>& plugins, boost::unordered_map< std::string, std::vector<std::string> >& overlapMap);
void CalcPriorityMap(const std::list<Plugin>& plugins, boost::unordered_map< std::string, std::vector<std::string> >& priorityMap);
bool GetVertexByName(const PluginGraph& graph, const std::string& name, vertex_t& vertex);
void SaveGraph(const PluginGraph& graph, const boost::filesystem::path outpath);
@@ -68,11 +60,9 @@ namespace boss {
void CheckForCycles(const PluginGraph& graph);
void AddNonOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector<std::string> >& priorityMap);
void AddNonOverlapEdges(PluginGraph& graph);
void AddOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector<std::string> >& overlapMap);
void ClearEdges(PluginGraph& graph);
void AddOverlapEdges(PluginGraph& graph);
bool EdgeCreatesCycle(PluginGraph& graph, vertex_t u, vertex_t v);
}
+43 -57
View File
@@ -88,19 +88,22 @@ struct plugin_loader {
};
struct plugin_list_loader {
plugin_list_loader(list<boss::Plugin>& plugins, boss::Game& game) : _plugins(plugins), _game(game) {}
plugin_list_loader(PluginGraph& graph, boss::Game& game) : _graph(graph), _game(game) {}
void operator () () {
for (list<boss::Plugin>::iterator it=_plugins.begin(), endit=_plugins.end(); it != endit; ++it) {
if (skipPlugins.find(it->Name()) == skipPlugins.end()) {
BOOST_LOG_TRIVIAL(info) << "Loading: " << it->Name();
*it = boss::Plugin(_game, it->Name(), false);
BOOST_LOG_TRIVIAL(info) << "Finished loading: " << it->Name();
boss::vertex_it vit, vitend;
for (boost::tie(vit, vitend) = boost::vertices(_graph); vit != vitend; ++vit) {
if (skipPlugins.find(_graph[*vit].Name()) == skipPlugins.end()) {
BOOST_LOG_TRIVIAL(info) << "Loading: " << _graph[*vit].Name();
boss::Plugin plugin(_game, _graph[*vit].Name(), false);
BOOST_LOG_TRIVIAL(trace) << "Merging plugin into existing data.";
_graph[*vit].Merge(plugin);
BOOST_LOG_TRIVIAL(info) << "Finished loading: " << _graph[*vit].Name();
}
}
}
list<boss::Plugin>& _plugins;
PluginGraph& _graph;
boss::Game& _game;
set<string> skipPlugins;
};
@@ -452,8 +455,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
YAML::Node mlist, ulist;
list<boss::Message> messages, mlist_messages, ulist_messages;
list<boss::Plugin> mlist_plugins, ulist_plugins;
boost::thread_group group;
list<boss::Plugin> plugins;
boost::thread_group group;
boss::PluginGraph graph;
string revision;
wxProgressDialog *progDia = new wxProgressDialog(translate("BOSS: Working..."),translate("BOSS working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME);
@@ -463,29 +467,30 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
//First calculate the mean plugin size. Store it temporarily in a map to reduce filesystem lookups and file size recalculation.
size_t meanFileSize = 0;
boost::unordered_map<boss::Plugin, size_t, plugin_hash> tempMap;
boost::unordered_map<std::string, size_t> tempMap;
for (fs::directory_iterator it(_game.DataPath()); it != fs::directory_iterator(); ++it) {
if (fs::is_regular_file(it->status()) && IsPlugin(it->path().string())) {
size_t fileSize = fs::file_size(it->path());
meanFileSize += fileSize;
tempMap.emplace(boss::Plugin(it->path().filename().string()), fileSize);
tempMap.emplace(it->path().filename().string(), fileSize);
plugins.push_back(boss::Plugin(it->path().filename().string())); //Just in case there's an error with the graph.
}
}
meanFileSize /= tempMap.size();
//Now load plugins.
plugin_list_loader pll(plugins, _game);
for (boost::unordered_map<boss::Plugin, size_t, plugin_hash>::const_iterator it=tempMap.begin(), endit=tempMap.end(); it != endit; ++it) {
plugin_list_loader pll(graph, _game);
for (boost::unordered_map<string, size_t>::const_iterator it=tempMap.begin(), endit=tempMap.end(); it != endit; ++it) {
BOOST_LOG_TRIVIAL(trace) << "Found plugin: " << it->first.Name();
BOOST_LOG_TRIVIAL(trace) << "Found plugin: " << it->first;
plugins.push_back(it->first);
vertex_t v = boost::add_vertex(boss::Plugin(_game, it->first, false), graph);
if (it->second > meanFileSize) {
plugin_loader pl(plugins.back(), _game);
pll.skipPlugins.insert(it->first.Name());
plugin_loader pl(graph[v], _game);
pll.skipPlugins.insert(it->first);
group.create_thread(pl);
}
@@ -544,22 +549,22 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
//Merge plugin list, masterlist and userlist plugin data.
BOOST_LOG_TRIVIAL(trace) << "Merging plugin list, masterlist and userlist data.";
map<string, bool> consistencyIssues;
for (list<boss::Plugin>::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << it->Name() << "\"";
boss::vertex_it vit, vitend;
for (boost::tie(vit, vitend) = boost::vertices(graph); vit != vitend; ++vit) {
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[*vit].Name() << "\"";
//Check if there is already a plugin in the 'plugins' list or not.
list<boss::Plugin>::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), *it);
list<boss::Plugin>::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), graph[*vit]);
if (pos != mlist_plugins.end()) {
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
it->Merge(*pos);
graph[*vit].Merge(*pos);
}
pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), *it);
pos = std::find(ulist_plugins.begin(), ulist_plugins.end(), graph[*vit]);
if (pos != ulist_plugins.end()) {
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
it->Merge(*pos);
graph[*vit].Merge(*pos);
}
progDia->Pulse();
@@ -567,29 +572,29 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
//Now that items are merged, evaluate any conditions they have.
BOOST_LOG_TRIVIAL(trace) << "Evaluate conditions for merged plugin data.";
try {
it->EvalAllConditions(_game, lang);
graph[*vit].EvalAllConditions(_game, lang);
} catch (boss::error& e) {
BOOST_LOG_TRIVIAL(error) << "\"" << it->Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % it->Name() % e.what()).str()));
BOOST_LOG_TRIVIAL(error) << "\"" << graph[*vit].Name() << "\" contains a condition that could not be evaluated. Details: " << e.what();
messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" contains a condition that could not be evaluated. Details: %2%")) % graph[*vit].Name() % e.what()).str()));
}
progDia->Pulse();
//Also check install validity.
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
map<string, bool> issues = it->CheckInstallValidity(_game);
list<boss::Message> pluginMessages = it->Messages();
map<string, bool> issues = graph[*vit].CheckInstallValidity(_game);
list<boss::Message> pluginMessages = graph[*vit].Messages();
for (map<string,bool>::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) {
if (jt->second) {
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is incompatible with \"" << it->Name() << "\" and is present.";
pluginMessages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is incompatible with \"%2%\" and is present.")) % jt->first % it->Name()).str()));
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is incompatible with \"" << graph[*vit].Name() << "\" and is present.";
pluginMessages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is incompatible with \"%2%\" and is present.")) % jt->first % graph[*vit].Name()).str()));
} else {
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is required by \"" << it->Name() << "\" but is missing.";
pluginMessages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is required by \"%2%\" but is missing.")) % jt->first % it->Name()).str()));
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is required by \"" << graph[*vit].Name() << "\" but is missing.";
pluginMessages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is required by \"%2%\" but is missing.")) % jt->first % graph[*vit].Name()).str()));
}
}
if (!issues.empty())
it->Messages(pluginMessages);
graph[*vit].Messages(pluginMessages);
progDia->Pulse();
}
@@ -597,36 +602,17 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
progDia->Pulse();
BOOST_LOG_TRIVIAL(trace) << "Moving masters before non-masters.";
plugins.sort(boss::master_sort);
progDia->Pulse();
BOOST_LOG_TRIVIAL(trace) << "Building plugin overlap map.";
boost::unordered_map< string, vector<string> > overlapMap;
CalcPluginOverlaps(plugins, overlapMap);
BOOST_LOG_TRIVIAL(trace) << "Building plugin priority map.";
boost::unordered_map< string, vector<string> > priorityMap;
CalcPriorityMap(plugins, priorityMap);
progDia->Pulse();
BOOST_LOG_TRIVIAL(trace) << "Building the plugin dependency graph...";
//Use an adjacency list (don't know yet if list or matrix is the better choice), and use "listS" as the VertexList type. We need a possible multi-graph to catch some forms of cyclic dependency (a working graph would not be a multi-graph though), so use "listS". Want a directed graph where we can access in-edges, so use "bidirectionalS". Also provide the boss::Plugin class as the vertex property type.
boss::PluginGraph graph;
//Now add the plugins in order to the graph as vertices.
for (list<boss::Plugin>::iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
BOOST_LOG_TRIVIAL(trace) << "Creating vertex for \"" << it->Name() << "\".";
boost::add_vertex(it, graph);
}
//Now add the interactions between plugins to the graph as edges.
BOOST_LOG_TRIVIAL(trace) << "Adding non-overlap edges.";
AddNonOverlapEdges(graph);
AddNonOverlapEdges(graph, priorityMap);
AddOverlapEdges(graph, overlapMap);
BOOST_LOG_TRIVIAL(trace) << "Adding overlap edges.";
AddOverlapEdges(graph);
//First delete any existing graph file.
fs::remove(_game.GraphPath());