Started to refactor plugin sorting code.

This commit is contained in:
WrinklyNinja
2014-07-14 14:22:39 +01:00
parent 3a3361b919
commit dc8f616bcb
4 changed files with 119 additions and 59 deletions
+2 -1
View File
@@ -49,7 +49,8 @@ set (LOOT_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/globals.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/generators.cpp")
"${CMAKE_SOURCE_DIR}/src/backend/generators.cpp"
"${CMAKE_SOURCE_DIR}/src/backend/sort.cpp")
set (LOOT_GUI_SRC ${LOOT_SRC}
# Code the API doesn't need.
+2
View File
@@ -119,6 +119,8 @@ namespace loot {
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
void LoadPlugins(bool headersOnly); //Loads all installed plugins.
void SortPlugins(const unsigned int language, std::list<Message>& messages, std::function<void(const std::string&)> callback);
//Caches for condition results, active plugins and CRCs.
std::unordered_map<std::string, bool> conditionCache; //Holds lowercased strings.
std::unordered_map<std::string, uint32_t> crcCache; //Holds lowercased strings.
+108
View File
@@ -0,0 +1,108 @@
/* 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 <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 {
void Game::SortPlugins(const unsigned int language, std::list<Message>& messages, std::function<void(const std::string&)> callback) {
boost::thread_group group;
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
///////////////////////////////////////////////////////
// Load Plugins & Lists
///////////////////////////////////////////////////////
callback("Reading installed plugins...");
group.create_thread([this, language, &messages]() {
try {
this->masterlist.Load(*this, language);
}
catch (exception &e) {
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str()));
}
});
group.create_thread([this]() {
this->LoadPlugins(false);
});
group.join_all();
//Now load userlist.
if (fs::exists(this->UserlistPath())) {
BOOST_LOG_TRIVIAL(debug) << "Parsing userlist at: " << this->UserlistPath();
try {
this->userlist.Load(this->UserlistPath());
}
catch (exception& e) {
BOOST_LOG_TRIVIAL(error) << "Userlist parsing failed. Details: " << e.what();
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Userlist parsing failed. Details: %1%")) % e.what()).str()));
}
}
///////////////////////////////////////////////////////
// Evaluate Global Messages
///////////////////////////////////////////////////////
callback("Evaluating global messages...");
//Merge all global message lists.
BOOST_LOG_TRIVIAL(debug) << "Merging all global message lists.";
if (!this->masterlist.messages.empty())
messages.insert(messages.end(), this->masterlist.messages.begin(), this->masterlist.messages.end());
if (!this->userlist.messages.empty())
messages.insert(messages.end(), this->userlist.messages.begin(), this->userlist.messages.end());
//Evaluate any conditions in the global messages.
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
try {
list<loot::Message>::iterator it = messages.begin();
while (it != messages.end()) {
if (!it->EvalCondition(*this, language))
it = messages.erase(it);
else
++it;
}
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
}
}
}
+7 -58
View File
@@ -605,14 +605,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
BOOST_LOG_TRIVIAL(debug) << "Beginning sorting process.";
list<loot::Message> messages;
boost::thread_group group;
unsigned int lang;
wxProgressDialog *progDia = new wxProgressDialog(translate("LOOT: Working..."),translate("LOOT working..."), 1000, this, wxPD_APP_MODAL|wxPD_AUTO_HIDE|wxPD_ELAPSED_TIME);
///////////////////////////////////////////////////////
// Load Plugins & Lists
///////////////////////////////////////////////////////
wxProgressDialog *progDia = new wxProgressDialog(translate("LOOT: Working..."), translate("LOOT working..."), 1000, this, wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_ELAPSED_TIME);
//Set language.
if (_settings["Language"])
@@ -622,61 +617,13 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(lang).Name();
group.create_thread([this, lang, &messages]() {
try {
this->_games[_currentGame].masterlist.Load(this->_games[_currentGame], lang);
}
catch (exception &e) {
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str()));
}
});
group.create_thread([this]() {
this->_games[_currentGame].LoadPlugins(false);
});
group.join_all();
//Now load userlist.
if (fs::exists(_games[_currentGame].UserlistPath())) {
BOOST_LOG_TRIVIAL(debug) << "Parsing userlist at: " << _games[_currentGame].UserlistPath();
try {
_games[_currentGame].userlist.Load(_games[_currentGame].UserlistPath());
} catch (exception& e) {
BOOST_LOG_TRIVIAL(error) << "Userlist parsing failed. Details: " << e.what();
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Userlist parsing failed. Details: %1%")) % e.what()).str()));
}
}
progDia->Pulse();
///////////////////////////////////////////////////////
// Merge & Check Metadata
// Load Plugins & Lists
///////////////////////////////////////////////////////
//Merge all global message lists.
BOOST_LOG_TRIVIAL(debug) << "Merging all global message lists.";
if (!_games[_currentGame].masterlist.messages.empty())
messages.insert(messages.end(), _games[_currentGame].masterlist.messages.begin(), _games[_currentGame].masterlist.messages.end());
if (!_games[_currentGame].userlist.messages.empty())
messages.insert(messages.end(), _games[_currentGame].userlist.messages.begin(), _games[_currentGame].userlist.messages.end());
//Evaluate any conditions in the global messages.
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
try {
list<loot::Message>::iterator it=messages.begin();
while (it != messages.end()) {
if (!it->EvalCondition(_games[_currentGame], lang))
it = messages.erase(it);
else
++it;
}
}
catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
}
progDia->Update(800, translate("Building plugin graph..."));
_games[_currentGame].SortPlugins(lang, messages, [progDia](const std::string& message) {
progDia->Pulse(FromUTF8(message));
});
///////////////////////////////////////////////////////
// Build Graph Edges & Sort
@@ -692,6 +639,8 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
*/
progDia->Update(800, translate("Building plugin graph..."));
//Check for back-edges, then perform a topological sort.
list<loot::Plugin> plugins;
for (auto &plugin : _games[_currentGame].plugins) {