2023-06-22 00:33:00 +02:00
//===========================================================================//
//
2024-04-05 18:06:36 +02:00
// Purpose: server side data block sender
2023-06-22 00:33:00 +02:00
//
//===========================================================================//
# include "engine/client/client.h"
2024-04-05 18:06:36 +02:00
# include "common/proto_oob.h"
2023-06-22 00:33:00 +02:00
# include "datablock_sender.h"
2024-02-24 02:15:09 +01:00
ConVar net_compressDataBlockLzAcceleration ( " net_compressDataBlockLzAcceleration " , " 1 " , FCVAR_DEVELOPMENTONLY , " The acceleration value for LZ4 data block compression " ) ;
2023-06-22 00:33:00 +02:00
//-----------------------------------------------------------------------------
2024-04-05 18:06:36 +02:00
// Purpose: sends the data block
2023-06-22 00:33:00 +02:00
//-----------------------------------------------------------------------------
2024-02-19 19:29:47 +01:00
void ServerDataBlockSender : : SendDataBlock ( const short transferId , const int transferSize ,
const short transferNr , const short blockNr , const uint8_t * const blockData , const int blockSize )
2023-06-22 00:33:00 +02:00
{
2024-04-05 18:06:36 +02:00
const CClient * const cl = m_pClient ;
if ( ! cl )
{
Assert ( 0 , " ServerDataBlockSender::SendDataBlock() called without a valid client handle! " ) ;
return ;
}
const CNetChan * const chan = cl - > m_NetChannel ;
if ( ! chan )
{
Assert ( 0 , " ServerDataBlockSender::SendDataBlock() called without a valid net channel! " ) ;
return ;
}
char dataBuf [ DATABLOCK_FRAGMENT_PACKET_SIZE ] ;
bf_write buf ( & dataBuf , sizeof ( dataBuf ) ) ;
// msg data (gets processed on client's out of band packet handler)
buf . WriteLong ( CONNECTIONLESS_HEADER ) ;
buf . WriteByte ( S2C_DATABLOCK_FRAGMENT ) ;
// transfer info
buf . WriteByte ( transferId ) ;
buf . WriteLong ( transferSize ) ;
buf . WriteByte ( transferNr ) ;
// block info
buf . WriteByte ( blockNr ) ;
buf . WriteLong ( blockSize ) ;
// block data
buf . WriteBytes ( blockData , blockSize ) ;
// send the data block packet
v_NET_SendPacket ( NULL ,
chan - > GetSocket ( ) ,
chan - > GetRemoteAddress ( ) ,
buf . GetData ( ) ,
buf . GetNumBytesWritten ( ) ,
NULL , false , NULL , true ) ;
2023-06-22 00:33:00 +02:00
}
//-----------------------------------------------------------------------------
// Purpose: gets the resend rate
//-----------------------------------------------------------------------------
float ServerDataBlockSender : : GetResendRate ( ) const
{
2024-02-19 19:29:47 +01:00
const CClient * const pClient = m_pClient ;
2023-06-22 00:33:00 +02:00
2024-02-19 19:29:47 +01:00
if ( ! pClient )
return 0.0f ;
const CNetChan * const pChan = pClient - > GetNetChan ( ) ;
2023-06-22 00:33:00 +02:00
if ( ! pChan )
2024-02-19 19:29:47 +01:00
return 0.0f ;
2023-06-22 00:33:00 +02:00
2024-02-19 19:29:47 +01:00
if ( m_bStartedTransfer )
return 0.0f ;
const float netResendRate = pChan - > GetResendRate ( ) ;
2023-06-22 00:33:00 +02:00
2024-02-19 19:29:47 +01:00
if ( netResendRate < net_datablock_networkLossForSlowSpeed - > GetFloat ( ) )
{
return m_flResendRate ;
2023-06-22 00:33:00 +02:00
}
2024-02-19 19:29:47 +01:00
return netResendRate ;
2023-06-22 00:33:00 +02:00
}
//-----------------------------------------------------------------------------
// Purpose: gets the receiver name (client name as registered on the server)
//-----------------------------------------------------------------------------
const char * ServerDataBlockSender : : GetReceiverName ( ) const
{
return m_pClient - > m_szServerName ;
}
2024-02-19 19:29:47 +01:00
//-----------------------------------------------------------------------------
// Purpose: write the whole data in the data block scratch buffer
//-----------------------------------------------------------------------------
void ServerDataBlockSender : : WriteDataBlock ( const uint8_t * const sourceData , const int dataSize ,
const bool isMultiplayer , const char * const debugName )
{
AcquireSRWLockExclusive ( & m_Lock ) ;
ServerDataBlockHeader_s * const pHeader = reinterpret_cast < ServerDataBlockHeader_s * > ( m_pScratchBuffer ) ;
bool copyRaw = true ;
int actualDataSize = dataSize ;
if ( net_compressDataBlock - > GetBool ( ) )
{
const int encodedSize = LZ4_compress_fast ( ( const char * ) sourceData , ( char * ) m_pScratchBuffer + sizeof ( ServerDataBlockHeader_s ) ,
2024-02-24 02:15:09 +01:00
dataSize , SNAPSHOT_SCRATCH_BUFFER_SIZE , net_compressDataBlockLzAcceleration . GetInt ( ) ) ;
2024-02-19 19:29:47 +01:00
// this shouldn't happen at all
if ( ! encodedSize )
{
Assert ( 0 ) ;
Error ( eDLL_T : : SERVER , 0 , " LZ4 error compressing data block for client. \n " ) ;
}
// make sure the encoded data is smaller than the raw data, in some cases
// this might turn larger which means we should just send raw data
else if ( encodedSize < dataSize )
{
actualDataSize = encodedSize ;
pHeader - > isCompressed = true ;
copyRaw = false ;
}
}
// in case no compression was performed, we send the raw data
if ( copyRaw )
{
// this should equal the dataSize at this point, even if compression failed
Assert ( actualDataSize = = dataSize ) ;
pHeader - > isCompressed = false ;
memcpy ( m_pScratchBuffer + sizeof ( ServerDataBlockHeader_s ) , sourceData , actualDataSize ) ;
}
2024-04-05 18:06:36 +02:00
// NOTE: we copy data in the scratch buffer with an offset of
// sizeof(ServerDataBlockHeader_s), the header gets send up as well so we
// have to take this into account !!!
StartBlockSender ( actualDataSize + sizeof ( ServerDataBlockHeader_s ) , isMultiplayer , debugName ) ;
2024-02-19 19:29:47 +01:00
ReleaseSRWLockExclusive ( & m_Lock ) ;
}