mirror of
https://github.com/loot/libloot.git
synced 2026-07-27 14:16:01 -07:00
Partially implemented plugin data generation.
* Created class for easy JSON <-> YAML object conversion. * Deleted test UI data, as it is mostly obsolete. * LOOT now passes some relevant data to the UI. Masterlist & userlist data are not yet passed, and so display of that data is not yet implemented.
This commit is contained in:
+171
-158
@@ -22,6 +22,7 @@
|
||||
<http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
'use strict';
|
||||
var loot = {};
|
||||
function isStorageSupported() {
|
||||
try {
|
||||
return ('localStorage' in window && window['localStorage'] !== null && window['localStorage'] !== undefined);
|
||||
@@ -683,15 +684,18 @@ function initUI() {
|
||||
settingsLangSelect.value = loot.settings.language;
|
||||
debugVerbositySelect.value = loot.settings.debugVerbosity;
|
||||
}
|
||||
var loot;
|
||||
function initJavascriptVars() {
|
||||
function initGlobalVars() {
|
||||
// Create and send a new query.
|
||||
var request_id = window.cefQuery({
|
||||
request: 'initJavascriptVars',
|
||||
request: 'initGlobalVars',
|
||||
persistent: false,
|
||||
onSuccess: function(response) {
|
||||
try {
|
||||
loot = JSON.parse(response);
|
||||
var temp = JSON.parse(response);
|
||||
loot.version = temp.version;
|
||||
loot.settings = temp.settings;
|
||||
loot.gameTypes = temp.gameTypes;
|
||||
loot.languages = temp.languages;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
@@ -703,164 +707,173 @@ function initJavascriptVars() {
|
||||
}
|
||||
});
|
||||
}
|
||||
function processURLParams() {
|
||||
/* Get the data path from the URL and load it. */
|
||||
/*var pos = document.URL.indexOf("?data=");*/
|
||||
var pos = 0;
|
||||
if (pos != -1) {
|
||||
/*var datapath = 'file:///' + document.URL.substring(pos+6);*/
|
||||
var datapath = 'testdata';
|
||||
require([datapath], function(){
|
||||
var totalMessageNo = 0;
|
||||
var warnMessageNo = 0;
|
||||
var errorMessageNo = 0;
|
||||
var activePluginNo = 0;
|
||||
var dirtyPluginNo = 0;
|
||||
/* Fill report with data. */
|
||||
document.getElementById('masterlistRevision').textContent = data.masterlist.revision.substr(0, 9);
|
||||
document.getElementById('masterlistDate').textContent = data.masterlist.date;
|
||||
var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0];
|
||||
for (var i = 0; i < data.globalMessages.length; ++i) {
|
||||
var li = document.createElement('li');
|
||||
li.className = data.globalMessages[i].type;
|
||||
/* innerHTML is open to abuse, but for hyperlinking it's too useful. */
|
||||
li.innerHTML = data.globalMessages[i].content;
|
||||
generalMessagesList.appendChild(li);
|
||||
function updateInterfaceWithGameInfo(response) {
|
||||
|
||||
if (li.className == 'warn') {
|
||||
try {
|
||||
loot.game = JSON.parse(response);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
console.log('Response: ' + response);
|
||||
}
|
||||
|
||||
var totalMessageNo = 0;
|
||||
var warnMessageNo = 0;
|
||||
var errorMessageNo = 0;
|
||||
var activePluginNo = 0;
|
||||
var dirtyPluginNo = 0;
|
||||
|
||||
/* Fill report with data. */
|
||||
document.getElementById('masterlistRevision').textContent = loot.game.masterlist.revision;
|
||||
document.getElementById('masterlistDate').textContent = loot.game.masterlist.date;
|
||||
|
||||
var generalMessagesList = document.getElementById('generalMessages').getElementsByTagName('ul')[0];
|
||||
for (var i = 0; i < loot.game.globalMessages.length; ++i) {
|
||||
var li = document.createElement('li');
|
||||
li.className = loot.game.globalMessages[i].type;
|
||||
/* innerHTML is open to abuse, but for hyperlinking it's too useful. */
|
||||
li.innerHTML = loot.game.globalMessages[i].content[0].str;
|
||||
generalMessagesList.appendChild(li);
|
||||
|
||||
if (li.className == 'warn') {
|
||||
warnMessageNo++;
|
||||
} else if (li.className == 'error') {
|
||||
errorMessageNo++;
|
||||
}
|
||||
}
|
||||
totalMessageNo = loot.game.globalMessages.length;
|
||||
var pluginsList = document.getElementById('main');
|
||||
var pluginsNav = document.getElementById('pluginsNav');
|
||||
for (var i = 0; i < loot.game.plugins.length; ++i) {
|
||||
var content, clone;
|
||||
/* First add link to navbar. */
|
||||
content = document.getElementById('pluginNav').content;
|
||||
clone = document.importNode(content, true);
|
||||
pluginsNav.appendChild(clone);
|
||||
clone = pluginsNav.lastElementChild;
|
||||
|
||||
clone.getElementsByClassName('name')[0].textContent = loot.game.plugins[i].name;
|
||||
clone.getElementsByTagName('a')[0].href = '#' + loot.game.plugins[i].name.replace(/\s+/g, '');
|
||||
//clone.getElementsByClassName('priority')[0].textContent = 'Priority: 500, Global: ✓'; // Or '✗'.
|
||||
|
||||
if (loot.game.plugins[i].isDummy) {
|
||||
clone.getElementsByClassName('dummyPlugin')[0].className += ' fa fa-eye-slash';
|
||||
}
|
||||
|
||||
if (loot.game.plugins[i].loadsBSA) {
|
||||
clone.getElementsByClassName('loadsBSA')[0].className += ' fa fa-paperclip';
|
||||
}
|
||||
|
||||
|
||||
/*// This won't actually be handled anything like this in the real data implementation.
|
||||
if (data.plugins[i].hasUserEdits) {
|
||||
clone.getElementsByClassName('hasUserEdits')[0].className += ' fa fa-user';
|
||||
}*/
|
||||
|
||||
/* Now add plugin 'card'. */
|
||||
content = document.getElementById('pluginSection').content;
|
||||
clone = document.importNode(content, true);
|
||||
pluginsList.appendChild(clone);
|
||||
clone = pluginsList.lastElementChild;
|
||||
|
||||
clone.setAttribute('data-active', loot.game.plugins[i].isActive);
|
||||
clone.id = loot.game.plugins[i].name.replace(/\s+/g, '');
|
||||
|
||||
if (loot.game.plugins[i].isActive) {
|
||||
++activePluginNo;
|
||||
}
|
||||
|
||||
/*if (loot.game.plugins[i].isDirty) {
|
||||
++dirtyPluginNo;
|
||||
}*/
|
||||
|
||||
clone.getElementsByTagName('h1')[0].textContent = loot.game.plugins[i].name;
|
||||
|
||||
if (loot.game.plugins[i].crc != 0) {
|
||||
clone.getElementsByClassName('crc')[0].textContent = 'CRC: ' + loot.game.plugins[i].crc;
|
||||
} else {
|
||||
clone.getElementsByClassName('crc')[0].textContent = '';
|
||||
}
|
||||
|
||||
if (loot.game.plugins[i].isDummy) {
|
||||
showElement(clone.getElementsByClassName('dummyPlugin')[0]);
|
||||
}
|
||||
|
||||
if (loot.game.plugins[i].loadsBSA) {
|
||||
showElement(clone.getElementsByClassName('loadsBSA')[0]);
|
||||
}
|
||||
|
||||
/*// This won't actually be handled anything like this in the real data implementation.
|
||||
if (data.plugins[i].hasUserEdits) {
|
||||
showElement(clone.getElementsByClassName('hasUserEdits')[0]);
|
||||
}*/
|
||||
|
||||
if (loot.game.plugins[i].version) {
|
||||
clone.getElementsByClassName('version')[0].textContent = 'Version: ' + loot.game.plugins[i].version;
|
||||
} else {
|
||||
hideElement(clone.getElementsByClassName('version')[0]);
|
||||
}
|
||||
|
||||
/*if (data.plugins[i].tagsAdd && data.plugins[i].tagsAdd.length != 0) {
|
||||
clone.getElementsByClassName('tag add')[0].textContent = data.plugins[i].tagsAdd.join(', ');
|
||||
} else {*/
|
||||
hideElement(clone.getElementsByClassName('tag add')[0]);
|
||||
//}
|
||||
|
||||
/*if (data.plugins[i].tagRemove && data.plugins[i].tagRemove.length != 0) {
|
||||
clone.getElementsByClassName('tag remove')[0].textContent = data.plugins[i].tagsRemove.join(', ');
|
||||
} else {*/
|
||||
hideElement(clone.getElementsByClassName('tag remove')[0]);
|
||||
//}
|
||||
|
||||
clone.getElementsByClassName('editMetadata')[0].setAttribute('data-target', clone.id);
|
||||
clone.getElementsByClassName('copyMetadata')[0].setAttribute('data-target', clone.id);
|
||||
clone.getElementsByClassName('clearMetadata')[0].setAttribute('data-target', clone.id);
|
||||
|
||||
/*if (data.plugins[i].messages && data.plugins[i].messages.length != 0) {
|
||||
for (var j = 0; j < data.plugins[i].messages.length; ++j) {
|
||||
var messageLi = document.createElement('li');
|
||||
messageLi.className = data.plugins[i].messages[j].type;
|
||||
// innerHTML is open to abuse, but for hyperlinking it's too useful.
|
||||
messageLi.innerHTML = data.plugins[i].messages[j].content;
|
||||
clone.getElementsByTagName('ul')[0].appendChild(messageLi);
|
||||
|
||||
if (messageLi.className == 'warn') {
|
||||
warnMessageNo++;
|
||||
} else if (li.className == 'error') {
|
||||
} else if (messageLi.className == 'error') {
|
||||
errorMessageNo++;
|
||||
}
|
||||
totalMessageNo++;
|
||||
}
|
||||
totalMessageNo = data.globalMessages.length;
|
||||
var pluginsList = document.getElementById('main');
|
||||
var pluginsNav = document.getElementById('pluginsNav');
|
||||
for (var i = 0; i < data.plugins.length; ++i) {
|
||||
var content, clone;
|
||||
/* First add link to navbar. */
|
||||
content = document.getElementById('pluginNav').content;
|
||||
clone = document.importNode(content, true);
|
||||
pluginsNav.appendChild(clone);
|
||||
clone = pluginsNav.lastElementChild;
|
||||
|
||||
clone.getElementsByClassName('name')[0].textContent = data.plugins[i].name;
|
||||
clone.getElementsByTagName('a')[0].href = '#' + data.plugins[i].name.replace(/\s+/g, '');
|
||||
clone.getElementsByClassName('priority')[0].textContent = 'Priority: 500, Global: ✓'; // Or '✗'.
|
||||
|
||||
if (data.plugins[i].isDummy) {
|
||||
clone.getElementsByClassName('dummyPlugin')[0].className += ' fa fa-eye-slash';
|
||||
}
|
||||
|
||||
if (data.plugins[i].loadsBSA) {
|
||||
clone.getElementsByClassName('loadsBSA')[0].className += ' fa fa-paperclip';
|
||||
}
|
||||
|
||||
if (data.plugins[i].hasUserEdits) {
|
||||
/* This won't actually be handled anything like this in the real data implementation. */
|
||||
clone.getElementsByClassName('hasUserEdits')[0].className += ' fa fa-user';
|
||||
}
|
||||
|
||||
/* Now add plugin 'card'. */
|
||||
content = document.getElementById('pluginSection').content;
|
||||
clone = document.importNode(content, true);
|
||||
pluginsList.appendChild(clone);
|
||||
clone = pluginsList.lastElementChild;
|
||||
|
||||
clone.setAttribute('data-active', data.plugins[i].isActive);
|
||||
clone.id = data.plugins[i].name.replace(/\s+/g, '');
|
||||
|
||||
if (data.plugins[i].isActive) {
|
||||
++activePluginNo;
|
||||
}
|
||||
|
||||
if (data.plugins[i].isDirty) {
|
||||
++dirtyPluginNo;
|
||||
}
|
||||
|
||||
clone.getElementsByTagName('h1')[0].textContent = data.plugins[i].name;
|
||||
|
||||
clone.getElementsByClassName('crc')[0].textContent = 'CRC: ' + data.plugins[i].crc;
|
||||
|
||||
if (data.plugins[i].isDummy) {
|
||||
showElement(clone.getElementsByClassName('dummyPlugin')[0]);
|
||||
}
|
||||
|
||||
if (data.plugins[i].loadsBSA) {
|
||||
showElement(clone.getElementsByClassName('loadsBSA')[0]);
|
||||
}
|
||||
|
||||
if (data.plugins[i].hasUserEdits) {
|
||||
/* This won't actually be handled anything like this in the real data implementation. */
|
||||
showElement(clone.getElementsByClassName('hasUserEdits')[0]);
|
||||
}
|
||||
|
||||
if (data.plugins[i].version) {
|
||||
clone.getElementsByClassName('version')[0].textContent = 'Version: ' + data.plugins[i].version;
|
||||
} else {
|
||||
hideElement(clone.getElementsByClassName('version')[0]);
|
||||
}
|
||||
|
||||
if (data.plugins[i].tagsAdd && data.plugins[i].tagsAdd.length != 0) {
|
||||
clone.getElementsByClassName('tag add')[0].textContent = data.plugins[i].tagsAdd.join(', ');
|
||||
} else {
|
||||
hideElement(clone.getElementsByClassName('tag add')[0]);
|
||||
}
|
||||
|
||||
if (data.plugins[i].tagRemove && data.plugins[i].tagRemove.length != 0) {
|
||||
clone.getElementsByClassName('tag remove')[0].textContent = data.plugins[i].tagsRemove.join(', ');
|
||||
} else {
|
||||
hideElement(clone.getElementsByClassName('tag remove')[0]);
|
||||
}
|
||||
|
||||
clone.getElementsByClassName('editMetadata')[0].setAttribute('data-target', clone.id);
|
||||
clone.getElementsByClassName('copyMetadata')[0].setAttribute('data-target', clone.id);
|
||||
clone.getElementsByClassName('clearMetadata')[0].setAttribute('data-target', clone.id);
|
||||
|
||||
if (data.plugins[i].messages && data.plugins[i].messages.length != 0) {
|
||||
for (var j = 0; j < data.plugins[i].messages.length; ++j) {
|
||||
var messageLi = document.createElement('li');
|
||||
messageLi.className = data.plugins[i].messages[j].type;
|
||||
/* innerHTML is open to abuse, but for hyperlinking it's too useful. */
|
||||
messageLi.innerHTML = data.plugins[i].messages[j].content;
|
||||
clone.getElementsByTagName('ul')[0].appendChild(messageLi);
|
||||
|
||||
if (messageLi.className == 'warn') {
|
||||
warnMessageNo++;
|
||||
} else if (messageLi.className == 'error') {
|
||||
errorMessageNo++;
|
||||
}
|
||||
totalMessageNo++;
|
||||
}
|
||||
} else {
|
||||
clone.getElementsByTagName('ul')[0].className += ' hidden';
|
||||
}
|
||||
}
|
||||
document.getElementById('filterTotalMessageNo').textContent = totalMessageNo;
|
||||
document.getElementById('totalMessageNo').textContent = totalMessageNo;
|
||||
document.getElementById('totalWarningNo').textContent = warnMessageNo;
|
||||
document.getElementById('totalErrorNo').textContent = errorMessageNo;
|
||||
document.getElementById('filterTotalPluginNo').textContent = data.plugins.length;
|
||||
document.getElementById('totalPluginNo').textContent = data.plugins.length;
|
||||
document.getElementById('activePluginNo').textContent = activePluginNo;
|
||||
document.getElementById('dirtyPluginNo').textContent = dirtyPluginNo;
|
||||
|
||||
/* Now apply translated UI strings. */
|
||||
for (var id in data.l10n) {
|
||||
var elem = document.getElementById(id);
|
||||
if (elem) {
|
||||
elem.textContent = data.l10n[id];
|
||||
}
|
||||
}
|
||||
|
||||
/* Now initialise the rest of the report. */
|
||||
initJavascriptVars();
|
||||
setupEventHandlers();
|
||||
if (isStorageSupported()) {
|
||||
loadSettings();
|
||||
}
|
||||
showElement(document.getElementsByTagName('section')[0]);
|
||||
});
|
||||
} else {*/
|
||||
clone.getElementsByTagName('ul')[0].className += ' hidden';
|
||||
//}
|
||||
}
|
||||
document.getElementById('filterTotalMessageNo').textContent = totalMessageNo;
|
||||
document.getElementById('totalMessageNo').textContent = totalMessageNo;
|
||||
document.getElementById('totalWarningNo').textContent = warnMessageNo;
|
||||
document.getElementById('totalErrorNo').textContent = errorMessageNo;
|
||||
document.getElementById('filterTotalPluginNo').textContent = loot.game.plugins.length;
|
||||
document.getElementById('totalPluginNo').textContent = loot.game.plugins.length;
|
||||
document.getElementById('activePluginNo').textContent = activePluginNo;
|
||||
document.getElementById('dirtyPluginNo').textContent = dirtyPluginNo;
|
||||
|
||||
// Now set up event handlers, as they depend on the plugin cards having been created.
|
||||
setupEventHandlers();
|
||||
}
|
||||
function initGameVars() {
|
||||
// Create and send a new query.
|
||||
var request_id = window.cefQuery({
|
||||
request: 'initGameVars',
|
||||
persistent: false,
|
||||
onSuccess: updateInterfaceWithGameInfo,
|
||||
onFailure: function(error_code, error_message) {
|
||||
showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
initGlobalVars();
|
||||
initGameVars();
|
||||
if (isStorageSupported()) {
|
||||
loadSettings();
|
||||
}
|
||||
processURLParams();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
/* LOOT
|
||||
|
||||
A load order optimisation tool for Oblivion, Skyrim, Fallout 3 and
|
||||
Fallout: New Vegas.
|
||||
|
||||
Copyright (C) 2014 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_JSON__
|
||||
#define __LOOT_JSON__
|
||||
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace loot {
|
||||
|
||||
// Handy class for turning YAML objects into JSON and vice-versa.
|
||||
class JSON {
|
||||
public:
|
||||
|
||||
inline static YAML::Node parse(std::string& json) {
|
||||
return YAML::Load(json);
|
||||
}
|
||||
|
||||
inline static std::string stringify(YAML::Node& yaml) {
|
||||
|
||||
YAML::Emitter out;
|
||||
out.SetOutputCharset(YAML::EscapeNonAscii);
|
||||
out.SetStringFormat(YAML::DoubleQuoted);
|
||||
out.SetBoolFormat(YAML::TrueFalseBool);
|
||||
out.SetSeqFormat(YAML::Flow);
|
||||
out.SetMapFormat(YAML::Flow);
|
||||
|
||||
out << yaml;
|
||||
|
||||
// yaml-cpp produces `!<!>` artifacts in its output, so remove them.
|
||||
std::string json = out.c_str();
|
||||
boost::replace_all(json, "!<!>", "");
|
||||
// There's also a bit of weirdness where there are some \x escapes and some \u escapes.
|
||||
// They should all be \u, so transform them.
|
||||
boost::replace_all(json, "\\x", "\\u00");
|
||||
|
||||
return json;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+8
-4
@@ -132,6 +132,8 @@ namespace loot {
|
||||
// LootState member functions
|
||||
//---------------------------
|
||||
|
||||
LootState::LootState() : _currentGame(0) {}
|
||||
|
||||
void LootState::Init(const std::string& cmdLineGame) {
|
||||
string initError;
|
||||
|
||||
@@ -226,23 +228,25 @@ namespace loot {
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Selecting game.";
|
||||
|
||||
size_t gameIndex(0);
|
||||
try {
|
||||
gameIndex = SelectGame(_settings, _games, cmdLineGame);
|
||||
_currentGame = SelectGame(_settings, _games, cmdLineGame);
|
||||
}
|
||||
catch (exception &) {
|
||||
BOOST_LOG_TRIVIAL(error) << "None of the supported games were detected.";
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(debug) << "Game selected is " << _games[gameIndex].Name();
|
||||
BOOST_LOG_TRIVIAL(debug) << "Game selected is " << _games[_currentGame].Name();
|
||||
|
||||
//Now that game is selected, initialise it.
|
||||
BOOST_LOG_TRIVIAL(debug) << "Initialising game-specific settings.";
|
||||
try {
|
||||
_games[gameIndex].Init();
|
||||
_games[_currentGame].Init();
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Game-specific settings could not be initialised. " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
Game& LootState::CurrentGame() {
|
||||
return _games[_currentGame];
|
||||
}
|
||||
}
|
||||
@@ -72,11 +72,14 @@ namespace loot {
|
||||
|
||||
class LootState {
|
||||
public:
|
||||
LootState();
|
||||
|
||||
void Init(const std::string& cmdLineGame);
|
||||
Game& CurrentGame();
|
||||
|
||||
YAML::Node _settings;
|
||||
std::vector<loot::Game> _games;
|
||||
size_t _currentGame;
|
||||
};
|
||||
|
||||
extern LootState g_app_state;
|
||||
|
||||
+111
-19
@@ -26,11 +26,17 @@
|
||||
#include "resource.h"
|
||||
#include "app.h"
|
||||
|
||||
#include "../backend/json.h"
|
||||
#include "../backend/parsers.h"
|
||||
|
||||
#include <include/cef_app.h>
|
||||
#include <include/cef_runnable.h>
|
||||
#include <include/cef_task.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
@@ -38,6 +44,11 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
using boost::format;
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace loc = boost::locale;
|
||||
|
||||
namespace loot {
|
||||
|
||||
namespace {
|
||||
@@ -75,7 +86,7 @@ namespace loot {
|
||||
callback->Failure((int)ret, "Shell execute failed.");
|
||||
return true;
|
||||
}
|
||||
else if (request == "initJavascriptVars") {
|
||||
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()) {
|
||||
@@ -123,28 +134,109 @@ namespace loot {
|
||||
|
||||
temp["languages"] = Language::Names();
|
||||
|
||||
// Now output as JSON.
|
||||
// Now output as JSON
|
||||
//-------------------
|
||||
|
||||
YAML::Emitter tempout;
|
||||
tempout.SetOutputCharset(YAML::EscapeNonAscii);
|
||||
tempout.SetStringFormat(YAML::DoubleQuoted);
|
||||
tempout.SetBoolFormat(YAML::TrueFalseBool);
|
||||
tempout.SetSeqFormat(YAML::Flow);
|
||||
tempout.SetMapFormat(YAML::Flow);
|
||||
|
||||
tempout << temp;
|
||||
|
||||
// yaml-cpp produces `!<!>` artifacts in its output, so remove them.
|
||||
std::string json = tempout.c_str();
|
||||
boost::replace_all(json, "!<!>", "");
|
||||
// There's also a bit of weirdness where there are some \x escapes and some \u escapes.
|
||||
// They should all be \u, so transform them.
|
||||
boost::replace_all(json, "\\x", "\\u00");
|
||||
|
||||
callback->Success(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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
||||
callback->Success(JSON::stringify(gameNode));
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user