Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

575 lines
16 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef DATATABLE_RECV_H
#define DATATABLE_RECV_H
#ifdef _WIN32
#pragma once
#endif
#include "dt_common.h"
#include "tier0/dbg.h"
#define ADDRESSPROXY_NONE -1
class RecvTable;
class RecvProp;
// This is passed into RecvProxy functions.
class CRecvProxyData
{
public:
const RecvProp *m_pRecvProp; // The property it's receiving.
DVariant m_Value; // The value given to you to store.
int m_iElement; // Which array element you're getting.
int m_ObjectID; // The object being referred to.
};
//-----------------------------------------------------------------------------
// pStruct = the base structure of the datatable this variable is in (like C_BaseEntity)
// pOut = the variable that this this proxy represents (like C_BaseEntity::m_SomeValue).
//
// Convert the network-standard-type value in m_Value into your own format in pStruct/pOut.
//-----------------------------------------------------------------------------
typedef void (*RecvVarProxyFn)( const CRecvProxyData *pData, void *pStruct, void *pOut );
// ------------------------------------------------------------------------ //
// ArrayLengthRecvProxies are optionally used to get the length of the
// incoming array when it changes.
// ------------------------------------------------------------------------ //
typedef void (*ArrayLengthRecvProxyFn)( void *pStruct, int objectID, int currentArrayLength );
// NOTE: DataTable receive proxies work differently than the other proxies.
// pData points at the object + the recv table's offset.
// pOut should be set to the location of the object to unpack the data table into.
// If the parent object just contains the child object, the default proxy just does *pOut = pData.
// If the parent object points at the child object, you need to dereference the pointer here.
// NOTE: don't ever return null from a DataTable receive proxy function. Bad things will happen.
typedef void (*DataTableRecvVarProxyFn)(const RecvProp *pProp, void **pOut, void *pData, int objectID);
// This is used to fork over the standard proxy functions to the engine so it can
// make some optimizations.
class CStandardRecvProxies
{
public:
CStandardRecvProxies();
RecvVarProxyFn m_Int32ToInt8;
RecvVarProxyFn m_Int32ToInt16;
RecvVarProxyFn m_Int32ToInt32;
RecvVarProxyFn m_FloatToFloat;
RecvVarProxyFn m_VectorToVector;
#ifdef SUPPORTS_INT64
RecvVarProxyFn m_Int64ToInt64;
#endif
};
extern CStandardRecvProxies g_StandardRecvProxies;
class CRecvDecoder;
class RecvProp
{
// This info comes from the receive data table.
public:
RecvProp();
void InitArray( int nElements, int elementStride );
int GetNumElements() const;
void SetNumElements( int nElements );
int GetElementStride() const;
void SetElementStride( int stride );
int GetFlags() const;
const char* GetName() const;
SendPropType GetType() const;
RecvTable* GetDataTable() const;
void SetDataTable( RecvTable *pTable );
RecvVarProxyFn GetProxyFn() const;
void SetProxyFn( RecvVarProxyFn fn );
DataTableRecvVarProxyFn GetDataTableProxyFn() const;
void SetDataTableProxyFn( DataTableRecvVarProxyFn fn );
int GetOffset() const;
void SetOffset( int o );
// Arrays only.
RecvProp* GetArrayProp() const;
void SetArrayProp( RecvProp *pProp );
// Arrays only.
void SetArrayLengthProxy( ArrayLengthRecvProxyFn proxy );
ArrayLengthRecvProxyFn GetArrayLengthProxy() const;
bool IsInsideArray() const;
void SetInsideArray();
// Some property types bind more data to the prop in here.
const void* GetExtraData() const;
void SetExtraData( const void *pData );
// If it's one of the numbered "000", "001", etc properties in an array, then
// these can be used to get its array property name for debugging.
const char* GetParentArrayPropName();
void SetParentArrayPropName( const char *pArrayPropName );
public:
const char *m_pVarName;
SendPropType m_RecvType;
int m_Flags;
int m_StringBufferSize;
private:
bool m_bInsideArray; // Set to true by the engine if this property sits inside an array.
// Extra data that certain special property types bind to the property here.
const void *m_pExtraData;
// If this is an array (DPT_Array).
RecvProp *m_pArrayProp;
ArrayLengthRecvProxyFn m_ArrayLengthProxy;
RecvVarProxyFn m_ProxyFn;
DataTableRecvVarProxyFn m_DataTableProxyFn; // For RDT_DataTable.
RecvTable *m_pDataTable; // For RDT_DataTable.
int m_Offset;
int m_ElementStride;
int m_nElements;
// If it's one of the numbered "000", "001", etc properties in an array, then
// these can be used to get its array property name for debugging.
const char *m_pParentArrayPropName;
};
class RecvTable
{
public:
typedef RecvProp PropType;
RecvTable();
RecvTable( RecvProp *pProps, int nProps, const char *pNetTableName );
~RecvTable();
void Construct( RecvProp *pProps, int nProps, const char *pNetTableName );
int GetNumProps();
RecvProp* GetProp( int i );
const char* GetName();
// Used by the engine while initializing array props.
void SetInitialized( bool bInitialized );
bool IsInitialized() const;
// Used by the engine.
void SetInMainList( bool bInList );
bool IsInMainList() const;
public:
// Properties described in a table.
RecvProp *m_pProps;
int m_nProps;
// The decoder. NOTE: this covers each RecvTable AND all its children (ie: its children
// will have their own decoders that include props for all their children).
CRecvDecoder *m_pDecoder;
const char *m_pNetTableName; // The name matched between client and server.
private:
bool m_bInitialized;
bool m_bInMainList;
};
inline int RecvTable::GetNumProps()
{
return m_nProps;
}
inline RecvProp* RecvTable::GetProp( int i )
{
Assert( i >= 0 && i < m_nProps );
return &m_pProps[i];
}
inline const char* RecvTable::GetName()
{
return m_pNetTableName;
}
inline void RecvTable::SetInitialized( bool bInitialized )
{
m_bInitialized = bInitialized;
}
inline bool RecvTable::IsInitialized() const
{
return m_bInitialized;
}
inline void RecvTable::SetInMainList( bool bInList )
{
m_bInMainList = bInList;
}
inline bool RecvTable::IsInMainList() const
{
return m_bInMainList;
}
// ------------------------------------------------------------------------------------------------------ //
// See notes on BEGIN_SEND_TABLE for a description. These macros work similarly.
// ------------------------------------------------------------------------------------------------------ //
#define BEGIN_RECV_TABLE(className, tableName) \
BEGIN_RECV_TABLE_NOBASE(className, tableName) \
RecvPropDataTable("baseclass", 0, 0, className::BaseClass::m_pClassRecvTable, DataTableRecvProxy_StaticDataTable),
#define BEGIN_RECV_TABLE_NOBASE(className, tableName) \
template <typename T> int ClientClassInit(T *); \
namespace tableName { \
struct ignored; \
} \
template <> int ClientClassInit<tableName::ignored>(tableName::ignored *); \
namespace tableName { \
RecvTable g_RecvTable; \
int g_RecvTableInit = ClientClassInit((tableName::ignored *)NULL); \
} \
template <> int ClientClassInit<tableName::ignored>(tableName::ignored *) \
{ \
typedef className currentRecvDTClass; \
const char *pRecvTableName = #tableName; \
RecvTable &RecvTable = tableName::g_RecvTable; \
static RecvProp RecvProps[] = { \
RecvPropInt("should_never_see_this", 0, sizeof(int)), // It adds a dummy property at the start so you can define "empty" SendTables.
#define END_RECV_TABLE() \
}; \
RecvTable.Construct(RecvProps+1, sizeof(RecvProps) / sizeof(RecvProp) - 1, pRecvTableName); \
return 1; \
}
// Normal offset of is invalid on non-array-types, this is dubious as hell. The rest of the codebase converted to the
// legit offsetof from the C headers, so we'll use the old impl here to avoid exposing temptation to others
#define _hacky_dtrecv_offsetof(s,m) ((size_t)&(((s *)0)->m))
#define RECVINFO(varName) #varName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName)
#define RECVINFO_NAME(varName, remoteVarName) #remoteVarName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName)
#define RECVINFO_STRING(varName) #varName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName), STRINGBUFSIZE(currentRecvDTClass, varName)
#define RECVINFO_BASECLASS(tableName) RecvPropDataTable("this", 0, 0, &REFERENCE_RECV_TABLE(tableName))
#define RECVINFO_ARRAY(varName) #varName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName), sizeof(((currentRecvDTClass*)0)->varName[0]), sizeof(((currentRecvDTClass*)0)->varName)/sizeof(((currentRecvDTClass*)0)->varName[0])
// Just specify the name and offset. Used for strings and data tables.
#define RECVINFO_NOSIZE(varName) #varName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName)
#define RECVINFO_DT(varName) RECVINFO_NOSIZE(varName)
#define RECVINFO_DTNAME(varName,remoteVarName) #remoteVarName, _hacky_dtrecv_offsetof(currentRecvDTClass, varName)
void RecvProxy_FloatToFloat ( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_VectorToVector( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_VectorXYToVectorXY( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_QuaternionToQuaternion( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_Int32ToInt8 ( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_Int32ToInt16 ( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_StringToString( const CRecvProxyData *pData, void *pStruct, void *pOut );
void RecvProxy_Int32ToInt32 ( const CRecvProxyData *pData, void *pStruct, void *pOut );
#ifdef SUPPORTS_INT64
void RecvProxy_Int64ToInt64 ( const CRecvProxyData *pData, void *pStruct, void *pOut );
#endif
// StaticDataTable does *pOut = pData.
void DataTableRecvProxy_StaticDataTable(const RecvProp *pProp, void **pOut, void *pData, int objectID);
// PointerDataTable does *pOut = *((void**)pData) (ie: pData is a pointer to the object to decode into).
void DataTableRecvProxy_PointerDataTable(const RecvProp *pProp, void **pOut, void *pData, int objectID);
RecvProp RecvPropFloat(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother.
int flags=0,
RecvVarProxyFn varProxy=RecvProxy_FloatToFloat
);
RecvProp RecvPropVector(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother.
int flags=0,
RecvVarProxyFn varProxy=RecvProxy_VectorToVector
);
RecvProp RecvPropVectorXY(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother.
int flags=0,
RecvVarProxyFn varProxy=RecvProxy_VectorXYToVectorXY
);
// This is here so the RecvTable can look more like the SendTable.
#define RecvPropQAngles RecvPropVector
#if 0 // We can't ship this since it changes the size of DTVariant to be 20 bytes instead of 16 and that breaks MODs!!!
RecvProp RecvPropQuaternion(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother.
int flags=0,
RecvVarProxyFn varProxy=RecvProxy_QuaternionToQuaternion
);
#endif
RecvProp RecvPropInt(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by RECVINFO macro, but set to SIZEOF_IGNORE if you don't want to bother.
int flags=0,
RecvVarProxyFn varProxy=0
);
RecvProp RecvPropString(
const char *pVarName,
int offset,
int bufferSize,
int flags=0,
RecvVarProxyFn varProxy=RecvProxy_StringToString
);
RecvProp RecvPropDataTable(
const char *pVarName,
int offset,
int flags,
RecvTable *pTable,
DataTableRecvVarProxyFn varProxy=DataTableRecvProxy_StaticDataTable
);
RecvProp RecvPropArray3(
const char *pVarName,
int offset,
int sizeofVar,
int elements,
RecvProp pArrayProp,
DataTableRecvVarProxyFn varProxy=DataTableRecvProxy_StaticDataTable
);
// Use the macro to let it automatically generate a table name. You shouldn't
// ever need to reference the table name. If you want to exclude this array, then
// reference the name of the variable in varTemplate.
RecvProp InternalRecvPropArray(
const int elementCount,
const int elementStride,
const char *pName,
ArrayLengthRecvProxyFn proxy
);
//
// Use this if you want to completely manage the way the array data is stored.
// You'll need to provide a proxy inside varTemplate that looks for 'iElement'
// to figure out where to store the specified element.
//
#define RecvPropVirtualArray( arrayLengthProxy, maxArrayLength, varTemplate, propertyName ) \
varTemplate, \
InternalRecvPropArray( \
maxArrayLength, \
0, \
#propertyName, \
arrayLengthProxy \
)
// Use this and pass the array name and it will figure out the count and stride automatically.
#define RecvPropVariableLengthArray( arrayLengthProxy, varTemplate, arrayName ) \
varTemplate, \
InternalRecvPropArray( \
sizeof(((currentRecvDTClass*)0)->arrayName) / PROPSIZEOF(currentRecvDTClass, arrayName[0]), \
PROPSIZEOF(currentRecvDTClass, arrayName[0]), \
#arrayName, \
arrayLengthProxy \
)
// Use this and pass the array name and it will figure out the count and stride automatically.
#define RecvPropArray( varTemplate, arrayName ) \
RecvPropVariableLengthArray( 0, varTemplate, arrayName )
// Use this one to specify the element count and stride manually.
#define RecvPropArray2( arrayLengthProxy, varTemplate, elementCount, elementStride, arrayName ) \
varTemplate, \
InternalRecvPropArray( elementCount, elementStride, #arrayName, arrayLengthProxy )
// ---------------------------------------------------------------------------------------- //
// Inlines.
// ---------------------------------------------------------------------------------------- //
inline void RecvProp::InitArray( int nElements, int elementStride )
{
m_RecvType = DPT_Array;
m_nElements = nElements;
m_ElementStride = elementStride;
}
inline int RecvProp::GetNumElements() const
{
return m_nElements;
}
inline void RecvProp::SetNumElements( int nElements )
{
m_nElements = nElements;
}
inline int RecvProp::GetElementStride() const
{
return m_ElementStride;
}
inline void RecvProp::SetElementStride( int stride )
{
m_ElementStride = stride;
}
inline int RecvProp::GetFlags() const
{
return m_Flags;
}
inline const char* RecvProp::GetName() const
{
return m_pVarName;
}
inline SendPropType RecvProp::GetType() const
{
return m_RecvType;
}
inline RecvTable* RecvProp::GetDataTable() const
{
return m_pDataTable;
}
inline void RecvProp::SetDataTable( RecvTable *pTable )
{
m_pDataTable = pTable;
}
inline RecvVarProxyFn RecvProp::GetProxyFn() const
{
return m_ProxyFn;
}
inline void RecvProp::SetProxyFn( RecvVarProxyFn fn )
{
m_ProxyFn = fn;
}
inline DataTableRecvVarProxyFn RecvProp::GetDataTableProxyFn() const
{
return m_DataTableProxyFn;
}
inline void RecvProp::SetDataTableProxyFn( DataTableRecvVarProxyFn fn )
{
m_DataTableProxyFn = fn;
}
inline int RecvProp::GetOffset() const
{
return m_Offset;
}
inline void RecvProp::SetOffset( int o )
{
m_Offset = o;
}
inline RecvProp* RecvProp::GetArrayProp() const
{
return m_pArrayProp;
}
inline void RecvProp::SetArrayProp( RecvProp *pProp )
{
m_pArrayProp = pProp;
}
inline void RecvProp::SetArrayLengthProxy( ArrayLengthRecvProxyFn proxy )
{
m_ArrayLengthProxy = proxy;
}
inline ArrayLengthRecvProxyFn RecvProp::GetArrayLengthProxy() const
{
return m_ArrayLengthProxy;
}
inline bool RecvProp::IsInsideArray() const
{
return m_bInsideArray;
}
inline void RecvProp::SetInsideArray()
{
m_bInsideArray = true;
}
inline const void* RecvProp::GetExtraData() const
{
return m_pExtraData;
}
inline void RecvProp::SetExtraData( const void *pData )
{
m_pExtraData = pData;
}
inline const char* RecvProp::GetParentArrayPropName()
{
return m_pParentArrayPropName;
}
inline void RecvProp::SetParentArrayPropName( const char *pArrayPropName )
{
m_pParentArrayPropName = pArrayPropName;
}
#endif // DATATABLE_RECV_H