From 4b980d6b585d22a19a0a8df52ecd6fe28065297a Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 3 Apr 2021 17:27:56 +0100 Subject: [PATCH] Improve saving and playing of .park scenario --- src/openrct2-ui/windows/TitleMenu.cpp | 2 +- src/openrct2/Context.cpp | 13 +++++--- src/openrct2/Context.h | 6 ++-- src/openrct2/Editor.cpp | 31 +++++++++++++++++- src/openrct2/ParkFile.cpp | 33 +++++++++++++++++++- src/openrct2/scenario/ScenarioRepository.cpp | 25 +++++++++++++-- 6 files changed, 98 insertions(+), 12 deletions(-) diff --git a/src/openrct2-ui/windows/TitleMenu.cpp b/src/openrct2-ui/windows/TitleMenu.cpp index 16470bee38..c28fcaea1c 100644 --- a/src/openrct2-ui/windows/TitleMenu.cpp +++ b/src/openrct2-ui/windows/TitleMenu.cpp @@ -112,7 +112,7 @@ rct_window* window_title_menu_open() static void window_title_menu_scenarioselect_callback(const utf8* path) { - context_load_park_from_file(path); + OpenRCT2::GetContext()->LoadParkFromFile(path, false, true); game_load_scripts(); } diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index da7cce69c4..06e693d751 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -555,7 +555,8 @@ namespace OpenRCT2 _drawingEngine = nullptr; } - bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail) final override + bool LoadParkFromFile( + const std::string& path, bool loadTitleScreenOnFail = false, bool asScenario = false) final override { log_verbose("Context::LoadParkFromFile(%s)", path.c_str()); try @@ -564,7 +565,7 @@ namespace OpenRCT2 { auto data = DecryptSea(fs::u8path(path)); auto ms = MemoryStream(data.data(), data.size(), MEMORY_ACCESS::READ); - if (!LoadParkFromStream(&ms, path, loadTitleScreenOnFail)) + if (!LoadParkFromStream(&ms, path, loadTitleScreenOnFail, asScenario)) { throw std::runtime_error(".sea file may have been renamed."); } @@ -573,7 +574,7 @@ namespace OpenRCT2 else { auto fs = FileStream(path, FILE_MODE_OPEN); - if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail)) + if (!LoadParkFromStream(&fs, path, loadTitleScreenOnFail, asScenario)) { return false; } @@ -593,7 +594,9 @@ namespace OpenRCT2 return false; } - bool LoadParkFromStream(IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail) final override + bool LoadParkFromStream( + IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false, + bool asScenario = false) final override { try { @@ -642,7 +645,7 @@ namespace OpenRCT2 gLastAutoSaveUpdate = AUTOSAVE_PAUSE; bool sendMap = false; - if (info.Type == FILE_TYPE::PARK || info.Type == FILE_TYPE::SAVED_GAME) + if (!asScenario && (info.Type == FILE_TYPE::PARK || info.Type == FILE_TYPE::SAVED_GAME)) { if (network_get_mode() == NETWORK_MODE_CLIENT) { diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index 967ac662b7..9dda928559 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -137,9 +137,11 @@ namespace OpenRCT2 virtual bool Initialise() abstract; virtual void InitialiseDrawingEngine() abstract; virtual void DisposeDrawingEngine() abstract; - virtual bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail = false) abstract; + virtual bool LoadParkFromFile( + const std::string& path, bool loadTitleScreenOnFail = false, bool asScenario = false) abstract; virtual bool LoadParkFromStream( - IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false) abstract; + IStream* stream, const std::string& path, bool loadTitleScreenFirstOnFail = false, + bool asScenario = false) abstract; virtual void WriteLine(const std::string& s) abstract; virtual void WriteErrorLine(const std::string& s) abstract; virtual void Finish() abstract; diff --git a/src/openrct2/Editor.cpp b/src/openrct2/Editor.cpp index cb5aa7178b..96aa654328 100644 --- a/src/openrct2/Editor.cpp +++ b/src/openrct2/Editor.cpp @@ -24,6 +24,7 @@ #include "localisation/Localisation.h" #include "localisation/LocalisationService.h" #include "management/NewsItem.h" +#include "object/DefaultObjects.h" #include "object/ObjectManager.h" #include "object/ObjectRepository.h" #include "peep/Staff.h" @@ -40,7 +41,6 @@ #include "world/Park.h" #include "world/Scenery.h" #include "world/Sprite.h" -#include "object/DefaultObjects.h" #include #include @@ -58,6 +58,7 @@ namespace Editor static bool LoadLandscapeFromSC4(const char* path); static void FinaliseMainView(); static bool ReadS6(const char* path); + static bool ReadPark(const char* path); static void ClearMapForEditing(bool fromSave); static void object_list_load() @@ -233,6 +234,8 @@ namespace Editor return LoadLandscapeFromSC4(path); case FILE_EXTENSION_SV4: return LoadLandscapeFromSV4(path); + case FILE_EXTENSION_PARK: + return ReadPark(path); default: return false; } @@ -299,6 +302,32 @@ namespace Editor return true; } + static bool ReadPark(const char* path) + { + try + { + auto context = GetContext(); + auto& objManager = context->GetObjectManager(); + auto importer = ParkImporter::CreateParkFile(context->GetObjectRepository()); + auto loadResult = importer->Load(path); + objManager.LoadObjects(loadResult.RequiredObjects); + importer->Import(); + + ClearMapForEditing(true); + gS6Info.editor_step = EditorStep::LandscapeEditor; + gScreenAge = 0; + gScreenFlags = SCREEN_FLAGS_SCENARIO_EDITOR; + viewport_init_all(); + context_open_window_view(WV_EDITOR_MAIN); + FinaliseMainView(); + return true; + } + catch (const std::exception&) + { + return false; + } + } + static void ClearMapForEditing(bool fromSave) { map_remove_all_rides(); diff --git a/src/openrct2/ParkFile.cpp b/src/openrct2/ParkFile.cpp index b5ae354084..f96343a398 100644 --- a/src/openrct2/ParkFile.cpp +++ b/src/openrct2/ParkFile.cpp @@ -33,6 +33,7 @@ #include "ride/ShopItem.h" #include "ride/Vehicle.h" #include "scenario/Scenario.h" +#include "scenario/ScenarioRepository.h" #include "world/Climate.h" #include "world/EntityList.h" #include "world/Entrance.h" @@ -161,6 +162,35 @@ namespace OpenRCT2 Save(fs); } + scenario_index_entry ReadScenarioChunk() + { + scenario_index_entry entry{}; + auto& os = *_os; + os.ReadWriteChunk(ParkFileChunkType::SCENARIO, [this, &entry](OrcaStream::ChunkStream& cs) { + entry.category = cs.Read(); + + std::string name; + ReadWriteStringTable(cs, name, "en-GB"); + String::Set(entry.name, sizeof(entry.name), name.c_str()); + String::Set(entry.internal_name, sizeof(entry.internal_name), name.c_str()); + + std::string parkName; + ReadWriteStringTable(cs, parkName, "en-GB"); + + std::string scenarioDetails; + ReadWriteStringTable(cs, scenarioDetails, "en-GB"); + String::Set(entry.details, sizeof(entry.details), scenarioDetails.c_str()); + + entry.objective_type = cs.Read(); + entry.objective_arg_1 = cs.Read(); + entry.objective_arg_3 = cs.Read(); + entry.objective_arg_2 = cs.Read(); + + entry.source_game = ScenarioSource::Other; + }); + return entry; + } + private: void ReadWriteAuthoringChunk(OrcaStream& os) { @@ -1404,7 +1434,8 @@ public: bool GetDetails(scenario_index_entry* dst) override { - return false; + *dst = _parkFile->ReadScenarioChunk(); + return true; } }; diff --git a/src/openrct2/scenario/ScenarioRepository.cpp b/src/openrct2/scenario/ScenarioRepository.cpp index 27abf48eb3..3d3b51acfb 100644 --- a/src/openrct2/scenario/ScenarioRepository.cpp +++ b/src/openrct2/scenario/ScenarioRepository.cpp @@ -130,7 +130,7 @@ class ScenarioFileIndex final : public FileIndex private: static constexpr uint32_t MAGIC_NUMBER = 0x58444953; // SIDX static constexpr uint16_t VERSION = 5; - static constexpr auto PATTERN = "*.sc4;*.sc6;*.sea"; + static constexpr auto PATTERN = "*.sc4;*.sc6;*.sea;*.park"; public: explicit ScenarioFileIndex(const IPlatformEnvironment& env) @@ -203,7 +203,28 @@ private: try { std::string extension = Path::GetExtension(path); - if (String::Equals(extension, ".sc4", true)) + if (String::Equals(extension, ".park", true)) + { + // OpenRCT2 park + bool result = false; + try + { + auto& objRepository = OpenRCT2::GetContext()->GetObjectRepository(); + auto importer = ParkImporter::CreateParkFile(objRepository); + importer->LoadScenario(path.c_str(), true); + if (importer->GetDetails(entry)) + { + String::Set(entry->path, sizeof(entry->path), path.c_str()); + entry->timestamp = timestamp; + result = true; + } + } + catch (const std::exception&) + { + } + return result; + } + else if (String::Equals(extension, ".sc4", true)) { // RCT1 scenario bool result = false;