Skip to content

Commit 4de6b61

Browse files
committed
Added fix for bullet sync not applying damage to the local player during network interruptions by applying remote calculated damage.
Enable with: setServerConfigSetting( "bad_net_bullet_fix", 1 ) Enable logging with: setServerConfigSetting( "enable_diagnostic", "1010" ) Conflicts: MTA10/mods/deathmatch/logic/CPacketHandler.cpp
1 parent bdbb59c commit 4de6b61

File tree

15 files changed

+377
-135
lines changed

15 files changed

+377
-135
lines changed

MTA10/mods/deathmatch/logic/CClientGame.cpp

Lines changed: 192 additions & 129 deletions
Large diffs are not rendered by default.

MTA10/mods/deathmatch/logic/CClientGame.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,8 @@ class CClientGame
559559
public:
560560
static bool StaticProcessPacket ( unsigned char ucPacketID, NetBitStreamInterface& bitStream );
561561

562+
bool ApplyPedDamageFromGame ( eWeaponType weaponType, float fDamage, uchar ucHitZone, CClientPed* pDamagedPed, CClientEntity* pInflictingEntity, CEventDamage* pEvent );
563+
562564
bool VerifySADataFiles ( int iEnableClientChecks = 0 );
563565
void DebugElementRender ( void );
564566

MTA10/mods/deathmatch/logic/CNetAPI.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2292,6 +2292,18 @@ void CNetAPI::ReadBulletsync ( CClientPlayer* pPlayer, NetBitStreamInterface& Bi
22922292
uchar ucOrderCounter = 0;
22932293
BitStream.Read ( ucOrderCounter );
22942294

2295+
float fDamage = 0;
2296+
uchar ucHitZone = 0;
2297+
CClientPlayer* pDamagedPlayer = NULL;
2298+
if ( BitStream.ReadBit() )
2299+
{
2300+
ElementID DamagedPlayerID = INVALID_ELEMENT_ID;
2301+
BitStream.Read( fDamage );
2302+
BitStream.Read( ucHitZone );
2303+
BitStream.Read( DamagedPlayerID );
2304+
pDamagedPlayer = DynamicCast < CClientPlayer > ( CElementIDs::GetElement( DamagedPlayerID ) );
2305+
}
2306+
22952307
// Duplicate bullet check
22962308
{
22972309
bool bIsDuplicate = false;
@@ -2315,7 +2327,7 @@ void CNetAPI::ReadBulletsync ( CClientPlayer* pPlayer, NetBitStreamInterface& Bi
23152327
return;
23162328
}
23172329

2318-
pPlayer->DischargeWeapon ( weaponType, vecStart, vecEnd );
2330+
pPlayer->DischargeWeapon ( weaponType, vecStart, vecEnd, fDamage, ucHitZone, pDamagedPlayer );
23192331
}
23202332

23212333

@@ -2344,7 +2356,7 @@ void CNetAPI::ReadWeaponBulletsync ( CClientPlayer* pPlayer, NetBitStreamInterfa
23442356
//
23452357
// Send bulletsync fire button press packet to remote players
23462358
//
2347-
void CNetAPI::SendBulletSyncFire ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd )
2359+
void CNetAPI::SendBulletSyncFire ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd, float fDamage, uchar ucHitZone, CClientPlayer* pRemoteDamagedPlayer )
23482360
{
23492361
// Send a bulletsync packet
23502362
NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream ();
@@ -2357,6 +2369,18 @@ void CNetAPI::SendBulletSyncFire ( eWeaponType weaponType, const CVector& vecSta
23572369

23582370
pBitStream->Write ( m_ucBulletSyncOrderCounter++ );
23592371

2372+
if ( fDamage > 0 && pRemoteDamagedPlayer )
2373+
{
2374+
pBitStream->WriteBit ( true );
2375+
pBitStream->Write ( fDamage );
2376+
pBitStream->Write ( ucHitZone );
2377+
pBitStream->Write ( pRemoteDamagedPlayer->GetID() );
2378+
}
2379+
else
2380+
{
2381+
pBitStream->WriteBit ( false );
2382+
}
2383+
23602384
// Send the packet
23612385
g_pNet->SendPacket ( PACKET_ID_PLAYER_BULLETSYNC, pBitStream, PACKET_PRIORITY_MEDIUM, PACKET_RELIABILITY_RELIABLE );
23622386
g_pNet->DeallocateNetBitStream ( pBitStream );

MTA10/mods/deathmatch/logic/CNetAPI.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class CNetAPI
5959

6060
void AddInterpolation ( const CVector& vecPosition );
6161
bool GetInterpolation ( CVector& vecPosition, unsigned short usLatency );
62-
void SendBulletSyncFire ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd );
62+
void SendBulletSyncFire ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd, float fDamage, uchar ucHitZone, CClientPlayer* pRemoteDamagedPlayer );
6363
void SendBulletSyncCustomWeaponFire ( CClientWeapon * pWeapon, const CVector& vecStart, const CVector& vecEnd );
6464
bool IsNetworkTrouble ( void ) { return m_bIsNetworkTrouble; }
6565

