diff --git a/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.cpp b/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.cpp index a185a2d892..2d7b364e73 100644 --- a/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.cpp +++ b/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.cpp @@ -18,7 +18,6 @@ #include "CWeaponNames.h" CBulletsyncPacket::CBulletsyncPacket(CPlayer* player) - : m_weapon(WEAPONTYPE_UNARMED), m_start(), m_end(), m_order(0), m_damage(0.0f), m_zone(0), m_damaged(INVALID_ELEMENT_ID) { m_pSourceElement = player; } @@ -101,41 +100,28 @@ bool CBulletsyncPacket::ReadWeaponAndPositions(NetBitStreamInterface& stream) return true; } +// Returns false when there's a validation error. +// Make sure to reset damage data to defaults when that happens. bool CBulletsyncPacket::ReadOptionalDamage(NetBitStreamInterface& stream) { if (!stream.ReadBit()) - { - ResetDamageData(); return true; - } stream.Read(m_damage); stream.Read(m_zone); stream.Read(m_damaged); if (IsNaN(m_damage)) - { - ResetDamageData(); return false; - } if (m_damage < 0.0f || m_damage > MAX_DAMAGE) - { - ResetDamageData(); return false; - } if (m_zone > MAX_BODY_ZONE) - { - ResetDamageData(); return false; - } if (m_damaged == 0) - { - ResetDamageData(); return false; - } // Check that target element exists (if specified) // Note: m_damaged can be INVALID_ELEMENT_ID when shooting at ground/world @@ -143,10 +129,7 @@ bool CBulletsyncPacket::ReadOptionalDamage(NetBitStreamInterface& stream) { CElement* pElement = CElementIDs::GetElement(m_damaged); if (!pElement) - { - ResetDamageData(); return false; - } // Element exists } @@ -158,19 +141,10 @@ bool CBulletsyncPacket::Read(NetBitStreamInterface& stream) if (!m_pSourceElement) return false; - CPlayer* pPlayer = static_cast(m_pSourceElement); - if (pPlayer) - { - // Check if player is spawned and alive - if (!pPlayer->IsSpawned() || pPlayer->IsDead()) - return false; - - // Check player position is reasonable relative to bullet start - const CVector& playerPos = pPlayer->GetPosition(); - const float maxShootDistance = 50.0f; // Max distance from player to bullet start - - // This check will be done after we read positions - } + // Check if player is spawned and alive + CPlayer* pPlayer = GetSourcePlayer(); + if (!pPlayer->IsSpawned() || pPlayer->IsDead()) + return false; if (!ReadWeaponAndPositions(stream)) return false; @@ -205,7 +179,13 @@ bool CBulletsyncPacket::Read(NetBitStreamInterface& stream) return false; if (!ReadOptionalDamage(stream)) + { + // todo: do we really need to reset damage data when we're returning + // false? returning false deletes the packet, and other packets don't + // reset internal data based on validation failures. + ResetDamageData(); return false; + } return true; } @@ -224,6 +204,7 @@ bool CBulletsyncPacket::Write(NetBitStreamInterface& stream) const if (id == INVALID_ELEMENT_ID) return false; + // why? if (id == 0) return false; diff --git a/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.h b/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.h index 0f46f8e964..6e2834c48f 100644 --- a/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.h +++ b/Server/mods/deathmatch/logic/packets/CBulletsyncPacket.h @@ -1,6 +1,6 @@ /***************************************************************************** * - * PROJECT: Multi Theft Auto v1.0 + * PROJECT: Multi Theft Auto * LICENSE: See LICENSE in the top level directory * FILE: mods/deathmatch/logic/packets/CBulletsyncPacket.h * PURPOSE: Bullet synchronization packet class @@ -9,9 +9,6 @@ * *****************************************************************************/ -#ifndef __CBULLETSYNCPACKET_H -#define __CBULLETSYNCPACKET_H - #pragma once #include "CPacket.h" @@ -48,13 +45,11 @@ class CBulletsyncPacket final : public CPacket static bool IsValidWeaponId(unsigned char weaponId) noexcept; public: - eWeaponType m_weapon{}; + eWeaponType m_weapon = WEAPONTYPE_UNARMED; CVector m_start{}; CVector m_end{}; - std::uint8_t m_order{}; - float m_damage{}; - std::uint8_t m_zone{}; - ElementID m_damaged{INVALID_ELEMENT_ID}; + std::uint8_t m_order = 0; + float m_damage = 0.0f; + std::uint8_t m_zone = 0; + ElementID m_damaged = INVALID_ELEMENT_ID; }; - -#endif // __CBULLETSYNCPACKET_H diff --git a/Server/mods/deathmatch/logic/packets/CPacket.h b/Server/mods/deathmatch/logic/packets/CPacket.h index 455e9a1c41..d9c3537bbc 100644 --- a/Server/mods/deathmatch/logic/packets/CPacket.h +++ b/Server/mods/deathmatch/logic/packets/CPacket.h @@ -43,7 +43,22 @@ class CPacket virtual ePacketOrdering GetPacketOrdering() const { return PACKET_ORDERING_DEFAULT; } virtual unsigned long GetFlags() const = 0; + // Overridden when it's an incoming packet. + // + // Incoming packets always have CPlayer* as the source element. + // + // - Examples of incoming-only packets: CPlayerDiagnosticPacket, CCommandPacket + // - Examples of dual packets: CBulletsyncPacket, CVoiceDataPacket virtual bool Read(NetBitStreamInterface& BitStream) { return false; }; + + // Overridden when it's an outgoing packet. + // + // Outgoing packets may have any element type as the source element. As of + // 2026-01, CStaticFunctionDefinitions::SetPedStat is the caller of + // SetSourceElement with a non-player source. + // + // - Examples of outgoing-only packets: CPlayerStatsPacket, CDebugEchoPacket + // - Examples of dual packets: CBulletsyncPacket, CVoiceDataPacket virtual bool Write(NetBitStreamInterface& BitStream) const { return false; }; void SetSourceElement(CElement* pSource) { m_pSourceElement = pSource; };