mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Re-implemented plugin loading.
Using a multi-threaded loader member function from the game class. This currently produces invalid cyclic errors for me though, so I need to fix that.
This commit is contained in:
+33
-7
@@ -31,6 +31,7 @@
|
||||
#include "streams.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -572,19 +573,44 @@ namespace loot {
|
||||
}
|
||||
|
||||
void Game::LoadPlugins(bool headersOnly) {
|
||||
//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) {
|
||||
boost::thread_group group;
|
||||
size_t meanFileSize = 0;
|
||||
unordered_map<std::string, size_t> tempMap;
|
||||
std::set<std::string> 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) {
|
||||
if (fs::is_regular_file(it->status()) && IsPlugin(it->path().string())) {
|
||||
const string filename = it->path().filename().string();
|
||||
|
||||
if (plugins.find(filename) == plugins.end())
|
||||
plugins.insert(std::pair<string, Plugin>(filename, Plugin(filename)));
|
||||
size_t fileSize = fs::file_size(it->path());
|
||||
meanFileSize += fileSize;
|
||||
|
||||
tempMap.emplace(it->path().filename().string(), fileSize);
|
||||
}
|
||||
}
|
||||
meanFileSize /= tempMap.size();
|
||||
|
||||
for (auto &pluginPair: plugins) {
|
||||
pluginPair.second = Plugin(*this, pluginPair.second.Name(), headersOnly);
|
||||
//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);
|
||||
});
|
||||
}
|
||||
}
|
||||
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() {
|
||||
|
||||
+2
-54
@@ -78,56 +78,6 @@ namespace loot {
|
||||
std::string revision;
|
||||
std::string date;
|
||||
};
|
||||
/*
|
||||
class PluginCache {
|
||||
|
||||
|
||||
bool IsActive(const std::string& plugin) const;
|
||||
|
||||
void GetLoadOrder(std::list<std::string>& loadOrder) const;
|
||||
void SetLoadOrder(const std::list<Plugin>& 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<std::string, Plugin> plugins; //Map so that plugin data can be edited.
|
||||
|
||||
std::unordered_set<std::string> 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<Plugin>& 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<Plugin>& _plugins;
|
||||
Game& _game;
|
||||
std::set<std::string> skipPlugins;
|
||||
};
|
||||
|
||||
class Game {
|
||||
public:
|
||||
@@ -159,7 +109,6 @@ 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;
|
||||
|
||||
@@ -173,12 +122,11 @@ namespace loot {
|
||||
//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.
|
||||
//END TO BE REMOVED
|
||||
|
||||
//Plugin data and metadata lists.
|
||||
Masterlist masterlist;
|
||||
MetadataList userlist;
|
||||
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited. TO BE REMOVED
|
||||
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited.
|
||||
|
||||
espm::Settings espm_settings;
|
||||
|
||||
@@ -200,7 +148,7 @@ namespace loot {
|
||||
|
||||
boost::filesystem::path gamePath; //Path to the game's folder.
|
||||
|
||||
std::unordered_set<std::string> activePlugins; //Holds lowercased strings. TO BE REMOVED
|
||||
std::unordered_set<std::string> activePlugins; //Holds lowercased strings.
|
||||
|
||||
//Creates directory in LOOT folder for LOOT's game-specific files.
|
||||
void CreateLOOTGameFolder();
|
||||
|
||||
+35
-73
@@ -607,7 +607,6 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Beginning sorting process.";
|
||||
|
||||
list<loot::Message> messages;
|
||||
list<loot::Plugin> plugins;
|
||||
boost::thread_group group;
|
||||
unsigned int lang;
|
||||
|
||||
@@ -633,38 +632,9 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("Masterlist parsing failed. Details: %1%")) % e.what()).str()));
|
||||
}
|
||||
});
|
||||
|
||||
//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<std::string, size_t> 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.create_thread([this]() {
|
||||
this->_game->LoadPlugins(false);
|
||||
});
|
||||
group.join_all();
|
||||
|
||||
//Now load userlist.
|
||||
@@ -685,48 +655,28 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
// Merge & Check Metadata
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
if (fs::exists(_game->MasterlistPath()) || fs::exists(_game->UserlistPath())) {
|
||||
//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());
|
||||
|
||||
|
||||
//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<loot::Message>::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<loot::Plugin>::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();
|
||||
//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(*_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()));
|
||||
}
|
||||
|
||||
progDia->Update(800, translate("Building plugin graph..."));
|
||||
|
||||
@@ -745,6 +695,10 @@ void Launcher::OnSortPlugins(wxCommandEvent& event) {
|
||||
*/
|
||||
|
||||
//Check for back-edges, then perform a topological sort.
|
||||
list<loot::Plugin> plugins;
|
||||
for (auto &plugin : _game->plugins) {
|
||||
plugins.push_back(plugin.second);
|
||||
}
|
||||
try {
|
||||
bool applyLoadOrder = false;
|
||||
|
||||
@@ -760,8 +714,16 @@ 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<loot::Plugin>::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.
|
||||
list<loot::Plugin>::iterator pos = std::find(_game->userlist.plugins.begin(), _game->userlist.plugins.end(), graph[*vit]);
|
||||
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.";
|
||||
|
||||
Reference in New Issue
Block a user