diff --git a/data/plugins/MaxPayne3.FusionFix.ini b/data/plugins/MaxPayne3.FusionFix.ini index c3f5635..8ca7377 100644 --- a/data/plugins/MaxPayne3.FusionFix.ini +++ b/data/plugins/MaxPayne3.FusionFix.ini @@ -1,8 +1,10 @@ [MAIN] +SkipIntro = 1 HideSkipButton = 1 -DisableGlobalLeaderboards = 1 // Fixes Hoboken Alleys map crash in coop +DisableGlobalLeaderboards = 1 // Fixes Hoboken Alleys map crash in coop OutlinesSizeMultiplier = 1.0f BorderlessWindowed = 1 +LightSyncRGB = 1 // Only Logitech hardware is supported, requires Logitech G HUB app GamepadIcons = 0 ; 0 - Xbox 360 ; 1 - Xbox One diff --git a/source/dllmain.cpp b/source/dllmain.cpp index 52247ae..c0818ef 100644 --- a/source/dllmain.cpp +++ b/source/dllmain.cpp @@ -7,6 +7,7 @@ import common; import comvars; import settings; +import natives; injector::hook_back hbCGameProcess; void __cdecl CGameProcessHook() @@ -17,30 +18,26 @@ void __cdecl CGameProcessHook() FusionFix::onGameInitEvent().executeAll(); }); - //if (CTimer__m_UserPause && CTimer__m_CodePause) - //{ - static auto oldMenuState = 0; - - //if (!*CTimer__m_UserPause && !*CTimer__m_CodePause) - //{ - uint32_t curMenuState = false; - if (curMenuState != oldMenuState) - { - FusionFix::onMenuExitEvent().executeAll(); - } - oldMenuState = curMenuState; - FusionFix::onGameProcessEvent().executeAll(); - //} - //else - //{ - // uint32_t curMenuState = true; - // if (curMenuState != oldMenuState) { - // FusionFix::onMenuEnterEvent().executeAll(); - // } - // oldMenuState = curMenuState; - // FusionFix::onMenuDrawingEvent().executeAll(); - //} - //} + static auto oldMenuState = 0; + if (!Natives::IsPauseMenuActive()) + { + auto curMenuState = false; + if (curMenuState != oldMenuState) + { + FusionFix::onMenuExitEvent().executeAll(); + } + oldMenuState = curMenuState; + FusionFix::onGameProcessEvent().executeAll(); + } + else + { + auto curMenuState = true; + if (curMenuState != oldMenuState) { + FusionFix::onMenuEnterEvent().executeAll(); + } + oldMenuState = curMenuState; + FusionFix::onMenuDrawingEvent().executeAll(); + } return hbCGameProcess.fun(); } @@ -52,14 +49,14 @@ void Init() auto pattern = hook::pattern("E8 ? ? ? ? E8 ? ? ? ? 8B 0D ? ? ? ? 8B 15 ? ? ? ? 89 0D"); hbCGameProcess.fun = injector::MakeCALL(pattern.get_first(0), CGameProcessHook, true).get(); - //static auto futures = FusionFix::onInitEventAsync().executeAllAsync(); + static auto futures = FusionFix::onInitEventAsync().executeAllAsync(); - //FusionFix::onGameInitEvent() += []() - //{ - // for (auto& f : futures.get()) - // f.wait(); - // futures.get().clear(); - //}; + FusionFix::onGameInitEvent() += []() + { + for (auto& f : futures.get()) + f.wait(); + futures.get().clear(); + }; FusionFix::onInitEvent().executeAll(); } diff --git a/source/hideskip.ixx b/source/hideskip.ixx index 8abd3cf..0fc5678 100644 --- a/source/hideskip.ixx +++ b/source/hideskip.ixx @@ -18,19 +18,26 @@ public: static raw_mem fnHideSkip1(pattern.get_first(8), { 0x90, 0x90, 0x90, 0x90, 0x90 }); // nop x5 pattern = hook::pattern("8B C8 89 86 ? ? ? ? E8 ? ? ? ? D9 EE 8B 86 ? ? ? ? 8B 38 83 EC 08 D9 54 24 04 8D 4C 24 20 D9 1C 24 E8 ? ? ? ? F3 0F 7E 00 8B 97 ? ? ? ? 83 EC 18 8B CC 66 0F D6 01 F3 0F 7E 40 ? 66 0F D6 41 ? F3 0F 7E 40 ? 6A 18 68 ? ? ? ? 66 0F D6 41 ? 8B 8E ? ? ? ? 6A 18"); static raw_mem fnHideSkip2(pattern.get_first(8), { 0x90, 0x90, 0x90, 0x90, 0x90 }); // nop x5 + + static auto HideSkipCB = []() + { + if (FusionFixSettings.GetInt("PREF_HIDESKIP")) + { + fnHideSkip1.Write(); + fnHideSkip2.Write(); + } + else + { + fnHideSkip1.Restore(); + fnHideSkip2.Restore(); + } + }; + + HideSkipCB(); FusionFix::onIniFileChange() += []() { - if (FusionFixSettings.GetInt("PREF_HIDESKIP")) - { - fnHideSkip1.Write(); - fnHideSkip2.Write(); - } - else - { - fnHideSkip1.Restore(); - fnHideSkip2.Restore(); - } + HideSkipCB(); }; }; } diff --git a/source/leaderboards.ixx b/source/leaderboards.ixx index e1fd80c..51d3f62 100644 --- a/source/leaderboards.ixx +++ b/source/leaderboards.ixx @@ -17,13 +17,20 @@ public: auto pattern = hook::pattern("8B 81 ? ? ? ? 83 F8 06"); static raw_mem fnLeaderboards(pattern.get_first(0), { 0xC3 }); // ret - FusionFix::onIniFileChange() += []() + static auto LeaderboardsCB = []() { if (FusionFixSettings.GetInt("PREF_DISABLELEADERBOARDS")) fnLeaderboards.Write(); else fnLeaderboards.Restore(); }; + + LeaderboardsCB(); + + FusionFix::onIniFileChange() += []() + { + LeaderboardsCB(); + }; }; } } Leaderboards; \ No newline at end of file diff --git a/source/led.ixx b/source/led.ixx new file mode 100644 index 0000000..5544e48 --- /dev/null +++ b/source/led.ixx @@ -0,0 +1,231 @@ +module; + +#include +#include "ledsdk/LogitechLEDLib.h" + +export module led; + +import common; +import settings; +import natives; + +bool bLogiLedInitialized = false; + +void AmbientLighting() +{ + LogiLedSetTargetDevice(LOGI_DEVICETYPE_ALL); + LogiLedSetLighting(100, 0, 0); +} + +void AmmoInClip() +{ + static std::vector keysLH = { + LogiLed::KeyName::TILDE, LogiLed::KeyName::ONE, LogiLed::KeyName::TWO, LogiLed::KeyName::THREE, + LogiLed::KeyName::FOUR,LogiLed::KeyName::FIVE,LogiLed::KeyName::SIX,LogiLed::KeyName::SEVEN, + LogiLed::KeyName::EIGHT,LogiLed::KeyName::NINE,LogiLed::KeyName::ZERO,LogiLed::KeyName::MINUS, + LogiLed::KeyName::EQUALS, + }; + + static std::vector keysRH = { + LogiLed::KeyName::F1, LogiLed::KeyName::F2, LogiLed::KeyName::F3, + LogiLed::KeyName::F4, LogiLed::KeyName::F5, LogiLed::KeyName::F6, + LogiLed::KeyName::F7, LogiLed::KeyName::F8, LogiLed::KeyName::F9, + LogiLed::KeyName::F10, LogiLed::KeyName::F11, LogiLed::KeyName::F12, + LogiLed::KeyName::PRINT_SCREEN, LogiLed::KeyName::SCROLL_LOCK, + LogiLed::KeyName::PAUSE_BREAK, + }; + + if (Natives::DoesMainPlayerExist()) + { + auto pPlayerPed = Natives::GetPlayerPed(Natives::GetPlayerId()); + auto pPlayerWeaponRH = Natives::GetWeaponFromHand(pPlayerPed, 0, 0); + auto pPlayerWeaponLH = Natives::GetWeaponFromHand(pPlayerPed, 1, 0); + + if (pPlayerWeaponRH) + { + static auto oldAmmoInClip = -1; + auto ammoInClip = Natives::GetWeaponAmmoInClip(pPlayerWeaponRH); + if (ammoInClip != oldAmmoInClip) + { + auto maxAmmoInClip = Natives::GetMaxAmmoInClip(pPlayerPed, Natives::GetWeaponType(pPlayerWeaponRH)); + auto ammoInClipPercent = ((float)ammoInClip / (float)maxAmmoInClip) * 100.0f; + + for (size_t i = 0; i < keysRH.size(); i++) + { + auto indexInPercent = ((float)i / (float)keysRH.size()) * 100.0f; + if (ammoInClipPercent > indexInPercent) + LogiLedSetLightingForKeyWithKeyName(keysRH[i], 100, 100, 100); + else + LogiLedSetLightingForKeyWithKeyName(keysRH[i], 25, 25, 25); + } + } + oldAmmoInClip = ammoInClip; + } + else + { + for (auto k : keysRH) + LogiLedSetLightingForKeyWithKeyName(k, 25, 25, 25); + } + + if (pPlayerWeaponLH) + { + static auto oldAmmoInClip = -1; + auto ammoInClip = Natives::GetWeaponAmmoInClip(pPlayerWeaponLH); + if (ammoInClip != oldAmmoInClip) + { + auto maxAmmoInClip = Natives::GetMaxAmmoInClip(pPlayerPed, Natives::GetWeaponType(pPlayerWeaponLH)); + auto ammoInClipPercent = ((float)ammoInClip / (float)maxAmmoInClip) * 100.0f; + + for (size_t i = 0; i < keysLH.size(); i++) + { + auto indexInPercent = ((float)i / (float)keysLH.size()) * 100.0f; + if (ammoInClipPercent > indexInPercent) + LogiLedSetLightingForKeyWithKeyName(keysLH[i], 100, 100, 100); + else + LogiLedSetLightingForKeyWithKeyName(keysLH[i], 25, 25, 25); + } + } + oldAmmoInClip = ammoInClip; + } + else + { + for (auto k : keysLH) + LogiLedSetLightingForKeyWithKeyName(k, 25, 25, 25); + } + + { + static std::vector keys = { + LogiLed::KeyName::NUM_ONE, LogiLed::KeyName::NUM_TWO, LogiLed::KeyName::NUM_THREE, + LogiLed::KeyName::NUM_FOUR, LogiLed::KeyName::NUM_FIVE, LogiLed::KeyName::NUM_SIX, + LogiLed::KeyName::NUM_SEVEN, LogiLed::KeyName::NUM_EIGHT, LogiLed::KeyName::NUM_NINE, + }; + + static auto oldPayneKillersAmt = -1; + auto payneKillersAmt = Natives::GetPaynekillerAmt(); + if (payneKillersAmt != oldPayneKillersAmt) + { + constexpr auto maxPayneKillersAmt = 9; + + for (auto i = 0; i < maxPayneKillersAmt; i++) + { + if (payneKillersAmt > i) + LogiLedSetLightingForKeyWithKeyName(keys[i], 100, 100, 100); + else + LogiLedSetLightingForKeyWithKeyName(keys[i], 25, 25, 25); + } + } + oldPayneKillersAmt = payneKillersAmt; + } + } +} + +void CurrentHealth(bool bForce = false) +{ + static std::vector keys = { + LogiLed::KeyName::G_1, LogiLed::KeyName::G_2, LogiLed::KeyName::G_3, LogiLed::KeyName::G_4, LogiLed::KeyName::G_5, + }; + + if (Natives::DoesMainPlayerExist()) + { + auto pPlayerPed = Natives::GetPlayerPed(Natives::GetPlayerId()); + + if (pPlayerPed) + { + auto pPlayerHealth = Natives::GetPedHealth(pPlayerPed); + static auto oldHealth = 0; + if (pPlayerHealth != oldHealth || bForce) + { + auto maxPlayerHealth = Natives::GetPedMaxHealth(pPlayerPed); + float healthPercent = (((float)pPlayerHealth - 100.0f) / ((float)maxPlayerHealth - 100.0f)) * 100.0f; + + for (size_t i = 0; i < keys.size(); i++) + { + auto indexInPercent = ((float)i / (float)keys.size()) * 100.0f; + if (healthPercent < indexInPercent) + LogiLedSetLightingForKeyWithKeyName(keys[i], 100, 0, 0); + else + LogiLedSetLightingForKeyWithKeyName(keys[i], 100, 100, 100); + } + } + oldHealth = pPlayerHealth; + } + } +} + +void ProcessLEDEvents() +{ + AmmoInClip(); + CurrentHealth(); +} + +class LED +{ +public: + LED() + { + FusionFix::onInitEvent() += []() + { + if (FusionFixSettings.GetInt("PREF_LEDILLUMINATION")) + { + bLogiLedInitialized = LogiLedInit(); + if (bLogiLedInitialized) + AmbientLighting(); + } + + FusionFix::onIniFileChange() += []() + { + if (FusionFixSettings.GetInt("PREF_LEDILLUMINATION")) + { + if (!bLogiLedInitialized) { + bLogiLedInitialized = LogiLedInit(); + if (bLogiLedInitialized) + AmbientLighting(); + } + } + else if (bLogiLedInitialized) { + LogiLedShutdown(); + bLogiLedInitialized = false; + } + }; + }; + + FusionFix::onGameProcessEvent() += []() + { + if (bLogiLedInitialized) + { + ProcessLEDEvents(); + } + }; + + FusionFix::onMenuEnterEvent() += []() + { + LogiLedSaveCurrentLighting(); + LogiLedSetTargetDevice(LOGI_DEVICETYPE_ALL); + AmbientLighting(); + }; + + FusionFix::onMenuExitEvent() += []() + { + LogiLedRestoreLighting(); + CurrentHealth(true); + }; + + FusionFix::onShutdownEvent() += []() + { + if (bLogiLedInitialized) { + LogiLedShutdown(); + bLogiLedInitialized = false; + } + }; + + IATHook::Replace(GetModuleHandleA(NULL), "KERNEL32.DLL", + std::forward_as_tuple("ExitProcess", static_cast([](UINT uExitCode) { + if (bLogiLedInitialized) { + LogiLedShutdown(); + bLogiLedInitialized = false; + } + ExitProcess(uExitCode); + })) + ); + } +} LED; \ No newline at end of file diff --git a/source/natives.ixx b/source/natives.ixx index 0d5818a..cb44d86 100644 --- a/source/natives.ixx +++ b/source/natives.ixx @@ -197,21 +197,18 @@ public: NativeContext cxt; (cxt.Push(args), ...); - //if (CTimer__m_CodePause && !*CTimer__m_CodePause) - //{ - if (!m_IndexTable[Hash]) - { - auto fn = GetNativeHandler(Hash); - if (fn) { - m_IndexTable[Hash] = fn; - fn->fun(&cxt); - } - } - else - { - m_IndexTable[Hash]->fun(&cxt); + if (!m_IndexTable[Hash]) + { + auto fn = GetNativeHandler(Hash); + if (fn) { + m_IndexTable[Hash] = fn; + fn->fun(&cxt); } - //} + } + else + { + m_IndexTable[Hash]->fun(&cxt); + } if constexpr (!std::is_void_v) { diff --git a/source/settings.ixx b/source/settings.ixx index 8787504..a904c05 100644 --- a/source/settings.ixx +++ b/source/settings.ixx @@ -9,8 +9,6 @@ export module settings; import common; import comvars; - - export class CSettings { private: @@ -20,10 +18,12 @@ public: static inline void ReadIniSettings() { CIniReader iniReader(""); + mFusionPrefs["PREF_SKIPINTRO"] = std::clamp(iniReader.ReadInteger("MAIN", "SkipIntro", 1), 0, 1); mFusionPrefs["PREF_HIDESKIP"] = std::clamp(iniReader.ReadInteger("MAIN", "HideSkipButton", 1), 0, 1); mFusionPrefs["PREF_DISABLELEADERBOARDS"] = std::clamp(iniReader.ReadInteger("MAIN", "DisableGlobalLeaderboards", 1), 0, 1); mFusionPrefs["PREF_OUTLINESIZE"] = std::clamp(iniReader.ReadFloat("MAIN", "OutlinesSizeMultiplier", 1.0f), 0.0f, 10.0f); mFusionPrefs["PREF_BORDERLESS"] = std::clamp(iniReader.ReadInteger("MAIN", "BorderlessWindowed", 1), 0, 1); + mFusionPrefs["PREF_LEDILLUMINATION"] = std::clamp(iniReader.ReadInteger("MAIN", "LightSyncRGB", 1), 0, 1); mFusionPrefs["PREF_BUTTONS"] = std::clamp(iniReader.ReadInteger("MAIN", "GamepadIcons", 0), 0, 6); static std::once_flag flag; diff --git a/source/skipintro.ixx b/source/skipintro.ixx new file mode 100644 index 0000000..08527b5 --- /dev/null +++ b/source/skipintro.ixx @@ -0,0 +1,46 @@ +module; + +#include + +export module skipintro; + +import common; +import settings; + +class SkipIntro +{ +public: + SkipIntro() + { + FusionFix::onInitEvent() += []() + { + if (FusionFixSettings.GetInt("PREF_SKIPINTRO")) + { + // legal screens + auto pattern = hook::pattern("81 FF ? ? ? ? 0F 86 ? ? ? ? E8 ? ? ? ? 89 86 ? ? ? ? 05 ? ? ? ? 89 86 ? ? ? ? C6 86 ? ? ? ? ? E9 ? ? ? ? 3C 01"); + injector::WriteMemory(pattern.get_first(2), 0, true); + pattern = hook::pattern("05 ? ? ? ? 89 86 ? ? ? ? C6 86 ? ? ? ? ? E9 ? ? ? ? 3C 01"); + injector::WriteMemory(pattern.get_first(1), 0, true); + pattern = hook::pattern("81 FF ? ? ? ? 0F 86 ? ? ? ? E8 ? ? ? ? 89 86 ? ? ? ? 05 ? ? ? ? 89 86 ? ? ? ? C6 86 ? ? ? ? ? E9 ? ? ? ? 3C 02"); + injector::WriteMemory(pattern.get_first(2), 0, true); + pattern = hook::pattern("05 ? ? ? ? 89 86 ? ? ? ? C6 86 ? ? ? ? ? E9 ? ? ? ? 3C 02"); + injector::WriteMemory(pattern.get_first(1), 0, true); + pattern = hook::pattern("81 FF ? ? ? ? 76 66"); + injector::WriteMemory(pattern.get_first(2), 0, true); + pattern = hook::pattern("05 ? ? ? ? 89 86 ? ? ? ? 8B 11"); + injector::WriteMemory(pattern.get_first(1), 0, true); + + pattern = hook::pattern("81 FF ? ? ? ? 76 4B"); + injector::WriteMemory(pattern.get_first(2), 0, true); + pattern = hook::pattern("3D ? ? ? ? 7D 0A E8"); + injector::WriteMemory(pattern.get_first(1), 0, true); + + // video + pattern = hook::pattern("74 25 6A 00 B9"); + injector::WriteMemory(pattern.get_first(), 0xEB, true); + pattern = hook::pattern("75 21 53 B9"); + injector::WriteMemory(pattern.get_first(), 0xEB, true); + } + }; + } +} SkipIntro; \ No newline at end of file