From 58a6e5a89fd80d368ea217958ea841d193ebac35 Mon Sep 17 00:00:00 2001 From: Nico <122193236+Nico8340@users.noreply.github.com> Date: Sun, 13 Jul 2025 02:58:39 +0200 Subject: [PATCH 1/2] Client --- .../logic/CClientExplosionManager.cpp | 8 +--- Client/mods/deathmatch/logic/CClientGame.cpp | 4 +- Client/mods/deathmatch/logic/CClientGame.h | 2 +- .../logic/CStaticFunctionDefinitions.cpp | 43 ++++++++++++++++--- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/Client/mods/deathmatch/logic/CClientExplosionManager.cpp b/Client/mods/deathmatch/logic/CClientExplosionManager.cpp index 8e79c61f503..583bbd62209 100644 --- a/Client/mods/deathmatch/logic/CClientExplosionManager.cpp +++ b/Client/mods/deathmatch/logic/CClientExplosionManager.cpp @@ -129,12 +129,6 @@ bool CClientExplosionManager::Hook_ExplosionCreation(CEntity* pGameExplodingEnti { auto vehicle = reinterpret_cast(pResponsible); pOriginSource = vehicle; - - // Create an explosion, if the vehicle was not blown by us directly (CClientVehicle::Blow) - if (vehicle->GetBlowState() == VehicleBlowState::INTACT) - { - vehicle->SetBlowState(VehicleBlowState::AWAITING_EXPLOSION_SYNC); - } } // If theres other players, sync it relative to the closest (lag compensation) else if (m_pManager->GetPlayerManager()->Count() > 1) @@ -157,7 +151,7 @@ bool CClientExplosionManager::Hook_ExplosionCreation(CEntity* pGameExplodingEnti } // Request a new explosion - g_pClientGame->SendExplosionSync(vecPosition, explosionType, pOriginSource); + g_pClientGame->SendExplosionSync(vecPosition, explosionType, pOriginSource, VehicleBlowState::AWAITING_EXPLOSION_SYNC); return false; } diff --git a/Client/mods/deathmatch/logic/CClientGame.cpp b/Client/mods/deathmatch/logic/CClientGame.cpp index 25f440fab5e..cd9ea5913f0 100644 --- a/Client/mods/deathmatch/logic/CClientGame.cpp +++ b/Client/mods/deathmatch/logic/CClientGame.cpp @@ -5262,7 +5262,7 @@ bool CClientGame::StaticProcessPacket(unsigned char ucPacketID, NetBitStreamInte return false; } -void CClientGame::SendExplosionSync(const CVector& vecPosition, eExplosionType Type, CClientEntity* pOrigin) +void CClientGame::SendExplosionSync(const CVector& vecPosition, eExplosionType Type, CClientEntity* pOrigin, std::optional vehicleBlowState) { SPositionSync position(false); position.data.vecPosition = vecPosition; @@ -5285,7 +5285,7 @@ void CClientGame::SendExplosionSync(const CVector& vecPosition, eExplosionType T { auto vehicle = reinterpret_cast(pOrigin); pBitStream->WriteBit(1); - pBitStream->WriteBit(vehicle->GetBlowState() == VehicleBlowState::BLOWN); + pBitStream->WriteBit(vehicleBlowState.value_or(vehicle->GetBlowState()) == VehicleBlowState::BLOWN); } else { diff --git a/Client/mods/deathmatch/logic/CClientGame.h b/Client/mods/deathmatch/logic/CClientGame.h index d21de68f067..d1a657db662 100644 --- a/Client/mods/deathmatch/logic/CClientGame.h +++ b/Client/mods/deathmatch/logic/CClientGame.h @@ -627,7 +627,7 @@ class CClientGame bool VerifySADataFiles(int iEnableClientChecks = 0); void DebugElementRender(); - void SendExplosionSync(const CVector& vecPosition, eExplosionType Type, CClientEntity* pOrigin = NULL); + void SendExplosionSync(const CVector& vecPosition, eExplosionType Type, CClientEntity* pOrigin = nullptr, std::optional vehicleBlowState = std::nullopt); void SendFireSync(CFire* pFire); void SendProjectileSync(CClientProjectile* pProjectile); diff --git a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index 857aa910477..905a2c43cfb 100644 --- a/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Client/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -2866,17 +2866,46 @@ bool CStaticFunctionDefinitions::BlowVehicle(CClientEntity& Entity, std::optiona { RUN_CHILDREN(BlowVehicle(**iter, withExplosion)) - if (IS_VEHICLE(&Entity)) - { - CClientVehicle& vehicle = static_cast(Entity); + if (!IS_VEHICLE(&Entity)) + return false; - VehicleBlowFlags blow; - blow.withExplosion = withExplosion.value_or(true); + CClientVehicle& vehicle = static_cast(Entity); + VehicleBlowFlags blow; + + blow.withExplosion = withExplosion.value_or(true); + + if (vehicle.IsLocalEntity()) + { vehicle.Blow(blow); - return true; } + else + { + CVector position; + vehicle.GetPosition(position); - return false; + const auto type = vehicle.GetType(); + const auto state = (blow.withExplosion ? VehicleBlowState::AWAITING_EXPLOSION_SYNC : VehicleBlowState::BLOWN); + eExplosionType explosion; + + switch (type) + { + case CLIENTVEHICLE_CAR: + explosion = EXP_TYPE_CAR; + break; + case CLIENTVEHICLE_HELI: + explosion = EXP_TYPE_HELI; + break; + case CLIENTVEHICLE_BOAT: + explosion = EXP_TYPE_BOAT; + break; + default: + explosion = EXP_TYPE_CAR; + } + + g_pClientGame->SendExplosionSync(position, explosion, &Entity, state); + } + + return true; } bool CStaticFunctionDefinitions::GetVehicleVariant(CClientVehicle* pVehicle, unsigned char& ucVariant, unsigned char& ucVariant2) From 0d3dc5d05a50c137469f2f7b13346434f2842e7d Mon Sep 17 00:00:00 2001 From: Nico <122193236+Nico8340@users.noreply.github.com> Date: Sun, 13 Jul 2025 02:58:42 +0200 Subject: [PATCH 2/2] Server --- Server/mods/deathmatch/logic/CGame.cpp | 10 ++++++---- .../deathmatch/logic/CStaticFunctionDefinitions.cpp | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 6b114ed01f0..4ca89e33b84 100644 --- a/Server/mods/deathmatch/logic/CGame.cpp +++ b/Server/mods/deathmatch/logic/CGame.cpp @@ -2833,18 +2833,20 @@ void CGame::Packet_ExplosionSync(CExplosionSyncPacket& Packet) if (previousBlowState != VehicleBlowState::BLOWN) { - vehicle->SetBlowState(VehicleBlowState::BLOWN); - vehicle->SetEngineOn(false); - // NOTE(botder): We only trigger this event if we didn't blow up a vehicle with `blowVehicle` if (previousBlowState == VehicleBlowState::INTACT) { CLuaArguments arguments; arguments.PushBoolean(!Packet.m_blowVehicleWithoutExplosion); arguments.PushElement(clientSource); - vehicle->CallEvent("onVehicleExplode", arguments); + + if (!vehicle->CallEvent("onVehicleExplode", arguments)) + return; } + vehicle->SetBlowState(VehicleBlowState::BLOWN); + vehicle->SetEngineOn(false); + syncToPlayers = vehicle->GetBlowState() == VehicleBlowState::BLOWN && !vehicle->IsBeingDeleted(); } else diff --git a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp index f8bfad986a3..0620c1d6165 100644 --- a/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp +++ b/Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp @@ -5485,7 +5485,9 @@ bool CStaticFunctionDefinitions::BlowVehicle(CElement* pElement, std::optionalCallEvent("onVehicleExplode", arguments); + + if (!vehicle->CallEvent("onVehicleExplode", arguments)) + return false; // Abort if vehicle got fixed or destroyed if (!vehicle->IsBlown() || vehicle->IsBeingDeleted())