# HG changeset patch # User Adam Kaminski # Date 1634649072 14400 # Tue Oct 19 09:11:12 2021 -0400 # Node ID fba1ab2fa4c3d6d4d065e53f0e9d0ccec7825e74 # Parent eff6a90ae21b349905de7ec8ffb3634e3476c14e "cl_backupcommands" also takes care of a client's weapon select commands. diff -r eff6a90ae21b -r fba1ab2fa4c3 src/cl_commands.cpp --- a/src/cl_commands.cpp Sun Oct 24 02:01:10 2021 +0100 +++ b/src/cl_commands.cpp Tue Oct 19 09:11:12 2021 -0400 @@ -73,12 +73,16 @@ static ULONG g_ulLastJoinTime = 0; static ULONG g_ulLastDropTime = 0; static ULONG g_ulLastSVCheatMessageTime = 0; +static ULONG g_ulLastWeaponSelectTime = 0; // [AK] static bool g_bIgnoreWeaponSelect = false; SDWORD g_sdwCheckCmd = 0; // [AK] Backups of the last few movement commands we sent to the server. static RingBuffer g_BackupMoveCMDs; +// [AK] The last weapon class we tried switching to before sending to the server. +static const PClass *g_pLastWeaponClass = NULL; + //***************************************************************************** // FUNCTIONS @@ -96,6 +100,8 @@ void CLIENT_ClearBackupCommands( void ) { g_BackupMoveCMDs.clear( ); + g_ulLastWeaponSelectTime = 0; + g_pLastWeaponClass = NULL; } //***************************************************************************** @@ -498,8 +504,44 @@ if ( ( pType == NULL ) || g_bIgnoreWeaponSelect ) return; - CLIENT_GetLocalBuffer( )->ByteStream.WriteByte( CLC_WEAPONSELECT ); - CLIENT_GetLocalBuffer( )->ByteStream.WriteShort( pType->getActorNetworkIndex() ); + // [AK] If we don't want to send backup commands, send only this one and that's it. + if ( cl_backupcommands == 0 ) + { + CLIENT_GetLocalBuffer( )->ByteStream.WriteByte( CLC_WEAPONSELECT ); + CLIENT_GetLocalBuffer( )->ByteStream.WriteShort( pType->getActorNetworkIndex() ); + } + else + { + // [AK] Save the weapon class and the original time we sent out the command, + // which we'll use when we re-send the command. + g_pLastWeaponClass = pType; + g_ulLastWeaponSelectTime = gametic; + + // [AK] Send out the backup command. + CLIENTCOMMANDS_SendBackupWeaponSelect( ); + } +} + +//***************************************************************************** +// +void CLIENTCOMMANDS_SendBackupWeaponSelect( void ) +{ + if (( g_pLastWeaponClass == NULL ) || ( g_bIgnoreWeaponSelect )) + return; + + // [AK] We don't want to send out this command more than we should (i.e. up to how + // many backup commands we can send). If the time that we originally sent this + // command is too far into the past, don't send it anymore. + if ( gametic - g_ulLastWeaponSelectTime > static_cast( cl_backupcommands )) + return; + + // [AK] A backup version of a weapon select command is different from an ordinary + // CLC_WEAPONSELECT command, so we'll use a different CLC identifier for it. We must + // also send the gametic so the server knows exactly where this command should go + // in the client's tic buffer, or can ignore it if it's already been received. + CLIENT_GetLocalBuffer( )->ByteStream.WriteByte( CLC_WEAPONSELECTBACKUP ); + CLIENT_GetLocalBuffer( )->ByteStream.WriteLong( g_ulLastWeaponSelectTime ); + CLIENT_GetLocalBuffer( )->ByteStream.WriteShort( g_pLastWeaponClass->getActorNetworkIndex( )); } //***************************************************************************** diff -r eff6a90ae21b -r fba1ab2fa4c3 src/cl_commands.h --- a/src/cl_commands.h Sun Oct 24 02:01:10 2021 +0100 +++ b/src/cl_commands.h Tue Oct 19 09:11:12 2021 -0400 @@ -84,6 +84,7 @@ void CLIENTCOMMANDS_MissingPacket( void ); void CLIENTCOMMANDS_Pong( ULONG ulTime ); void CLIENTCOMMANDS_WeaponSelect( const PClass *pType ); +void CLIENTCOMMANDS_SendBackupWeaponSelect( void ); void CLIENTCOMMANDS_Taunt( void ); void CLIENTCOMMANDS_Spectate( void ); void CLIENTCOMMANDS_RequestJoin( const char *pszJoinPassword ); diff -r eff6a90ae21b -r fba1ab2fa4c3 src/cl_main.cpp --- a/src/cl_main.cpp Sun Oct 24 02:01:10 2021 +0100 +++ b/src/cl_main.cpp Tue Oct 19 09:11:12 2021 -0400 @@ -2527,6 +2527,11 @@ // Send the move header and the gametic. CLIENTCOMMANDS_ClientMove( ); + + // [AK] If we had recently sent out a weapon select command, try sending out backup copies of + // it in case it doesn't reach the server. Only do this a few times. + if ( cl_backupcommands > 0 ) + CLIENTCOMMANDS_SendBackupWeaponSelect( ); } //***************************************************************************** diff -r eff6a90ae21b -r fba1ab2fa4c3 src/network_enums.h --- a/src/network_enums.h Sun Oct 24 02:01:10 2021 +0100 +++ b/src/network_enums.h Tue Oct 19 09:11:12 2021 -0400 @@ -411,6 +411,7 @@ ENUM_ELEMENT( CLC_MISSINGPACKET ), ENUM_ELEMENT( CLC_PONG ), ENUM_ELEMENT( CLC_WEAPONSELECT ), + ENUM_ELEMENT( CLC_WEAPONSELECTBACKUP ), ENUM_ELEMENT( CLC_TAUNT ), ENUM_ELEMENT( CLC_SPECTATE ), ENUM_ELEMENT( CLC_REQUESTJOIN ), diff -r eff6a90ae21b -r fba1ab2fa4c3 src/sv_main.cpp --- a/src/sv_main.cpp Sun Oct 24 02:01:10 2021 +0100 +++ b/src/sv_main.cpp Tue Oct 19 09:11:12 2021 -0400 @@ -145,7 +145,7 @@ static bool server_ClientMove( BYTESTREAM_s *pByteStream, bool bSentBackup ); static bool server_MissingPacket( BYTESTREAM_s *pByteStream ); static bool server_UpdateClientPing( BYTESTREAM_s *pByteStream ); -static bool server_WeaponSelect( BYTESTREAM_s *pByteStream ); +static bool server_WeaponSelect( BYTESTREAM_s *pByteStream, bool bSentBackup ); static bool server_Taunt( BYTESTREAM_s *pByteStream ); static bool server_Spectate( BYTESTREAM_s *pByteStream ); static bool server_RequestJoin( BYTESTREAM_s *pByteStream ); @@ -4766,9 +4766,10 @@ // Ping response from client. return ( server_UpdateClientPing( pByteStream )); case CLC_WEAPONSELECT: + case CLC_WEAPONSELECTBACKUP: // Client has sent a weapon change. - return ( server_WeaponSelect( pByteStream )); + return ( server_WeaponSelect( pByteStream, lCommand == CLC_WEAPONSELECTBACKUP )); case CLC_TAUNT: // Client is taunting! Broadcast it to other clients. @@ -6053,18 +6054,27 @@ //***************************************************************************** // -static bool server_WeaponSelect( BYTESTREAM_s *pByteStream ) +static bool server_WeaponSelect( BYTESTREAM_s *pByteStream, bool bSentBackup ) { // [BB] To keep weapon sync when buffering movement commands, the weapon // select commands also need to be stored in the same buffer the keep // the proper order of the commands. - return server_ParseBufferedCommand ( pByteStream ); + // [AK] Also check if this is supposed to be a backup command. + if ( bSentBackup ) + return server_ParseBufferedCommand ( pByteStream ); + else + return server_ParseBufferedCommand ( pByteStream ); } ClientWeaponSelectCommand::ClientWeaponSelectCommand ( BYTESTREAM_s *pByteStream ) // Read in the identification of the weapon the player is selecting. : usActorNetworkIndex ( pByteStream->ReadShort() ) { } +ClientBackupWeaponSelectCommand::ClientBackupWeaponSelectCommand ( BYTESTREAM_s *pByteStream ) + // [AK] Read in the gametic the client sent us. + : ulGametic ( pByteStream->ReadLong() ), ClientWeaponSelectCommand( pByteStream ) { } + + bool ClientWeaponSelectCommand::process( const ULONG ulClient ) const { const PClass *pType; @@ -6074,6 +6084,11 @@ if ( players[ulClient].mo == NULL ) return ( false ); + // [AK] CLC_WEAPONSELECTBACKUP commands should all have non-zero client gametics, + // so in these cases we'll update the gametic the client sent us with this. + if ( getClientTic( ) != 0 ) + g_aClients[ulClient].ulClientGameTic = getClientTic( ); + // Try to find the class that corresponds to the name of the weapon the client // is sending us. If it doesn't exist, or the class isn't a type of weapon, boot // them. diff -r eff6a90ae21b -r fba1ab2fa4c3 src/sv_main.h --- a/src/sv_main.h Sun Oct 24 02:01:10 2021 +0100 +++ b/src/sv_main.h Tue Oct 19 09:11:12 2021 -0400 @@ -321,6 +321,19 @@ }; //***************************************************************************** +class ClientBackupWeaponSelectCommand : public ClientWeaponSelectCommand +{ + ULONG ulGametic; +public: + ClientBackupWeaponSelectCommand ( BYTESTREAM_s *pByteStream ); + + virtual unsigned int getClientTic() const + { + return ulGametic; + } +}; + +//***************************************************************************** struct CLIENT_s { // The network address of this client.