mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
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:
@@ -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
File diff suppressed because it is too large
Load Diff
+357
-373
File diff suppressed because it is too large
Load Diff
+56
-56
@@ -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
@@ -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
|
||||
|
||||
@@ -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_;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user