MTA10/mods/deathmatch/logic/CPacketHandler.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2545,7 +2545,10 @@ void CPacketHandler::Packet_PlayerNetworkStatus ( NetBitStreamInterface& bitStre
25452545
Arguments.PushNumber ( uiTicks ); // Ticks since interruption start
25462546
CClientPlayer* pLocalPlayer = g_pClientGame->m_pPlayerManager->GetLocalPlayer ();
25472547
if ( pLocalPlayer )
2548+
{
2549+
pLocalPlayer->SetIsInNetworkInterruption( ucType == 0 );
25482550
pLocalPlayer->CallEvent ( "onClientPlayerNetworkStatus", Arguments, false );
2551+
}
25492552
}
25502553
}
25512554

MTA10/mods/shared_logic/CClientPlayer.cpp

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#include <StdInc.h>
1919
int g_iDamageEventLimit = -1;
20+
extern float g_fApplyDamageLastAmount;
21+
extern CClientPed* g_pApplyDamageLastDamagedPed;
2022

2123
CClientPlayer::CClientPlayer ( CClientManager* pManager, ElementID ID, bool bIsLocalPlayer ) : ClassInit ( this ), CClientPed ( pManager, 0, ID, bIsLocalPlayer )
2224
{
@@ -259,10 +261,13 @@ void CClientPlayer::SetNametagText ( const char * szText )
259261
}
260262

261263

262-
void CClientPlayer::DischargeWeapon ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd )
264+
void CClientPlayer::DischargeWeapon ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd, float fBackupDamage, uchar ucBackupHitZone, CClientPlayer* pBackupDamagedPlayer )
263265
{
264266
if ( m_pPlayerPed )
265267
{
268+
g_pApplyDamageLastDamagedPed = NULL;
269+
g_fApplyDamageLastAmount = 0;
270+
266271
// Check weapon matches and is enabled for bullet sync
267272
if ( weaponType == GetCurrentWeaponType () &&
268273
g_pClientGame->GetWeaponTypeUsesBulletSync ( weaponType ) )
@@ -280,6 +285,40 @@ void CClientPlayer::DischargeWeapon ( eWeaponType weaponType, const CVector& vec
280285

281286
m_shotSyncData->m_bRemoteBulletSyncVectorsValid = false;
282287
}
288+
289+
// Apply extra damage if player has bad network
290+
if ( pBackupDamagedPlayer && pBackupDamagedPlayer->GetGamePlayer() && pBackupDamagedPlayer->GetWasRecentlyInNetworkInterruption( 1000 ) )
291+
{
292+
// Subtract any damage that did get applied during FireBullet
293+
if ( pBackupDamagedPlayer == g_pApplyDamageLastDamagedPed )
294+
fBackupDamage -= g_fApplyDamageLastAmount;
295+
296+
if ( fBackupDamage > 0 )
297+
{
298+
// Apply left over damage like what the game would:
299+
// CClientPlayer has pre damage health/armor
300+
// CPlayerPed has post damage health/armor
301+
302+
float fPreviousHealth = pBackupDamagedPlayer->m_fHealth;
303+
float fPreviousArmor = pBackupDamagedPlayer->m_fArmor;
304+
305+
// Calculate how much damage should be applied to health/armor
306+
float fArmorDamage = Min( fBackupDamage, pBackupDamagedPlayer->m_fArmor );
307+
float fHealthDamage = Min( fBackupDamage - fArmorDamage, pBackupDamagedPlayer->m_fHealth );
308+
309+
float fNewArmor = pBackupDamagedPlayer->m_fArmor - fArmorDamage;
310+
float fNewHealth = pBackupDamagedPlayer->m_fHealth - fHealthDamage;
311+
312+
// Ensure CPlayerPed has post damage health/armor
313+
pBackupDamagedPlayer->GetGamePlayer()->SetHealth( fNewHealth );
314+
pBackupDamagedPlayer->GetGamePlayer()->SetArmor( fNewArmor );
315+
316+
g_pClientGame->ApplyPedDamageFromGame( weaponType, fBackupDamage, ucBackupHitZone, pBackupDamagedPlayer, this, NULL );
317+
318+
SString strMessage( "Applied %0.2f damage to %s (from %s) due to network interruption", fBackupDamage, pBackupDamagedPlayer->GetNick(), GetNick() );
319+
g_pClientGame->TellServerSomethingImportant( 1010, strMessage, false );
320+
}
321+
}
283322
}
284323
}
285324

