mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Merge branch 'refactor-plugin-cache' into dev
This commit is contained in:
@@ -33,8 +33,8 @@ LOOT requires the following C/C++ libraries (version numbers used in latest deve
|
||||
* [Google Test](https://github.com/google/googletest) v1.7: Required to build the tests, but not the API or the GUI.
|
||||
* [Libespm](http://github.com/WrinklyNinja/libespm) v2.5.0
|
||||
* [Libgit2](http://libgit2.github.com/) v0.23.4
|
||||
* [Libloadorder](http://github.com/WrinklyNinja/libloadorder) revision 3a7d694
|
||||
* [Pseudosem](http://github.com/WrinklyNinja/pseudosem): v1.0.1
|
||||
* [Libloadorder](http://github.com/WrinklyNinja/libloadorder) v7.0.0
|
||||
* [Pseudosem](http://github.com/WrinklyNinja/pseudosem) v1.0.1
|
||||
* [yaml-cpp](http://github.com/WrinklyNinja/yaml-cpp): Use the `patched-for-loot` branch.
|
||||
|
||||
In addition, LOOT's UI relies on the web libraries below, which can be fetched by running `bower install` from the repository root.
|
||||
|
||||
@@ -25,8 +25,8 @@ make git2
|
||||
cd ../..
|
||||
|
||||
# Build libloadorder
|
||||
wget https://github.com/WrinklyNinja/libloadorder/archive/3a7d694e2eab9957b745fe828da1ed00f537c989.tar.gz -O - | tar -xz
|
||||
mv libloadorder-3a7d694e2eab9957b745fe828da1ed00f537c989 libloadorder
|
||||
wget https://github.com/WrinklyNinja/libloadorder/archive/7.0.0.tar.gz -O - | tar -xz
|
||||
mv libloadorder-7.0.0 libloadorder
|
||||
mkdir libloadorder/build && cd libloadorder/build
|
||||
cmake .. -DPROJECT_ARCH=64 -DPROJECT_STATIC_RUNTIME=OFF -DBUILD_SHARED_LIBS=OFF -DGTEST_ROOT=../gtest-1.7.0
|
||||
make loadorder64
|
||||
|
||||
+15
-16
@@ -363,9 +363,9 @@ LOOT_API unsigned int loot_load_lists(loot_db db, const char * const masterlistP
|
||||
db->extTagMap = nullptr;
|
||||
db->extMessageArray = nullptr;
|
||||
|
||||
db->masterlist = temp;
|
||||
db->GetMasterlist() = temp;
|
||||
db->rawMetadata = temp;
|
||||
db->userlist = userTemp;
|
||||
db->GetUserlist() = userTemp;
|
||||
db->rawUserMetadata = userTemp;
|
||||
|
||||
return loot_ok;
|
||||
@@ -400,15 +400,14 @@ LOOT_API unsigned int loot_eval_lists(loot_db db, const unsigned int language) {
|
||||
loot::MetadataList userTemp = db->rawUserMetadata;
|
||||
try {
|
||||
// Refresh active plugins before evaluating conditions.
|
||||
db->RefreshActivePluginsList();
|
||||
temp.EvalAllConditions(*db, language);
|
||||
userTemp.EvalAllConditions(*db, language);
|
||||
}
|
||||
catch (loot::error& e) {
|
||||
return c_error(e);
|
||||
}
|
||||
db->masterlist = temp;
|
||||
db->userlist = userTemp;
|
||||
db->GetMasterlist() = temp;
|
||||
db->GetUserlist() = userTemp;
|
||||
|
||||
return loot_ok;
|
||||
}
|
||||
@@ -576,12 +575,12 @@ LOOT_API unsigned int loot_get_tag_map(loot_db db, char *** const tagMap, size_t
|
||||
|
||||
std::set<std::string> allTags;
|
||||
|
||||
for (const auto &plugin : db->masterlist.Plugins()) {
|
||||
for (const auto &plugin : db->GetMasterlist().Plugins()) {
|
||||
for (const auto &tag : plugin.Tags()) {
|
||||
allTags.insert(tag.Name());
|
||||
}
|
||||
}
|
||||
for (const auto &plugin : db->userlist.Plugins()) {
|
||||
for (const auto &plugin : db->GetUserlist().Plugins()) {
|
||||
for (const auto &tag : plugin.Tags()) {
|
||||
allTags.insert(tag.Name());
|
||||
}
|
||||
@@ -650,7 +649,7 @@ LOOT_API unsigned int loot_get_plugin_tags(loot_db db, const char * const plugin
|
||||
*numTags_removed = 0;
|
||||
|
||||
std::set<std::string> tagsAdded, tagsRemoved;
|
||||
loot::PluginMetadata p = db->masterlist.FindPlugin(loot::PluginMetadata(plugin));
|
||||
loot::PluginMetadata p = db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin));
|
||||
for (const auto &tag : p.Tags()) {
|
||||
if (tag.IsAddition())
|
||||
tagsAdded.insert(tag.Name());
|
||||
@@ -658,7 +657,7 @@ LOOT_API unsigned int loot_get_plugin_tags(loot_db db, const char * const plugin
|
||||
tagsRemoved.insert(tag.Name());
|
||||
}
|
||||
|
||||
p = db->userlist.FindPlugin(loot::PluginMetadata(plugin));
|
||||
p = db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin));
|
||||
*userlistModified = !p.Tags().empty();
|
||||
for (const auto &tag : p.Tags()) {
|
||||
*userlistModified = true;
|
||||
@@ -731,10 +730,10 @@ LOOT_API unsigned int loot_get_plugin_messages(loot_db db, const char * const pl
|
||||
*messages = nullptr;
|
||||
*numMessages = 0;
|
||||
|
||||
loot::PluginMetadata p = db->masterlist.FindPlugin(loot::PluginMetadata(plugin));
|
||||
loot::PluginMetadata p = db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin));
|
||||
std::list<loot::Message> pluginMessages(p.Messages());
|
||||
|
||||
p = db->userlist.FindPlugin(loot::PluginMetadata(plugin));
|
||||
p = db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin));
|
||||
std::list<loot::Message> temp(p.Messages());
|
||||
pluginMessages.insert(pluginMessages.end(), temp.begin(), temp.end());
|
||||
|
||||
@@ -767,8 +766,8 @@ LOOT_API unsigned int loot_get_dirty_info(loot_db db, const char * const plugin,
|
||||
*needsCleaning = loot_needs_cleaning_unknown;
|
||||
|
||||
// Is there any dirty info? Testing for applicability happens in loot_eval_lists().
|
||||
if (!db->masterlist.FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty()
|
||||
|| !db->userlist.FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty()) {
|
||||
if (!db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty()
|
||||
|| !db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)).DirtyInfo().empty()) {
|
||||
*needsCleaning = loot_needs_cleaning_yes;
|
||||
}
|
||||
|
||||
@@ -776,9 +775,9 @@ LOOT_API unsigned int loot_get_dirty_info(loot_db db, const char * const plugin,
|
||||
// This isn't a very reliable system, because if the lists have been evaluated in some language
|
||||
// other than English, the strings will be in different languages (and the API can't tell what they'd be)
|
||||
// and the strings may be non-standard and begin with something other than "Do not clean." anyway.
|
||||
std::list<loot::Message> messages(db->masterlist.FindPlugin(loot::PluginMetadata(plugin)).Messages());
|
||||
std::list<loot::Message> messages(db->GetMasterlist().FindPlugin(loot::PluginMetadata(plugin)).Messages());
|
||||
|
||||
std::list<loot::Message> temp(db->userlist.FindPlugin(loot::PluginMetadata(plugin)).Messages());
|
||||
std::list<loot::Message> temp(db->GetUserlist().FindPlugin(loot::PluginMetadata(plugin)).Messages());
|
||||
messages.insert(messages.end(), temp.begin(), temp.end());
|
||||
|
||||
for (const auto& message : messages) {
|
||||
@@ -805,7 +804,7 @@ LOOT_API unsigned int loot_write_minimal_list(loot_db db, const char * const out
|
||||
if (boost::filesystem::exists(outputFile) && !overwrite)
|
||||
return c_error(loot_error_file_write_fail, "Output file exists but overwrite is not set to true.");
|
||||
|
||||
loot::Masterlist temp = db->masterlist;
|
||||
loot::Masterlist temp = db->GetMasterlist();
|
||||
std::unordered_set<loot::PluginMetadata> minimalPlugins;
|
||||
for (const auto &plugin : temp.Plugins()) {
|
||||
loot::PluginMetadata p(plugin.Name());
|
||||
|
||||
+27
-31
@@ -41,7 +41,7 @@ namespace lc = boost::locale;
|
||||
namespace loot {
|
||||
Game::Game() : _pluginsFullyLoaded(false) {}
|
||||
|
||||
Game::Game(const GameSettings& gameSettings) : GameSettings(gameSettings.Id(), gameSettings.FolderName()), _pluginsFullyLoaded(false) {
|
||||
Game::Game(const GameSettings& gameSettings) : GameSettings(gameSettings), _pluginsFullyLoaded(false) {
|
||||
this->SetName(gameSettings.Name())
|
||||
.SetMaster(gameSettings.Master())
|
||||
.SetRepoURL(gameSettings.RepoURL())
|
||||
@@ -77,12 +77,6 @@ namespace loot {
|
||||
}
|
||||
|
||||
LoadOrderHandler::Init(*this, gameLocalAppData);
|
||||
|
||||
RefreshActivePluginsList();
|
||||
}
|
||||
|
||||
void Game::RefreshActivePluginsList() {
|
||||
CacheActivePlugins(GetActivePlugins());
|
||||
}
|
||||
|
||||
void Game::RedatePlugins() {
|
||||
@@ -124,29 +118,30 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Scanning for plugins in " << this->DataPath();
|
||||
for (fs::directory_iterator it(this->DataPath()); it != fs::directory_iterator(); ++it) {
|
||||
if (fs::is_regular_file(it->status()) && Plugin::IsValid(it->path().filename().string(), *this)) {
|
||||
Plugin temp(it->path().filename().string());
|
||||
BOOST_LOG_TRIVIAL(info) << "Found plugin: " << temp.Name();
|
||||
string name = it->path().filename().string();
|
||||
BOOST_LOG_TRIVIAL(info) << "Found plugin: " << name;
|
||||
|
||||
// Trim .ghost extension if present.
|
||||
if (boost::iends_with(name, ".ghost"))
|
||||
name = name.substr(0, name.length() - 6);
|
||||
|
||||
uintmax_t fileSize = fs::file_size(it->path());
|
||||
meanFileSize += fileSize;
|
||||
|
||||
//Insert the lowercased name as a key for case-insensitive matching.
|
||||
string name = boost::locale::to_lower(temp.Name());
|
||||
plugins.insert(pair<string, Plugin>(name, temp));
|
||||
sizeMap.insert(pair<uintmax_t, string>(fileSize, name));
|
||||
sizeMap.emplace(fileSize, name);
|
||||
}
|
||||
}
|
||||
meanFileSize /= sizeMap.size(); //Rounding error, but not important.
|
||||
|
||||
// Get the number of threads to use.
|
||||
// hardware_concurrency() may be zero, if so then use only one thread.
|
||||
size_t threadsToUse = std::min((size_t)thread::hardware_concurrency(), plugins.size());
|
||||
size_t threadsToUse = std::min((size_t)thread::hardware_concurrency(), sizeMap.size());
|
||||
threadsToUse = std::max(threadsToUse, (size_t)1);
|
||||
|
||||
// Divide the plugins up by thread.
|
||||
unsigned int pluginsPerThread = ceil((double)plugins.size() / threadsToUse);
|
||||
vector<vector<unordered_map<string, Plugin>::iterator>> pluginGroups(threadsToUse);
|
||||
BOOST_LOG_TRIVIAL(info) << "Loading " << plugins.size() << " plugins using " << threadsToUse << " threads, with up to " << pluginsPerThread << " plugins per thread.";
|
||||
unsigned int pluginsPerThread = ceil((double)sizeMap.size() / threadsToUse);
|
||||
vector<vector<string>> pluginGroups(threadsToUse);
|
||||
BOOST_LOG_TRIVIAL(info) << "Loading " << sizeMap.size() << " plugins using " << threadsToUse << " threads, with up to " << pluginsPerThread << " plugins per thread.";
|
||||
|
||||
// The plugins should be split between the threads so that the data
|
||||
// load is as evenly spread as possible.
|
||||
@@ -155,7 +150,7 @@ namespace loot {
|
||||
if (currentGroup == threadsToUse)
|
||||
currentGroup = 0;
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding plugin " << plugin.second << " to loading group " << currentGroup;
|
||||
pluginGroups[currentGroup].push_back(plugins.find(plugin.second));
|
||||
pluginGroups[currentGroup].push_back(plugin.second);
|
||||
++currentGroup;
|
||||
}
|
||||
|
||||
@@ -163,19 +158,11 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Starting plugin loading.";
|
||||
vector<thread> threads;
|
||||
while (threads.size() < threadsToUse) {
|
||||
vector<unordered_map<string, Plugin>::iterator>& pluginGroup = pluginGroups[threads.size()];
|
||||
threads.push_back(thread([this, &pluginGroup, headersOnly]() {
|
||||
for (auto it : pluginGroup) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Loading " << it->second.Name();
|
||||
try {
|
||||
it->second = Plugin(*this, it->second.Name(), headersOnly);
|
||||
}
|
||||
catch (exception &e) {
|
||||
BOOST_LOG_TRIVIAL(error) << it->second.Name() << ": Exception occurred: " << e.what();
|
||||
Plugin p(it->second.Name());
|
||||
p.Messages(list<Message>(1, Message(Message::error, lc::translate("An exception occurred while loading this plugin. Details:").str() + " " + e.what())));
|
||||
it->second = p;
|
||||
}
|
||||
vector<string>& pluginGroup = pluginGroups[threads.size()];
|
||||
threads.push_back(thread([&]() {
|
||||
for (auto pluginName : pluginGroup) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Loading " << pluginName;
|
||||
AddPlugin(Plugin(*this, pluginName, headersOnly));
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -193,6 +180,15 @@ namespace loot {
|
||||
return _pluginsFullyLoaded;
|
||||
}
|
||||
|
||||
bool Game::IsPluginActive(const std::string& pluginName) const {
|
||||
try {
|
||||
return GetPlugin(pluginName).IsActive();
|
||||
}
|
||||
catch (...) {
|
||||
return LoadOrderHandler::IsPluginActive(pluginName);
|
||||
}
|
||||
}
|
||||
|
||||
std::list<Game> ToGames(const std::list<GameSettings>& settings) {
|
||||
return list<Game>(settings.begin(), settings.end());
|
||||
}
|
||||
|
||||
@@ -28,12 +28,8 @@
|
||||
#include "game_cache.h"
|
||||
#include "game_settings.h"
|
||||
#include "load_order_handler.h"
|
||||
#include "../plugin/plugin.h"
|
||||
#include "../metadata_list.h"
|
||||
#include "../masterlist.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
@@ -47,16 +43,14 @@ namespace loot {
|
||||
|
||||
void Init(bool createFolder, const boost::filesystem::path& gameLocalAppData = "");
|
||||
|
||||
void RefreshActivePluginsList();
|
||||
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
|
||||
|
||||
void LoadPlugins(bool headersOnly); //Loads all installed plugins.
|
||||
bool ArePluginsFullyLoaded() const; // Checks if the game's plugins have already been loaded.
|
||||
|
||||
//Plugin data and metadata lists.
|
||||
Masterlist masterlist;
|
||||
MetadataList userlist;
|
||||
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited.
|
||||
// Check if the plugin is active by using the cached value if
|
||||
// available, and otherwise asking the load order handler.
|
||||
bool IsPluginActive(const std::string& pluginName) const;
|
||||
private:
|
||||
bool _pluginsFullyLoaded;
|
||||
};
|
||||
|
||||
@@ -40,22 +40,29 @@ namespace lc = boost::locale;
|
||||
|
||||
namespace loot {
|
||||
GameCache::GameCache() {}
|
||||
GameCache::GameCache(const GameCache& cache)
|
||||
: conditionCache(cache.conditionCache),
|
||||
crcCache(cache.crcCache),
|
||||
activePlugins(cache.activePlugins) {}
|
||||
GameCache::GameCache(const GameCache& cache) :
|
||||
masterlist(cache.masterlist),
|
||||
userlist(cache.userlist),
|
||||
conditionCache(cache.conditionCache),
|
||||
plugins(cache.plugins) {}
|
||||
|
||||
GameCache& GameCache::operator=(const GameCache& cache) {
|
||||
conditionCache = cache.conditionCache;
|
||||
crcCache = cache.crcCache;
|
||||
activePlugins = cache.activePlugins;
|
||||
if (&cache != this) {
|
||||
masterlist = cache.masterlist;
|
||||
userlist = cache.userlist;
|
||||
conditionCache = cache.conditionCache;
|
||||
plugins = cache.plugins;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void GameCache::CacheCrc(const std::string& plugin, uint32_t crc) {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
crcCache.insert(pair<string, uint32_t>(boost::locale::to_lower(plugin), crc));
|
||||
Masterlist & GameCache::GetMasterlist() {
|
||||
return masterlist;
|
||||
}
|
||||
|
||||
MetadataList & GameCache::GetUserlist() {
|
||||
return userlist;
|
||||
}
|
||||
|
||||
void GameCache::CacheCondition(const std::string& condition, bool result) {
|
||||
@@ -63,22 +70,6 @@ namespace loot {
|
||||
conditionCache.insert(pair<string, bool>(boost::locale::to_lower(condition), result));
|
||||
}
|
||||
|
||||
void GameCache::CacheActivePlugins(const std::unordered_set<std::string>& plugins) {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
activePlugins = plugins;
|
||||
}
|
||||
|
||||
uint32_t GameCache::GetCachedCrc(const std::string& plugin) const {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
|
||||
auto it = crcCache.find(boost::locale::to_lower(plugin));
|
||||
|
||||
if (it != crcCache.end())
|
||||
return it->second;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> GameCache::GetCachedCondition(const std::string& condition) const {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
|
||||
@@ -90,17 +81,33 @@ namespace loot {
|
||||
return std::pair<bool, bool>(false, false);
|
||||
}
|
||||
|
||||
bool GameCache::IsPluginActive(const std::string& plugin) const {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
std::set<Plugin> GameCache::GetPlugins() const {
|
||||
std::set<Plugin> output;
|
||||
std::transform(begin(plugins),
|
||||
end(plugins),
|
||||
inserter<set<Plugin>>(output, begin(output)),
|
||||
[](const pair<std::string, Plugin>& pluginPair) {
|
||||
return pluginPair.second;
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
return activePlugins.find(boost::locale::to_lower(plugin)) != activePlugins.end();
|
||||
const Plugin& GameCache::GetPlugin(const std::string & pluginName) const {
|
||||
auto it = plugins.find(boost::locale::to_lower(pluginName));
|
||||
if (it != end(plugins))
|
||||
return it->second;
|
||||
|
||||
throw error(error::invalid_args, "No plugin \"" + pluginName + "\" exists.");
|
||||
}
|
||||
|
||||
void GameCache::AddPlugin(const Plugin&& plugin) {
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
plugins.emplace(boost::locale::to_lower(plugin.Name()), plugin);
|
||||
}
|
||||
|
||||
void GameCache::ClearCache() {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
|
||||
conditionCache.clear();
|
||||
crcCache.clear();
|
||||
activePlugins.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,14 @@
|
||||
#ifndef __LOOT_GAME_CRC_CACHE__
|
||||
#define __LOOT_GAME_CRC_CACHE__
|
||||
|
||||
#include <string>
|
||||
#include "../metadata_list.h"
|
||||
#include "../masterlist.h"
|
||||
#include "../plugin/plugin.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace loot {
|
||||
class GameCache {
|
||||
@@ -39,22 +42,23 @@ namespace loot {
|
||||
|
||||
GameCache& operator=(const GameCache& cache);
|
||||
|
||||
void CacheCrc(const std::string& plugin, uint32_t crc);
|
||||
void CacheCondition(const std::string& condition, bool result);
|
||||
void CacheActivePlugins(const std::unordered_set<std::string>& plugins);
|
||||
Masterlist& GetMasterlist();
|
||||
MetadataList& GetUserlist();
|
||||
|
||||
// Returns 0 if no cached CRC.
|
||||
uint32_t GetCachedCrc(const std::string& plugin) const;
|
||||
// Returns false for second bool if no cached condition.
|
||||
std::pair<bool, bool> GetCachedCondition(const std::string& condition) const;
|
||||
bool IsPluginActive(const std::string& plugin) const;
|
||||
void CacheCondition(const std::string& condition, bool result);
|
||||
|
||||
std::set<Plugin> GetPlugins() const;
|
||||
const Plugin& GetPlugin(const std::string & pluginName) const;
|
||||
void AddPlugin(const Plugin&& plugin);
|
||||
|
||||
void ClearCache();
|
||||
private:
|
||||
//Caches for condition results, CRCs and active plugins.
|
||||
Masterlist masterlist;
|
||||
MetadataList userlist;
|
||||
std::unordered_map<std::string, bool> conditionCache;
|
||||
std::unordered_map<std::string, uint32_t> crcCache;
|
||||
std::unordered_set<std::string> activePlugins;
|
||||
std::unordered_map<std::string, Plugin> plugins;
|
||||
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
@@ -97,33 +97,28 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> LoadOrderHandler::GetActivePlugins() const {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Getting active plugins.";
|
||||
bool LoadOrderHandler::IsPluginActive(const std::string& pluginName) const {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Checking if plugin \"" << pluginName << "\" is active.";
|
||||
|
||||
char ** pluginArr;
|
||||
size_t pluginArrSize;
|
||||
unsigned int ret = lo_get_active_plugins(_gh, &pluginArr, &pluginArrSize);
|
||||
if (ret != LIBLO_OK && ret != LIBLO_WARN_BAD_FILENAME && ret != LIBLO_WARN_INVALID_LIST && ret != LIBLO_WARN_LO_MISMATCH) {
|
||||
bool result = false;
|
||||
unsigned int ret = lo_get_plugin_active(_gh, pluginName.c_str(), &result);
|
||||
if (ret != LIBLO_OK && ret != LIBLO_WARN_BAD_FILENAME) {
|
||||
const char * e = nullptr;
|
||||
string err;
|
||||
lo_get_error_message(&e);
|
||||
if (e == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "libloadorder failed to get the active plugins list. Details could not be fetched.";
|
||||
err = lc::translate("libloadorder failed to get the active plugins list. Details could not be fetched.").str();
|
||||
BOOST_LOG_TRIVIAL(error) << "libloadorder failed to check if a plugin is active. Details could not be fetched.";
|
||||
err = lc::translate("libloadorder failed to check if a plugin is active. Details could not be fetched.").str();
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(error) << "libloadorder failed to get the active plugins list. Details: " << e;
|
||||
err = lc::translate("libloadorder failed to get the active plugins list. Details:").str() + " " + e;
|
||||
BOOST_LOG_TRIVIAL(error) << "libloadorder failed to check if a plugin is active. Details: " << e;
|
||||
err = lc::translate("libloadorder failed to check if a plugin is active. Details:").str() + " " + e;
|
||||
}
|
||||
lo_cleanup();
|
||||
throw error(error::liblo_error, err);
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> activePlugins;
|
||||
for (size_t i = 0; i < pluginArrSize; ++i) {
|
||||
activePlugins.insert(boost::locale::to_lower(string(pluginArr[i])));
|
||||
}
|
||||
return activePlugins;
|
||||
return result;
|
||||
}
|
||||
|
||||
std::list<std::string> LoadOrderHandler::GetLoadOrder() const {
|
||||
|
||||
@@ -43,9 +43,10 @@ namespace loot {
|
||||
|
||||
void Init(const GameSettings& game, const boost::filesystem::path& gameLocalAppData = "");
|
||||
|
||||
std::unordered_set<std::string> GetActivePlugins() const;
|
||||
std::list<std::string> GetLoadOrder() const;
|
||||
|
||||
bool IsPluginActive(const std::string& pluginName) const;
|
||||
|
||||
//These modify game load order, even though const.
|
||||
void SetLoadOrder(const char * const * const loadOrder, const size_t numPlugins) const; // For API.
|
||||
void SetLoadOrder(const std::list<std::string>& loadOrder) const;
|
||||
|
||||
@@ -287,21 +287,27 @@ namespace loot {
|
||||
if (_game == nullptr)
|
||||
return;
|
||||
|
||||
uint32_t crc = _game->GetCachedCrc(file);
|
||||
uint32_t crc = 0;
|
||||
if (file == "LOOT")
|
||||
crc = GetCrc32(boost::filesystem::absolute("LOOT.exe"));
|
||||
else {
|
||||
// CRC could be for a plugin or a file.
|
||||
// Get the CRC from the game plugin cache if possible.
|
||||
try {
|
||||
crc = _game->GetPlugin(file).Crc();
|
||||
}
|
||||
catch (...) {}
|
||||
|
||||
if (crc == 0) {
|
||||
if (file == "LOOT")
|
||||
crc = GetCrc32(boost::filesystem::absolute("LOOT.exe"));
|
||||
if (boost::filesystem::exists(_game->DataPath() / file))
|
||||
crc = GetCrc32(_game->DataPath() / file);
|
||||
else if ((boost::iends_with(file, ".esp") || boost::iends_with(file, ".esm")) && boost::filesystem::exists(_game->DataPath() / (file + ".ghost")))
|
||||
crc = GetCrc32(_game->DataPath() / (file + ".ghost"));
|
||||
if (crc == 0) {
|
||||
if (boost::filesystem::exists(_game->DataPath() / file))
|
||||
crc = GetCrc32(_game->DataPath() / file);
|
||||
else if ((boost::iends_with(file, ".esp") || boost::iends_with(file, ".esm")) && boost::filesystem::exists(_game->DataPath() / (file + ".ghost")))
|
||||
crc = GetCrc32(_game->DataPath() / (file + ".ghost"));
|
||||
}
|
||||
else {
|
||||
result = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_game->CacheCrc(file, crc);
|
||||
}
|
||||
|
||||
result = checksum == crc;
|
||||
@@ -358,7 +364,7 @@ namespace loot {
|
||||
if (file == "LOOT")
|
||||
result = false;
|
||||
else
|
||||
result = Plugin(file).IsActive(*_game);
|
||||
result = _game->IsPluginActive(file);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << "Active check result: " << result;
|
||||
}
|
||||
|
||||
@@ -98,9 +98,10 @@ namespace loot {
|
||||
uint32_t crc = 0;
|
||||
|
||||
// Get the CRC from the game plugin cache if possible.
|
||||
auto pluginPairIt = game.plugins.find(boost::locale::to_lower(pluginName));
|
||||
if (pluginPairIt != game.plugins.end())
|
||||
crc = pluginPairIt->second.Crc();
|
||||
try {
|
||||
crc = game.GetPlugin(pluginName).Crc();
|
||||
}
|
||||
catch (...) {}
|
||||
|
||||
// Otherwise calculate it from the file.
|
||||
if (crc == 0) {
|
||||
|
||||
@@ -92,6 +92,10 @@ namespace loot {
|
||||
return pluginList;
|
||||
}
|
||||
|
||||
std::list<Message> MetadataList::Messages() const {
|
||||
return messages;
|
||||
}
|
||||
|
||||
// Merges multiple matching regex entries if any are found.
|
||||
PluginMetadata MetadataList::FindPlugin(const PluginMetadata& plugin) const {
|
||||
PluginMetadata match(plugin.Name());
|
||||
@@ -132,6 +136,10 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
|
||||
void MetadataList::AppendMessage(const Message& message) {
|
||||
messages.push_back(message);
|
||||
}
|
||||
|
||||
void MetadataList::EvalAllConditions(Game& game, const unsigned int language) {
|
||||
unordered_set<PluginMetadata> replacementSet;
|
||||
for (auto &plugin : plugins) {
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace loot {
|
||||
void clear();
|
||||
|
||||
std::list<PluginMetadata> Plugins() const;
|
||||
std::list<Message> Messages() const;
|
||||
|
||||
// Merges multiple matching regex entries if any are found.
|
||||
PluginMetadata FindPlugin(const PluginMetadata& plugin) const;
|
||||
@@ -62,13 +63,15 @@ namespace loot {
|
||||
// be required for other plugins.
|
||||
void ErasePlugin(const PluginMetadata& plugin);
|
||||
|
||||
void AppendMessage(const Message& message);
|
||||
|
||||
// Eval plugin conditions.
|
||||
void EvalAllConditions(Game& game, const unsigned int language);
|
||||
|
||||
std::list<Message> messages;
|
||||
protected:
|
||||
std::unordered_set<PluginMetadata> plugins;
|
||||
std::list<PluginMetadata> regexPlugins;
|
||||
std::list<Message> messages;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -37,19 +37,11 @@ using namespace std;
|
||||
using libespm::FormId;
|
||||
|
||||
namespace loot {
|
||||
// TODO: Remove the name-only constructor.
|
||||
Plugin::Plugin(const std::string& n) :
|
||||
PluginMetadata(n),
|
||||
libespm::Plugin(libespm::GameId::SKYRIM),
|
||||
_isEmpty(true),
|
||||
_loadsBsa(false),
|
||||
crc(0),
|
||||
numOverrideRecords(0) {}
|
||||
|
||||
Plugin::Plugin(Game& game, const std::string& name, const bool headerOnly) :
|
||||
Plugin::Plugin(const Game& game, const std::string& name, const bool headerOnly) :
|
||||
PluginMetadata(name),
|
||||
libespm::Plugin(game.LibespmId()),
|
||||
_isEmpty(true),
|
||||
_isActive(false),
|
||||
_loadsBsa(false),
|
||||
crc(0),
|
||||
numOverrideRecords(0) {
|
||||
@@ -67,7 +59,6 @@ namespace loot {
|
||||
if (!headerOnly) {
|
||||
BOOST_LOG_TRIVIAL(trace) << Name() << ": Caching CRC value.";
|
||||
crc = GetCrc32(filepath);
|
||||
game.CacheCrc(Name(), crc);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << Name() << ": Counting override FormIDs.";
|
||||
@@ -97,6 +88,8 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
}
|
||||
// Get whether the plugin is active or not.
|
||||
_isActive = game.IsPluginActive(Name());
|
||||
|
||||
// Get whether the plugin loads a BSA or not.
|
||||
if (game.Id() == Game::tes5) {
|
||||
@@ -115,7 +108,7 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Cannot read plugin file \"" << Name() << "\". Details: " << e.what();
|
||||
BOOST_LOG_TRIVIAL(error) << "Cannot read plugin file \"" << name << "\". Details: " << e.what();
|
||||
messages.push_back(loot::Message(loot::Message::error, (boost::format(boost::locale::translate("Cannot read \"%1%\". Details: %2%")) % name % e.what()).str()));
|
||||
}
|
||||
|
||||
@@ -124,8 +117,6 @@ namespace loot {
|
||||
|
||||
bool Plugin::DoFormIDsOverlap(const Plugin& plugin) const {
|
||||
//Basically std::set_intersection except with an early exit instead of an append to results.
|
||||
//BOOST_LOG_TRIVIAL(trace) << "Checking for FormID overlap between \"" << name << "\" and \"" << plugin.Name() << "\".";
|
||||
|
||||
set<FormId> formIds(getFormIds());
|
||||
set<FormId> otherFormIds(plugin.getFormIds());
|
||||
auto i = begin(formIds);
|
||||
@@ -193,8 +184,12 @@ namespace loot {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Plugin::IsActive(const Game& game) const {
|
||||
return game.IsPluginActive(Name());
|
||||
bool Plugin::operator < (const Plugin & rhs) const {
|
||||
return boost::ilexicographical_compare(Name(), rhs.Name());;
|
||||
}
|
||||
|
||||
bool Plugin::IsActive() const {
|
||||
return _isActive;
|
||||
}
|
||||
|
||||
uint32_t Plugin::Crc() const {
|
||||
@@ -203,7 +198,7 @@ namespace loot {
|
||||
|
||||
bool Plugin::CheckInstallValidity(const Game& game) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Checking that the current install is valid according to " << Name() << "'s data.";
|
||||
if (IsActive(game)) {
|
||||
if (IsActive()) {
|
||||
auto pluginExists = [](const Game& game, const std::string& file) {
|
||||
return boost::filesystem::exists(game.DataPath() / file)
|
||||
|| ((boost::iends_with(file, ".esp") || boost::iends_with(file, ".esm")) && boost::filesystem::exists(game.DataPath() / (file + ".ghost")));
|
||||
@@ -214,7 +209,7 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << Name() << "\" requires \"" << master << "\", but it is missing.";
|
||||
messages.push_back(Message(Message::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be installed, but it is missing.")) % master).str()));
|
||||
}
|
||||
else if (!Plugin(master).IsActive(game)) {
|
||||
else if (!game.IsPluginActive(master)) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << Name() << "\" requires \"" << master << "\", but it is inactive.";
|
||||
messages.push_back(Message(Message::error, (boost::format(boost::locale::translate("This plugin requires \"%1%\" to be active, but it is inactive.")) % master).str()));
|
||||
}
|
||||
@@ -228,7 +223,7 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
for (const auto &inc : Incs()) {
|
||||
if (pluginExists(game, inc.Name()) && Plugin(inc.Name()).IsActive(game)) {
|
||||
if (pluginExists(game, inc.Name()) && game.IsPluginActive(inc.Name())) {
|
||||
BOOST_LOG_TRIVIAL(error) << "\"" << Name() << "\" is incompatible with \"" << inc.Name() << "\", but both are present.";
|
||||
messages.push_back(loot::Message(Message::error, (boost::format(boost::locale::translate("This plugin is incompatible with \"%1%\", but both are present.")) % inc.Name()).str()));
|
||||
}
|
||||
|
||||
@@ -41,8 +41,7 @@ namespace loot {
|
||||
|
||||
class Plugin : public PluginMetadata, private libespm::Plugin {
|
||||
public:
|
||||
Plugin(const std::string& name);
|
||||
Plugin(Game& game, const std::string& name, const bool headerOnly);
|
||||
Plugin(const Game& game, const std::string& name, const bool headerOnly);
|
||||
|
||||
using libespm::Plugin::getDescription;
|
||||
using libespm::Plugin::getFormIds;
|
||||
@@ -54,7 +53,7 @@ namespace loot {
|
||||
size_t NumOverrideFormIDs() const;
|
||||
|
||||
bool LoadsBSA() const;
|
||||
bool IsActive(const Game& game) const;
|
||||
bool IsActive() const;
|
||||
|
||||
//Load ordering functions.
|
||||
bool DoFormIDsOverlap(const Plugin& plugin) const;
|
||||
@@ -63,8 +62,11 @@ namespace loot {
|
||||
//Validity checks.
|
||||
bool CheckInstallValidity(const Game& game); //Checks that reqs and masters are all present, and that no incs are present. Returns true if the plugin is dirty.
|
||||
static bool IsValid(const std::string& filename, const Game& game);
|
||||
|
||||
bool operator < (const Plugin& rhs) const;
|
||||
private:
|
||||
bool _isEmpty; // Does the plugin contain any records other than the TES4 header?
|
||||
bool _isActive;
|
||||
bool _loadsBsa;
|
||||
std::string version; //Obtained from description field.
|
||||
uint32_t crc;
|
||||
|
||||
@@ -177,21 +177,16 @@ namespace loot {
|
||||
// Using a set of plugin names followed by finding the matching key
|
||||
// in the unordered map, as it's probably faster than copying the
|
||||
// full plugin objects then sorting them.
|
||||
set<string> pluginNames;
|
||||
for (const auto &plugin : game.plugins) {
|
||||
pluginNames.insert(plugin.first);
|
||||
}
|
||||
|
||||
for (const auto &plugin : pluginNames) {
|
||||
vertex_t v = boost::add_vertex(game.plugins.find(plugin)->second, graph);
|
||||
for (const auto &plugin : game.GetPlugins()) {
|
||||
vertex_t v = boost::add_vertex(plugin, graph);
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging for plugin \"" << graph[v].Name() << "\"";
|
||||
|
||||
//Check if there is a plugin entry in the masterlist. This will also find matching regex entries.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging masterlist data down to plugin list data.";
|
||||
graph[v].MergeMetadata(game.masterlist.FindPlugin(graph[v]));
|
||||
graph[v].MergeMetadata(game.GetMasterlist().FindPlugin(graph[v]));
|
||||
|
||||
//Check if there is a plugin entry in the userlist. This will also find matching regex entries.
|
||||
PluginMetadata ulistPlugin = game.userlist.FindPlugin(graph[v]);
|
||||
PluginMetadata ulistPlugin = game.GetUserlist().FindPlugin(graph[v]);
|
||||
|
||||
if (!ulistPlugin.HasNameOnly() && ulistPlugin.Enabled()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Merging userlist data down to plugin list data.";
|
||||
|
||||
+64
-63
@@ -354,15 +354,15 @@ namespace loot {
|
||||
decLength = 2;
|
||||
}
|
||||
size_t i = 0;
|
||||
for (const auto& plugin : plugins) {
|
||||
if (Plugin(plugin).IsActive(_lootState.CurrentGame())) {
|
||||
for (const auto& pluginName : plugins) {
|
||||
if (_lootState.CurrentGame().IsPluginActive(pluginName)) {
|
||||
ss << setw(decLength) << i << " " << hex << setw(2) << i << dec << " ";
|
||||
++i;
|
||||
}
|
||||
else {
|
||||
ss << setw(decLength + 4) << " ";
|
||||
}
|
||||
ss << plugin << "\r\n";
|
||||
ss << pluginName << "\r\n";
|
||||
}
|
||||
CopyToClipboard(ss.str());
|
||||
callback->Success("");
|
||||
@@ -400,7 +400,7 @@ namespace loot {
|
||||
void Handler::GetConflictingPlugins(const std::string& pluginName, CefRefPtr<CefFrame> frame, CefRefPtr<Callback> callback) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Searching for plugins that conflict with " << pluginName;
|
||||
|
||||
auto pluginIt = _lootState.CurrentGame().plugins.find(boost::locale::to_lower(pluginName));
|
||||
auto plugin = _lootState.CurrentGame().GetPlugin(pluginName);
|
||||
|
||||
// Checking for FormID overlap will only work if the plugins have been loaded, so check if
|
||||
// the plugins have been fully loaded, and if not load all plugins.
|
||||
@@ -411,13 +411,13 @@ namespace loot {
|
||||
|
||||
SendProgressUpdate(frame, loc::translate("Checking for conflicting plugins..."));
|
||||
YAML::Node node;
|
||||
for (const auto& pluginPair : _lootState.CurrentGame().plugins) {
|
||||
for (const auto& otherPlugin : _lootState.CurrentGame().GetPlugins()) {
|
||||
YAML::Node pluginNode;
|
||||
|
||||
pluginNode["crc"] = pluginPair.second.Crc();
|
||||
pluginNode["isEmpty"] = pluginPair.second.IsEmpty();
|
||||
if (pluginIt != _lootState.CurrentGame().plugins.end() && pluginIt->second.DoFormIDsOverlap(pluginPair.second)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Found conflicting plugin: " << pluginPair.second.Name();
|
||||
pluginNode["crc"] = otherPlugin.Crc();
|
||||
pluginNode["isEmpty"] = otherPlugin.IsEmpty();
|
||||
if (plugin.DoFormIDsOverlap(otherPlugin)) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Found conflicting plugin: " << otherPlugin.Name();
|
||||
pluginNode["conflicts"] = true;
|
||||
}
|
||||
else {
|
||||
@@ -425,13 +425,13 @@ namespace loot {
|
||||
}
|
||||
|
||||
// Plugin loading may have produced an error message, so rederive displayed data.
|
||||
YAML::Node derivedNode = GenerateDerivedMetadata(pluginPair.second.Name());
|
||||
YAML::Node derivedNode = GenerateDerivedMetadata(otherPlugin.Name());
|
||||
for (const auto &pair : derivedNode) {
|
||||
const string key = pair.first.as<string>();
|
||||
pluginNode[key] = pair.second;
|
||||
}
|
||||
|
||||
node[pluginPair.second.Name()] = pluginNode;
|
||||
node[otherPlugin.Name()] = pluginNode;
|
||||
}
|
||||
|
||||
if (node.size() > 0)
|
||||
@@ -444,8 +444,8 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Copying metadata for plugin " << pluginName;
|
||||
|
||||
// Get metadata from masterlist and userlist.
|
||||
PluginMetadata plugin = _lootState.CurrentGame().masterlist.FindPlugin(pluginName);
|
||||
plugin.MergeMetadata(_lootState.CurrentGame().userlist.FindPlugin(pluginName));
|
||||
PluginMetadata plugin = _lootState.CurrentGame().GetMasterlist().FindPlugin(pluginName);
|
||||
plugin.MergeMetadata(_lootState.CurrentGame().GetUserlist().FindPlugin(pluginName));
|
||||
|
||||
// Generate text representation.
|
||||
string text;
|
||||
@@ -465,10 +465,10 @@ namespace loot {
|
||||
std::string Handler::ClearPluginMetadata(const std::string& pluginName) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Clearing user metadata for plugin " << pluginName;
|
||||
|
||||
_lootState.CurrentGame().userlist.ErasePlugin(PluginMetadata(pluginName));
|
||||
_lootState.CurrentGame().GetUserlist().ErasePlugin(PluginMetadata(pluginName));
|
||||
|
||||
// Save userlist edits.
|
||||
_lootState.CurrentGame().userlist.Save(_lootState.CurrentGame().UserlistPath());
|
||||
_lootState.CurrentGame().GetUserlist().Save(_lootState.CurrentGame().UserlistPath());
|
||||
|
||||
// Now rederive the displayed metadata from the masterlist.
|
||||
YAML::Node derivedMetadata = GenerateDerivedMetadata(pluginName);
|
||||
@@ -484,7 +484,7 @@ namespace loot {
|
||||
PluginMetadata newUserlistEntry(pluginMetadata["name"].as<string>());
|
||||
|
||||
// Find existing userlist entry.
|
||||
PluginMetadata ulistPlugin = _lootState.CurrentGame().userlist.FindPlugin(newUserlistEntry);
|
||||
PluginMetadata ulistPlugin = _lootState.CurrentGame().GetUserlist().FindPlugin(newUserlistEntry);
|
||||
|
||||
// First sort out the priority value. This is only given if it was changed.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Calculating userlist metadata priority value from Javascript variables.";
|
||||
@@ -537,28 +537,28 @@ namespace loot {
|
||||
|
||||
// For cleanliness, only data that does not duplicate masterlist and plugin data should be retained, so diff that.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Removing any user metadata that duplicates masterlist metadata.";
|
||||
auto pluginIt = _lootState.CurrentGame().plugins.find(boost::locale::to_lower(newUserlistEntry.Name()));
|
||||
if (pluginIt != _lootState.CurrentGame().plugins.end()) {
|
||||
Plugin tempPlugin(pluginIt->second);
|
||||
tempPlugin.MergeMetadata(_lootState.CurrentGame().masterlist.FindPlugin(newUserlistEntry));
|
||||
try {
|
||||
Plugin tempPlugin(_lootState.CurrentGame().GetPlugin(newUserlistEntry.Name()));
|
||||
tempPlugin.MergeMetadata(_lootState.CurrentGame().GetMasterlist().FindPlugin(newUserlistEntry));
|
||||
newUserlistEntry = newUserlistEntry.NewMetadata(tempPlugin);
|
||||
}
|
||||
else
|
||||
newUserlistEntry = newUserlistEntry.NewMetadata(_lootState.CurrentGame().masterlist.FindPlugin(newUserlistEntry));
|
||||
catch (...) {
|
||||
newUserlistEntry = newUserlistEntry.NewMetadata(_lootState.CurrentGame().GetMasterlist().FindPlugin(newUserlistEntry));
|
||||
}
|
||||
|
||||
// Now erase any existing userlist entry.
|
||||
if (!ulistPlugin.HasNameOnly()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Erasing the existing userlist entry.";
|
||||
_lootState.CurrentGame().userlist.ErasePlugin(ulistPlugin);
|
||||
_lootState.CurrentGame().GetUserlist().ErasePlugin(ulistPlugin);
|
||||
}
|
||||
// Add a new userlist entry if necessary.
|
||||
if (!newUserlistEntry.HasNameOnly()) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Adding new metadata to new userlist entry.";
|
||||
_lootState.CurrentGame().userlist.AddPlugin(newUserlistEntry);
|
||||
_lootState.CurrentGame().GetUserlist().AddPlugin(newUserlistEntry);
|
||||
}
|
||||
|
||||
// Save edited userlist.
|
||||
_lootState.CurrentGame().userlist.Save(_lootState.CurrentGame().UserlistPath());
|
||||
_lootState.CurrentGame().GetUserlist().Save(_lootState.CurrentGame().UserlistPath());
|
||||
|
||||
// Now rederive the derived metadata.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Returning newly derived display metadata.";
|
||||
@@ -642,20 +642,18 @@ namespace loot {
|
||||
// First clear CRC and condition caches, otherwise they could lead to incorrect evaluations.
|
||||
_lootState.CurrentGame().ClearCache();
|
||||
|
||||
// Also refresh active plugins list.
|
||||
_lootState.CurrentGame().RefreshActivePluginsList();
|
||||
|
||||
bool isFirstLoad = _lootState.CurrentGame().plugins.empty();
|
||||
bool isFirstLoad = _lootState.CurrentGame().GetPlugins().empty();
|
||||
_lootState.CurrentGame().LoadPlugins(true);
|
||||
|
||||
//Sort plugins into their load order.
|
||||
list<loot::Plugin> installed;
|
||||
list<string> loadOrder = _lootState.CurrentGame().GetLoadOrder();
|
||||
for (const auto &pluginName : loadOrder) {
|
||||
const auto pos = _lootState.CurrentGame().plugins.find(boost::locale::to_lower(pluginName));
|
||||
|
||||
if (pos != _lootState.CurrentGame().plugins.end())
|
||||
installed.push_back(pos->second);
|
||||
try {
|
||||
const auto plugin = _lootState.CurrentGame().GetPlugin(pluginName);
|
||||
installed.push_back(plugin);
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
list<Message> parsingErrors;
|
||||
@@ -665,7 +663,7 @@ namespace loot {
|
||||
SendProgressUpdate(frame, loc::translate("Parsing masterlist..."));
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist.";
|
||||
try {
|
||||
_lootState.CurrentGame().masterlist.Load(_lootState.CurrentGame().MasterlistPath());
|
||||
_lootState.CurrentGame().GetMasterlist().Load(_lootState.CurrentGame().MasterlistPath());
|
||||
}
|
||||
catch (exception &e) {
|
||||
parsingErrors.push_back(Message(Message::error, (boost::format(loc::translate(
|
||||
@@ -682,7 +680,7 @@ namespace loot {
|
||||
SendProgressUpdate(frame, loc::translate("Parsing userlist..."));
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing userlist.";
|
||||
try {
|
||||
_lootState.CurrentGame().userlist.Load(_lootState.CurrentGame().UserlistPath());
|
||||
_lootState.CurrentGame().GetUserlist().Load(_lootState.CurrentGame().UserlistPath());
|
||||
}
|
||||
catch (exception &e) {
|
||||
parsingErrors.push_back(Message(Message::error, (boost::format(loc::translate(
|
||||
@@ -713,7 +711,7 @@ namespace loot {
|
||||
|
||||
// Store the masterlist revision and date.
|
||||
try {
|
||||
Masterlist::Info info = _lootState.CurrentGame().masterlist.GetInfo(_lootState.CurrentGame().MasterlistPath(), true);
|
||||
Masterlist::Info info = _lootState.CurrentGame().GetMasterlist().GetInfo(_lootState.CurrentGame().MasterlistPath(), true);
|
||||
gameNode["masterlist"]["revision"] = info.revision;
|
||||
gameNode["masterlist"]["date"] = info.date;
|
||||
}
|
||||
@@ -733,15 +731,15 @@ namespace loot {
|
||||
// description as part of it.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Getting masterlist metadata for: " << plugin.Name();
|
||||
Plugin mlistPlugin(plugin);
|
||||
mlistPlugin.MergeMetadata(_lootState.CurrentGame().masterlist.FindPlugin(plugin));
|
||||
mlistPlugin.MergeMetadata(_lootState.CurrentGame().GetMasterlist().FindPlugin(plugin));
|
||||
|
||||
// Now do the same again for any userlist data.
|
||||
BOOST_LOG_TRIVIAL(trace) << "Getting userlist metadata for: " << plugin.Name();
|
||||
PluginMetadata ulistPlugin(_lootState.CurrentGame().userlist.FindPlugin(plugin));
|
||||
PluginMetadata ulistPlugin(_lootState.CurrentGame().GetUserlist().FindPlugin(plugin));
|
||||
|
||||
pluginNode["__type"] = "Plugin"; // For conversion back into a JS typed object.
|
||||
pluginNode["name"] = plugin.Name();
|
||||
pluginNode["isActive"] = plugin.IsActive(_lootState.CurrentGame());
|
||||
pluginNode["isActive"] = plugin.IsActive();
|
||||
pluginNode["isEmpty"] = plugin.IsEmpty();
|
||||
pluginNode["isMaster"] = plugin.isMasterFile();
|
||||
pluginNode["loadsBSA"] = plugin.LoadsBSA();
|
||||
@@ -800,12 +798,14 @@ namespace loot {
|
||||
//Evaluate any conditions in the global messages.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
|
||||
list<Message> messages = parsingErrors;
|
||||
auto metadataListMessages = _lootState.CurrentGame().GetMasterlist().Messages();
|
||||
messages.insert(end(messages),
|
||||
begin(metadataListMessages),
|
||||
end(metadataListMessages));
|
||||
metadataListMessages = _lootState.CurrentGame().GetUserlist().Messages();
|
||||
messages.insert(messages.end(),
|
||||
_lootState.CurrentGame().masterlist.messages.begin(),
|
||||
_lootState.CurrentGame().masterlist.messages.end());
|
||||
messages.insert(messages.end(),
|
||||
_lootState.CurrentGame().userlist.messages.begin(),
|
||||
_lootState.CurrentGame().userlist.messages.end());
|
||||
begin(metadataListMessages),
|
||||
end(metadataListMessages));
|
||||
try {
|
||||
list<Message>::iterator it = messages.begin();
|
||||
while (it != messages.end()) {
|
||||
@@ -851,20 +851,20 @@ namespace loot {
|
||||
bool wasChanged = true;
|
||||
try {
|
||||
SendProgressUpdate(frame, loc::translate("Updating and parsing masterlist..."));
|
||||
wasChanged = _lootState.CurrentGame().masterlist.Update(_lootState.CurrentGame());
|
||||
wasChanged = _lootState.CurrentGame().GetMasterlist().Update(_lootState.CurrentGame());
|
||||
}
|
||||
catch (loot::error &e) {
|
||||
if (e.code() == loot::error::ok) {
|
||||
// There was a parsing error, but roll-back was successful, so the process
|
||||
|
||||
// should still complete.
|
||||
_lootState.CurrentGame().masterlist.messages.push_back(Message(Message::error, e.what()));
|
||||
_lootState.CurrentGame().GetMasterlist().AppendMessage(Message(Message::error, e.what()));
|
||||
wasChanged = true;
|
||||
}
|
||||
else {
|
||||
// Error wasn't a parsing error. Need to try parsing masterlist if it exists.
|
||||
try {
|
||||
_lootState.CurrentGame().masterlist.Load(_lootState.CurrentGame().MasterlistPath());
|
||||
_lootState.CurrentGame().GetMasterlist().Load(_lootState.CurrentGame().MasterlistPath());
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
@@ -879,7 +879,7 @@ namespace loot {
|
||||
|
||||
// Store the masterlist revision and date.
|
||||
try {
|
||||
Masterlist::Info info = _lootState.CurrentGame().masterlist.GetInfo(_lootState.CurrentGame().MasterlistPath(), true);
|
||||
Masterlist::Info info = _lootState.CurrentGame().GetMasterlist().GetInfo(_lootState.CurrentGame().MasterlistPath(), true);
|
||||
gameNode["masterlist"]["revision"] = info.revision;
|
||||
gameNode["masterlist"]["date"] = info.date;
|
||||
}
|
||||
@@ -888,9 +888,9 @@ namespace loot {
|
||||
gameNode["masterlist"]["date"] = e.what();
|
||||
}
|
||||
|
||||
for (const auto& pluginPair : _lootState.CurrentGame().plugins) {
|
||||
Plugin mlistPlugin(pluginPair.second);
|
||||
mlistPlugin.MergeMetadata(_lootState.CurrentGame().masterlist.FindPlugin(pluginPair.second));
|
||||
for (const auto& plugin : _lootState.CurrentGame().GetPlugins()) {
|
||||
Plugin mlistPlugin(plugin);
|
||||
mlistPlugin.MergeMetadata(_lootState.CurrentGame().GetMasterlist().FindPlugin(plugin));
|
||||
|
||||
YAML::Node pluginNode;
|
||||
if (!mlistPlugin.HasNameOnly()) {
|
||||
@@ -906,7 +906,7 @@ namespace loot {
|
||||
|
||||
// Now merge masterlist and userlist metadata and evaluate,
|
||||
// putting any resulting metadata into the base of the pluginNode.
|
||||
YAML::Node derivedNode = GenerateDerivedMetadata(pluginPair.second.Name());
|
||||
YAML::Node derivedNode = GenerateDerivedMetadata(plugin.Name());
|
||||
|
||||
for (const auto &pair : derivedNode) {
|
||||
const string key = pair.first.as<string>();
|
||||
@@ -918,7 +918,7 @@ namespace loot {
|
||||
|
||||
//Evaluate any conditions in the global messages.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
|
||||
list<Message> messages = _lootState.CurrentGame().masterlist.messages;
|
||||
list<Message> messages = _lootState.CurrentGame().GetMasterlist().Messages();
|
||||
try {
|
||||
list<Message>::iterator it = messages.begin();
|
||||
while (it != messages.end()) {
|
||||
@@ -955,16 +955,16 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Clearing all user metadata.";
|
||||
// Record which plugins have userlist entries.
|
||||
vector<string> userlistPlugins;
|
||||
for (const auto &plugin : _lootState.CurrentGame().userlist.Plugins()) {
|
||||
for (const auto &plugin : _lootState.CurrentGame().GetUserlist().Plugins()) {
|
||||
userlistPlugins.push_back(plugin.Name());
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << "User metadata exists for " << userlistPlugins.size() << " plugins.";
|
||||
|
||||
// Clear the user metadata.
|
||||
_lootState.CurrentGame().userlist.clear();
|
||||
_lootState.CurrentGame().GetUserlist().clear();
|
||||
|
||||
// Save userlist edits.
|
||||
_lootState.CurrentGame().userlist.Save(_lootState.CurrentGame().UserlistPath());
|
||||
_lootState.CurrentGame().GetUserlist().Save(_lootState.CurrentGame().UserlistPath());
|
||||
|
||||
// Regenerate the derived metadata (priority, messages, tags and dirty state)
|
||||
// for any plugins with userlist entries.
|
||||
@@ -1075,15 +1075,16 @@ namespace loot {
|
||||
|
||||
YAML::Node Handler::GenerateDerivedMetadata(const std::string& pluginName) {
|
||||
// Now rederive the displayed metadata from the masterlist and userlist.
|
||||
auto pluginIt = _lootState.CurrentGame().plugins.find(boost::locale::to_lower(pluginName));
|
||||
if (pluginIt != _lootState.CurrentGame().plugins.end()) {
|
||||
PluginMetadata master(_lootState.CurrentGame().masterlist.FindPlugin(pluginIt->second));
|
||||
PluginMetadata user(_lootState.CurrentGame().userlist.FindPlugin(pluginIt->second));
|
||||
try {
|
||||
auto plugin = _lootState.CurrentGame().GetPlugin(pluginName);
|
||||
PluginMetadata master(_lootState.CurrentGame().GetMasterlist().FindPlugin(plugin));
|
||||
PluginMetadata user(_lootState.CurrentGame().GetUserlist().FindPlugin(plugin));
|
||||
|
||||
return this->GenerateDerivedMetadata(pluginIt->second, master, user);
|
||||
return this->GenerateDerivedMetadata(plugin, master, user);
|
||||
}
|
||||
catch (...) {
|
||||
return YAML::Node();
|
||||
}
|
||||
|
||||
return YAML::Node();
|
||||
}
|
||||
|
||||
void Handler::CopyToClipboard(const std::string& text) {
|
||||
|
||||
@@ -133,33 +133,8 @@ TEST_F(Game, Init) {
|
||||
ASSERT_FALSE(boost::filesystem::exists(loot::g_path_local / game.FolderName()));
|
||||
EXPECT_THROW(game.Init(false), loot::error);
|
||||
EXPECT_FALSE(boost::filesystem::exists(loot::g_path_local / game.FolderName()));
|
||||
EXPECT_FALSE(game.IsPluginActive("Skyrim.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("skyrim.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Master Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Plugin Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Plugin Dependent.esp"));
|
||||
|
||||
game = loot::Game(loot::Game::tes5).SetGamePath(dataPath.parent_path());
|
||||
EXPECT_FALSE(game.IsPluginActive("Skyrim.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("skyrim.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Master Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Plugin Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Plugin Dependent.esp"));
|
||||
|
||||
EXPECT_NO_THROW(game.Init(false, localPath));
|
||||
EXPECT_FALSE(boost::filesystem::exists(loot::g_path_local / game.FolderName()));
|
||||
EXPECT_TRUE(game.IsPluginActive("Skyrim.esm"));
|
||||
@@ -200,32 +175,6 @@ TEST_F(Game, Init) {
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(Game, RefreshActivePluginsList) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
|
||||
// Throw because the load order handler hasn't been initialised.
|
||||
EXPECT_THROW(game.RefreshActivePluginsList(), loot::error);
|
||||
|
||||
// Calling Init calls RefreshActivePluginsList, so clear it before testing
|
||||
// separately.
|
||||
game.Init(false, localPath);
|
||||
EXPECT_NO_THROW(game.ClearCache());
|
||||
EXPECT_NO_THROW(game.RefreshActivePluginsList());
|
||||
EXPECT_TRUE(game.IsPluginActive("Skyrim.esm"));
|
||||
EXPECT_TRUE(game.IsPluginActive("skyrim.esm"));
|
||||
EXPECT_TRUE(game.IsPluginActive("Blank.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Master Dependent.esm"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Master Dependent.esp"));
|
||||
EXPECT_TRUE(game.IsPluginActive("Blank - Different Master Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Plugin Dependent.esp"));
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank - Different Plugin Dependent.esp"));
|
||||
}
|
||||
|
||||
TEST_F(Game, RedatePlugins) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
@@ -267,11 +216,11 @@ TEST_F(Game, LoadPlugins) {
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
|
||||
EXPECT_NO_THROW(game.LoadPlugins(false));
|
||||
EXPECT_EQ(11, game.plugins.size());
|
||||
EXPECT_EQ(11, game.GetPlugins().size());
|
||||
|
||||
// Check that all the plugins' data have loaded correctly.
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("skyrim.esm"));
|
||||
loot::Plugin plugin = game.plugins.find("skyrim.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("Skyrim.esm"));
|
||||
loot::Plugin plugin = game.GetPlugin("Skyrim.esm");
|
||||
EXPECT_EQ("Skyrim.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -292,8 +241,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x187BE342, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank.esm"));
|
||||
plugin = game.plugins.find("blank.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank.esm"));
|
||||
plugin = game.GetPlugin("blank.esm");
|
||||
EXPECT_EQ("Blank.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -314,8 +263,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x187BE342, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different.esm"));
|
||||
plugin = game.plugins.find("blank - different.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("Blank - Different.esm"));
|
||||
plugin = game.GetPlugin("Blank - Different.esm");
|
||||
EXPECT_EQ("Blank - Different.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -335,8 +284,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x64B9F757, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - master dependent.esm"));
|
||||
plugin = game.plugins.find("blank - master dependent.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - master dependent.esm"));
|
||||
plugin = game.GetPlugin("blank - master dependent.esm");
|
||||
EXPECT_EQ("Blank - Master Dependent.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -357,8 +306,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0xB2D4119E, plugin.Crc());
|
||||
EXPECT_EQ(4, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different master dependent.esm"));
|
||||
plugin = game.plugins.find("blank - different master dependent.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different master dependent.esm"));
|
||||
plugin = game.GetPlugin("blank - different master dependent.esm");
|
||||
EXPECT_EQ("Blank - Different Master Dependent.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -378,8 +327,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0xAADF6710, plugin.Crc());
|
||||
EXPECT_EQ(4, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank.esp"));
|
||||
plugin = game.plugins.find("blank.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank.esp"));
|
||||
plugin = game.GetPlugin("blank.esp");
|
||||
EXPECT_EQ("Blank.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -396,8 +345,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x24F0E2A1, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different.esp"));
|
||||
plugin = game.plugins.find("blank - different.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different.esp"));
|
||||
plugin = game.GetPlugin("blank - different.esp");
|
||||
EXPECT_EQ("Blank - Different.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -413,8 +362,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0xD4C9B7AE, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - master dependent.esp"));
|
||||
plugin = game.plugins.find("blank - master dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - master dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - master dependent.esp");
|
||||
EXPECT_EQ("Blank - Master Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -431,8 +380,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x832152DC, plugin.Crc());
|
||||
EXPECT_EQ(2, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different master dependent.esp"));
|
||||
plugin = game.plugins.find("blank - different master dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different master dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - different master dependent.esp");
|
||||
EXPECT_EQ("Blank - Different Master Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -448,8 +397,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x3AD17683, plugin.Crc());
|
||||
EXPECT_EQ(2, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - plugin dependent.esp"));
|
||||
plugin = game.plugins.find("blank - plugin dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - plugin dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - plugin dependent.esp");
|
||||
EXPECT_EQ("Blank - Plugin Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -464,8 +413,8 @@ TEST_F(Game, LoadPlugins) {
|
||||
EXPECT_EQ(0x28EF26DB, plugin.Crc());
|
||||
EXPECT_EQ(1, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different plugin dependent.esp"));
|
||||
plugin = game.plugins.find("blank - different plugin dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different plugin dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - different plugin dependent.esp");
|
||||
EXPECT_EQ("Blank - Different Plugin Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -485,11 +434,11 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
|
||||
EXPECT_NO_THROW(game.LoadPlugins(true));
|
||||
EXPECT_EQ(11, game.plugins.size());
|
||||
EXPECT_EQ(11, game.GetPlugins().size());
|
||||
|
||||
// Check that all the plugins' data have loaded correctly.
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("skyrim.esm"));
|
||||
loot::Plugin plugin = game.plugins.find("skyrim.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("Skyrim.esm"));
|
||||
loot::Plugin plugin = game.GetPlugin("Skyrim.esm");
|
||||
EXPECT_EQ("Skyrim.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -499,8 +448,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank.esm"));
|
||||
plugin = game.plugins.find("blank.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank.esm"));
|
||||
plugin = game.GetPlugin("blank.esm");
|
||||
EXPECT_EQ("Blank.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -510,8 +459,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different.esm"));
|
||||
plugin = game.plugins.find("blank - different.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("Blank - Different.esm"));
|
||||
plugin = game.GetPlugin("Blank - Different.esm");
|
||||
EXPECT_EQ("Blank - Different.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -521,8 +470,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - master dependent.esm"));
|
||||
plugin = game.plugins.find("blank - master dependent.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - master dependent.esm"));
|
||||
plugin = game.GetPlugin("blank - master dependent.esm");
|
||||
EXPECT_EQ("Blank - Master Dependent.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -534,8 +483,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different master dependent.esm"));
|
||||
plugin = game.plugins.find("blank - different master dependent.esm")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different master dependent.esm"));
|
||||
plugin = game.GetPlugin("blank - different master dependent.esm");
|
||||
EXPECT_EQ("Blank - Different Master Dependent.esm", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_TRUE(plugin.isMasterFile());
|
||||
@@ -547,8 +496,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank.esp"));
|
||||
plugin = game.plugins.find("blank.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank.esp"));
|
||||
plugin = game.GetPlugin("blank.esp");
|
||||
EXPECT_EQ("Blank.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -558,8 +507,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different.esp"));
|
||||
plugin = game.plugins.find("blank - different.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different.esp"));
|
||||
plugin = game.GetPlugin("blank - different.esp");
|
||||
EXPECT_EQ("Blank - Different.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -569,8 +518,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - master dependent.esp"));
|
||||
plugin = game.plugins.find("blank - master dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - master dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - master dependent.esp");
|
||||
EXPECT_EQ("Blank - Master Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -582,8 +531,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different master dependent.esp"));
|
||||
plugin = game.plugins.find("blank - different master dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different master dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - different master dependent.esp");
|
||||
EXPECT_EQ("Blank - Different Master Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -595,8 +544,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - plugin dependent.esp"));
|
||||
plugin = game.plugins.find("blank - plugin dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - plugin dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - plugin dependent.esp");
|
||||
EXPECT_EQ("Blank - Plugin Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -608,8 +557,8 @@ TEST_F(Game, LoadPlugins_HeadersOnly) {
|
||||
EXPECT_EQ(0, plugin.Crc());
|
||||
EXPECT_EQ(0, plugin.NumOverrideFormIDs());
|
||||
|
||||
ASSERT_NE(game.plugins.end(), game.plugins.find("blank - different plugin dependent.esp"));
|
||||
plugin = game.plugins.find("blank - different plugin dependent.esp")->second;
|
||||
ASSERT_NO_THROW(game.GetPlugin("blank - different plugin dependent.esp"));
|
||||
plugin = game.GetPlugin("blank - different plugin dependent.esp");
|
||||
EXPECT_EQ("Blank - Different Plugin Dependent.esp", plugin.Name());
|
||||
EXPECT_FALSE(plugin.IsEmpty());
|
||||
EXPECT_FALSE(plugin.isMasterFile());
|
||||
@@ -631,6 +580,81 @@ TEST_F(Game, ArePluginsFullyLoaded) {
|
||||
EXPECT_TRUE(game.ArePluginsFullyLoaded());
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldThrowIfCheckingIfPluginThatIsntLoadedIsActiveAndGameHasNotBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
|
||||
EXPECT_ANY_THROW(game.IsPluginActive("Blank.esm"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEsmAsActiveIfItHasNotBeenLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
|
||||
EXPECT_TRUE(game.IsPluginActive("Blank.esm"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEspAsInctiveIfItHasNotBeenLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEsmAsInactiveIfItsHeaderHasBeenLoadedAndGameHasNotBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.LoadPlugins(true));
|
||||
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esm"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEspAsActiveIfItsHeaderHasBeenLoadedAndGameHasNotBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.LoadPlugins(true));
|
||||
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEsmAsActiveIfItsHeaderHasBeenLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
ASSERT_NO_THROW(game.LoadPlugins(true));
|
||||
|
||||
EXPECT_TRUE(game.IsPluginActive("Blank.esm"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEspAsActiveIfItsHeaderHasBeenLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
ASSERT_NO_THROW(game.LoadPlugins(true));
|
||||
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEsmAsActiveIfItHasBeenFullyLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
ASSERT_NO_THROW(game.LoadPlugins(false));
|
||||
|
||||
EXPECT_TRUE(game.IsPluginActive("Blank.esm"));
|
||||
}
|
||||
|
||||
TEST_F(Game, shouldShowBlankEspAsActiveIfItHasBeenFullyLoadedAndTheGameHasBeenInitialised) {
|
||||
loot::Game game(loot::Game::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
ASSERT_NO_THROW(game.Init(false, localPath));
|
||||
ASSERT_NO_THROW(game.LoadPlugins(false));
|
||||
|
||||
EXPECT_FALSE(game.IsPluginActive("Blank.esp"));
|
||||
}
|
||||
|
||||
TEST(ToGames, EmptySettings) {
|
||||
EXPECT_EQ(std::list<loot::Game>(), loot::ToGames(std::list<loot::GameSettings>()));
|
||||
}
|
||||
|
||||
@@ -35,35 +35,20 @@ TEST_F(GameCache, Constructors) {
|
||||
loot::GameCache cache;
|
||||
std::unordered_set<std::string> plugins({"skyrim.esm"});
|
||||
|
||||
EXPECT_NO_THROW(cache.CacheCrc("Blank.esp", 5));
|
||||
EXPECT_NO_THROW(cache.CacheCondition("True Condition", true));
|
||||
EXPECT_NO_THROW(cache.CacheActivePlugins(plugins));
|
||||
|
||||
loot::GameCache cache2(cache);
|
||||
EXPECT_EQ(5, cache2.GetCachedCrc("blank.Esp"));
|
||||
EXPECT_EQ(std::make_pair(true, true), cache2.GetCachedCondition("true Condition"));
|
||||
EXPECT_TRUE(cache2.IsPluginActive("Skyrim.esm"));
|
||||
}
|
||||
|
||||
TEST_F(GameCache, AssignmentOperator) {
|
||||
loot::GameCache cache;
|
||||
std::unordered_set<std::string> plugins({"skyrim.esm"});
|
||||
|
||||
EXPECT_NO_THROW(cache.CacheCrc("Blank.esp", 5));
|
||||
EXPECT_NO_THROW(cache.CacheCondition("True Condition", true));
|
||||
EXPECT_NO_THROW(cache.CacheActivePlugins(plugins));
|
||||
|
||||
loot::GameCache cache2 = cache;
|
||||
EXPECT_EQ(5, cache2.GetCachedCrc("blank.Esp"));
|
||||
EXPECT_EQ(std::make_pair(true, true), cache2.GetCachedCondition("true Condition"));
|
||||
EXPECT_TRUE(cache2.IsPluginActive("Skyrim.esm"));
|
||||
}
|
||||
|
||||
TEST_F(GameCache, CacheCrc) {
|
||||
loot::GameCache cache;
|
||||
EXPECT_NO_THROW(cache.CacheCrc("Blank.esp", 5));
|
||||
EXPECT_EQ(5, cache.GetCachedCrc("blank.Esp"));
|
||||
EXPECT_EQ(0, cache.GetCachedCrc("Blank.missing.esp"));
|
||||
}
|
||||
|
||||
TEST_F(GameCache, CacheCondition) {
|
||||
@@ -78,19 +63,6 @@ TEST_F(GameCache, CacheCondition) {
|
||||
EXPECT_EQ(std::make_pair(false, false), cache.GetCachedCondition("false missing Condition"));
|
||||
}
|
||||
|
||||
TEST_F(GameCache, CacheActivePlugins) {
|
||||
loot::GameCache cache;
|
||||
std::unordered_set<std::string> plugins({
|
||||
"skyrim.esm",
|
||||
"blank.esp"
|
||||
});
|
||||
EXPECT_NO_THROW(cache.CacheActivePlugins(plugins));
|
||||
|
||||
EXPECT_TRUE(cache.IsPluginActive("Skyrim.esm"));
|
||||
EXPECT_TRUE(cache.IsPluginActive("Blank.esp"));
|
||||
EXPECT_FALSE(cache.IsPluginActive("Blank.missing.esp"));
|
||||
}
|
||||
|
||||
TEST_F(GameCache, ClearCache) {}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -66,19 +66,19 @@ TEST_F(LoadOrderHandler, Init) {
|
||||
EXPECT_NO_THROW(loh.Init(game, localPath));
|
||||
}
|
||||
|
||||
TEST_F(LoadOrderHandler, GetActivePlugins) {
|
||||
TEST_F(LoadOrderHandler, IsPluginActive) {
|
||||
loot::LoadOrderHandler loh;
|
||||
loot::GameSettings game(loot::GameSettings::tes5);
|
||||
game.SetGamePath(dataPath.parent_path());
|
||||
|
||||
EXPECT_THROW(loh.IsPluginActive("Skyrim.esm"), loot::error);
|
||||
|
||||
ASSERT_NO_THROW(loh.Init(game, localPath));
|
||||
|
||||
std::unordered_set<std::string> expected({
|
||||
"skyrim.esm",
|
||||
"blank.esm",
|
||||
"blank - different master dependent.esp",
|
||||
});
|
||||
|
||||
EXPECT_EQ(expected, loh.GetActivePlugins());
|
||||
EXPECT_TRUE(loh.IsPluginActive("Skyrim.esm"));
|
||||
EXPECT_TRUE(loh.IsPluginActive("Blank.esm"));
|
||||
EXPECT_TRUE(loh.IsPluginActive("Blank - Different Master Dependent.esp"));
|
||||
EXPECT_FALSE(loh.IsPluginActive("Blank.esp"));
|
||||
}
|
||||
|
||||
TEST_F(LoadOrderHandler, GetLoadOrder) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user