mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Some refactoring of Javascript callbacks.
Also changed settings file to use javascript-friendly key names.
This commit is contained in:
@@ -624,87 +624,113 @@ function setupEventHandlers() {
|
||||
|
||||
document.body.addEventListener('mouseover', toggleHoverText, false);
|
||||
}
|
||||
function initUI() {
|
||||
if (typeof loot == 'undefined') {
|
||||
console.log('loot is not defined.');
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('LOOTVersion').textContent = loot.version;
|
||||
/* Fill in languages, games, settings values. */
|
||||
|
||||
/* Fill in game row template's game type options. */
|
||||
var select = document.getElementById('gameRow').content.querySelector('select');
|
||||
for (var j = 0; j < loot.gameTypes.length; ++j) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.gameTypes[j];
|
||||
option.textContent = loot.gameTypes[j];
|
||||
select.appendChild(option);
|
||||
}
|
||||
|
||||
/* Now fill game lists/table. */
|
||||
var gameSelect = document.getElementById('defaultGameSelect');
|
||||
var gameMenu = document.getElementById('gameMenu').firstElementChild;
|
||||
var gameTableBody = document.getElementById('gameTable').getElementsByTagName('tbody')[0];
|
||||
/* Add "auto" value for default game. */
|
||||
var option = document.createElement('option');
|
||||
option.value = 'auto';
|
||||
option.textContent = 'Autodetect';
|
||||
gameSelect.appendChild(option);
|
||||
/* Add row for creating new rows. */
|
||||
setupTable(gameTableBody);
|
||||
for (var i = 0; i < loot.settings.games.length; ++i) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.settings.games[i].folder;
|
||||
option.textContent = loot.settings.games[i].name;
|
||||
gameSelect.appendChild(option);
|
||||
|
||||
var li = document.createElement('li');
|
||||
li.setAttribute('data-action', 'change-game');
|
||||
li.setAttribute('data-target', loot.settings.games[i].folder);
|
||||
li.textContent = loot.settings.games[i].name;
|
||||
gameMenu.appendChild(li);
|
||||
|
||||
addTableRow(gameTableBody, loot.settings.games[i]);
|
||||
}
|
||||
|
||||
/* Now fill in language options. */
|
||||
var settingsLangSelect = document.getElementById('languageSelect');
|
||||
var messageLangSelect = document.getElementById('messageRow').content.querySelector('.language');
|
||||
for (var i = 0; i < loot.languages.length; ++i) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.languages[i];
|
||||
option.textContent = loot.languages[i];
|
||||
settingsLangSelect.appendChild(option);
|
||||
messageLangSelect.appendChild(option.cloneNode(true));
|
||||
}
|
||||
|
||||
/* Now fill in settings values. */
|
||||
gameSelect.value = loot.settings.game;
|
||||
settingsLangSelect.value = loot.settings.language;
|
||||
debugVerbositySelect.value = loot.settings.debugVerbosity;
|
||||
function processCefError(errorCode, errorMessage) {
|
||||
showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message);
|
||||
}
|
||||
function initGlobalVars() {
|
||||
// Create and send a new query.
|
||||
var request_id = window.cefQuery({
|
||||
request: 'initGlobalVars',
|
||||
request: 'getVersion',
|
||||
persistent: false,
|
||||
onSuccess: function(response) {
|
||||
try {
|
||||
var temp = JSON.parse(response);
|
||||
loot.version = temp.version;
|
||||
loot.settings = temp.settings;
|
||||
loot.gameTypes = temp.gameTypes;
|
||||
loot.languages = temp.languages;
|
||||
loot.version = JSON.parse(response);
|
||||
|
||||
document.getElementById('LOOTVersion').textContent = loot.version;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
}
|
||||
initUI();
|
||||
},
|
||||
onFailure: function(error_code, error_message) {
|
||||
showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message);
|
||||
}
|
||||
onFailure: processCefError
|
||||
});
|
||||
var request_id = window.cefQuery({
|
||||
request: 'getLanguages',
|
||||
persistent: false,
|
||||
onSuccess: function(response) {
|
||||
try {
|
||||
loot.languages = JSON.parse(response);
|
||||
|
||||
/* Now fill in language options. */
|
||||
var settingsLangSelect = document.getElementById('languageSelect');
|
||||
var messageLangSelect = document.getElementById('messageRow').content.querySelector('.language');
|
||||
for (var i = 0; i < loot.languages.length; ++i) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.languages[i].locale;
|
||||
option.textContent = loot.languages[i].name;
|
||||
settingsLangSelect.appendChild(option);
|
||||
messageLangSelect.appendChild(option.cloneNode(true));
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
}
|
||||
},
|
||||
onFailure: processCefError
|
||||
});
|
||||
var request_id = window.cefQuery({
|
||||
request: 'getGameTypes',
|
||||
persistent: false,
|
||||
onSuccess: function(response) {
|
||||
try {
|
||||
loot.gameTypes = JSON.parse(response);
|
||||
|
||||
/* Fill in game row template's game type options. */
|
||||
var select = document.getElementById('gameRow').content.querySelector('select');
|
||||
for (var j = 0; j < loot.gameTypes.length; ++j) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.gameTypes[j];
|
||||
option.textContent = loot.gameTypes[j];
|
||||
select.appendChild(option);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
}
|
||||
|
||||
// Settings depend on having the game types filled, so now send the CEF query for the settings.
|
||||
var request_id = window.cefQuery({
|
||||
request: 'getSettings',
|
||||
persistent: false,
|
||||
onSuccess: function(response) {
|
||||
try {
|
||||
loot.settings = JSON.parse(response);
|
||||
|
||||
|
||||
/* Now fill game lists/table. */
|
||||
var gameSelect = document.getElementById('defaultGameSelect');
|
||||
var gameMenu = document.getElementById('gameMenu').firstElementChild;
|
||||
var gameTableBody = document.getElementById('gameTable').getElementsByTagName('tbody')[0];
|
||||
/* Add row for creating new rows. */
|
||||
setupTable(gameTableBody);
|
||||
for (var i = 0; i < loot.settings.games.length; ++i) {
|
||||
var option = document.createElement('option');
|
||||
option.value = loot.settings.games[i].folder;
|
||||
option.textContent = loot.settings.games[i].name;
|
||||
gameSelect.appendChild(option);
|
||||
|
||||
var li = document.createElement('li');
|
||||
li.setAttribute('data-action', 'change-game');
|
||||
li.setAttribute('data-target', loot.settings.games[i].folder);
|
||||
li.textContent = loot.settings.games[i].name;
|
||||
gameMenu.appendChild(li);
|
||||
|
||||
addTableRow(gameTableBody, loot.settings.games[i]);
|
||||
}
|
||||
|
||||
gameSelect.value = loot.settings.game;
|
||||
document.getElementById('languageSelect').value = loot.settings.language;
|
||||
document.getElementById('debugVerbositySelect').value = loot.settings.debugVerbosity;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
}
|
||||
|
||||
},
|
||||
onFailure: processCefError
|
||||
});
|
||||
},
|
||||
onFailure: processCefError
|
||||
});
|
||||
}
|
||||
function updateInterfaceWithGameInfo(response) {
|
||||
@@ -860,10 +886,10 @@ function updateInterfaceWithGameInfo(response) {
|
||||
// Now set up event handlers, as they depend on the plugin cards having been created.
|
||||
setupEventHandlers();
|
||||
}
|
||||
function initGameVars() {
|
||||
function getGameData() {
|
||||
// Create and send a new query.
|
||||
var request_id = window.cefQuery({
|
||||
request: 'initGameVars',
|
||||
request: 'getGameData',
|
||||
persistent: false,
|
||||
onSuccess: updateInterfaceWithGameInfo,
|
||||
onFailure: function(error_code, error_message) {
|
||||
@@ -873,7 +899,7 @@ function initGameVars() {
|
||||
}
|
||||
|
||||
initGlobalVars();
|
||||
initGameVars();
|
||||
getGameData();
|
||||
if (isStorageSupported()) {
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
@@ -283,6 +283,7 @@ along with LOOT. If not, see <http://www.gnu.org/licenses/>.
|
||||
<h1>Settings</h1>
|
||||
<label for="defaultGameSelect">Default Game</label>
|
||||
<select id="defaultGameSelect">
|
||||
<option value="auto">Autodetect</option>
|
||||
<!-- Game <option> elements go here. -->
|
||||
</select><br>
|
||||
<label for="languageSelect">Language</label>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# Example Default LOOT Settings File
|
||||
# This file is written in YAML <http://www.yaml.org/>.
|
||||
|
||||
Language: eng # One of 'eng', 'spa', 'rus' or ''.
|
||||
language: eng # One of 'eng', 'spa', 'rus' or ''.
|
||||
|
||||
Game: auto # auto, or one of the 'folder' values below.
|
||||
Last Game: auto # auto, or one of the 'folder' values below.
|
||||
Debug Verbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0.
|
||||
Update Masterlist: true
|
||||
game: auto # auto, or one of the 'folder' values below.
|
||||
lastGame: auto # auto, or one of the 'folder' values below.
|
||||
debugVerbosity: 0 # 0, 1, 2, 3. Logging takes place if > 0.
|
||||
updateMasterlist: true
|
||||
|
||||
# Games. The four types are 'Oblivion', 'Skyrim', 'Fallout3' and 'FalloutNV'. They correspond to each base game's libespm and libloadorder settings.
|
||||
Games:
|
||||
games:
|
||||
- folder: Oblivion
|
||||
name: "TES IV: Oblivion"
|
||||
type: Oblivion
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace loot {
|
||||
std::vector<Game> GetGames(const YAML::Node& settings) {
|
||||
vector<Game> games;
|
||||
|
||||
if (settings["Games"])
|
||||
games = settings["Games"].as< vector<Game> >();
|
||||
if (settings["games"])
|
||||
games = settings["games"].as< vector<Game> >();
|
||||
|
||||
if (find(games.begin(), games.end(), Game(Game::tes4)) == games.end())
|
||||
games.push_back(Game(Game::tes4));
|
||||
@@ -66,10 +66,10 @@ namespace loot {
|
||||
string preferredGame(cmdLineGame);
|
||||
if (preferredGame.empty()) {
|
||||
// Get preferred game from settings.
|
||||
if (settings["Game"] && settings["Game"].as<string>() != "auto")
|
||||
preferredGame = settings["Game"].as<string>();
|
||||
else if (settings["Last Game"] && settings["Last Game"].as<string>() != "auto")
|
||||
preferredGame = settings["Last Game"].as<string>();
|
||||
if (settings["game"] && settings["game"].as<string>() != "auto")
|
||||
preferredGame = settings["game"].as<string>();
|
||||
else if (settings["lastGame"] && settings["lastGame"].as<string>() != "auto")
|
||||
preferredGame = settings["lastGame"].as<string>();
|
||||
}
|
||||
|
||||
// Get index of preferred game if there is one.
|
||||
|
||||
@@ -412,11 +412,11 @@ namespace loot {
|
||||
YAML::Node root;
|
||||
std::vector<Game> games;
|
||||
|
||||
root["Language"] = "en";
|
||||
root["Game"] = "auto";
|
||||
root["Last Game"] = "auto";
|
||||
root["Debug Verbosity"] = 0;
|
||||
root["Update Masterlist"] = true;
|
||||
root["language"] = "en";
|
||||
root["game"] = "auto";
|
||||
root["lastGame"] = "auto";
|
||||
root["debugVerbosity"] = 0;
|
||||
root["updateMasterlist"] = true;
|
||||
|
||||
games.push_back(Game(Game::tes4));
|
||||
games.push_back(Game(Game::tes5));
|
||||
@@ -424,7 +424,7 @@ namespace loot {
|
||||
games.push_back(Game(Game::fonv));
|
||||
games.push_back(Game(Game::tes4, "Nehrim").SetDetails("Nehrim - At Fate's Edge", "Nehrim.esm", "https://github.com/loot/oblivion.git", "master", "", "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Nehrim - At Fate's Edge_is1\\InstallLocation"));
|
||||
|
||||
root["Games"] = games;
|
||||
root["games"] = games;
|
||||
|
||||
//Save settings.
|
||||
YAML::Emitter yout;
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ namespace loot {
|
||||
return YAML::Load(json);
|
||||
}
|
||||
|
||||
inline static std::string stringify(YAML::Node& yaml) {
|
||||
inline static std::string stringify(const YAML::Node& yaml) {
|
||||
|
||||
YAML::Emitter out;
|
||||
out.SetOutputCharset(YAML::EscapeNonAscii);
|
||||
|
||||
+11
-4
@@ -170,8 +170,8 @@ namespace loot {
|
||||
);
|
||||
boost::log::add_common_attributes();
|
||||
unsigned int verbosity;
|
||||
if (_settings["Debug Verbosity"]) {
|
||||
verbosity = _settings["Debug Verbosity"].as<unsigned int>();
|
||||
if (_settings["debugVerbosity"]) {
|
||||
verbosity = _settings["debugVerbosity"].as<unsigned int>();
|
||||
}
|
||||
if (verbosity == 0)
|
||||
boost::log::core::get()->set_logging_enabled(false);
|
||||
@@ -191,8 +191,8 @@ namespace loot {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Initialising language settings.";
|
||||
//Defaults in case language string is empty or setting is missing.
|
||||
string localeId = loot::Language(loot::Language::any).Locale() + ".UTF-8";
|
||||
if (_settings["Language"]) {
|
||||
loot::Language lang(_settings["Language"].as<string>());
|
||||
if (_settings["language"]) {
|
||||
loot::Language lang(_settings["language"].as<string>());
|
||||
BOOST_LOG_TRIVIAL(debug) << "Selected language: " << lang.Name();
|
||||
localeId = lang.Locale() + ".UTF-8";
|
||||
}
|
||||
@@ -249,4 +249,11 @@ namespace loot {
|
||||
Game& LootState::CurrentGame() {
|
||||
return _games[_currentGame];
|
||||
}
|
||||
|
||||
const YAML::Node& LootState::GetSettings() const {
|
||||
return _settings;
|
||||
}
|
||||
const YAML::Node& LootState::GetSetting(const std::string& setting) const {
|
||||
return _settings[setting];
|
||||
}
|
||||
}
|
||||
@@ -75,8 +75,13 @@ namespace loot {
|
||||
LootState();
|
||||
|
||||
void Init(const std::string& cmdLineGame);
|
||||
|
||||
Game& CurrentGame();
|
||||
|
||||
const YAML::Node& GetSettings() const;
|
||||
const YAML::Node& GetSetting(const std::string& setting) const;
|
||||
|
||||
private:
|
||||
YAML::Node _settings;
|
||||
std::vector<loot::Game> _games;
|
||||
size_t _currentGame;
|
||||
|
||||
+177
-160
@@ -69,179 +69,196 @@ namespace loot {
|
||||
CefRefPtr<Callback> callback) {
|
||||
|
||||
if (request == "openReadme") {
|
||||
// Open readme in default application.
|
||||
HINSTANCE ret = ShellExecute(0, NULL, ToWinWide(ToFileURL(g_path_readme)).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
if ((int)ret > 32)
|
||||
callback->Success(request);
|
||||
else
|
||||
callback->Failure((int)ret, "Shell execute failed.");
|
||||
try {
|
||||
OpenReadme();
|
||||
callback->Success("");
|
||||
}
|
||||
catch (error &e) {
|
||||
callback->Failure(e.code(), e.what());
|
||||
}
|
||||
catch (exception &e) {
|
||||
callback->Failure(-1, e.what());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if (request == "openLogLocation") {
|
||||
//Open debug log folder.
|
||||
HINSTANCE ret = ShellExecute(NULL, L"open", ToWinWide(g_path_log.parent_path().string()).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
if ((int)ret > 32)
|
||||
callback->Success(request);
|
||||
else
|
||||
callback->Failure((int)ret, "Shell execute failed.");
|
||||
return true;
|
||||
}
|
||||
else if (request == "initGlobalVars") {
|
||||
// Convert the _settings YAML object to a JSON string, and also add members for the LOOT version, game types and languages.
|
||||
|
||||
if (g_app_state._games.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Application state not yet initialised, initialising now...";
|
||||
g_app_state.Init("");
|
||||
BOOST_LOG_TRIVIAL(info) << "Application state initialised.";
|
||||
}
|
||||
|
||||
YAML::Node temp;
|
||||
|
||||
// LOOT Version
|
||||
//-------------
|
||||
|
||||
temp["version"] = to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch);
|
||||
|
||||
// LOOT Settings
|
||||
//--------------
|
||||
|
||||
//temp["settings"] = g_app_state._settings;
|
||||
|
||||
// Do a bit of translation of key names into more javascript-friendly names.
|
||||
// Consider instead making the settings file use the more friendly names itself.
|
||||
|
||||
temp["settings"]["debugVerbosity"] = g_app_state._settings["Debug Verbosity"];
|
||||
temp["settings"]["game"] = g_app_state._settings["Game"];
|
||||
temp["settings"]["games"] = g_app_state._settings["Games"];
|
||||
temp["settings"]["language"] = Language(g_app_state._settings["Language"].as<string>()).Name();
|
||||
temp["settings"]["lastGame"] = g_app_state._settings["Last Game"];
|
||||
|
||||
// LOOT Game Types
|
||||
//-----------------
|
||||
|
||||
vector<string> gameTypes;
|
||||
gameTypes.push_back(Game(Game::tes4).FolderName());
|
||||
gameTypes.push_back(Game(Game::tes5).FolderName());
|
||||
gameTypes.push_back(Game(Game::fo3).FolderName());
|
||||
gameTypes.push_back(Game(Game::fonv).FolderName());
|
||||
|
||||
temp["gameTypes"] = gameTypes;
|
||||
|
||||
// LOOT Languages
|
||||
//---------------
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Setting GUI values for LOOT's languages.";
|
||||
|
||||
temp["languages"] = Language::Names();
|
||||
|
||||
// Now output as JSON
|
||||
//-------------------
|
||||
|
||||
callback->Success(JSON::stringify(temp));
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (request == "initGameVars") {
|
||||
// Get masterlist revision info and parse if it exists. Also get plugin headers info and parse userlist if it exists.
|
||||
|
||||
if (g_app_state._games.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Application state not yet initialised, initialising now...";
|
||||
g_app_state.Init("");
|
||||
BOOST_LOG_TRIVIAL(info) << "Application state initialised.";
|
||||
}
|
||||
|
||||
g_app_state.CurrentGame().LoadPlugins(true);
|
||||
|
||||
//Sort plugins into their load order.
|
||||
list<loot::Plugin> installed;
|
||||
list<string> loadOrder;
|
||||
g_app_state.CurrentGame().GetLoadOrder(loadOrder);
|
||||
for (const auto &pluginName : loadOrder) {
|
||||
const auto pos = g_app_state.CurrentGame().plugins.find(pluginName);
|
||||
|
||||
if (pos != g_app_state.CurrentGame().plugins.end())
|
||||
installed.push_back(pos->second);
|
||||
}
|
||||
|
||||
//Parse masterlist, don't update it.
|
||||
if (fs::exists(g_app_state.CurrentGame().MasterlistPath())) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist.";
|
||||
g_app_state.CurrentGame().masterlist.MetadataList::Load(g_app_state.CurrentGame().MasterlistPath());
|
||||
}
|
||||
|
||||
//Parse userlist.
|
||||
if (fs::exists(g_app_state.CurrentGame().UserlistPath())) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing userlist.";
|
||||
g_app_state.CurrentGame().userlist.Load(g_app_state.CurrentGame().UserlistPath());
|
||||
}
|
||||
|
||||
// Now convert to a single object that can be turned into a JSON string
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// The data structure is to be set as 'loot.game'.
|
||||
YAML::Node gameNode;
|
||||
|
||||
// ID the game using its folder value.
|
||||
gameNode["folder"] = g_app_state.CurrentGame().FolderName();
|
||||
|
||||
// Store the masterlist revision and date.
|
||||
gameNode["masterlist"]["revision"] = g_app_state.CurrentGame().masterlist.GetRevision(g_app_state.CurrentGame().MasterlistPath());
|
||||
gameNode["masterlist"]["date"] = g_app_state.CurrentGame().masterlist.GetDate(g_app_state.CurrentGame().MasterlistPath());
|
||||
|
||||
// Now store plugin data.
|
||||
for (const auto& plugin : g_app_state.CurrentGame().plugins) {
|
||||
// Test data has 'hasUserEdits', and 'tagsAdd', 'tagsRemove' keys, but
|
||||
// the first will be handled by userlist lookups, and the other two are probably
|
||||
// going to get moved around, haven't decided how best to handle the split between masterlist, userlist and plugin-sourced metadata.
|
||||
YAML::Node pluginNode;
|
||||
pluginNode["name"] = plugin.second.Name();
|
||||
pluginNode["isActive"] = g_app_state.CurrentGame().IsActive(plugin.first);
|
||||
pluginNode["isDummy"] = (plugin.second.FormIDs().size() == 0);
|
||||
pluginNode["loadsBSA"] = plugin.second.LoadsBSA(g_app_state.CurrentGame());
|
||||
pluginNode["crc"] = IntToHexString(plugin.second.Crc());
|
||||
pluginNode["version"] = plugin.second.Version();
|
||||
|
||||
gameNode["plugins"].push_back(pluginNode);
|
||||
}
|
||||
|
||||
//Set language.
|
||||
unsigned int language;
|
||||
if (g_app_state._settings["Language"])
|
||||
language = Language(g_app_state._settings["Language"].as<string>()).Code();
|
||||
else
|
||||
language = loot::Language::any;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
|
||||
|
||||
//Evaluate any conditions in the global messages.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
|
||||
try {
|
||||
list<loot::Message>::iterator it = g_app_state.CurrentGame().masterlist.messages.begin();
|
||||
while (it != g_app_state.CurrentGame().masterlist.messages.end()) {
|
||||
if (!it->EvalCondition(g_app_state.CurrentGame(), language))
|
||||
it = g_app_state.CurrentGame().masterlist.messages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
OpenLogLocation();
|
||||
callback->Success("");
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
|
||||
g_app_state.CurrentGame().masterlist.messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
|
||||
catch (error &e) {
|
||||
callback->Failure(e.code(), e.what());
|
||||
}
|
||||
catch (exception &e) {
|
||||
callback->Failure(-1, e.what());
|
||||
}
|
||||
|
||||
// Now store global messages from masterlist.
|
||||
gameNode["globalMessages"] = g_app_state.CurrentGame().masterlist.messages;
|
||||
|
||||
callback->Success(JSON::stringify(gameNode));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (request == "getVersion") {
|
||||
callback->Success(GetVersion());
|
||||
return true;
|
||||
}
|
||||
else if (request == "getSettings") {
|
||||
callback->Success(GetSettings());
|
||||
return true;
|
||||
}
|
||||
else if (request == "getLanguages") {
|
||||
callback->Success(GetLanguages());
|
||||
return true;
|
||||
}
|
||||
else if (request == "getGameTypes") {
|
||||
callback->Success(GetGameTypes());
|
||||
return true;
|
||||
}
|
||||
else if (request == "getGameData") {
|
||||
callback->Success(GetGameData());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Handler::OpenReadme() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Opening LOOT readme.";
|
||||
// Open readme in default application.
|
||||
HINSTANCE ret = ShellExecute(0, NULL, ToWinWide(ToFileURL(g_path_readme)).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
if ((int)ret <= 32)
|
||||
throw error(error::windows_error, "Shell execute failed.");
|
||||
}
|
||||
|
||||
void Handler::OpenLogLocation() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Opening LOOT local appdata folder.";
|
||||
//Open debug log folder.
|
||||
HINSTANCE ret = ShellExecute(NULL, L"open", ToWinWide(g_path_log.parent_path().string()).c_str(), NULL, NULL, SW_SHOWNORMAL);
|
||||
if ((int)ret <= 32)
|
||||
throw error(error::windows_error, "Shell execute failed.");
|
||||
}
|
||||
|
||||
std::string Handler::GetVersion() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Getting LOOT version.";
|
||||
YAML::Node version(to_string(g_version_major) + "." + to_string(g_version_minor) + "." + to_string(g_version_patch));
|
||||
return JSON::stringify(version);
|
||||
}
|
||||
|
||||
std::string Handler::GetSettings() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Getting LOOT settings.";
|
||||
return JSON::stringify(g_app_state.GetSettings());
|
||||
}
|
||||
|
||||
std::string Handler::GetLanguages() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Getting LOOT's supported languages.";
|
||||
// Need to get an array of language names and their corresponding codes.
|
||||
YAML::Node temp;
|
||||
vector<string> names = Language::Names();
|
||||
for (const auto& name : names) {
|
||||
YAML::Node lang;
|
||||
lang["name"] = name;
|
||||
lang["locale"] = Language(name).Locale();
|
||||
temp.push_back(lang);
|
||||
}
|
||||
return JSON::stringify(temp);
|
||||
}
|
||||
|
||||
std::string Handler::GetGameTypes() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Getting LOOT's supported game types.";
|
||||
YAML::Node temp;
|
||||
temp.push_back(Game(Game::tes4).FolderName());
|
||||
temp.push_back(Game(Game::tes5).FolderName());
|
||||
temp.push_back(Game(Game::fo3).FolderName());
|
||||
temp.push_back(Game(Game::fonv).FolderName());
|
||||
return JSON::stringify(temp);
|
||||
}
|
||||
|
||||
std::string Handler::GetGameData() {
|
||||
BOOST_LOG_TRIVIAL(info) << "Getting data specific to LOOT's active game.";
|
||||
// Get masterlist revision info and parse if it exists. Also get plugin headers info and parse userlist if it exists.
|
||||
|
||||
g_app_state.CurrentGame().LoadPlugins(true);
|
||||
|
||||
//Sort plugins into their load order.
|
||||
list<loot::Plugin> installed;
|
||||
list<string> loadOrder;
|
||||
g_app_state.CurrentGame().GetLoadOrder(loadOrder);
|
||||
for (const auto &pluginName : loadOrder) {
|
||||
const auto pos = g_app_state.CurrentGame().plugins.find(pluginName);
|
||||
|
||||
if (pos != g_app_state.CurrentGame().plugins.end())
|
||||
installed.push_back(pos->second);
|
||||
}
|
||||
|
||||
//Parse masterlist, don't update it.
|
||||
if (fs::exists(g_app_state.CurrentGame().MasterlistPath())) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing masterlist.";
|
||||
g_app_state.CurrentGame().masterlist.MetadataList::Load(g_app_state.CurrentGame().MasterlistPath());
|
||||
}
|
||||
|
||||
//Parse userlist.
|
||||
if (fs::exists(g_app_state.CurrentGame().UserlistPath())) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "Parsing userlist.";
|
||||
g_app_state.CurrentGame().userlist.Load(g_app_state.CurrentGame().UserlistPath());
|
||||
}
|
||||
|
||||
// Now convert to a single object that can be turned into a JSON string
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
// The data structure is to be set as 'loot.game'.
|
||||
YAML::Node gameNode;
|
||||
|
||||
// ID the game using its folder value.
|
||||
gameNode["folder"] = g_app_state.CurrentGame().FolderName();
|
||||
|
||||
// Store the masterlist revision and date.
|
||||
gameNode["masterlist"]["revision"] = g_app_state.CurrentGame().masterlist.GetRevision(g_app_state.CurrentGame().MasterlistPath());
|
||||
gameNode["masterlist"]["date"] = g_app_state.CurrentGame().masterlist.GetDate(g_app_state.CurrentGame().MasterlistPath());
|
||||
|
||||
// Now store plugin data.
|
||||
for (const auto& plugin : g_app_state.CurrentGame().plugins) {
|
||||
// Test data has 'hasUserEdits', and 'tagsAdd', 'tagsRemove' keys, but
|
||||
// the first will be handled by userlist lookups, and the other two are probably
|
||||
// going to get moved around, haven't decided how best to handle the split between masterlist, userlist and plugin-sourced metadata.
|
||||
YAML::Node pluginNode;
|
||||
pluginNode["name"] = plugin.second.Name();
|
||||
pluginNode["isActive"] = g_app_state.CurrentGame().IsActive(plugin.first);
|
||||
pluginNode["isDummy"] = (plugin.second.FormIDs().size() == 0);
|
||||
pluginNode["loadsBSA"] = plugin.second.LoadsBSA(g_app_state.CurrentGame());
|
||||
pluginNode["crc"] = IntToHexString(plugin.second.Crc());
|
||||
pluginNode["version"] = plugin.second.Version();
|
||||
|
||||
gameNode["plugins"].push_back(pluginNode);
|
||||
}
|
||||
|
||||
//Set language.
|
||||
unsigned int language;
|
||||
if (g_app_state.GetSetting("language"))
|
||||
language = Language(g_app_state.GetSetting("language").as<string>()).Code();
|
||||
else
|
||||
language = loot::Language::any;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Using message language: " << Language(language).Name();
|
||||
|
||||
//Evaluate any conditions in the global messages.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Evaluating global message conditions.";
|
||||
try {
|
||||
list<loot::Message>::iterator it = g_app_state.CurrentGame().masterlist.messages.begin();
|
||||
while (it != g_app_state.CurrentGame().masterlist.messages.end()) {
|
||||
if (!it->EvalCondition(g_app_state.CurrentGame(), language))
|
||||
it = g_app_state.CurrentGame().masterlist.messages.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "A global message contains a condition that could not be evaluated. Details: " << e.what();
|
||||
g_app_state.CurrentGame().masterlist.messages.push_back(loot::Message(loot::Message::error, (format(loc::translate("A global message contains a condition that could not be evaluated. Details: %1%")) % e.what()).str()));
|
||||
}
|
||||
|
||||
// Now store global messages from masterlist.
|
||||
gameNode["globalMessages"] = g_app_state.CurrentGame().masterlist.messages;
|
||||
|
||||
return JSON::stringify(gameNode);
|
||||
}
|
||||
|
||||
// LootHandler methods
|
||||
//--------------------
|
||||
|
||||
|
||||
@@ -46,6 +46,14 @@ namespace loot {
|
||||
const CefString& request,
|
||||
bool persistent,
|
||||
CefRefPtr<Callback> callback) OVERRIDE;
|
||||
private:
|
||||
void OpenReadme();
|
||||
void OpenLogLocation();
|
||||
std::string GetVersion();
|
||||
std::string GetSettings();
|
||||
std::string GetLanguages();
|
||||
std::string GetGameTypes();
|
||||
std::string GetGameData();
|
||||
};
|
||||
|
||||
class LootHandler : public CefClient,
|
||||
|
||||
@@ -51,14 +51,14 @@ CefSettings GetCefSettings() {
|
||||
|
||||
// Don't set CEF locale, as it tries to load resources and crashes
|
||||
// if they can't be found.
|
||||
/*if (_settings["Language"]) {
|
||||
loot::Language lang(_settings["Language"].as<string>());
|
||||
/*if (_settings["language"]) {
|
||||
loot::Language lang(_settings["language"].as<string>());
|
||||
CefString(&cef_settings.locale).FromString(lang.Locale());
|
||||
}*/
|
||||
|
||||
// Set CEF logging.
|
||||
CefString(&cef_settings.log_file).FromString("CEFDebugLog.txt");
|
||||
/*if (!_settings["Debug Verbosity"] || _settings["Debug Verbosity"].as<unsigned int>() == 0)
|
||||
/*if (!_settings["debugVerbosity"] || _settings["debugVerbosity"].as<unsigned int>() == 0)
|
||||
cef_settings.log_severity = LOGSEVERITY_DISABLE;
|
||||
*/
|
||||
// Enable remote debugging.
|
||||
|
||||
Reference in New Issue
Block a user