mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Issue #39 work. Started to implement graph sort.
Also moved graph-related stuff into a new h/cpp file pair, and fixed the boss::master_sort function. For some unknown reason, an exception gets thrown after roughly 180 operations on the graph object, ie. near the end of the out-edges addition for the first plugin in the list.
This commit is contained in:
+4
-4
@@ -11,9 +11,9 @@
|
||||
cmake_minimum_required (VERSION 2.8.9)
|
||||
project (boss)
|
||||
|
||||
set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/backend/game.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/backend/network.cpp" "${CMAKE_SOURCE_DIR}/src/backend/globals.cpp" "${PROJECT_LIBS_DIR}/pugixml/src/pugixml.cpp")
|
||||
set (BOSS_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata.cpp" "${CMAKE_SOURCE_DIR}/src/backend/game.cpp" "${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp" "${CMAKE_SOURCE_DIR}/src/backend/network.cpp" "${CMAKE_SOURCE_DIR}/src/backend/globals.cpp" "${CMAKE_SOURCE_DIR}/src/backend/graph.cpp")
|
||||
|
||||
set (BOSS_SRC ${BOSS_SRC} "${PROJECT_LIBS_DIR}/boost/libs/iostreams/src/file_descriptor.cpp")
|
||||
set (BOSS_SRC ${BOSS_SRC} "${PROJECT_LIBS_DIR}/pugixml/src/pugixml.cpp" "${PROJECT_LIBS_DIR}/boost/libs/iostreams/src/file_descriptor.cpp")
|
||||
|
||||
# Include source and library directories.
|
||||
include_directories ("${PROJECT_LIBS_DIR}/alphanum" "${PROJECT_LIBS_DIR}/boost" "${PROJECT_LIBS_DIR}/yaml-cpp/include" "${CMAKE_SOURCE_DIR}/src" "${PROJECT_LIBS_DIR}/libloadorder/src" "${PROJECT_LIBS_DIR}/libespm" "${PROJECT_LIBS_DIR}/zlib" "${PROJECT_LIBS_DIR}/pugixml/src" "${PROJECT_LIBS_DIR}/wxWidgets/include" "${PROJECT_LIBS_DIR}/libgit2/include")
|
||||
@@ -49,8 +49,8 @@ link_directories ("${PROJECT_LIBS_DIR}/wxWidgets/lib")
|
||||
|
||||
# Settings when compiling and cross-compiling on Linux.
|
||||
IF (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
|
||||
set (CMAKE_C_FLAGS "-m${PROJECT_ARCH}")
|
||||
set (CMAKE_CXX_FLAGS "-m${PROJECT_ARCH}")
|
||||
set (CMAKE_C_FLAGS "-m${PROJECT_ARCH} -O3")
|
||||
set (CMAKE_CXX_FLAGS "-m${PROJECT_ARCH} -O3")
|
||||
set (CMAKE_EXE_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
set (CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
set (CMAKE_MODULE_LINKER_FLAGS "-static-libstdc++ -static-libgcc")
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/* BOSS
|
||||
|
||||
A plugin load order optimiser for games that use the esp/esm plugin system.
|
||||
|
||||
Copyright (C) 2012 WrinklyNinja
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS 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.
|
||||
|
||||
BOSS 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 BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "graph.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
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<list<Plugin>::const_iterator> >& 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 != endit; ++jt) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking for FormID overlap between \"" << it->Name() << "\" and \"" << jt->Name() << "\".";
|
||||
if (it->DoFormIDsOverlap(*jt)) {
|
||||
std::string key;
|
||||
list<Plugin>::const_iterator value;
|
||||
//Priority values should override the number of override records as the deciding factor if they differ.
|
||||
if (it->Priority() < jt->Priority()) {
|
||||
key = jt->Name();
|
||||
value = it;
|
||||
} else if (jt->Priority() < it->Priority()) {
|
||||
key = it->Name();
|
||||
value = jt;
|
||||
} else if (it->NumOverrideFormIDs() >= jt->NumOverrideFormIDs()) {
|
||||
key = jt->Name();
|
||||
value = it;
|
||||
} else {
|
||||
key = it->Name();
|
||||
value = jt;
|
||||
}
|
||||
boost::unordered_map< string, vector<list<Plugin>::const_iterator> >::iterator mapIt = overlapMap.find(key);
|
||||
if (mapIt == overlapMap.end()) {
|
||||
overlapMap.insert(pair<string, vector<list<Plugin>::const_iterator> >(key, vector<list<Plugin>::const_iterator>(1, value)));
|
||||
} else {
|
||||
mapIt->second.push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/* BOSS
|
||||
|
||||
A plugin load order optimiser for games that use the esp/esm plugin system.
|
||||
|
||||
Copyright (C) 2012 WrinklyNinja
|
||||
|
||||
This file is part of BOSS.
|
||||
|
||||
BOSS 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.
|
||||
|
||||
BOSS 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 BOSS. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BOSS_GRAPH__
|
||||
#define __BOSS_GRAPH__
|
||||
|
||||
#include "metadata.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/graph/graph_traits.hpp>
|
||||
#include <boost/graph/adjacency_list.hpp>
|
||||
#include <boost/graph/topological_sort.hpp>
|
||||
|
||||
namespace boss {
|
||||
|
||||
typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, std::list<boss::Plugin>::const_iterator> PluginGraph;
|
||||
typedef boost::graph_traits<PluginGraph>::vertex_descriptor vertex_t;
|
||||
|
||||
//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::list<Plugin>::const_iterator> >& overlapMap);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -706,7 +706,7 @@ namespace boss {
|
||||
}
|
||||
|
||||
bool master_sort(const Plugin& lhs, const Plugin& rhs) {
|
||||
if ((lhs.IsMaster() && !rhs.IsMaster()) || (!lhs.IsMaster() && rhs.IsMaster()))
|
||||
if (lhs.IsMaster() && !rhs.IsMaster())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
@@ -719,65 +719,4 @@ namespace boss {
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
//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 != 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->Priority() < jt->Priority()) {
|
||||
key = jt->Name();
|
||||
value = it->Name();
|
||||
} else if (jt->Priority() < it->Priority()) {
|
||||
key = it->Name();
|
||||
value = jt->Name();
|
||||
} else 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 GetPluginInEdges(const Plugin& plugin, const boost::unordered_map< std::string, std::vector<std::string> >& overlapMap, std::set<std::string>& inVertices) {
|
||||
//In-vertices are named in the plugin's entry in the overlap map, and in the plugin's requirements, masters and loadAfter members.
|
||||
|
||||
vector<string> strVec = plugin.Masters();
|
||||
inVertices.insert(strVec.begin(), strVec.end());
|
||||
|
||||
boost::unordered_map< std::string, std::vector<std::string> >::const_iterator it = overlapMap.find(plugin.Name());
|
||||
if (it != overlapMap.end())
|
||||
inVertices.insert(it->second.begin(), it->second.end());
|
||||
|
||||
set<File> fileset = plugin.Reqs();
|
||||
for (set<File>::const_iterator it=fileset.begin(), endIt=fileset.end(); it != endIt; ++it) {
|
||||
inVertices.insert(it->Name());
|
||||
}
|
||||
|
||||
fileset = plugin.LoadAfter();
|
||||
for (set<File>::const_iterator it=fileset.begin(), endIt=fileset.end(); it != endIt; ++it) {
|
||||
inVertices.insert(it->Name());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace boss {
|
||||
|
||||
|
||||
@@ -216,11 +214,6 @@ namespace boss {
|
||||
bool master_sort(const Plugin& lhs, const Plugin& rhs);
|
||||
|
||||
bool IsPlugin(const std::string& file);
|
||||
|
||||
//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 GetPluginInEdges(const Plugin& plugin, const boost::unordered_map< std::string, std::vector<std::string> >& overlapMap, std::set<std::string>& inVertices);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+103
-56
@@ -33,6 +33,7 @@
|
||||
#include "../backend/generators.h"
|
||||
#include "../backend/network.h"
|
||||
#include "../backend/streams.h"
|
||||
#include "../backend/graph.h"
|
||||
|
||||
#include <ostream>
|
||||
#include <algorithm>
|
||||
@@ -56,6 +57,7 @@
|
||||
#include <boost/log/support/date_time.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
|
||||
#include <wx/snglinst.h>
|
||||
#include <wx/aboutdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
@@ -475,7 +477,6 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
bool cyclicDependenciesExist = false;
|
||||
if (fs::exists(_game.MasterlistPath()) || fs::exists(_game.UserlistPath())) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging plugin lists, evaluating conditions and and checking for install validity...";
|
||||
|
||||
@@ -529,16 +530,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
//Check that the metadata is self-consistent.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that plugin data is self-consistent.";
|
||||
set<string> dependencies, incompatibilities, reqs;
|
||||
map<string, bool> issues;
|
||||
issues = it->CheckSelfConsistency(plugins, dependencies, incompatibilities, reqs);
|
||||
consistencyIssues.insert(issues.begin(), issues.end());
|
||||
|
||||
//Also check install validity.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to this plugin's data.";
|
||||
issues = it->CheckInstallValidity(_game);
|
||||
map<string, bool> issues = it->CheckInstallValidity(_game);
|
||||
list<boss::Message> pluginMessages = it->Messages();
|
||||
for (map<string,bool>::const_iterator jt=issues.begin(), endJt=issues.end(); jt != endJt; ++jt) {
|
||||
if (jt->second) {
|
||||
@@ -554,66 +548,119 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
|
||||
progDia->Pulse();
|
||||
}
|
||||
|
||||
for (map<string,bool>::const_iterator jt=consistencyIssues.begin(), endJt=consistencyIssues.end(); jt != endJt; ++jt) {
|
||||
if (jt->second) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is a circular dependency. Plugins will not be sorted.";
|
||||
messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is a circular dependency. Plugins will not be sorted.")) % jt->first).str()));
|
||||
cyclicDependenciesExist = true;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << jt->first << "\" is given as a dependency and an incompatibility.";
|
||||
messages.push_back(boss::Message(boss::g_message_error, (format(loc::translate("\"%1%\" is given as a dependency and an incompatibility.")) % jt->first).str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
progDia->Pulse();
|
||||
|
||||
if (!cyclicDependenciesExist) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Sorting plugins...";
|
||||
//First sort the plugins list so that masters come before non-masters.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Moving masters before non-masters.";
|
||||
plugins.sort(boss::master_sort);
|
||||
|
||||
//std::sort doesn't compare each plugin to every other plugin, it seems to compare plugins until no movement is necessary, because it assumes that each plugin will be comparable on all tested data, which isn't the case when dealing with masters, etc.
|
||||
list<boss::Plugin>::iterator it=plugins.begin();
|
||||
while (it != plugins.end()) {
|
||||
list<boss::Plugin>::iterator jt=it;
|
||||
++jt;
|
||||
list<boss::Plugin>::const_iterator firstNonMaster;
|
||||
for (list<boss::Plugin>::const_iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
|
||||
if (!it->IsMaster()) {
|
||||
firstNonMaster = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Sorting for: " << it->Name();
|
||||
//Now build overlap map.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Building plugin overlap map.";
|
||||
boost::unordered_map< string, vector<list<Plugin>::const_iterator> > overlapMap;
|
||||
CalcPluginOverlaps(plugins, overlapMap);
|
||||
|
||||
/* vector<string> masters = it->Masters();
|
||||
if (!masters.empty()) {
|
||||
out << "\t" << "Masters:" << endl;
|
||||
for (size_t i=0, max=masters.size(); i < max; ++i)
|
||||
out << "\t\t" << masters[i] << endl;
|
||||
}*/
|
||||
BOOST_LOG_TRIVIAL(trace) << "Building the plugin dependency graph...";
|
||||
bool cyclicDependenciesExist = false;
|
||||
|
||||
list<boss::Plugin> moved;
|
||||
while (jt != plugins.end()) {
|
||||
/* if (it->MustLoadAfter(*jt)
|
||||
|| jt->Priority() < it->Priority()) {
|
||||
|| (!jt->OverlapFormIDs(*it).empty() && jt->FormIDs().size() != it->FormIDs().size() && jt->FormIDs().size() > it->FormIDs().size())) {
|
||||
*/
|
||||
// if (load_order_sort(*jt, *it)) {
|
||||
if (it->MustLoadAfter(*jt)) {
|
||||
BOOST_LOG_TRIVIAL(trace) << jt->Name() << " should load before " << it->Name();
|
||||
moved.push_back(*jt);
|
||||
jt = plugins.erase(jt);
|
||||
} else
|
||||
++jt;
|
||||
//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.
|
||||
|
||||
progDia->Pulse();
|
||||
boss::PluginGraph graph;
|
||||
|
||||
//Now add the plugins in order to the graph as vertices.
|
||||
for (list<boss::Plugin>::const_iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Creating vertex for \"" << it->Name() << "\".";
|
||||
boost::add_vertex(it, graph);
|
||||
}
|
||||
|
||||
//Vertices are numbered from 0 to (N - 1), where N is the number of vertices in the graph. A plugin's vertex number is therefore the same as its position in the list, and this can be used to create edges between plugins.
|
||||
list<boss::Plugin>::const_iterator beginIt = plugins.begin();
|
||||
for (list<boss::Plugin>::const_iterator it=plugins.begin(), endIt=plugins.end(); it != endIt; ++it) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Editing vertex for \"" << it->Name() << "\".";
|
||||
//Check if this plugin already has a vertex, and if not, create one.
|
||||
boss::vertex_t vertex = boost::vertex( std::distance(beginIt, it), graph);
|
||||
|
||||
//Now add edges for everything.
|
||||
list<boss::Plugin>::const_iterator result;
|
||||
set<File> fileset;
|
||||
vector<string> strVec = it->Masters();
|
||||
|
||||
if (it->IsMaster()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding out-edges for non-master plugins.";
|
||||
//Need to add out-edges to all non-master plugins.
|
||||
for (list<boss::Plugin>::const_iterator jt=firstNonMaster, endIt; jt != endIt; ++jt) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Getting vertex for \"" << jt->Name() << "\".";
|
||||
boss::vertex_t childVertex = boost::vertex( std::distance(beginIt, jt), graph );
|
||||
|
||||
//Now that we have the non-master plugin's vertex, create an edge between the two.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding edge from \"" << it->Name() << "\" to \"" << jt->Name() << "\".";
|
||||
boost::add_edge(vertex, childVertex, graph);
|
||||
}
|
||||
if (!moved.empty()) {
|
||||
plugins.insert(it, moved.begin(), moved.end());
|
||||
advance(it, -1*(int)moved.size());
|
||||
} else
|
||||
++it;
|
||||
|
||||
progDia->Pulse();
|
||||
}
|
||||
|
||||
plugins.sort(boss::load_order_sort);
|
||||
//Now add masters.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for masters.";
|
||||
for (vector<string>::const_iterator jt=strVec.begin(), endjt=strVec.end(); jt != endjt; ++jt) {
|
||||
//Find the other plugin.
|
||||
result = std::find(plugins.begin(), plugins.end(), boss::Plugin(*jt));
|
||||
//Add the vertex (again assuming that duplicates won't be created).
|
||||
boss::vertex_t parentVertex = boost::vertex( std::distance(beginIt, result), graph);
|
||||
boost::add_edge(parentVertex, vertex, graph);
|
||||
}
|
||||
|
||||
//Now add requirements.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for requirements.";
|
||||
fileset = it->Reqs();
|
||||
for (set<File>::const_iterator jt=fileset.begin(), endjt=fileset.end(); jt != endjt; ++jt) {
|
||||
if (boss::IsPlugin(jt->Name())) {
|
||||
//Find the other plugin.
|
||||
result = std::find(plugins.begin(), plugins.end(), *jt);
|
||||
//Add the vertex (again assuming that duplicates won't be created).
|
||||
boss::vertex_t parentVertex = boost::vertex( std::distance(beginIt, result), graph);
|
||||
boost::add_edge(parentVertex, vertex, graph);
|
||||
}
|
||||
}
|
||||
|
||||
//Now add "load after" plugins.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding in-edges for 'load after's.";
|
||||
fileset = it->LoadAfter();
|
||||
for (set<File>::const_iterator jt=fileset.begin(), endjt=fileset.end(); jt != endjt; ++jt) {
|
||||
if (boss::IsPlugin(jt->Name())) {
|
||||
//Find the other plugin.
|
||||
result = std::find(plugins.begin(), plugins.end(), *jt);
|
||||
//Add the vertex (again assuming that duplicates won't be created).
|
||||
boss::vertex_t parentVertex = boost::vertex( std::distance(beginIt, result), graph);
|
||||
boost::add_edge(parentVertex, vertex, graph);
|
||||
}
|
||||
}
|
||||
|
||||
//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_LOG_TRIVIAL(trace) << "Adding in-edges for overlaps.";
|
||||
boost::unordered_map< std::string, std::vector<list<Plugin>::const_iterator> >::const_iterator overlapIt = overlapMap.find(it->Name());
|
||||
if (overlapIt != overlapMap.end()) {
|
||||
for (vector<list<Plugin>::const_iterator>::const_iterator jt=overlapIt->second.begin(), endjt=overlapIt->second.end(); jt != endjt; ++jt) {
|
||||
boss::vertex_t parentVertex = boost::vertex( std::distance(beginIt, *jt), graph);
|
||||
|
||||
if (!boost::edge(vertex, parentVertex, graph).second) {
|
||||
//No edge going the other way, OK to add this edge.
|
||||
boost::add_edge(parentVertex, vertex, graph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (!cyclicDependenciesExist) {
|
||||
progDia->Pulse();
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Displaying load order preview.";
|
||||
|
||||
Reference in New Issue
Block a user