@@ -299,3 +338,17 @@ uint CClientPlayer::GetRemoteBuildNumber ( void )
299338
{
300339
return m_uiRemoteBuildNumber;
301340
}
341+
342+
bool CClientPlayer::GetWasRecentlyInNetworkInterruption ( uint uiMaxTicksAgo )
343+
{
344+
if ( m_bInNetworkInterruption )
345+
return true;
346+
return m_TimeSinceNetworkInterruptionEnded.Get() < uiMaxTicksAgo;
347+
}
348+
349+
void CClientPlayer::SetIsInNetworkInterruption ( bool bBegan )
350+
{
351+
m_bInNetworkInterruption = bBegan;
352+
if ( !bBegan )
353+
m_TimeSinceNetworkInterruptionEnded.Reset();
354+
}

MTA10/mods/shared_logic/CClientPlayer.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,13 @@ class CClientPlayer : public CClientPed
109109

110110
inline CClientManager* GetManager ( void ) { return m_pManager; }
111111

112-
void DischargeWeapon ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd );
112+
void DischargeWeapon ( eWeaponType weaponType, const CVector& vecStart, const CVector& vecEnd, float fBackupDamage, uchar ucBackupHitZone, CClientPlayer* pBackupDamagedPlayer );
113113

114114
void SetRemoteVersionInfo ( ushort usBitstreamVersion, uint uiBuildNumber );
115115
ushort GetRemoteBitstreamVersion ( void );
116116
uint GetRemoteBuildNumber ( void );
117+
bool GetWasRecentlyInNetworkInterruption ( uint uiMaxTicksAgo );
118+
void SetIsInNetworkInterruption ( bool bInNetworkInterruption );
117119

118120
CVector m_vecPrevBulletSyncStart;
119121
CVector m_vecPrevBulletSyncEnd;
@@ -168,6 +170,8 @@ class CClientPlayer : public CClientPed
168170
CVector m_vecLightsyncCalcedVelocity;
169171
ushort m_usRemoteBitstreamVersion;
170172
uint m_uiRemoteBuildNumber;
173+
bool m_bInNetworkInterruption;
174+
CElapsedTime m_TimeSinceNetworkInterruptionEnded;
171175

172176
#ifdef MTA_DEBUG
173177
private:

MTA10_Server/mods/deathmatch/logic/CGame.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2268,6 +2268,11 @@ void CGame::Packet_Bulletsync ( CBulletsyncPacket& Packet )
22682268
CPlayer* pPlayer = Packet.GetSourcePlayer ();
22692269
if ( pPlayer && pPlayer->IsJoined () )
22702270
{
2271+
// Remove bad net fix data if disabled
2272+
if ( !GetConfig()->GetBadNetBulletFixEnabled() )
2273+
{
2274+
Packet.m_DamagedPlayerID = INVALID_ELEMENT_ID;
2275+
}
22712276
// Relay to other players
22722277
RelayNearbyPacket ( Packet );
22732278
}

