diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 17f6b10a37d7..a49c9e12d5e5 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -24,6 +24,7 @@ - Improved: [#16251] openrct2.d.ts: removed unused LabelWidget.onChange property. - Improved: [#16258] Increased image limit in the engine. - Improved: [#16408] Improve --version cli option to report more compatibility information. +- Improved: [#16764] [Plugin] Add hook 'map.save', called before the map is about is saved. - Change: [#14484] Make the Heartline Twister coaster ratings a little bit less hateful. - Change: [#16077] When importing SV6 files, the RCT1 land types are only added when they were actually used. - Change: [#16424] Following an entity in the title sequence no longer toggles underground view when it's underground. diff --git a/distribution/openrct2.d.ts b/distribution/openrct2.d.ts index ec84c0d07271..954121a3d083 100644 --- a/distribution/openrct2.d.ts +++ b/distribution/openrct2.d.ts @@ -285,6 +285,7 @@ declare global { subscribe(hook: "action.location", callback: (e: ActionLocationArgs) => void): IDisposable; subscribe(hook: "guest.generation", callback: (e: GuestGenerationArgs) => void): IDisposable; subscribe(hook: "vehicle.crash", callback: (e: VehicleCrashArgs) => void): IDisposable; + subscribe(hook: "map.save", callback: () => void): IDisposable; /** * Registers a function to be called every so often in realtime, specified by the given delay. @@ -385,7 +386,8 @@ declare global { type HookType = "interval.tick" | "interval.day" | "network.chat" | "network.action" | "network.join" | "network.leave" | - "ride.ratings.calculate" | "action.location" | "vehicle.crash"; + "ride.ratings.calculate" | "action.location" | "vehicle.crash" | + "map.save"; type ExpenditureType = "ride_construction" | diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index d62859e89a7d..74115e8d20fe 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -793,3 +793,17 @@ bool stop_silent_record() return false; } + +void PrepareMapForSave() +{ + viewport_set_saved_view(); + +#ifdef ENABLE_SCRIPTING + auto& scriptEngine = GetContext()->GetScriptEngine(); + auto& hookEngine = scriptEngine.GetHookEngine(); + if (hookEngine.HasSubscriptions(OpenRCT2::Scripting::HOOK_TYPE::MAP_SAVE)) + { + hookEngine.Call(OpenRCT2::Scripting::HOOK_TYPE::MAP_SAVE, false); + } +#endif +} diff --git a/src/openrct2/Game.h b/src/openrct2/Game.h index 79aff47c0ea3..c76a99a93632 100644 --- a/src/openrct2/Game.h +++ b/src/openrct2/Game.h @@ -173,3 +173,4 @@ void rct2_to_utf8_self(char* buffer, size_t length); void game_fix_save_vars(); void start_silent_record(); bool stop_silent_record(); +void PrepareMapForSave(); diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index bddce90ea482..6f73e18900fa 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -2758,7 +2758,7 @@ bool NetworkBase::LoadMap(IStream* stream) bool NetworkBase::SaveMap(IStream* stream, const std::vector& objects) const { bool result = false; - viewport_set_saved_view(); + PrepareMapForSave(); try { auto exporter = std::make_unique(); diff --git a/src/openrct2/park/ParkFile.cpp b/src/openrct2/park/ParkFile.cpp index 8c05e99d2a2d..395da8836a38 100644 --- a/src/openrct2/park/ParkFile.cpp +++ b/src/openrct2/park/ParkFile.cpp @@ -2289,7 +2289,7 @@ int32_t scenario_save(u8string_view path, int32_t flags) window_close_construction_windows(); } - viewport_set_saved_view(); + PrepareMapForSave(); bool result = false; auto parkFile = std::make_unique(); diff --git a/src/openrct2/platform/Crash.cpp b/src/openrct2/platform/Crash.cpp index b3ff4fc0c687..33f31f0538e6 100644 --- a/src/openrct2/platform/Crash.cpp +++ b/src/openrct2/platform/Crash.cpp @@ -175,15 +175,10 @@ static bool OnCrash( auto saveFilePathUTF8 = String::ToUtf8(saveFilePath); try { - auto exporter = std::make_unique(); - - // Make sure the save is using the current viewport settings. - viewport_set_saved_view(); - - // Disable RLE encoding for better compression. - gUseRLE = false; + PrepareMapForSave(); // Export all loaded objects to avoid having custom objects missing in the reports. + auto exporter = std::make_unique(); auto ctx = OpenRCT2::GetContext(); auto& objManager = ctx->GetObjectManager(); exporter->ExportObjectsList = objManager.GetPackableObjects(); diff --git a/src/openrct2/scripting/HookEngine.cpp b/src/openrct2/scripting/HookEngine.cpp index 6c2a750348b5..33525160d90d 100644 --- a/src/openrct2/scripting/HookEngine.cpp +++ b/src/openrct2/scripting/HookEngine.cpp @@ -31,6 +31,7 @@ static const EnumMap HooksLookupTable({ { "action.location", HOOK_TYPE::ACTION_LOCATION }, { "guest.generation", HOOK_TYPE::GUEST_GENERATION }, { "vehicle.crash", HOOK_TYPE::VEHICLE_CRASH }, + { "map.save", HOOK_TYPE::MAP_SAVE }, }); HOOK_TYPE OpenRCT2::Scripting::GetHookType(const std::string& name) diff --git a/src/openrct2/scripting/HookEngine.h b/src/openrct2/scripting/HookEngine.h index b1a875eaa771..dde0f4de1b44 100644 --- a/src/openrct2/scripting/HookEngine.h +++ b/src/openrct2/scripting/HookEngine.h @@ -40,6 +40,7 @@ namespace OpenRCT2::Scripting ACTION_LOCATION, GUEST_GENERATION, VEHICLE_CRASH, + MAP_SAVE, COUNT, UNDEFINED = -1, }; diff --git a/src/openrct2/scripting/ScriptEngine.h b/src/openrct2/scripting/ScriptEngine.h index b1d7606dd7b9..e80dd529a1c6 100644 --- a/src/openrct2/scripting/ScriptEngine.h +++ b/src/openrct2/scripting/ScriptEngine.h @@ -46,7 +46,7 @@ namespace OpenRCT2 namespace OpenRCT2::Scripting { - static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 46; + static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 47; // Versions marking breaking changes. static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33; diff --git a/src/openrct2/util/SawyerCoding.cpp b/src/openrct2/util/SawyerCoding.cpp index 26adf55b686a..06bafb725951 100644 --- a/src/openrct2/util/SawyerCoding.cpp +++ b/src/openrct2/util/SawyerCoding.cpp @@ -24,8 +24,6 @@ static size_t encode_chunk_rle(const uint8_t* src_buffer, uint8_t* dst_buffer, s static size_t encode_chunk_repeat(const uint8_t* src_buffer, uint8_t* dst_buffer, size_t length); static void encode_chunk_rotate(uint8_t* buffer, size_t length); -bool gUseRLE = true; - uint32_t sawyercoding_calculate_checksum(const uint8_t* buffer, size_t length) { uint32_t checksum = 0; @@ -44,13 +42,6 @@ size_t sawyercoding_write_chunk_buffer(uint8_t* dst_file, const uint8_t* buffer, { uint8_t *encode_buffer, *encode_buffer2; - if (!gUseRLE) - { - if (chunkHeader.encoding == CHUNK_ENCODING_RLE || chunkHeader.encoding == CHUNK_ENCODING_RLECOMPRESSED) - { - chunkHeader.encoding = CHUNK_ENCODING_NONE; - } - } switch (chunkHeader.encoding) { case CHUNK_ENCODING_NONE: diff --git a/src/openrct2/util/SawyerCoding.h b/src/openrct2/util/SawyerCoding.h index 3045ce888eea..a39cb66eb903 100644 --- a/src/openrct2/util/SawyerCoding.h +++ b/src/openrct2/util/SawyerCoding.h @@ -41,8 +41,6 @@ enum FILE_TYPE_SC4 = (2 << 2) }; -extern bool gUseRLE; - uint32_t sawyercoding_calculate_checksum(const uint8_t* buffer, size_t length); size_t sawyercoding_write_chunk_buffer(uint8_t* dst_file, const uint8_t* src_buffer, sawyercoding_chunk_header chunkHeader); size_t sawyercoding_decode_sv4(const uint8_t* src, uint8_t* dst, size_t length, size_t bufferLength);