diff --git a/data/plugins/GTAIV.EFLC.FusionFix.ini b/data/plugins/GTAIV.EFLC.FusionFix.ini index 50e0d590..9027ea95 100644 --- a/data/plugins/GTAIV.EFLC.FusionFix.ini +++ b/data/plugins/GTAIV.EFLC.FusionFix.ini @@ -19,8 +19,8 @@ ShadowBias = 5.0 // controls shadow bias, adjust ac ShadowSoftness = 3.0 // controls shadow blur ShadowBias = 8.0 // controls shadow bias, adjust according to softness -[NIGHTSHADOWS] // WARNING: enabling any of these options is not recommended -VehicleNightShadows = 0 // 1: enables shadows cast by vehicles from artificial lights, do not use with Headlight Shadows option +[NIGHTSHADOWS] // WARNING: enabling this option is not recommended +VehicleNightShadows = 0 // 1: with Headlight Shadows option, casts vehicle night shadows and disables player shadow(to avoid bugs), without Headlight Shadows enables shadows cast by vehicles from artificial lights [FRAMELIMIT] FrameLimitType = 2 // 1: realtime (thread-lock) | 2: accurate (sleep-yield), uses less resources diff --git a/external/modupdater b/external/modupdater index f0b371be..5fb99622 160000 --- a/external/modupdater +++ b/external/modupdater @@ -1 +1 @@ -Subproject commit f0b371be2fc8e450bbeae948a63ded9971142c8e +Subproject commit 5fb9962268d57d1ba549e273e020186e6e0eb97f diff --git a/source/comvars.ixx b/source/comvars.ixx index db7829ba..4fbdb1e0 100644 --- a/source/comvars.ixx +++ b/source/comvars.ixx @@ -1042,6 +1042,7 @@ export int bMenuNeedsUpdate2 = 0; export bool bEnableSnow = false; export bool bEnableHall = false; export bool bFixAutoExposure = true; +export bool bHeadlightShadows = false; export inline LONG getWindowWidth() { diff --git a/source/consoleshadows.ixx b/source/consoleshadows.ixx index d7c16a1c..79aace3b 100644 --- a/source/consoleshadows.ixx +++ b/source/consoleshadows.ixx @@ -10,11 +10,10 @@ import comvars; void* fnAE3DE0 = nullptr; void* fnAE3310 = nullptr; -bool bHeadlightShadows = false; bool bVehicleNightShadows = false; int __cdecl sub_AE3DE0(int a1, int a2) { - if (bVehicleNightShadows || bHeadlightShadows) + if (bVehicleNightShadows) injector::cstd::call(fnAE3310, a1, 0, 0, 0, a2); return injector::cstd::call(fnAE3DE0, a1, a2); } @@ -79,26 +78,6 @@ public: sh_grcSetRendersState = safetyhook::create_inline(pattern.get_first(0), grcSetRenderStateHook); } - // Enable player/ped shadows while in vehicles - //if (bVehicleNightShadows) - //{ - // auto pattern = hook::pattern("75 14 F6 86 ? ? ? ? ? 74 0B 80 7C 24 ? ? 0F 84 ? ? ? ? C6 44 24"); - // if (!pattern.empty()) - // { - // injector::WriteMemory(pattern.get_first(0), 0xEB, true); - // pattern = hook::pattern("75 12 8B 86 ? ? ? ? C1 E8 0B 25 ? ? ? ? 89 44 24 0C 85 D2"); - // injector::WriteMemory(pattern.get_first(0), 0xEB, true); - // } - // else - // { - // pattern = hook::pattern("75 17 F6 86 ? ? ? ? ? 74 0E 80 7C 24 ? ? 0F 84"); - // injector::WriteMemory(pattern.get_first(0), 0xEB, true); - // pattern = hook::pattern("75 0F 8B 86 ? ? ? ? C1 E8 0B 24 01 88 44 24 0E"); - // injector::WriteMemory(pattern.get_first(0), 0xEB, true); - // } - // - //} - // Headlight shadows { auto pattern = hook::pattern("68 04 05 00 00 6A 02 6A 00"); @@ -121,40 +100,47 @@ public: }); bHeadlightShadows = FusionFixSettings("PREF_HEADLIGHTSHADOWS"); - struct test + pattern = hook::pattern("E8 ? ? ? ? 85 C0 74 29 6A 00"); + if (!pattern.empty()) { - void operator()(injector::reg_pack& regs) - { - auto FindPlayerCar = (int (*)())0x93F1C0; - auto getLocalPlayerPed = (int (*)())0x93F050; + static auto getLocalPlayerPed = (int (*)())injector::GetBranchDestination(pattern.get_first(0)).as_int(); + static auto FindPlayerCar = (int (*)())injector::GetBranchDestination(pattern.get_first(11)).as_int(); - if (bHeadlightShadows) + static auto loc_AE3867 = (uintptr_t)hook::get_pattern("8B 74 24 14 FF 44 24 10"); + static auto loc_AE376B = (uintptr_t)hook::get_pattern("85 D2 75 4C 0F B6 46 62 50"); + static auto loc_AE374F = (uintptr_t)hook::get_pattern("C6 44 24 ? ? 83 F8 04 75 12"); + + pattern = hook::pattern("83 F8 03 75 14 F6 86"); + struct ShadowsHook + { + void operator()(injector::reg_pack& regs) { - auto car = FindPlayerCar(); + if (bHeadlightShadows && bVehicleNightShadows) + { + auto car = FindPlayerCar(); + + // Disable player/car shadows + if (regs.esi && (regs.esi == car || (regs.esi == getLocalPlayerPed() && car && *(uint32_t*)(car + 0xFA0) == regs.esi))) + { + *(uintptr_t*)(regs.esp - 4) = loc_AE3867; + return; + } + } - if (regs.esi && (regs.esi == car || (regs.esi == getLocalPlayerPed() && car && *(BYTE*)(car + 0xFA0)))) + // Enable player/ped shadows while in vehicles + if (bHeadlightShadows && bVehicleNightShadows && (regs.eax == 3 || regs.eax == 4)) { - *(uintptr_t*)(regs.esp - 4) = 0xAE3867; + *(uintptr_t*)(regs.esp - 4) = loc_AE376B; return; } + + if ((*(uint8_t*)(regs.esi + 620) & 4) == 0) + { + *(uintptr_t*)(regs.esp - 4) = loc_AE374F; + } } - - if ((bVehicleNightShadows && !bHeadlightShadows) && (regs.eax == 3 || regs.eax == 4)) - { - *(uintptr_t*)(regs.esp - 4) = 0xAE376B; - return; - } - - if ((*(BYTE*)(regs.esi + 620) & 4) != 0) - { - - } - else - { - *(uintptr_t*)(regs.esp - 4) = 0xAE374F; - } - } - }; injector::MakeInline(0xAE3736, 0xAE3744); + }; injector::MakeInline(pattern.get_first(0), pattern.get_first(14)); + } } }; } diff --git a/source/extrainfo.ixx b/source/extrainfo.ixx index 3e5fa97a..58ffef94 100644 --- a/source/extrainfo.ixx +++ b/source/extrainfo.ixx @@ -49,11 +49,21 @@ public: if (imgNum >= imgArrSize) extra += FF_WARN1[0] ? FF_WARN1 : L"; ~r~WARNING: 255 IMG limit exceeded, will cause streaming issues."; static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); - if (LamppostShadows->get()) + if (LamppostShadows->get() || bHeadlightShadows) { extra += L"~n~"; extra += L" "; - auto FF_WARN2 = CText::getText("FF_WARN2"); + auto FF_WARN2 = std::wstring(CText::getText("FF_WARN2")); + auto HeadlightShadow = CText::getText("HeadlightShadow"); + + if (bHeadlightShadows) + { + auto pos = FF_WARN2.find(L": "); + if (pos != std::wstring::npos) { + FF_WARN2.replace(pos, 2, L": " + std::wstring(HeadlightShadow) + L" / "); + } + } + if (FF_WARN2[0]) extra += FF_WARN2; else diff --git a/source/fixes.ixx b/source/fixes.ixx index a296ff7f..e7888a3c 100644 --- a/source/fixes.ixx +++ b/source/fixes.ixx @@ -56,32 +56,6 @@ public: return r; } - static inline SafetyHookInline shsub_925DB0{}; - static int __cdecl sub_925DB0(int a1, int a2, int flags) - { - static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); - if (!LamppostShadows->get()) - { - if (!Natives::IsInteriorScene()) - return -1; - } - - return shsub_925DB0.ccall(a1, a2, flags); - } - - static inline SafetyHookInline shsub_D77A00{}; - static void __fastcall sub_D77A00(void* _this, void* edx) - { - static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); - if (!LamppostShadows->get()) - { - if (!Natives::IsInteriorScene()) - return; - } - - return shsub_D77A00.fastcall(_this, edx); - } - Fixes() { FusionFix::onInitEventAsync() += []() @@ -436,36 +410,6 @@ public: if (!pattern.empty()) injector::MakeNOP(pattern.get_first(0), 8, true); } - - // Lampposts shadows workaround - { - auto pattern = hook::pattern("80 3D ? ? ? ? ? 75 04 83 C8 FF"); - shsub_925DB0 = safetyhook::create_inline(pattern.get_first(), sub_925DB0); - - pattern = find_pattern("83 EC 3C 80 3D ? ? ? ? ? 56 8B F1", "83 EC 3C 53 33 DB"); - shsub_D77A00 = safetyhook::create_inline(pattern.get_first(0), sub_D77A00); - - pattern = find_pattern("8B 55 20 F6 C1 06"); - if (!pattern.empty()) - { - static auto ShadowsHook2 = safetyhook::create_mid(pattern.get_first(0), [](SafetyHookContext& regs) - { - static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); - if (!LamppostShadows->get()) - { - if (Natives::IsInteriorScene()) - { - if ((*(uint32_t*)(regs.edi + 0x4C) & 0x8000000) != 0) // new flag to detect affected lampposts - { - regs.ecx &= ~3; - regs.ecx &= ~4; - *(uint32_t*)(regs.esp + 0x18) = regs.ecx; - } - } - } - }); - } - } // Render LOD lights during cutscenes (console behavior) { diff --git a/source/shadows.ixx b/source/shadows.ixx index 4a323856..f979a627 100644 --- a/source/shadows.ixx +++ b/source/shadows.ixx @@ -8,6 +8,7 @@ import ; import common; import comvars; import settings; +import natives; int32_t bExtraDynamicShadows; std::string curModelName; @@ -102,6 +103,32 @@ int GetNightShadowQuality() class Shadows { + static inline SafetyHookInline shsub_925DB0{}; + static int __cdecl sub_925DB0(int a1, int a2, int flags) + { + static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); + if (!LamppostShadows->get() && !bHeadlightShadows) + { + if (!Natives::IsInteriorScene()) + return -1; + } + + return shsub_925DB0.ccall(a1, a2, flags); + } + + static inline SafetyHookInline shsub_D77A00{}; + static void __fastcall sub_D77A00(void* _this, void* edx) + { + static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); + if (!LamppostShadows->get()) + { + if (!Natives::IsInteriorScene()) + return; + } + + return shsub_D77A00.fastcall(_this, edx); + } + public: Shadows() { @@ -244,6 +271,36 @@ public: // Fix night shadow resolution pattern = find_pattern("8B 0D ? ? ? ? 85 C9 7E 1B", "8B 0D ? ? ? ? 33 C0 85 C9 7E 1B"); static auto shsub_925E70 = safetyhook::create_inline(pattern.get_first(0), GetNightShadowQuality); + + // Lampposts shadows workaround + { + auto pattern = hook::pattern("80 3D ? ? ? ? ? 75 04 83 C8 FF"); + shsub_925DB0 = safetyhook::create_inline(pattern.get_first(), sub_925DB0); + + pattern = find_pattern("83 EC 3C 80 3D ? ? ? ? ? 56 8B F1", "83 EC 3C 53 33 DB"); + shsub_D77A00 = safetyhook::create_inline(pattern.get_first(0), sub_D77A00); + + pattern = find_pattern("8B 55 20 F6 C1 06"); + if (!pattern.empty()) + { + static auto ShadowsHook2 = safetyhook::create_mid(pattern.get_first(0), [](SafetyHookContext& regs) + { + static auto LamppostShadows = FusionFixSettings.GetRef("PREF_LAMPPOSTSHADOWS"); + if (!LamppostShadows->get()) + { + if (Natives::IsInteriorScene()) + { + if ((*(uint32_t*)(regs.edi + 0x4C) & 0x8000000) != 0) // new flag to detect affected lampposts + { + regs.ecx &= ~3; + regs.ecx &= ~4; + *(uint32_t*)(regs.esp + 0x18) = regs.ecx; + } + } + } + }); + } + } } }; }