From dc8f616bcb637f2fd4158aaf820b555a19eedf27 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Mon, 14 Jul 2014 14:22:39 +0100 Subject: [PATCH] Started to refactor plugin sorting code. --- CMakeLists.txt | 3 +- src/backend/game.h | 2 + src/backend/sort.cpp | 108 +++++++++++++++++++++++++++++++++++++++++++ src/gui/main.cpp | 65 +++----------------------- 4 files changed, 119 insertions(+), 59 deletions(-) create mode 100644 src/backend/sort.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 42e92acc..a51f7768 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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. diff --git a/src/backend/game.h b/src/backend/game.h index e67e9b47..99fdaedf 100644 --- a/src/backend/game.h +++ b/src/backend/game.h @@ -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& messages, std::function callback); + //Caches for condition results, active plugins and CRCs. std::unordered_map conditionCache; //Holds lowercased strings. std::unordered_map crcCache; //Holds lowercased strings. diff --git a/src/backend/sort.cpp b/src/backend/sort.cpp new file mode 100644 index 00000000..2ad231af --- /dev/null +++ b/src/backend/sort.cpp @@ -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 +. +*/ + +#include "game.h" +#include "helpers.h" + +#include +#include +#include +#include + +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& messages, std::function 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::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())); + } + } +} \ No newline at end of file diff --git a/src/gui/main.cpp b/src/gui/main.cpp index 24fd2c13..d8584ab3 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -605,14 +605,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Beginning sorting process."; list 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::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 plugins; for (auto &plugin : _games[_currentGame].plugins) {