From 268e39d12a968134bf916d034021972d3f8407e7 Mon Sep 17 00:00:00 2001 From: Keith Stellyes Date: Wed, 21 Oct 2020 10:53:22 -0700 Subject: [PATCH 1/6] GOG installer extraction for POSIX --- data/language/en-GB.txt | 9 ++++ debian/control | 1 + distribution/changelog.txt | 1 + readme.md | 1 + src/openrct2-ui/UiContext.Android.cpp | 11 ++++ src/openrct2-ui/UiContext.Linux.cpp | 69 ++++++++++++++++++++++++ src/openrct2-ui/UiContext.Win32.cpp | 11 ++++ src/openrct2-ui/UiContext.cpp | 10 ++++ src/openrct2-ui/UiContext.h | 4 ++ src/openrct2-ui/UiContext.macOS.mm | 11 ++++ src/openrct2/config/Config.cpp | 78 ++++++++++++++++++++++++++- src/openrct2/localisation/StringIds.h | 10 ++++ src/openrct2/ui/DummyUiContext.cpp | 10 ++++ src/openrct2/ui/UiContext.h | 5 ++ 14 files changed, 229 insertions(+), 2 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 1f4b3466a3..8533df7a85 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3651,6 +3651,15 @@ STR_6396 :Disable screensaver and monitor power saving STR_6397 :If checked, screensaver and other monitor power saving features will be inhibited while OpenRCT2 is running. STR_6398 :File contains unsupported ride types. Please update to a newer version of OpenRCT2. STR_6399 :OpenRCT2 needs files from the original RollerCoaster Tycoon 2 in order to work. Please set the “game_path” variable in config.ini to the directory where you installed RollerCoaster Tycoon 2, then restart OpenRCT2. +STR_6400 :I have the GOG installer for RollerCoaster Tycoon 2 downloaded, but it is not installed +STR_6401 :I have RollerCoaster Tycoon 2 installed already +STR_6402 :OpenRCT2 Data Setup +STR_6403 :Select which applies best to you +STR_6404 :Please select GOG RollerCoaster Tycoon 2 installer +STR_6405 :Select GOG Installer +STR_6406 :GOG RollerCoaster Tycoon 2 Installer +STR_6407 :This may take a few minutes +STR_6408 :Please install innoextract to extract GOG Installer ############# # Scenarios # diff --git a/debian/control b/debian/control index 9c3d0a27de..06cf51d293 100644 --- a/debian/control +++ b/debian/control @@ -12,6 +12,7 @@ Homepage: https://openrct2.io/ Vcs-Browser: https://github.com/OpenRCT2/OpenRCT2 Vcs-Git: https://github.com/OpenRCT2/OpenRCT2 Depends: ${shlibs:Depends}, ${misc:Depends} +Recommends: innoextract Description: An open source re-implementation of Roller Coaster Tycoon 2. An open source clone of RollerCoaster Tycoon 2 built by decompiling the original game one bit at a time. diff --git a/distribution/changelog.txt b/distribution/changelog.txt index bc8b39adff..0ad984c819 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -36,6 +36,7 @@ 0.3.2 (2020-11-01) ------------------------------------------------------------------------ +- Feature: [#12307] For Linux users, allow extraction of GOG installer via innoextract. - Feature: [#12110] Add Hybrid Coaster (Rocky Mountain Construction I-Box) track type. - Feature: [#12999] .sea (RCT Classic) scenarios are now listed in the “New Scenario” dialog. - Feature: [#13000] objective_options command for console. diff --git a/readme.md b/readme.md index bc2bb6ef11..27e3f5664b 100644 --- a/readme.md +++ b/readme.md @@ -116,6 +116,7 @@ The program can also be built as a command line program using CMake. This type o - gl (commonly provided by Mesa or GPU vendors; only for UI client, can be disabled) - duktape (unless scripting is disabled) - cmake +- innoextract (optional runtime dependency; used for GOG installer extraction during setup) Refer to https://github.com/OpenRCT2/OpenRCT2/wiki/Building-OpenRCT2-on-Linux#required-packages-general for more information about installing the packages. diff --git a/src/openrct2-ui/UiContext.Android.cpp b/src/openrct2-ui/UiContext.Android.cpp index c278f2dd80..4ba2a368fb 100644 --- a/src/openrct2-ui/UiContext.Android.cpp +++ b/src/openrct2-ui/UiContext.Android.cpp @@ -40,6 +40,17 @@ namespace OpenRCT2::Ui return false; } + bool HasMenuSupport() override + { + return false; + } + + int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) override + { + return -1; + } + void ShowMessageBox(SDL_Window* window, const std::string& message) override { log_verbose(message.c_str()); diff --git a/src/openrct2-ui/UiContext.Linux.cpp b/src/openrct2-ui/UiContext.Linux.cpp index 9b7b2e6c6d..3eacd67048 100644 --- a/src/openrct2-ui/UiContext.Linux.cpp +++ b/src/openrct2-ui/UiContext.Linux.cpp @@ -16,6 +16,7 @@ # include # include # include +# include # include # include # include @@ -256,6 +257,74 @@ namespace OpenRCT2::Ui return GetDialogApp(&dummy) != DIALOG_TYPE::NONE; } + bool HasMenuSupport() override + { + std::string executablePath; + DIALOG_TYPE dtype = GetDialogApp(&executablePath); + return dtype != DIALOG_TYPE::NONE; + } + + int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) override + { + std::string executablePath; + DIALOG_TYPE dtype = GetDialogApp(&executablePath); + + size_t longest_string = 0; + for (const auto& option : options) + { + if (option.size() > longest_string) + { + longest_string = option.size(); + } + } + + // zenity and kdialog don't support automatic scaling, this is an approximation + int width = (longest_string + 1) * 8; + int height = (options.size() + 1) * 8; + + switch (dtype) + { + case DIALOG_TYPE::ZENITY: + { + auto sb = StringBuilder(); + sb.Append(reinterpret_cast( + String::Format("zenity --list --column '' --width=%d --height=%d", width, height))); + for (const auto& option : options) + { + sb.Append(reinterpret_cast(String::Format(" '%s'", option.c_str()))); + } + sb.Append( + reinterpret_cast(String::Format(" --title '%s' --text '%s'", title.c_str(), text.c_str()))); + + std::string buff; + Platform::Execute(sb.GetBuffer(), &buff); + return std::find(options.begin(), options.end(), buff) - options.begin(); + } + case DIALOG_TYPE::KDIALOG: + { + auto sb = StringBuilder(); + sb.Append(reinterpret_cast( + String::Format("kdialog --geometry %dx%d --title '%s' --menu ", width, height, title.c_str()))); + sb.Append(reinterpret_cast(String::Format(" '%s'", text.c_str()))); + for (const auto& option : options) + { + sb.Append(reinterpret_cast(String::Format(" '%s' '%s'", option.c_str(), option.c_str()))); + } + + std::string buff; + Platform::Execute(sb.GetBuffer(), &buff); + return std::find(options.begin(), options.end(), buff) - options.begin(); + } + default: + { + break; + } + } + + return options.size(); + } + private: static DIALOG_TYPE GetDialogApp(std::string* executablePath) { diff --git a/src/openrct2-ui/UiContext.Win32.cpp b/src/openrct2-ui/UiContext.Win32.cpp index b5d3a11d16..9ffc58d766 100644 --- a/src/openrct2-ui/UiContext.Win32.cpp +++ b/src/openrct2-ui/UiContext.Win32.cpp @@ -95,6 +95,17 @@ namespace OpenRCT2::Ui MessageBoxW(hwnd, messageW.c_str(), L"OpenRCT2", MB_OK); } + bool HasMenuSupport() override + { + return false; + } + + int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) override + { + return -1; + } + void OpenFolder(const std::string& path) override { std::wstring pathW = String::ToWideChar(path); diff --git a/src/openrct2-ui/UiContext.cpp b/src/openrct2-ui/UiContext.cpp index b79b1754d2..c84ed7657c 100644 --- a/src/openrct2-ui/UiContext.cpp +++ b/src/openrct2-ui/UiContext.cpp @@ -604,6 +604,16 @@ public: _platformUiContext->ShowMessageBox(_window, message); } + bool HasMenuSupport() override + { + return _platformUiContext->HasMenuSupport(); + } + + int32_t ShowMenuDialog(const std::vector& options, const std::string& title, const std::string& text) override + { + return _platformUiContext->ShowMenuDialog(options, title, text); + } + void OpenFolder(const std::string& path) override { _platformUiContext->OpenFolder(path); diff --git a/src/openrct2-ui/UiContext.h b/src/openrct2-ui/UiContext.h index ed1904f0d9..cd2b9fb339 100644 --- a/src/openrct2-ui/UiContext.h +++ b/src/openrct2-ui/UiContext.h @@ -12,6 +12,7 @@ #include #include #include +#include struct SDL_Window; @@ -33,6 +34,9 @@ namespace OpenRCT2 virtual bool IsSteamOverlayAttached() abstract; virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract; + virtual bool HasMenuSupport() abstract; + virtual int ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) abstract; virtual void OpenFolder(const std::string& path) abstract; virtual void OpenURL(const std::string& url) abstract; diff --git a/src/openrct2-ui/UiContext.macOS.mm b/src/openrct2-ui/UiContext.macOS.mm index cf84f450a9..c62158990c 100644 --- a/src/openrct2-ui/UiContext.macOS.mm +++ b/src/openrct2-ui/UiContext.macOS.mm @@ -64,6 +64,17 @@ namespace OpenRCT2::Ui } } + bool HasMenuSupport() override + { + return false; + } + + int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) override + { + return -1; + } + void OpenFolder(const std::string& path) override { @autoreleasepool diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 7e60af7326..01dac05cad 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -11,6 +11,7 @@ #include "../Context.h" #include "../OpenRCT2.h" +#include "../PlatformEnvironment.h" #include "../core/Console.hpp" #include "../core/File.h" #include "../core/FileStream.h" @@ -721,6 +722,21 @@ namespace Config } return std::string(); } + + static bool ExtractGogInstaller(const utf8* installerPath, const utf8* targetPath) + { + std::string path; + std::string output; + + if (!Platform::FindApp("innoextract", &path)) + { + GetContext()->GetUiContext()->ShowMessageBox(format_string(STR_INSTALL_INNOEXTRACT, nullptr)); + return false; + } + int32_t exit_status = Platform::Execute( + String::Format("%s '%s' --exclude-temp --output-dir '%s'", path.c_str(), installerPath, targetPath), &output); + return exit_status == 0; + } } // namespace Config GeneralConfiguration gConfigGeneral; @@ -816,13 +832,71 @@ bool config_find_or_browse_install_directory() while (true) { uiContext->ShowMessageBox(format_string(STR_NEEDS_RCT2_FILES, nullptr)); + std::string gog = language_get_string(STR_OWN_ON_GOG); + std::string hdd = language_get_string(STR_INSTALLED_ON_HDD); - std::string installPath = uiContext->ShowDirectoryDialog(format_string(STR_PICK_RCT2_DIR, nullptr)); + std::vector options; + std::string chosenOption; + + if (uiContext->HasMenuSupport()) + { + options.push_back(hdd); + options.push_back(gog); + int optionIndex = uiContext->ShowMenuDialog( + options, language_get_string(STR_OPENRCT2_SETUP), language_get_string(STR_WHICH_APPLIES_BEST)); + if (optionIndex < 0 || static_cast(optionIndex) >= options.size()) + { + // graceful fallback if app errors or user exits out of window + chosenOption = hdd; + } + else + { + chosenOption = options[optionIndex]; + } + } + + chosenOption = hdd; + + std::string installPath; + if (chosenOption == hdd) + { + installPath = uiContext->ShowDirectoryDialog(language_get_string(STR_PICK_RCT2_DIR)); + } + else if (chosenOption == gog) + { + uiContext->ShowMessageBox(language_get_string(STR_PLEASE_SELECT_GOG_INSTALLER)); + utf8 gogPath[4096]; + std::string dest = Path::Combine( + GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::CONFIG), "rct2"); + file_dialog_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.type = FileDialogType::Open; + desc.title = language_get_string(STR_SELECT_GOG_INSTALLER); + desc.filters[0].name = language_get_string(STR_GOG_INSTALLER); + desc.filters[0].pattern = "*.exe"; + desc.filters[1].name = language_get_string(STR_ALL_FILES); + desc.filters[1].pattern = "*"; + desc.filters[2].name = nullptr; + + desc.initial_directory = Platform::GetFolderPath(SPECIAL_FOLDER::USER_HOME).c_str(); + + if (!platform_open_common_file_dialog(gogPath, &desc, 4096)) + { + return false; + } + + uiContext->ShowMessageBox(language_get_string(STR_THIS_WILL_TAKE_A_FEW_MINUTES)); + if (!Config::ExtractGogInstaller(gogPath, dest.c_str())) + { + return false; + } + + installPath = Path::Combine(dest, "app"); + } if (installPath.empty()) { return false; } - Memory::Free(gConfigGeneral.rct2_path); gConfigGeneral.rct2_path = String::Duplicate(installPath.c_str()); diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 9d00e48a67..cd56a7ea6a 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3905,6 +3905,16 @@ enum STR_NEEDS_RCT2_FILES_MANUAL = 6399, + STR_OWN_ON_GOG = 6400, + STR_INSTALLED_ON_HDD = 6401, + STR_OPENRCT2_SETUP = 6402, + STR_WHICH_APPLIES_BEST = 6403, + STR_PLEASE_SELECT_GOG_INSTALLER = 6404, + STR_SELECT_GOG_INSTALLER = 6405, + STR_GOG_INSTALLER = 6406, + STR_THIS_WILL_TAKE_A_FEW_MINUTES = 6407, + STR_INSTALL_INNOEXTRACT = 6408, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings }; diff --git a/src/openrct2/ui/DummyUiContext.cpp b/src/openrct2/ui/DummyUiContext.cpp index b636c8eef4..9f2a8915e7 100644 --- a/src/openrct2/ui/DummyUiContext.cpp +++ b/src/openrct2/ui/DummyUiContext.cpp @@ -90,6 +90,16 @@ namespace OpenRCT2::Ui void ShowMessageBox(const std::string& /*message*/) override { } + bool HasMenuSupport() override + { + return false; + } + + int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) override + { + return options.size(); + } void OpenFolder(const std::string& /*path*/) override { } diff --git a/src/openrct2/ui/UiContext.h b/src/openrct2/ui/UiContext.h index e169ccfd9b..2668e1ac9f 100644 --- a/src/openrct2/ui/UiContext.h +++ b/src/openrct2/ui/UiContext.h @@ -113,6 +113,11 @@ namespace OpenRCT2 virtual void TriggerResize() abstract; virtual void ShowMessageBox(const std::string& message) abstract; + + virtual bool HasMenuSupport() abstract; + // Creates a menu with a series of options, returns the index of the selected option + virtual int ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) abstract; virtual void OpenFolder(const std::string& path) abstract; virtual void OpenURL(const std::string& url) abstract; virtual std::string ShowFileDialog(const FileDialogDesc& desc) abstract; From 72cc8df3956a25e89a2a1578fcaef39ec4a51d8f Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Sat, 12 Dec 2020 23:31:02 +0100 Subject: [PATCH 2/6] Stub FindApp on Windows --- src/openrct2/platform/Platform.Win32.cpp | 7 +++++++ src/openrct2/platform/Platform.macOS.mm | 1 - 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index 59110fa973..47648220f6 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -30,6 +30,7 @@ # endif # include "../OpenRCT2.h" +# include "../common.h" # include "../core/Path.hpp" # include "../core/String.hpp" # include "Platform2.h" @@ -520,6 +521,12 @@ namespace Platform { return false; } + + bool FindApp(const std::string& app, std::string* output) + { + log_warning("FindApp not implemented for Windows!"); + return false; + } } // namespace Platform #endif diff --git a/src/openrct2/platform/Platform.macOS.mm b/src/openrct2/platform/Platform.macOS.mm index de9310adcd..74aa0b7574 100644 --- a/src/openrct2/platform/Platform.macOS.mm +++ b/src/openrct2/platform/Platform.macOS.mm @@ -130,7 +130,6 @@ namespace Platform } return false; } - } #endif From 9058f00bfaa93430360b2b6d8dbdd1c6b8401374 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Sun, 13 Dec 2020 16:02:57 +0100 Subject: [PATCH 3/6] Strictly use int32_t for ShowMenuDialog --- src/openrct2-ui/UiContext.h | 2 +- src/openrct2/ui/DummyUiContext.cpp | 2 +- src/openrct2/ui/UiContext.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/openrct2-ui/UiContext.h b/src/openrct2-ui/UiContext.h index cd2b9fb339..4917703eae 100644 --- a/src/openrct2-ui/UiContext.h +++ b/src/openrct2-ui/UiContext.h @@ -35,7 +35,7 @@ namespace OpenRCT2 virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract; virtual bool HasMenuSupport() abstract; - virtual int ShowMenuDialog( + virtual int32_t ShowMenuDialog( const std::vector& options, const std::string& title, const std::string& text) abstract; virtual void OpenFolder(const std::string& path) abstract; diff --git a/src/openrct2/ui/DummyUiContext.cpp b/src/openrct2/ui/DummyUiContext.cpp index 9f2a8915e7..d0a40d1917 100644 --- a/src/openrct2/ui/DummyUiContext.cpp +++ b/src/openrct2/ui/DummyUiContext.cpp @@ -98,7 +98,7 @@ namespace OpenRCT2::Ui int32_t ShowMenuDialog( const std::vector& options, const std::string& title, const std::string& text) override { - return options.size(); + return static_cast(options.size()); } void OpenFolder(const std::string& /*path*/) override { diff --git a/src/openrct2/ui/UiContext.h b/src/openrct2/ui/UiContext.h index 2668e1ac9f..0f557defef 100644 --- a/src/openrct2/ui/UiContext.h +++ b/src/openrct2/ui/UiContext.h @@ -116,7 +116,7 @@ namespace OpenRCT2 virtual bool HasMenuSupport() abstract; // Creates a menu with a series of options, returns the index of the selected option - virtual int ShowMenuDialog( + virtual int32_t ShowMenuDialog( const std::vector& options, const std::string& title, const std::string& text) abstract; virtual void OpenFolder(const std::string& path) abstract; virtual void OpenURL(const std::string& url) abstract; From 09c6339bd487bc83b7cd651cff83f7008ecaa2be Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Sun, 13 Dec 2020 17:41:24 +0100 Subject: [PATCH 4/6] Stub Execute() for Win32 --- src/openrct2/platform/Platform.Win32.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index 47648220f6..f07c599bc5 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -524,9 +524,15 @@ namespace Platform bool FindApp(const std::string& app, std::string* output) { - log_warning("FindApp not implemented for Windows!"); + log_warning("FindApp() not implemented for Windows!"); return false; } + + int32_t Execute(const std::string& command, std::string* output) + { + log_warning("Execute() not implemented for Windows!"); + return -1; + } } // namespace Platform #endif From 07c3a930e4514545f1e6aff890e3b56fc8e09416 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Thu, 24 Dec 2020 18:07:58 +0100 Subject: [PATCH 5/6] Apply review requests --- data/language/en-GB.txt | 6 +++--- distribution/changelog.txt | 2 +- src/openrct2/config/Config.cpp | 6 ++++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 8533df7a85..935493ef8b 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3651,15 +3651,15 @@ STR_6396 :Disable screensaver and monitor power saving STR_6397 :If checked, screensaver and other monitor power saving features will be inhibited while OpenRCT2 is running. STR_6398 :File contains unsupported ride types. Please update to a newer version of OpenRCT2. STR_6399 :OpenRCT2 needs files from the original RollerCoaster Tycoon 2 in order to work. Please set the “game_path” variable in config.ini to the directory where you installed RollerCoaster Tycoon 2, then restart OpenRCT2. -STR_6400 :I have the GOG installer for RollerCoaster Tycoon 2 downloaded, but it is not installed +STR_6400 :I have the GOG offline installer for RollerCoaster Tycoon 2 downloaded, but it is not installed STR_6401 :I have RollerCoaster Tycoon 2 installed already STR_6402 :OpenRCT2 Data Setup STR_6403 :Select which applies best to you STR_6404 :Please select GOG RollerCoaster Tycoon 2 installer STR_6405 :Select GOG Installer STR_6406 :GOG RollerCoaster Tycoon 2 Installer -STR_6407 :This may take a few minutes -STR_6408 :Please install innoextract to extract GOG Installer +STR_6407 :This may take a few minutes. +STR_6408 :Please install innoextract to extract GOG Installer. ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 0ad984c819..b74c8a4785 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -3,6 +3,7 @@ - Feature: [#6677] Add Discord RPC to macOS builds. - Feature: [#6844] Enhanced track designer with ability to add/remove scenery and footpaths. - Feature: [#11859] Add on-ride photo section to Air Powered Vertical and Reverse Freefall Coaster. +- Feature: [#12307] Allow extraction of GOG installer via innoextract (for Linux users). - Feature: [#13057] Make GameAction flags accessible by plugins. - Feature: [#13078] [Plugin] Add colour picker widget. - Feature: [#13376] Open custom window at specified tab. @@ -36,7 +37,6 @@ 0.3.2 (2020-11-01) ------------------------------------------------------------------------ -- Feature: [#12307] For Linux users, allow extraction of GOG installer via innoextract. - Feature: [#12110] Add Hybrid Coaster (Rocky Mountain Construction I-Box) track type. - Feature: [#12999] .sea (RCT Classic) scenarios are now listed in the “New Scenario” dialog. - Feature: [#13000] objective_options command for console. diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 01dac05cad..a435b9d126 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -854,8 +854,10 @@ bool config_find_or_browse_install_directory() chosenOption = options[optionIndex]; } } - - chosenOption = hdd; + else + { + chosenOption = hdd; + } std::string installPath; if (chosenOption == hdd) From 52bc650abf73925d5de46b79d61b185187e48d53 Mon Sep 17 00:00:00 2001 From: Gymnasiast Date: Sun, 3 Jan 2021 18:40:02 +0100 Subject: [PATCH 6/6] Improve feedback when selecting the wrong file --- data/language/en-GB.txt | 5 ++- src/openrct2/config/Config.cpp | 62 ++++++++++++++++++--------- src/openrct2/localisation/StringIds.h | 1 + 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 935493ef8b..fa8dc310d4 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3655,11 +3655,12 @@ STR_6400 :I have the GOG offline installer for RollerCoaster Tycoon 2 downloa STR_6401 :I have RollerCoaster Tycoon 2 installed already STR_6402 :OpenRCT2 Data Setup STR_6403 :Select which applies best to you -STR_6404 :Please select GOG RollerCoaster Tycoon 2 installer +STR_6404 :Please select the GOG RollerCoaster Tycoon 2 installer. STR_6405 :Select GOG Installer STR_6406 :GOG RollerCoaster Tycoon 2 Installer STR_6407 :This may take a few minutes. -STR_6408 :Please install innoextract to extract GOG Installer. +STR_6408 :Please install “innoextract” to extract GOG Installer, then restart OpenRCT2. +STR_6409 :The selected file is not the offline GOG Installer for RollerCoaster Tycoon 2. You may have downloaded the GOG Galaxy downloader stub or selected the wrong file. ############# # Scenarios # diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index a435b9d126..b1a241509f 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -723,6 +723,23 @@ namespace Config return std::string(); } + static bool SelectGogInstaller(utf8* installerPath) + { + file_dialog_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.type = FileDialogType::Open; + desc.title = language_get_string(STR_SELECT_GOG_INSTALLER); + desc.filters[0].name = language_get_string(STR_GOG_INSTALLER); + desc.filters[0].pattern = "*.exe"; + desc.filters[1].name = language_get_string(STR_ALL_FILES); + desc.filters[1].pattern = "*"; + desc.filters[2].name = nullptr; + + desc.initial_directory = Platform::GetFolderPath(SPECIAL_FOLDER::USER_HOME).c_str(); + + return platform_open_common_file_dialog(installerPath, &desc, 4096); + } + static bool ExtractGogInstaller(const utf8* installerPath, const utf8* targetPath) { std::string path; @@ -730,11 +747,12 @@ namespace Config if (!Platform::FindApp("innoextract", &path)) { - GetContext()->GetUiContext()->ShowMessageBox(format_string(STR_INSTALL_INNOEXTRACT, nullptr)); + log_error("Please install innoextract to extract files from GOG."); return false; } int32_t exit_status = Platform::Execute( String::Format("%s '%s' --exclude-temp --output-dir '%s'", path.c_str(), installerPath, targetPath), &output); + log_info("Exit status %d", exit_status); return exit_status == 0; } } // namespace Config @@ -866,31 +884,33 @@ bool config_find_or_browse_install_directory() } else if (chosenOption == gog) { - uiContext->ShowMessageBox(language_get_string(STR_PLEASE_SELECT_GOG_INSTALLER)); - utf8 gogPath[4096]; - std::string dest = Path::Combine( - GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::CONFIG), "rct2"); - file_dialog_desc desc; - memset(&desc, 0, sizeof(desc)); - desc.type = FileDialogType::Open; - desc.title = language_get_string(STR_SELECT_GOG_INSTALLER); - desc.filters[0].name = language_get_string(STR_GOG_INSTALLER); - desc.filters[0].pattern = "*.exe"; - desc.filters[1].name = language_get_string(STR_ALL_FILES); - desc.filters[1].pattern = "*"; - desc.filters[2].name = nullptr; - - desc.initial_directory = Platform::GetFolderPath(SPECIAL_FOLDER::USER_HOME).c_str(); - - if (!platform_open_common_file_dialog(gogPath, &desc, 4096)) + // Check if innoextract is installed. If not, prompt the user to install it. + std::string dummy; + if (!Platform::FindApp("innoextract", &dummy)) { + uiContext->ShowMessageBox(format_string(STR_INSTALL_INNOEXTRACT, nullptr)); return false; } - uiContext->ShowMessageBox(language_get_string(STR_THIS_WILL_TAKE_A_FEW_MINUTES)); - if (!Config::ExtractGogInstaller(gogPath, dest.c_str())) + const std::string dest = Path::Combine( + GetContext()->GetPlatformEnvironment()->GetDirectoryPath(DIRBASE::CONFIG), "rct2"); + + while (true) { - return false; + uiContext->ShowMessageBox(language_get_string(STR_PLEASE_SELECT_GOG_INSTALLER)); + utf8 gogPath[4096]; + if (!Config::SelectGogInstaller(gogPath)) + { + // The user clicked "Cancel", so stop trying. + return false; + } + + uiContext->ShowMessageBox(language_get_string(STR_THIS_WILL_TAKE_A_FEW_MINUTES)); + + if (Config::ExtractGogInstaller(gogPath, dest.c_str())) + break; + + uiContext->ShowMessageBox(language_get_string(STR_NOT_THE_GOG_INSTALLER)); } installPath = Path::Combine(dest, "app"); diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index cd56a7ea6a..b1b959b217 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3914,6 +3914,7 @@ enum STR_GOG_INSTALLER = 6406, STR_THIS_WILL_TAKE_A_FEW_MINUTES = 6407, STR_INSTALL_INNOEXTRACT = 6408, + STR_NOT_THE_GOG_INSTALLER = 6409, // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings