diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 25f440fab5..56ba8b26cd 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -137,6 +137,8 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) m_Glitches[GLITCH_BADDRIVEBYHITBOX] = false; m_Glitches[GLITCH_QUICKSTAND] = false; m_Glitches[GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE] = false; + m_Glitches[GLITCH_VEHICLE_RAPID_STOP] = false; + g_pMultiplayer->SetRapidVehicleStopFixEnabled(true); g_pMultiplayer->DisableBadDrivebyHitboxes(true); @@ -5992,6 +5994,8 @@ bool CClientGame::SetGlitchEnabled(unsigned char ucGlitch, bool bEnabled) g_pMultiplayer->DisableQuickReload(!bEnabled); if (ucGlitch == GLITCH_CLOSEDAMAGE) g_pMultiplayer->DisableCloseRangeDamage(!bEnabled); + if (ucGlitch == GLITCH_VEHICLE_RAPID_STOP) + g_pMultiplayer->SetRapidVehicleStopFixEnabled(!bEnabled); return true; } return false; diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index d21de68f06..60d185f641 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -204,6 +204,7 @@ class CClientGame GLITCH_BADDRIVEBYHITBOX, GLITCH_QUICKSTAND, GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE, + GLITCH_VEHICLE_RAPID_STOP, NUM_GLITCHES }; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 1f50f7ac67..f62e9955b4 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -2378,6 +2378,7 @@ void CPacketHandler::Packet_MapInfo(NetBitStreamInterface& bitStream) g_pClientGame->SetGlitchEnabled(CClientGame::GLITCH_FASTSPRINT, funBugs.data3.bFastSprint); g_pClientGame->SetGlitchEnabled(CClientGame::GLITCH_BADDRIVEBYHITBOX, funBugs.data4.bBadDrivebyHitboxes); g_pClientGame->SetGlitchEnabled(CClientGame::GLITCH_QUICKSTAND, funBugs.data5.bQuickStand); + g_pClientGame->SetGlitchEnabled(CClientGame::GLITCH_VEHICLE_RAPID_STOP, funBugs.data6.vehicleRapidStop); SWorldSpecialPropertiesStateSync wsProps; if (bitStream.Can(eBitStreamVersion::WorldSpecialProperties)) diff --git a/Client/multiplayer_sa/CMultiplayerSA.h b/Client/multiplayer_sa/CMultiplayerSA.h index f4c79ce9b6..75206d8211 100644 --- a/Client/multiplayer_sa/CMultiplayerSA.h +++ b/Client/multiplayer_sa/CMultiplayerSA.h @@ -336,6 +336,9 @@ class CMultiplayerSA : public CMultiplayer bool IsVehicleEngineAutoStartEnabled() const noexcept override; void SetVehicleEngineAutoStartEnabled(bool enabled) override; + bool IsRapidVehicleStopFixEnabled() const noexcept override { return m_isRapidVehicleStopFixEnabled; }; + void SetRapidVehicleStopFixEnabled(bool enabled) override; + void SetPedTargetingMarkerEnabled(bool bEnable); bool IsPedTargetingMarkerEnabled(); bool IsConnected(); @@ -385,6 +388,8 @@ class CMultiplayerSA : public CMultiplayer DWORD m_dwLastAnimArrayAddress; float m_fShadowsOffset; + bool m_isRapidVehicleStopFixEnabled{false}; + /* VOID SetPlayerShotVectors(CPlayerPed* player, Vector3D * vecTarget, Vector3D * vecStart); VOID SetPlayerCameraVectors(CPlayerPed* player, Vector3D * vecSource, Vector3D * vecFront); Vector3D * GetLocalShotOriginVector();*/ diff --git a/Client/multiplayer_sa/CMultiplayerSA_FrameRateFixes.cpp b/Client/multiplayer_sa/CMultiplayerSA_FrameRateFixes.cpp index 550789c246..620d9ba2ea 100644 --- a/Client/multiplayer_sa/CMultiplayerSA_FrameRateFixes.cpp +++ b/Client/multiplayer_sa/CMultiplayerSA_FrameRateFixes.cpp @@ -619,6 +619,77 @@ static void __declspec(naked) HOOK_CWeapon_Update() } } +#define HOOKPOS_CPhysical__ApplyAirResistance 0x544D29 +#define HOOKSIZE_CPhysical__ApplyAirResistance 5 +static const unsigned int RETURN_CPhysical__ApplyAirResistance = 0x544D4D; +static void _declspec(naked) HOOK_CPhysical__ApplyAirResistance() +{ + _asm { + fld ds:[0x862CD0] // 0.99000001f + fld ds:[0xB7CB5C] // CTimer::ms_fTimeStep + fdiv kOriginalTimeStep // 1.666f + mov eax, 0x822130 // powf + call eax + + fld st(0) + fmul [esi+0x50] + fstp [esi+0x50] + + fld st(0) + fmul [esi+0x54] + fstp [esi+0x54] + + fmul [esi+0x58] + fstp [esi+0x58] + jmp RETURN_CPhysical__ApplyAirResistance + } +} + +template +static void _declspec(naked) HOOK_VehicleRapidStopFix() +{ + static unsigned int RETURN_VehicleRapidStopFix = returnAddress; + _asm { + fld ds:[0xC2B9CC] // mod_HandlingManager.m_fWheelFriction + fmul ds:[0xB7CB5C] // CTimer::ms_fTimeStep + fdiv kOriginalTimeStep // 1.666f + jmp RETURN_VehicleRapidStopFix + } +} + +void CMultiplayerSA::SetRapidVehicleStopFixEnabled(bool enabled) +{ + if (m_isRapidVehicleStopFixEnabled == enabled) + return; + + if (enabled) + { + EZHookInstall(CPhysical__ApplyAirResistance); + + // CVehicle::ProcessWheel + HookInstall(0x6D6E69, (DWORD)HOOK_VehicleRapidStopFix<0x6D6E6F>, 6); + HookInstall(0x6D6EA8, (DWORD)HOOK_VehicleRapidStopFix<0x6D6EAE>, 6); + + // CVehicle::ProcessBikeWheel + HookInstall(0x6D767F, (DWORD)HOOK_VehicleRapidStopFix<0x6D7685>, 6); + HookInstall(0x6D76AB, (DWORD)HOOK_VehicleRapidStopFix<0x6D76B1>, 6); + HookInstall(0x6D76CD, (DWORD)HOOK_VehicleRapidStopFix<0x6D76D3>, 6); + } + else + { + MemCpy((void*)HOOKPOS_CPhysical__ApplyAirResistance, "\xD9\x46\x50\xD8\x0D", 5); + + MemCpy((void*)0x6D6E69, "\xD9\x05\xCC\xB9\xC2\x00", 6); + MemCpy((void*)0x6D6EA8, "\xD9\x05\xCC\xB9\xC2\x00", 6); + + MemCpy((void*)0x6D767F, "\xD9\x05\xCC\xB9\xC2\x00", 6); + MemCpy((void*)0x6D76AB, "\xD9\x05\xCC\xB9\xC2\x00", 6); + MemCpy((void*)0x6D76CD, "\xD9\x05\xCC\xB9\xC2\x00", 6); + } + + m_isRapidVehicleStopFixEnabled = enabled; +} + void CMultiplayerSA::InitHooks_FrameRateFixes() { EZHookInstall(CTaskSimpleUseGun__SetMoveAnim); diff --git a/Client/sdk/multiplayer/CMultiplayer.h b/Client/sdk/multiplayer/CMultiplayer.h index 555de9e526..af3ae03f20 100644 --- a/Client/sdk/multiplayer/CMultiplayer.h +++ b/Client/sdk/multiplayer/CMultiplayer.h @@ -447,6 +447,9 @@ class CMultiplayer virtual bool IsVehicleEngineAutoStartEnabled() const noexcept = 0; virtual void SetVehicleEngineAutoStartEnabled(bool enabled) = 0; + virtual bool IsRapidVehicleStopFixEnabled() const noexcept = 0; + virtual void SetRapidVehicleStopFixEnabled(bool enabled) = 0; + virtual void SetPedTargetingMarkerEnabled(bool bEnabled) = 0; virtual bool IsPedTargetingMarkerEnabled() = 0; diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 16e7b7312b..e327383645 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -240,6 +240,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti m_Glitches[GLITCH_BADDRIVEBYHITBOX] = false; m_Glitches[GLITCH_QUICKSTAND] = false; m_Glitches[GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE] = false; + m_Glitches[GLITCH_VEHICLE_RAPID_STOP] = false; for (int i = 0; i < WEAPONTYPE_LAST_WEAPONTYPE; i++) m_JetpackWeapons[i] = false; @@ -279,6 +280,7 @@ CGame::CGame() : m_FloodProtect(4, 30000, 30000) // Max of 4 connecti m_GlitchNames["baddrivebyhitbox"] = GLITCH_BADDRIVEBYHITBOX; m_GlitchNames["quickstand"] = GLITCH_QUICKSTAND; m_GlitchNames["kickoutofvehicle_onmodelreplace"] = GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE; + m_GlitchNames["vehicle_rapid_stop"] = GLITCH_VEHICLE_RAPID_STOP; m_bCloudsEnabled = true; diff --git a/Server/mods/deathmatch/logic/CGame.h b/Server/mods/deathmatch/logic/CGame.h index bffd2970e3..338ce119cc 100644 --- a/Server/mods/deathmatch/logic/CGame.h +++ b/Server/mods/deathmatch/logic/CGame.h @@ -196,6 +196,7 @@ class CGame GLITCH_BADDRIVEBYHITBOX, GLITCH_QUICKSTAND, GLITCH_KICKOUTOFVEHICLE_ONMODELREPLACE, + GLITCH_VEHICLE_RAPID_STOP, NUM_GLITCHES }; diff --git a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp index 0fd78c8bd3..614ff8c9ab 100644 --- a/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CMapInfoPacket.cpp @@ -170,6 +170,7 @@ bool CMapInfoPacket::Write(NetBitStreamInterface& BitStream) const funBugs.data3.bFastSprint = g_pGame->IsGlitchEnabled(CGame::GLITCH_FASTSPRINT); funBugs.data4.bBadDrivebyHitboxes = g_pGame->IsGlitchEnabled(CGame::GLITCH_BADDRIVEBYHITBOX); funBugs.data5.bQuickStand = g_pGame->IsGlitchEnabled(CGame::GLITCH_QUICKSTAND); + funBugs.data6.vehicleRapidStop = g_pGame->IsGlitchEnabled(CGame::GLITCH_VEHICLE_RAPID_STOP); BitStream.Write(&funBugs); // Write world special properties states diff --git a/Shared/sdk/net/SyncStructures.h b/Shared/sdk/net/SyncStructures.h index c9d4a98075..87109e3202 100644 --- a/Shared/sdk/net/SyncStructures.h +++ b/Shared/sdk/net/SyncStructures.h @@ -1964,6 +1964,10 @@ struct SFunBugsStateSync : public ISyncStructure { BITCOUNT5 = 1 }; + enum + { + BITCOUNT6 = 1 + }; bool Read(NetBitStreamInterface& bitStream) { @@ -1984,6 +1988,10 @@ struct SFunBugsStateSync : public ISyncStructure bOk &= bitStream.ReadBits(reinterpret_cast(&data5), BITCOUNT5); else data5.bQuickStand = 0; + if (bitStream.Can(eBitStreamVersion::Glitch_VehicleRapidStop)) + bOk &= bitStream.ReadBits(reinterpret_cast(&data6), BITCOUNT6); + else + data6.vehicleRapidStop = 0; //// Example for adding item: // if ( bitStream.Version() >= 0x999 ) @@ -2004,6 +2012,8 @@ struct SFunBugsStateSync : public ISyncStructure bitStream.WriteBits(reinterpret_cast(&data4), BITCOUNT4); if (bitStream.Can(eBitStreamVersion::QuickStandGlitch)) bitStream.WriteBits(reinterpret_cast(&data5), BITCOUNT5); + if (bitStream.Can(eBitStreamVersion::Glitch_VehicleRapidStop)) + bitStream.WriteBits(reinterpret_cast(&data6), BITCOUNT6); //// Example for adding item: // if (bitStream.Can(eBitStreamVersion::YourGlitch)) @@ -2042,6 +2052,12 @@ struct SFunBugsStateSync : public ISyncStructure { bool bQuickStand : 1; } data5; + + // Add new ones in separate structs + struct + { + bool vehicleRapidStop : 1; + } data6; }; ////////////////////////////////////////// diff --git a/Shared/sdk/net/bitstream.h b/Shared/sdk/net/bitstream.h index 160077ec35..3c45f47ad6 100644 --- a/Shared/sdk/net/bitstream.h +++ b/Shared/sdk/net/bitstream.h @@ -624,6 +624,10 @@ enum class eBitStreamVersion : unsigned short // 2025-06-02 WorldSpecialProperty_VehicleEngineAutoStart, + // Add "vehicle_rapid_stop" to setGlitchEnabled + // 2025-06-05 + Glitch_VehicleRapidStop, + // This allows us to automatically increment the BitStreamVersion when things are added to this enum. // Make sure you only add things above this comment. Next,