Adopt a modified version of the Google C++ style

This commit doesn't make the code completely conformant, but sorts
out things like:

* Indendation (now 2 spaces)
* else statement formatting
* #define guard names
* Order of includes
* Removes usage of `using namespace std;`
* Order of class member declarations
* Naming conventions for classes, member functions, member
  variables
* Privacy of non-const class member variables
This commit is contained in:
Oliver Hamlet
2016-07-14 17:13:42 +01:00
parent e1924a69ec
commit 60cdb1c428
112 changed files with 13941 additions and 14092 deletions
+27
View File
@@ -66,3 +66,30 @@ If you're adding a new translation, LOOT's source code must be updated to recogn
* In [archive.js](scripts/archive.js), add the language folder to the list on line 83.
* In [installer.iss](scripts/installer.iss), add an entry for your language's translation file to the `[Files]` section.
* In [LOOT Metadata Syntax.html](docs/LOOT%20Metadata%20Syntax.html), add a row for your language to the Language Codes table.
## Code Style
LOOT's JavaScript uses a slightly tweaked version of the Airbnb style, and can be automatically linted by ESLint, so isn't covered here.
### C++ Code Style
The [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) is used as the base, with deviations as listed below. Note that the LOOT API is a C API, so the style guide doesn't apply to its header.
#### C++ Features
* Static variables may contain non-POD types.
* Reference arguments don't need to be `const` (ie. they can be used for output variables).
* Exceptions can be used.
* Unsigned integer types can be used.
* There's no restriction on which Boost libraries can be used.
* Specialising `std::hash` is allowed.
#### Naming
* Constant, enumerator and variable names should use `camelCase` or `underscore_separators`, but they should be consistent within the same scope.
* Function names should use `PascalCase` or `camelCase`, but they should be consistent within the same scope.
#### Formatting
* Line length doesn't matter.
* `public`, `protected` and `private` keywords should not be indented within a class declaration.
+461 -461
View File
File diff suppressed because it is too large Load Diff
+357 -373
View File
File diff suppressed because it is too large Load Diff
+56 -56
View File
@@ -22,123 +22,123 @@
<http://www.gnu.org/licenses/>.
*/
#include "loot_db.h"
#include "api/loot_db.h"
#include "../backend/error.h"
#include "backend/error.h"
loot_db::loot_db(const unsigned int clientGame, const std::string& gamePath, const boost::filesystem::path& gameLocalDataPath)
: Game(loot::GameType(clientGame)) {
this->SetGamePath(gamePath);
this->Init(false, gameLocalDataPath);
: Game(loot::GameType(clientGame)) {
this->SetGamePath(gamePath);
this->Init(false, gameLocalDataPath);
}
loot::Masterlist& loot_db::getUnevaluatedMasterlist() {
return unevaluatedMasterlist_;
return unevaluatedMasterlist_;
}
loot::MetadataList& loot_db::getUnevaluatedUserlist() {
return unevaluatedUserlist_;
return unevaluatedUserlist_;
}
const char * loot_db::getRevisionIdString() const {
return revisionId.c_str();
return revisionId.c_str();
}
const char * loot_db::getRevisionDateString() const {
return revisionDate.c_str();
return revisionDate.c_str();
}
const std::vector<const char *>& loot_db::getPluginNames() const {
return cPluginNames;
return cPluginNames;
}
const std::vector<const char *>& loot_db::getBashTagMap() const {
return cBashTagMap;
return cBashTagMap;
}
unsigned int loot_db::getBashTagUid(const std::string& name) const {
auto it = bashTagMap.find(name);
if (it != end(bashTagMap))
return it->second;
auto it = bashTagMap.find(name);
if (it != end(bashTagMap))
return it->second;
throw loot::Error(loot::Error::Code::no_tag_map, "The Bash Tag \"" + name + "\" does not exist in the Bash Tag map.");
throw loot::Error(loot::Error::Code::no_tag_map, "The Bash Tag \"" + name + "\" does not exist in the Bash Tag map.");
}
const std::vector<unsigned int>& loot_db::getAddedTagIds() const {
return addedTagIds;
return addedTagIds;
}
const std::vector<unsigned int>& loot_db::getRemovedTagIds() const {
return removedTagIds;
return removedTagIds;
}
const std::vector<loot_message>& loot_db::getPluginMessages() const {
return cPluginMessages;
return cPluginMessages;
}
void loot_db::setRevisionIdString(const std::string& str) {
revisionId = str;
revisionId = str;
}
void loot_db::setRevisionDateString(const std::string& str) {
revisionDate = str;
revisionDate = str;
}
void loot_db::setAddedTags(const std::set<std::string>& names) {
addedTagIds.clear();
for (const auto& name : names)
addedTagIds.push_back(getBashTagUid(name));
addedTagIds.clear();
for (const auto& name : names)
addedTagIds.push_back(getBashTagUid(name));
}
void loot_db::setRemovedTags(const std::set<std::string>& names) {
removedTagIds.clear();
for (const auto& name : names)
removedTagIds.push_back(getBashTagUid(name));
removedTagIds.clear();
for (const auto& name : names)
removedTagIds.push_back(getBashTagUid(name));
}
void loot_db::setPluginMessages(const std::list<loot::Message>& pluginMessages) {
cPluginMessages.resize(pluginMessages.size());
pluginMessageStrings.resize(pluginMessages.size());
cPluginMessages.resize(pluginMessages.size());
pluginMessageStrings.resize(pluginMessages.size());
size_t i = 0;
for (const auto& message : pluginMessages) {
pluginMessageStrings[i] = message.ChooseContent(loot::Language::Code::english).GetText();
size_t i = 0;
for (const auto& message : pluginMessages) {
pluginMessageStrings[i] = message.ChooseContent(loot::Language::Code::english).GetText();
cPluginMessages[i].type = static_cast<unsigned int>(message.GetType());
cPluginMessages[i].message = pluginMessageStrings[i].c_str();
cPluginMessages[i].type = static_cast<unsigned int>(message.GetType());
cPluginMessages[i].message = pluginMessageStrings[i].c_str();
++i;
}
++i;
}
}
void loot_db::addBashTagsToMap(std::set<std::string> names) {
for (const auto& name : names) {
// Try adding the Bash Tag to the map assuming it's not already in
// there, then use the UID in the returned value, as that will be
// equal to the value in the map, even if the Bash Tag was already
// present.
unsigned int uid = bashTagMap.size();
// If the tag already exists in the map, do
auto it = bashTagMap.emplace(name, uid).first;
if (it->second == cBashTagMap.size())
cBashTagMap.push_back(it->first.c_str());
else
cBashTagMap.at(it->second) = it->first.c_str();
}
for (const auto& name : names) {
// Try adding the Bash Tag to the map assuming it's not already in
// there, then use the UID in the returned value, as that will be
// equal to the value in the map, even if the Bash Tag was already
// present.
unsigned int uid = bashTagMap.size();
// If the tag already exists in the map, do
auto it = bashTagMap.emplace(name, uid).first;
if (it->second == cBashTagMap.size())
cBashTagMap.push_back(it->first.c_str());
else
cBashTagMap.at(it->second) = it->first.c_str();
}
}
void loot_db::clearBashTagMap() {
bashTagMap.clear();
cBashTagMap.clear();
bashTagMap.clear();
cBashTagMap.clear();
}
void loot_db::clearArrays() {
pluginNames.clear();
cPluginNames.clear();
pluginNames.clear();
cPluginNames.clear();
addedTagIds.clear();
removedTagIds.clear();
addedTagIds.clear();
removedTagIds.clear();
cPluginMessages.clear();
pluginMessageStrings.clear();
cPluginMessages.clear();
pluginMessageStrings.clear();
}
+59 -62
View File
@@ -22,92 +22,89 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_API_LOOT_DB_INT_H
#define LOOT_API_LOOT_DB_INT_H
#include "../backend/game/game.h"
#include "../include/loot/api.h"
#ifndef LOOT_API_LOOT_DB
#define LOOT_API_LOOT_DB
#include <vector>
#include <unordered_map>
#include "backend/game/game.h"
#include "loot/api.h"
struct loot_db : public loot::Game {
loot_db(const unsigned int clientGame,
const std::string& gamePath,
const boost::filesystem::path& gameLocalDataPath);
loot_db(const unsigned int clientGame,
const std::string& gamePath,
const boost::filesystem::path& gameLocalDataPath);
loot::Masterlist& getUnevaluatedMasterlist();
loot::MetadataList& getUnevaluatedUserlist();
loot::Masterlist& getUnevaluatedMasterlist();
loot::MetadataList& getUnevaluatedUserlist();
loot::MetadataList rawUserMetadata;
loot::Masterlist rawMetadata;
const char * getRevisionIdString() const;
const char * getRevisionDateString() const;
const char * getRevisionIdString() const;
const char * getRevisionDateString() const;
const std::vector<const char *>& getPluginNames() const;
const std::vector<const char *>& getPluginNames() const;
const std::vector<const char *>& getBashTagMap() const;
unsigned int getBashTagUid(const std::string& name) const;
const std::vector<const char *>& getBashTagMap() const;
unsigned int getBashTagUid(const std::string& name) const;
const std::vector<unsigned int>& getAddedTagIds() const;
const std::vector<unsigned int>& getRemovedTagIds() const;
const std::vector<unsigned int>& getAddedTagIds() const;
const std::vector<unsigned int>& getRemovedTagIds() const;
const std::vector<loot_message>& getPluginMessages() const;
const std::vector<loot_message>& getPluginMessages() const;
void setRevisionIdString(const std::string& str);
void setRevisionDateString(const std::string& str);
void setRevisionIdString(const std::string& str);
void setRevisionDateString(const std::string& str);
template<class T>
void setPluginNames(const T& plugins) {
// First take copies of the C++ strings to store.
pluginNames.resize(plugins.size());
std::transform(begin(plugins),
end(plugins),
begin(pluginNames),
[](const loot::PluginMetadata& plugin) {
return plugin.Name();
});
template<class T>
void setPluginNames(const T& plugins) {
// First take copies of the C++ strings to store.
pluginNames.resize(plugins.size());
std::transform(begin(plugins),
end(plugins),
begin(pluginNames),
[](const loot::PluginMetadata& plugin) {
return plugin.Name();
});
// Now store their C strings.
cPluginNames.resize(pluginNames.size());
std::transform(begin(pluginNames),
end(pluginNames),
begin(cPluginNames),
[](const std::string& pluginName) {
return pluginName.c_str();
});
}
// Now store their C strings.
cPluginNames.resize(pluginNames.size());
std::transform(begin(pluginNames),
end(pluginNames),
begin(cPluginNames),
[](const std::string& pluginName) {
return pluginName.c_str();
});
}
void setAddedTags(const std::set<std::string>& names);
void setRemovedTags(const std::set<std::string>& names);
void setAddedTags(const std::set<std::string>& names);
void setRemovedTags(const std::set<std::string>& names);
void setPluginMessages(const std::list<loot::Message>& pluginMessages);
void setPluginMessages(const std::list<loot::Message>& pluginMessages);
void addBashTagsToMap(std::set<std::string> names);
void addBashTagsToMap(std::set<std::string> names);
void clearBashTagMap();
void clearArrays();
void clearBashTagMap();
void clearArrays();
private:
loot::Masterlist unevaluatedMasterlist_;
loot::MetadataList unevaluatedUserlist_;
loot::Masterlist unevaluatedMasterlist_;
loot::MetadataList unevaluatedUserlist_;
std::string revisionId;
std::string revisionDate;
std::string revisionId;
std::string revisionDate;
std::vector<std::string> pluginNames;
std::vector<const char *> cPluginNames;
std::vector<std::string> pluginNames;
std::vector<const char *> cPluginNames;
// For the Bash Tag map, a string is mapped to a UID that is also the
// index of the vector where the C string can be found.
std::unordered_map<std::string, unsigned int> bashTagMap;
std::vector<const char *> cBashTagMap;
// For the Bash Tag map, a string is mapped to a UID that is also the
// index of the vector where the C string can be found.
std::unordered_map<std::string, unsigned int> bashTagMap;
std::vector<const char *> cBashTagMap;
std::vector<unsigned int> addedTagIds;
std::vector<unsigned int> removedTagIds;
std::vector<unsigned int> addedTagIds;
std::vector<unsigned int> removedTagIds;
std::vector<loot_message> cPluginMessages;
std::vector<std::string> pluginMessageStrings;
std::vector<loot_message> cPluginMessages;
std::vector<std::string> pluginMessageStrings;
};
#endif
+49 -48
View File
@@ -23,12 +23,13 @@ Fallout: New Vegas.
*/
#include "loot_paths.h"
#include "../helpers/helpers.h"
#include "../error.h"
#include <locale>
#include <boost/locale.hpp>
#include <locale>
#include "backend/error.h"
#include "backend/helpers/helpers.h"
#ifdef _WIN32
# ifndef UNICODE
@@ -42,69 +43,69 @@ Fallout: New Vegas.
#endif
namespace loot {
boost::filesystem::path LootPaths::getReadmePath() {
return lootAppPath / "docs" / "LOOT Readme.html";
}
boost::filesystem::path LootPaths::getReadmePath() {
return lootAppPath_ / "docs" / "LOOT Readme.html";
}
boost::filesystem::path LootPaths::getUIIndexPath() {
return lootAppPath / "resources" / "ui" / "index.html";
}
boost::filesystem::path LootPaths::getUIIndexPath() {
return lootAppPath_ / "resources" / "ui" / "index.html";
}
boost::filesystem::path LootPaths::getL10nPath() {
return lootAppPath / "resources" / "l10n";
}
boost::filesystem::path LootPaths::getL10nPath() {
return lootAppPath_ / "resources" / "l10n";
}
boost::filesystem::path LootPaths::getLootDataPath() {
return lootDataPath;
}
boost::filesystem::path LootPaths::getLootDataPath() {
return lootDataPath_;
}
boost::filesystem::path LootPaths::getSettingsPath() {
return lootDataPath / "settings.yaml";
}
boost::filesystem::path LootPaths::getSettingsPath() {
return lootDataPath_ / "settings.yaml";
}
boost::filesystem::path LootPaths::getLogPath() {
return lootDataPath / "LOOTDebugLog.txt";
}
boost::filesystem::path LootPaths::getLogPath() {
return lootDataPath_ / "LOOTDebugLog.txt";
}
void LootPaths::initialise() {
// Set the locale to get UTF-8 conversions working correctly.
std::locale::global(boost::locale::generator().generate(""));
boost::filesystem::path::imbue(std::locale());
void LootPaths::initialise() {
// Set the locale to get UTF-8 conversions working correctly.
std::locale::global(boost::locale::generator().generate(""));
boost::filesystem::path::imbue(std::locale());
lootAppPath = boost::filesystem::current_path();
lootDataPath = getLocalAppDataPath() / "LOOT";
}
lootAppPath_ = boost::filesystem::current_path();
lootDataPath_ = getLocalAppDataPath() / "LOOT";
}
boost::filesystem::path LootPaths::getLocalAppDataPath() {
boost::filesystem::path LootPaths::getLocalAppDataPath() {
#ifdef _WIN32
HWND owner = 0;
PWSTR path;
HWND owner = 0;
PWSTR path;
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path) != S_OK)
throw Error(Error::Code::windows_error, boost::locale::translate("Failed to get %LOCALAPPDATA% path."));
if (SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path) != S_OK)
throw Error(Error::Code::windows_error, boost::locale::translate("Failed to get %LOCALAPPDATA% path."));
boost::filesystem::path localAppDataPath(FromWinWide(path));
CoTaskMemFree(path);
boost::filesystem::path localAppDataPath(FromWinWide(path));
CoTaskMemFree(path);
return localAppDataPath;
return localAppDataPath;
#else
// Use XDG_CONFIG_HOME environmental variable if it's available.
const char * xdgConfigHome = getenv("XDG_CONFIG_HOME");
const char * xdgConfigHome = getenv("XDG_CONFIG_HOME");
if (xdgConfigHome != nullptr)
return boost::filesystem::path(xdgConfigHome);
if (xdgConfigHome != nullptr)
return boost::filesystem::path(xdgConfigHome);
// Otherwise, use the HOME env. var. if it's available.
xdgConfigHome = getenv("HOME");
// Otherwise, use the HOME env. var. if it's available.
xdgConfigHome = getenv("HOME");
if (xdgConfigHome != nullptr)
return boost::filesystem::path(xdgConfigHome) / ".config";
if (xdgConfigHome != nullptr)
return boost::filesystem::path(xdgConfigHome) / ".config";
// If somehow both are missing, use the current path.
return boost::filesystem::current_path();
// If somehow both are missing, use the current path.
return boost::filesystem::current_path();
#endif
}
}
boost::filesystem::path LootPaths::lootAppPath;
boost::filesystem::path LootPaths::lootDataPath;
boost::filesystem::path LootPaths::lootAppPath_;
boost::filesystem::path LootPaths::lootDataPath_;
}
+19 -19
View File
@@ -22,31 +22,31 @@ along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_BACKEND_LOOT_PATHS
#define LOOT_BACKEND_LOOT_PATHS
#ifndef LOOT_BACKEND_APP_LOOT_PATHS
#define LOOT_BACKEND_APP_LOOT_PATHS
#include <boost/filesystem.hpp>
namespace loot {
class LootPaths {
public:
static boost::filesystem::path getReadmePath();
static boost::filesystem::path getUIIndexPath();
static boost::filesystem::path getL10nPath();
static boost::filesystem::path getLootDataPath();
static boost::filesystem::path getSettingsPath();
static boost::filesystem::path getLogPath();
class LootPaths {
public:
static boost::filesystem::path getReadmePath();
static boost::filesystem::path getUIIndexPath();
static boost::filesystem::path getL10nPath();
static boost::filesystem::path getLootDataPath();
static boost::filesystem::path getSettingsPath();
static boost::filesystem::path getLogPath();
// Sets the app path to the current path, and the data path to the user
// local app data path / "LOOT".
static void initialise();
private:
static boost::filesystem::path lootAppPath;
static boost::filesystem::path lootDataPath;
// Sets the app path to the current path, and the data path to the user
// local app data path / "LOOT".
static void initialise();
private:
//Get the local application data path.
static boost::filesystem::path getLocalAppDataPath();
//Get the local application data path.
static boost::filesystem::path getLocalAppDataPath();
};
static boost::filesystem::path lootAppPath_;
static boost::filesystem::path lootDataPath_;
};
}
#endif
+203 -201
View File
@@ -22,273 +22,275 @@
<http://www.gnu.org/licenses/>.
*/
#include "loot_settings.h"
#include "backend/app/loot_version.h"
#include "backend/app/loot_settings.h"
#include <thread>
#include <boost/filesystem/fstream.hpp>
using namespace std;
#include "backend/app/loot_version.h"
using std::lock_guard;
using std::recursive_mutex;
using std::string;
namespace loot {
LootSettings::WindowPosition::WindowPosition() : top(0), bottom(0), left(0), right(0) {}
LootSettings::WindowPosition::WindowPosition() : top(0), bottom(0), left(0), right(0) {}
LootSettings::LootSettings() :
gameSettings({
GameSettings(GameType::tes4),
GameSettings(GameType::tes5),
GameSettings(GameType::fo3),
GameSettings(GameType::fonv),
GameSettings(GameType::fo4),
GameSettings(GameType::tes4, "Nehrim")
.SetName("Nehrim - At Fate's Edge")
.SetMaster("Nehrim.esm")
.SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"),
}),
enableDebugLogging(false),
updateMasterlist(true),
game("auto"),
language(Language(Language::Code::english)),
lastGame("auto") {}
LootSettings::LootSettings() :
gameSettings_({
GameSettings(GameType::tes4),
GameSettings(GameType::tes5),
GameSettings(GameType::fo3),
GameSettings(GameType::fonv),
GameSettings(GameType::fo4),
GameSettings(GameType::tes4, "Nehrim")
.SetName("Nehrim - At Fate's Edge")
.SetMaster("Nehrim.esm")
.SetRegistryKey("Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"),
}),
enableDebugLogging_(false),
updateMasterlist_(true),
game_("auto"),
language_(Language(Language::Code::english)),
lastGame_("auto") {}
void LootSettings::load(YAML::Node& settings) {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::load(YAML::Node& settings) {
lock_guard<recursive_mutex> guard(mutex_);
upgradeYaml(settings);
upgradeYaml(settings);
if (settings["enableDebugLogging"])
enableDebugLogging = settings["enableDebugLogging"].as<bool>();
if (settings["updateMasterlist"])
updateMasterlist = settings["updateMasterlist"].as<bool>();
if (settings["game"])
game = settings["game"].as<string>();
if (settings["language"])
language = Language(settings["language"].as<string>());
if (settings["lastGame"])
lastGame = settings["lastGame"].as<string>();
if (settings["lastVersion"])
lastVersion = settings["lastVersion"].as<string>();
if (settings["enableDebugLogging"])
enableDebugLogging_ = settings["enableDebugLogging"].as<bool>();
if (settings["updateMasterlist"])
updateMasterlist_ = settings["updateMasterlist"].as<bool>();
if (settings["game"])
game_ = settings["game"].as<string>();
if (settings["language"])
language_ = Language(settings["language"].as<string>());
if (settings["lastGame"])
lastGame_ = settings["lastGame"].as<string>();
if (settings["lastVersion"])
lastVersion_ = settings["lastVersion"].as<string>();
if (settings["window"]
&& settings["window"]["top"] && settings["window"]["bottom"]
&& settings["window"]["left"] && settings["window"]["right"]) {
windowPosition.top = settings["window"]["top"].as<long>();
windowPosition.bottom = settings["window"]["bottom"].as<long>();
windowPosition.left = settings["window"]["left"].as<long>();
windowPosition.right = settings["window"]["right"].as<long>();
}
if (settings["window"]
&& settings["window"]["top"] && settings["window"]["bottom"]
&& settings["window"]["left"] && settings["window"]["right"]) {
windowPosition_.top = settings["window"]["top"].as<long>();
windowPosition_.bottom = settings["window"]["bottom"].as<long>();
windowPosition_.left = settings["window"]["left"].as<long>();
windowPosition_.right = settings["window"]["right"].as<long>();
}
if (settings["games"]) {
gameSettings = settings["games"].as<vector<GameSettings>>();
if (settings["games"]) {
gameSettings_ = settings["games"].as<std::vector<GameSettings>>();
// If a base game isn't in the settings, add it.
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameType::tes4)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameType::tes4));
// If a base game isn't in the settings, add it.
if (find(begin(gameSettings_), end(gameSettings_), GameSettings(GameType::tes4)) == end(gameSettings_))
gameSettings_.push_back(GameSettings(GameType::tes4));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameType::tes5)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameType::tes5));
if (find(begin(gameSettings_), end(gameSettings_), GameSettings(GameType::tes5)) == end(gameSettings_))
gameSettings_.push_back(GameSettings(GameType::tes5));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameType::fo3)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameType::fo3));
if (find(begin(gameSettings_), end(gameSettings_), GameSettings(GameType::fo3)) == end(gameSettings_))
gameSettings_.push_back(GameSettings(GameType::fo3));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameType::fonv)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameType::fonv));
if (find(begin(gameSettings_), end(gameSettings_), GameSettings(GameType::fonv)) == end(gameSettings_))
gameSettings_.push_back(GameSettings(GameType::fonv));
if (find(begin(gameSettings), end(gameSettings), GameSettings(GameType::fo4)) == end(gameSettings))
gameSettings.push_back(GameSettings(GameType::fo4));
}
if (find(begin(gameSettings_), end(gameSettings_), GameSettings(GameType::fo4)) == end(gameSettings_))
gameSettings_.push_back(GameSettings(GameType::fo4));
}
if (settings["filters"])
filters = settings["filters"].as<map<string, bool>>();
}
if (settings["filters"])
filters_ = settings["filters"].as<std::map<string, bool>>();
}
void LootSettings::load(const boost::filesystem::path& file) {
boost::filesystem::ifstream in(file);
YAML::Node content = YAML::Load(in);
load(content);
}
void LootSettings::save(const boost::filesystem::path& file) {
lock_guard<recursive_mutex> guard(mutex_);
void LootSettings::load(const boost::filesystem::path& file) {
boost::filesystem::ifstream in(file);
YAML::Node content = YAML::Load(in);
load(content);
}
YAML::Emitter yout;
yout.SetIndent(2);
yout << toYaml();
void LootSettings::save(const boost::filesystem::path& file) {
std::lock_guard<std::recursive_mutex> guard(mutex);
boost::filesystem::ofstream out(file);
out << yout.c_str();
}
YAML::Emitter yout;
yout.SetIndent(2);
yout << toYaml();
bool LootSettings::isDebugLoggingEnabled() const {
lock_guard<recursive_mutex> guard(mutex_);
boost::filesystem::ofstream out(file);
out << yout.c_str();
}
return enableDebugLogging_;
}
bool LootSettings::isDebugLoggingEnabled() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
bool LootSettings::isWindowPositionStored() const {
lock_guard<recursive_mutex> guard(mutex_);
return enableDebugLogging;
}
return windowPosition_.top != 0 || windowPosition_.bottom != 0 || windowPosition_.left != 0 || windowPosition_.right != 0;
}
bool LootSettings::isWindowPositionStored() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
std::string LootSettings::getGame() const {
lock_guard<recursive_mutex> guard(mutex_);
return windowPosition.top != 0 || windowPosition.bottom != 0 || windowPosition.left != 0 || windowPosition.right != 0;
}
return game_;
}
std::string LootSettings::getGame() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
std::string LootSettings::getLastGame() const {
lock_guard<recursive_mutex> guard(mutex_);
return game;
}
return lastGame_;
}
std::string LootSettings::getLastGame() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
std::string LootSettings::getLastVersion() const {
lock_guard<recursive_mutex> guard(mutex_);
return lastGame;
}
return lastVersion_;
}
std::string LootSettings::getLastVersion() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
const Language& LootSettings::getLanguage() const {
lock_guard<recursive_mutex> guard(mutex_);
return lastVersion;
}
return language_;
}
const Language& LootSettings::getLanguage() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
const LootSettings::WindowPosition& LootSettings::getWindowPosition() const {
lock_guard<recursive_mutex> guard(mutex_);
return language;
}
return windowPosition_;
}
const LootSettings::WindowPosition& LootSettings::getWindowPosition() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
std::vector<GameSettings> LootSettings::getGameSettings() const {
lock_guard<recursive_mutex> guard(mutex_);
return windowPosition;
}
return gameSettings_;
}
std::vector<GameSettings> LootSettings::getGameSettings() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::storeLastGame(const std::string& lastGame) {
lock_guard<recursive_mutex> guard(mutex_);
return gameSettings;
}
this->lastGame_ = lastGame;
}
void LootSettings::storeLastGame(const std::string& lastGame) {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::storeWindowPosition(const WindowPosition& position) {
lock_guard<recursive_mutex> guard(mutex_);
this->lastGame = lastGame;
}
windowPosition_ = position;
}
void LootSettings::storeWindowPosition(const WindowPosition& position) {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::storeGameSettings(const std::vector<GameSettings>& gameSettings) {
lock_guard<recursive_mutex> guard(mutex_);
windowPosition = position;
}
this->gameSettings_ = gameSettings;
}
void LootSettings::storeGameSettings(const std::vector<GameSettings>& gameSettings) {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::storeFilterState(const std::string& filterId, bool enabled) {
lock_guard<recursive_mutex> guard(mutex_);
this->gameSettings = gameSettings;
}
filters_[filterId] = enabled;
}
void LootSettings::storeFilterState(const std::string& filterId, bool enabled) {
std::lock_guard<std::recursive_mutex> guard(mutex);
void LootSettings::updateLastVersion() {
lock_guard<recursive_mutex> guard(mutex_);
filters[filterId] = enabled;
}
lastVersion_ = LootVersion::string();
}
void LootSettings::updateLastVersion() {
std::lock_guard<std::recursive_mutex> guard(mutex);
YAML::Node LootSettings::toYaml() const {
lock_guard<recursive_mutex> guard(mutex_);
lastVersion = LootVersion::string();
}
YAML::Node node;
YAML::Node LootSettings::toYaml() const {
std::lock_guard<std::recursive_mutex> guard(mutex);
node["enableDebugLogging"] = enableDebugLogging_;
node["updateMasterlist"] = updateMasterlist_;
node["game"] = game_;
node["language"] = language_.GetLocale();
node["lastGame"] = lastGame_;
node["lastVersion"] = lastVersion_;
YAML::Node node;
if (isWindowPositionStored()) {
node["window"]["top"] = windowPosition_.top;
node["window"]["bottom"] = windowPosition_.bottom;
node["window"]["left"] = windowPosition_.left;
node["window"]["right"] = windowPosition_.right;
}
node["enableDebugLogging"] = enableDebugLogging;
node["updateMasterlist"] = updateMasterlist;
node["game"] = game;
node["language"] = language.GetLocale();
node["lastGame"] = lastGame;
node["lastVersion"] = lastVersion;
node["games"] = gameSettings_;
if (isWindowPositionStored()) {
node["window"]["top"] = windowPosition.top;
node["window"]["bottom"] = windowPosition.bottom;
node["window"]["left"] = windowPosition.left;
node["window"]["right"] = windowPosition.right;
}
if (!filters_.empty())
node["filters"] = filters_;
node["games"] = gameSettings;
return node;
}
if (!filters.empty())
node["filters"] = filters;
void LootSettings::upgradeYaml(YAML::Node& yaml) {
// Upgrade YAML settings' keys and values from those used in earlier
// versions of LOOT.
return node;
}
if (yaml["Debug Verbosity"] && !yaml["enableDebugLogging"])
yaml["enableDebugLogging"] = yaml["Debug Verbosity"].as<unsigned int>() > 0;
void LootSettings::upgradeYaml(YAML::Node& yaml) {
// Upgrade YAML settings' keys and values from those used in earlier
// versions of LOOT.
if (yaml["Update Masterlist"] && !yaml["updateMasterlist"])
yaml["updateMasterlist"] = yaml["Update Masterlist"];
if (yaml["Debug Verbosity"] && !yaml["enableDebugLogging"])
yaml["enableDebugLogging"] = yaml["Debug Verbosity"].as<unsigned int>() > 0;
if (yaml["Game"] && !yaml["game"])
yaml["game"] = yaml["Game"];
if (yaml["Update Masterlist"] && !yaml["updateMasterlist"])
yaml["updateMasterlist"] = yaml["Update Masterlist"];
if (yaml["Language"] && !yaml["language"])
yaml["language"] = yaml["Language"];
if (yaml["Game"] && !yaml["game"])
yaml["game"] = yaml["Game"];
if (yaml["Last Game"] && !yaml["lastGame"])
yaml["lastGame"] = yaml["Last Game"];
if (yaml["Language"] && !yaml["language"])
yaml["language"] = yaml["Language"];
if (yaml["Games"] && !yaml["games"]) {
yaml["games"] = yaml["Games"];
if (yaml["Last Game"] && !yaml["lastGame"])
yaml["lastGame"] = yaml["Last Game"];
for (auto node : yaml["games"]) {
if (node["url"]) {
node["repo"] = node["url"];
node["branch"] = "v0.8";
}
}
}
if (yaml["Games"] && !yaml["games"]) {
yaml["games"] = yaml["Games"];
if (yaml["games"]) {
const std::set<string> oldDefaultBranches({
"master",
"v0.7",
});
for (auto node : yaml["games"]) {
if (node["url"]) {
node["repo"] = node["url"];
node["branch"] = "v0.8";
}
}
}
// Handle exception if YAML is invalid, eg. if an unrecognised
// game type is used (which can happen if downgrading from a
// later version of LOOT that supports more game types).
// However, can't remove elements from a sequence Node, so have to
// copy the valid elements into a new node then overwrite the
// original.
YAML::Node validGames;
for (auto node : yaml["games"]) {
try {
GameSettings settings(node.as<GameSettings>());
if (yaml["games"]) {
const set<string> oldDefaultBranches({
"master",
"v0.7",
});
// Handle exception if YAML is invalid, eg. if an unrecognised
// game type is used (which can happen if downgrading from a
// later version of LOOT that supports more game types).
// However, can't remove elements from a sequence Node, so have to
// copy the valid elements into a new node then overwrite the
// original.
YAML::Node validGames;
for (auto node : yaml["games"]) {
try {
GameSettings settings(node.as<GameSettings>());
if (!yaml["Games"]) {
// Update existing default branch, if the default
// repositories are used.
if (settings.RepoURL() == GameSettings(settings.Type()).RepoURL()
&& oldDefaultBranches.count(settings.RepoBranch()) == 1) {
settings.SetRepoBranch("v0.8");
}
}
validGames.push_back(settings);
}
catch (...) {}
}
yaml["games"] = validGames;
if (!yaml["Games"]) {
// Update existing default branch, if the default
// repositories are used.
if (settings.RepoURL() == GameSettings(settings.Type()).RepoURL()
&& oldDefaultBranches.count(settings.RepoBranch()) == 1) {
settings.SetRepoBranch("v0.8");
}
}
if (yaml["filters"])
yaml["filters"].remove("contentFilter");
validGames.push_back(settings);
} catch (...) {}
}
yaml["games"] = validGames;
}
if (yaml["filters"])
yaml["filters"].remove("contentFilter");
}
}
+45 -45
View File
@@ -22,11 +22,8 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_BACKEND_LOOT_SETTINGS
#define LOOT_BACKEND_LOOT_SETTINGS
#include "backend/game/game_settings.h"
#include "backend/helpers/language.h"
#ifndef LOOT_BACKEND_APP_LOOT_SETTINGS
#define LOOT_BACKEND_APP_LOOT_SETTINGS
#include <map>
#include <mutex>
@@ -36,55 +33,58 @@
#include <boost/filesystem.hpp>
#include <yaml-cpp/yaml.h>
#include "backend/game/game_settings.h"
#include "backend/helpers/language.h"
namespace loot {
class LootSettings {
public:
struct WindowPosition {
WindowPosition();
class LootSettings {
public:
struct WindowPosition {
WindowPosition();
long top;
long bottom;
long left;
long right;
};
long top;
long bottom;
long left;
long right;
};
LootSettings();
LootSettings();
void load(YAML::Node& settings);
void load(const boost::filesystem::path& file);
void save(const boost::filesystem::path& file);
void load(YAML::Node& settings);
void load(const boost::filesystem::path& file);
void save(const boost::filesystem::path& file);
bool isDebugLoggingEnabled() const;
bool isWindowPositionStored() const;
std::string getGame() const;
std::string getLastGame() const;
std::string getLastVersion() const;
const Language& getLanguage() const;
const WindowPosition& getWindowPosition() const;
std::vector<GameSettings> getGameSettings() const;
bool isDebugLoggingEnabled() const;
bool isWindowPositionStored() const;
std::string getGame() const;
std::string getLastGame() const;
std::string getLastVersion() const;
const Language& getLanguage() const;
const WindowPosition& getWindowPosition() const;
std::vector<GameSettings> getGameSettings() const;
void storeLastGame(const std::string& lastGame);
void storeWindowPosition(const WindowPosition& position);
void storeGameSettings(const std::vector<GameSettings>& gameSettings);
void storeFilterState(const std::string& filterId, bool enabled);
void updateLastVersion();
void storeLastGame(const std::string& lastGame);
void storeWindowPosition(const WindowPosition& position);
void storeGameSettings(const std::vector<GameSettings>& gameSettings);
void storeFilterState(const std::string& filterId, bool enabled);
void updateLastVersion();
YAML::Node toYaml() const;
private:
bool enableDebugLogging;
bool updateMasterlist;
std::string game;
std::string lastGame;
std::string lastVersion;
Language language;
WindowPosition windowPosition;
std::vector<GameSettings> gameSettings;
std::map<std::string, bool> filters;
YAML::Node toYaml() const;
private:
static void upgradeYaml(YAML::Node& yaml);
mutable std::recursive_mutex mutex;
bool enableDebugLogging_;
bool updateMasterlist_;
std::string game_;
std::string lastGame_;
std::string lastVersion_;
Language language_;
WindowPosition windowPosition_;
std::vector<GameSettings> gameSettings_;
std::map<std::string, bool> filters_;
static void upgradeYaml(YAML::Node& yaml);
};
mutable std::recursive_mutex mutex_;
};
}
#endif
+218 -219
View File
@@ -22,263 +22,262 @@
<http://www.gnu.org/licenses/>.
*/
#include "loot_state.h"
#include "loot_paths.h"
#include "backend/error.h"
#include "backend/app/loot_version.h"
#include "backend/helpers/helpers.h"
#include "backend/helpers/language.h"
#include "backend/app/loot_state.h"
#include <boost/filesystem/fstream.hpp>
#include <boost/format.hpp>
#include <boost/locale.hpp>
#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/utility/setup/file.hpp>
#include "backend/error.h"
#include "backend/app/loot_paths.h"
#include "backend/app/loot_version.h"
#include "backend/helpers/helpers.h"
#include "backend/helpers/language.h"
#ifdef _WIN32
#include <windows.h>
#endif
using namespace std;
using boost::locale::translate;
using boost::format;
using boost::locale::translate;
using std::exception;
using std::locale;
using std::lock_guard;
using std::mutex;
using std::string;
using std::vector;
namespace fs = boost::filesystem;
namespace loot {
LootState::LootState() : unappliedChangeCounter(0), _currentGame(_games.end()) {}
LootState::LootState() : unappliedChangeCounter_(0), currentGame_(games_.end()) {}
void LootState::load(YAML::Node& settings) {
std::lock_guard<std::mutex> guard(mutex);
void LootState::load(YAML::Node& settings) {
lock_guard<mutex> guard(mutex_);
LootSettings::load(settings);
LootSettings::load(settings);
// Enable/disable debug logging in case it has changed.
boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled());
// Enable/disable debug logging in case it has changed.
boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled());
// Update existing games, add new games.
unordered_set<string> newGameFolders;
BOOST_LOG_TRIVIAL(trace) << "Updating existing games and adding new games.";
for (const auto &game : getGameSettings()) {
auto pos = find(_games.begin(), _games.end(), game);
// Update existing games, add new games.
std::unordered_set<string> newGameFolders;
BOOST_LOG_TRIVIAL(trace) << "Updating existing games and adding new games.";
for (const auto &game : getGameSettings()) {
auto pos = find(games_.begin(), games_.end(), game);
if (pos != _games.end()) {
pos->SetName(game.Name())
.SetMaster(game.Master())
.SetRepoURL(game.RepoURL())
.SetRepoBranch(game.RepoBranch())
.SetGamePath(game.GamePath())
.SetRegistryKey(game.RegistryKey());
}
else {
BOOST_LOG_TRIVIAL(trace) << "Adding new game entry for: " << game.FolderName();
_games.push_back(game);
}
newGameFolders.insert(game.FolderName());
}
// Remove deleted games. As the current game is stored using its index,
// removing an earlier game may invalidate it.
BOOST_LOG_TRIVIAL(trace) << "Removing deleted games.";
for (auto it = _games.begin(); it != _games.end();) {
if (newGameFolders.find(it->FolderName()) == newGameFolders.end()) {
BOOST_LOG_TRIVIAL(trace) << "Removing game: " << it->FolderName();
it = _games.erase(it);
}
else
++it;
}
// Re-initialise the current game in case the game path setting was changed.
_currentGame->Init(true);
// Update game path in settings object.
storeGameSettings(ToGameSettings(_games));
if (pos != games_.end()) {
pos->SetName(game.Name())
.SetMaster(game.Master())
.SetRepoURL(game.RepoURL())
.SetRepoBranch(game.RepoBranch())
.SetGamePath(game.GamePath())
.SetRegistryKey(game.RegistryKey());
} else {
BOOST_LOG_TRIVIAL(trace) << "Adding new game entry for: " << game.FolderName();
games_.push_back(game);
}
void LootState::Init(const std::string& cmdLineGame) {
// Do some preliminary locale / UTF-8 support setup here, in case the settings file reading requires it.
//Boost.Locale initialisation: Specify location of language dictionaries.
boost::locale::generator gen;
gen.add_messages_path(LootPaths::getL10nPath().string());
gen.add_messages_domain("loot");
newGameFolders.insert(game.FolderName());
}
//Boost.Locale initialisation: Generate and imbue locales.
locale::global(gen(Language(Language::Code::english).GetLocale() + ".UTF-8"));
boost::filesystem::path::imbue(locale());
// Remove deleted games. As the current game is stored using its index,
// removing an earlier game may invalidate it.
BOOST_LOG_TRIVIAL(trace) << "Removing deleted games.";
for (auto it = games_.begin(); it != games_.end();) {
if (newGameFolders.find(it->FolderName()) == newGameFolders.end()) {
BOOST_LOG_TRIVIAL(trace) << "Removing game: " << it->FolderName();
it = games_.erase(it);
} else
++it;
}
// Check if the LOOT local app data folder exists, and create it if not.
if (!fs::exists(LootPaths::getLootDataPath())) {
BOOST_LOG_TRIVIAL(info) << "Local app data LOOT folder doesn't exist, creating it.";
try {
fs::create_directory(LootPaths::getLootDataPath());
}
catch (exception& e) {
_initErrors.push_back((format(translate("Error: Could not create LOOT settings file. %1%")) % e.what()).str());
}
}
if (fs::exists(LootPaths::getSettingsPath())) {
try {
LootSettings::load(LootPaths::getSettingsPath());
}
catch (exception& e) {
_initErrors.push_back((format(translate("Error: Settings parsing failed. %1%")) % e.what()).str());
}
}
// Re-initialise the current game in case the game path setting was changed.
currentGame_->Init(true);
// Update game path in settings object.
storeGameSettings(toGameSettings(games_));
}
//Set up logging.
boost::log::add_file_log(
boost::log::keywords::file_name = LootPaths::getLogPath().string().c_str(),
boost::log::keywords::auto_flush = true,
boost::log::keywords::format = (
boost::log::expressions::stream
<< "[" << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S") << "]"
<< " [" << boost::log::trivial::severity << "]: "
<< boost::log::expressions::smessage
)
);
boost::log::add_common_attributes();
boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled());
void LootState::init(const std::string& cmdLineGame) {
// Do some preliminary locale / UTF-8 support setup here, in case the settings file reading requires it.
//Boost.Locale initialisation: Specify location of language dictionaries.
boost::locale::generator gen;
gen.add_messages_path(LootPaths::getL10nPath().string());
gen.add_messages_domain("loot");
// Log some useful info.
BOOST_LOG_TRIVIAL(info) << "LOOT Version: " << LootVersion::major << "." << LootVersion::minor << "." << LootVersion::patch;
BOOST_LOG_TRIVIAL(info) << "LOOT Build Revision: " << LootVersion::revision;
//Boost.Locale initialisation: Generate and imbue locales.
locale::global(gen(Language(Language::Code::english).GetLocale() + ".UTF-8"));
boost::filesystem::path::imbue(locale());
// Check if the LOOT local app data folder exists, and create it if not.
if (!fs::exists(LootPaths::getLootDataPath())) {
BOOST_LOG_TRIVIAL(info) << "Local app data LOOT folder doesn't exist, creating it.";
try {
fs::create_directory(LootPaths::getLootDataPath());
} catch (exception& e) {
initErrors_.push_back((format(translate("Error: Could not create LOOT settings file. %1%")) % e.what()).str());
}
}
if (fs::exists(LootPaths::getSettingsPath())) {
try {
LootSettings::load(LootPaths::getSettingsPath());
} catch (exception& e) {
initErrors_.push_back((format(translate("Error: Settings parsing failed. %1%")) % e.what()).str());
}
}
//Set up logging.
boost::log::add_file_log(
boost::log::keywords::file_name = LootPaths::getLogPath().string().c_str(),
boost::log::keywords::auto_flush = true,
boost::log::keywords::format = (
boost::log::expressions::stream
<< "[" << boost::log::expressions::format_date_time< boost::posix_time::ptime >("TimeStamp", "%H:%M:%S") << "]"
<< " [" << boost::log::trivial::severity << "]: "
<< boost::log::expressions::smessage
)
);
boost::log::add_common_attributes();
boost::log::core::get()->set_logging_enabled(isDebugLoggingEnabled());
// Log some useful info.
BOOST_LOG_TRIVIAL(info) << "LOOT Version: " << LootVersion::major << "." << LootVersion::minor << "." << LootVersion::patch;
BOOST_LOG_TRIVIAL(info) << "LOOT Build Revision: " << LootVersion::revision;
#ifdef _WIN32
// Check if LOOT is being run through Mod Organiser.
bool runFromMO = GetModuleHandle(ToWinWide("hook.dll").c_str()) != NULL;
if (runFromMO) {
BOOST_LOG_TRIVIAL(info) << "LOOT is being run through Mod Organiser.";
}
bool runFromMO = GetModuleHandle(ToWinWide("hook.dll").c_str()) != NULL;
if (runFromMO) {
BOOST_LOG_TRIVIAL(info) << "LOOT is being run through Mod Organiser.";
}
#endif
// The CEF debug log is appended to, not overwritten, so it gets really long.
// Delete the current CEF debug log.
fs::remove(LootPaths::getLootDataPath() / "CEFDebugLog.txt");
fs::remove(LootPaths::getLootDataPath() / "CEFDebugLog.txt");
// Now that settings have been loaded, set the locale again to handle translations.
if (getLanguage().GetCode() != Language::Code::english) {
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings.";
loot::Language lang(getLanguage());
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.GetName();
// Now that settings have been loaded, set the locale again to handle translations.
if (getLanguage().GetCode() != Language::Code::english) {
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings.";
Language lang(getLanguage());
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.GetName();
//Boost.Locale initialisation: Generate and imbue locales.
locale::global(gen(lang.GetLocale() + ".UTF-8"));
boost::filesystem::path::imbue(locale());
}
//Boost.Locale initialisation: Generate and imbue locales.
locale::global(gen(lang.GetLocale() + ".UTF-8"));
boost::filesystem::path::imbue(locale());
}
// Detect games & select startup game
//-----------------------------------
// Detect games & select startup game
//-----------------------------------
//Detect installed games.
BOOST_LOG_TRIVIAL(debug) << "Detecting installed games.";
_games = ToGames(getGameSettings());
//Detect installed games.
BOOST_LOG_TRIVIAL(debug) << "Detecting installed games.";
games_ = toGames(getGameSettings());
try {
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
SelectGame(cmdLineGame);
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
_currentGame->Init(true);
// Update game path in settings object.
storeGameSettings(ToGameSettings(_games));
}
catch (loot::Error &e) {
if (e.code() == loot::Error::Code::no_game_detected) {
_initErrors.push_back(e.what());
}
else {
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
_initErrors.push_back((format(translate("Error: Game-specific settings could not be initialised. %1%")) % e.what()).str());
}
}
BOOST_LOG_TRIVIAL(debug) << "Game selected is " << _currentGame->Name();
}
const std::vector<std::string>& LootState::InitErrors() const {
return _initErrors;
}
void LootState::save(const boost::filesystem::path & file) {
storeLastGame(_currentGame->FolderName());
updateLastVersion();
LootSettings::save(file);
}
void LootState::ChangeGame(const std::string& newGameFolder) {
std::lock_guard<std::mutex> guard(mutex);
BOOST_LOG_TRIVIAL(debug) << "Changing current game to that with folder: " << newGameFolder;
_currentGame = find(_games.begin(), _games.end(), Game(GameType::autodetect, newGameFolder));
_currentGame->Init(true);
// Update game path in settings object.
storeGameSettings(ToGameSettings(_games));
BOOST_LOG_TRIVIAL(debug) << "New game is " << _currentGame->Name();
}
Game& LootState::CurrentGame() {
std::lock_guard<std::mutex> guard(mutex);
return *_currentGame;
}
std::vector<std::string> LootState::InstalledGames() {
vector<string> installedGames;
for (auto &game : _games) {
if (game.IsInstalled())
installedGames.push_back(game.FolderName());
}
return installedGames;
}
bool LootState::hasUnappliedChanges() const {
return unappliedChangeCounter > 0;
}
void LootState::incrementUnappliedChangeCounter() {
++unappliedChangeCounter;
}
void LootState::decrementUnappliedChangeCounter() {
if (unappliedChangeCounter > 0)
--unappliedChangeCounter;
}
void LootState::SelectGame(std::string preferredGame) {
if (preferredGame.empty()) {
// Get preferred game from settings.
if (getGame() != "auto")
preferredGame = getGame();
else if (getLastGame() != "auto")
preferredGame = getLastGame();
}
// Get iterator to preferred game.
_currentGame = find_if(begin(_games), end(_games), [&](Game& game) {
return (preferredGame.empty() || preferredGame == game.FolderName()) && game.IsInstalled();
});
// If the preferred game cannot be found, get the first installed game.
if (_currentGame == end(_games)) {
_currentGame = find_if(begin(_games), end(_games), [](Game& game) {
return game.IsInstalled();
});
}
// If no game can be selected, throw an exception.
if (_currentGame == end(_games)) {
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
throw Error(Error::Code::no_game_detected, translate("None of the supported games were detected."));
}
}
std::list<Game> LootState::ToGames(const std::vector<GameSettings>& settings) {
return list<Game>(settings.begin(), settings.end());
}
std::vector<GameSettings> LootState::ToGameSettings(const std::list<Game>& games) {
return vector<GameSettings>(games.begin(), games.end());
try {
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
selectGame(cmdLineGame);
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
currentGame_->Init(true);
// Update game path in settings object.
storeGameSettings(toGameSettings(games_));
} catch (Error &e) {
if (e.code() == Error::Code::no_game_detected) {
initErrors_.push_back(e.what());
} else {
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
initErrors_.push_back((format(translate("Error: Game-specific settings could not be initialised. %1%")) % e.what()).str());
}
}
BOOST_LOG_TRIVIAL(debug) << "Game selected is " << currentGame_->Name();
}
const std::vector<std::string>& LootState::getInitErrors() const {
return initErrors_;
}
void LootState::save(const boost::filesystem::path & file) {
storeLastGame(currentGame_->FolderName());
updateLastVersion();
LootSettings::save(file);
}
void LootState::changeGame(const std::string& newGameFolder) {
lock_guard<mutex> guard(mutex_);
BOOST_LOG_TRIVIAL(debug) << "Changing current game to that with folder: " << newGameFolder;
currentGame_ = find(games_.begin(), games_.end(), Game(GameType::autodetect, newGameFolder));
currentGame_->Init(true);
// Update game path in settings object.
storeGameSettings(toGameSettings(games_));
BOOST_LOG_TRIVIAL(debug) << "New game is " << currentGame_->Name();
}
Game& LootState::getCurrentGame() {
lock_guard<mutex> guard(mutex_);
return *currentGame_;
}
std::vector<std::string> LootState::getInstalledGames() {
vector<string> installedGames;
for (auto &game : games_) {
if (game.IsInstalled())
installedGames.push_back(game.FolderName());
}
return installedGames;
}
bool LootState::hasUnappliedChanges() const {
return unappliedChangeCounter_ > 0;
}
void LootState::incrementUnappliedChangeCounter() {
++unappliedChangeCounter_;
}
void LootState::decrementUnappliedChangeCounter() {
if (unappliedChangeCounter_ > 0)
--unappliedChangeCounter_;
}
void LootState::selectGame(std::string preferredGame) {
if (preferredGame.empty()) {
// Get preferred game from settings.
if (getGame() != "auto")
preferredGame = getGame();
else if (getLastGame() != "auto")
preferredGame = getLastGame();
}
// Get iterator to preferred game.
currentGame_ = find_if(begin(games_), end(games_), [&](Game& game) {
return (preferredGame.empty() || preferredGame == game.FolderName()) && game.IsInstalled();
});
// If the preferred game cannot be found, get the first installed game.
if (currentGame_ == end(games_)) {
currentGame_ = find_if(begin(games_), end(games_), [](Game& game) {
return game.IsInstalled();
});
}
// If no game can be selected, throw an exception.
if (currentGame_ == end(games_)) {
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
throw Error(Error::Code::no_game_detected, translate("None of the supported games were detected."));
}
}
std::list<Game> LootState::toGames(const std::vector<GameSettings>& settings) {
return std::list<Game>(settings.begin(), settings.end());
}
std::vector<GameSettings> LootState::toGameSettings(const std::list<Game>& games) {
return vector<GameSettings>(games.begin(), games.end());
}
}
+30 -30
View File
@@ -22,49 +22,49 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_BACKEND_LOOT_STATE
#define LOOT_BACKEND_LOOT_STATE
#ifndef LOOT_BACKEND_APP_LOOT_STATE
#define LOOT_BACKEND_APP_LOOT_STATE
#include "loot_settings.h"
#include "backend/app/loot_settings.h"
#include "backend/game/game.h"
namespace loot {
class LootState : public LootSettings {
public:
LootState();
class LootState : public LootSettings {
public:
LootState();
void load(YAML::Node& settings);
void Init(const std::string& cmdLineGame);
const std::vector<std::string>& InitErrors() const;
void load(YAML::Node& settings);
void init(const std::string& cmdLineGame);
const std::vector<std::string>& getInitErrors() const;
void save(const boost::filesystem::path& file);
void save(const boost::filesystem::path& file);
Game& CurrentGame();
void ChangeGame(const std::string& newGameFolder);
Game& getCurrentGame();
void changeGame(const std::string& newGameFolder);
// Get the folder names of the installed games.
std::vector<std::string> InstalledGames();
// Get the folder names of the installed games.
std::vector<std::string> getInstalledGames();
bool hasUnappliedChanges() const;
void incrementUnappliedChangeCounter();
void decrementUnappliedChangeCounter();
private:
std::list<Game> _games;
std::list<Game>::iterator _currentGame;
std::vector<std::string> _initErrors;
bool hasUnappliedChanges() const;
void incrementUnappliedChangeCounter();
void decrementUnappliedChangeCounter();
private:
// Select initial game.
void selectGame(std::string cmdLineGame);
// Used to check if LOOT has unaccepted sorting or metadata changes on quit.
size_t unappliedChangeCounter;
static std::list<Game> toGames(const std::vector<GameSettings>& settings);
static std::vector<GameSettings> toGameSettings(const std::list<Game>& games);
// Select initial game.
void SelectGame(std::string cmdLineGame);
std::list<Game> games_;
std::list<Game>::iterator currentGame_;
std::vector<std::string> initErrors_;
static std::list<Game> ToGames(const std::vector<GameSettings>& settings);
static std::vector<GameSettings> ToGameSettings(const std::list<Game>& games);
// Used to check if LOOT has unaccepted sorting or metadata changes on quit.
size_t unappliedChangeCounter_;
// Mutex used to protect access to member variables.
std::mutex mutex;
};
// Mutex used to protect access to member variables.
std::mutex mutex_;
};
}
#endif
+10 -10
View File
@@ -22,21 +22,21 @@ along with LOOT. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef LOOT_BACKEND_LOOT_VERSION
#define LOOT_BACKEND_LOOT_VERSION
#ifndef LOOT_BACKEND_APP_LOOT_VERSION
#define LOOT_BACKEND_APP_LOOT_VERSION
#include <string>
namespace loot {
class LootVersion {
public:
static const unsigned int major;
static const unsigned int minor;
static const unsigned int patch;
static const std::string revision;
class LootVersion {
public:
static const unsigned int major;
static const unsigned int minor;
static const unsigned int patch;
static const std::string revision;
static std::string string();
};
static std::string string();
};
}
#endif
+36 -36
View File
@@ -22,52 +22,52 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOOT_ERROR__
#define __LOOT_ERROR__
#ifndef LOOT_BACKEND_ERROR
#define LOOT_BACKEND_ERROR
#include <exception>
#include <string>
namespace loot {
class Error : public std::exception {
public:
enum struct Code : unsigned int {
// These must not be changed for API stability.
ok = 0,
liblo_error = 1,
path_write_fail = 2,
path_read_fail = 3,
condition_eval_fail = 4,
regex_eval_fail = 5,
no_mem = 6,
invalid_args = 7,
no_tag_map = 8,
path_not_found = 9,
no_game_detected = 10,
//11 was subversion_error, and was removed along with svn support.
git_error = 12,
windows_error = 13,
sorting_error = 14,
};
class Error : public std::exception {
public:
enum struct Code : unsigned int {
// These must not be changed for API stability.
ok = 0,
liblo_error = 1,
path_write_fail = 2,
path_read_fail = 3,
condition_eval_fail = 4,
regex_eval_fail = 5,
no_mem = 6,
invalid_args = 7,
no_tag_map = 8,
path_not_found = 9,
no_game_detected = 10,
//11 was subversion_error, and was removed along with svn support.
git_error = 12,
windows_error = 13,
sorting_error = 14,
};
Error(const Code code_arg, const std::string& what_arg) : _code(code_arg), _what(what_arg) {}
~Error() throw() {};
Error(const Code code_arg, const std::string& what_arg) : code_(code_arg), what_(what_arg) {}
~Error() throw() {};
Code code() const { return _code; }
Code code() const { return code_; }
unsigned int codeAsUnsignedInt() const {
return asUnsignedInt(_code);
}
unsigned int codeAsUnsignedInt() const {
return asUnsignedInt(code_);
}
const char * what() const throw() { return _what.c_str(); }
const char * what() const throw() { return what_.c_str(); }
static unsigned int asUnsignedInt(Code code) {
return static_cast<unsigned int>(code);
}
private:
Code _code;
std::string _what;
};
static unsigned int asUnsignedInt(Code code) {
return static_cast<unsigned int>(code);
}
private:
Code code_;
std::string what_;
};
}
#endif
+154 -153
View File
@@ -22,10 +22,7 @@
<http://www.gnu.org/licenses/>.
*/
#include "game.h"
#include "../app/loot_paths.h"
#include "../helpers/helpers.h"
#include "../error.h"
#include "backend/game/game.h"
#include <thread>
#include <cmath>
@@ -34,165 +31,169 @@
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
using namespace std;
#include "backend/app/loot_paths.h"
#include "backend/error.h"
#include "backend/helpers/helpers.h"
using boost::locale::translate;
using std::list;
using std::string;
using std::thread;
using std::vector;
namespace fs = boost::filesystem;
namespace lc = boost::locale;
namespace loot {
Game::Game() : _pluginsFullyLoaded(false) {}
Game::Game() : pluginsFullyLoaded_(false) {}
Game::Game(const GameSettings& gameSettings) : GameSettings(gameSettings), _pluginsFullyLoaded(false) {
this->SetName(gameSettings.Name())
.SetMaster(gameSettings.Master())
.SetRepoURL(gameSettings.RepoURL())
.SetRepoBranch(gameSettings.RepoBranch())
.SetGamePath(gameSettings.GamePath())
.SetRegistryKey(gameSettings.RegistryKey());
Game::Game(const GameSettings& gameSettings) : GameSettings(gameSettings), pluginsFullyLoaded_(false) {
this->SetName(gameSettings.Name())
.SetMaster(gameSettings.Master())
.SetRepoURL(gameSettings.RepoURL())
.SetRepoBranch(gameSettings.RepoBranch())
.SetGamePath(gameSettings.GamePath())
.SetRegistryKey(gameSettings.RegistryKey());
}
Game::Game(const GameType gameType, const std::string& folder) : GameSettings(gameType, folder), pluginsFullyLoaded_(false) {}
void Game::Init(bool createFolder, const boost::filesystem::path& gameLocalAppData) {
if (Type() != GameType::tes4 && Type() != GameType::tes5 && Type() != GameType::fo3 && Type() != GameType::fonv && Type() != GameType::fo4) {
throw Error(Error::Code::invalid_args, translate("Invalid game ID supplied.").str());
}
BOOST_LOG_TRIVIAL(info) << "Initialising filesystem-related data for game: " << Name();
if (!this->IsInstalled()) {
BOOST_LOG_TRIVIAL(error) << "Game path could not be detected.";
throw Error(Error::Code::path_not_found, translate("Game path could not be detected.").str());
}
if (createFolder) {
//Make sure that the LOOT game path exists.
try {
if (!fs::exists(LootPaths::getLootDataPath() / FolderName()))
fs::create_directories(LootPaths::getLootDataPath() / FolderName());
} catch (fs::filesystem_error& e) {
BOOST_LOG_TRIVIAL(error) << "Could not create LOOT folder for game. Details: " << e.what();
throw Error(Error::Code::path_write_fail, translate("Could not create LOOT folder for game. Details:").str() + " " + e.what());
}
}
LoadOrderHandler::Init(*this, gameLocalAppData);
}
void Game::RedatePlugins() {
if (Type() != GameType::tes5)
return;
list<string> loadorder = GetLoadOrder();
if (!loadorder.empty()) {
time_t lastTime = 0;
for (const auto &pluginName : loadorder) {
fs::path filepath = DataPath() / pluginName;
if (!fs::exists(filepath)) {
if (fs::exists(filepath.string() + ".ghost"))
filepath += ".ghost";
else
continue;
}
time_t thisTime = fs::last_write_time(filepath);
BOOST_LOG_TRIVIAL(info) << "Current timestamp for \"" << filepath.filename().string() << "\": " << thisTime;
if (thisTime >= lastTime) {
lastTime = thisTime;
BOOST_LOG_TRIVIAL(trace) << "No need to redate \"" << filepath.filename().string() << "\".";
} else {
lastTime += 60;
fs::last_write_time(filepath, lastTime); //Space timestamps by a minute.
BOOST_LOG_TRIVIAL(info) << "Redated \"" << filepath.filename().string() << "\" to: " << lastTime;
}
}
}
}
Game::Game(const GameType gameType, const std::string& folder) : GameSettings(gameType, folder), _pluginsFullyLoaded(false) {}
void Game::Init(bool createFolder, const boost::filesystem::path& gameLocalAppData) {
if (Type() != GameType::tes4 && Type() != GameType::tes5 && Type() != GameType::fo3 && Type() != GameType::fonv && Type() != GameType::fo4) {
throw Error(Error::Code::invalid_args, lc::translate("Invalid game ID supplied.").str());
}
BOOST_LOG_TRIVIAL(info) << "Initialising filesystem-related data for game: " << Name();
if (!this->IsInstalled()) {
BOOST_LOG_TRIVIAL(error) << "Game path could not be detected.";
throw Error(Error::Code::path_not_found, lc::translate("Game path could not be detected.").str());
}
if (createFolder) {
//Make sure that the LOOT game path exists.
try {
if (!fs::exists(LootPaths::getLootDataPath() / FolderName()))
fs::create_directories(LootPaths::getLootDataPath() / FolderName());
}
catch (fs::filesystem_error& e) {
BOOST_LOG_TRIVIAL(error) << "Could not create LOOT folder for game. Details: " << e.what();
throw Error(Error::Code::path_write_fail, lc::translate("Could not create LOOT folder for game. Details:").str() + " " + e.what());
}
}
LoadOrderHandler::Init(*this, gameLocalAppData);
}
void Game::LoadPlugins(bool headersOnly) {
uintmax_t meanFileSize = 0;
std::multimap<uintmax_t, string> sizeMap;
void Game::RedatePlugins() {
if (Type() != GameType::tes5)
return;
list<string> loadorder = GetLoadOrder();
if (!loadorder.empty()) {
time_t lastTime = 0;
for (const auto &pluginName : loadorder) {
fs::path filepath = DataPath() / pluginName;
if (!fs::exists(filepath)) {
if (fs::exists(filepath.string() + ".ghost"))
filepath += ".ghost";
else
continue;
}
time_t thisTime = fs::last_write_time(filepath);
BOOST_LOG_TRIVIAL(info) << "Current timestamp for \"" << filepath.filename().string() << "\": " << thisTime;
if (thisTime >= lastTime) {
lastTime = thisTime;
BOOST_LOG_TRIVIAL(trace) << "No need to redate \"" << filepath.filename().string() << "\".";
}
else {
lastTime += 60;
fs::last_write_time(filepath, lastTime); //Space timestamps by a minute.
BOOST_LOG_TRIVIAL(info) << "Redated \"" << filepath.filename().string() << "\" to: " << lastTime;
}
}
}
}
// First find out how many plugins there are, and their sizes.
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)) {
string name = it->path().filename().string();
BOOST_LOG_TRIVIAL(info) << "Found plugin: " << name;
void Game::LoadPlugins(bool headersOnly) {
uintmax_t meanFileSize = 0;
multimap<uintmax_t, string> sizeMap;
// First find out how many plugins there are, and their sizes.
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)) {
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;
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(), sizeMap.size());
threadsToUse = std::max(threadsToUse, (size_t)1);
// Divide the plugins up by 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.
size_t currentGroup = 0;
for (const auto& plugin : sizeMap) {
if (currentGroup == threadsToUse)
currentGroup = 0;
BOOST_LOG_TRIVIAL(trace) << "Adding plugin " << plugin.second << " to loading group " << currentGroup;
pluginGroups[currentGroup].push_back(plugin.second);
++currentGroup;
}
// Clear the existing plugin cache.
ClearCachedPlugins();
// Load the plugins.
BOOST_LOG_TRIVIAL(trace) << "Starting plugin loading.";
vector<thread> threads;
while (threads.size() < threadsToUse) {
vector<string>& pluginGroup = pluginGroups[threads.size()];
threads.push_back(thread([&]() {
for (auto pluginName : pluginGroup) {
BOOST_LOG_TRIVIAL(trace) << "Loading " << pluginName;
if (boost::iequals(pluginName, Master()))
AddPlugin(Plugin(*this, pluginName, true));
else
AddPlugin(Plugin(*this, pluginName, headersOnly));
}
}));
}
// Join all threads.
for (auto& thread : threads) {
if (thread.joinable())
thread.join();
}
_pluginsFullyLoaded = !headersOnly;
}
// Trim .ghost extension if present.
if (boost::iends_with(name, ".ghost"))
name = name.substr(0, name.length() - 6);
bool Game::ArePluginsFullyLoaded() const {
return _pluginsFullyLoaded;
}
uintmax_t fileSize = fs::file_size(it->path());
meanFileSize += fileSize;
bool Game::IsPluginActive(const std::string& pluginName) const {
try {
return GetPlugin(pluginName).IsActive();
}
catch (...) {
return LoadOrderHandler::IsPluginActive(pluginName);
}
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(), sizeMap.size());
threadsToUse = std::max(threadsToUse, (size_t)1);
// Divide the plugins up by 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.
size_t currentGroup = 0;
for (const auto& plugin : sizeMap) {
if (currentGroup == threadsToUse)
currentGroup = 0;
BOOST_LOG_TRIVIAL(trace) << "Adding plugin " << plugin.second << " to loading group " << currentGroup;
pluginGroups[currentGroup].push_back(plugin.second);
++currentGroup;
}
// Clear the existing plugin cache.
ClearCachedPlugins();
// Load the plugins.
BOOST_LOG_TRIVIAL(trace) << "Starting plugin loading.";
vector<thread> threads;
while (threads.size() < threadsToUse) {
vector<string>& pluginGroup = pluginGroups[threads.size()];
threads.push_back(thread([&]() {
for (auto pluginName : pluginGroup) {
BOOST_LOG_TRIVIAL(trace) << "Loading " << pluginName;
if (boost::iequals(pluginName, Master()))
AddPlugin(Plugin(*this, pluginName, true));
else
AddPlugin(Plugin(*this, pluginName, headersOnly));
}
}));
}
// Join all threads.
for (auto& thread : threads) {
if (thread.joinable())
thread.join();
}
pluginsFullyLoaded_ = !headersOnly;
}
bool Game::ArePluginsFullyLoaded() const {
return pluginsFullyLoaded_;
}
bool Game::IsPluginActive(const std::string& pluginName) const {
try {
return GetPlugin(pluginName).IsActive();
} catch (...) {
return LoadOrderHandler::IsPluginActive(pluginName);
}
}
}
+22 -22
View File
@@ -22,38 +22,38 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOOT_GAME__
#define __LOOT_GAME__
#include "game_cache.h"
#include "game_settings.h"
#include "load_order_handler.h"
#ifndef LOOT_BACKEND_GAME_GAME
#define LOOT_BACKEND_GAME_GAME
#include <string>
#include <boost/filesystem.hpp>
#include "backend/game/game_cache.h"
#include "backend/game/game_settings.h"
#include "backend/game/load_order_handler.h"
namespace loot {
class Game : public GameSettings, public LoadOrderHandler, public GameCache {
public:
//Game functions.
Game(); //Sets game to GameType::autodetect, with all other vars being empty.
Game(const GameSettings& gameSettings);
Game(const GameType gameType, const std::string& lootFolder = "");
class Game : public GameSettings, public LoadOrderHandler, public GameCache {
public:
//Game functions.
Game(); //Sets game to GameType::autodetect, with all other vars being empty.
Game(const GameSettings& gameSettings);
Game(const GameType gameType, const std::string& lootFolder = "");
void Init(bool createFolder, const boost::filesystem::path& gameLocalAppData = "");
void Init(bool createFolder, const boost::filesystem::path& gameLocalAppData = "");
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
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.
void LoadPlugins(bool headersOnly); //Loads all installed plugins.
bool ArePluginsFullyLoaded() const; // Checks if the game's plugins have already been loaded.
// 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;
};
// 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_;
};
}
#endif
+113 -111
View File
@@ -22,9 +22,7 @@
<http://www.gnu.org/licenses/>.
*/
#include "game_cache.h"
#include "../helpers/helpers.h"
#include "../error.h"
#include "backend/game/game_cache.h"
#include <thread>
@@ -32,118 +30,122 @@
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
using namespace std;
#include "backend/error.h"
#include "backend/helpers/helpers.h"
namespace fs = boost::filesystem;
namespace lc = boost::locale;
using boost::locale::to_lower;
using std::lock_guard;
using std::mutex;
using std::pair;
using std::string;
namespace loot {
GameCache::GameCache() : isLoadOrderSorted(false) {}
GameCache::GameCache() : isLoadOrderSorted_(false) {}
GameCache::GameCache(const GameCache& cache) :
masterlist(cache.masterlist),
userlist(cache.userlist),
conditionCache(cache.conditionCache),
plugins(cache.plugins),
messages(cache.messages),
isLoadOrderSorted(cache.isLoadOrderSorted) {}
GameCache::GameCache(const GameCache& cache) :
masterlist_(cache.masterlist_),
userlist_(cache.userlist_),
conditions_(cache.conditions_),
plugins_(cache.plugins_),
messages_(cache.messages_),
isLoadOrderSorted_(cache.isLoadOrderSorted_) {}
GameCache& GameCache::operator=(const GameCache& cache) {
if (&cache != this) {
masterlist = cache.masterlist;
userlist = cache.userlist;
conditionCache = cache.conditionCache;
plugins = cache.plugins;
messages = cache.messages;
isLoadOrderSorted = cache.isLoadOrderSorted;
}
GameCache& GameCache::operator=(const GameCache& cache) {
if (&cache != this) {
masterlist_ = cache.masterlist_;
userlist_ = cache.userlist_;
conditions_ = cache.conditions_;
plugins_ = cache.plugins_;
messages_ = cache.messages_;
isLoadOrderSorted_ = cache.isLoadOrderSorted_;
}
return *this;
}
Masterlist & GameCache::GetMasterlist() {
return masterlist;
}
MetadataList & GameCache::GetUserlist() {
return userlist;
}
void GameCache::CacheCondition(const std::string& condition, bool result) {
std::lock_guard<std::mutex> guard(mutex);
conditionCache.insert(pair<string, bool>(boost::locale::to_lower(condition), result));
}
std::pair<bool, bool> GameCache::GetCachedCondition(const std::string& condition) const {
std::lock_guard<std::mutex> guard(mutex);
auto it = conditionCache.find(boost::locale::to_lower(condition));
if (it != conditionCache.end())
return std::pair<bool, bool>(it->second, true);
else
return std::pair<bool, bool>(false, false);
}
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;
}
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::Code::invalid_args, "No plugin \"" + pluginName + "\" exists.");
}
void GameCache::AddPlugin(const Plugin&& plugin) {
std::lock_guard<std::mutex> lock(mutex);
auto pair = plugins.emplace(boost::locale::to_lower(plugin.Name()), plugin);
if (!pair.second)
pair.first->second = plugin;
}
std::vector<Message> GameCache::GetMessages() const {
vector<Message> output(messages);
if (!isLoadOrderSorted)
output.push_back(Message(Message::Type::warn, "You have not sorted your load order this session."));
return output;
}
void GameCache::AppendMessage(const Message& message) {
std::lock_guard<std::mutex> guard(mutex);
messages.push_back(message);
}
void GameCache::SetLoadOrderSorted(bool isLoadOrderSorted) {
this->isLoadOrderSorted = isLoadOrderSorted;
}
void GameCache::ClearCachedConditions() {
std::lock_guard<std::mutex> guard(mutex);
conditionCache.clear();
}
void GameCache::ClearCachedPlugins() {
std::lock_guard<std::mutex> guard(mutex);
plugins.clear();
}
void GameCache::ClearMessages() {
std::lock_guard<std::mutex> guard(mutex);
messages.clear();
}
return *this;
}
Masterlist & GameCache::GetMasterlist() {
return masterlist_;
}
MetadataList & GameCache::GetUserlist() {
return userlist_;
}
void GameCache::CacheCondition(const std::string& condition, bool result) {
lock_guard<mutex> guard(mutex_);
conditions_.insert(pair<string, bool>(to_lower(condition), result));
}
std::pair<bool, bool> GameCache::GetCachedCondition(const std::string& condition) const {
lock_guard<mutex> guard(mutex_);
auto it = conditions_.find(to_lower(condition));
if (it != conditions_.end())
return pair<bool, bool>(it->second, true);
else
return pair<bool, bool>(false, false);
}
std::set<Plugin> GameCache::GetPlugins() const {
std::set<Plugin> output;
std::transform(begin(plugins_),
end(plugins_),
std::inserter<std::set<Plugin>>(output, begin(output)),
[](const pair<string, Plugin>& pluginPair) {
return pluginPair.second;
});
return output;
}
const Plugin& GameCache::GetPlugin(const std::string & pluginName) const {
auto it = plugins_.find(to_lower(pluginName));
if (it != end(plugins_))
return it->second;
throw Error(Error::Code::invalid_args, "No plugin \"" + pluginName + "\" exists.");
}
void GameCache::AddPlugin(const Plugin&& plugin) {
lock_guard<mutex> lock(mutex_);
auto pair = plugins_.emplace(to_lower(plugin.Name()), plugin);
if (!pair.second)
pair.first->second = plugin;
}
std::vector<Message> GameCache::GetMessages() const {
std::vector<Message> output(messages_);
if (!isLoadOrderSorted_)
output.push_back(Message(Message::Type::warn, "You have not sorted your load order this session."));
return output;
}
void GameCache::AppendMessage(const Message& message) {
lock_guard<mutex> guard(mutex_);
messages_.push_back(message);
}
void GameCache::SetLoadOrderSorted(bool isLoadOrderSorted) {
this->isLoadOrderSorted_ = isLoadOrderSorted;
}
void GameCache::ClearCachedConditions() {
lock_guard<mutex> guard(mutex_);
conditions_.clear();
}
void GameCache::ClearCachedPlugins() {
lock_guard<mutex> guard(mutex_);
plugins_.clear();
}
void GameCache::ClearMessages() {
lock_guard<mutex> guard(mutex_);
messages_.clear();
}
}
+35 -35
View File
@@ -22,54 +22,54 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOOT_GAME_CRC_CACHE__
#define __LOOT_GAME_CRC_CACHE__
#ifndef LOOT_BACKEND_GAME_GAME_CACHE
#define LOOT_BACKEND_GAME_GAME_CACHE
#include "../metadata_list.h"
#include "../masterlist.h"
#include "../plugin/plugin.h"
#include <string>
#include <mutex>
#include <string>
#include <unordered_map>
#include "backend/masterlist.h"
#include "backend/metadata_list.h"
#include "backend/plugin/plugin.h"
namespace loot {
class GameCache {
public:
GameCache();
GameCache(const GameCache& cache);
class GameCache {
public:
GameCache();
GameCache(const GameCache& cache);
GameCache& operator=(const GameCache& cache);
GameCache& operator=(const GameCache& cache);
Masterlist& GetMasterlist();
MetadataList& GetUserlist();
Masterlist& GetMasterlist();
MetadataList& GetUserlist();
// Returns false for second bool if no cached condition.
std::pair<bool, bool> GetCachedCondition(const std::string& condition) const;
void CacheCondition(const std::string& condition, bool result);
// Returns false for second bool if no cached condition.
std::pair<bool, bool> GetCachedCondition(const std::string& condition) 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);
std::set<Plugin> GetPlugins() const;
const Plugin& GetPlugin(const std::string& pluginName) const;
void AddPlugin(const Plugin&& plugin);
std::vector<Message> GetMessages() const;
void AppendMessage(const Message& message);
std::vector<Message> GetMessages() const;
void AppendMessage(const Message& message);
void SetLoadOrderSorted(bool isLoadOrderSorted);
void SetLoadOrderSorted(bool isLoadOrderSorted);
void ClearCachedConditions();
void ClearCachedPlugins();
void ClearMessages();
private:
Masterlist masterlist;
MetadataList userlist;
std::unordered_map<std::string, bool> conditionCache;
std::unordered_map<std::string, Plugin> plugins;
std::vector<Message> messages;
bool isLoadOrderSorted;
void ClearCachedConditions();
void ClearCachedPlugins();
void ClearMessages();
private:
Masterlist masterlist_;
MetadataList userlist_;
std::unordered_map<std::string, bool> conditions_;
std::unordered_map<std::string, Plugin> plugins_;
std::vector<Message> messages_;
bool isLoadOrderSorted_;
mutable std::mutex mutex;
};
mutable std::mutex mutex_;
};
}
#endif
+174 -181
View File
@@ -22,225 +22,218 @@
<http://www.gnu.org/licenses/>.
*/
#include "game_settings.h"
#include "../app/loot_paths.h"
#include "../helpers/helpers.h"
#include "../error.h"
#include "backend/game/game_settings.h"
#include <boost/algorithm/string.hpp>
#include <boost/locale.hpp>
#include <boost/log/trivial.hpp>
using namespace std;
#include "backend/app/loot_paths.h"
#include "backend/error.h"
#include "backend/helpers/helpers.h"
namespace fs = boost::filesystem;
namespace lc = boost::locale;
namespace loot {
GameSettings::GameSettings() : type_(GameType::autodetect) {}
GameSettings::GameSettings() : type_(GameType::autodetect) {}
GameSettings::GameSettings(const GameType gameType, const std::string& folder) : type_(gameType) {
if (Type() == GameType::tes4) {
_name = "TES IV: Oblivion";
_registryKey = "Software\\Bethesda Softworks\\Oblivion\\Installed Path";
_lootFolderName = "Oblivion";
_masterFile = "Oblivion.esm";
_repositoryURL = "https://github.com/loot/oblivion.git";
_repositoryBranch = "v0.8";
}
else if (Type() == GameType::tes5) {
_name = "TES V: Skyrim";
_registryKey = "Software\\Bethesda Softworks\\Skyrim\\Installed Path";
_lootFolderName = "Skyrim";
_masterFile = "Skyrim.esm";
_repositoryURL = "https://github.com/loot/skyrim.git";
_repositoryBranch = "v0.8";
}
else if (Type() == GameType::fo3) {
_name = "Fallout 3";
_registryKey = "Software\\Bethesda Softworks\\Fallout3\\Installed Path";
_lootFolderName = "Fallout3";
_masterFile = "Fallout3.esm";
_repositoryURL = "https://github.com/loot/fallout3.git";
_repositoryBranch = "v0.8";
}
else if (Type() == GameType::fonv) {
_name = "Fallout: New Vegas";
_registryKey = "Software\\Bethesda Softworks\\FalloutNV\\Installed Path";
_lootFolderName = "FalloutNV";
_masterFile = "FalloutNV.esm";
_repositoryURL = "https://github.com/loot/falloutnv.git";
_repositoryBranch = "v0.8";
}
else if (Type() == GameType::fo4) {
_name = "Fallout 4";
_registryKey = "Software\\Bethesda Softworks\\Fallout4\\Installed Path";
_lootFolderName = "Fallout4";
_masterFile = "Fallout4.esm";
_repositoryURL = "https://github.com/loot/fallout4.git";
_repositoryBranch = "v0.8";
}
GameSettings::GameSettings(const GameType gameCode, const std::string& folder) : type_(gameCode) {
if (Type() == GameType::tes4) {
name_ = "TES IV: Oblivion";
registryKey_ = "Software\\Bethesda Softworks\\Oblivion\\Installed Path";
lootFolderName_ = "Oblivion";
masterFile_ = "Oblivion.esm";
repositoryURL_ = "https://github.com/loot/oblivion.git";
repositoryBranch_ = "v0.8";
} else if (Type() == GameType::tes5) {
name_ = "TES V: Skyrim";
registryKey_ = "Software\\Bethesda Softworks\\Skyrim\\Installed Path";
lootFolderName_ = "Skyrim";
masterFile_ = "Skyrim.esm";
repositoryURL_ = "https://github.com/loot/skyrim.git";
repositoryBranch_ = "v0.8";
} else if (Type() == GameType::fo3) {
name_ = "Fallout 3";
registryKey_ = "Software\\Bethesda Softworks\\Fallout3\\Installed Path";
lootFolderName_ = "Fallout3";
masterFile_ = "Fallout3.esm";
repositoryURL_ = "https://github.com/loot/fallout3.git";
repositoryBranch_ = "v0.8";
} else if (Type() == GameType::fonv) {
name_ = "Fallout: New Vegas";
registryKey_ = "Software\\Bethesda Softworks\\FalloutNV\\Installed Path";
lootFolderName_ = "FalloutNV";
masterFile_ = "FalloutNV.esm";
repositoryURL_ = "https://github.com/loot/falloutnv.git";
repositoryBranch_ = "v0.8";
} else if (Type() == GameType::fo4) {
name_ = "Fallout 4";
registryKey_ = "Software\\Bethesda Softworks\\Fallout4\\Installed Path";
lootFolderName_ = "Fallout4";
masterFile_ = "Fallout4.esm";
repositoryURL_ = "https://github.com/loot/fallout4.git";
repositoryBranch_ = "v0.8";
}
if (!folder.empty())
_lootFolderName = folder;
if (!folder.empty())
lootFolderName_ = folder;
}
bool GameSettings::IsInstalled() {
try {
BOOST_LOG_TRIVIAL(trace) << "Checking if game \"" << name_ << "\" is installed.";
if (!gamePath_.empty() && fs::exists(gamePath_ / "Data" / masterFile_))
return true;
if (fs::exists(fs::path("..") / "Data" / masterFile_)) {
gamePath_ = "..";
return true;
}
bool GameSettings::IsInstalled() {
try {
BOOST_LOG_TRIVIAL(trace) << "Checking if game \"" << _name << "\" is installed.";
if (!_gamePath.empty() && fs::exists(_gamePath / "Data" / _masterFile))
return true;
if (fs::exists(fs::path("..") / "Data" / _masterFile)) {
_gamePath = "..";
return true;
}
#ifdef _WIN32
string path;
string key_parent = fs::path(_registryKey).parent_path().string();
string key_name = fs::path(_registryKey).filename().string();
path = RegKeyStringValue("HKEY_LOCAL_MACHINE", key_parent, key_name);
if (!path.empty() && fs::exists(fs::path(path) / "Data" / _masterFile)) {
_gamePath = path;
return true;
}
std::string path;
std::string key_parent = fs::path(registryKey_).parent_path().string();
std::string key_name = fs::path(registryKey_).filename().string();
path = RegKeyStringValue("HKEY_LOCAL_MACHINE", key_parent, key_name);
if (!path.empty() && fs::exists(fs::path(path) / "Data" / masterFile_)) {
gamePath_ = path;
return true;
}
#endif
}
catch (exception &e) {
BOOST_LOG_TRIVIAL(error) << "Error while checking if game \"" << _name << "\" is installed: " << e.what();
}
} catch (std::exception &e) {
BOOST_LOG_TRIVIAL(error) << "Error while checking if game \"" << name_ << "\" is installed: " << e.what();
}
return false;
}
return false;
}
bool GameSettings::operator == (const GameSettings& rhs) const {
return (boost::iequals(_name, rhs.Name()) || boost::iequals(_lootFolderName, rhs.FolderName()));
}
bool GameSettings::operator == (const GameSettings& rhs) const {
return (boost::iequals(name_, rhs.Name()) || boost::iequals(lootFolderName_, rhs.FolderName()));
}
GameType GameSettings::Type() const {
return type_;
}
GameType GameSettings::Type() const {
return type_;
}
libespm::GameId GameSettings::LibespmId() const {
if (type_ == GameType::tes4)
return libespm::GameId::OBLIVION;
else if (type_ == GameType::tes5)
return libespm::GameId::SKYRIM;
else if (type_ == GameType::fo3)
return libespm::GameId::FALLOUT3;
else if (type_ == GameType::fonv)
return libespm::GameId::FALLOUTNV;
else
return libespm::GameId::FALLOUT4;
}
libespm::GameId GameSettings::LibespmId() const {
if (type_ == GameType::tes4)
return libespm::GameId::OBLIVION;
else if (type_ == GameType::tes5)
return libespm::GameId::SKYRIM;
else if (type_ == GameType::fo3)
return libespm::GameId::FALLOUT3;
else if (type_ == GameType::fonv)
return libespm::GameId::FALLOUTNV;
else
return libespm::GameId::FALLOUT4;
}
string GameSettings::Name() const {
return _name;
}
std::string GameSettings::Name() const {
return name_;
}
string GameSettings::FolderName() const {
return _lootFolderName;
}
std::string GameSettings::FolderName() const {
return lootFolderName_;
}
std::string GameSettings::Master() const {
return _masterFile;
}
std::string GameSettings::Master() const {
return masterFile_;
}
std::string GameSettings::RegistryKey() const {
return _registryKey;
}
std::string GameSettings::RegistryKey() const {
return registryKey_;
}
std::string GameSettings::RepoURL() const {
return _repositoryURL;
}
std::string GameSettings::RepoURL() const {
return repositoryURL_;
}
std::string GameSettings::RepoBranch() const {
return _repositoryBranch;
}
std::string GameSettings::RepoBranch() const {
return repositoryBranch_;
}
fs::path GameSettings::GamePath() const {
return _gamePath;
}
fs::path GameSettings::GamePath() const {
return gamePath_;
}
fs::path GameSettings::DataPath() const {
if (_gamePath.empty())
return "";
else
return _gamePath / "Data";
}
fs::path GameSettings::DataPath() const {
if (gamePath_.empty())
return "";
else
return gamePath_ / "Data";
}
fs::path GameSettings::MasterlistPath() const {
if (_lootFolderName.empty())
return "";
else
return LootPaths::getLootDataPath() / _lootFolderName / "masterlist.yaml";
}
fs::path GameSettings::MasterlistPath() const {
if (lootFolderName_.empty())
return "";
else
return LootPaths::getLootDataPath() / lootFolderName_ / "masterlist.yaml";
}
fs::path GameSettings::UserlistPath() const {
if (_lootFolderName.empty())
return "";
else
return LootPaths::getLootDataPath() / _lootFolderName / "userlist.yaml";
}
fs::path GameSettings::UserlistPath() const {
if (lootFolderName_.empty())
return "";
else
return LootPaths::getLootDataPath() / lootFolderName_ / "userlist.yaml";
}
std::string GameSettings::GetArchiveFileExtension() const {
if (type_ == GameType::fo4)
return ".ba2";
else
return ".bsa";
}
std::string GameSettings::GetArchiveFileExtension() const {
if (type_ == GameType::fo4)
return ".ba2";
else
return ".bsa";
}
GameSettings& GameSettings::SetName(const std::string& name) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" name to: " << name;
_name = name;
return *this;
}
GameSettings& GameSettings::SetName(const std::string& name) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" name to: " << name;
name_ = name;
return *this;
}
GameSettings& GameSettings::SetMaster(const std::string& masterFile) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" master file to: " << masterFile;
_masterFile = masterFile;
return *this;
}
GameSettings& GameSettings::SetMaster(const std::string& masterFile) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" master file to: " << masterFile;
masterFile_ = masterFile;
return *this;
}
GameSettings& GameSettings::SetRegistryKey(const std::string& registry) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" registry key to: " << registry;
_registryKey = registry;
return *this;
}
GameSettings& GameSettings::SetRegistryKey(const std::string& registry) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" registry key to: " << registry;
registryKey_ = registry;
return *this;
}
GameSettings& GameSettings::SetRepoURL(const std::string& repositoryURL) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" repo URL to: " << repositoryURL;
_repositoryURL = repositoryURL;
return *this;
}
GameSettings& GameSettings::SetRepoURL(const std::string& repositoryURL) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" repo URL to: " << repositoryURL;
repositoryURL_ = repositoryURL;
return *this;
}
GameSettings& GameSettings::SetRepoBranch(const std::string& repositoryBranch) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" repo branch to: " << repositoryBranch;
_repositoryBranch = repositoryBranch;
return *this;
}
GameSettings& GameSettings::SetRepoBranch(const std::string& repositoryBranch) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" repo branch to: " << repositoryBranch;
repositoryBranch_ = repositoryBranch;
return *this;
}
GameSettings& GameSettings::SetGamePath(const boost::filesystem::path& path) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << _name << "\" game path to: " << path;
_gamePath = path;
return *this;
}
GameSettings& GameSettings::SetGamePath(const boost::filesystem::path& path) {
BOOST_LOG_TRIVIAL(trace) << "Setting \"" << name_ << "\" game path to: " << path;
gamePath_ = path;
return *this;
}
}
namespace YAML {
Emitter& operator << (Emitter& out, const loot::GameSettings& rhs) {
out << BeginMap
<< Key << "type" << Value << YAML::SingleQuoted << loot::GameSettings(rhs.Type()).FolderName()
<< Key << "folder" << Value << YAML::SingleQuoted << rhs.FolderName()
<< Key << "name" << Value << YAML::SingleQuoted << rhs.Name()
<< Key << "master" << Value << YAML::SingleQuoted << rhs.Master()
<< Key << "repo" << Value << YAML::SingleQuoted << rhs.RepoURL()
<< Key << "branch" << Value << YAML::SingleQuoted << rhs.RepoBranch()
<< Key << "path" << Value << YAML::SingleQuoted << rhs.GamePath().string()
<< Key << "registry" << Value << YAML::SingleQuoted << rhs.RegistryKey()
<< EndMap;
Emitter& operator << (Emitter& out, const loot::GameSettings& rhs) {
out << BeginMap
<< Key << "type" << Value << YAML::SingleQuoted << loot::GameSettings(rhs.Type()).FolderName()
<< Key << "folder" << Value << YAML::SingleQuoted << rhs.FolderName()
<< Key << "name" << Value << YAML::SingleQuoted << rhs.Name()
<< Key << "master" << Value << YAML::SingleQuoted << rhs.Master()
<< Key << "repo" << Value << YAML::SingleQuoted << rhs.RepoURL()
<< Key << "branch" << Value << YAML::SingleQuoted << rhs.RepoBranch()
<< Key << "path" << Value << YAML::SingleQuoted << rhs.GamePath().string()
<< Key << "registry" << Value << YAML::SingleQuoted << rhs.RegistryKey()
<< EndMap;
return out;
}
return out;
}
}
+91 -90
View File
@@ -22,125 +22,126 @@
<http://www.gnu.org/licenses/>.
*/
#ifndef __LOOT_GAME_SETTINGS__
#define __LOOT_GAME_SETTINGS__
#ifndef LOOT_BACKEND_GAME_GAME_SETTINGS
#define LOOT_BACKEND_GAME_GAME_SETTINGS
#include <string>
#include <list>
#include <boost/filesystem.hpp>
#include <yaml-cpp/yaml.h>
#include <libespm/GameId.h>
#include <yaml-cpp/yaml.h>
#include "backend/game/game_type.h"
namespace loot {
class GameSettings {
public:
//Game functions.
GameSettings(); //Sets game to LOOT_GameType::autodetect, with all other vars being empty.
GameSettings(const GameType gameType, const std::string& lootFolder = "");
class GameSettings {
public:
GameSettings(); //Sets game type to autodetect, with all other vars being empty.
GameSettings(const GameType gameType, const std::string& lootFolder = "");
bool IsInstalled(); //Sets gamePath if the current value is not valid and a valid path is found.
bool IsInstalled(); //Sets gamePath if the current value is not valid and a valid path is found.
bool operator == (const GameSettings& rhs) const; //Compares names and folder names.
bool operator == (const GameSettings& rhs) const; //Compares names and folder names.
GameType Type() const;
libespm::GameId LibespmId() const;
std::string Name() const; //Returns the game's name, eg. "TES IV: Oblivion".
std::string FolderName() const;
std::string Master() const;
std::string RegistryKey() const;
std::string RepoURL() const;
std::string RepoBranch() const;
GameType Type() const;
libespm::GameId LibespmId() const;
std::string Name() const; //Returns the game's name, eg. "TES IV: Oblivion".
std::string FolderName() const;
std::string Master() const;
std::string RegistryKey() const;
std::string RepoURL() const;
std::string RepoBranch() const;
boost::filesystem::path GamePath() const;
boost::filesystem::path DataPath() const;
boost::filesystem::path MasterlistPath() const;
boost::filesystem::path UserlistPath() const;
boost::filesystem::path GamePath() const;
boost::filesystem::path DataPath() const;
boost::filesystem::path MasterlistPath() const;
boost::filesystem::path UserlistPath() const;
std::string GetArchiveFileExtension() const;
std::string GetArchiveFileExtension() const;
GameSettings& SetName(const std::string& name);
GameSettings& SetMaster(const std::string& masterFile);
GameSettings& SetRegistryKey(const std::string& registry);
GameSettings& SetRepoURL(const std::string& repositoryURL);
GameSettings& SetRepoBranch(const std::string& repositoryBranch);
GameSettings& SetGamePath(const boost::filesystem::path& path);
private:
GameType type_;
std::string _name;
std::string _masterFile;
GameSettings& SetName(const std::string& name);
GameSettings& SetMaster(const std::string& masterFile);
GameSettings& SetRegistryKey(const std::string& registry);
GameSettings& SetRepoURL(const std::string& repositoryURL);
GameSettings& SetRepoBranch(const std::string& repositoryBranch);
GameSettings& SetGamePath(const boost::filesystem::path& path);
std::string _registryKey;
private:
GameType type_;
std::string name_;
std::string masterFile_;
std::string _lootFolderName;
std::string _repositoryURL;
std::string _repositoryBranch;
std::string registryKey_;
boost::filesystem::path _gamePath; //Path to the game's folder.
};
std::string lootFolderName_;
std::string repositoryURL_;
std::string repositoryBranch_;
boost::filesystem::path gamePath_; //Path to the game's folder.
};
}
namespace YAML {
template<>
struct convert < loot::GameSettings > {
static Node encode(const loot::GameSettings& rhs) {
Node node;
template<>
struct convert<loot::GameSettings> {
static Node encode(const loot::GameSettings& rhs) {
Node node;
node["type"] = loot::GameSettings(rhs.Type()).FolderName();
node["name"] = rhs.Name();
node["folder"] = rhs.FolderName();
node["master"] = rhs.Master();
node["repo"] = rhs.RepoURL();
node["branch"] = rhs.RepoBranch();
node["path"] = rhs.GamePath().string();
node["registry"] = rhs.RegistryKey();
node["type"] = loot::GameSettings(rhs.Type()).FolderName();
node["name"] = rhs.Name();
node["folder"] = rhs.FolderName();
node["master"] = rhs.Master();
node["repo"] = rhs.RepoURL();
node["branch"] = rhs.RepoBranch();
node["path"] = rhs.GamePath().string();
node["registry"] = rhs.RegistryKey();
return node;
}
return node;
}
static bool decode(const Node& node, loot::GameSettings& rhs) {
if (!node.IsMap())
throw RepresentationException(node.Mark(), "bad conversion: 'game settings' object must be a map");
if (!node["folder"])
throw RepresentationException(node.Mark(), "bad conversion: 'folder' key missing from 'game settings' object");
if (!node["type"])
throw RepresentationException(node.Mark(), "bad conversion: 'type' key missing from 'game settings' object");
static bool decode(const Node& node, loot::GameSettings& rhs) {
using loot::GameSettings;
using loot::GameType;
if (node["type"].as<std::string>() == loot::GameSettings(loot::GameType::tes4).FolderName())
rhs = loot::GameSettings(loot::GameType::tes4, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == loot::GameSettings(loot::GameType::tes5).FolderName())
rhs = loot::GameSettings(loot::GameType::tes5, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == loot::GameSettings(loot::GameType::fo3).FolderName())
rhs = loot::GameSettings(loot::GameType::fo3, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == loot::GameSettings(loot::GameType::fonv).FolderName())
rhs = loot::GameSettings(loot::GameType::fonv, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == loot::GameSettings(loot::GameType::fo4).FolderName())
rhs = loot::GameSettings(loot::GameType::fo4, node["folder"].as<std::string>());
else
throw RepresentationException(node.Mark(), "bad conversion: invalid value for 'type' key in 'game settings' object");
if (!node.IsMap())
throw RepresentationException(node.Mark(), "bad conversion: 'game settings' object must be a map");
if (!node["folder"])
throw RepresentationException(node.Mark(), "bad conversion: 'folder' key missing from 'game settings' object");
if (!node["type"])
throw RepresentationException(node.Mark(), "bad conversion: 'type' key missing from 'game settings' object");
if (node["name"])
rhs.SetName(node["name"].as<std::string>());
if (node["master"])
rhs.SetMaster(node["master"].as<std::string>());
if (node["repo"])
rhs.SetRepoURL(node["repo"].as<std::string>());
if (node["branch"])
rhs.SetRepoBranch(node["branch"].as<std::string>());
if (node["path"])
rhs.SetGamePath(node["path"].as<std::string>());
if (node["registry"])
rhs.SetRegistryKey(node["registry"].as<std::string>());
if (node["type"].as<std::string>() == GameSettings(GameType::tes4).FolderName())
rhs = GameSettings(GameType::tes4, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == GameSettings(GameType::tes5).FolderName())
rhs = GameSettings(GameType::tes5, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == GameSettings(GameType::fo3).FolderName())
rhs = GameSettings(GameType::fo3, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == GameSettings(GameType::fonv).FolderName())
rhs = GameSettings(GameType::fonv, node["folder"].as<std::string>());
else if (node["type"].as<std::string>() == GameSettings(GameType::fo4).FolderName())
rhs = GameSettings(GameType::fo4, node["folder"].as<std::string>());
else
throw RepresentationException(node.Mark(), "bad conversion: invalid value for 'type' key in 'game settings' object");
return true;
}
};
if (node["name"])
rhs.SetName(node["name"].as<std::string>());
if (node["master"])
rhs.SetMaster(node["master"].as<std::string>());
if (node["repo"])
rhs.SetRepoURL(node["repo"].as<std::string>());
if (node["branch"])
rhs.SetRepoBranch(node["branch"].as<std::string>());
if (node["path"])
rhs.SetGamePath(node["path"].as<std::string>());
if (node["registry"])
rhs.SetRegistryKey(node["registry"].as<std::string>());
Emitter& operator << (Emitter& out, const loot::GameSettings& rhs);
return true;
}
};
Emitter& operator << (Emitter& out, const loot::GameSettings& rhs);
}
#endif
+8 -8
View File
@@ -26,14 +26,14 @@ along with LOOT. If not, see
#define LOOT_BACKEND_GAME_GAME_TYPE
namespace loot {
enum struct GameType : unsigned int {
autodetect = 0,
tes4 = 1,
tes5 = 2,
fo3 = 3,
fonv = 4,
fo4 = 5,
};
enum struct GameType : unsigned int {
autodetect = 0,
tes4 = 1,
tes5 = 2,
fo3 = 3,
fonv = 4,
fo4 = 5,
};
}
#endif

Some files were not shown because too many files have changed in this diff Show More