diff --git a/r5dev/common/proto_oob.h b/r5dev/common/proto_oob.h new file mode 100644 index 00000000..b9d922a1 --- /dev/null +++ b/r5dev/common/proto_oob.h @@ -0,0 +1,45 @@ +//============ Copyright Valve Corporation, All rights reserved. ==============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( PROTO_OOB_H ) +#define PROTO_OOB_H +#ifdef _WIN32 +#pragma once +#endif + +#include "proto_version.h" + +#define PORT_RCON 37015 // default RCON port, TCP +#define PORT_SERVER 37015 // Default server port, UDP/TCP +#define PORT_CLIENT 37005 // Default client port, UDP/TCP + +// Out of band message id bytes +// Prefixes: S = server, C = client, A = any + +#define C2S_CONNECT 'A' // client requests to connect +#define S2C_DISCONNECT 'B' // server requests to disconnect + +#define C2S_CHALLENGE 'H' // + challenge value +#define S2C_CHALLENGE 'I' // + challenge value + +#define S2C_CONNACCEPT 'J' +#define S2C_CONNREJECT 'K' // special protocol for rejected connections + +// Generic Ping Request +#define A2A_PING 'L' // respond with an A2A_ACK +#define A2A_ACK 'M' // general acknowledgment without info + +#define S2C_UNKNOWN_UISCRIPT 'N' // TODO: figure out what this does, see [r5apex + 0x288880] + +// Data Block Request +#define S2C_DATABLOCK_FRAGMENT 'O' // data block fragment +#define C2S_DATABLOCK_ACK 'P' // data block fragment acknowledgment + +// All OOB packet start with this sequence +#define CONNECTIONLESS_HEADER 0xFFFFFFFF + +#endif diff --git a/r5dev/common/proto_version.h b/r5dev/common/proto_version.h new file mode 100644 index 00000000..cfc0a46f --- /dev/null +++ b/r5dev/common/proto_version.h @@ -0,0 +1,17 @@ +//============ Copyright Valve Corporation, All rights reserved. ==============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#if !defined( PROTO_VERSION_H ) +#define PROTO_VERSION_H +#ifdef _WIN32 +#pragma once +#endif + +// The current network protocol version. Changing this makes clients and servers incompatible +#define PROTOCOL_VERSION 529 + +#endif diff --git a/r5dev/engine/CMakeLists.txt b/r5dev/engine/CMakeLists.txt index acd19043..e4e1c558 100644 --- a/r5dev/engine/CMakeLists.txt +++ b/r5dev/engine/CMakeLists.txt @@ -136,6 +136,8 @@ add_sources( SOURCE_GROUP "Shared" "shared/base_rcon.h" "shared/shared_rcon.cpp" "shared/shared_rcon.h" + "shared/datablock.cpp" + "shared/datablock.h" ) if( NOT ${PROJECT_NAME} STREQUAL "engine_ds" ) @@ -207,7 +209,6 @@ add_sources( SOURCE_GROUP "Public" "${ENGINE_SOURCE_DIR}/public/dt_send.h" "${ENGINE_SOURCE_DIR}/public/dt_recv.h" "${ENGINE_SOURCE_DIR}/public/datamap.h" - "${ENGINE_SOURCE_DIR}/public/idatablock.h" "${ENGINE_SOURCE_DIR}/public/idebugoverlay.h" "${ENGINE_SOURCE_DIR}/public/iengine.h" "${ENGINE_SOURCE_DIR}/public/iserver.h" diff --git a/r5dev/engine/client/datablock_receiver.cpp b/r5dev/engine/client/datablock_receiver.cpp index 22429622..d8ae7e12 100644 --- a/r5dev/engine/client/datablock_receiver.cpp +++ b/r5dev/engine/client/datablock_receiver.cpp @@ -1,60 +1,62 @@ //===========================================================================// // -// Purpose: client side datablock receiver +// Purpose: client side data block receiver // //===========================================================================// #include "engine/client/clientstate.h" #include "datablock_receiver.h" +#include "common/proto_oob.h" #include "engine/common.h" #include "engine/host_cmd.h" -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -ClientDataBlockReceiver::~ClientDataBlockReceiver() -{ - ClientDataBlockReceiver__Destructor(this); -} - //----------------------------------------------------------------------------- // Purpose: send an ack back to the server to let them know -// we received the datablock +// we received the data block //----------------------------------------------------------------------------- void ClientDataBlockReceiver::AcknowledgeTransmission() { - ClientDataBlockReceiver__AcknowledgeTransmission(this); -} + const CClientState* const cl = m_pClientState; -//----------------------------------------------------------------------------- -// Purpose: initialize the data block receiver context -//----------------------------------------------------------------------------- -void ClientDataBlockReceiver::StartBlockReceiver(const int transferSize, const double startTime) -{ - m_bStartedRecv = true; - m_nTransferSize = transferSize; - m_nTotalBlocks = transferSize / MAX_DATABLOCK_FRAGMENT_SIZE + (transferSize % MAX_DATABLOCK_FRAGMENT_SIZE != 0); - m_nBlockAckTick = 0; - m_flStartTime = startTime; + if (!cl) + { + Assert(0, "ClientDataBlockReceiver::AcknowledgeTransmission() called without a valid client handle!"); + return; + } - memset(m_BlockStatus, 0, sizeof(m_BlockStatus)); -} + const CNetChan* const chan = cl->m_NetChannel; -//----------------------------------------------------------------------------- -// Purpose: reset the data block receiver context -//----------------------------------------------------------------------------- -void ClientDataBlockReceiver::ResetBlockReceiver(const short transferNr) -{ - m_nTransferNr = transferNr; + if (!chan) + { + Assert(0, "ClientDataBlockReceiver::AcknowledgeTransmission() called without a net channel!"); + return; + } - m_bStartedRecv = false; - m_bCompletedRecv = false; + char dataBuf[DATABLOCK_FRAGMENT_PACKET_SIZE]; + bf_write buf(&dataBuf, sizeof(dataBuf)); - m_TransferId = 0; - m_nTotalBlocks = 0; - m_nBlockAckTick = 0; - m_flStartTime = 0.0; + buf.WriteLong(CONNECTIONLESS_HEADER); + buf.WriteByte(C2S_DATABLOCK_ACK); - memset(m_BlockStatus, 0, sizeof(m_BlockStatus)); + buf.WriteShort(m_TransferId); + buf.WriteShort(m_nTransferNr); + + for (int i = m_nTotalBlocks; (i--) > 0;) + { + if (m_BlockStatus[i]) + { + // ack the last blockNr we recv'd and processed + buf.WriteShort(i); + break; + } + } + + // send the data block ack packet + v_NET_SendPacket(NULL, + chan->GetSocket(), + chan->GetRemoteAddress(), + buf.GetData(), + buf.GetNumBytesWritten(), + NULL, false, NULL, true); } //----------------------------------------------------------------------------- diff --git a/r5dev/engine/client/datablock_receiver.h b/r5dev/engine/client/datablock_receiver.h index 438157d7..cd1df700 100644 --- a/r5dev/engine/client/datablock_receiver.h +++ b/r5dev/engine/client/datablock_receiver.h @@ -1,37 +1,21 @@ +//===========================================================================// +// +// Purpose: client side data block receiver +// +//===========================================================================// #ifndef DATABLOCK_RECEIVER_H #define DATABLOCK_RECEIVER_H -#include "idatablock.h" +#include "engine/shared/datablock.h" class CClientState; class ClientDataBlockReceiver : public NetDataBlockReceiver { - friend class CClientState; public: - virtual ~ClientDataBlockReceiver(); virtual void AcknowledgeTransmission() override; - void StartBlockReceiver(const int transferSize, const double startTime); - void ResetBlockReceiver(const short transferNr); - bool ProcessDataBlock(const double startTime, const short transferId, const int transferSize, const short counter, const short currentBlockId, const void* const blockBuffer, const int blockBufferBytes); - -protected: - CClientState* m_pClientState; - bool m_bStartedRecv; - bool m_bCompletedRecv; - bool byte12; - short m_TransferId; - short m_nTransferNr; - bool m_bInitialized; - int m_nTransferSize; - int m_nTotalBlocks; - int m_nBlockAckTick; - double m_flStartTime; - - bool m_BlockStatus[MAX_DATABLOCK_FRAGMENTS]; - char* m_pScratchBuffer; }; struct ClientDataBlockHeader_s @@ -41,7 +25,6 @@ struct ClientDataBlockHeader_s }; // virtual methods -inline void*(*ClientDataBlockReceiver__Destructor)(ClientDataBlockReceiver* thisptr); inline void*(*ClientDataBlockReceiver__AcknowledgeTransmission)(ClientDataBlockReceiver* thisptr); // non-virtual methods @@ -54,16 +37,11 @@ class VClientDataBlockReceiver : public IDetour { virtual void GetAdr(void) const { - LogFunAdr("ClientDataBlockReceiver::~ClientDataBlockReceiver", ClientDataBlockReceiver__Destructor); LogFunAdr("ClientDataBlockReceiver::AcknowledgeTransmission", ClientDataBlockReceiver__AcknowledgeTransmission); LogFunAdr("ClientDataBlockReceiver::ProcessDataBlock", ClientDataBlockReceiver__ProcessDataBlock); } virtual void GetFun(void) const { - g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 8B DA 48 8B F9 E8 ?? ?? ?? ?? F6 C3 01 74" - " 0D BA ?? ?? ?? ?? 48 8B CF E8 ?? ?? ?? ?? 48 8B C7 48 8B 5C 24 ?? 48 83 C4 20 5F C3 CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24" - " ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8D 05 ?? ?? ?? ?? C6 41 12 00").GetPtr(ClientDataBlockReceiver__Destructor); - g_GameDll.FindPatternSIMD("40 53 48 81 EC ?? ?? ?? ?? 4C 8B 51 08").GetPtr(ClientDataBlockReceiver__AcknowledgeTransmission); g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 30 0F B7 44 24 ??") diff --git a/r5dev/engine/net.h b/r5dev/engine/net.h index 2a0d8637..87bce5da 100644 --- a/r5dev/engine/net.h +++ b/r5dev/engine/net.h @@ -22,10 +22,16 @@ constexpr const char* DEFAULT_NET_ENCRYPTION_KEY = "WDNWLmJYQ2ZlM0VoTid3Yg=="; inline void*(*v_NET_Init)(bool bDeveloper); inline void(*v_NET_SetKey)(netkey_t* pKey, const char* szHash); inline void(*v_NET_Config)(void); + +inline int(*v_NET_GetPacket)(int iSocket, uint8_t* pScratch, bool bEncrypted); +inline int(*v_NET_SendPacket)(CNetChan* pChan, int iSocket, const netadr_t& toAdr, const uint8_t* pData, unsigned int nLen, void* unused0, bool bCompress, void* unused1, bool bEncrypt); + inline bool(*v_NET_ReceiveDatagram)(int iSocket, netpacket_s* pInpacket, bool bRaw); inline int(*v_NET_SendDatagram)(SOCKET s, void* pPayload, int iLenght, netadr_t* pAdr, bool bEncrypted); + inline bool(*v_NET_BufferToBufferCompress)(uint8_t* const dest, size_t* const destLen, uint8_t* const source, const size_t sourceLen); inline unsigned int(*v_NET_BufferToBufferDecompress_LZSS)(CLZSS* lzss, unsigned char* pInput, unsigned char* pOutput, unsigned int unBufSize); + inline void(*v_NET_PrintFunc)(const char* fmt, ...); /////////////////////////////////////////////////////////////////////////////// @@ -57,10 +63,16 @@ class VNet : public IDetour LogFunAdr("NET_Init", v_NET_Init); LogFunAdr("NET_Config", v_NET_Config); LogFunAdr("NET_SetKey", v_NET_SetKey); + + LogFunAdr("NET_GetPacket", v_NET_GetPacket); + LogFunAdr("NET_SendPacket", v_NET_SendPacket); + LogFunAdr("NET_ReceiveDatagram", v_NET_ReceiveDatagram); LogFunAdr("NET_SendDatagram", v_NET_SendDatagram); + LogFunAdr("NET_BufferToBufferCompress", v_NET_BufferToBufferCompress); LogFunAdr("NET_BufferToBufferDecompress_LZSS", v_NET_BufferToBufferDecompress_LZSS); + LogFunAdr("NET_PrintFunc", v_NET_PrintFunc); LogVarAdr("g_NetAdr", g_pNetAdr); LogVarAdr("g_NetKey", g_pNetKey); @@ -71,6 +83,11 @@ class VNet : public IDetour g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 81 EC F0 01 ??").GetPtr(v_NET_Init); g_GameDll.FindPatternSIMD("48 81 EC ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 3D ?? ?? ?? ?? ?? 0F 57 C0").GetPtr(v_NET_Config); g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 20 48 8B F9 41 B8").GetPtr(v_NET_SetKey); + + + g_GameDll.FindPatternSIMD("48 8B C4 44 88 40 18 48 89 50 10 41 55").GetPtr(v_NET_GetPacket); + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 48 89 74 24 ?? 55 57 41 55 41 56 41 57 48 8D AC 24 ?? ?? ?? ?? B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 48 2B E0 4C 63 F2").GetPtr(v_NET_SendPacket); + g_GameDll.FindPatternSIMD("48 89 74 24 18 48 89 7C 24 20 55 41 54 41 55 41 56 41 57 48 8D AC 24 50 EB").GetPtr(v_NET_ReceiveDatagram); g_GameDll.FindPatternSIMD("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 41 56 41 57 48 81 EC ?? 05 ?? ??").GetPtr(v_NET_SendDatagram); diff --git a/r5dev/engine/server/datablock_sender.cpp b/r5dev/engine/server/datablock_sender.cpp index e09e2dd0..1435054e 100644 --- a/r5dev/engine/server/datablock_sender.cpp +++ b/r5dev/engine/server/datablock_sender.cpp @@ -1,27 +1,60 @@ //===========================================================================// // -// Purpose: server side datablock sender +// Purpose: server side data block sender // //===========================================================================// #include "engine/client/client.h" +#include "common/proto_oob.h" #include "datablock_sender.h" //----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -ServerDataBlockSender::~ServerDataBlockSender() -{ - ServerDataBlockSender__Destructor(this); -} - -//----------------------------------------------------------------------------- -// Purpose: sends the datablock +// 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) { - ServerDataBlockSender__SendDataBlock(this, transferId, transferSize, - transferNr, blockNr, blockData, 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); } //----------------------------------------------------------------------------- @@ -60,72 +93,6 @@ const char* ServerDataBlockSender::GetReceiverName() const return m_pClient->m_szServerName; } -//----------------------------------------------------------------------------- -// Purpose: initialize the data block sender context -//----------------------------------------------------------------------------- -void ServerDataBlockSender::StartBlockSender(const int transferSize, const bool isMultiplayer, const char* const debugName) -{ - m_bMultiplayer = isMultiplayer; - m_nBlockAckTick = 0; - m_nTransferSize = transferSize + sizeof(ServerDataBlockHeader_s); - - // calculate the number of data blocks we have, which get sent individually - // to the receiver - m_nTotalBlocks = m_nTransferSize / MAX_DATABLOCK_FRAGMENT_SIZE + (m_nTransferSize % MAX_DATABLOCK_FRAGMENT_SIZE != 0); - - strncpy(m_szDebugName, debugName, sizeof(m_szDebugName)); - m_szDebugName[sizeof(m_szDebugName) - 1] = '\0'; - - // null status memory - memset(m_bBlockAckStatus, 0, sizeof(m_bBlockAckStatus)); - memset(m_flBlockSendTimes, 0, sizeof(m_flBlockSendTimes)); - - m_bInitialized = true; - m_bStartedTransfer = false; - - const double currentTime = Plat_FloatTime(); - - m_TimeLastSend = currentTime; - m_TimeCurrentSend = currentTime; - m_TimeFirstSend = currentTime; - - m_nTotalSizeRemaining = 4096; - m_nBlockSendsAttempted = 0; -} - -//----------------------------------------------------------------------------- -// Purpose: reset the data block sender context -//----------------------------------------------------------------------------- -void ServerDataBlockSender::ResetBlockSender(void) -{ - if (!m_bInitialized) - return; - - m_bInitialized = false; - m_bStartedTransfer = false; - - m_nTransferId = 0; - m_nTransferSize = 0; - m_nTotalBlocks = 0; - m_nBlockAckTick = 0; - - m_TimeCurrentSend = 0.0; - m_TimeFirstSend = 0.0; - - m_nTotalSizeRemaining = 0; - - m_TimeLastSend = 0.0; - m_szDebugName[0] = '\0'; - m_bDumbDataBlockInfo = false; - m_nCurrentBlock = -1; - m_nBlockSendsAttempted = 0; - - memset(m_bBlockAckStatus, 0, sizeof(m_bBlockAckStatus)); - memset(m_flBlockSendTimes, 0, sizeof(m_flBlockSendTimes)); - - m_nTransferNr++; -} - //----------------------------------------------------------------------------- // Purpose: write the whole data in the data block scratch buffer //----------------------------------------------------------------------------- @@ -172,8 +139,10 @@ void ServerDataBlockSender::WriteDataBlock(const uint8_t* const sourceData, cons memcpy(m_pScratchBuffer + sizeof(ServerDataBlockHeader_s), sourceData, actualDataSize); } - // create the context - StartBlockSender(actualDataSize, isMultiplayer, debugName); + // 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); } diff --git a/r5dev/engine/server/datablock_sender.h b/r5dev/engine/server/datablock_sender.h index 00aabdb5..29f505a9 100644 --- a/r5dev/engine/server/datablock_sender.h +++ b/r5dev/engine/server/datablock_sender.h @@ -1,83 +1,24 @@ +//===========================================================================// +// +// Purpose: server side data block sender +// +//===========================================================================// #ifndef DATABLOCK_SENDER_H #define DATABLOCK_SENDER_H -#include "idatablock.h" +#include "engine/shared/datablock.h" class CClient; class ServerDataBlockSender : public NetDataBlockSender { - friend class CClient; public: - virtual ~ServerDataBlockSender() override; virtual void SendDataBlock(const short transferId, const int transferSize, const short transferNr, const short blockNr, const uint8_t* const blockData, const int blockSize) override; virtual float GetResendRate() const override; virtual const char* GetReceiverName() const override; - void StartBlockSender(const int transferSize, const bool isMultiplayer, const char* const debugName); - void ResetBlockSender(); - void WriteDataBlock(const uint8_t* const sourceData, const int dataSize, const bool isMultiplayer, const char* const debugName); - -protected: - char pad_0008[56]; - RTL_SRWLOCK m_Lock; - char pad_0048[56]; - - // the server side client handle that is our 'receiving' end - CClient* m_pClient; - - char m_bInitialized; - char m_bStartedTransfer; - - char m_bMultiplayer; - char field_8B; - - // the current transfer id, and the global transfer count for this - // particular client. the transfer nr keeps getting incremented on - // each new context setup - short m_nTransferId; - short m_nTransferNr; - - // the total transfer size for the data, and the number of blocks this data - // has been carved up to - int m_nTransferSize; - int m_nTotalBlocks; - - // last block that has been ack'd, and the current block that is pending to - // be sent to the receiver - int m_nBlockAckTick; - int m_nCurrentBlock; - - // the total number of bytes remaining to be sent, and the number of times - // we attempted to send data blocks - int m_nTotalSizeRemaining; - int m_nBlockSendsAttempted; - - // the resend rate for this connection, which depends of the stability/loss - // and other factors computed from the netchan - float m_flResendRate; - char pad_00AC[4]; // padding, in case we want to stuff our own vars in here - - // times used to determine when a data block has been sent, and how long it - // took to get this out and acknowledged - double m_TimeCurrentSend; - double m_TimeFirstSend; - double m_TimeLastSend; - - // the last time we attempted to send this block, this gets updated when - // a data block hasn't been acknowledged in time and is being resent - double m_flBlockSendTimes[MAX_DATABLOCK_FRAGMENTS]; - - // the debug name used when details get dumped to the console - char m_szDebugName[MAX_DATABLOCK_DEBUG_NAME]; - - // if a data block has been acknowledged by the receiver, we mark that - // particular block as acknowledged - bool m_bBlockAckStatus[MAX_DATABLOCK_FRAGMENTS]; - uint8_t* m_pScratchBuffer; - bool m_bDumbDataBlockInfo; }; struct ServerDataBlock @@ -93,7 +34,6 @@ struct ServerDataBlockHeader_s bool isCompressed; }; -inline void*(*ServerDataBlockSender__Destructor)(ServerDataBlockSender* thisptr); inline void* (*ServerDataBlockSender__SendDataBlock)(ServerDataBlockSender* thisptr, const short transferId, const int transferSize, const short transferNr, const short blockNr, const uint8_t* const blockData, const int blockSize); @@ -103,15 +43,10 @@ class VServerDataBlockSender : public IDetour { virtual void GetAdr(void) const { - LogFunAdr("ServerDataBlockSender::~ServerDataBlockSender", ServerDataBlockSender__Destructor); LogFunAdr("ServerDataBlockSender::SendDataBlock", ServerDataBlockSender__SendDataBlock); } virtual void GetFun(void) const { - g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 8B DA 48 8B F9 E8 ?? ?? ?? ?? F6 C3 01 74" - " 0D BA ?? ?? ?? ?? 48 8B CF E8 ?? ?? ?? ?? 48 8B C7 48 8B 5C 24 ?? 48 83 C4 20 5F C3 CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24" - " ?? 48 89 74 24 ?? 57 48 83 EC 20 33 F6 66 C7 81 ?? ?? ?? ?? ?? ??").GetPtr(ServerDataBlockSender__Destructor); - g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 55 48 8D AC 24 ?? ?? ?? ?? 48 81 EC ?? ?? ?? ?? 48 8B 99 ?? ?? ?? ??").GetPtr(ServerDataBlockSender__SendDataBlock); } virtual void GetVar(void) const { } diff --git a/r5dev/engine/shared/datablock.cpp b/r5dev/engine/shared/datablock.cpp new file mode 100644 index 00000000..52c3dfc0 --- /dev/null +++ b/r5dev/engine/shared/datablock.cpp @@ -0,0 +1,112 @@ +//===========================================================================// +// +// Purpose: data block sender & receiver +// +//===========================================================================// +#include "datablock.h" + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +NetDataBlockSender::~NetDataBlockSender() +{ + ResetBlockSender(); + + delete[] m_pScratchBuffer; + m_pScratchBuffer = nullptr; + + m_pClient = nullptr; +} + +//----------------------------------------------------------------------------- +// Purpose: reset the data block sender context +//----------------------------------------------------------------------------- +void NetDataBlockSender::ResetBlockSender(void) +{ + m_bInitialized = false; + m_bStartedTransfer = false; + + m_nTransferId = 0; + m_nTransferSize = 0; + m_nTotalBlocks = 0; + m_nBlockAckTick = 0; + + m_TimeCurrentSend = 0.0; + m_TimeFirstSend = 0.0; + + m_nTotalSizeRemaining = 0; + + m_TimeLastSend = 0.0; + m_szDebugName[0] = '\0'; + m_bDumbDataBlockInfo = false; + m_nCurrentBlock = DATABLOCK_INVALID_BLOCK_NR; + m_nBlockSendsAttempted = 0; + + memset(m_bBlockAckStatus, 0, sizeof(m_bBlockAckStatus)); + memset(m_flBlockSendTimes, 0, sizeof(m_flBlockSendTimes)); +} + +//----------------------------------------------------------------------------- +// Purpose: initialize the data block sender context +//----------------------------------------------------------------------------- +void NetDataBlockSender::StartBlockSender(const int transferSize, const bool isMultiplayer, const char* const debugName) +{ + m_bMultiplayer = isMultiplayer; + m_nBlockAckTick = 0; + m_nTransferSize = transferSize; + + // calculate the number of data blocks we have, which get sent individually + // to the receiver + m_nTotalBlocks = m_nTransferSize / MAX_DATABLOCK_FRAGMENT_SIZE + (m_nTransferSize % MAX_DATABLOCK_FRAGMENT_SIZE != 0); + + strncpy(m_szDebugName, debugName, sizeof(m_szDebugName)); + m_szDebugName[sizeof(m_szDebugName) - 1] = '\0'; + + // null status memory + memset(m_bBlockAckStatus, 0, sizeof(m_bBlockAckStatus)); + memset(m_flBlockSendTimes, 0, sizeof(m_flBlockSendTimes)); + + m_bInitialized = true; + m_bStartedTransfer = false; + + const double currentTime = Plat_FloatTime(); + + m_TimeLastSend = currentTime; + m_TimeCurrentSend = currentTime; + m_TimeFirstSend = currentTime; + + m_nTotalSizeRemaining = 4096; + m_nBlockSendsAttempted = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: initialize the data block receiver context +//----------------------------------------------------------------------------- +void NetDataBlockReceiver::StartBlockReceiver(const int transferSize, const double startTime) +{ + m_bStartedRecv = true; + m_nTransferSize = transferSize; + m_nTotalBlocks = transferSize / MAX_DATABLOCK_FRAGMENT_SIZE + (transferSize % MAX_DATABLOCK_FRAGMENT_SIZE != 0); + m_nBlockAckTick = 0; + m_flStartTime = startTime; + + memset(m_BlockStatus, 0, sizeof(m_BlockStatus)); +} + +//----------------------------------------------------------------------------- +// Purpose: reset the data block receiver context +//----------------------------------------------------------------------------- +void NetDataBlockReceiver::ResetBlockReceiver(const short transferNr) +{ + m_nTransferNr = transferNr; + + m_bStartedRecv = false; + m_bCompletedRecv = false; + + m_TransferId = 0; + m_nTotalBlocks = 0; + m_nBlockAckTick = 0; + m_flStartTime = 0.0; + + memset(m_BlockStatus, 0, sizeof(m_BlockStatus)); +} diff --git a/r5dev/engine/shared/datablock.h b/r5dev/engine/shared/datablock.h new file mode 100644 index 00000000..1c10a739 --- /dev/null +++ b/r5dev/engine/shared/datablock.h @@ -0,0 +1,173 @@ +//===========================================================================// +// +// Purpose: data block sender & receiver +// +//===========================================================================// +#ifndef IDATABLOCK_H +#define IDATABLOCK_H + +// the maximum size of each data block fragment +#define MAX_DATABLOCK_FRAGMENT_SIZE 1024 + +// the maximum amount of fragments per data block +#define MAX_DATABLOCK_FRAGMENTS 768 + +#define DATABLOCK_DEBUG_NAME_LEN 64 +#define DATABLOCK_INVALID_BLOCK_NR -1 + +// the maximum size of a data block fragment packet (encoded header + actual data) +#define DATABLOCK_FRAGMENT_PACKET_SIZE (MAX_DATABLOCK_FRAGMENT_SIZE + 176) + +//----------------------------------------------------------------------------- +// Forward decelerations +//----------------------------------------------------------------------------- +class CClient; +class CClientState; + +abstract_class NetDataBlockSender +{ +public: + virtual ~NetDataBlockSender(); + + + virtual void SendDataBlock(const short transferId, const int transferSize, + const short transferNr, const short blockNr, const uint8_t* const blockData, const int blockSize) = 0; + virtual float GetResendRate() const = 0; + virtual const char* GetReceiverName() const = 0; + + void StartBlockSender(const int transferSize, const bool isMultiplayer, const char* const debugName); + void ResetBlockSender(); + +protected: + char pad_0008[56]; + RTL_SRWLOCK m_Lock; + char pad_0048[56]; + + // the server side client handle that is our 'receiving' end + CClient* m_pClient; + + char m_bInitialized; + char m_bStartedTransfer; + + char m_bMultiplayer; + char field_8B; + + // the current transfer id, and the global transfer count for this + // particular client. the transfer nr keeps getting incremented on + // each new context setup + short m_nTransferId; + short m_nTransferNr; + + // the total transfer size for the data, and the number of blocks this data + // has been carved up to + int m_nTransferSize; + int m_nTotalBlocks; + + // last block that has been ack'd, and the current block that is pending to + // be sent to the receiver + int m_nBlockAckTick; + int m_nCurrentBlock; + + // the total number of bytes remaining to be sent, and the number of times + // we attempted to send data blocks + int m_nTotalSizeRemaining; + int m_nBlockSendsAttempted; + + // the resend rate for this connection, which depends of the stability/loss + // and other factors computed from the netchan + float m_flResendRate; + char pad_00AC[4]; // padding, in case we want to stuff our own vars in here + + // times used to determine when a data block has been sent, and how long it + // took to get this out and acknowledged + double m_TimeCurrentSend; + double m_TimeFirstSend; + double m_TimeLastSend; + + // the last time we attempted to send this block, this gets updated when + // a data block hasn't been acknowledged in time and is being resent + double m_flBlockSendTimes[MAX_DATABLOCK_FRAGMENTS]; + + // the debug name used when details get dumped to the console + char m_szDebugName[DATABLOCK_DEBUG_NAME_LEN]; + + // if a data block has been acknowledged by the receiver, we mark that + // particular block as acknowledged + bool m_bBlockAckStatus[MAX_DATABLOCK_FRAGMENTS]; + uint8_t* m_pScratchBuffer; + bool m_bDumbDataBlockInfo; +}; + +abstract_class NetDataBlockReceiver +{ +public: + virtual ~NetDataBlockReceiver() {}; + // Called when cvar 'net_debugDataBlockReceiver' is set; + // currently a nullsub in the engine. + virtual void DebugDataBlockReceiver() {}; + virtual void AcknowledgeTransmission() = 0; + + void StartBlockReceiver(const int transferSize, const double startTime); + void ResetBlockReceiver(const short transferNr); + +protected: + // the client side 'client' handle + CClientState* m_pClientState; + + // whether the transfer has been started and completed + bool m_bStartedRecv; + bool m_bCompletedRecv; + + bool byte12; + + // the current transfer id, and the global transfer count for this + // particular client. the transfer nr keeps getting incremented on + // each new context setup + short m_TransferId; + short m_nTransferNr; + + bool m_bInitialized; + + // the total transfer size, and the # amount of blocks the data has been + // carved into + int m_nTransferSize; + int m_nTotalBlocks; + + int m_nBlockAckTick; + + // the time the data block receiver was started for this transfer + double m_flStartTime; + + // if we successfully processed a data block, we mark it as processed + bool m_BlockStatus[MAX_DATABLOCK_FRAGMENTS]; + char* m_pScratchBuffer; +}; + +inline void* (*NetDataBlockSender__Destructor)(NetDataBlockSender* thisptr); +inline void* (*NetDataBlockReceiver__Destructor)(NetDataBlockReceiver* thisptr); + +/////////////////////////////////////////////////////////////////////////////// +class VNetDataBlock : public IDetour +{ + virtual void GetAdr(void) const + { + LogFunAdr("NetDataBlockSender::~NetDataBlockSender", NetDataBlockSender__Destructor); + LogFunAdr("NetDataBlockReceiver::~NetDataBlockReceiver", NetDataBlockReceiver__Destructor); + } + virtual void GetFun(void) const + { + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 8B DA 48 8B F9 E8 ?? ?? ?? ?? F6 C3 01 74" + " 0D BA ?? ?? ?? ?? 48 8B CF E8 ?? ?? ?? ?? 48 8B C7 48 8B 5C 24 ?? 48 83 C4 20 5F C3 CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24" + " ?? 48 89 74 24 ?? 57 48 83 EC 20 33 F6 66 C7 81 ?? ?? ?? ?? ?? ??").GetPtr(NetDataBlockSender__Destructor); + + g_GameDll.FindPatternSIMD("48 89 5C 24 ?? 57 48 83 EC 20 8B DA 48 8B F9 E8 ?? ?? ?? ?? F6 C3 01 74" + " 0D BA ?? ?? ?? ?? 48 8B CF E8 ?? ?? ?? ?? 48 8B C7 48 8B 5C 24 ?? 48 83 C4 20 5F C3 CC CC CC CC CC CC CC CC CC CC CC CC 48 89 5C 24" + " ?? 48 89 74 24 ?? 57 48 83 EC 20 48 8D 05 ?? ?? ?? ?? C6 41 12 00").GetPtr(NetDataBlockReceiver__Destructor); + } + virtual void GetVar(void) const { } + virtual void GetCon(void) const { } + virtual void Detour(const bool bAttach) const { } +}; +/////////////////////////////////////////////////////////////////////////////// + +#endif // IDATABLOCK_H diff --git a/r5dev/public/idatablock.h b/r5dev/public/idatablock.h deleted file mode 100644 index d213f103..00000000 --- a/r5dev/public/idatablock.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef IDATABLOCK_H -#define IDATABLOCK_H - -// the maximum size of each data block fragment -#define MAX_DATABLOCK_FRAGMENT_SIZE 1024 - -// the maximum amount of fragments per data block -#define MAX_DATABLOCK_FRAGMENTS 768 - -#define MAX_DATABLOCK_DEBUG_NAME 64 - -abstract_class NetDataBlockSender -{ -public: - virtual ~NetDataBlockSender() {}; - virtual void SendDataBlock(const short transferId, const int transferSize, - const short transferNr, const short blockNr, const uint8_t* const blockData, const int blockSize) = 0; - virtual float GetResendRate() const = 0; - virtual const char* GetReceiverName() const = 0; -}; - -abstract_class NetDataBlockReceiver -{ -public: - virtual ~NetDataBlockReceiver() {}; - // Called when cvar 'net_debugDataBlockReceiver' is set; - // currently a nullsub in the engine. - virtual void DebugDataBlockReceiver() {}; - virtual void AcknowledgeTransmission() = 0; -}; - -#endif // IDATABLOCK_H