diff --git a/Client/mods/deathmatch/logic/CClientExplosionManager.cpp b/Client/mods/deathmatch/logic/CClientExplosionManager.cpp index 8e79c61f50..583bbd6220 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 25f440fab5..cd9ea5913f 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 d21de68f06..d1a657db66 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 857aa91047..905a2c43cf 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) diff --git a/Server/mods/deathmatch/logic/CGame.cpp b/Server/mods/deathmatch/logic/CGame.cpp index 6b114ed01f..4ca89e33b8 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 f8bfad986a..0620c1d616 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())