diff --git a/src/openrct2-ui/windows/Options.cpp b/src/openrct2-ui/windows/Options.cpp index a65dc60646..96eed6565c 100644 --- a/src/openrct2-ui/windows/Options.cpp +++ b/src/openrct2-ui/windows/Options.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -1150,7 +1151,7 @@ static void window_options_mousedown(rct_window *w, rct_widgetindex widgetIndex, gDropdownItemsArgs[i - 1] = (uintptr_t)LanguagesDescriptors[i].native_name; } window_options_show_dropdown(w, widget, LANGUAGE_COUNT - 1); - dropdown_set_checked(gCurrentLanguage - 1, true); + dropdown_set_checked(LocalisationService_GetCurrentLanguage() - 1, true); break; case WIDX_DATE_FORMAT_DROPDOWN: for (size_t i = 0; i < 4; i++) { @@ -1389,8 +1390,8 @@ static void window_options_dropdown(rct_window *w, rct_widgetindex widgetIndex, break; case WIDX_LANGUAGE_DROPDOWN: { - sint32 fallbackLanguage = gCurrentLanguage; - if (dropdownIndex != gCurrentLanguage - 1) { + auto fallbackLanguage = LocalisationService_GetCurrentLanguage(); + if (dropdownIndex != LocalisationService_GetCurrentLanguage() - 1) { if (!language_open(dropdownIndex + 1)) { // Failed to open language file, try to recover by falling @@ -1635,7 +1636,7 @@ static void window_options_invalidate(rct_window *w) case WINDOW_OPTIONS_PAGE_CULTURE: // Language - set_format_arg(0, char*, LanguagesDescriptors[gCurrentLanguage].native_name); + set_format_arg(0, char*, LanguagesDescriptors[LocalisationService_GetCurrentLanguage()].native_name); // Currency: pounds, dollars, etc. (10 total) window_options_culture_widgets[WIDX_CURRENCY].text = CurrencyDescriptors[gConfigGeneral.currency_format].stringId; diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index e35b840746..c2b5612f90 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -124,7 +124,8 @@ namespace OpenRCT2 std::shared_ptr uiContext) : _env(env), _audioContext(audioContext), - _uiContext(uiContext) + _uiContext(uiContext), + _localisationService(std::make_shared(env)) { Instance = this; } @@ -395,14 +396,14 @@ namespace OpenRCT2 // 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. - _objectRepository->LoadOrConstruct(); + _objectRepository->LoadOrConstruct(_localisationService->GetCurrentLanguage()); // 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 // as its not required until the player wants to place a new ride. - _trackDesignRepository->Scan(); + _trackDesignRepository->Scan(_localisationService->GetCurrentLanguage()); - _scenarioRepository->Scan(); + _scenarioRepository->Scan(_localisationService->GetCurrentLanguage()); TitleSequenceManager::Scan(); if (!gOpenRCT2Headless) diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index 16841f7a8e..2b864c82ac 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -400,11 +400,7 @@ static exitcode_t HandleCommandScanObjects([[maybe_unused]] CommandLineArgEnumer auto context = std::unique_ptr(OpenRCT2::CreateContext()); auto env = context->GetPlatformEnvironment(); auto objectRepository = CreateObjectRepository(env); - - // HACK: set gCurrentLanguage otherwise it be wrong for the index file - gCurrentLanguage = gConfigGeneral.language; - - objectRepository->Construct(); + objectRepository->Construct(gConfigGeneral.language); return EXITCODE_OK; } diff --git a/src/openrct2/core/FileIndex.hpp b/src/openrct2/core/FileIndex.hpp index f834e4f2ee..99adbf1bbf 100644 --- a/src/openrct2/core/FileIndex.hpp +++ b/src/openrct2/core/FileIndex.hpp @@ -107,11 +107,11 @@ public: * Queries and directories and loads the index header. If the index is up to date, * the items are loaded from the index and returned, otherwise the index is rebuilt. */ - std::vector LoadOrBuild() const + std::vector LoadOrBuild(sint32 language) const { std::vector items; auto scanResult = Scan(); - auto readIndexResult = ReadIndexFile(scanResult.Stats); + auto readIndexResult = ReadIndexFile(language, scanResult.Stats); if (std::get<0>(readIndexResult)) { // Index was loaded @@ -120,15 +120,15 @@ public: else { // Index was not loaded - items = Build(scanResult); + items = Build(language, scanResult); } return items; } - std::vector Rebuild() const + std::vector Rebuild(sint32 language) const { auto scanResult = Scan(); - auto items = Build(scanResult); + auto items = Build(language, scanResult); return items; } @@ -208,7 +208,7 @@ private: } } - std::vector Build(const ScanResult &scanResult) const + std::vector Build(sint32 language, const ScanResult &scanResult) const { std::vector allItems; Console::WriteLine("Building %s (%zu items)", _name.c_str(), scanResult.Files.size()); @@ -262,7 +262,7 @@ private: allItems.insert(allItems.end(), itr.begin(), itr.end()); } - WriteIndexFile(scanResult.Stats, allItems); + WriteIndexFile(language, scanResult.Stats, allItems); } auto endTime = std::chrono::high_resolution_clock::now(); @@ -272,7 +272,7 @@ private: return allItems; } - std::tuple> ReadIndexFile(const DirectoryStats &stats) const + std::tuple> ReadIndexFile(sint32 language, const DirectoryStats &stats) const { bool loadedItems = false; std::vector items; @@ -289,7 +289,7 @@ private: header.MagicNumber == _magicNumber && header.VersionA == FILE_INDEX_VERSION && header.VersionB == _version && - header.LanguageId == gCurrentLanguage && + header.LanguageId == language && header.Stats.TotalFiles == stats.TotalFiles && header.Stats.TotalFileSize == stats.TotalFileSize && header.Stats.FileDateModifiedChecksum == stats.FileDateModifiedChecksum && @@ -318,7 +318,7 @@ private: return std::make_tuple(loadedItems, items); } - void WriteIndexFile(const DirectoryStats &stats, const std::vector &items) const + void WriteIndexFile(sint32 language, const DirectoryStats &stats, const std::vector &items) const { try { @@ -331,7 +331,7 @@ private: header.MagicNumber = _magicNumber; header.VersionA = FILE_INDEX_VERSION; header.VersionB = _version; - header.LanguageId = gCurrentLanguage; + header.LanguageId = language; header.Stats = stats; header.NumItems = (uint32)items.size(); fs.WriteValue(header); diff --git a/src/openrct2/interface/Fonts.cpp b/src/openrct2/interface/Fonts.cpp index f63832a736..5e58ac578c 100644 --- a/src/openrct2/interface/Fonts.cpp +++ b/src/openrct2/interface/Fonts.cpp @@ -148,7 +148,8 @@ static bool LoadCustomConfigFont(LocalisationService& localisationService) void TryLoadFonts(LocalisationService& localisationService) { #ifndef NO_TTF - TTFontFamily const * fontFamily = LanguagesDescriptors[gCurrentLanguage].font_family; + auto currentLanguage = localisationService.GetCurrentLanguage(); + TTFontFamily const * fontFamily = LanguagesDescriptors[currentLanguage].font_family; if (fontFamily != FAMILY_OPENRCT2_SPRITE) { diff --git a/src/openrct2/localisation/Language.h b/src/openrct2/localisation/Language.h index 1e20175715..e2b77ba462 100644 --- a/src/openrct2/localisation/Language.h +++ b/src/openrct2/localisation/Language.h @@ -86,8 +86,6 @@ struct language_descriptor { extern const language_descriptor LanguagesDescriptors[LANGUAGE_COUNT]; -extern sint32 gCurrentLanguage; - extern const utf8 BlackUpArrowString[]; extern const utf8 BlackDownArrowString[]; extern const utf8 BlackLeftArrowString[]; diff --git a/src/openrct2/localisation/LocalisationService.cpp b/src/openrct2/localisation/LocalisationService.cpp index ee08e1b75d..8f988577fd 100644 --- a/src/openrct2/localisation/LocalisationService.cpp +++ b/src/openrct2/localisation/LocalisationService.cpp @@ -40,6 +40,11 @@ LocalisationService::LocalisationService(const std::shared_ptrGetDirectoryPath(DIRBASE::OPENRCT2, DIRID::LANGUAGE); - auto languagePath = Path::Combine(languageDirectory, locale + "txt"); + auto languagePath = Path::Combine(languageDirectory, locale + ".txt"); return languagePath; } @@ -98,8 +103,10 @@ void LocalisationService::OpenLanguage(sint32 id, IObjectManager& objectManager) // Objects and their localised strings need to be refreshed objectManager.ResetObjects(); } - - throw std::runtime_error("Unable to open language " + std::to_string(id)); + else + { + throw std::runtime_error("Unable to open language " + std::to_string(id)); + } } void LocalisationService::CloseLanguages() diff --git a/src/openrct2/localisation/LocalisationService.h b/src/openrct2/localisation/LocalisationService.h index 11b04c51c8..e7017aad22 100644 --- a/src/openrct2/localisation/LocalisationService.h +++ b/src/openrct2/localisation/LocalisationService.h @@ -46,6 +46,7 @@ namespace OpenRCT2::Localisation void UseTrueTypeFont(bool value) { _useTrueTypeFont = value; } LocalisationService(const std::shared_ptr& env); + ~LocalisationService(); const char * GetString(rct_string_id id) const; std::tuple GetLocalisedScenarioStrings(const std::string& scenarioFilename) const; diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index c29cc1401a..95eb256f63 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -43,6 +43,7 @@ #include "../config/Config.h" #include "../localisation/Localisation.h" +#include "../localisation/LocalisationService.h" #include "../object/Object.h" #include "ObjectList.h" #include "../platform/platform.h" @@ -225,17 +226,17 @@ public: ClearItems(); } - void LoadOrConstruct() override + void LoadOrConstruct(sint32 language) override { ClearItems(); - auto items = _fileIndex.LoadOrBuild(); + auto items = _fileIndex.LoadOrBuild(language); AddItems(items); SortItems(); } - void Construct() override + void Construct(sint32 language) override { - auto items = _fileIndex.Rebuild(); + auto items = _fileIndex.Rebuild(language); AddItems(items); SortItems(); } @@ -665,8 +666,9 @@ const rct_object_entry * object_list_find(rct_object_entry * entry) void object_list_load() { auto context = GetContext(); - IObjectRepository * objectRepository = context->GetObjectRepository(); - objectRepository->LoadOrConstruct(); + const auto localisationService = context->GetLocalisationService(); + auto objectRepository = context->GetObjectRepository(); + objectRepository->LoadOrConstruct(localisationService->GetCurrentLanguage()); IObjectManager * objectManager = context->GetObjectManager(); objectManager->UnloadAll(); diff --git a/src/openrct2/object/ObjectRepository.h b/src/openrct2/object/ObjectRepository.h index 2e62a595bd..1d71b20e02 100644 --- a/src/openrct2/object/ObjectRepository.h +++ b/src/openrct2/object/ObjectRepository.h @@ -29,6 +29,11 @@ namespace OpenRCT2 interface IPlatformEnvironment; } +namespace OpenRCT2::Localisation +{ + class LocalisationService; +} + struct rct_drawpixelinfo; struct ObjectRepositoryItem @@ -59,8 +64,8 @@ interface IObjectRepository { virtual ~IObjectRepository() = default; - virtual void LoadOrConstruct() abstract; - virtual void Construct() abstract; + virtual void LoadOrConstruct(sint32 language) abstract; + virtual void Construct(sint32 language) abstract; virtual size_t GetNumObjects() const abstract; virtual const ObjectRepositoryItem * GetObjects() const abstract; virtual const ObjectRepositoryItem * FindObject(const utf8 * name) const abstract; diff --git a/src/openrct2/object/StringTable.cpp b/src/openrct2/object/StringTable.cpp index cc1a5568b5..33d0ae26e7 100644 --- a/src/openrct2/object/StringTable.cpp +++ b/src/openrct2/object/StringTable.cpp @@ -19,6 +19,7 @@ #include "../core/String.hpp" #include "../localisation/Language.h" #include "../localisation/LanguagePack.h" +#include "../localisation/LocalisationService.h" #include "Object.h" #include "StringTable.h" @@ -111,7 +112,8 @@ void StringTable::SetString(uint8 id, uint8 language, const std::string &text) void StringTable::Sort() { - std::sort(_strings.begin(), _strings.end(), [](const StringTableEntry &a, const StringTableEntry &b) -> bool + auto targetLanguage = LocalisationService_GetCurrentLanguage(); + std::sort(_strings.begin(), _strings.end(), [targetLanguage](const StringTableEntry &a, const StringTableEntry &b) -> bool { if (a.Id == b.Id) { @@ -120,11 +122,11 @@ void StringTable::Sort() return String::Compare(a.Text, b.Text, true) < 0; } - if (a.LanguageId == gCurrentLanguage) + if (a.LanguageId == targetLanguage) { return true; } - if (b.LanguageId == gCurrentLanguage) + if (b.LanguageId == targetLanguage) { return false; } diff --git a/src/openrct2/ride/TrackDesignRepository.cpp b/src/openrct2/ride/TrackDesignRepository.cpp index b2e61d5f9e..c105e1a478 100644 --- a/src/openrct2/ride/TrackDesignRepository.cpp +++ b/src/openrct2/ride/TrackDesignRepository.cpp @@ -26,6 +26,7 @@ #include "../core/FileStream.hpp" #include "../core/Path.hpp" #include "../core/String.hpp" +#include "../localisation/LocalisationService.h" #include "../object/ObjectRepository.h" #include "../object/RideObject.h" #include "../PlatformEnvironment.h" @@ -284,10 +285,10 @@ public: return refs; } - void Scan() override + void Scan(sint32 language) override { _items.clear(); - auto trackDesigns = _fileIndex.LoadOrBuild(); + auto trackDesigns = _fileIndex.LoadOrBuild(language); for (const auto &td : trackDesigns) { _items.push_back(td); @@ -404,7 +405,7 @@ ITrackDesignRepository * CreateTrackDesignRepository(std::shared_ptrGetTrackDesignRepository(); - repo->Scan(); + repo->Scan(LocalisationService_GetCurrentLanguage()); } bool track_repository_delete(const utf8 * path) diff --git a/src/openrct2/ride/TrackDesignRepository.h b/src/openrct2/ride/TrackDesignRepository.h index c5d09129bd..7426f149d4 100644 --- a/src/openrct2/ride/TrackDesignRepository.h +++ b/src/openrct2/ride/TrackDesignRepository.h @@ -46,7 +46,7 @@ interface ITrackDesignRepository virtual std::vector GetItemsForRideGroup(uint8 rideType, const RideGroup * rideGroup) const abstract; - virtual void Scan() abstract; + virtual void Scan(sint32 language) abstract; virtual bool Delete(const std::string &path) abstract; virtual std::string Rename(const std::string &path, const std::string &newName) abstract; virtual std::string Install(const std::string &path) abstract; diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index 2992a65796..b02cddbcad 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -33,6 +33,7 @@ #include "../config/Config.h" #include "../localisation/Localisation.h" +#include "../localisation/LocalisationService.h" #include "../platform/platform.h" #include "Scenario.h" #include "../Game.h" @@ -339,13 +340,13 @@ public: ClearHighscores(); } - void Scan() override + void Scan(sint32 language) override { ImportMegaPark(); // Reload scenarios from index _scenarios.clear(); - auto scenarios = _fileIndex.LoadOrBuild(); + auto scenarios = _fileIndex.LoadOrBuild(language); for (auto scenario : scenarios) { AddScenario(scenario); @@ -415,11 +416,11 @@ public: return nullptr; } - bool TryRecordHighscore(const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) override + bool TryRecordHighscore(sint32 language, const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) override { // Scan the scenarios so we have a fresh list to query. This is to prevent the issue of scenario completions // not getting recorded, see #4951. - Scan(); + Scan(language); scenario_index_entry * scenario = GetByFilename(scenarioFileName); if (scenario != nullptr) @@ -743,7 +744,7 @@ IScenarioRepository * GetScenarioRepository() void scenario_repository_scan() { IScenarioRepository * repo = GetScenarioRepository(); - repo->Scan(); + repo->Scan(LocalisationService_GetCurrentLanguage()); } size_t scenario_repository_get_count() @@ -761,6 +762,6 @@ const scenario_index_entry *scenario_repository_get_by_index(size_t index) bool scenario_repository_try_record_highscore(const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) { IScenarioRepository * repo = GetScenarioRepository(); - return repo->TryRecordHighscore(scenarioFileName, companyValue, name); + return repo->TryRecordHighscore(LocalisationService_GetCurrentLanguage(), scenarioFileName, companyValue, name); } diff --git a/src/openrct2/scenario/ScenarioRepository.h b/src/openrct2/scenario/ScenarioRepository.h index 90e4c912c7..5baea19768 100644 --- a/src/openrct2/scenario/ScenarioRepository.h +++ b/src/openrct2/scenario/ScenarioRepository.h @@ -64,7 +64,7 @@ interface IScenarioRepository /** * Scans the scenario directories and grabs the metadata for all the scenarios. */ - virtual void Scan() abstract; + virtual void Scan(sint32 language) abstract; virtual size_t GetCount() const abstract; virtual const scenario_index_entry * GetByIndex(size_t index) const abstract; @@ -75,7 +75,7 @@ interface IScenarioRepository virtual const scenario_index_entry * GetByInternalName(const utf8 * name) const abstract; virtual const scenario_index_entry * GetByPath(const utf8 * path) const abstract; - virtual bool TryRecordHighscore(const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) abstract; + virtual bool TryRecordHighscore(sint32 language, const utf8 * scenarioFileName, money32 companyValue, const utf8 * name) abstract; }; IScenarioRepository * CreateScenarioRepository(std::shared_ptr env);