Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

557 lines
18 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #ifndef NETMESSAGES_H
  7. #define NETMESSAGES_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #pragma warning(disable : 4100) // unreferenced formal parameter
  11. #endif
  12. #include <inetmessage.h>
  13. #include <checksum_crc.h>
  14. #include <checksum_md5.h>
  15. #include <const.h>
  16. #include <utlvector.h>
  17. #include "qlimits.h"
  18. #include "mathlib/vector.h"
  19. #include <soundflags.h>
  20. #include <bitbuf.h>
  21. #include <inetchannel.h>
  22. #include "protocol.h"
  23. #include <inetmsghandler.h>
  24. #include <igameevents.h>
  25. #include <bitvec.h>
  26. #include "networksystem/inetworksystem.h"
  27. #include <engine/iserverplugin.h>
  28. #include <color.h>
  29. #include <tier0/tslist.h>
  30. #include <tier1/utldelegate.h>
  31. #include "tier1/utlstring.h"
  32. #include "tier1/tokenset.h"
  33. #include "netmessages_signon.h"
  34. // eliminates a conflict with TYPE_BOOL in OSX
  35. #ifdef TYPE_BOOL
  36. #undef TYPE_BOOL
  37. #endif
  38. #include "netmessages.pb.h"
  39. #if !defined( _X360 )
  40. #include "xbox/xboxstubs.h"
  41. #endif
  42. template< int msgType, typename PB_OBJECT_TYPE, int groupType = INetChannelInfo::GENERIC, bool bReliable = true >
  43. class CNetMessagePB : public INetMessage, public PB_OBJECT_TYPE
  44. {
  45. public:
  46. typedef CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType, bReliable > MyType_t;
  47. typedef PB_OBJECT_TYPE PBType_t;
  48. static const int sk_Type = msgType;
  49. CNetMessagePB() :
  50. m_bReliable( bReliable )
  51. {
  52. }
  53. virtual ~CNetMessagePB()
  54. {
  55. }
  56. virtual bool ReadFromBuffer( bf_read &buffer )
  57. {
  58. int size = buffer.ReadVarInt32();
  59. if ( size < 0 || size > NET_MAX_PAYLOAD )
  60. {
  61. return false;
  62. }
  63. // Check its valid
  64. if ( size > buffer.GetNumBytesLeft() )
  65. {
  66. return false;
  67. }
  68. // If the read buffer is byte aligned, we can parse right out of it
  69. if ( ( buffer.GetNumBitsRead() % 8 ) == 0 )
  70. {
  71. bool parseResult = PB_OBJECT_TYPE::ParseFromArray( buffer.GetBasePointer() + buffer.GetNumBytesRead(), size );
  72. buffer.SeekRelative( size * 8 );
  73. return parseResult;
  74. }
  75. // otherwise we have to do a temp allocation so we can read it all shifted
  76. #ifdef NET_SHOW_UNALIGNED_MSGS
  77. DevMsg("Warning: unaligned read of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size );
  78. #endif
  79. void *parseBuffer = stackalloc( size );
  80. if ( !buffer.ReadBytes( parseBuffer, size ) )
  81. {
  82. return false;
  83. }
  84. if ( ! PB_OBJECT_TYPE::ParseFromArray( parseBuffer, size ) )
  85. {
  86. return false;
  87. }
  88. return true;
  89. }
  90. virtual bool WriteToBuffer( bf_write &buffer ) const
  91. {
  92. if ( !PB_OBJECT_TYPE::IsInitialized() )
  93. {
  94. Msg("WriteToBuffer Message %s is not initialized! Probably missing required fields!\n", PB_OBJECT_TYPE::GetTypeName().c_str() );
  95. }
  96. int size = PB_OBJECT_TYPE::ByteSize();
  97. // If the write is byte aligned we can go direct
  98. if ( ( buffer.GetNumBitsWritten() % 8 ) == 0 )
  99. {
  100. int sizeWithHeader = size + 1 + buffer.ByteSizeVarInt32( GetType() ) + buffer.ByteSizeVarInt32( size );
  101. if ( buffer.GetNumBytesLeft() >= sizeWithHeader )
  102. {
  103. buffer.WriteVarInt32( GetType() );
  104. buffer.WriteVarInt32( size );
  105. if ( !PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )buffer.GetData() + buffer.GetNumBytesWritten() ) )
  106. {
  107. return false;
  108. }
  109. // Tell the buffer we just splatted into it
  110. buffer.SeekToBit( buffer.GetNumBitsWritten() + ( size * 8 ) );
  111. return true;
  112. }
  113. // Won't fit
  114. return false;
  115. }
  116. // otherwise we have to do a temp allocation so we can write it all shifted
  117. #ifdef NET_SHOW_UNALIGNED_MSGS
  118. DevMsg("Warning: unaligned write of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size );
  119. #endif
  120. void *serializeBuffer = stackalloc( size );
  121. if ( ! PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )serializeBuffer ) )
  122. {
  123. return false;
  124. }
  125. buffer.WriteVarInt32( GetType() );
  126. buffer.WriteVarInt32( size );
  127. return buffer.WriteBytes( serializeBuffer, size );
  128. }
  129. virtual const char *ToString() const
  130. {
  131. m_toString = PB_OBJECT_TYPE::DebugString();
  132. return m_toString.c_str();
  133. }
  134. virtual int GetType() const
  135. {
  136. return msgType;
  137. }
  138. virtual size_t GetSize() const
  139. {
  140. return sizeof( *this );
  141. }
  142. virtual const char *GetName() const
  143. {
  144. if ( s_typeName.empty() )
  145. {
  146. s_typeName = PB_OBJECT_TYPE::GetTypeName();
  147. }
  148. return s_typeName.c_str();
  149. }
  150. virtual int GetGroup() const
  151. {
  152. return groupType;
  153. }
  154. virtual void SetReliable( bool state )
  155. {
  156. m_bReliable = state;
  157. }
  158. virtual bool IsReliable() const
  159. {
  160. return m_bReliable;
  161. }
  162. virtual INetMessage *Clone() const
  163. {
  164. MyType_t *pClone = new MyType_t;
  165. pClone->CopyFrom( *this );
  166. pClone->m_bReliable = m_bReliable;
  167. return pClone;
  168. }
  169. protected:
  170. bool m_bReliable; // true if message should be sent reliable
  171. mutable std::string m_toString; // cached copy of ToString()
  172. static std::string s_typeName;
  173. };
  174. template< int msgType, typename PB_OBJECT_TYPE, int groupType , bool bReliable >
  175. std::string CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType , bReliable >::s_typeName;
  176. class CNetMessageBinder
  177. {
  178. public:
  179. CNetMessageBinder()
  180. : m_pBind( NULL )
  181. {
  182. }
  183. ~CNetMessageBinder()
  184. {
  185. delete m_pBind;
  186. }
  187. template< class _N >
  188. void Bind( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler )
  189. {
  190. delete m_pBind;
  191. m_pBind = new BindParams<_N>( pNetChannel, handler );
  192. }
  193. void Unbind()
  194. {
  195. delete m_pBind;
  196. m_pBind = NULL;
  197. }
  198. bool IsBound() const
  199. {
  200. return m_pBind != NULL;
  201. }
  202. private:
  203. template < class _N >
  204. struct BindParams : public INetMessageBinder
  205. {
  206. BindParams( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler )
  207. : m_NetChannel( pNetChannel )
  208. , m_handler( handler )
  209. {
  210. if ( m_NetChannel )
  211. {
  212. m_NetChannel->RegisterMessage( this );
  213. }
  214. }
  215. virtual ~BindParams()
  216. {
  217. if ( m_NetChannel )
  218. {
  219. m_NetChannel->UnregisterMessage( this );
  220. }
  221. }
  222. virtual int GetType( void ) const
  223. {
  224. return _N::sk_Type;
  225. }
  226. virtual void SetNetChannel(INetChannel * netchan)
  227. {
  228. if( m_NetChannel != netchan )
  229. {
  230. if( m_NetChannel )
  231. m_NetChannel->UnregisterMessage( this );
  232. m_NetChannel = netchan;
  233. if( m_NetChannel )
  234. m_NetChannel->RegisterMessage( this );
  235. }
  236. }
  237. virtual INetMessage *CreateFromBuffer( bf_read &buffer )
  238. {
  239. INetMessage *pMsg = new typename _N::MyType_t;
  240. if ( !pMsg->ReadFromBuffer( buffer ) )
  241. {
  242. delete pMsg;
  243. return NULL;
  244. }
  245. return pMsg;
  246. }
  247. virtual bool Process( const INetMessage &src )
  248. {
  249. const typename _N::MyType_t &typedSrc = static_cast< const typename _N::MyType_t & >( src );
  250. Assert( m_handler );
  251. if( m_handler )
  252. {
  253. return m_handler( static_cast< typename _N::PBType_t const & >( typedSrc ) );
  254. }
  255. return false;
  256. }
  257. INetChannel *m_NetChannel; // netchannel this message is from/for
  258. CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > m_handler;
  259. };
  260. INetMessageBinder *m_pBind;
  261. };
  262. ///////////////////////////////////////////////////////////////////////////////////////
  263. // bidirectional net messages:
  264. ///////////////////////////////////////////////////////////////////////////////////////
  265. class CNETMsg_Tick_t : public CNetMessagePB< net_Tick, CNETMsg_Tick >
  266. {
  267. public:
  268. static float FrametimeToFloat( uint32 frametime ) { return ( float )frametime / 1000000.0f; }
  269. CNETMsg_Tick_t( int tick, float host_computationtime, float host_computationtime_stddeviation, float host_framestarttime_std_deviation )
  270. {
  271. SetReliable( false );
  272. set_tick( tick );
  273. set_host_computationtime( MIN( ( uint32 )( 1000000.0 * host_computationtime ), 1000000u ) );
  274. set_host_computationtime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_computationtime_stddeviation ), 1000000u ) );
  275. set_host_framestarttime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_framestarttime_std_deviation ), 1000000u ) );
  276. }
  277. };
  278. class CNETMsg_StringCmd_t : public CNetMessagePB< net_StringCmd, CNETMsg_StringCmd, INetChannelInfo::STRINGCMD >
  279. {
  280. public:
  281. CNETMsg_StringCmd_t( const char *command )
  282. {
  283. set_command( command );
  284. }
  285. };
  286. class CNETMsg_PlayerAvatarData_t : public CNetMessagePB< net_PlayerAvatarData, CNETMsg_PlayerAvatarData, INetChannelInfo::PAINTMAP >
  287. {
  288. // 12 KB player avatar 64x64 rgb only no alpha
  289. // WARNING-WARNING-WARNING
  290. // This message is extremely large for our net channels
  291. // and must be pumped through special fragmented waiting list
  292. // via chunk-based ack mechanism!
  293. // See: INetChannel::EnqueueVeryLargeAsyncTransfer
  294. // WARNING-WARNING-WARNING
  295. public:
  296. CNETMsg_PlayerAvatarData_t() {}
  297. CNETMsg_PlayerAvatarData_t( uint32 unAccountID, void const *pvData, uint32 cbData )
  298. {
  299. set_accountid( unAccountID );
  300. set_rgb( ( const char * ) pvData, cbData );
  301. }
  302. };
  303. class CNETMsg_SignonState_t : public CNetMessagePB< net_SignonState, CNETMsg_SignonState, INetChannelInfo::SIGNON >
  304. {
  305. public:
  306. CNETMsg_SignonState_t( int state, int spawncount )
  307. {
  308. set_signon_state( state );
  309. set_spawn_count( spawncount );
  310. set_num_server_players( 0 );
  311. }
  312. };
  313. inline void NetMsgSetCVarUsingDictionary( CMsg_CVars::CVar *convar, char const * name, char const * value )
  314. {
  315. convar->set_value( value );
  316. if ( 0 ) ( void ) 0;
  317. /** Removed for partner depot **/
  318. else
  319. {
  320. #ifdef _DEBUG
  321. DevWarning( "Missing dictionary entry for cvar '%s'\n", name );
  322. #endif
  323. convar->set_name( name );
  324. }
  325. }
  326. inline void NetMsgExpandCVarUsingDictionary( CMsg_CVars::CVar *convar )
  327. {
  328. if ( convar->has_name() )
  329. return;
  330. switch ( convar->dictionary_name() )
  331. {
  332. case 0: return;
  333. /** Removed for partner depot **/
  334. default:
  335. DevWarning( "Invalid dictionary entry for cvar # %d\n", convar->dictionary_name() );
  336. convar->set_name( "undefined" );
  337. break;
  338. }
  339. }
  340. inline const char * NetMsgGetCVarUsingDictionary( CMsg_CVars::CVar const &convar )
  341. {
  342. if ( convar.has_name() )
  343. return convar.name().c_str();
  344. switch ( convar.dictionary_name() )
  345. {
  346. case 0: return "";
  347. /** Removed for partner depot **/
  348. default:
  349. DevWarning( "Invalid dictionary entry for cvar # %d\n", convar.dictionary_name() );
  350. return "undefined";
  351. }
  352. }
  353. class CNETMsg_SetConVar_t : public CNetMessagePB< net_SetConVar, CNETMsg_SetConVar, INetChannelInfo::STRINGCMD >
  354. {
  355. public:
  356. CNETMsg_SetConVar_t() {}
  357. CNETMsg_SetConVar_t( const char * name, const char * value )
  358. {
  359. AddToTail( name, value );
  360. }
  361. void AddToTail( const char * name, const char * value )
  362. {
  363. NetMsgSetCVarUsingDictionary( mutable_convars()->add_cvars(), name, value );
  364. }
  365. };
  366. typedef CNetMessagePB< net_NOP, CNETMsg_NOP > CNETMsg_NOP_t;
  367. typedef CNetMessagePB< net_Disconnect, CNETMsg_Disconnect > CNETMsg_Disconnect_t;
  368. typedef CNetMessagePB< net_File, CNETMsg_File > CNETMsg_File_t;
  369. typedef CNetMessagePB< net_SplitScreenUser, CNETMsg_SplitScreenUser > CNETMsg_SplitScreenUser_t;
  370. ///////////////////////////////////////////////////////////////////////////////////////
  371. // Client messages: Sent from the client to the server
  372. ///////////////////////////////////////////////////////////////////////////////////////
  373. typedef CNetMessagePB< clc_SplitPlayerConnect, CCLCMsg_SplitPlayerConnect > CCLCMsg_SplitPlayerConnect_t;
  374. typedef CNetMessagePB< clc_Move, CCLCMsg_Move, INetChannelInfo::MOVE, false > CCLCMsg_Move_t;
  375. typedef CNetMessagePB< clc_ClientInfo, CCLCMsg_ClientInfo > CCLCMsg_ClientInfo_t;
  376. typedef CNetMessagePB< clc_VoiceData, CCLCMsg_VoiceData, INetChannelInfo::VOICE, false > CCLCMsg_VoiceData_t;
  377. typedef CNetMessagePB< clc_BaselineAck, CCLCMsg_BaselineAck > CCLCMsg_BaselineAck_t;
  378. typedef CNetMessagePB< clc_ListenEvents, CCLCMsg_ListenEvents > CCLCMsg_ListenEvents_t;
  379. typedef CNetMessagePB< clc_RespondCvarValue, CCLCMsg_RespondCvarValue > CCLCMsg_RespondCvarValue_t;
  380. typedef CNetMessagePB< clc_LoadingProgress, CCLCMsg_LoadingProgress > CCLCMsg_LoadingProgress_t;
  381. typedef CNetMessagePB< clc_CmdKeyValues, CCLCMsg_CmdKeyValues > CCLCMsg_CmdKeyValues_t;
  382. typedef CNetMessagePB< clc_HltvReplay, CCLCMsg_HltvReplay > CCLCMsg_HltvReplay_t;
  383. class CCLCMsg_FileCRCCheck_t : public CNetMessagePB< clc_FileCRCCheck, CCLCMsg_FileCRCCheck >
  384. {
  385. public:
  386. // Warning: These routines may use the va() function...
  387. static void SetPath( CCLCMsg_FileCRCCheck& msg, const char *path );
  388. static const char *GetPath( const CCLCMsg_FileCRCCheck& msg );
  389. static void SetFileName( CCLCMsg_FileCRCCheck& msg, const char *fileName );
  390. static const char *GetFileName( const CCLCMsg_FileCRCCheck& msg );
  391. };
  392. ///////////////////////////////////////////////////////////////////////////////////////
  393. // Server messages: Sent from the server to the client
  394. ///////////////////////////////////////////////////////////////////////////////////////
  395. typedef CNetMessagePB< svc_ServerInfo, CSVCMsg_ServerInfo, INetChannelInfo::SIGNON > CSVCMsg_ServerInfo_t;
  396. typedef CNetMessagePB< svc_ClassInfo, CSVCMsg_ClassInfo, INetChannelInfo::SIGNON > CSVCMsg_ClassInfo_t;
  397. typedef CNetMessagePB< svc_SendTable, CSVCMsg_SendTable, INetChannelInfo::SIGNON > CSVCMsg_SendTable_t;
  398. typedef CNetMessagePB< svc_Print, CSVCMsg_Print, INetChannelInfo::GENERIC, false > CSVCMsg_Print_t;
  399. typedef CNetMessagePB< svc_SetPause, CSVCMsg_SetPause > CSVCMsg_SetPause_t;
  400. typedef CNetMessagePB< svc_SetView, CSVCMsg_SetView > CSVCMsg_SetView_t;
  401. typedef CNetMessagePB< svc_CreateStringTable, CSVCMsg_CreateStringTable, INetChannelInfo::SIGNON > CSVCMsg_CreateStringTable_t;
  402. typedef CNetMessagePB< svc_UpdateStringTable, CSVCMsg_UpdateStringTable, INetChannelInfo::STRINGTABLE > CSVCMsg_UpdateStringTable_t;
  403. typedef CNetMessagePB< svc_VoiceInit, CSVCMsg_VoiceInit, INetChannelInfo::SIGNON > CSVCMsg_VoiceInit_t;
  404. typedef CNetMessagePB< svc_VoiceData, CSVCMsg_VoiceData, INetChannelInfo::VOICE, false > CSVCMsg_VoiceData_t;
  405. typedef CNetMessagePB< svc_FixAngle, CSVCMsg_FixAngle, INetChannelInfo::GENERIC, false > CSVCMsg_FixAngle_t;
  406. typedef CNetMessagePB< svc_Prefetch, CSVCMsg_Prefetch, INetChannelInfo::SOUNDS > CSVCMsg_Prefetch_t;
  407. typedef CNetMessagePB< svc_CrosshairAngle, CSVCMsg_CrosshairAngle > CSVCMsg_CrosshairAngle_t;
  408. typedef CNetMessagePB< svc_BSPDecal, CSVCMsg_BSPDecal > CSVCMsg_BSPDecal_t;
  409. typedef CNetMessagePB< svc_SplitScreen, CSVCMsg_SplitScreen > CSVCMsg_SplitScreen_t;
  410. typedef CNetMessagePB< svc_GetCvarValue, CSVCMsg_GetCvarValue > CSVCMsg_GetCvarValue_t;
  411. typedef CNetMessagePB< svc_Menu, CSVCMsg_Menu, INetChannelInfo::GENERIC, false > CSVCMsg_Menu_t;
  412. typedef CNetMessagePB< svc_UserMessage, CSVCMsg_UserMessage, INetChannelInfo::USERMESSAGES, false > CSVCMsg_UserMessage_t;
  413. typedef CNetMessagePB< svc_PaintmapData, CSVCMsg_PaintmapData, INetChannelInfo::PAINTMAP > CSVCMsg_PaintmapData_t;
  414. typedef CNetMessagePB< svc_GameEvent, CSVCMsg_GameEvent, INetChannelInfo::EVENTS > CSVCMsg_GameEvent_t;
  415. typedef CNetMessagePB< svc_GameEventList, CSVCMsg_GameEventList > CSVCMsg_GameEventList_t;
  416. typedef CNetMessagePB< svc_TempEntities, CSVCMsg_TempEntities, INetChannelInfo::TEMPENTS, false > CSVCMsg_TempEntities_t;
  417. typedef CNetMessagePB< svc_PacketEntities, CSVCMsg_PacketEntities, INetChannelInfo::ENTITIES > CSVCMsg_PacketEntities_t;
  418. typedef CNetMessagePB< svc_Sounds, CSVCMsg_Sounds, INetChannelInfo::SOUNDS > CSVCMsg_Sounds_t;
  419. typedef CNetMessagePB< svc_EntityMessage, CSVCMsg_EntityMsg, INetChannelInfo::ENTMESSAGES, false > CSVCMsg_EntityMsg_t;
  420. typedef CNetMessagePB< svc_CmdKeyValues, CSVCMsg_CmdKeyValues > CSVCMsg_CmdKeyValues_t;
  421. typedef CNetMessagePB< svc_EncryptedData, CSVCMsg_EncryptedData, INetChannelInfo::ENCRYPTED > CSVCMsg_EncryptedData_t;
  422. typedef CNetMessagePB< svc_HltvReplay, CSVCMsg_HltvReplay, INetChannelInfo::ENTITIES > CSVCMsg_HltvReplay_t;
  423. typedef CNetMessagePB< svc_Broadcast_Command, CSVCMsg_Broadcast_Command, INetChannelInfo::STRINGCMD > CSVCMsg_Broadcast_Command_t;
  424. ///////////////////////////////////////////////////////////////////////////////////////
  425. // Utility classes
  426. ///////////////////////////////////////////////////////////////////////////////////////
  427. class CmdKeyValuesHelper
  428. {
  429. public:
  430. static void CLCMsg_SetKeyValues( CCLCMsg_CmdKeyValues& msg, const KeyValues *keyValues );
  431. static KeyValues* CLCMsg_GetKeyValues ( const CCLCMsg_CmdKeyValues& msg );
  432. static void SVCMsg_SetKeyValues( CSVCMsg_CmdKeyValues& msg, const KeyValues *keyValues );
  433. static KeyValues *SVCMsg_GetKeyValues ( const CSVCMsg_CmdKeyValues& msg );
  434. };
  435. class INetChannel;
  436. class CmdEncryptedDataMessageCodec
  437. {
  438. public:
  439. static bool SVCMsg_EncryptedData_EncryptMessage( CSVCMsg_EncryptedData_t &msgEncryptedResult, INetMessage *pMsgPlaintextInput, char const *key );
  440. static bool SVCMsg_EncryptedData_Process( CSVCMsg_EncryptedData const &msgEncryptedInput, INetChannel *pProcessingChannel, char const *key );
  441. };
  442. //////////////////////////////////////////////////////////////////////////
  443. // Helper class to share network buffers in the entire process
  444. //////////////////////////////////////////////////////////////////////////
  445. class net_scratchbuffer_t
  446. {
  447. public:
  448. net_scratchbuffer_t()
  449. {
  450. m_pBufferNetMaxMessage = sm_NetScratchBuffers.Get();
  451. if ( !m_pBufferNetMaxMessage )
  452. m_pBufferNetMaxMessage = new buffer_t;
  453. }
  454. ~net_scratchbuffer_t()
  455. {
  456. sm_NetScratchBuffers.PutObject( m_pBufferNetMaxMessage );
  457. }
  458. byte * GetBuffer() const
  459. {
  460. return m_pBufferNetMaxMessage->buf;
  461. }
  462. int Size() const
  463. {
  464. return NET_MAX_MESSAGE;
  465. }
  466. private:
  467. struct buffer_t { byte buf[ NET_MAX_MESSAGE ]; };
  468. buffer_t *m_pBufferNetMaxMessage; // buffer that is allocated and returned to shared pool
  469. private:
  470. net_scratchbuffer_t( const net_scratchbuffer_t& ); // FORBID
  471. net_scratchbuffer_t& operator=( const net_scratchbuffer_t& ); // FORBID
  472. static CTSPool< buffer_t > sm_NetScratchBuffers;
  473. };
  474. #endif // NETMESSAGES_H