diff --git a/src/OpenRCT2.cpp b/src/OpenRCT2.cpp index f870399a0b..94c3551557 100644 --- a/src/OpenRCT2.cpp +++ b/src/OpenRCT2.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include "core/Console.hpp" #include "core/Guard.hpp" #include "core/String.hpp" #include "network/network.h" @@ -82,7 +83,6 @@ namespace OpenRCT2 /** If set, will end the OpenRCT2 game loop. Intentially private to this module so that the flag can not be set back to false. */ static bool _finished; - static void SetupEnvironment(); static void SetVersionInfoString(); static bool ShouldRunVariableFrame(); static void RunGameLoop(); @@ -114,47 +114,31 @@ extern "C" Guard::Assert(gHashCTX != nullptr, "EVP_MD_CTX_create failed"); #endif // DISABLE_NETWORK - utf8 userPath[MAX_PATH]; - platform_resolve_openrct_data_path(); - platform_resolve_user_data_path(); - platform_get_user_directory(userPath, NULL, sizeof(userPath)); - if (!platform_ensure_directory_exists(userPath)) + crash_init(); + + // Sets up the environment OpenRCT2 is running in, e.g. directory paths + OpenRCT2::_env = OpenRCT2::SetupEnvironment(); + if (OpenRCT2::_env == nullptr) { - log_fatal("Could not create user directory (do you have write access to your documents folder?)"); return false; } - crash_init(); - if (!rct2_interop_setup_segment()) { log_fatal("Unable to load RCT2 data sector"); return false; } - openrct2_set_exe_path(); - - config_set_defaults(); - if (!config_open_default()) - { - if (!config_find_or_browse_install_directory()) - { - gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); - config_save_default(); - utf8 path[MAX_PATH]; - config_get_default_path(path, sizeof(path)); - log_fatal("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path); - return false; - } - } - - gOpenRCT2ShowChangelog = true; - if (gConfigGeneral.last_run_version != NULL && (strcmp(gConfigGeneral.last_run_version, OPENRCT2_VERSION) == 0)) + if (gConfigGeneral.last_run_version != nullptr && String::Equals(gConfigGeneral.last_run_version, OPENRCT2_VERSION)) { gOpenRCT2ShowChangelog = false; } - gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); - config_save_default(); + else + { + gOpenRCT2ShowChangelog = true; + gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); + config_save_default(); + } // TODO add configuration option to allow multiple instances // if (!gOpenRCT2Headless && !platform_lock_single_instance()) { @@ -162,17 +146,6 @@ extern "C" // return false; // } - if (!rct2_init_directories()) - { - return false; - } - if (!rct2_startup_checks()) - { - return false; - } - - // Sets up the environment OpenRCT2 is running in, e.g. directory paths - OpenRCT2::SetupEnvironment(); IObjectRepository * objRepo = CreateObjectRepository(OpenRCT2::_env); ITrackDesignRepository * tdRepo = CreateTrackDesignRepository(OpenRCT2::_env); CreateScenarioRepository(OpenRCT2::_env); @@ -190,7 +163,7 @@ extern "C" // TODO Ideally we want to delay this until we show the title so that we can // still open the game window and draw a progress screen for the creation // of the object cache. - objRepo->LoadOrConstruct(false); + objRepo->LoadOrConstruct(); // TODO Like objects, this can take a while if there are a lot of track designs // its also really something really we might want to do in the background @@ -328,8 +301,43 @@ extern "C" namespace OpenRCT2 { - static void SetupEnvironment() + IPlatformEnvironment * SetupEnvironment() { + utf8 userPath[MAX_PATH]; + platform_resolve_openrct_data_path(); + platform_resolve_user_data_path(); + platform_get_user_directory(userPath, NULL, sizeof(userPath)); + if (!platform_ensure_directory_exists(userPath)) + { + Console::Error::WriteLine("Could not create user directory (do you have write access to your documents folder?)"); + return false; + } + openrct2_set_exe_path(); + + config_set_defaults(); + if (!config_open_default()) + { + if (!config_find_or_browse_install_directory()) + { + gConfigGeneral.last_run_version = String::Duplicate(OPENRCT2_VERSION); + config_save_default(); + utf8 path[MAX_PATH]; + config_get_default_path(path, sizeof(path)); + Console::Error::WriteLine("An RCT2 install directory must be specified! Please edit \"game_path\" in %s.", path); + return nullptr; + } + config_save_default(); + } + + if (!rct2_init_directories()) + { + return false; + } + if (!rct2_startup_checks()) + { + return false; + } + utf8 path[260]; std::string basePaths[4]; basePaths[(size_t)DIRBASE::RCT2] = std::string(gRCT2AddressAppPath); @@ -337,7 +345,9 @@ namespace OpenRCT2 basePaths[(size_t)DIRBASE::OPENRCT2] = std::string(path); platform_get_user_directory(path, nullptr, sizeof(path)); basePaths[(size_t)DIRBASE::USER] = std::string(path); - OpenRCT2::_env = CreatePlatformEnvironment(basePaths); + + IPlatformEnvironment * env = CreatePlatformEnvironment(basePaths); + return env; } static void SetVersionInfoString() diff --git a/src/OpenRCT2.h b/src/OpenRCT2.h index 4a7e965e01..a601dd6798 100644 --- a/src/OpenRCT2.h +++ b/src/OpenRCT2.h @@ -40,6 +40,17 @@ enum STARTUP_ACTION STARTUP_ACTION_EDIT }; +#ifdef __cplusplus + +interface IPlatformEnvironment; + +namespace OpenRCT2 +{ + IPlatformEnvironment * SetupEnvironment(); +} + +#endif + #ifdef __cplusplus extern "C" { diff --git a/src/cmdline/RootCommands.cpp b/src/cmdline/RootCommands.cpp index 6990b75134..2d684229b6 100644 --- a/src/cmdline/RootCommands.cpp +++ b/src/cmdline/RootCommands.cpp @@ -21,7 +21,6 @@ extern "C" { #include "../config.h" - #include "../OpenRCT2.h" #include "../platform/crash.h" } @@ -31,6 +30,7 @@ extern "C" #include "../core/String.hpp" #include "../network/network.h" #include "../object/ObjectRepository.h" +#include "../OpenRCT2.h" #include "CommandLine.hpp" #ifdef USE_BREAKPAD @@ -67,7 +67,6 @@ static utf8 * _userDataPath = nullptr; static utf8 * _openrctDataPath = nullptr; static utf8 * _rct2DataPath = nullptr; static bool _silentBreakpad = false; -static bool _forceScan = false; static const CommandLineOptionDefinition StandardOptions[] { @@ -91,7 +90,6 @@ static const CommandLineOptionDefinition StandardOptions[] #ifdef USE_BREAKPAD { CMDLINE_TYPE_SWITCH, &_silentBreakpad, NAC, "silent-breakpad", "make breakpad crash reporting silent" }, #endif // USE_BREAKPAD - { CMDLINE_TYPE_SWITCH, &_forceScan, 'f', "force-scan", "forces scanning of object repository" }, OptionTableEnd }; @@ -101,6 +99,7 @@ static exitcode_t HandleCommandIntro(CommandLineArgEnumerator * enumerator); static exitcode_t HandleCommandHost(CommandLineArgEnumerator * enumerator); static exitcode_t HandleCommandJoin(CommandLineArgEnumerator * enumerator); static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator); +static exitcode_t HandleCommandScanObjects(CommandLineArgEnumerator * enumerator); #if defined(__WINDOWS__) && !defined(__MINGW32__) @@ -131,6 +130,7 @@ const CommandLineCommand CommandLine::RootCommands[] #endif DefineCommand("set-rct2", "", StandardOptions, HandleCommandSetRCT2), DefineCommand("convert", " ", StandardOptions, CommandLine::HandleCommandConvert), + DefineCommand("scan-objects", "", StandardOptions, HandleCommandScanObjects), #if defined(__WINDOWS__) && !defined(__MINGW32__) DefineCommand("register-shell", "", RegisterShellOptions, HandleCommandRegisterShell), @@ -197,14 +197,6 @@ exitcode_t CommandLine::HandleCommandDefault() gOpenRCT2Headless = _headless; gOpenRCT2SilentBreakpad = _silentBreakpad || _headless; - if (_forceScan) - { - IObjectRepository * objectRepository = GetObjectRepository(); - objectRepository->LoadOrConstruct(true); - - result = EXITCODE_OK; - } - if (_userDataPath != nullptr) { String::Set(gCustomUserDataPath, sizeof(gCustomUserDataPath), _userDataPath); @@ -398,6 +390,20 @@ static exitcode_t HandleCommandSetRCT2(CommandLineArgEnumerator * enumerator) } } +static exitcode_t HandleCommandScanObjects(CommandLineArgEnumerator * enumerator) +{ + exitcode_t result = CommandLine::HandleCommandDefault(); + if (result != EXITCODE_CONTINUE) + { + return result; + } + + IPlatformEnvironment * env = OpenRCT2::SetupEnvironment(); + IObjectRepository * objectRepository = CreateObjectRepository(env); + objectRepository->Construct(); + return EXITCODE_OK; +} + #if defined(__WINDOWS__) && !defined(__MINGW32__) static exitcode_t HandleCommandRegisterShell(CommandLineArgEnumerator * enumerator) { diff --git a/src/config.c b/src/config.c index 63c5ad4e16..d1e5fc1807 100644 --- a/src/config.c +++ b/src/config.c @@ -936,6 +936,9 @@ bool config_find_or_browse_install_directory() gConfigGeneral.game_path = malloc(strlen(path) + 1); safe_strcpy(gConfigGeneral.game_path, path, MAX_PATH); } else { + if (gOpenRCT2Headless) { + return false; + } while (1) { platform_show_messagebox("OpenRCT2 needs files from the original RollerCoaster Tycoon 2 in order to work. Please select the directory where you installed RollerCoaster Tycoon 2."); installPath = platform_open_directory_browser("Please select your RCT2 directory"); diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp index ca83285645..0c051b68d9 100644 --- a/src/object/ObjectRepository.cpp +++ b/src/object/ObjectRepository.cpp @@ -112,32 +112,29 @@ public: ClearItems(); } - void LoadOrConstruct(bool forceScan) override + void LoadOrConstruct() override { ClearItems(); - _queryDirectoryResult = { 0 }; - - const std::string &rct2Path = _env->GetDirectoryPath(DIRBASE::RCT2, DIRID::OBJECT); - const std::string &openrct2Path = _env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT); - QueryDirectory(&_queryDirectoryResult, rct2Path); - QueryDirectory(&_queryDirectoryResult, openrct2Path); - - if (forceScan || !Load()) + Query(); + if (!Load()) { - if (forceScan) - { - Console::WriteLine("Forcing object repository scan."); - } _languageId = gCurrentLanguage; - - Construct(); + Scan(); Save(); } // SortItems(); } + void Construct() override + { + _languageId = gCurrentLanguage; + Query(); + Scan(); + Save(); + } + size_t GetNumObjects() const override { return _items.size(); @@ -238,6 +235,16 @@ private: _itemMap.clear(); } + void Query() + { + _queryDirectoryResult = { 0 }; + + const std::string &rct2Path = _env->GetDirectoryPath(DIRBASE::RCT2, DIRID::OBJECT); + const std::string &openrct2Path = _env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT); + QueryDirectory(&_queryDirectoryResult, rct2Path); + QueryDirectory(&_queryDirectoryResult, openrct2Path); + } + void QueryDirectory(QueryDirectoryResult * result, const std::string &directory) { utf8 pattern[MAX_PATH]; @@ -246,11 +253,8 @@ private: Path::QueryDirectory(result, pattern); } - void Construct() + void Scan() { - utf8 objectDirectory[MAX_PATH]; - Path::GetDirectory(objectDirectory, sizeof(objectDirectory), gRCT2AddressObjectDataPath); - Console::WriteLine("Scanning %lu objects...", _queryDirectoryResult.TotalFiles); _numConflicts = 0; @@ -670,7 +674,7 @@ extern "C" void object_list_load() { IObjectRepository * objectRepository = GetObjectRepository(); - objectRepository->LoadOrConstruct(false); + objectRepository->LoadOrConstruct(); IObjectManager * objectManager = GetObjectManager(); objectManager->UnloadAll(); diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h index e696c7c783..2e968886b8 100644 --- a/src/object/ObjectRepository.h +++ b/src/object/ObjectRepository.h @@ -63,7 +63,8 @@ interface IObjectRepository { virtual ~IObjectRepository() { } - virtual void LoadOrConstruct(bool forceScan) abstract; + virtual void LoadOrConstruct() abstract; + virtual void Construct() abstract; virtual size_t GetNumObjects() const abstract; virtual const ObjectRepositoryItem * GetObjects() const abstract; virtual const ObjectRepositoryItem * FindObject(const utf8 * name) const abstract;