mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Refactored plugin loading code into new class.
PluginLoader now handles the details of how plugins are read, cleaning up the Game and Plugin classes a little.
This commit is contained in:
@@ -91,6 +91,7 @@ set (LOOT_SRC "${CMAKE_SOURCE_DIR}/src/backend/metadata/conditional_metadata.c
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/metadata_list.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/masterlist.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/plugin.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/plugin_loader.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/helpers.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/language.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/version.cpp"
|
||||
@@ -113,6 +114,7 @@ set (LOOT_HEADERS "${CMAKE_SOURCE_DIR}/src/backend/metadata/condition_grammar.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/metadata_list.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/masterlist.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/plugin.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/plugin_loader.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/helpers.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/language.h"
|
||||
"${CMAKE_SOURCE_DIR}/src/backend/version.h"
|
||||
|
||||
+1
-14
@@ -51,20 +51,7 @@ namespace loot {
|
||||
gameSettings.RegistryKey());
|
||||
}
|
||||
|
||||
Game::Game(const unsigned int gameCode, const std::string& folder) : GameSettings(gameCode, folder), gh(nullptr) {
|
||||
if (Id() == Game::tes4) {
|
||||
espm_settings = espm::Settings("tes4");
|
||||
}
|
||||
else if (Id() == Game::tes5) {
|
||||
espm_settings = espm::Settings("tes5");
|
||||
}
|
||||
else if (Id() == Game::fo3) {
|
||||
espm_settings = espm::Settings("fo3");
|
||||
}
|
||||
else if (Id() == Game::fonv) {
|
||||
espm_settings = espm::Settings("fonv");
|
||||
}
|
||||
}
|
||||
Game::Game(const unsigned int gameCode, const std::string& folder) : GameSettings(gameCode, folder), gh(nullptr) {}
|
||||
|
||||
Game::~Game() {
|
||||
lo_destroy_handle(gh);
|
||||
|
||||
+1
-5
@@ -40,7 +40,6 @@
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
#include <api/libloadorder.h>
|
||||
#include <src/libespm.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace loot {
|
||||
@@ -62,12 +61,11 @@ namespace loot {
|
||||
void GetLoadOrder(std::list<std::string>& loadOrder) const;
|
||||
void SetLoadOrder(const std::list<std::string>& loadOrder) const; //Modifies game load order, even though const.
|
||||
void SetLoadOrder(const char * const * const loadOrder, const size_t numPlugins) const; // For API.
|
||||
|
||||
void RefreshActivePluginsList();
|
||||
void RedatePlugins(); //Change timestamps to match load order (Skyrim only).
|
||||
|
||||
void LoadPlugins(bool headersOnly); //Loads all installed plugins.
|
||||
bool HasBeenLoaded(); // Checks if the game's plugins have already been loaded.
|
||||
|
||||
std::list<Plugin> Sort(const unsigned int language, std::function<void(const std::string&)> progressCallback);
|
||||
|
||||
//Caches for condition results, active plugins and CRCs.
|
||||
@@ -79,8 +77,6 @@ namespace loot {
|
||||
Masterlist masterlist;
|
||||
MetadataList userlist;
|
||||
std::unordered_map<std::string, Plugin> plugins; //Map so that plugin data can be edited.
|
||||
|
||||
espm::Settings espm_settings;
|
||||
private:
|
||||
boost::filesystem::path _gameLocalDataPath; // Path to the game's folder in %LOCALAPPDATA%.
|
||||
|
||||
|
||||
+18
-71
@@ -23,11 +23,10 @@
|
||||
*/
|
||||
|
||||
#include "plugin.h"
|
||||
#include "plugin_loader.h"
|
||||
#include "game.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <src/libespm.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
@@ -42,71 +41,34 @@ using boost::regex_search;
|
||||
using boost::smatch;
|
||||
|
||||
namespace loot {
|
||||
Plugin::Plugin() : PluginMetadata(), isMaster(false), crc(0), numOverrideRecords(0) {}
|
||||
Plugin::Plugin() : PluginMetadata(), _isEmpty(true), isMaster(false), crc(0), numOverrideRecords(0) {}
|
||||
|
||||
Plugin::Plugin(const std::string& n) : PluginMetadata(n), isMaster(false), crc(0), numOverrideRecords(0) {}
|
||||
Plugin::Plugin(const std::string& n) : PluginMetadata(n), _isEmpty(true), isMaster(false), crc(0), numOverrideRecords(0) {}
|
||||
|
||||
Plugin::Plugin(loot::Game& game, const std::string& n, const bool headerOnly)
|
||||
: PluginMetadata(n), isMaster(false), crc(0), numOverrideRecords(0) {
|
||||
// Get data from file contents using libespm. Assumes libespm has already been initialised.
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Opening with libespm...";
|
||||
boost::filesystem::path filepath = game.DataPath() / name;
|
||||
|
||||
//In case the plugin is ghosted.
|
||||
if (!boost::filesystem::exists(filepath) && boost::filesystem::exists(filepath.string() + ".ghost"))
|
||||
filepath += ".ghost";
|
||||
|
||||
espm::File * file = nullptr;
|
||||
: PluginMetadata(n), _isEmpty(true), isMaster(false), crc(0), numOverrideRecords(0) {
|
||||
try {
|
||||
if (game.Id() == Game::tes4)
|
||||
file = new espm::tes4::File(filepath, game.espm_settings, false, headerOnly);
|
||||
else if (game.Id() == Game::tes5)
|
||||
file = new espm::tes5::File(filepath, game.espm_settings, false, headerOnly);
|
||||
else if (game.Id() == Game::fo3)
|
||||
file = new espm::fo3::File(filepath, game.espm_settings, false, headerOnly);
|
||||
else
|
||||
file = new espm::fonv::File(filepath, game.espm_settings, false, headerOnly);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Checking master flag.";
|
||||
isMaster = file->isMaster(game.espm_settings);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Getting masters.";
|
||||
for (const auto& master : file->getMasters()) {
|
||||
masters.push_back(boost::locale::conv::to_utf<char>(master, "Windows-1252", boost::locale::conv::stop));
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Number of masters: " << masters.size();
|
||||
PluginLoader loader;
|
||||
loader.Load(game, name, headerOnly, false);
|
||||
isMaster = loader.IsMaster();
|
||||
masters = loader.Masters();
|
||||
_isEmpty = loader.IsEmpty();
|
||||
formIDs.insert(loader.FormIDs().begin(), loader.FormIDs().end());
|
||||
|
||||
if (!headerOnly) {
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Getting CRC.";
|
||||
crc = file->crc;
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": Caching CRC value.";
|
||||
crc = loader.Crc();
|
||||
game.crcCache.insert(pair<string, uint32_t>(boost::locale::to_lower(name), crc));
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Getting the FormIDs.";
|
||||
vector<uint32_t> records = file->getFormIDs();
|
||||
vector<string> plugins = masters;
|
||||
plugins.push_back(name);
|
||||
for (const auto &record : records) {
|
||||
FormID fid = FormID(plugins, record);
|
||||
formIDs.insert(fid);
|
||||
if (!boost::iequals(fid.Plugin(), name))
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": Counting override FormIDs.";
|
||||
for (const auto& formID : formIDs) {
|
||||
if (!boost::iequals(formID.Plugin(), name))
|
||||
++numOverrideRecords;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Checking if plugin is empty.";
|
||||
if (headerOnly) {
|
||||
// Check the header records count.
|
||||
_isEmpty = file->getNumRecords() == 0;
|
||||
}
|
||||
else {
|
||||
_isEmpty = formIDs.empty();
|
||||
}
|
||||
|
||||
//Also read Bash Tags applied and version string in description.
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Reading the description.";
|
||||
string text = boost::locale::conv::to_utf<char>(file->getDescription(), "Windows-1252", boost::locale::conv::stop);
|
||||
|
||||
string text = loader.Description();
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Attempting to read the version from the description.";
|
||||
for (size_t i = 0; i < version_checks.size(); ++i) {
|
||||
smatch what;
|
||||
@@ -139,7 +101,6 @@ namespace loot {
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
delete file;
|
||||
BOOST_LOG_TRIVIAL(error) << "Cannot read plugin file \"" << name << "\". Details: " << e.what();
|
||||
messages.push_back(loot::Message(loot::Message::error, (boost::format(boost::locale::translate("Cannot read \"%1%\". Details: %2%")) % name % e.what()).str()));
|
||||
}
|
||||
@@ -222,22 +183,8 @@ namespace loot {
|
||||
}
|
||||
|
||||
try {
|
||||
boost::filesystem::path filepath = game.DataPath() / name;
|
||||
//In case the plugin is ghosted.
|
||||
if (!boost::filesystem::exists(filepath) && boost::filesystem::exists(filepath.string() + ".ghost"))
|
||||
filepath += ".ghost";
|
||||
|
||||
espm::File * file = nullptr;
|
||||
if (game.Id() == Game::tes4)
|
||||
file = new espm::tes4::File(filepath, game.espm_settings, false, true);
|
||||
else if (game.Id() == Game::tes5)
|
||||
file = new espm::tes5::File(filepath, game.espm_settings, false, true);
|
||||
else if (game.Id() == Game::fo3)
|
||||
file = new espm::fo3::File(filepath, game.espm_settings, false, true);
|
||||
else
|
||||
file = new espm::fonv::File(filepath, game.espm_settings, false, true);
|
||||
|
||||
delete file;
|
||||
PluginLoader loader;
|
||||
return loader.Load(game, name, true, true);
|
||||
}
|
||||
catch (std::exception& /*e*/) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "The .es(p|m) file \"" << name << "\" is not a valid plugin.";
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2015 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "plugin_loader.h"
|
||||
#include "game.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include <src/libespm.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace loot {
|
||||
PluginLoader::PluginLoader() : _isMaster(false), _crc(0) {}
|
||||
|
||||
bool PluginLoader::Load(const Game& game, const std::string& name, const bool headerOnly, const bool checkValidityOnly) {
|
||||
espm::File * file = nullptr;
|
||||
espm::Settings espmSettings;
|
||||
|
||||
// Get data from file contents using libespm.
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Opening with libespm...";
|
||||
boost::filesystem::path filepath = game.DataPath() / name;
|
||||
|
||||
//In case the plugin is ghosted.
|
||||
if (!boost::filesystem::exists(filepath) && boost::filesystem::exists(filepath.string() + ".ghost"))
|
||||
filepath += ".ghost";
|
||||
|
||||
try {
|
||||
if (game.Id() == Game::tes4) {
|
||||
espmSettings = espm::Settings("tes4");
|
||||
file = new espm::tes4::File(filepath, espmSettings, false, headerOnly);
|
||||
}
|
||||
else if (game.Id() == Game::tes5) {
|
||||
espmSettings = espm::Settings("tes5");
|
||||
file = new espm::tes5::File(filepath, espmSettings, false, headerOnly);
|
||||
}
|
||||
else if (game.Id() == Game::fo3) {
|
||||
espmSettings = espm::Settings("fo3");
|
||||
file = new espm::fo3::File(filepath, espmSettings, false, headerOnly);
|
||||
}
|
||||
else {
|
||||
espmSettings = espm::Settings("fonv");
|
||||
file = new espm::fonv::File(filepath, espmSettings, false, headerOnly);
|
||||
}
|
||||
|
||||
// If only wanting to test for valid parsing, quit now.
|
||||
if (checkValidityOnly) {
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << filepath.filename() << ": " << "Checking master flag.";
|
||||
_isMaster = file->isMaster(espmSettings);
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << filepath.filename() << ": " << "Getting masters.";
|
||||
for (const auto& master : file->getMasters()) {
|
||||
_masters.push_back(boost::locale::conv::to_utf<char>(master, "Windows-1252", boost::locale::conv::stop));
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << filepath.filename() << ": " << "Number of masters: " << _masters.size();
|
||||
|
||||
if (!headerOnly) {
|
||||
BOOST_LOG_TRIVIAL(trace) << filepath.filename() << ": " << "Getting CRC.";
|
||||
_crc = file->crc;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Getting the FormIDs.";
|
||||
vector<uint32_t> records = file->getFormIDs();
|
||||
vector<string> plugins = _masters;
|
||||
plugins.push_back(name);
|
||||
for (const auto &record : records) {
|
||||
_formIDs.insert(FormID(plugins, record));
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Checking if plugin is empty.";
|
||||
if (headerOnly) {
|
||||
// Check the header records count.
|
||||
_isEmpty = file->getNumRecords() == 0;
|
||||
}
|
||||
else {
|
||||
_isEmpty = _formIDs.empty();
|
||||
}
|
||||
|
||||
//Also read Bash Tags applied and version string in description.
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Reading the description.";
|
||||
_description = boost::locale::conv::to_utf<char>(file->getDescription(), "Windows-1252", boost::locale::conv::stop);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
delete file;
|
||||
throw;
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(trace) << name << ": " << "Plugin loading complete.";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PluginLoader::IsEmpty() const {
|
||||
return _isEmpty;
|
||||
}
|
||||
|
||||
bool PluginLoader::IsMaster() const {
|
||||
return _isMaster;
|
||||
}
|
||||
|
||||
const std::set<FormID>& PluginLoader::FormIDs() const {
|
||||
return _formIDs;
|
||||
}
|
||||
|
||||
std::vector<std::string> PluginLoader::Masters() const {
|
||||
return _masters;
|
||||
}
|
||||
|
||||
std::string PluginLoader::Description() const {
|
||||
return _description;
|
||||
}
|
||||
|
||||
uint32_t PluginLoader::Crc() const {
|
||||
return _crc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2012-2015 WrinklyNinja
|
||||
|
||||
This file is part of LOOT.
|
||||
|
||||
LOOT is free software: you can redistribute
|
||||
it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation, either version 3 of
|
||||
the License, or (at your option) any later version.
|
||||
|
||||
LOOT is distributed in the hope that it will
|
||||
be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with LOOT. If not, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __LOOT_PLUGIN_LOADER__
|
||||
#define __LOOT_PLUGIN_LOADER__
|
||||
|
||||
#include "metadata/formid.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace loot {
|
||||
class Game;
|
||||
|
||||
class PluginLoader {
|
||||
public:
|
||||
PluginLoader();
|
||||
|
||||
bool Load(const Game& game, const std::string& name, const bool headerOnly, const bool checkValidityOnly);
|
||||
|
||||
bool IsEmpty() const;
|
||||
bool IsMaster() const; //Checks master bit flag.
|
||||
const std::set<FormID>& FormIDs() const;
|
||||
std::vector<std::string> Masters() const;
|
||||
std::string Description() const;
|
||||
uint32_t Crc() const;
|
||||
private:
|
||||
bool _isEmpty;
|
||||
bool _isMaster;
|
||||
std::set<FormID> _formIDs;
|
||||
std::vector<std::string> _masters;
|
||||
std::string _description;
|
||||
uint32_t _crc;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user