11/* ****************************************************************************
22 *
3- * PROJECT: Multi Theft Auto
3+ * PROJECT: Multi Theft Auto v1.0
44 * LICENSE: See LICENSE in the top level directory
5+ * FILE: mods/deathmatch/logic/packets/CBulletsyncPacket.cpp
56 *
67 * Multi Theft Auto is available from https://www.multitheftauto.com/
78 *
1213#include " net/SyncStructures.h"
1314#include " CPlayer.h"
1415#include " CWeaponStatManager.h"
16+ #include " CElementIDs.h"
17+ #include " CElement.h"
1518
16- CBulletsyncPacket::CBulletsyncPacket (CPlayer* player) : m_weapon(WEAPONTYPE_UNARMED), m_order(0 ), m_damage(0 .0f ), m_zone(0 ), m_damaged(INVALID_ELEMENT_ID)
19+ CBulletsyncPacket::CBulletsyncPacket (CPlayer* player)
20+ : m_weapon(WEAPONTYPE_UNARMED)
21+ , m_start()
22+ , m_end()
23+ , m_order(0 )
24+ , m_damage(0 .0f )
25+ , m_zone(0 )
26+ , m_damaged(INVALID_ELEMENT_ID)
1727{
1828 m_pSourceElement = player;
1929}
2030
21- bool CBulletsyncPacket::Read (NetBitStreamInterface& stream)
31+ bool CBulletsyncPacket::IsValidVector ( const CVector& vec) noexcept
2232{
23- if (!m_pSourceElement)
33+ if (!vec.IsValid ())
34+ return false ;
35+
36+ if (IsNaN (vec.fX ))
2437 return false ;
38+
39+ if (IsNaN (vec.fY ))
40+ return false ;
41+
42+ if (IsNaN (vec.fZ ))
43+ return false ;
44+
45+ return true ;
46+ }
2547
26- char type = 0 ;
27- if (!stream.Read (type) || !CWeaponStatManager::HasWeaponBulletSync (type))
48+ bool CBulletsyncPacket::ValidateVectorBounds (const CVector& vec) const noexcept
49+ {
50+ if (vec.fX < -MAX_WORLD_COORD || vec.fX > MAX_WORLD_COORD)
51+ return false ;
52+ if (vec.fY < -MAX_WORLD_COORD || vec.fY > MAX_WORLD_COORD)
2853 return false ;
54+ if (vec.fZ < -MAX_WORLD_COORD || vec.fZ > MAX_WORLD_COORD)
55+ return false ;
56+ return true ;
57+ }
2958
30- m_weapon = static_cast <eWeaponType>(type);
59+ bool CBulletsyncPacket::IsValidWeaponId (unsigned char weaponId) noexcept
60+ {
61+ return CWeaponStatManager::HasWeaponBulletSync (static_cast <uint32_t >(weaponId));
62+ }
63+
64+ bool CBulletsyncPacket::ValidateTrajectory () const noexcept
65+ {
66+ const float dx = m_end.fX - m_start.fX ;
67+ const float dy = m_end.fY - m_start.fY ;
68+ const float dz = m_end.fZ - m_start.fZ ;
69+
70+ const float movementSq = (dx * dx) + (dy * dy) + (dz * dz);
71+
72+ if (IsNaN (movementSq))
73+ return false ;
74+
75+ if (movementSq < MIN_DISTANCE_SQ)
76+ return false ;
77+
78+ if (movementSq > MAX_DISTANCE_SQ)
79+ return false ;
80+
81+ return true ;
82+ }
83+
84+ void CBulletsyncPacket::ResetDamageData () noexcept
85+ {
86+ m_damage = 0 .0f ;
87+ m_zone = 0 ;
88+ m_damaged = INVALID_ELEMENT_ID;
89+ }
3190
32- if (!stream.Read (reinterpret_cast <char *>(&m_start), sizeof (CVector)) || !stream.Read (reinterpret_cast <char *>(&m_end), sizeof (CVector)))
91+ bool CBulletsyncPacket::ReadWeaponAndPositions (NetBitStreamInterface& stream)
92+ {
93+ unsigned char type = 0 ;
94+ if (!stream.Read (type))
3395 return false ;
3496
35- if (!m_start. IsValid () || !m_end. IsValid ( ))
97+ if (!IsValidWeaponId (type ))
3698 return false ;
3799
38- if (!stream.Read (m_order))
100+ m_weapon = static_cast <eWeaponType>(type);
101+
102+ if (!stream.Read (reinterpret_cast <char *>(&m_start), sizeof (CVector)))
103+ return false ;
104+
105+ if (!stream.Read (reinterpret_cast <char *>(&m_end), sizeof (CVector)))
106+ return false ;
107+
108+ if (!IsValidVector (m_start))
109+ return false ;
110+
111+ if (!IsValidVector (m_end))
39112 return false ;
113+
114+ if (!ValidateVectorBounds (m_start))
115+ return false ;
116+
117+ if (!ValidateVectorBounds (m_end))
118+ return false ;
119+
120+ if (!ValidateTrajectory ())
121+ return false ;
122+
123+ return true ;
124+ }
40125
41- if (stream.ReadBit ())
126+ bool CBulletsyncPacket::ReadOptionalDamage (NetBitStreamInterface& stream)
127+ {
128+ if (!stream.ReadBit ())
42129 {
43- stream.Read (m_damage);
44- stream.Read (m_zone);
45- stream.Read (m_damaged);
130+ ResetDamageData ();
131+ return true ;
46132 }
47133
134+ stream.Read (m_damage);
135+ stream.Read (m_zone);
136+ stream.Read (m_damaged);
137+
138+ if (IsNaN (m_damage))
139+ {
140+ ResetDamageData ();
141+ return false ;
142+ }
143+
144+ if (m_damage < 0 .0f || m_damage > MAX_DAMAGE)
145+ {
146+ ResetDamageData ();
147+ return false ;
148+ }
149+
150+ if (m_zone > MAX_BODY_ZONE)
151+ {
152+ ResetDamageData ();
153+ return false ;
154+ }
155+
156+ if (m_damaged == 0 )
157+ {
158+ ResetDamageData ();
159+ return false ;
160+ }
161+
162+ // Validate that target element exists
163+ if (m_damaged != INVALID_ELEMENT_ID)
164+ {
165+ CElement* pElement = CElementIDs::GetElement (m_damaged);
166+ if (!pElement)
167+ {
168+ ResetDamageData ();
169+ return false ;
170+ }
171+
172+ // Check element type is valid for damage
173+ auto elementType = pElement->GetType ();
174+ if (elementType != CElement::PLAYER &&
175+ elementType != CElement::PED &&
176+ elementType != CElement::VEHICLE)
177+ {
178+ ResetDamageData ();
179+ return false ;
180+ }
181+ }
182+
183+ return true ;
184+ }
185+
186+ bool CBulletsyncPacket::Read (NetBitStreamInterface& stream)
187+ {
188+ if (!m_pSourceElement)
189+ return false ;
190+
191+ CPlayer* pPlayer = static_cast <CPlayer*>(m_pSourceElement);
192+ if (pPlayer)
193+ {
194+ // Check if player is spawned and alive
195+ if (!pPlayer->IsSpawned () || pPlayer->IsDead ())
196+ return false ;
197+
198+ // Check player position is reasonable relative to bullet start
199+ const CVector& playerPos = pPlayer->GetPosition ();
200+ const float maxShootDistance = 50 .0f ; // Max distance from player to bullet start
201+
202+ // This check will be done after we read positions
203+ }
204+
205+ if (!ReadWeaponAndPositions (stream))
206+ return false ;
207+
208+ // Now validate player position relative to shot origin
209+ if (pPlayer)
210+ {
211+ const CVector& playerPos = pPlayer->GetPosition ();
212+ float dx = m_start.fX - playerPos.fX ;
213+ float dy = m_start.fY - playerPos.fY ;
214+ float dz = m_start.fZ - playerPos.fZ ;
215+ float distSq = dx*dx + dy*dy + dz*dz;
216+
217+ const float maxShootDistanceSq = 50 .0f * 50 .0f ;
218+ if (distSq > maxShootDistanceSq)
219+ return false ;
220+
221+ // Check if player has this weapon
222+ if (!pPlayer->HasWeaponType (static_cast <unsigned char >(m_weapon)))
223+ return false ;
224+
225+ // Check if weapon has ammo
226+ if (pPlayer->GetWeaponAmmoInClip (static_cast <unsigned char >(m_weapon)) == 0 )
227+ return false ;
228+ }
229+
230+ if (!stream.Read (m_order))
231+ return false ;
232+
233+ if (!ReadOptionalDamage (stream))
234+ return false ;
235+
48236 return true ;
49237}
50238
@@ -53,26 +241,52 @@ bool CBulletsyncPacket::Write(NetBitStreamInterface& stream) const
53241 if (!m_pSourceElement)
54242 return false ;
55243
56- auto * player = static_cast <CPlayer*>(m_pSourceElement);
57- auto id = player->GetID ();
244+ const auto * pPlayer = static_cast <const CPlayer*>(m_pSourceElement);
245+ if (!pPlayer)
246+ return false ;
247+
248+ const ElementID id = pPlayer->GetID ();
249+
250+ if (id == INVALID_ELEMENT_ID)
251+ return false ;
252+
253+ if (id == 0 )
254+ return false ;
255+
256+ if (!IsValidVector (m_start))
257+ return false ;
258+
259+ if (!IsValidVector (m_end))
260+ return false ;
261+
262+ if (!ValidateVectorBounds (m_start))
263+ return false ;
264+
265+ if (!ValidateVectorBounds (m_end))
266+ return false ;
267+
268+ if (!ValidateTrajectory ())
269+ return false ;
270+
271+ const unsigned char weaponType = static_cast <unsigned char >(m_weapon);
272+ if (!IsValidWeaponId (weaponType))
273+ return false ;
58274
59275 stream.Write (id);
60- stream.Write (static_cast < char >(m_weapon) );
276+ stream.Write (weaponType );
61277 stream.Write (reinterpret_cast <const char *>(&m_start), sizeof (CVector));
62278 stream.Write (reinterpret_cast <const char *>(&m_end), sizeof (CVector));
63279 stream.Write (m_order);
64280
65- if (m_damage > 0 .0f && m_damaged != INVALID_ELEMENT_ID)
281+ const bool hasDamage = (m_damage > EPSILON) && (m_damaged != INVALID_ELEMENT_ID);
282+ stream.WriteBit (hasDamage);
283+
284+ if (hasDamage)
66285 {
67- stream.WriteBit (true );
68286 stream.Write (m_damage);
69287 stream.Write (m_zone);
70288 stream.Write (m_damaged);
71289 }
72- else
73- {
74- stream.WriteBit (false );
75- }
76290
77291 return true ;
78- }
292+ }
0 commit comments