From 1a641cc0452c7e72d94e36daa79238c8b37ee5f4 Mon Sep 17 00:00:00 2001 From: WrinklyNinja Date: Mon, 11 Aug 2014 14:07:06 +0100 Subject: [PATCH] Fixed game switch crash and missing game switching. Games that aren't detected get their menu items disabled so they can't be switched to. Also rewrote the CEF init queries to use JS Promises to ensure everything gets loaded when needed. Game switching doesn't work properly yet though. --- resources/report/js/script.js | 197 ++++++++++++++++++++-------------- src/gui/app.cpp | 3 + src/gui/app.h | 3 +- src/gui/handler.cpp | 20 +++- src/gui/handler.h | 1 + 5 files changed, 139 insertions(+), 85 deletions(-) diff --git a/resources/report/js/script.js b/resources/report/js/script.js index b2b2afcd..7a15f49d 100644 --- a/resources/report/js/script.js +++ b/resources/report/js/script.js @@ -207,7 +207,7 @@ function updateSelectedGame() { index = i; } } - if (loot.settings.games.type == 'Skyrim') { + if (loot.settings.games[index].type == 'Skyrim') { document.getElementById('redatePluginsButton').classList.toggle('disabled', false); } else { document.getElementById('redatePluginsButton').classList.toggle('disabled', true); @@ -245,7 +245,7 @@ function changeGame(evt) { var request = { name: 'changeGame', args: [ - evt.target.getAttribute('data-target') + evt.currentTarget.getAttribute('data-target') ] }; @@ -382,7 +382,7 @@ function toggleMenu(evt) { hideElement(target); /* Also remove event listeners to any dynamically-generated items. */ - var elements = target.querySelectorAll('[data-action]'); + var elements = target.querySelectorAll('[data-action]:not(.disabled)'); for (var i = 0; i < elements.length; ++i) { var action = elements[i].getAttribute('data-action'); if (action == 'show-editor') { @@ -403,7 +403,7 @@ function toggleMenu(evt) { showElement(target); /* Also attach event listeners to any dynamically-generated items. */ - var elements = target.querySelectorAll('[data-action]'); + var elements = target.querySelectorAll('[data-action]:not(.disabled)'); for (var i = 0; i < elements.length; ++i) { var action = elements[i].getAttribute('data-action'); if (action == 'show-editor') { @@ -605,7 +605,7 @@ function setupEventHandlers() { function processCefError(errorCode, errorMessage) { showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message); } -function initGlobalVars() { +function initVars() { // Create and send a new query. var request_id = window.cefQuery({ request: 'getVersion', @@ -646,78 +646,125 @@ function initGlobalVars() { }, onFailure: processCefError }); - var request_id = window.cefQuery({ + + var parallelPromises = []; + + parallelPromises.push(new Promise(function(resolve, reject) { + var request_id = window.cefQuery({ request: 'getGameTypes', persistent: false, - onSuccess: function(response) { - try { - loot.gameTypes = JSON.parse(response); + onSuccess: resolve, + onFailure: function(errorCode, errorMessage) { + reject(Error('Error code: ' + error_code + '; ' + error_message)) + } + }); + })); - /* 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); + parallelPromises.push(new Promise(function(resolve, reject) { + var request_id = window.cefQuery({ + request: 'getInstalledGames', + persistent: false, + onSuccess: resolve, + onFailure: function(errorCode, errorMessage) { + reject(Error('Error code: ' + error_code + '; ' + error_message)) + } + }); + })); + + parallelPromises.push(new Promise(function(resolve, reject) { + var request_id = window.cefQuery({ + request: 'getGameData', + persistent: false, + onSuccess: resolve, + onFailure: function(errorCode, errorMessage) { + reject(Error('Error code: ' + error_code + '; ' + error_message)) + } + }); + })); + + parallelPromises.push(new Promise(function(resolve, reject) { + var request_id = window.cefQuery({ + request: 'getSettings', + persistent: false, + onSuccess: resolve, + onFailure: function(errorCode, errorMessage) { + reject(Error('Error code: ' + error_code + '; ' + error_message)) + } + }); + })); + + Promise.all(parallelPromises).then(function(results) { + try { + loot.gameTypes = JSON.parse(results[0]); + } catch (e) { + console.log(e); + console.log('getGameTypes response: ' + results[0]); + } + + /* 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); + } + + try { + loot.installedGames = JSON.parse(results[1]); + } catch (e) { + console.log(e); + console.log('getInstalledGames response: ' + results[1]); + } + + updateInterfaceWithGameInfo(results[2]); + + try { + loot.settings = JSON.parse(results[3]); + } catch (e) { + console.log(e); + console.log('getSettings response: ' + results[3]); + } + + /* Now fill game lists/table. */ + var gameSelect = document.getElementById('defaultGameSelect'); + var gameMenu = document.getElementById('gameMenu').firstElementChild; + var gameTable = document.getElementById('gameTable'); + 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); + + if (loot.installedGames.indexOf(loot.settings.games[i].folder) == -1) { + li.classList.toggle('disabled', true); } - // 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); + var icon = document.createElement('span'); + icon.className = 'fa fa-fw'; + li.appendChild(icon); + var text = document.createElement('span'); + text.textContent = loot.settings.games[i].name; + li.appendChild(text); - /* Now fill game lists/table. */ - var gameSelect = document.getElementById('defaultGameSelect'); - var gameMenu = document.getElementById('gameMenu').firstElementChild; - var gameTable = document.getElementById('gameTable'); - 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); + gameMenu.appendChild(li); - var li = document.createElement('li'); - li.setAttribute('data-action', 'change-game'); - li.setAttribute('data-target', loot.settings.games[i].folder); + gameTable.addRow(loot.settings.games[i]); + } - var icon = document.createElement('span'); - icon.className = 'fa fa-fw'; - li.appendChild(icon); + /* Highlight game in menu. */ + updateSelectedGame(); - var text = document.createElement('span'); - text.textContent = loot.settings.games[i].name; - li.appendChild(text); - - gameMenu.appendChild(li); - - gameTable.addRow(loot.settings.games[i]); - } - - /* Highlight game in menu. */ - updateSelectedGame(); - - 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 + gameSelect.value = loot.settings.game; + document.getElementById('languageSelect').value = loot.settings.language; + document.getElementById('debugVerbositySelect').value = loot.settings.debugVerbosity; + }).catch(function(err) { + console.log(err); }); } function getPriorityString(plugin) { @@ -732,7 +779,7 @@ function updateInterfaceWithGameInfo(response) { loot.game = JSON.parse(response, jsonToPlugin); } catch (e) { console.log(e); - console.log('Response: ' + response); + console.log('getGameData response: ' + response); } var totalMessageNo = 0; @@ -796,17 +843,6 @@ function updateInterfaceWithGameInfo(response) { // Now set up event handlers, as they depend on the plugin cards having been created. setupEventHandlers(); } -function getGameData() { - // Create and send a new query. - var request_id = window.cefQuery({ - request: 'getGameData', - persistent: false, - onSuccess: updateInterfaceWithGameInfo, - onFailure: function(error_code, error_message) { - showMessageBox('error', "Error", "Error code: " + error_code + "; " + error_message); - } - }); -} require.config({ baseUrl: "js", @@ -819,8 +855,7 @@ require(['marked', 'order!custom', 'order!plugin'], function(response) { tables: true, sanitize: true }); - initGlobalVars(); - getGameData(); + initVars(); if (isStorageSupported()) { loadSettings(); } diff --git a/src/gui/app.cpp b/src/gui/app.cpp index 3383ceee..16bb66a1 100644 --- a/src/gui/app.cpp +++ b/src/gui/app.cpp @@ -247,6 +247,9 @@ namespace loot { Game& LootState::CurrentGame() { return _games[_currentGame]; } + std::vector& LootState::InstalledGames() { + return _games; + } const YAML::Node& LootState::GetSettings() const { return _settings; diff --git a/src/gui/app.h b/src/gui/app.h index 1737d5a3..110dd626 100644 --- a/src/gui/app.h +++ b/src/gui/app.h @@ -70,12 +70,13 @@ namespace loot { void ChangeGame(const std::string& newGameFolder); Game& CurrentGame(); + std::vector& InstalledGames(); const YAML::Node& GetSettings() const; private: YAML::Node _settings; - std::vector _games; + std::vector _games; size_t _currentGame; }; diff --git a/src/gui/handler.cpp b/src/gui/handler.cpp index 7f8347f4..b68e7781 100644 --- a/src/gui/handler.cpp +++ b/src/gui/handler.cpp @@ -110,6 +110,10 @@ namespace loot { callback->Success(GetGameTypes()); return true; } + else if (request == "getInstalledGames") { + callback->Success(GetInstalledGames()); + return true; + } else if (request == "getGameData") { BOOST_LOG_TRIVIAL(info) << "Setting LOOT window title bar text to include game name: " << g_app_state.CurrentGame().Name(); #if defined(OS_WIN) @@ -136,11 +140,11 @@ namespace loot { return false; } - const std::string requestName = req["name"].as(); + const string requestName = req["name"].as(); if (requestName == "find") { // Has one arg, which is the search string. - const std::string search = req["args"][0].as(); + const string search = req["args"][0].as(); // In case there is a search already running, cancel it. browser->GetHost()->StopFinding(true); @@ -156,7 +160,7 @@ namespace loot { } else if (requestName == "changeGame") { // Has one arg, which is the folder name of the new game. - const std::string folder = req["args"][0].as(); + const string folder = req["args"][0].as(); BOOST_LOG_TRIVIAL(info) << "Changing game to that with folder: " << folder; g_app_state.ChangeGame(folder); @@ -228,6 +232,16 @@ namespace loot { return JSON::stringify(temp); } + std::string Handler::GetInstalledGames() { + BOOST_LOG_TRIVIAL(info) << "Getting LOOT's detected games."; + YAML::Node temp; + for (const auto &game : g_app_state.InstalledGames()) { + if (game.IsInstalled()) + temp.push_back(game.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. diff --git a/src/gui/handler.h b/src/gui/handler.h index a26873a4..6e5a0737 100644 --- a/src/gui/handler.h +++ b/src/gui/handler.h @@ -53,6 +53,7 @@ namespace loot { std::string GetSettings(); std::string GetLanguages(); std::string GetGameTypes(); + std::string GetInstalledGames(); std::string GetGameData(); };