mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Fully implemented ConVar class so we could statically construct all SDK convars, this avoids a level of indirection, and allows for creating ConVar's everywhere in the project. This patch also removed the settings tab of the ImGui server browser, as it has threading issues, while it technically never caused a crash yet, it has been removed as there was no point keeping it vs the work required to make it thread save (it only managed 2 convars which are perfectly manageable through cfg's or the in-game console). Also temporarily disabled the creation of ConVar's in the mod system due to a memory leak, we would allocate and register a convar based on details parsed out of a mod file definition, but never unregister and free it.
151 lines
4.7 KiB
C++
151 lines
4.7 KiB
C++
//===========================================================================//
|
|
//
|
|
// Purpose: server side data block sender
|
|
//
|
|
//===========================================================================//
|
|
#include "engine/client/client.h"
|
|
#include "common/proto_oob.h"
|
|
#include "datablock_sender.h"
|
|
|
|
ConVar net_compressDataBlockLzAcceleration("net_compressDataBlockLzAcceleration", "1", FCVAR_DEVELOPMENTONLY, "The acceleration value for LZ4 data block compression");
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: sends the data block
|
|
//-----------------------------------------------------------------------------
|
|
void ServerDataBlockSender::SendDataBlock(const short transferId, const int transferSize,
|
|
const short transferNr, const short blockNr, const uint8_t* const blockData, const int blockSize)
|
|
{
|
|
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);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets the resend rate
|
|
//-----------------------------------------------------------------------------
|
|
float ServerDataBlockSender::GetResendRate() const
|
|
{
|
|
const CClient* const pClient = m_pClient;
|
|
|
|
if (!pClient)
|
|
return 0.0f;
|
|
|
|
const CNetChan* const pChan = pClient->GetNetChan();
|
|
|
|
if (!pChan)
|
|
return 0.0f;
|
|
|
|
if (m_bStartedTransfer)
|
|
return 0.0f;
|
|
|
|
const float netResendRate = pChan->GetResendRate();
|
|
|
|
if (netResendRate < net_datablock_networkLossForSlowSpeed->GetFloat())
|
|
{
|
|
return m_flResendRate;
|
|
}
|
|
|
|
return netResendRate;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: gets the receiver name (client name as registered on the server)
|
|
//-----------------------------------------------------------------------------
|
|
const char* ServerDataBlockSender::GetReceiverName() const
|
|
{
|
|
return m_pClient->m_szServerName;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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),
|
|
dataSize, SNAPSHOT_SCRATCH_BUFFER_SIZE, net_compressDataBlockLzAcceleration.GetInt());
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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);
|
|
|
|
ReleaseSRWLockExclusive(&m_Lock);
|
|
}
|