From 45766402e1e6745b83efa7701d95a2b2af2dbf63 Mon Sep 17 00:00:00 2001 From: emoose Date: Mon, 10 Jun 2024 12:10:25 +0100 Subject: [PATCH] FixPegasusClopping: fixes looping clop sound effect remaining active through the session Moves lens flare fix to bugfixes.cpp, and added INI settings for toggling all fixes --- Outrun2006Tweaks.ini | 18 ++++++++++ src/dllmain.cpp | 10 ++++++ src/game_addrs.hpp | 4 +++ src/hooks_bugfixes.cpp | 77 ++++++++++++++++++++++++++++++++++++++++-- src/hooks_graphics.cpp | 40 ---------------------- src/plugin.hpp | 5 +++ 6 files changed, 112 insertions(+), 42 deletions(-) diff --git a/Outrun2006Tweaks.ini b/Outrun2006Tweaks.ini index 5ceeb84..934e757 100644 --- a/Outrun2006Tweaks.ini +++ b/Outrun2006Tweaks.ini @@ -80,3 +80,21 @@ SkipIntroLogos = false # DisableCountdownTimer: disables the countdown timer, may be useful for modders, or those who just want to take a leisurely drive. # Can also be enabled via -OuttaTime launch parameter. DisableCountdownTimer = false + +[Bugfixes] +# FixPegasusClopping: fixes looping clop sound effect remaining active through the session. +FixPegasusClopping = true + +# FixC2CRankings: fixes C2C scoreboard rankings not updating due to incomplete anti-piracy checks. +# (game still contained "SecuROM_Tripwire" checks inside it, despite Steam release not using SecuROM...) +FixC2CRankings = true + +# PreventDESTSaveCorruption: prevents the save corruption caused by trying to remap controls with many devices connected. +# This usually resulted in player name replaced with "DEST" and some garbage text, along with player character model disappearing along with all unlocks/miles. +# (if you got hit by this bug, you can restore name/model by replacing first 0xB0 bytes in your corrupted License.dat file with the contents of a different one) +PreventDESTSaveCorruption = true + +# FixLensFlarePath: game tries to load in lens flare data from common/, but the game files have it inside media/, causing lens flare not to be drawn. +# If lens flare is still present inside media/ then this will just patch game to load it from there instead. +# (if you already moved the lens flare file yourself then no change will be applied) +FixLensFlarePath = true diff --git a/src/dllmain.cpp b/src/dllmain.cpp index ef4a3e9..e054dc2 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -71,6 +71,11 @@ namespace Settings spdlog::info(" - SkipIntroLogos: {}", SkipIntroLogos); spdlog::info(" - CountdownTimerDisable: {}", CountdownTimerDisable); + + spdlog::info(" - FixPegasusClopping: {}", FixPegasusClopping); + spdlog::info(" - FixC2CRankings: {}", FixC2CRankings); + spdlog::info(" - PreventDESTSaveCorruption: {}", PreventDESTSaveCorruption); + spdlog::info(" - FixLensFlarePath: {}", FixLensFlarePath); } bool read(std::filesystem::path& iniPath) @@ -114,6 +119,11 @@ namespace Settings SkipIntroLogos = ini.Get("Misc", "SkipIntroLogos", std::move(SkipIntroLogos)); CountdownTimerDisable = ini.Get("Misc", "CountdownTimerDisable", std::move(CountdownTimerDisable)); + FixPegasusClopping = ini.Get("Bugfixes", "FixPegasusClopping", std::move(FixPegasusClopping)); + FixC2CRankings = ini.Get("Bugfixes", "FixC2CRankings", std::move(FixC2CRankings)); + PreventDESTSaveCorruption = ini.Get("Bugfixes", "PreventDESTSaveCorruption", std::move(PreventDESTSaveCorruption)); + FixLensFlarePath = ini.Get("Bugfixes", "FixLensFlarePath", std::move(FixLensFlarePath)); + return true; } }; diff --git a/src/game_addrs.hpp b/src/game_addrs.hpp index a62eb86..881a4a7 100644 --- a/src/game_addrs.hpp +++ b/src/game_addrs.hpp @@ -45,6 +45,8 @@ namespace Game inline fn_0args GhostCarExecServer = nullptr; inline fn_0args fn4666A0 = nullptr; + inline fn_1arg PrjSndRequest = nullptr; + inline void init() { current_mode = Module::exe_ptr(0x38026C); @@ -82,5 +84,7 @@ namespace Game EventControl = Module::fn_ptr(0x3FAB0); // EventControl GhostCarExecServer = Module::fn_ptr(0x80F80); // GhostCarExecServer fn4666A0 = Module::fn_ptr(0x666A0); + + PrjSndRequest = Module::fn_ptr(0x249F0); } }; \ No newline at end of file diff --git a/src/hooks_bugfixes.cpp b/src/hooks_bugfixes.cpp index 7f62074..d45bc20 100644 --- a/src/hooks_bugfixes.cpp +++ b/src/hooks_bugfixes.cpp @@ -5,6 +5,40 @@ #include "plugin.hpp" #include "game_addrs.hpp" +class FixPegasusClopping : public Hook +{ + const static int SndOff_PEGA_Addr = 0x4BCC0; + + inline static SafetyHookInline SndOff_PEGA = {}; + static void destination() + { + SndOff_PEGA.call(); + + const int SND_STOP = 0x8000; + Game::PrjSndRequest(SND_STOP | 0x8D); // 0x8D = clop + } + +public: + std::string_view description() override + { + return "FixPegasusClopping"; + } + + bool validate() override + { + return Settings::FixPegasusClopping; + } + + bool apply() override + { + SndOff_PEGA = safetyhook::create_inline(Module::exe_ptr(SndOff_PEGA_Addr), destination); + return !!SndOff_PEGA; + } + + static FixPegasusClopping instance; +}; +FixPegasusClopping FixPegasusClopping::instance; + class FixC2CRankings : public Hook { // A lot of the C2C ranking code has a strange check that tries to OpenEventA an existing named event based on current process ID @@ -23,7 +57,7 @@ class FixC2CRankings : public Hook bool validate() override { - return true; + return Settings::FixC2CRankings; } bool apply() override @@ -67,7 +101,7 @@ class PreventDESTSaveCorruption : public Hook bool validate() override { - return true; + return Settings::PreventDESTSaveCorruption; } bool apply() override @@ -79,3 +113,42 @@ class PreventDESTSaveCorruption : public Hook static PreventDESTSaveCorruption instance; }; PreventDESTSaveCorruption PreventDESTSaveCorruption::instance; + +class FixLensFlarePath : public Hook +{ + // Game tries to load in lens flare data from common/, but the game files have it inside media/, causing lens flare not to be drawn. + // We'll just patch code to load from media/ instead + // (only patch it if file actually exists inside media/ though, some may have already moved it to common/) + + const static int LoadLensFlareOffset_StringAddr = 0x1A29F8; + +public: + std::string_view description() override + { + return "FixLensFlarePath"; + } + + bool validate() override + { + return Settings::FixLensFlarePath; + } + + bool apply() override + { + std::string NewPath = "\\media\\lens_flare_offset.bin"; + if (std::filesystem::exists("." + NewPath)) + { + auto* patch_addr = Module::exe_ptr(LoadLensFlareOffset_StringAddr); + + DWORD dwProtect; + VirtualProtect((void*)patch_addr, NewPath.length(), PAGE_EXECUTE_READWRITE, &dwProtect); + strcpy(patch_addr, NewPath.c_str()); + VirtualProtect((void*)patch_addr, NewPath.length(), dwProtect, &dwProtect); + } + + return true; + } + + static FixLensFlarePath instance; +}; +FixLensFlarePath FixLensFlarePath::instance; diff --git a/src/hooks_graphics.cpp b/src/hooks_graphics.cpp index 5d046fe..73a98d5 100644 --- a/src/hooks_graphics.cpp +++ b/src/hooks_graphics.cpp @@ -27,46 +27,6 @@ class DisableDPIScaling : public Hook }; DisableDPIScaling DisableDPIScaling::instance; -class LensFlarePathFix : public Hook -{ - const static int LoadLensFlareOffset_StringAddr = 0x1A29F8; - -public: - std::string_view description() override - { - return "LensFlarePathFix"; - } - - bool validate() override - { - return true; - } - - bool apply() override - { - // Game code tries to load lens_flare_offset.bin from the wrong path - // Code tries loading from common/, but game files have it inside media/ - // We'll just patch code to load from media/ instead - // (only patch it if file actually exists inside media/ though, some fix guides already told people to move it to common/) - - std::string NewPath = "\\media\\lens_flare_offset.bin"; - if (std::filesystem::exists("." + NewPath)) - { - auto* patch_addr = Module::exe_ptr(LoadLensFlareOffset_StringAddr); - - DWORD dwProtect; - VirtualProtect((void*)patch_addr, NewPath.length(), PAGE_EXECUTE_READWRITE, &dwProtect); - strcpy(patch_addr, NewPath.c_str()); - VirtualProtect((void*)patch_addr, NewPath.length(), dwProtect, &dwProtect); - } - - return true; - } - - static LensFlarePathFix instance; -}; -LensFlarePathFix LensFlarePathFix::instance; - class ScreenEdgeCullFix : public Hook { const static int CalcBall3D2D_Addr = 0x49E70; diff --git a/src/plugin.hpp b/src/plugin.hpp index ffe93b3..e69bd2e 100644 --- a/src/plugin.hpp +++ b/src/plugin.hpp @@ -56,6 +56,11 @@ namespace Settings inline bool SkipIntroLogos = false; inline bool CountdownTimerDisable = false; + + inline bool FixPegasusClopping = true; + inline bool FixC2CRankings = true; + inline bool PreventDESTSaveCorruption = true; + inline bool FixLensFlarePath = true; } namespace Util