From 0f62dd7e4c5a55f8750f231454a189596ac2ca83 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 23 Aug 2025 00:10:19 +0200 Subject: [PATCH 1/8] New event --- Client/mods/deathmatch/logic/CClientGame.cpp | 48 ++++++++++++++++++- Client/mods/deathmatch/logic/CClientGame.h | 2 + Client/mods/deathmatch/logic/CEvents.cpp | 3 +- Client/mods/deathmatch/logic/CEvents.h | 5 +- .../logic/CStaticFunctionDefinitions.cpp | 4 +- .../logic/CStaticFunctionDefinitions.h | 2 +- .../logic/lua/CLuaFunctionDefs.Event.cpp | 2 +- .../mods/deathmatch/logic/lua/CLuaManager.h | 1 + Server/mods/deathmatch/logic/CGame.cpp | 29 +++++++++++ Server/mods/deathmatch/logic/CGame.h | 1 + .../deathmatch/logic/CPacketTranslator.cpp | 5 ++ .../packets/CDamageCancelEventPacket.cpp | 30 ++++++++++++ .../logic/packets/CDamageCancelEventPacket.h | 37 ++++++++++++++ Shared/mods/deathmatch/logic/Enums.cpp | 1 + Shared/sdk/net/Packets.h | 4 +- 15 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp create mode 100644 Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 230baa6204f..d1254b597f2 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -74,12 +74,13 @@ CVector g_vecBulletFireEndPosition; #define DOUBLECLICK_MOVE_THRESHOLD 10.0f static constexpr long long TIME_DISCORD_UPDATE_RATE = 15000; +static constexpr int CANCEL_DAMAGE_EVENT_INTERVAL = 1000; CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) { // Init the global var with ourself g_pClientGame = this; - + // Packet handler m_pPacketHandler = new CPacketHandler(); @@ -4428,6 +4429,29 @@ bool CClientGame::ApplyPedDamageFromGame(eWeaponType weaponUsed, float fDamage, } pDamagedPed->GetGamePlayer()->SetHealth(fPreviousHealth); pDamagedPed->GetGamePlayer()->SetArmor(fPreviousArmor); + + if (GetTickCount64_() - m_lastCancelDamageEventTime_Ped >= CANCEL_DAMAGE_EVENT_INTERVAL && weaponUsed != eWeaponType::WEAPONTYPE_DROWNING) + { + NetBitStreamInterface* bitStream = g_pNet->AllocateNetBitStream(); + + bitStream->Write(pDamagedPed->GetID()); + + SWeaponTypeSync weapon; + weapon.data.ucWeaponType = weaponUsed; + bitStream->Write(&weapon); + + SFloatSync<8, 10> damage; + damage.data.fValue = fDamage; + bitStream->Write(&damage); + + bitStream->WriteString(m_pLuaManager->GetEvents()->GetEventCancellingResourceName()); + + g_pNet->SendPacket(PACKET_ID_CANCEL_DAMAGE_EVENT, bitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(bitStream); + + m_lastCancelDamageEventTime_Ped = GetTickCount64_(); + } + return false; } @@ -4787,6 +4811,28 @@ bool CClientGame::VehicleDamageHandler(CEntitySAInterface* pVehicleInterface, fl if (!pClientVehicle->CallEvent("onClientVehicleDamage", Arguments, true)) { bAllowDamage = false; + + if (GetTickCount64_() - m_lastCancelDamageEventTime_Vehicle >= CANCEL_DAMAGE_EVENT_INTERVAL) + { + NetBitStreamInterface* bitStream = g_pNet->AllocateNetBitStream(); + + bitStream->Write(pClientVehicle->GetID()); + + SWeaponTypeSync weapon; + weapon.data.ucWeaponType = weaponType; + bitStream->Write(&weapon); + + SFloatSync<8, 10> damage; + damage.data.fValue = fLoss; + bitStream->Write(&damage); + + bitStream->WriteString(m_pLuaManager->GetEvents()->GetEventCancellingResourceName()); + + g_pNet->SendPacket(PACKET_ID_CANCEL_DAMAGE_EVENT, bitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(bitStream); + + m_lastCancelDamageEventTime_Vehicle = GetTickCount64_(); + } } } diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index 0c33091763b..f330d5bea7c 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -874,6 +874,8 @@ class CClientGame RunNamedAnimTask_type m_mapOfRunNamedAnimTasks; long long m_timeLastDiscordStateUpdate; + std::int64_t m_lastCancelDamageEventTime_Ped; + std::int64_t m_lastCancelDamageEventTime_Vehicle; }; extern CClientGame* g_pClientGame; diff --git a/Client/mods/deathmatch/logic/CEvents.cpp b/Client/mods/deathmatch/logic/CEvents.cpp index 1a8ef75f6f8..d6a0bf88e32 100644 --- a/Client/mods/deathmatch/logic/CEvents.cpp +++ b/Client/mods/deathmatch/logic/CEvents.cpp @@ -147,8 +147,9 @@ void CEvents::PostEventPulse() m_CancelledList.pop_back(); } -void CEvents::CancelEvent(bool bCancelled) +void CEvents::CancelEvent(bool bCancelled, const std::string& resourceName) { + m_eventCancellingResourceName = resourceName; m_bEventCancelled = bCancelled; } diff --git a/Client/mods/deathmatch/logic/CEvents.h b/Client/mods/deathmatch/logic/CEvents.h index 23c4cb513a0..4f6f636cb0b 100644 --- a/Client/mods/deathmatch/logic/CEvents.h +++ b/Client/mods/deathmatch/logic/CEvents.h @@ -42,9 +42,11 @@ class CEvents void PreEventPulse(); void PostEventPulse(); - void CancelEvent(bool bCancelled = true); + void CancelEvent(bool bCancelled = true, const std::string& resourceName = std::string()); bool WasEventCancelled(); + std::string GetEventCancellingResourceName() const noexcept { return m_eventCancellingResourceName; } + private: void RemoveAllEvents(); @@ -52,4 +54,5 @@ class CEvents std::vector m_CancelledList; bool m_bEventCancelled; bool m_bWasEventCancelled; + std::string m_eventCancellingResourceName{}; }; diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 544d0ad26aa..360454279d9 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -221,9 +221,9 @@ bool CStaticFunctionDefinitions::TriggerLatentServerEvent(const char* szName, CC return false; } -bool CStaticFunctionDefinitions::CancelEvent(bool bCancel) +bool CStaticFunctionDefinitions::CancelEvent(bool bCancel, CLuaMain* luaMain) { - m_pEvents->CancelEvent(bCancel); + m_pEvents->CancelEvent(bCancel, luaMain->GetResource()->GetName()); return true; } diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h index ba779ad2ba0..4bc23326a69 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.h @@ -35,7 +35,7 @@ class CStaticFunctionDefinitions static bool TriggerServerEvent(const char* szName, CClientEntity& CallWithEntity, CLuaArguments& Arguments); static bool TriggerLatentServerEvent(const char* szName, CClientEntity& CallWithEntity, CLuaArguments& Arguments, int bandwidth, CLuaMain* pLuaMain, ushort usResourceNetId); - static bool CancelEvent(bool bCancel); + static bool CancelEvent(bool bCancel, CLuaMain* luaMain); static bool WasEventCancelled(); // Misc funcs diff --git a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Event.cpp b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Event.cpp index 183abe241d2..fe51be06128 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Event.cpp +++ b/Client/mods/deathmatch/logic/lua/CLuaFunctionDefs.Event.cpp @@ -270,7 +270,7 @@ int CLuaFunctionDefs::TriggerServerEvent(lua_State* luaVM) int CLuaFunctionDefs::CancelEvent(lua_State* luaVM) { // Cancel it - if (CStaticFunctionDefinitions::CancelEvent(true)) + if (CStaticFunctionDefinitions::CancelEvent(true, m_pLuaManager->GetVirtualMachine(luaVM))) { lua_pushboolean(luaVM, true); return 1; diff --git a/Client/mods/deathmatch/logic/lua/CLuaManager.h b/Client/mods/deathmatch/logic/lua/CLuaManager.h index 04f2a552f76..bf3aad88a6a 100644 --- a/Client/mods/deathmatch/logic/lua/CLuaManager.h +++ b/Client/mods/deathmatch/logic/lua/CLuaManager.h @@ -42,6 +42,7 @@ class CLuaManager void ProcessPendingDeleteList(); bool IsLuaVMValid(lua_State* luaVM) { return MapFindRef(m_VirtualMachineMap, luaVM) != nullptr; }; + CEvents* GetEvents() const noexcept { return m_pEvents; } CClientGUIManager* m_pGUIManager; diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 910a1722dde..cef94649c25 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -60,6 +60,7 @@ #include "packets/CPlayerListPacket.h" #include "packets/CPlayerClothesPacket.h" #include "packets/CPlayerWorldSpecialPropertyPacket.h" +#include "packets/CDamageCancelEventPacket.h" #include "packets/CServerInfoSyncPacket.h" #include "packets/CLuaPacket.h" #include "../utils/COpenPortsTester.h" @@ -1330,6 +1331,12 @@ bool CGame::ProcessPacket(CPacket& Packet) return true; } + case PACKET_ID_CANCEL_DAMAGE_EVENT: + { + Packet_CancelDamageEvent(static_cast(Packet)); + return true; + } + default: break; } @@ -1650,6 +1657,7 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPlayerChangesProtectedData", "element, key, value", nullptr, false); m_Events.AddEvent("onPlayerChangesWorldSpecialProperty", "property, enabled", nullptr, false); m_Events.AddEvent("onPlayerTeleport", "previousX, previousY, previousZ, currentX, currentY, currentZ", nullptr, false); + m_Events.AddEvent("onDamageEventCancelled", "damagedEntity, weapon, damage, resourceName", nullptr, false); // Ped events m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false); @@ -4206,6 +4214,27 @@ void CGame::Packet_PlayerWorldSpecialProperty(CPlayerWorldSpecialPropertyPacket& player->CallEvent("onPlayerChangesWorldSpecialProperty", arguments, nullptr); } +void CGame::Packet_CancelDamageEvent(CDamageCancelEventPacket& packet) noexcept +{ + CPlayer* player = packet.GetSourcePlayer(); + if (!player) + return; + + CElement* damagedEntity = CElementIDs::GetElement(packet.GetDamagedEntityID()); + if (!damagedEntity) + return; + + CLuaArguments arguments; + arguments.PushElement(damagedEntity); + arguments.PushNumber(packet.GetWeaponType()); + arguments.PushNumber(packet.GetDamage()); + + const std::string& resourceName = packet.GetResourceName(); + arguments.PushString(resourceName); + + player->CallEvent("onDamageEventCancelled", arguments, nullptr); +} + void CGame::Packet_PlayerModInfo(CPlayerModInfoPacket& Packet) { CPlayer* pPlayer = Packet.GetSourcePlayer(); diff --git a/Server/mods/deathmatch/logic/CGame.h b/Server/mods/deathmatch/logic/CGame.h index 07c4f227e65..7bda325753a 100644 --- a/Server/mods/deathmatch/logic/CGame.h +++ b/Server/mods/deathmatch/logic/CGame.h @@ -523,6 +523,7 @@ class CGame void Packet_PlayerNetworkStatus(class CPlayerNetworkStatusPacket& Packet); void Packet_PlayerResourceStart(class CPlayerResourceStartPacket& Packet); void Packet_PlayerWorldSpecialProperty(class CPlayerWorldSpecialPropertyPacket& packet) noexcept; + void Packet_CancelDamageEvent(class CDamageCancelEventPacket& packet) noexcept; static void PlayerCompleteConnect(CPlayer* pPlayer); diff --git a/Server/mods/deathmatch/logic/CPacketTranslator.cpp b/Server/mods/deathmatch/logic/CPacketTranslator.cpp index 2d12509c502..0fc5dae0e41 100644 --- a/Server/mods/deathmatch/logic/CPacketTranslator.cpp +++ b/Server/mods/deathmatch/logic/CPacketTranslator.cpp @@ -49,6 +49,7 @@ #include "packets/CPlayerNetworkStatusPacket.h" #include "packets/CPlayerResourceStartPacket.h" #include "packets/CPlayerWorldSpecialPropertyPacket.h" +#include "packets/CDamageCancelEventPacket.h" CPacketTranslator::CPacketTranslator(CPlayerManager* pPlayerManager) { @@ -217,6 +218,10 @@ CPacket* CPacketTranslator::Translate(const NetServerPlayerID& Socket, ePacketID pTemp = new CPlayerWorldSpecialPropertyPacket; break; + case PACKET_ID_CANCEL_DAMAGE_EVENT: + pTemp = new CDamageCancelEventPacket; + break; + default: break; } diff --git a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp new file mode 100644 index 00000000000..6dfbfcc93c1 --- /dev/null +++ b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp @@ -0,0 +1,30 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include "StdInc.h" +#include "CDamageCancelEventPacket.h" +#include + +bool CDamageCancelEventPacket::Read(NetBitStreamInterface& bitStream) noexcept +{ + bitStream.Read(m_damagedEntityID); + + SWeaponTypeSync weaponType; + bitStream.Read(&weaponType); + m_weaponType = static_cast(weaponType.data.ucWeaponType); + + SFloatSync<8, 10> damage; + bitStream.Read(&damage); + m_damage = damage.data.fValue; + + bitStream.ReadString(m_resourceName); + + return true; +} diff --git a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h new file mode 100644 index 00000000000..713bada8073 --- /dev/null +++ b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * FILE: mods/deathmatch/logic/packets/CDamageCancelEventPacket.h + * + * Multi Theft Auto is available from https://www.multitheftauto.com/ + * + *****************************************************************************/ + +#pragma once + +#include "CPacket.h" +#include + +class CDamageCancelEventPacket final : public CPacket +{ +public: + CDamageCancelEventPacket() noexcept {} + + ePacketID GetPacketID() const noexcept { return PACKET_ID_CANCEL_DAMAGE_EVENT; } + unsigned long GetFlags() const noexcept { return PACKET_HIGH_PRIORITY | PACKET_RELIABLE | PACKET_SEQUENCED; } + virtual ePacketOrdering GetPacketOrdering() const noexcept { return PACKET_ORDERING_DEFAULT; } + + bool Read(NetBitStreamInterface& bitStream) noexcept; + + ElementID GetDamagedEntityID() const noexcept { return m_damagedEntityID; } + eWeaponType GetWeaponType() const noexcept { return m_weaponType; } + float GetDamage() const noexcept { return m_damage; } + std::string GetResourceName() const noexcept { return m_resourceName; } + +private: + std::string m_resourceName{}; + ElementID m_damagedEntityID; + float m_damage; + eWeaponType m_weaponType; +}; diff --git a/Shared/mods/deathmatch/logic/Enums.cpp b/Shared/mods/deathmatch/logic/Enums.cpp index 8bb99db974f..921cd07c074 100644 --- a/Shared/mods/deathmatch/logic/Enums.cpp +++ b/Shared/mods/deathmatch/logic/Enums.cpp @@ -233,4 +233,5 @@ ADD_ENUM1(PACKET_ID_SERVER_INFO_SYNC) ADD_ENUM1(PACKET_ID_DISCORD_JOIN) ADD_ENUM1(PACKET_ID_PLAYER_RESOURCE_START) ADD_ENUM1(PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY) +ADD_ENUM1(PACKET_ID_CANCEL_DAMAGE_EVENT) IMPLEMENT_ENUM_END("ePacketID") diff --git a/Shared/sdk/net/Packets.h b/Shared/sdk/net/Packets.h index 2f587cad140..443d3807572 100644 --- a/Shared/sdk/net/Packets.h +++ b/Shared/sdk/net/Packets.h @@ -177,5 +177,7 @@ enum ePacketID PACKET_ID_SERVER_INFO_SYNC, PACKET_ID_DISCORD_JOIN, PACKET_ID_PLAYER_RESOURCE_START, - PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY + PACKET_ID_PLAYER_WORLD_SPECIAL_PROPERTY, + + PACKET_ID_CANCEL_DAMAGE_EVENT, }; From 97752629c729938cb2c36ef2cd5421905e460ab6 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 23 Aug 2025 00:23:29 +0200 Subject: [PATCH 2/8] Update CClientGame.cpp --- Client/mods/deathmatch/logic/CClientGame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index d1254b597f2..b6a17d3e210 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -80,7 +80,7 @@ CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) { // Init the global var with ourself g_pClientGame = this; - + // Packet handler m_pPacketHandler = new CPacketHandler(); From cc373019923ee022b437497735d02972743edd24 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sat, 23 Aug 2025 01:46:50 +0200 Subject: [PATCH 3/8] Add attacker --- Client/mods/deathmatch/logic/CClientGame.cpp | 4 ++++ Server/mods/deathmatch/logic/CGame.cpp | 9 ++++++++- .../logic/packets/CDamageCancelEventPacket.cpp | 3 +++ .../deathmatch/logic/packets/CDamageCancelEventPacket.h | 2 ++ 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index b6a17d3e210..166a23aac96 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -4436,6 +4436,10 @@ bool CClientGame::ApplyPedDamageFromGame(eWeaponType weaponUsed, float fDamage, bitStream->Write(pDamagedPed->GetID()); + bitStream->WriteBit(pInflictingEntity != nullptr); + if (pInflictingEntity) + bitStream->Write(pInflictingEntity->GetID()); + SWeaponTypeSync weapon; weapon.data.ucWeaponType = weaponUsed; bitStream->Write(&weapon); diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index cef94649c25..5c82cf8c9bb 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -1657,7 +1657,7 @@ void CGame::AddBuiltInEvents() m_Events.AddEvent("onPlayerChangesProtectedData", "element, key, value", nullptr, false); m_Events.AddEvent("onPlayerChangesWorldSpecialProperty", "property, enabled", nullptr, false); m_Events.AddEvent("onPlayerTeleport", "previousX, previousY, previousZ, currentX, currentY, currentZ", nullptr, false); - m_Events.AddEvent("onDamageEventCancelled", "damagedEntity, weapon, damage, resourceName", nullptr, false); + m_Events.AddEvent("onDamageEventCancelled", "attacker, damagedEntity, weapon, damage, resourceName", nullptr, false); // Ped events m_Events.AddEvent("onPedVehicleEnter", "vehicle, seat, jacked", NULL, false); @@ -4224,7 +4224,14 @@ void CGame::Packet_CancelDamageEvent(CDamageCancelEventPacket& packet) noexcept if (!damagedEntity) return; + CElement* attackerEntity = CElementIDs::GetElement(packet.GetAtackerEntityID()); + CLuaArguments arguments; + if (attackerEntity) + arguments.PushElement(attackerEntity); + else + arguments.PushNil(); + arguments.PushElement(damagedEntity); arguments.PushNumber(packet.GetWeaponType()); arguments.PushNumber(packet.GetDamage()); diff --git a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp index 6dfbfcc93c1..d8d4dd809a0 100644 --- a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.cpp @@ -16,6 +16,9 @@ bool CDamageCancelEventPacket::Read(NetBitStreamInterface& bitStream) noexcept { bitStream.Read(m_damagedEntityID); + if (bitStream.ReadBit()) + bitStream.Read(m_atackerEntityID); + SWeaponTypeSync weaponType; bitStream.Read(&weaponType); m_weaponType = static_cast(weaponType.data.ucWeaponType); diff --git a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h index 713bada8073..c006ba1f8fa 100644 --- a/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h +++ b/Server/mods/deathmatch/logic/packets/CDamageCancelEventPacket.h @@ -25,6 +25,7 @@ class CDamageCancelEventPacket final : public CPacket bool Read(NetBitStreamInterface& bitStream) noexcept; ElementID GetDamagedEntityID() const noexcept { return m_damagedEntityID; } + ElementID GetAtackerEntityID() const noexcept { return m_atackerEntityID; } eWeaponType GetWeaponType() const noexcept { return m_weaponType; } float GetDamage() const noexcept { return m_damage; } std::string GetResourceName() const noexcept { return m_resourceName; } @@ -32,6 +33,7 @@ class CDamageCancelEventPacket final : public CPacket private: std::string m_resourceName{}; ElementID m_damagedEntityID; + ElementID m_atackerEntityID{INVALID_ELEMENT_ID}; float m_damage; eWeaponType m_weaponType; }; From 16b261df47edc585c172ec16eaf60084db7ecb37 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 24 Aug 2025 17:21:18 +0200 Subject: [PATCH 4/8] mtaserver.conf settings --- Client/game_sa/CPedSA.cpp | 20 ++ Client/game_sa/CPedSA.h | 2 + Client/mods/deathmatch/logic/CClientGame.cpp | 76 +++-- Client/mods/deathmatch/logic/CClientGame.h | 11 +- Client/mods/deathmatch/logic/CClientPed.h | 1 + Client/mods/deathmatch/logic/CClientVehicle.h | 2 + .../mods/deathmatch/logic/CPacketHandler.cpp | 8 + .../mods/deathmatch/logic/rpc/CWorldRPCs.cpp | 1 + Client/sdk/game/CPed.h | 2 + Server/mods/deathmatch/logic/CGame.cpp | 4 +- Server/mods/deathmatch/logic/CMainConfig.cpp | 11 + Server/mods/deathmatch/logic/CMainConfig.h | 274 +++++++++--------- .../logic/CStaticFunctionDefinitions.cpp | 1 + .../logic/packets/CSyncSettingsPacket.cpp | 6 +- .../logic/packets/CSyncSettingsPacket.h | 4 +- .../mods/deathmatch/logic/CTickRateSettings.h | 2 + 16 files changed, 269 insertions(+), 156 deletions(-) diff --git a/Client/game_sa/CPedSA.cpp b/Client/game_sa/CPedSA.cpp index ef718d32d1e..422a5bf787d 100644 --- a/Client/game_sa/CPedSA.cpp +++ b/Client/game_sa/CPedSA.cpp @@ -20,6 +20,7 @@ #include "CProjectileInfoSA.h" #include "CWeaponStatManagerSA.h" #include "CFireManagerSA.h" +#include "CAnimManagerSA.h" extern CGameSA* pGame; @@ -576,6 +577,25 @@ void CPedSA::GetAttachedSatchels(std::vector& satchelsList) const } } +bool CPedSA::IsPedCuttingWithChainsaw() const +{ + if (GetPedIntelligence()->GetTaskManager()->GetActiveTask()->GetTaskType() == TASK_SIMPLE_FIGHT) + { + CPedSAInterface* gamePed = GetPedInterface(); + + if (gamePed->weaponAudioEntity.m_chainsawState == eChainsawState::CUTTING) + { + auto cuttingAnim = pGame->GetAnimManager()->RpAnimBlendClumpGetAssociation(gamePed->m_pRwObject, "csaw_g"); + if (!cuttingAnim) + cuttingAnim = pGame->GetAnimManager()->RpAnimBlendClumpGetAssociation(gamePed->m_pRwObject, "csaw_part"); + + return cuttingAnim != nullptr; + } + } + + return false; +} + //////////////////////////////////////////////////////////////// // // CPed_PreRenderAfterTest diff --git a/Client/game_sa/CPedSA.h b/Client/game_sa/CPedSA.h index a17ae306e60..1e5ff913f51 100644 --- a/Client/game_sa/CPedSA.h +++ b/Client/game_sa/CPedSA.h @@ -475,6 +475,8 @@ class CPedSA : public virtual CPed, public virtual CPhysicalSA void GetAttachedSatchels(std::vector &satchelsList) const override; + bool IsPedCuttingWithChainsaw() const override; + static void StaticSetHooks(); private: diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 166a23aac96..e64a410ac75 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -74,7 +74,6 @@ CVector g_vecBulletFireEndPosition; #define DOUBLECLICK_MOVE_THRESHOLD 10.0f static constexpr long long TIME_DISCORD_UPDATE_RATE = 15000; -static constexpr int CANCEL_DAMAGE_EVENT_INTERVAL = 1000; CClientGame::CClientGame(bool bLocalPlay) : m_ServerInfo(new CServerInfo()) { @@ -4430,30 +4429,65 @@ bool CClientGame::ApplyPedDamageFromGame(eWeaponType weaponUsed, float fDamage, pDamagedPed->GetGamePlayer()->SetHealth(fPreviousHealth); pDamagedPed->GetGamePlayer()->SetArmor(fPreviousArmor); - if (GetTickCount64_() - m_lastCancelDamageEventTime_Ped >= CANCEL_DAMAGE_EVENT_INTERVAL && weaponUsed != eWeaponType::WEAPONTYPE_DROWNING) + if (GetTickCount64_() - pDamagedPed->m_lastEventDamageCancelledTime >= g_TickRateSettings.cancelledDamageInterval) { - NetBitStreamInterface* bitStream = g_pNet->AllocateNetBitStream(); + bool sendPacket = true; + + if (!m_triggerEventDamageCancelledForDamageEveryFrame) + { + switch (weaponUsed) + { + case WEAPONTYPE_TEARGAS: + case WEAPONTYPE_SPRAYCAN: + case WEAPONTYPE_EXTINGUISHER: + case WEAPONTYPE_FLAMETHROWER: + case WEAPONTYPE_MOLOTOV: + case WEAPONTYPE_DROWNING: + case WEAPONTYPE_MINIGUN: + case WEAPONTYPE_RUNOVERBYCAR: + { + sendPacket = false; + break; + } + case WEAPONTYPE_CHAINSAW: + { + if (pInflictingEntity && pInflictingEntity->GetType() == eClientEntityType::CCLIENTPED || pInflictingEntity->GetType() == eClientEntityType::CCLIENTPLAYER) + { + CClientPed* attackerPed = static_cast(pInflictingEntity); + if (!attackerPed->m_pPlayerPed || !attackerPed->m_pPlayerPed->IsPedCuttingWithChainsaw()) + sendPacket = false; + } + + break; + } + } + } - bitStream->Write(pDamagedPed->GetID()); + if (sendPacket) + { + NetBitStreamInterface* bitStream = g_pNet->AllocateNetBitStream(); - bitStream->WriteBit(pInflictingEntity != nullptr); - if (pInflictingEntity) - bitStream->Write(pInflictingEntity->GetID()); + bitStream->Write(pDamagedPed->GetID()); - SWeaponTypeSync weapon; - weapon.data.ucWeaponType = weaponUsed; - bitStream->Write(&weapon); + bitStream->WriteBit(pInflictingEntity != nullptr); + if (pInflictingEntity) + bitStream->Write(pInflictingEntity->GetID()); - SFloatSync<8, 10> damage; - damage.data.fValue = fDamage; - bitStream->Write(&damage); + SWeaponTypeSync weapon; + weapon.data.ucWeaponType = weaponUsed; + bitStream->Write(&weapon); - bitStream->WriteString(m_pLuaManager->GetEvents()->GetEventCancellingResourceName()); + SFloatSync<8, 10> damage; + damage.data.fValue = fDamage; + bitStream->Write(&damage); - g_pNet->SendPacket(PACKET_ID_CANCEL_DAMAGE_EVENT, bitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); - g_pNet->DeallocateNetBitStream(bitStream); + bitStream->WriteString(m_pLuaManager->GetEvents()->GetEventCancellingResourceName()); - m_lastCancelDamageEventTime_Ped = GetTickCount64_(); + g_pNet->SendPacket(PACKET_ID_CANCEL_DAMAGE_EVENT, bitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); + g_pNet->DeallocateNetBitStream(bitStream); + + pDamagedPed->m_lastEventDamageCancelledTime = GetTickCount64_(); + } } return false; @@ -4816,12 +4850,16 @@ bool CClientGame::VehicleDamageHandler(CEntitySAInterface* pVehicleInterface, fl { bAllowDamage = false; - if (GetTickCount64_() - m_lastCancelDamageEventTime_Vehicle >= CANCEL_DAMAGE_EVENT_INTERVAL) + if (m_triggerEventDamageCancelledForVehicles && GetTickCount64_() - pClientVehicle->m_lastEventDamageCancelledTime >= g_TickRateSettings.cancelledDamageInterval) { NetBitStreamInterface* bitStream = g_pNet->AllocateNetBitStream(); bitStream->Write(pClientVehicle->GetID()); + bitStream->WriteBit(pClientAttacker != nullptr); + if (pClientAttacker) + bitStream->Write(pClientAttacker->GetID()); + SWeaponTypeSync weapon; weapon.data.ucWeaponType = weaponType; bitStream->Write(&weapon); @@ -4835,7 +4873,7 @@ bool CClientGame::VehicleDamageHandler(CEntitySAInterface* pVehicleInterface, fl g_pNet->SendPacket(PACKET_ID_CANCEL_DAMAGE_EVENT, bitStream, PACKET_PRIORITY_HIGH, PACKET_RELIABILITY_RELIABLE_ORDERED); g_pNet->DeallocateNetBitStream(bitStream); - m_lastCancelDamageEventTime_Vehicle = GetTickCount64_(); + pClientVehicle->m_lastEventDamageCancelledTime = GetTickCount64_(); } } } diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index f330d5bea7c..00b5150a4ce 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -664,6 +664,12 @@ class CClientGame void PedStepHandler(CPedSAInterface* pPed, bool bFoot); void VehicleWeaponHitHandler(SVehicleWeaponHitEvent& event); + void SetEventDamageCancelledSettings(bool calledForVehicles, bool calledForDmgEveryFrame) noexcept + { + m_triggerEventDamageCancelledForVehicles = calledForVehicles; + m_triggerEventDamageCancelledForDamageEveryFrame = calledForDmgEveryFrame; + } + private: eStatus m_Status; eServerType m_ServerType; @@ -874,8 +880,9 @@ class CClientGame RunNamedAnimTask_type m_mapOfRunNamedAnimTasks; long long m_timeLastDiscordStateUpdate; - std::int64_t m_lastCancelDamageEventTime_Ped; - std::int64_t m_lastCancelDamageEventTime_Vehicle; + + bool m_triggerEventDamageCancelledForVehicles; + bool m_triggerEventDamageCancelledForDamageEveryFrame; }; extern CClientGame* g_pClientGame; diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index 489b1a0a501..cd755e613b2 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -740,6 +740,7 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule uint m_uiFrameLastRebuildPlayer; bool m_bIsSyncing; bool m_shouldRecreate{false}; + std::int64_t m_lastEventDamageCancelledTime{0}; bool m_bBulletImpactData; CClientEntityPtr m_pBulletImpactEntity; diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index 05c2601cf6a..009046a5e4d 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -760,4 +760,6 @@ class CClientVehicle : public CClientStreamElement std::array(VehicleDummies::VEHICLE_DUMMY_COUNT)> m_dummyPositions; bool m_copyDummyPositions = true; + + std::int64_t m_lastEventDamageCancelledTime{0}; }; diff --git a/Client/mods/deathmatch/logic/CPacketHandler.cpp b/Client/mods/deathmatch/logic/CPacketHandler.cpp index 054750b525c..f662efbe711 100644 --- a/Client/mods/deathmatch/logic/CPacketHandler.cpp +++ b/Client/mods/deathmatch/logic/CPacketHandler.cpp @@ -5482,6 +5482,14 @@ void CPacketHandler::Packet_SyncSettings(NetBitStreamInterface& bitStream) uchar ucAllowShotgunDamageFix = 0; bitStream.Read(ucAllowShotgunDamageFix); + bool triggerEventDamageCancelledForVehicles; + bitStream.ReadBit(triggerEventDamageCancelledForVehicles); + + bool triggerEventDamageCancelledForDamageEveryFrame; + bitStream.ReadBit(triggerEventDamageCancelledForDamageEveryFrame); + + g_pClientGame->SetEventDamageCancelledSettings(triggerEventDamageCancelledForVehicles, triggerEventDamageCancelledForDamageEveryFrame); + SMiscGameSettings miscGameSettings; miscGameSettings.bUseAltPulseOrder = (ucUseAltPulseOrder != 0); miscGameSettings.bAllowFastSprintFix = (ucAllowFastSprintFix != 0); diff --git a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp index 65b1fe589a0..636e3d17c81 100644 --- a/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp +++ b/Client/mods/deathmatch/logic/rpc/CWorldRPCs.cpp @@ -603,6 +603,7 @@ void CWorldRPCs::SetSyncIntervals(NetBitStreamInterface& bitStream) bitStream.Read(g_TickRateSettings.iKeySyncAnalogMove); bitStream.Read(g_TickRateSettings.iPedSyncerDistance); bitStream.Read(g_TickRateSettings.iUnoccupiedVehicleSyncerDistance); + bitStream.Read(g_TickRateSettings.cancelledDamageInterval); } void CWorldRPCs::SetMoonSize(NetBitStreamInterface& bitStream) diff --git a/Client/sdk/game/CPed.h b/Client/sdk/game/CPed.h index 3219738e699..46ec8f70a2c 100644 --- a/Client/sdk/game/CPed.h +++ b/Client/sdk/game/CPed.h @@ -307,4 +307,6 @@ class CPed : public virtual CPhysical virtual void GetAttachedSatchels(std::vector &satchelsList) const = 0; virtual void Say(const ePedSpeechContext& speechId, float probability) = 0; + + virtual bool IsPedCuttingWithChainsaw() const = 0; }; diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 5c82cf8c9bb..d6962d26835 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -4757,8 +4757,10 @@ void CGame::SendSyncSettings(CPlayer* pPlayer) uchar ucAllowDrivebyAnimFix = true; uchar ucAllowShotgunDamageFix = true; + const SEVentDamageCancelledSettings& damageCancelledSettings = m_pMainConfig->GetEventDamageCancelledSettings(); + CSyncSettingsPacket packet(weaponTypesUsingBulletSync, ucVehExtrapolateEnabled, sVehExtrapolateBaseMs, sVehExtrapolatePercent, sVehExtrapolateMaxMs, - ucUseAltPulseOrder, ucAllowFastSprintFix, ucAllowDrivebyAnimFix, ucAllowShotgunDamageFix); + ucUseAltPulseOrder, ucAllowFastSprintFix, ucAllowDrivebyAnimFix, ucAllowShotgunDamageFix, damageCancelledSettings.triggerOnVehicleDamage == 1, damageCancelledSettings.triggerForDamageCalledEveryFrame == 1); if (pPlayer) pPlayer->Send(packet); else diff --git a/Server/mods/deathmatch/logic/CMainConfig.cpp b/Server/mods/deathmatch/logic/CMainConfig.cpp index affe0441532..3b959b507d5 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.cpp +++ b/Server/mods/deathmatch/logic/CMainConfig.cpp @@ -540,6 +540,9 @@ bool CMainConfig::Load() GetBoolean(m_pRootNode, "elementdata_whitelisted", m_elementDataWhitelisted); GetBoolean(m_pRootNode, "check_duplicate_serials", m_checkDuplicateSerials); + GetInteger(m_pRootNode, "cancelled_damage_for_vehicles", m_eventDamageCancelledSettings.triggerOnVehicleDamage); + GetInteger(m_pRootNode, "cancelled_damage_send_frame_based_dmg", m_eventDamageCancelledSettings.triggerForDamageCalledEveryFrame); + ApplyNetOptions(); return true; @@ -1508,6 +1511,7 @@ const std::vector& CMainConfig::GetIntSettingList() {true, true, 50, 100, 4000, "keysync_mouse_sync_interval", &g_TickRateSettings.iKeySyncRotation, &CMainConfig::OnTickRateChange}, {true, true, 50, 100, 4000, "keysync_analog_sync_interval", &g_TickRateSettings.iKeySyncAnalogMove, &CMainConfig::OnTickRateChange}, {true, true, 50, 100, 4000, "donkey_work_interval", &g_TickRateSettings.iNearListUpdate, &CMainConfig::OnTickRateChange}, + {true, true, 50, 1000, 4000, "cancelled_damage_send_interval", &g_TickRateSettings.cancelledDamageInterval, &CMainConfig::OnTickRateChange}, {true, true, 0, 0, 1, "bullet_sync", &m_bBulletSyncEnabled, &CMainConfig::OnTickRateChange}, {true, true, 0, 0, 120, "vehext_percent", &m_iVehExtrapolatePercent, &CMainConfig::OnTickRateChange}, {true, true, 0, 150, 500, "vehext_ping_limit", &m_iVehExtrapolatePingLimit, &CMainConfig::OnTickRateChange}, @@ -1531,6 +1535,8 @@ const std::vector& CMainConfig::GetIntSettingList() {true, true, 50, 1000, 5000, "player_triggered_event_interval", &m_iPlayerTriggeredEventIntervalMs, &CMainConfig::OnPlayerTriggeredEventIntervalChange}, {true, true, 1, 100, 1000, "max_player_triggered_events_per_interval", &m_iMaxPlayerTriggeredEventsPerInterval, &CMainConfig::OnPlayerTriggeredEventIntervalChange}, {true, true, 0, 1, 1, "resource_client_file_checks", &m_checkResourceClientFiles, nullptr}, + {true, true, 0, 0, 1, "cancelled_damage_for_vehicles", &m_eventDamageCancelledSettings.triggerOnVehicleDamage, &CMainConfig::OnSettingChange}, + {true, true, 0, 1, 1, "cancelled_damage_send_frame_based_dmg", &m_eventDamageCancelledSettings.triggerForDamageCalledEveryFrame, &CMainConfig::OnSettingChange}, }; static std::vector settingsList; @@ -1580,6 +1586,11 @@ void CMainConfig::OnPlayerTriggeredEventIntervalChange() g_pGame->ApplyPlayerTriggeredEventIntervalChange(); } +void CMainConfig::OnSettingChange() +{ + g_pGame->SendSyncSettings(); +} + void CGame::ApplyPlayerTriggeredEventIntervalChange() { m_iClientTriggeredEventsIntervalMs = m_pMainConfig->GetPlayerTriggeredEventInterval(); diff --git a/Server/mods/deathmatch/logic/CMainConfig.h b/Server/mods/deathmatch/logic/CMainConfig.h index ffb0b8de8dd..4edee359002 100644 --- a/Server/mods/deathmatch/logic/CMainConfig.h +++ b/Server/mods/deathmatch/logic/CMainConfig.h @@ -39,6 +39,12 @@ struct SIntSetting PFN_SettingChangeCallback changeCallback; }; +struct SEVentDamageCancelledSettings +{ + int triggerOnVehicleDamage{false}; + int triggerForDamageCalledEveryFrame{true}; +}; + class CMainConfig : public CXMLConfig { public: @@ -68,68 +74,68 @@ class CMainConfig : public CXMLConfig unsigned int GetVoiceQuality() { return m_ucVoiceQuality; }; unsigned int GetVoiceBitrate() { return m_uiVoiceBitrate; }; - bool GetAseInternetPushEnabled() { return m_iAseMode == 2 && !IsFakeLagCommandEnabled(); } - bool GetAseInternetListenEnabled() { return m_iAseMode == 1 && !IsFakeLagCommandEnabled(); } - bool GetAseLanListenEnabled() { return m_bDontBroadcastLan ? false : true; } - unsigned short GetHTTPPort(); - eHTTPDownloadType GetHTTPDownloadType() { return m_ucHTTPDownloadType; }; - const std::string& GetHTTPDownloadURL() { return m_strHTTPDownloadURL; }; - int GetHTTPMaxConnectionsPerClient() { return m_iHTTPMaxConnectionsPerClient; }; - int GetHTTPThreadCount() { return m_iHTTPThreadCount; }; - int GetHTTPDosThreshold() { return m_iHTTPDosThreshold; }; - const SString& GetHTTPDosExclude() { return m_strHTTPDosExclude; }; - int GetEnableClientChecks() { return m_iEnableClientChecks; }; - const std::string& GetLogFile() { return m_strLogFile; }; - const std::string& GetAuthFile() { return m_strAuthFile; }; - bool GetJoinFloodProtectionEnabled() { return m_bJoinFloodProtectionEnabled; }; - bool GetScriptDebugLogEnabled() { return m_bScriptDebugLogEnabled && !m_strScriptDebugLogFile.empty(); }; - const std::string& GetScriptDebugLogFile() { return m_strScriptDebugLogFile; }; - unsigned int GetScriptDebugLogLevel() { return m_uiScriptDebugLogLevel; }; - const std::string& GetAccessControlListFile() { return m_strAccessControlListFile; }; - bool GetSerialVerificationEnabled() { return m_bVerifySerials; }; + bool GetAseInternetPushEnabled() { return m_iAseMode == 2 && !IsFakeLagCommandEnabled(); } + bool GetAseInternetListenEnabled() { return m_iAseMode == 1 && !IsFakeLagCommandEnabled(); } + bool GetAseLanListenEnabled() { return m_bDontBroadcastLan ? false : true; } + unsigned short GetHTTPPort(); + eHTTPDownloadType GetHTTPDownloadType() { return m_ucHTTPDownloadType; }; + const std::string& GetHTTPDownloadURL() { return m_strHTTPDownloadURL; }; + int GetHTTPMaxConnectionsPerClient() { return m_iHTTPMaxConnectionsPerClient; }; + int GetHTTPThreadCount() { return m_iHTTPThreadCount; }; + int GetHTTPDosThreshold() { return m_iHTTPDosThreshold; }; + const SString& GetHTTPDosExclude() { return m_strHTTPDosExclude; }; + int GetEnableClientChecks() { return m_iEnableClientChecks; }; + const std::string& GetLogFile() { return m_strLogFile; }; + const std::string& GetAuthFile() { return m_strAuthFile; }; + bool GetJoinFloodProtectionEnabled() { return m_bJoinFloodProtectionEnabled; }; + bool GetScriptDebugLogEnabled() { return m_bScriptDebugLogEnabled && !m_strScriptDebugLogFile.empty(); }; + const std::string& GetScriptDebugLogFile() { return m_strScriptDebugLogFile; }; + unsigned int GetScriptDebugLogLevel() { return m_uiScriptDebugLogLevel; }; + const std::string& GetAccessControlListFile() { return m_strAccessControlListFile; }; + bool GetSerialVerificationEnabled() { return m_bVerifySerials; }; const std::map& GetRulesForASE() const noexcept { return m_RulesForASEMap; }; - bool IsDisableAC(const char* szTagAC) { return MapContains(m_DisableComboACMap, szTagAC); }; - bool IsEnableDiagnostic(const char* szTag) { return MapContains(m_EnableDiagnosticMap, szTag); }; - CMtaVersion GetMinClientVersion() { return m_strMinClientVersion; } - const CMtaVersion& GetRecommendedClientVersion() { return m_strRecommendedClientVersion; } - int GetMinClientVersionAutoUpdate() { return m_iMinClientVersionAutoUpdate; } - const SString& GetIdFile() { return m_strIdFile; } - bool GetThreadNetEnabled() { return m_bThreadNetEnabled; } - const SString& GetGlobalDatabasesPath() { return m_strGlobalDatabasesPath; } - const SString& GetSystemDatabasesPath() { return m_strSystemDatabasesPath; } - const SString& GetBackupPath() { return m_strBackupPath; } - int GetBackupInterval() { return m_iBackupInterval; } - int GetBackupAmount() { return m_iBackupAmount; } - void NotifyDidBackup(); - bool ShouldCompactInternalDatabases(); - unsigned short GetFPSLimit() { return m_usFPSLimit; }; - bool SetFPSLimit(unsigned short usFPS, bool bSave); - int GetPendingWorkToDoSleepTime(); - int GetNoWorkToDoSleepTime(); - int GetServerLogicFpsLimit() { return m_iServerLogicFpsLimit; }; - const SString& GetDbLogFilename() { return m_strDbLogFilename; } - bool GetSyncMapElementData() const { return m_bSyncMapElementData; } - void SetSyncMapElementData(bool bOn) { m_bSyncMapElementData = bOn; } - bool GetBulletSyncEnabled() const { return m_bBulletSyncEnabled != 0; } - int GetVehExtrapolatePercent() const { return m_iVehExtrapolatePercent; } - int GetVehExtrapolatePingLimit() const { return m_iVehExtrapolatePingLimit; } - bool GetUseAltPulseOrder() const { return m_bUseAltPulseOrder != 0; } - const SString& GetLoadstringLogFilename() const { return m_strLoadstringLogFilename; } - bool GetLoadstringLogEnabled() const { return !m_strLoadstringLogFilename.empty(); } - bool GetCrashDumpUploadEnabled() const { return m_bCrashDumpUploadEnabled != 0; } - bool GetFilterDuplicateLogLinesEnabled() const { return m_bFilterDuplicateLogLinesEnabled != 0; } - bool IsAuthSerialGroup(const SString& strGroup) const { return ListContains(m_AuthSerialGroupList, strGroup); }; - bool IsAuthSerialHttpIpException(const SString& strIp) const { return ListContains(m_AuthSerialHttpIpExceptionList, strIp); } - bool GetAuthSerialEnabled() const { return !m_AuthSerialGroupList.empty(); }; - bool GetAuthSerialHttpEnabled() const { return m_bAuthSerialHttpEnabled && GetAuthSerialEnabled(); }; - const std::vector& GetAuthSerialGroupList() const { return m_AuthSerialGroupList; } - const std::vector& GetAuthSerialHttpIpExceptionList() const { return m_AuthSerialHttpIpExceptionList; } - const std::vector& GetOwnerEmailAddressList() const { return m_OwnerEmailAddressList; } - bool IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; } - bool IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; } - bool IsElementDataWhitelisted() const { return m_elementDataWhitelisted; } - bool IsCheckDuplicateSerialsEnabled() const noexcept { return m_checkDuplicateSerials; } - bool IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; } + bool IsDisableAC(const char* szTagAC) { return MapContains(m_DisableComboACMap, szTagAC); }; + bool IsEnableDiagnostic(const char* szTag) { return MapContains(m_EnableDiagnosticMap, szTag); }; + CMtaVersion GetMinClientVersion() { return m_strMinClientVersion; } + const CMtaVersion& GetRecommendedClientVersion() { return m_strRecommendedClientVersion; } + int GetMinClientVersionAutoUpdate() { return m_iMinClientVersionAutoUpdate; } + const SString& GetIdFile() { return m_strIdFile; } + bool GetThreadNetEnabled() { return m_bThreadNetEnabled; } + const SString& GetGlobalDatabasesPath() { return m_strGlobalDatabasesPath; } + const SString& GetSystemDatabasesPath() { return m_strSystemDatabasesPath; } + const SString& GetBackupPath() { return m_strBackupPath; } + int GetBackupInterval() { return m_iBackupInterval; } + int GetBackupAmount() { return m_iBackupAmount; } + void NotifyDidBackup(); + bool ShouldCompactInternalDatabases(); + unsigned short GetFPSLimit() { return m_usFPSLimit; }; + bool SetFPSLimit(unsigned short usFPS, bool bSave); + int GetPendingWorkToDoSleepTime(); + int GetNoWorkToDoSleepTime(); + int GetServerLogicFpsLimit() { return m_iServerLogicFpsLimit; }; + const SString& GetDbLogFilename() { return m_strDbLogFilename; } + bool GetSyncMapElementData() const { return m_bSyncMapElementData; } + void SetSyncMapElementData(bool bOn) { m_bSyncMapElementData = bOn; } + bool GetBulletSyncEnabled() const { return m_bBulletSyncEnabled != 0; } + int GetVehExtrapolatePercent() const { return m_iVehExtrapolatePercent; } + int GetVehExtrapolatePingLimit() const { return m_iVehExtrapolatePingLimit; } + bool GetUseAltPulseOrder() const { return m_bUseAltPulseOrder != 0; } + const SString& GetLoadstringLogFilename() const { return m_strLoadstringLogFilename; } + bool GetLoadstringLogEnabled() const { return !m_strLoadstringLogFilename.empty(); } + bool GetCrashDumpUploadEnabled() const { return m_bCrashDumpUploadEnabled != 0; } + bool GetFilterDuplicateLogLinesEnabled() const { return m_bFilterDuplicateLogLinesEnabled != 0; } + bool IsAuthSerialGroup(const SString& strGroup) const { return ListContains(m_AuthSerialGroupList, strGroup); }; + bool IsAuthSerialHttpIpException(const SString& strIp) const { return ListContains(m_AuthSerialHttpIpExceptionList, strIp); } + bool GetAuthSerialEnabled() const { return !m_AuthSerialGroupList.empty(); }; + bool GetAuthSerialHttpEnabled() const { return m_bAuthSerialHttpEnabled && GetAuthSerialEnabled(); }; + const std::vector& GetAuthSerialGroupList() const { return m_AuthSerialGroupList; } + const std::vector& GetAuthSerialHttpIpExceptionList() const { return m_AuthSerialHttpIpExceptionList; } + const std::vector& GetOwnerEmailAddressList() const { return m_OwnerEmailAddressList; } + bool IsDatabaseCredentialsProtectionEnabled() const { return m_bDatabaseCredentialsProtectionEnabled != 0; } + bool IsFakeLagCommandEnabled() const { return m_bFakeLagCommandEnabled != 0; } + bool IsElementDataWhitelisted() const { return m_elementDataWhitelisted; } + bool IsCheckDuplicateSerialsEnabled() const noexcept { return m_checkDuplicateSerials; } + bool IsCheckResourceClientFilesEnabled() const noexcept { return m_checkResourceClientFiles != 0; } SString GetSetting(const SString& configSetting); bool GetSetting(const SString& configSetting, SString& strValue); @@ -147,10 +153,13 @@ class CMainConfig : public CXMLConfig void OnTickRateChange(); void OnAseSettingChange(); void OnPlayerTriggeredEventIntervalChange(); + void OnSettingChange(); int GetPlayerTriggeredEventInterval() const { return m_iPlayerTriggeredEventIntervalMs; } int GetMaxPlayerTriggeredEventsPerInterval() const { return m_iMaxPlayerTriggeredEventsPerInterval; } + SEVentDamageCancelledSettings GetEventDamageCancelledSettings() const noexcept { return m_eventDamageCancelledSettings; } + private: void RegisterCommand(const char* szName, FCommandHandler* pFunction, bool bRestricted, const char* szConsoleHelpText); bool GetSettingTable(const SString& strName, const char** szAttribNames, uint uiNumAttribNames, CLuaArguments* outTable); @@ -164,75 +173,76 @@ class CMainConfig : public CXMLConfig unsigned char m_ucVoiceQuality; unsigned int m_uiVoiceBitrate; - bool m_bVoiceEnabled; - std::string m_strServerIP; - std::string m_strServerName; - unsigned short m_usServerPort; - unsigned int m_uiHardMaxPlayers; - unsigned int m_uiSoftMaxPlayers; - bool m_bHTTPEnabled; - std::string m_strPassword; - int m_iAseMode; - int m_iUpdateCycleDatagramsLimit; - int m_iUpdateCycleMessagesLimit; - unsigned short m_usHTTPPort; - eHTTPDownloadType m_ucHTTPDownloadType; - std::string m_strHTTPDownloadURL; - int m_iHTTPMaxConnectionsPerClient; - int m_iHTTPThreadCount; - int m_iHTTPDosThreshold; - SString m_strHTTPDosExclude; - int m_iEnableClientChecks; - std::string m_strLogFile; - std::string m_strAuthFile; - bool m_bJoinFloodProtectionEnabled; - bool m_bScriptDebugLogEnabled; - std::string m_strScriptDebugLogFile; - unsigned int m_uiScriptDebugLogLevel; - std::string m_strAccessControlListFile; - bool m_bVerifySerials; - unsigned short m_usFPSLimit; - int m_bDontBroadcastLan; - std::set m_DisableComboACMap; - std::map m_RulesForASEMap; - std::set m_EnableDiagnosticMap; - std::vector m_AuthSerialGroupList; - bool m_bAuthSerialHttpEnabled; - std::vector m_AuthSerialHttpIpExceptionList; - std::vector m_OwnerEmailAddressList; - CMtaVersion m_strMinClientVersion; - CMtaVersion m_strRecommendedClientVersion; - SString m_strIdFile; - SString m_strGlobalDatabasesPath; - SString m_strSystemDatabasesPath; - SString m_strBackupPath; - SString m_strDbLogFilename; - int m_iBackupInterval; - int m_iBackupAmount; - int m_iCompactInternalDatabases; - bool m_bDidBackup; - SString m_strBandwidthReductionMode; - int m_iPendingWorkToDoSleepTime; - int m_iNoWorkToDoSleepTime; - bool m_bThreadNetEnabled; - bool m_bSyncMapElementData; - int m_bBulletSyncEnabled; - std::map m_TransientSettings; - SNetOptions m_NetOptions; - int m_iVehExtrapolatePercent; - int m_iVehExtrapolatePingLimit; - int m_bUseAltPulseOrder; - int m_bNetAutoFilter; - SString m_strLoadstringLogFilename; - int m_iMinClientVersionAutoUpdate; - int m_iServerLogicFpsLimit; - int m_bCrashDumpUploadEnabled; - int m_bFilterDuplicateLogLinesEnabled; - int m_bDatabaseCredentialsProtectionEnabled; - int m_bFakeLagCommandEnabled; - int m_iPlayerTriggeredEventIntervalMs; - int m_iMaxPlayerTriggeredEventsPerInterval; - bool m_elementDataWhitelisted; - bool m_checkDuplicateSerials; - int m_checkResourceClientFiles; + bool m_bVoiceEnabled; + std::string m_strServerIP; + std::string m_strServerName; + unsigned short m_usServerPort; + unsigned int m_uiHardMaxPlayers; + unsigned int m_uiSoftMaxPlayers; + bool m_bHTTPEnabled; + std::string m_strPassword; + int m_iAseMode; + int m_iUpdateCycleDatagramsLimit; + int m_iUpdateCycleMessagesLimit; + unsigned short m_usHTTPPort; + eHTTPDownloadType m_ucHTTPDownloadType; + std::string m_strHTTPDownloadURL; + int m_iHTTPMaxConnectionsPerClient; + int m_iHTTPThreadCount; + int m_iHTTPDosThreshold; + SString m_strHTTPDosExclude; + int m_iEnableClientChecks; + std::string m_strLogFile; + std::string m_strAuthFile; + bool m_bJoinFloodProtectionEnabled; + bool m_bScriptDebugLogEnabled; + std::string m_strScriptDebugLogFile; + unsigned int m_uiScriptDebugLogLevel; + std::string m_strAccessControlListFile; + bool m_bVerifySerials; + unsigned short m_usFPSLimit; + int m_bDontBroadcastLan; + std::set m_DisableComboACMap; + std::map m_RulesForASEMap; + std::set m_EnableDiagnosticMap; + std::vector m_AuthSerialGroupList; + bool m_bAuthSerialHttpEnabled; + std::vector m_AuthSerialHttpIpExceptionList; + std::vector m_OwnerEmailAddressList; + CMtaVersion m_strMinClientVersion; + CMtaVersion m_strRecommendedClientVersion; + SString m_strIdFile; + SString m_strGlobalDatabasesPath; + SString m_strSystemDatabasesPath; + SString m_strBackupPath; + SString m_strDbLogFilename; + int m_iBackupInterval; + int m_iBackupAmount; + int m_iCompactInternalDatabases; + bool m_bDidBackup; + SString m_strBandwidthReductionMode; + int m_iPendingWorkToDoSleepTime; + int m_iNoWorkToDoSleepTime; + bool m_bThreadNetEnabled; + bool m_bSyncMapElementData; + int m_bBulletSyncEnabled; + std::map m_TransientSettings; + SNetOptions m_NetOptions; + int m_iVehExtrapolatePercent; + int m_iVehExtrapolatePingLimit; + int m_bUseAltPulseOrder; + int m_bNetAutoFilter; + SString m_strLoadstringLogFilename; + int m_iMinClientVersionAutoUpdate; + int m_iServerLogicFpsLimit; + int m_bCrashDumpUploadEnabled; + int m_bFilterDuplicateLogLinesEnabled; + int m_bDatabaseCredentialsProtectionEnabled; + int m_bFakeLagCommandEnabled; + int m_iPlayerTriggeredEventIntervalMs; + int m_iMaxPlayerTriggeredEventsPerInterval; + bool m_elementDataWhitelisted; + bool m_checkDuplicateSerials; + int m_checkResourceClientFiles; + SEVentDamageCancelledSettings m_eventDamageCancelledSettings{}; }; diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 14644dc1094..19f1539e96f 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -10968,6 +10968,7 @@ bool CStaticFunctionDefinitions::SendSyncIntervals(CPlayer* pPlayer) BitStream.pBitStream->Write(g_TickRateSettings.iKeySyncAnalogMove); BitStream.pBitStream->Write(g_TickRateSettings.iPedSyncerDistance); BitStream.pBitStream->Write(g_TickRateSettings.iUnoccupiedVehicleSyncerDistance); + BitStream.pBitStream->Write(g_TickRateSettings.cancelledDamageInterval); pPlayer->Send(CLuaPacket(SET_SYNC_INTERVALS, *BitStream.pBitStream)); }; diff --git a/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.cpp b/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.cpp index a4b959e94d3..2aa3fbb907f 100644 --- a/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.cpp @@ -15,7 +15,7 @@ CSyncSettingsPacket::CSyncSettingsPacket(const std::set& weaponTypesUsingBulletSync, uchar ucVehExtrapolateEnabled, short sVehExtrapolateBaseMs, short sVehExtrapolatePercent, short sVehExtrapolateMaxMs, uchar ucUseAltPulseOrder, uchar ucAllowFastSprintFix, - uchar ucAllowDrivebyAnimationFix, uchar ucAllowShotgunDamageFix) + uchar ucAllowDrivebyAnimationFix, uchar ucAllowShotgunDamageFix, bool triggerDamageEventCancelledForVehicles, bool triggerDamageEventCancelledForDamageEveryFrame) { m_weaponTypesUsingBulletSync = weaponTypesUsingBulletSync; m_ucVehExtrapolateEnabled = ucVehExtrapolateEnabled; @@ -26,6 +26,8 @@ CSyncSettingsPacket::CSyncSettingsPacket(const std::set& weaponType m_ucAllowFastSprintFix = ucAllowFastSprintFix; m_ucAllowDrivebyAnimationFix = ucAllowDrivebyAnimationFix; m_ucAllowShotgunDamageFix = ucAllowShotgunDamageFix; + m_triggerDamageEventCancelledForVehicles = triggerDamageEventCancelledForVehicles; + m_triggerDamageEventCancelledForDamageEveryFrame = triggerDamageEventCancelledForDamageEveryFrame; } bool CSyncSettingsPacket::Read(NetBitStreamInterface& BitStream) @@ -51,5 +53,7 @@ bool CSyncSettingsPacket::Write(NetBitStreamInterface& BitStream) const BitStream.Write(m_ucAllowFastSprintFix); BitStream.Write(m_ucAllowDrivebyAnimationFix); BitStream.Write(m_ucAllowShotgunDamageFix); + BitStream.WriteBit(m_triggerDamageEventCancelledForVehicles); + BitStream.WriteBit(m_triggerDamageEventCancelledForDamageEveryFrame); return true; } diff --git a/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.h b/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.h index b4c22df18f1..44139b8a8f1 100644 --- a/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.h +++ b/Server/mods/deathmatch/logic/packets/CSyncSettingsPacket.h @@ -19,7 +19,7 @@ class CSyncSettingsPacket final : public CPacket CSyncSettingsPacket(){}; CSyncSettingsPacket(const std::set& weaponTypesUsingBulletSync, uchar ucVehExtrapolateEnabled, short sVehExtrapolateBaseMs, short sVehExtrapolatePercent, short sVehExtrapolateMaxMs, uchar ucUseAltPulseOrder, uchar ucAllowFastSprintFix, - uchar ucAllowDrivebyAnimationFix, uchar ucAllowShotgunDamageFix); + uchar ucAllowDrivebyAnimationFix, uchar ucAllowShotgunDamageFix, bool triggerDamageEventCancelledForVehicles, bool triggerDamageEventCancelledForDamageEveryFrame); ePacketID GetPacketID() const { return PACKET_ID_SYNC_SETTINGS; }; unsigned long GetFlags() const { return PACKET_HIGH_PRIORITY | PACKET_RELIABLE | PACKET_SEQUENCED; }; @@ -36,4 +36,6 @@ class CSyncSettingsPacket final : public CPacket uchar m_ucAllowFastSprintFix; uchar m_ucAllowDrivebyAnimationFix; uchar m_ucAllowShotgunDamageFix; + bool m_triggerDamageEventCancelledForVehicles; + bool m_triggerDamageEventCancelledForDamageEveryFrame; }; diff --git a/Shared/mods/deathmatch/logic/CTickRateSettings.h b/Shared/mods/deathmatch/logic/CTickRateSettings.h index bc6e8d7a411..f6c3bd22857 100644 --- a/Shared/mods/deathmatch/logic/CTickRateSettings.h +++ b/Shared/mods/deathmatch/logic/CTickRateSettings.h @@ -27,6 +27,7 @@ struct CTickRateSettings iUnoccupiedVehicleSyncerDistance = 130; iVehicleContactSyncRadius = 30; playerTeleportAlert = 100; + cancelledDamageInterval = 1000; } int iPureSync; @@ -43,6 +44,7 @@ struct CTickRateSettings int iUnoccupiedVehicleSyncerDistance; int iVehicleContactSyncRadius; int playerTeleportAlert; + int cancelledDamageInterval; }; extern CTickRateSettings g_TickRateSettings; From 451cb9d82202185cc077f22deed3b8cb966a99d1 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 24 Aug 2025 17:29:05 +0200 Subject: [PATCH 5/8] Update mtaserver.conf --- Server/mods/deathmatch/mtaserver.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Server/mods/deathmatch/mtaserver.conf b/Server/mods/deathmatch/mtaserver.conf index 2dd6960ae0b..a97d77c6e6f 100644 --- a/Server/mods/deathmatch/mtaserver.conf +++ b/Server/mods/deathmatch/mtaserver.conf @@ -153,6 +153,10 @@ 100 + + 1000 + 1 @@ -317,6 +321,14 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 0 + + + 1 + From da0894d275626c80f9d4589c7dcd899c8adc9b61 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 24 Aug 2025 17:31:06 +0200 Subject: [PATCH 6/8] Update mtaserver.conf.template --- Server/mods/deathmatch/mtaserver.conf.template | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Server/mods/deathmatch/mtaserver.conf.template b/Server/mods/deathmatch/mtaserver.conf.template index 35cab835032..9f92d24dfdf 100644 --- a/Server/mods/deathmatch/mtaserver.conf.template +++ b/Server/mods/deathmatch/mtaserver.conf.template @@ -154,6 +154,10 @@ 100 + + 1000 + 1 @@ -317,4 +321,12 @@ 1 + + + 0 + + + 1 From f0478ac1ba3f8a50e38b875fae51382885ec2006 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 24 Aug 2025 17:32:24 +0200 Subject: [PATCH 7/8] Update editor.conf --- Server/mods/deathmatch/editor.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Server/mods/deathmatch/editor.conf b/Server/mods/deathmatch/editor.conf index 513bdeb5ebb..9f6d98b3974 100644 --- a/Server/mods/deathmatch/editor.conf +++ b/Server/mods/deathmatch/editor.conf @@ -153,6 +153,10 @@ 100 + + 1000 + 1 @@ -296,6 +300,14 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 0 + + + 1 + From 66e970085f9ffc4e0b87a96b5be19140796ad394 Mon Sep 17 00:00:00 2001 From: FileEX Date: Sun, 24 Aug 2025 17:33:18 +0200 Subject: [PATCH 8/8] Update local.conf --- Server/mods/deathmatch/local.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Server/mods/deathmatch/local.conf b/Server/mods/deathmatch/local.conf index 812499c830a..8f2af2ff3c7 100644 --- a/Server/mods/deathmatch/local.conf +++ b/Server/mods/deathmatch/local.conf @@ -153,6 +153,10 @@ 100 + + 1000 + 1 @@ -302,6 +306,14 @@ Values: 0 - Off, 1 - Enabled. Default - 1 --> 1 + + 0 + + + 1 +