1
1
/* ****************************************************************************
2
2
*
3
- * PROJECT: Multi Theft Auto
3
+ * PROJECT: Multi Theft Auto v1.0
4
4
* LICENSE: See LICENSE in the top level directory
5
+ * FILE: mods/deathmatch/logic/packets/CBulletsyncPacket.cpp
5
6
*
6
7
* Multi Theft Auto is available from https://www.multitheftauto.com/
7
8
*
12
13
#include " net/SyncStructures.h"
13
14
#include " CPlayer.h"
14
15
#include " CWeaponStatManager.h"
16
+ #include " CElementIDs.h"
17
+ #include " CElement.h"
15
18
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)
17
27
{
18
28
m_pSourceElement = player;
19
29
}
20
30
21
- bool CBulletsyncPacket::Read (NetBitStreamInterface& stream)
31
+ bool CBulletsyncPacket::IsValidVector ( const CVector& vec) noexcept
22
32
{
23
- if (!m_pSourceElement)
33
+ if (!vec.IsValid ())
34
+ return false ;
35
+
36
+ if (IsNaN (vec.fX ))
24
37
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
+ }
25
47
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)
28
53
return false ;
54
+ if (vec.fZ < -MAX_WORLD_COORD || vec.fZ > MAX_WORLD_COORD)
55
+ return false ;
56
+ return true ;
57
+ }
29
58
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
+ }
31
90
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))
33
95
return false ;
34
96
35
- if (!m_start. IsValid () || !m_end. IsValid ( ))
97
+ if (!IsValidWeaponId (type ))
36
98
return false ;
37
99
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))
39
112
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
+ }
40
125
41
- if (stream.ReadBit ())
126
+ bool CBulletsyncPacket::ReadOptionalDamage (NetBitStreamInterface& stream)
127
+ {
128
+ if (!stream.ReadBit ())
42
129
{
43
- stream.Read (m_damage);
44
- stream.Read (m_zone);
45
- stream.Read (m_damaged);
130
+ ResetDamageData ();
131
+ return true ;
46
132
}
47
133
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
+
48
236
return true ;
49
237
}
50
238
@@ -53,26 +241,52 @@ bool CBulletsyncPacket::Write(NetBitStreamInterface& stream) const
53
241
if (!m_pSourceElement)
54
242
return false ;
55
243
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 ;
58
274
59
275
stream.Write (id);
60
- stream.Write (static_cast < char >(m_weapon) );
276
+ stream.Write (weaponType );
61
277
stream.Write (reinterpret_cast <const char *>(&m_start), sizeof (CVector));
62
278
stream.Write (reinterpret_cast <const char *>(&m_end), sizeof (CVector));
63
279
stream.Write (m_order);
64
280
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)
66
285
{
67
- stream.WriteBit (true );
68
286
stream.Write (m_damage);
69
287
stream.Write (m_zone);
70
288
stream.Write (m_damaged);
71
289
}
72
- else
73
- {
74
- stream.WriteBit (false );
75
- }
76
290
77
291
return true ;
78
- }
292
+ }
0 commit comments