diff --git a/src/backend/graph.cpp b/src/backend/graph.cpp index 21643a47..c4779110 100644 --- a/src/backend/graph.cpp +++ b/src/backend/graph.cpp @@ -31,96 +31,13 @@ using namespace std; namespace boss { - vertex_t GetPluginVertex(PluginGraph& graph, const Plugin& plugin, boost::unordered_map& pluginVertexMap) { - - vertex_t vertex; - string name = boost::to_lower_copy(plugin.Name()); - - boost::unordered_map::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& plugins, boost::unordered_map< std::string, std::vector >& overlapMap) { - for (list::const_iterator it=plugins.begin(), - endit=plugins.end(); - it != endit; - ++it) { - list::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 >::iterator mapIt = overlapMap.find(key); - if (mapIt == overlapMap.end()) { - overlapMap.insert(pair >(key, vector(1, value))); - } else { - mapIt->second.push_back(value); - } - } - } - } - } - - void CalcPriorityMap(const std::list& plugins, boost::unordered_map< std::string, std::vector >& priorityMap) { - for (list::const_iterator it=plugins.begin(), - endit=plugins.end(); - it != endit; - ++it) { - list::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 >::iterator mapIt = priorityMap.find(key); - if (mapIt == priorityMap.end()) { - priorityMap.insert(pair >(key, vector(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 index_map; boost::associative_property_map< map > 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 tempPlugins; for (std::list::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 >& 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 strVec(graph[*vit]->Masters()); + vector strVec(graph[*vit].Masters()); for (vector::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 fileset(graph[*vit]->Reqs()); + set fileset(graph[*vit].Reqs()); for (set::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::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 >::const_iterator priorityIt = priorityMap.find(graph[*vit]->Name()); - if (priorityIt != priorityMap.end()) { - for (vector::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 >& 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 >::const_iterator overlapIt = overlapMap.find(graph[*vit]->Name()); - if (overlapIt != overlapMap.end()) { - for (vector::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. diff --git a/src/backend/graph.h b/src/backend/graph.h index d97f5c4d..b3cdeb32 100644 --- a/src/backend/graph.h +++ b/src/backend/graph.h @@ -35,7 +35,7 @@ namespace boss { - typedef boost::adjacency_list::iterator> PluginGraph; + typedef boost::adjacency_list PluginGraph; typedef boost::graph_traits::vertex_descriptor vertex_t; typedef boost::graph_traits::vertex_iterator vertex_it; typedef boost::graph_traits::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& 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& plugins, boost::unordered_map< std::string, std::vector >& overlapMap); - - void CalcPriorityMap(const std::list& plugins, boost::unordered_map< std::string, std::vector >& 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 >& priorityMap); + void AddNonOverlapEdges(PluginGraph& graph); - void AddOverlapEdges(PluginGraph& graph, const boost::unordered_map< std::string, std::vector >& overlapMap); - - void ClearEdges(PluginGraph& graph); + void AddOverlapEdges(PluginGraph& graph); bool EdgeCreatesCycle(PluginGraph& graph, vertex_t u, vertex_t v); } diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 06a38022..66106761 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -88,19 +88,22 @@ struct plugin_loader { }; struct plugin_list_loader { - plugin_list_loader(list& plugins, boss::Game& game) : _plugins(plugins), _game(game) {} + plugin_list_loader(PluginGraph& graph, boss::Game& game) : _graph(graph), _game(game) {} void operator () () { - for (list::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& _plugins; + PluginGraph& _graph; boss::Game& _game; set skipPlugins; }; @@ -452,8 +455,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { YAML::Node mlist, ulist; list messages, mlist_messages, ulist_messages; list mlist_plugins, ulist_plugins; - boost::thread_group group; list 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 tempMap; + boost::unordered_map 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::const_iterator it=tempMap.begin(), endit=tempMap.end(); it != endit; ++it) { + plugin_list_loader pll(graph, _game); + for (boost::unordered_map::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 consistencyIssues; - for (list::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::iterator pos = std::find(mlist_plugins.begin(), mlist_plugins.end(), *it); + list::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 issues = it->CheckInstallValidity(_game); - list pluginMessages = it->Messages(); + map issues = graph[*vit].CheckInstallValidity(_game); + list pluginMessages = graph[*vit].Messages(); for (map::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 > overlapMap; - CalcPluginOverlaps(plugins, overlapMap); - - BOOST_LOG_TRIVIAL(trace) << "Building plugin priority map."; - boost::unordered_map< string, vector > 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::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());