diff --git a/src/backend/game.cpp b/src/backend/game.cpp index 11099263..e7d58455 100644 --- a/src/backend/game.cpp +++ b/src/backend/game.cpp @@ -31,7 +31,6 @@ #include "streams.h" #include -#include using namespace std; @@ -577,44 +576,19 @@ namespace loot { } void Game::LoadPlugins(bool headersOnly) { - boost::thread_group group; - size_t meanFileSize = 0; - unordered_map tempMap; - std::set skipPlugins; - //First calculate the mean plugin size. Store it temporarily in a map to reduce filesystem lookups and file size recalculation. - for (fs::directory_iterator it(this->DataPath()); it != fs::directory_iterator(); ++it) { + //Add all plugins in data folder not already in the hashset to the hashset, and load them. + for (fs::directory_iterator it(DataPath()); it != fs::directory_iterator(); ++it) { if (fs::is_regular_file(it->status()) && IsPlugin(it->path().string())) { + const string filename = it->path().filename().string(); - size_t fileSize = fs::file_size(it->path()); - meanFileSize += fileSize; - - tempMap.emplace(it->path().filename().string(), fileSize); + if (plugins.find(filename) == plugins.end()) + plugins.insert(std::pair(filename, Plugin(filename))); } } - meanFileSize /= tempMap.size(); - //Now load plugins. - for (const auto &pluginPair : tempMap) { - - BOOST_LOG_TRIVIAL(info) << "Found plugin: " << pluginPair.first; - - auto plugin = plugins.emplace(pluginPair.first, Plugin(pluginPair.first)); - - if (pluginPair.second > meanFileSize) { - skipPlugins.insert(pluginPair.first); - group.create_thread([this, &plugin, headersOnly]() { - plugin.first->second = Plugin(*this, plugin.first->first, headersOnly); - }); - } + for (auto &pluginPair: plugins) { + pluginPair.second = Plugin(*this, pluginPair.second.Name(), headersOnly); } - group.create_thread([this, &skipPlugins, headersOnly]() { - for (auto &pluginPair : this->plugins) { - if (skipPlugins.find(pluginPair.first) == skipPlugins.end()) { - pluginPair.second = Plugin(*this, pluginPair.first, headersOnly); - } - } - }); - group.join_all(); } void Game::CreateLOOTGameFolder() { diff --git a/src/backend/game.h b/src/backend/game.h index 12f6d8d4..89729cfc 100644 --- a/src/backend/game.h +++ b/src/backend/game.h @@ -78,6 +78,56 @@ namespace loot { std::string revision; std::string date; }; + /* + class PluginCache { + + + bool IsActive(const std::string& plugin) const; + + void GetLoadOrder(std::list& loadOrder) const; + void SetLoadOrder(const std::list& loadOrder) const; //Modifies game load order, even though const. + + void RefreshActivePluginsList(); + void RedatePlugins(); //Change timestamps to match load order (Skyrim only). + void LoadPlugins(bool headersOnly); //Loads all installed plugins. + std::unordered_map plugins; //Map so that plugin data can be edited. + + std::unordered_set activePlugins; //Holds lowercased strings. + }; + */ + + // A couple of plugin loader classes for handling plugin loading in separate threads. + class PluginLoader { + public: + PluginLoader(Plugin& plugin, Game& game) : _plugin(plugin), _game(game) { + } + + void operator () () { + _plugin = Plugin(_game, _plugin.Name(), false); + } + + Plugin& _plugin; + Game& _game; + std::string _filename; + bool _b; + }; + + class PluginsLoader { + public: + PluginsLoader(std::list& plugins, Game& game) : _plugins(plugins), _game(game) {} + + void operator () () { + for (auto &plugin : _plugins) { + if (skipPlugins.find(plugin.Name()) == skipPlugins.end()) { + plugin = Plugin(_game, plugin.Name(), false); + } + } + } + + std::list& _plugins; + Game& _game; + std::set skipPlugins; + }; class Game { public: @@ -110,6 +160,7 @@ namespace loot { boost::filesystem::path UserlistPath() const; boost::filesystem::path ReportDataPath() const; +//TO BE REMOVED //Game plugin functions. bool IsActive(const std::string& plugin) const; @@ -123,11 +174,12 @@ namespace loot { //Caches for condition results, active plugins and CRCs. std::unordered_map conditionCache; //Holds lowercased strings. std::unordered_map crcCache; //Holds lowercased strings. +//END TO BE REMOVED //Plugin data and metadata lists. Masterlist masterlist; MetadataList userlist; - std::unordered_map plugins; //Map so that plugin data can be edited. + std::unordered_map plugins; //Map so that plugin data can be edited. TO BE REMOVED espm::Settings espm_settings; @@ -149,7 +201,7 @@ namespace loot { boost::filesystem::path gamePath; //Path to the game's folder. - std::unordered_set activePlugins; //Holds lowercased strings. + std::unordered_set activePlugins; //Holds lowercased strings. TO BE REMOVED //Creates directory in LOOT folder for LOOT's game-specific files. void CreateLOOTGameFolder(); diff --git a/src/gui/main.cpp b/src/gui/main.cpp index bc113d38..ba68322f 100644 --- a/src/gui/main.cpp +++ b/src/gui/main.cpp @@ -624,6 +624,7 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { BOOST_LOG_TRIVIAL(debug) << "Beginning sorting process."; list messages; + list plugins; boost::thread_group group; unsigned int lang; @@ -649,9 +650,38 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str())); } }); - group.create_thread([this]() { - this->_game->LoadPlugins(false); - }); + + //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; + 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(it->path().filename().string(), fileSize); + } + } + meanFileSize /= tempMap.size(); + + //Now load plugins. + PluginsLoader pll(plugins, *_game); + for (const auto &pluginPair: tempMap) { + + BOOST_LOG_TRIVIAL(info) << "Found plugin: " << pluginPair.first; + + plugins.push_back(loot::Plugin(pluginPair.first)); + + if (pluginPair.second > meanFileSize) { + pll.skipPlugins.insert(pluginPair.first); + PluginLoader pl(plugins.back(), *_game); + group.create_thread(pl); + } + + progDia->Pulse(); + } + group.create_thread(pll); group.join_all(); //Now load userlist. @@ -672,27 +702,47 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { // Merge & Check Metadata /////////////////////////////////////////////////////// - //Merge all global message lists. - BOOST_LOG_TRIVIAL(debug) << "Merging all global message lists."; - if (!_game->masterlist.messages.empty()) - messages.insert(messages.end(), _game->masterlist.messages.begin(), _game->masterlist.messages.end()); - if (!_game->userlist.messages.empty()) - messages.insert(messages.end(), _game->userlist.messages.begin(), _game->userlist.messages.end()); + if (fs::exists(_game->MasterlistPath()) || fs::exists(_game->UserlistPath())) { - //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(*_game, lang)) - it = messages.erase(it); - else - ++it; + + //Merge all global message lists. + BOOST_LOG_TRIVIAL(debug) << "Merging all global message lists."; + if (!_game->masterlist.messages.empty()) + messages.insert(messages.end(), _game->masterlist.messages.begin(), _game->masterlist.messages.end()); + if (!_game->userlist.messages.empty()) + messages.insert(messages.end(), _game->userlist.messages.begin(), _game->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(*_game, 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())); + } + + //Merge plugin list and masterlist. + BOOST_LOG_TRIVIAL(debug) << "Merging plugin list and masterlist data."; + for (auto &plugin : plugins) { + BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << plugin.Name() << "\""; + + //Check if there is a plugin entry in the masterlist. This will also find matching regex entries. + list::iterator pos = std::find(_game->masterlist.plugins.begin(), _game->masterlist.plugins.end(), plugin); + + if (pos != _game->masterlist.plugins.end()) { + BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data."; + plugin.MergeMetadata(*pos); + } + + progDia->Pulse(); } - } - 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...")); @@ -712,10 +762,6 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { */ //Check for back-edges, then perform a topological sort. - list plugins; - for (auto &plugin : _game->plugins) { - plugins.push_back(plugin.second); - } try { bool applyLoadOrder = false; @@ -731,16 +777,8 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) { 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 a plugin entry in the masterlist. This will also find matching regex entries. - list::iterator pos = std::find(_game->masterlist.plugins.begin(), _game->masterlist.plugins.end(), graph[*vit]); - - if (pos != _game->masterlist.plugins.end()) { - BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data."; - graph[*vit].MergeMetadata(*pos); - } - //Check if there is a plugin entry in the userlist. This will also find matching regex entries. - pos = std::find(_game->userlist.plugins.begin(), _game->userlist.plugins.end(), graph[*vit]); + list::iterator pos = std::find(_game->userlist.plugins.begin(), _game->userlist.plugins.end(), graph[*vit]); if (pos != _game->userlist.plugins.end() && pos->Enabled()) { BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";