From ecd12e010418d2e91114c9ac208021807c9649c8 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Tue, 15 Jul 2014 23:24:38 +0100 Subject: [PATCH] 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. --- resources/report/js/script.js | 329 ++++++------ resources/report/testdata.js | 958 ---------------------------------- src/backend/json.h | 65 +++ src/gui/app.cpp | 12 +- src/gui/app.h | 3 + src/gui/handler.cpp | 130 ++++- 6 files changed, 358 insertions(+), 1139 deletions(-) delete mode 100644 resources/report/testdata.js create mode 100644 src/backend/json.h diff --git a/resources/report/js/script.js b/resources/report/js/script.js index ee23c87d..18c10f24 100644 --- a/resources/report/js/script.js +++ b/resources/report/js/script.js @@ -22,6 +22,7 @@ . */ '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(); diff --git a/resources/report/testdata.js b/resources/report/testdata.js deleted file mode 100644 index 0bcdaf36..00000000 --- a/resources/report/testdata.js +++ /dev/null @@ -1,958 +0,0 @@ -var data = { - "masterlist": { - "revision": "f66688fbe946396bc8fa1d5dadb7c8211c189cee", - "date": "2014-05-10" - }, - "plugins": [ - { - "name": "Skyrim.esm", - "isActive": true, - "crc": "C665FD56" - }, - { - "name": "Update.esm", - "loadsBSA": true, - "isActive": true, - "hasUserEdits": true, - "crc": "E5B67BDA", - "tagsAdd": ["Delev", - "Relev"], "messages": [{"type": "warn", - "content": "Warning: Contains 3 UDR records. Clean with TES5Edit."}] - }, - { - "name": "Unofficial Skyrim Patch.esp", - "loadsBSA": true, - "isActive": false, - "crc": "29D2C7DF", - "version": "2.0.0a", - "tagsAdd": ["Delev", - "Relev"] - }, - { - "name": "Unofficial Dawnguard Patch.esp", - "isActive": false, - "crc": "FF134167", - "version": "2.0.0b", - "tagsAdd": ["Delev", - "Relev"], "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "Unofficial Hearthfire Patch.esp", - "isActive": false, - "crc": "F913F25E", - "version": "2.0.0", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "Dragonborn.esm", - "loadsBSA": true, - "isActive": true, - "crc": "A9F83BFF", - "messages": [{"type": "warn", - "content": "Warning: Contains 61 ITM records, 8 UDR records and 1 deleted navmeshes. Clean with TES5Edit."}] - }, - { - "name": "Unofficial Dragonborn Patch.esp", - "loadsBSA": true, - "isActive": true, - "crc": "DA46F3C8", - "version": "2.0.0", - "tagsAdd": ["Delev"] - }, - { - "name": "Wyrmstooth.esp", - "loadsBSA": true, - "isActive": false, - "crc": "6629BE21", - "version": "1.10", - "messages": [{"type": "warn", - "content": "Warning: This plugin is incompatible with \"Dragonborn.esm\", but both are present."}] - }, - { - "name": "EnchantingAwakened.esp", - "isActive": false, - "crc": "4E2FE0C1", - "version": "1.60" - }, - { - "name": "SPIKE.esm", - "isActive": false, - "crc": "418D8B2F" - }, - { - "name": "UndergroundBathhouse.esm", - "loadsBSA": true, - "isActive": false, - "crc": "2838692F" - }, - { - "name": "Xvision Children.esm", - "isActive": false, - "crc": "A159E35B" - }, - { - "name": "Cutting Room Floor.esp", - "isActive": false, - "crc": "1BA027FF", - "version": "1.0.2", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Unofficial Skyrim Patch.esp\" to be active, but it is inactive."}] - }, - { - "name": "Run For Your Lives.esp", - "isActive": false, - "crc": "1931B1F5", - "version": "1.2.3" - }, - { - "name": "WATER DB.esp", - "isActive": false, - "crc": "1765B1A6", - "version": "1.87" - }, - { - "name": "MorePP.esp", - "loadsBSA": true, - "isActive": true, - "crc": "EA659B06" - }, - { - "name": "Follower Trap Safety.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "36016080" - }, - { - "name": "STEP-part6.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "AnimeticaNymph.esp", - "isActive": false, - "crc": "50263C4C" - }, - { - "name": "AnimeticaMikuAppend.esp", - "isActive": false, - "crc": "89C4E907" - }, - { - "name": "dD-No Twitching Dragon Death Animation.esp", - "isActive": false, - "crc": "49CDAE6D" - }, - { - "name": "AnimeticaTenshi.esp", - "isActive": false, - "crc": "44EB184D" - }, - { - "name": "BFSEffects.esp", - "isActive": false, - "crc": "543D56D4", - "version": "3.6", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "STEP-part2.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "AMatterOftime.esp", - "isActive": false, - "crc": "75025A7E", - "version": "1.00" - }, - { - "name": "STEP-part5.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "Footprints.esp", - "isActive": false, - "crc": "BFAF15E8" - }, - { - "name": "Book Covers Dragonborn.esp", - "isActive": false, - "crc": "65CBDF50" - }, - { - "name": "dD - Enhanced Blood Main.esp", - "isActive": false, - "crc": "7AFD4E3E", - "messages": [{"type": "say", - "content": "Note: Requires: Dragonborn Compatibility_Patch."}] - }, - { - "name": "dD - Realistic Ragdoll Force - Reduced.esp", - "isActive": false, - "crc": "AFCAAEAB", - "messages": [{"type": "say", - "content": "Note: Ragdolls will conflict with other mods that change the skeleton.nif. Check Custom Skeleton Replacers for compatibly with other skeleton.nif."}] - }, - { - "name": "Dynamic TimeScale.esp", - "isActive": false, - "crc": "B518ED06", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "Brawl Bugs CE.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "D284ACF" - }, - { - "name": "AnimeticaIkaros.esp", - "isActive": false, - "crc": "45DB135A" - }, - { - "name": "Dragons no LODs.esp", - "isActive": false, - "crc": "7F627C16", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "AnimeticaFate.esp", - "isActive": false, - "crc": "FC012D4E" - }, - { - "name": "EK_RingLimiter.esp", - "isActive": false, - "crc": "4E44A8B5" - }, - { - "name": "Auto Unequip Ammo.esp", - "isActive": false, - "crc": "4B399546" - }, - { - "name": "RaceMenu.esp", - "isActive": false, - "crc": "2765B7D0" - }, - { - "name": "dD-Dragonborn-Dawnguard-EBT Patch.esp", - "isActive": false, - "crc": "FE5C3763", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"dD - Enhanced Blood Main.esp\" to be active, but it is inactive."}] - }, - { - "name": "AnimeticaAstrea.esp", - "isActive": false, - "crc": "26772B36" - }, - { - "name": "foobar.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false - }, - { - "name": "AnimeticaHaruhi.esp", - "isActive": false, - "crc": "70D4E89A" - }, - { - "name": "EpisodeParallax.esp", - "isActive": false, - "crc": "A5B27576" - }, - { - "name": "fFastTravelSpeedMult_4.esp", - "isActive": false, - "crc": "CC1A0B4E", - "version": "1.0" - }, - { - "name": "BarenziahQuestMarkers_Droppable.esp", - "isActive": false, - "crc": "39EA9697" - }, - { - "name": "dD-No Spinning Death Animation.esp", - "isActive": false, - "crc": "94E02E5A" - }, - { - "name": "Guard Dialogue Overhaul.esp", - "isActive": false, - "crc": "BD421FB8", - "messages": [{"type": "say", - "content": "Note: Do not clean. \"Dirty\" edits are intentional and required for the mod to function." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPIKE.esm\" to be active, but it is inactive."}] - }, - { - "name": "kuerteeSimpleMultipleFollowers.esp", - "isActive": false, - "crc": "5C99F173" - }, - { - "name": "HearthfireMoveKidsfix.esp", - "isActive": false, - "crc": "BA0EB4C5", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "iHUD.esp", - "isActive": false, - "crc": "6633B25E" - }, - { - "name": "imp_helm.esp", - "isActive": false, - "crc": "5604D208", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "LFox Alchemists Have Ingredients Light.esp", - "isActive": false, - "crc": "74F94A53", - "tagsAdd": ["Relev"], "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "Lightweight Potions and Poisons.esp", - "isActive": false, - "crc": "276314FF", - "version": "0.1." - }, - { - "name": "No Empty Tag on Containers.esp", - "isActive": false, - "crc": "77E800E" - }, - { - "name": "Footprints - Ash.esp", - "isActive": false, - "crc": "D3E16A61", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Footprints.esp\" to be active, but it is inactive."}] - }, - { - "name": "STEP-part3.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "MoreRainWindy66percentLessView.esp", - "isActive": false, - "crc": "50B2CC8F" - }, - { - "name": "Piratelords Loot Adjustments.esp", - "isActive": false, - "crc": "66D0C4C7", - "tagsAdd": ["Delev", - "Relev"], "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "Book Covers Dawnguard.esp", - "isActive": false, - "crc": "819C137E", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "Book Covers Skyrim.esp", - "isActive": false, - "crc": "4075148A" - }, - { - "name": "Ars Metallica.esp", - "isActive": false, - "crc": "8D03ECC0", - "version": "1.2.1" - }, - { - "name": "Ars Metallica - Dawnguard.esp", - "isActive": false, - "crc": "FE8960A3", - "version": "1.2.1", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Ars Metallica.esp\" to be active, but it is inactive."}] - }, - { - "name": "Ars Metallica - Hearthfire.esp", - "isActive": false, - "crc": "18A5C66B", - "version": "1.2.1", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Ars Metallica.esp\" to be active, but it is inactive."}] - }, - { - "name": "Book Covers Hearthfire.esp", - "isActive": false, - "crc": "D306DE27", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Book Covers Skyrim.esp\" to be active, but it is inactive."}] - }, - { - "name": "Moss Rocks.esp", - "isActive": false, - "crc": "D7FF66AC" - }, - { - "name": "moveitLWT.esp", - "isActive": false, - "crc": "1CBC50DC" - }, - { - "name": "PersonalizedMusic_v4.0.esp", - "isActive": false, - "crc": "74D7D28B" - }, - { - "name": "NoPsychicLockKnowledge.esp", - "isActive": false, - "crc": "336B524B" - }, - { - "name": "Radiant and Unique Potions Poisons and Booze.esp", - "isActive": false, - "crc": "EA004B82" - }, - { - "name": "Reduced Distance NPC Greetings.esp", - "isActive": false, - "crc": "24658104", - "version": "50" - }, - { - "name": "SkyUI.esp", - "loadsBSA": true, - "isActive": true, - "crc": "9330CAF7", - "version": "4.1" - }, - { - "name": "AnimeticaKobato.esp", - "isActive": false, - "crc": "3B0B19DD" - }, - { - "name": "Smithing Flexible Tree.esp", - "isActive": false, - "crc": "965889B3", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "SoS - The Wilds.esp", - "isActive": false, - "crc": "49F5E301", - "version": "1.13", - "messages": [{"type": "say", - "content": "Note: Do not use the Crash Fix ESP for this mod. It is flagged as a master and is only meant as a last resort for fixing crashes."}] - }, - { - "name": "SkyFalls Plus SkyMills - All DLC.esp", - "isActive": false, - "crc": "4040AFD0", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "SFO - Dragonborn.esp", - "isActive": false, - "crc": "C9DB0844" - }, - { - "name": "Distant DetailHF.esp", - "isActive": false, - "crc": "29C8DF7B", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "Bring Out Your Dead.esp", - "isActive": false, - "crc": "3ABC3315", - "version": "1.2.2", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Unofficial Skyrim Patch.esp\" to be active, but it is inactive."}] - }, - { - "name": "Xvision Children - Complete.esp", - "isActive": false, - "crc": "4A786D54", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Xvision Children.esm\" to be active, but it is inactive."}] - }, - { - "name": "Xvision Children - USKP.esp", - "isActive": false, - "crc": "A4ACB325", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"unofficial skyrim patch.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Xvision Children.esm\" to be active, but it is inactive."}] - }, - { - "name": "ExpandedSnowSystems.esp", - "isActive": false, - "crc": "739AC421", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "SoS - The Dungeons.esp", - "isActive": false, - "crc": "79377267", - "version": "1.23", - "messages": [{"type": "say", - "content": "Note: Do not use the Crash Fix ESP for this mod. It is flagged as a master and is only meant as a last resort for fixing crashes."}] - }, - { - "name": "Oblivion Gates v3 - Skyrim + Dawnguard DLC.esp", - "isActive": false, - "crc": "C56B1AEE", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "BirdsHFclean.esp", - "isActive": false, - "crc": "5CA1AC97", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "EMCompViljaSkyrim.esp", - "isActive": false, - "crc": "A2A7E570" - }, - { - "name": "EMViljaInSolstheimAddOn.esp", - "isActive": false, - "crc": "FA24307A", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"EMCompViljaSkyrim.esp\" to be active, but it is inactive."}] - }, - { - "name": "A Thane-Worthy Breezehome.esp", - "isActive": false, - "crc": "28A7A956", - "messages": [{"type": "warn", - "content": "Warning: This file contains 1 deleted NavMesh record(s) that TES5Edit cannot repair automatically and it may cause problems with your game. NavMesh deletions should be reported to the mod author. A guide to repairing NavMesh deletions with TES5Edit is located here." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "NoxUE2.00.esp", - "isActive": false, - "crc": "D62F798B", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "AnimeticaSena.esp", - "isActive": false, - "crc": "5837DA98" - }, - { - "name": "Soul Gems Differ - E.esp", - "isActive": false, - "crc": "D85F580A" - }, - { - "name": "AetherSuite.esp", - "isActive": false, - "crc": "F9553087" - }, - { - "name": "SplashofRain.esp", - "isActive": false, - "crc": "363772B6", - "version": "1.04" - }, - { - "name": "Unique Grasses.esp", - "isActive": false, - "crc": "24202A6D" - }, - { - "name": "SPTDiverseMuscleTones.esp", - "isActive": false, - "crc": "2D5C68FE", - "version": "5.1" - }, - { - "name": "SPTDiverseMuscleTonesViljaPatch.esp", - "isActive": false, - "crc": "117758E3", - "version": "5.0", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"EMCompViljaSkyrim.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTones.esp\" to be active, but it is inactive."}] - }, - { - "name": "SPTDiverseMuscleTonesDawnguardDragonborn.esp", - "isActive": false, - "crc": "F4927D22", - "version": "5.0", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTones.esp\" to be active, but it is inactive."}] - }, - { - "name": "SPTDiverseMuscleTonesNPCs.esp", - "isActive": false, - "crc": "554F1CAB", - "version": "5.0", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Unofficial Skyrim Patch.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Cutting Room Floor.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Bring Out Your Dead.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTones.esp\" to be active, but it is inactive."}] - }, - { - "name": "SPTDiverseGuardsSkyrim.esp", - "isActive": false, - "crc": "682A3893", - "version": "4.6", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTones.esp\" to be active, but it is inactive."}] - }, - { - "name": "SPTConsistentOlderPeople.esp", - "isActive": false, - "crc": "CAF3C1BE", - "version": "1.8", - "messages": [{"type": "say", - "content": "Note: If this is not newer than v1.3, update to the latest version." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Cutting Room Floor.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Bring Out Your Dead.esp\" to be active, but it is inactive."}] - }, - { - "name": "EnchantingAwakenedAWEPatch.esp", - "isActive": false, - "crc": "DDDCC598", - "version": "1.50", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Animated Weapon Enchants.esp\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"EnchantingAwakened.esp\" to be active, but it is inactive."}] - }, - { - "name": "AnimeticaMiko.esp", - "isActive": false, - "crc": "1538B6B7" - }, - { - "name": "Better Dynamic Snow.esp", - "isActive": false, - "crc": "F3204EF1" - }, - { - "name": "StaticMeshImprovementMod.esp", - "isActive": false, - "crc": "EC37D3CE" - }, - { - "name": "Ars Metallica - Dragonborn.esp", - "isActive": false, - "crc": "1091DB21", - "version": "1.2.1", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Ars Metallica.esp\" to be active, but it is inactive."}] - }, - { - "name": "SPTDiverseMuscleTonesPlayer.esp", - "isActive": false, - "crc": "5EA9E4D7", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTones.esp\" to be active, but it is inactive."}] - }, - { - "name": "STEP-part1.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "STEP-part4.esp", - "isDummy": true, - "loadsBSA": true, - "isActive": false, - "crc": "2994FBF7" - }, - { - "name": "fs_swordandshield.esp", - "loadsBSA": true, - "isActive": false, - "crc": "8D438E3", - "messages": [{"type": "warn", - "content": "Warning: This plugin is incompatible with \"MorePP.esp\", but both are present."}] - }, - { - "name": "SwiftPotion.esp", - "isActive": false, - "crc": "E08D9F45" - }, - { - "name": "TheChoiceIsYours.esp", - "isActive": false, - "crc": "58BC5ABB" - }, - { - "name": "Point The Way.esp", - "isActive": false, - "crc": "F372CBC2", - "version": "1.0.2" - }, - { - "name": "SkyrimImprovedPuddles-DG-HF-DB.esp", - "isActive": false, - "crc": "D0427B6", - "version": "1.1", - "messages": [{"type": "say", - "content": "Note: Use only one SkyrimImprovedPuddles esp." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "The Paarthurnax Dilemma.esp", - "isActive": false, - "crc": "9E446FBD", - "version": "1.2.5" - }, - { - "name": "TheTownIsSafe.esp", - "isActive": false, - "crc": "B5AAAF6B", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin is incompatible with \"When Vampires Attack.esp\", but both are present."}] - }, - { - "name": "TradeBarter.esp", - "isActive": false, - "crc": "AC24F58B", - "tagsAdd": ["Delev", - "Relev"], "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"HearthFires.esm\" to be installed, but it is missing."}] - }, - { - "name": "Tamriel Compendium - Skill Books.esp", - "isActive": false, - "crc": "1F348D90", - "version": "1.1", - "tagsAdd": ["Relev"] - }, - { - "name": "WATER.esp", - "isActive": false, - "crc": "AFE4A968", - "version": "1.87" - }, - { - "name": "WetandCold.esp", - "isActive": false, - "crc": "E034A81F", - "version": "1.321" - }, - { - "name": "WetandCold - Ashes.esp", - "isActive": false, - "crc": "8C003085", - "version": "1.06", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"WetandCold.esp\" to be active, but it is inactive."}] - }, - { - "name": "When Vampires Attack.esp", - "isActive": false, - "crc": "4743D674", - "version": "1.1", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin is incompatible with \"TheTownIsSafe.esp\", but both are present."}] - }, - { - "name": "whiteruntrees.esp", - "isActive": false, - "crc": "6265C55E" - }, - { - "name": "Map Markers Complete.esp", - "isActive": false, - "crc": "D48714FB" - }, - { - "name": "Oblivion Gates in Cities.esp", - "isActive": false, - "crc": "E7D68506", - "version": "1.0" - }, - { - "name": "Gildergreen Regrown.esp", - "isActive": false, - "crc": "7AFAAD00", - "version": "1.2.5" - }, - { - "name": "TheChoiceIsYours_Dawnguard.esp", - "isActive": false, - "crc": "8BD6B852", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}] - }, - { - "name": "SPTKatlaSailReangle.esp", - "isActive": false, - "crc": "10511ED2" - }, - { - "name": "Warburg's 3D Paper World Map - Texture 1.esp", - "isActive": false, - "crc": "26ADE83C", - "messages": [{"type": "say", - "content": "Note: In case of persistent zoom-in issues, consider creating and using a Userlist to load the map lower, below any dynamic plugin(s)."}] - }, - { - "name": "Bashed Patch, 0.esp", - "isActive": false, - "crc": "C2306BE5", - "version": "2013-12-13 13:55:02", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"TradeBarter.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Ars Metallica.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"Piratelords Loot Adjustments.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPTConsistentOlderPeople.esp\" to be active, but it is inactive." - }, - { - "type": "warn", - "content": "Warning: This plugin requires \"SPTDiverseMuscleTonesFemaleVariety.esp\" to be installed, but it is missing."}] - }, - { - "name": "warburg's 3d paper world map - dawnguard.esp", - "isActive": false, - "crc": "53E8693D", - "messages": [{"type": "warn", - "content": "Warning: This plugin requires \"Dawnguard.esm\" to be installed, but it is missing."}]} - ], - "globalMessages": [ - { - "type": "say", - "content": "Note: There have been no changes in the Details tab since LOOT was last run for this game." - }, - { - "type": "say", - "content": "Note: Latest LOOT thread." - }, - { - "type": "say", - "content": "Note: Your SKSE is up-to-date." - }, - { - "type": "warn", - "content": "Warning: The load order displayed in the Details tab was not applied as sorting was canceled." - } - ], -} \ No newline at end of file diff --git a/src/backend/json.h b/src/backend/json.h new file mode 100644 index 00000000..f6cbb256 --- /dev/null +++ b/src/backend/json.h @@ -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 +. +*/ + +#ifndef __LOOT_JSON__ +#define __LOOT_JSON__ + + +#include + +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 \ No newline at end of file diff --git a/src/gui/app.cpp b/src/gui/app.cpp index dec06baf..33c302f4 100644 --- a/src/gui/app.cpp +++ b/src/gui/app.cpp @@ -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]; + } } \ No newline at end of file diff --git a/src/gui/app.h b/src/gui/app.h index c5bf8f7b..56a4baf4 100644 --- a/src/gui/app.h +++ b/src/gui/app.h @@ -72,11 +72,14 @@ namespace loot { class LootState { public: + LootState(); void Init(const std::string& cmdLineGame); + Game& CurrentGame(); YAML::Node _settings; std::vector _games; + size_t _currentGame; }; extern LootState g_app_state; diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index cc413984..f8de31a1 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -26,11 +26,17 @@ #include "resource.h" #include "app.h" +#include "../backend/json.h" +#include "../backend/parsers.h" + #include #include #include #include +#include +#include +#include #include #include @@ -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 installed; + list 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()).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::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; }