# HG changeset patch # User Adam Kaminski # Date 1634649072 14400 # Tue Oct 19 09:11:12 2021 -0400 # Node ID 2ffb121bb95ffdaa3945f303688f302699fbe3ae # Parent 91eca24b9b6996e774fd8232b0187f5f0d9d5490 "cl_backupcommands" also takes care of a client's weapon select commands. diff -r 91eca24b9b69 -r 2ffb121bb95f src/cl_commands.cpp --- a/src/cl_commands.cpp Mon Oct 18 23:30:04 2021 -0400 +++ 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 91eca24b9b69 -r 2ffb121bb95f src/cl_commands.h --- a/src/cl_commands.h Mon Oct 18 23:30:04 2021 -0400 +++ 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 91eca24b9b69 -r 2ffb121bb95f src/cl_main.cpp --- a/src/cl_main.cpp Mon Oct 18 23:30:04 2021 -0400 +++ 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 91eca24b9b69 -r 2ffb121bb95f src/network_enums.h --- a/src/network_enums.h Mon Oct 18 23:30:04 2021 -0400 +++ 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 91eca24b9b69 -r 2ffb121bb95f src/sv_main.cpp --- a/src/sv_main.cpp Mon Oct 18 23:30:04 2021 -0400 +++ b/src/sv_main.cpp Tue Oct 19 09:11:12 2021 -0400 @@ -234,6 +234,9 @@ // Maximum packet size. static ULONG g_ulMaxPacketSize = 0; +// [AK] Did we just receive a CLC_WEAPONSELECTBACKUP command from a client? +static bool g_bReadingBackupWeaponSelect = false; + // List of all translations edited by level scripts. static TArray g_EditedTranslationList; @@ -4766,6 +4769,10 @@ // Ping response from client. return ( server_UpdateClientPing( pByteStream )); case CLC_WEAPONSELECT: + case CLC_WEAPONSELECTBACKUP: + + // [AK] Check if this is a backup weapon select (CLC_WEAPONSELECTBACKUP) command. + g_bReadingBackupWeaponSelect = ( lCommand == CLC_WEAPONSELECTBACKUP ); // Client has sent a weapon change. return ( server_WeaponSelect( pByteStream )); @@ -6062,8 +6069,14 @@ } ClientWeaponSelectCommand::ClientWeaponSelectCommand ( BYTESTREAM_s *pByteStream ) +{ + // [AK] If this is a backup (CLC_WEAPONSELECTBACKUP) command, then the client + // also sent us their gametic. Otherwise, the gametic should always be zero. + ulGametic = g_bReadingBackupWeaponSelect ? pByteStream->ReadLong( ) : 0; + // Read in the identification of the weapon the player is selecting. - : usActorNetworkIndex ( pByteStream->ReadShort() ) { } + usActorNetworkIndex = pByteStream->ReadShort( ); +} bool ClientWeaponSelectCommand::process( const ULONG ulClient ) const { @@ -6074,6 +6087,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 ( ulGametic != 0 ) + g_aClients[ulClient].ulClientGameTic = ulGametic; + // 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 91eca24b9b69 -r 2ffb121bb95f src/sv_main.h --- a/src/sv_main.h Mon Oct 18 23:30:04 2021 -0400 +++ b/src/sv_main.h Tue Oct 19 09:11:12 2021 -0400 @@ -313,11 +313,18 @@ //***************************************************************************** class ClientWeaponSelectCommand : public ClientCommand { - const USHORT usActorNetworkIndex; + ULONG ulGametic; + USHORT usActorNetworkIndex; + public: ClientWeaponSelectCommand ( BYTESTREAM_s *pByteStream ); bool process ( const ULONG ulClient ) const; + + virtual unsigned int getClientTic ( ) const + { + return ulGametic; + } }; //*****************************************************************************