diff --git a/src/openrct2/GameState.h b/src/openrct2/GameState.h index 6c03f6b610..d44fd4de1a 100644 --- a/src/openrct2/GameState.h +++ b/src/openrct2/GameState.h @@ -26,6 +26,7 @@ #include "world/Climate.h" #include "world/Location.hpp" #include "world/Park.h" +#include "world/ScenerySelection.h" #include #include diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 92064b5f14..cf3a5dbf3c 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -66,6 +66,7 @@ #include "../ride/Vehicle.h" #include "../scenario/Scenario.h" #include "../scenario/ScenarioRepository.h" +#include "../scenario/ScenarioSources.h" #include "../util/SawyerCoding.h" #include "../util/Util.h" #include "../world/Climate.h" @@ -156,6 +157,14 @@ namespace OpenRCT2::RCT2 throw std::runtime_error("Park is not a scenario."); } chunkReader.ReadChunk(&_s6.Info, sizeof(_s6.Info)); + + // If the name or the details contain a colour code, they might be in UTF-8 already. + // This is caused by a bug that was in OpenRCT2 for 3 years. + if (!IsLikelyUTF8(_s6.Info.Name) && !IsLikelyUTF8(_s6.Info.Details)) + { + RCT2StringToUTF8Self(_s6.Info.Name, sizeof(_s6.Info.Name)); + RCT2StringToUTF8Self(_s6.Info.Details, sizeof(_s6.Info.Details)); + } } else { @@ -225,7 +234,69 @@ namespace OpenRCT2::RCT2 bool GetDetails(ScenarioIndexEntry* dst) override { *dst = {}; - return false; + + dst->Category = _s6.Info.Category; + dst->ObjectiveType = _s6.Info.ObjectiveType; + dst->ObjectiveArg1 = _s6.Info.ObjectiveArg1; + dst->ObjectiveArg2 = _s6.Info.ObjectiveArg2; + dst->ObjectiveArg3 = _s6.Info.ObjectiveArg3; + dst->Highscore = nullptr; + + if (String::IsNullOrEmpty(_s6.Info.Name)) + { + // If the scenario doesn't have a name, set it to the filename + String::Set(dst->Name, sizeof(dst->Name), Path::GetFileNameWithoutExtension(dst->Path).c_str()); + } + else + { + String::Set(dst->Name, sizeof(dst->Name), _s6.Info.Name); + // Normalise the name to make the scenario as recognisable as possible. + ScenarioSources::NormaliseName(dst->Name, sizeof(dst->Name), dst->Name); + } + + // dst->name will be translated later so keep the untranslated name here + String::Set(dst->InternalName, sizeof(dst->InternalName), dst->Name); + + String::Set(dst->Details, sizeof(dst->Details), _s6.Info.Details); + + // Look up and store information regarding the origins of this scenario. + SourceDescriptor desc; + if (ScenarioSources::TryGetByName(dst->Name, &desc)) + { + dst->ScenarioId = desc.id; + dst->SourceIndex = desc.index; + dst->SourceGame = ScenarioSource{ desc.source }; + dst->Category = desc.category; + } + else + { + dst->ScenarioId = SC_UNIDENTIFIED; + dst->SourceIndex = -1; + if (dst->Category == SCENARIO_CATEGORY_REAL) + { + dst->SourceGame = ScenarioSource::Real; + } + else + { + dst->SourceGame = ScenarioSource::Other; + } + } + + // Localise the park name and description + StringId localisedStringIds[3]; + if (LanguageGetLocalisedScenarioStrings(dst->Name, localisedStringIds)) + { + if (localisedStringIds[0] != STR_NONE) + { + String::Set(dst->Name, sizeof(dst->Name), LanguageGetString(localisedStringIds[0])); + } + if (localisedStringIds[2] != STR_NONE) + { + String::Set(dst->Details, sizeof(dst->Details), LanguageGetString(localisedStringIds[2])); + } + } + + return true; } void Import(GameState_t& gameState) override diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index d593b40191..92ba336095 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -249,26 +249,25 @@ private: } // RCT2 or RCTC scenario - auto stream = GetStreamFromRCT2Scenario(path); - auto chunkReader = SawyerChunkReader(stream.get()); - - const auto header = chunkReader.ReadChunkAs(); - if (header.Type == S6_TYPE_SCENARIO) + bool result = false; + try { - auto info = chunkReader.ReadChunkAs(); - // If the name or the details contain a colour code, they might be in UTF-8 already. - // This is caused by a bug that was in OpenRCT2 for 3 years. - if (!IsLikelyUTF8(info.Name) && !IsLikelyUTF8(info.Details)) + auto& objRepository = OpenRCT2::GetContext()->GetObjectRepository(); + auto s6Importer = ParkImporter::CreateS6(objRepository); + s6Importer->LoadScenario(path, true); + if (s6Importer->GetDetails(entry)) { - RCT2StringToUTF8Self(info.Name, sizeof(info.Name)); - RCT2StringToUTF8Self(info.Details, sizeof(info.Details)); + entry->Path = path; + entry->Timestamp = timestamp; + result = true; } - - *entry = CreateNewScenarioEntry(path, timestamp, &info); - return true; + } + catch (const std::exception&) + { } LOG_VERBOSE("%s is not a scenario", path.c_str()); + return result; } catch (const std::exception&) { @@ -276,63 +275,6 @@ private: } return false; } - - static ScenarioIndexEntry CreateNewScenarioEntry(const std::string& path, uint64_t timestamp, RCT2::S6Info* s6Info) - { - ScenarioIndexEntry entry = {}; - - // Set new entry - entry.Path = path; - entry.Timestamp = timestamp; - entry.Category = s6Info->Category; - entry.ObjectiveType = s6Info->ObjectiveType; - entry.ObjectiveArg1 = s6Info->ObjectiveArg1; - entry.ObjectiveArg2 = s6Info->ObjectiveArg2; - entry.ObjectiveArg3 = s6Info->ObjectiveArg3; - entry.Highscore = nullptr; - if (String::IsNullOrEmpty(s6Info->Name)) - { - // If the scenario doesn't have a name, set it to the filename - String::Set(entry.Name, sizeof(entry.Name), Path::GetFileNameWithoutExtension(entry.Path).c_str()); - } - else - { - String::Set(entry.Name, sizeof(entry.Name), s6Info->Name); - // Normalise the name to make the scenario as recognisable as possible. - ScenarioSources::NormaliseName(entry.Name, sizeof(entry.Name), entry.Name); - } - - // entry.name will be translated later so keep the untranslated name here - String::Set(entry.InternalName, sizeof(entry.InternalName), entry.Name); - - String::Set(entry.Details, sizeof(entry.Details), s6Info->Details); - - // Look up and store information regarding the origins of this scenario. - SourceDescriptor desc; - if (ScenarioSources::TryGetByName(entry.Name, &desc)) - { - entry.ScenarioId = desc.id; - entry.SourceIndex = desc.index; - entry.SourceGame = ScenarioSource{ desc.source }; - entry.Category = desc.category; - } - else - { - entry.ScenarioId = SC_UNIDENTIFIED; - entry.SourceIndex = -1; - if (entry.Category == SCENARIO_CATEGORY_REAL) - { - entry.SourceGame = ScenarioSource::Real; - } - else - { - entry.SourceGame = ScenarioSource::Other; - } - } - - ScenarioTranslate(&entry); - return entry; - } }; class ScenarioRepository final : public IScenarioRepository @@ -813,19 +755,3 @@ bool ScenarioRepositoryTryRecordHighscore(const utf8* scenarioFileName, money64 IScenarioRepository* repo = GetScenarioRepository(); return repo->TryRecordHighscore(LocalisationService_GetCurrentLanguage(), scenarioFileName, companyValue, name); } - -void ScenarioTranslate(ScenarioIndexEntry* scenarioEntry) -{ - StringId localisedStringIds[3]; - if (LanguageGetLocalisedScenarioStrings(scenarioEntry->Name, localisedStringIds)) - { - if (localisedStringIds[0] != STR_NONE) - { - String::Set(scenarioEntry->Name, sizeof(scenarioEntry->Name), LanguageGetString(localisedStringIds[0])); - } - if (localisedStringIds[2] != STR_NONE) - { - String::Set(scenarioEntry->Details, sizeof(scenarioEntry->Details), LanguageGetString(localisedStringIds[2])); - } - } -} diff --git a/src/openrct2/scenario/ScenarioRepository.h b/src/openrct2/scenario/ScenarioRepository.h index b814c616ae..14e3c14b25 100644 --- a/src/openrct2/scenario/ScenarioRepository.h +++ b/src/openrct2/scenario/ScenarioRepository.h @@ -97,4 +97,3 @@ void ScenarioRepositoryScan(); [[nodiscard]] size_t ScenarioRepositoryGetCount(); [[nodiscard]] const ScenarioIndexEntry* ScenarioRepositoryGetByIndex(size_t index); [[nodiscard]] bool ScenarioRepositoryTryRecordHighscore(const utf8* scenarioFileName, money64 companyValue, const utf8* name); -void ScenarioTranslate(ScenarioIndexEntry* scenarioEntry);