@@ -10,11 +10,10 @@ import comvars;
1010
1111void * fnAE3DE0 = nullptr ;
1212void * fnAE3310 = nullptr ;
13- bool bHeadlightShadows = true ;
1413bool bVehicleNightShadows = false ;
1514int __cdecl sub_AE3DE0 (int a1, int a2)
1615{
17- if (bVehicleNightShadows && !bHeadlightShadows )
16+ if (bVehicleNightShadows)
1817 injector::cstd<void (int , int , int , int , int )>::call (fnAE3310, a1, 0 , 0 , 0 , a2);
1918 return injector::cstd<int (int , int )>::call (fnAE3DE0, a1, a2);
2019}
@@ -29,6 +28,29 @@ void __stdcall grcSetRenderStateHook()
2928 }
3029}
3130
31+ namespace CShadows
32+ {
33+ injector::hook_back<void (__cdecl*)(int , int , int , int , int , int , int , int , int , int , int , int , int , int , int )> hbStoreStaticShadow;
34+
35+ void __cdecl StoreStaticShadowPlayerDriving (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15)
36+ {
37+ if (!bHeadlightShadows)
38+ {
39+ a3 &= ~3 ;
40+ a3 &= ~4 ;
41+ }
42+
43+ return hbStoreStaticShadow.fun (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
44+ }
45+
46+ void __cdecl StoreStaticShadowNPC (int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, int a12, int a13, int a14, int a15)
47+ {
48+ a3 &= ~3 ;
49+ a3 &= ~4 ;
50+
51+ return hbStoreStaticShadow.fun (a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15);
52+ }
53+ }
3254class ConsoleShadows
3355{
3456public:
@@ -37,7 +59,6 @@ public:
3759 FusionFix::onInitEventAsync () += []()
3860 {
3961 CIniReader iniReader (" " );
40- bHeadlightShadows = iniReader.ReadInteger (" NIGHTSHADOWS" , " HeadlightShadows" , 1 ) != 0 ;
4162 bVehicleNightShadows = iniReader.ReadInteger (" NIGHTSHADOWS" , " VehicleNightShadows" , 0 ) != 0 ;
4263
4364 // Render dynamic shadows casted by vehicles from point lights.
@@ -57,46 +78,68 @@ public:
5778 sh_grcSetRendersState = safetyhook::create_inline (pattern.get_first (0 ), grcSetRenderStateHook);
5879 }
5980
60- // Enable player/ped shadows while in vehicles
61- if (bVehicleNightShadows && !bHeadlightShadows)
81+ // Headlight shadows
6282 {
63- auto pattern = hook::pattern (" 75 14 F6 86 ? ? ? ? ? 74 0B 80 7C 24 ? ? 0F 84 ? ? ? ? C6 44 24 " );
64- if (!pattern.empty ())
83+ auto pattern = hook::pattern (" 68 04 05 00 00 6A 02 6A 00 " );
84+ if (!pattern.count ( 2 ). empty ())
6585 {
66- injector::WriteMemory<uint8_t >(pattern.get_first (0 ), 0xEB , true );
67- pattern = hook::pattern (" 75 12 8B 86 ? ? ? ? C1 E8 0B 25 ? ? ? ? 89 44 24 0C 85 D2" );
68- injector::WriteMemory<uint8_t >(pattern.get_first (0 ), 0xEB , true );
86+ CShadows::hbStoreStaticShadow.fun = injector::MakeCALL (pattern.count (2 ).get (0 ).get <void *>(9 ), CShadows::StoreStaticShadowPlayerDriving).get ();
87+ CShadows::hbStoreStaticShadow.fun = injector::MakeCALL (pattern.count (2 ).get (1 ).get <void *>(9 ), CShadows::StoreStaticShadowPlayerDriving).get ();
6988 }
70- else
89+
90+ pattern = hook::pattern (" 68 04 01 00 00 6A 02 6A 00" );
91+ if (!pattern.count (2 ).empty ())
7192 {
72- pattern = hook::pattern (" 75 17 F6 86 ? ? ? ? ? 74 0E 80 7C 24 ? ? 0F 84" );
73- injector::WriteMemory<uint8_t >(pattern.get_first (0 ), 0xEB , true );
74- pattern = hook::pattern (" 75 0F 8B 86 ? ? ? ? C1 E8 0B 24 01 88 44 24 0E" );
75- injector::WriteMemory<uint8_t >(pattern.get_first (0 ), 0xEB , true );
93+ CShadows::hbStoreStaticShadow.fun = injector::MakeCALL (pattern.count (2 ).get (0 ).get <void *>(9 ), CShadows::StoreStaticShadowNPC).get ();
94+ CShadows::hbStoreStaticShadow.fun = injector::MakeCALL (pattern.count (2 ).get (1 ).get <void *>(9 ), CShadows::StoreStaticShadowNPC).get ();
7695 }
96+
97+ FusionFixSettings.SetCallback (" PREF_HEADLIGHTSHADOWS" , [](int32_t value)
98+ {
99+ bHeadlightShadows = value;
100+ });
101+ bHeadlightShadows = FusionFixSettings (" PREF_HEADLIGHTSHADOWS" );
77102
78- }
79-
80- // Disable headlight shadows to avoid flickering/self-shadowing.
81- if (!bHeadlightShadows)
82- {
83- auto pattern = hook::pattern (" 74 76 FF 75 30 FF 75 2C FF 75 28 83 EC 0C 80 7D 38 00" );
103+ pattern = hook::pattern (" E8 ? ? ? ? 85 C0 74 29 6A 00" );
84104 if (!pattern.empty ())
85105 {
86- injector::WriteMemory<uint8_t >(pattern.get_first (0 ), 0xEB , true );
87- pattern = hook::pattern (" 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3 68" );
88- injector::WriteMemory (pattern.count (2 ).get (1 ).get <void *>(1 ), 0x100 , true );
89- pattern = hook::pattern (" 8B E5 5D C3 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 8B E5 5D C3" );
90- injector::WriteMemory (pattern.count (2 ).get (1 ).get <void *>(5 ), 0x100 , true );
91- }
92- else
93- {
94- pattern = hook::pattern (" 0F 84 ? ? ? ? 80 7D 28 00 74 4C 8B 45 20 8B 0D" );
95- injector::WriteMemory<uint16_t >(pattern.get_first (0 ), 0xE990 , true );
96- pattern = hook::pattern (" 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3 8B 15" );
97- injector::WriteMemory (pattern.get_first (1 ), 0x100 , true );
98- pattern = hook::pattern (" 8D 44 24 50 50 68 ? ? ? ? 6A 02 6A 00 E8 ? ? ? ? 83 C4 40 5B 8B E5 5D C3" );
99- injector::WriteMemory (pattern.get_first (6 ), 0x100 , true );
106+ static auto getLocalPlayerPed = (int (*)())injector::GetBranchDestination (pattern.get_first (0 )).as_int ();
107+ static auto FindPlayerCar = (int (*)())injector::GetBranchDestination (pattern.get_first (11 )).as_int ();
108+
109+ static auto loc_AE3867 = (uintptr_t )hook::get_pattern (" 8B 74 24 14 FF 44 24 10" );
110+ static auto loc_AE376B = (uintptr_t )hook::get_pattern (" 85 D2 75 4C 0F B6 46 62 50" );
111+ static auto loc_AE374F = (uintptr_t )hook::get_pattern (" C6 44 24 ? ? 83 F8 04 75 12" );
112+
113+ pattern = hook::pattern (" 83 F8 03 75 14 F6 86" );
114+ struct ShadowsHook
115+ {
116+ void operator ()(injector::reg_pack& regs)
117+ {
118+ if (bHeadlightShadows && bVehicleNightShadows)
119+ {
120+ auto car = FindPlayerCar ();
121+
122+ // Disable player/car shadows
123+ if (regs.esi && (regs.esi == car || (regs.esi == getLocalPlayerPed () && car && *(uint32_t *)(car + 0xFA0 ))))
124+ {
125+ *(uintptr_t *)(regs.esp - 4 ) = loc_AE3867;
126+ return ;
127+ }
128+ }
129+
130+ // Enable player/ped shadows while in vehicles
131+ if (bHeadlightShadows && bVehicleNightShadows && (regs.eax == 3 || regs.eax == 4 ))
132+ {
133+ *(uintptr_t *)(regs.esp - 4 ) = loc_AE376B;
134+ return ;
135+ }
136+
137+ if ((*(uint8_t *)(regs.esi + 620 ) & 4 ) == 0 )
138+ {
139+ *(uintptr_t *)(regs.esp - 4 ) = loc_AE374F;
140+ }
141+ }
142+ }; injector::MakeInline<ShadowsHook>(pattern.get_first (0 ), pattern.get_first (14 ));
100143 }
101144 }
102145 };
0 commit comments