MTA10_Server/mods/deathmatch/logic/CMainConfig.cpp

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ bool CMainConfig::Load ( void )
355355

356356
{
357357
SString strEnable;
358-
GetString ( m_pRootNode, "enablediagnostic", strEnable );
358+
GetString ( m_pRootNode, "enable_diagnostic", strEnable );
359359
strEnable = strEnable.Replace( " ", "" );
360360
std::vector < SString > tagList;
361361
strEnable.Split ( ",", tagList );
@@ -1167,6 +1167,14 @@ bool CMainConfig::GetSetting ( const SString& strName, SString& strValue )
11671167
return false;
11681168
}
11691169
else
1170+
if ( strName == "enable_diagnostic" )
1171+
{
1172+
for ( std::set < SString >::iterator iter = m_EnableDiagnosticMap.begin() ; iter != m_EnableDiagnosticMap.end() ; ++iter )
1173+
strValue += *iter + ",";
1174+
strValue = strValue.TrimEnd( "," );
1175+
return true;
1176+
}
1177+
else
11701178
{
11711179
// Check settings in this list here
11721180
const std::vector < SIntSetting >& settingList = GetIntSettingList ();
@@ -1358,6 +1366,27 @@ bool CMainConfig::SetSetting ( const SString& strName, const SString& strValue,
13581366
Save ();
13591367
return true;
13601368
}
1369+
else
1370+
if ( strName == "enable_diagnostic" )
1371+
{
1372+
if ( true )
1373+
{
1374+
m_EnableDiagnosticMap.clear();
1375+
SString strEnableDiagnostic = strValue.Replace( " ", "" );
1376+
std::vector < SString > tagList;
1377+
strEnableDiagnostic.Split ( ",", tagList );
1378+
for ( std::vector < SString >::iterator it = tagList.begin () ; it != tagList.end () ; ++it )
1379+
if ( (*it).length () )
1380+
MapInsert ( m_EnableDiagnosticMap, *it );
1381+
1382+
if ( bSave )
1383+
{
1384+
SetString ( m_pRootNode, "enable_diagnostic", strEnableDiagnostic );
1385+
Save ();
1386+
}
1387+
return true;
1388+
}
1389+
}
13611390

13621391
// Check settings in this list here
13631392
const std::vector < SIntSetting >& settingList = GetIntSettingList ();
@@ -1423,6 +1452,7 @@ const std::vector < SIntSetting >& CMainConfig::GetIntSettingList ( void )
14231452
{ false, false, 0, 1, 2, "compact_internal_databases", &m_iCompactInternalDatabases, NULL },
14241453
{ true, true, 0, 1, 2, "minclientversion_auto_update", &m_iMinClientVersionAutoUpdate, NULL },
14251454
{ true, true, 0, 0, 100, "server_logic_fps_limit", &m_iServerLogicFpsLimit, NULL },
1455+
{ true, true, 0, 0, 1, "bad_net_bullet_fix", &m_bBadNetBulletFixEnabled, NULL },
14261456
};
14271457

14281458
static std::vector < SIntSetting > settingsList;

MTA10_Server/mods/deathmatch/logic/CMainConfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class CMainConfig: public CXMLConfig
124124
bool GetUseAltPulseOrder ( void ) const { return m_bUseAltPulseOrder != 0; }
125125
const SString& GetLoadstringLogFilename ( void ) const { return m_strLoadstringLogFilename; }
126126
bool GetLoadstringLogEnabled ( void ) const { return !m_strLoadstringLogFilename.empty(); }
127+
bool GetBadNetBulletFixEnabled ( void ) const { return m_bBadNetBulletFixEnabled != 0; }
127128

128129
SString GetSetting ( const SString& configSetting );
129130
bool GetSetting ( const SString& configSetting, SString& strValue );
@@ -213,6 +214,7 @@ class CMainConfig: public CXMLConfig
213214
SString m_strLoadstringLogFilename;
214215
int m_iMinClientVersionAutoUpdate;
215216
int m_iServerLogicFpsLimit;
217+
int m_bBadNetBulletFixEnabled;
216218
};
217219

218220
#endif

0 commit comments

Comments
 (0)