Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.
 
 
 
 
 
 

808 lines
26 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef DATATABLE_SEND_H
#define DATATABLE_SEND_H
#ifdef _WIN32
#pragma once
#endif
#include "dt_common.h"
#include "tier0/dbg.h"
#include "const.h"
#include "bitvec.h"
// ------------------------------------------------------------------------ //
// Send proxies can be used to convert a variable into a networkable type
// (a good example is converting an edict pointer into an integer index).
// These allow you to translate data. For example, if you had a user-entered
// string number like "10" (call the variable pUserStr) and wanted to encode
// it as an integer, you would use a SendPropInt32 and write a proxy that said:
// pOut->m_Int = atoi(pUserStr);
// pProp : the SendProp that has the proxy
// pStructBase : the base structure (like CBaseEntity*).
// pData : the address of the variable to proxy.
// pOut : where to output the proxied value.
// iElement : the element index if this data is part of an array (or 0 if not).
// objectID : entity index for debugging purposes.
// Return false if you don't want the engine to register and send a delta to
// the clients for this property (regardless of whether it actually changed or not).
// ------------------------------------------------------------------------ //
typedef void (*SendVarProxyFn)( const SendProp *pProp, const void *pStructBase, const void *pData, DVariant *pOut, int iElement, int objectID );
// Return the pointer to the data for the datatable.
// If the proxy returns null, it's the same as if pRecipients->ClearAllRecipients() was called.
class CSendProxyRecipients;
typedef void* (*SendTableProxyFn)(
const SendProp *pProp,
const void *pStructBase,
const void *pData,
CSendProxyRecipients *pRecipients,
int objectID );
class CNonModifiedPointerProxy
{
public:
CNonModifiedPointerProxy( SendTableProxyFn fn );
public:
SendTableProxyFn m_Fn;
CNonModifiedPointerProxy *m_pNext;
};
// This tells the engine that the send proxy will not modify the pointer
// - it only plays with the recipients. This must be set on proxies that work
// this way, otherwise the engine can't track which properties changed
// in NetworkStateChanged().
#define REGISTER_SEND_PROXY_NON_MODIFIED_POINTER( sendProxyFn ) static CNonModifiedPointerProxy __proxy_##sendProxyFn( sendProxyFn );
class CStandardSendProxiesV1
{
public:
CStandardSendProxiesV1();
SendVarProxyFn m_Int8ToInt32;
SendVarProxyFn m_Int16ToInt32;
SendVarProxyFn m_Int32ToInt32;
SendVarProxyFn m_UInt8ToInt32;
SendVarProxyFn m_UInt16ToInt32;
SendVarProxyFn m_UInt32ToInt32;
SendVarProxyFn m_FloatToFloat;
SendVarProxyFn m_VectorToVector;
#ifdef SUPPORTS_INT64
SendVarProxyFn m_Int64ToInt64;
SendVarProxyFn m_UInt64ToInt64;
#endif
};
class CStandardSendProxies : public CStandardSendProxiesV1
{
public:
CStandardSendProxies();
SendTableProxyFn m_DataTableToDataTable;
SendTableProxyFn m_SendLocalDataTable;
CNonModifiedPointerProxy **m_ppNonModifiedPointerProxies;
};
extern CStandardSendProxies g_StandardSendProxies;
// Max # of datatable send proxies you can have in a tree.
#define MAX_DATATABLE_PROXIES 32
// ------------------------------------------------------------------------ //
// Datatable send proxies are used to tell the engine where the datatable's
// data is and to specify which clients should get the data.
//
// pRecipients is the object that allows you to specify which clients will
// receive the data.
// ------------------------------------------------------------------------ //
class CSendProxyRecipients
{
public:
void SetAllRecipients(); // Note: recipients are all set by default when each proxy is called.
void ClearAllRecipients();
void SetRecipient( int iClient ); // Note: these are CLIENT indices, not entity indices (so the first player's index is 0).
void ClearRecipient( int iClient );
// Clear all recipients and set only the specified one.
void SetOnly( int iClient );
public:
// Make sure we have enough room for the max possible player count
CBitVec< ABSOLUTE_PLAYER_LIMIT > m_Bits;
};
inline void CSendProxyRecipients::SetAllRecipients()
{
m_Bits.SetAll();
}
inline void CSendProxyRecipients::ClearAllRecipients()
{
m_Bits.ClearAll();
}
inline void CSendProxyRecipients::SetRecipient( int iClient )
{
m_Bits.Set( iClient );
}
inline void CSendProxyRecipients::ClearRecipient( int iClient )
{
m_Bits.Clear( iClient );
}
inline void CSendProxyRecipients::SetOnly( int iClient )
{
m_Bits.ClearAll();
m_Bits.Set( iClient );
}
// ------------------------------------------------------------------------ //
// ArrayLengthSendProxies are used when you want to specify an array's length
// dynamically.
// ------------------------------------------------------------------------ //
typedef int (*ArrayLengthSendProxyFn)( const void *pStruct, int objectID );
class RecvProp;
class SendTable;
class CSendTablePrecalc;
// -------------------------------------------------------------------------------------------------------------- //
// SendProp.
// -------------------------------------------------------------------------------------------------------------- //
// If SendProp::GetDataTableProxyIndex() returns this, then the proxy is one that always sends
// the data to all clients, so we don't need to store the results.
#define DATATABLE_PROXY_INDEX_NOPROXY 255
#define DATATABLE_PROXY_INDEX_INVALID 254
class SendProp
{
public:
SendProp();
virtual ~SendProp();
void Clear();
int GetOffset() const;
void SetOffset( int i );
SendVarProxyFn GetProxyFn() const;
void SetProxyFn( SendVarProxyFn f );
SendTableProxyFn GetDataTableProxyFn() const;
void SetDataTableProxyFn( SendTableProxyFn f );
SendTable* GetDataTable() const;
void SetDataTable( SendTable *pTable );
char const* GetExcludeDTName() const;
// 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() const;
void SetParentArrayPropName( char *pArrayPropName );
const char* GetName() const;
bool IsSigned() const;
bool IsExcludeProp() const;
bool IsInsideArray() const; // Returns true if SPROP_INSIDEARRAY is set.
void SetInsideArray();
// Arrays only.
void SetArrayProp( SendProp *pProp );
SendProp* GetArrayProp() const;
// Arrays only.
void SetArrayLengthProxy( ArrayLengthSendProxyFn fn );
ArrayLengthSendProxyFn GetArrayLengthProxy() const;
int GetNumElements() const;
void SetNumElements( int nElements );
// Return the # of bits to encode an array length (must hold GetNumElements()).
int GetNumArrayLengthBits() const;
int GetElementStride() const;
SendPropType GetType() const;
int GetFlags() const;
void SetFlags( int flags );
// Some property types bind more data to the SendProp in here.
const void* GetExtraData() const;
void SetExtraData( const void *pData );
public:
RecvProp *m_pMatchingRecvProp; // This is temporary and only used while precalculating
// data for the decoders.
SendPropType m_Type;
int m_nBits;
float m_fLowValue;
float m_fHighValue;
SendProp *m_pArrayProp; // If this is an array, this is the property that defines each array element.
ArrayLengthSendProxyFn m_ArrayLengthProxy; // This callback returns the array length.
int m_nElements; // Number of elements in the array (or 1 if it's not an array).
int m_ElementStride; // Pointer distance between array elements.
const char *m_pExcludeDTName; // If this is an exclude prop, then this is the name of the datatable to exclude a prop from.
const char *m_pParentArrayPropName;
const char *m_pVarName;
float m_fHighLowMul;
private:
int m_Flags; // SPROP_ flags.
SendVarProxyFn m_ProxyFn; // NULL for DPT_DataTable.
SendTableProxyFn m_DataTableProxyFn; // Valid for DPT_DataTable.
SendTable *m_pDataTable;
// SENDPROP_VECTORELEM makes this negative to start with so we can detect that and
// set the SPROP_IS_VECTOR_ELEM flag.
int m_Offset;
// Extra data bound to this property.
const void *m_pExtraData;
};
inline int SendProp::GetOffset() const
{
return m_Offset;
}
inline void SendProp::SetOffset( int i )
{
m_Offset = i;
}
inline SendVarProxyFn SendProp::GetProxyFn() const
{
Assert( m_Type != DPT_DataTable );
return m_ProxyFn;
}
inline void SendProp::SetProxyFn( SendVarProxyFn f )
{
m_ProxyFn = f;
}
inline SendTableProxyFn SendProp::GetDataTableProxyFn() const
{
Assert( m_Type == DPT_DataTable );
return m_DataTableProxyFn;
}
inline void SendProp::SetDataTableProxyFn( SendTableProxyFn f )
{
m_DataTableProxyFn = f;
}
inline SendTable* SendProp::GetDataTable() const
{
return m_pDataTable;
}
inline void SendProp::SetDataTable( SendTable *pTable )
{
m_pDataTable = pTable;
}
inline char const* SendProp::GetExcludeDTName() const
{
return m_pExcludeDTName;
}
inline const char* SendProp::GetParentArrayPropName() const
{
return m_pParentArrayPropName;
}
inline void SendProp::SetParentArrayPropName( char *pArrayPropName )
{
Assert( !m_pParentArrayPropName );
m_pParentArrayPropName = pArrayPropName;
}
inline const char* SendProp::GetName() const
{
return m_pVarName;
}
inline bool SendProp::IsSigned() const
{
return !(m_Flags & SPROP_UNSIGNED);
}
inline bool SendProp::IsExcludeProp() const
{
return (m_Flags & SPROP_EXCLUDE) != 0;
}
inline bool SendProp::IsInsideArray() const
{
return (m_Flags & SPROP_INSIDEARRAY) != 0;
}
inline void SendProp::SetInsideArray()
{
m_Flags |= SPROP_INSIDEARRAY;
}
inline void SendProp::SetArrayProp( SendProp *pProp )
{
m_pArrayProp = pProp;
}
inline SendProp* SendProp::GetArrayProp() const
{
return m_pArrayProp;
}
inline void SendProp::SetArrayLengthProxy( ArrayLengthSendProxyFn fn )
{
m_ArrayLengthProxy = fn;
}
inline ArrayLengthSendProxyFn SendProp::GetArrayLengthProxy() const
{
return m_ArrayLengthProxy;
}
inline int SendProp::GetNumElements() const
{
return m_nElements;
}
inline void SendProp::SetNumElements( int nElements )
{
m_nElements = nElements;
}
inline int SendProp::GetElementStride() const
{
return m_ElementStride;
}
inline SendPropType SendProp::GetType() const
{
return m_Type;
}
inline int SendProp::GetFlags() const
{
return m_Flags;
}
inline void SendProp::SetFlags( int flags )
{
// Make sure they're using something from the valid set of flags.
Assert( !( flags & ~((1 << SPROP_NUMFLAGBITS) - 1) ) );
m_Flags = flags;
}
inline const void* SendProp::GetExtraData() const
{
return m_pExtraData;
}
inline void SendProp::SetExtraData( const void *pData )
{
m_pExtraData = pData;
}
// -------------------------------------------------------------------------------------------------------------- //
// SendTable.
// -------------------------------------------------------------------------------------------------------------- //
class SendTable
{
public:
typedef SendProp PropType;
SendTable();
SendTable( SendProp *pProps, int nProps, const char *pNetTableName );
~SendTable();
void Construct( SendProp *pProps, int nProps, const char *pNetTableName );
const char* GetName() const;
int GetNumProps() const;
SendProp* GetProp( int i );
// Used by the engine.
bool IsInitialized() const;
void SetInitialized( bool bInitialized );
// Used by the engine while writing info into the signon.
void SetWriteFlag(bool bHasBeenWritten);
bool GetWriteFlag() const;
bool HasPropsEncodedAgainstTickCount() const;
void SetHasPropsEncodedAgainstTickcount( bool bState );
public:
SendProp *m_pProps;
int m_nProps;
const char *m_pNetTableName; // The name matched between client and server.
// The engine hooks the SendTable here.
CSendTablePrecalc *m_pPrecalc;
protected:
bool m_bInitialized : 1;
bool m_bHasBeenWritten : 1;
bool m_bHasPropsEncodedAgainstCurrentTickCount : 1; // m_flSimulationTime and m_flAnimTime, e.g.
};
inline const char* SendTable::GetName() const
{
return m_pNetTableName;
}
inline int SendTable::GetNumProps() const
{
return m_nProps;
}
inline SendProp* SendTable::GetProp( int i )
{
Assert( i >= 0 && i < m_nProps );
return &m_pProps[i];
}
inline bool SendTable::IsInitialized() const
{
return m_bInitialized;
}
inline void SendTable::SetInitialized( bool bInitialized )
{
m_bInitialized = bInitialized;
}
inline bool SendTable::GetWriteFlag() const
{
return m_bHasBeenWritten;
}
inline void SendTable::SetWriteFlag(bool bHasBeenWritten)
{
m_bHasBeenWritten = bHasBeenWritten;
}
inline bool SendTable::HasPropsEncodedAgainstTickCount() const
{
return m_bHasPropsEncodedAgainstCurrentTickCount;
}
inline void SendTable::SetHasPropsEncodedAgainstTickcount( bool bState )
{
m_bHasPropsEncodedAgainstCurrentTickCount = bState;
}
// ------------------------------------------------------------------------------------------------------ //
// Use BEGIN_SEND_TABLE if you want to declare a SendTable and have it inherit all the properties from
// its base class. There are two requirements for this to work:
// 1. Its base class must have a static SendTable pointer member variable called m_pClassSendTable which
// points to its send table. The DECLARE_SERVERCLASS and IMPLEMENT_SERVERCLASS macros do this automatically.
// 2. Your class must typedef its base class as BaseClass. So it would look like this:
// class Derived : public CBaseEntity
// {
// typedef CBaseEntity BaseClass;
// };
// If you don't want to interit a base class's properties, use BEGIN_SEND_TABLE_NOBASE.
// ------------------------------------------------------------------------------------------------------ //
#define BEGIN_SEND_TABLE(className, tableName) \
BEGIN_SEND_TABLE_NOBASE(className, tableName) \
SendPropDataTable("baseclass", 0, className::BaseClass::m_pClassSendTable, SendProxy_DataTableToDataTable),
#define BEGIN_SEND_TABLE_NOBASE(className, tableName) \
template <typename T> int ServerClassInit(T *); \
namespace tableName { \
struct ignored; \
} \
template <> int ServerClassInit<tableName::ignored>(tableName::ignored *); \
namespace tableName { \
SendTable g_SendTable;\
int g_SendTableInit = ServerClassInit((tableName::ignored *)NULL); \
} \
template <> int ServerClassInit<tableName::ignored>(tableName::ignored *) \
{ \
typedef className currentSendDTClass; \
static const char *g_pSendTableName = #tableName; \
SendTable &sendTable = tableName::g_SendTable; \
static SendProp g_SendProps[] = { \
SendPropInt("should_never_see_this", 0, sizeof(int)), // It adds a dummy property at the start so you can define "empty" SendTables.
#define END_SEND_TABLE() \
};\
sendTable.Construct(g_SendProps+1, sizeof(g_SendProps) / sizeof(SendProp) - 1, g_pSendTableName);\
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_dtsend_offsetof(s,m) ((size_t)&(((s *)0)->m))
// These can simplify creating the variables.
// Note: currentSendDTClass::MakeANetworkVar_##varName equates to currentSendDTClass. It's
// there as a check to make sure all networked variables use the CNetworkXXXX macros in network_var.h.
#define SENDINFO(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName)
#define SENDINFO_ARRAY(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0])
#define SENDINFO_ARRAY3(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName), sizeof(((currentSendDTClass*)0)->varName[0]), sizeof(((currentSendDTClass*)0)->varName)/sizeof(((currentSendDTClass*)0)->varName[0])
#define SENDINFO_ARRAYELEM(varName, i) #varName "[" #i "]", _hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName[i]), sizeof(((currentSendDTClass*)0)->varName[0])
#define SENDINFO_NETWORKARRAYELEM(varName, i)#varName "[" #i "]", _hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0])
// NOTE: Be VERY careful to specify any other vector elems for the same vector IN ORDER and
// right after each other, otherwise it might miss the Y or Z component in SP.
//
// Note: this macro specifies a negative offset so the engine can detect it and setup m_pNext
#define SENDINFO_VECTORELEM(varName, i) #varName "[" #i "]", -(int)_hacky_dtsend_offsetof(currentSendDTClass::MakeANetworkVar_##varName, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0])
#define SENDINFO_STRUCTELEM(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName.m_Value)
#define SENDINFO_STRUCTARRAYELEM(varName, i)#varName "[" #i "]", _hacky_dtsend_offsetof(currentSendDTClass, varName.m_Value[i]), sizeof(((currentSendDTClass*)0)->varName.m_Value[0])
// Use this when you're not using a CNetworkVar to represent the data you're sending.
#define SENDINFO_NOCHECK(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName)
#define SENDINFO_STRING_NOCHECK(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass, varName)
#define SENDINFO_DT(varName) #varName, _hacky_dtsend_offsetof(currentSendDTClass, varName)
#define SENDINFO_DT_NAME(varName, remoteVarName) #remoteVarName, _hacky_dtsend_offsetof(currentSendDTClass, varName)
#define SENDINFO_NAME(varName,remoteVarName) #remoteVarName, _hacky_dtsend_offsetof(currentSendDTClass, varName), sizeof(((currentSendDTClass*)0)->varName)
// ------------------------------------------------------------------------ //
// Built-in proxy types.
// See the definition of SendVarProxyFn for information about these.
// ------------------------------------------------------------------------ //
void SendProxy_QAngles ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_AngleToFloat ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_FloatToFloat ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_VectorToVector ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_VectorXYToVectorXY( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
#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!!!
void SendProxy_QuaternionToQuaternion( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
#endif
void SendProxy_Int8ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_Int16ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
void SendProxy_Int32ToInt32 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
#ifdef SUPPORTS_INT64
void SendProxy_Int64ToInt64 ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
#endif
void SendProxy_StringToString ( const SendProp *pProp, const void *pStruct, const void *pData, DVariant *pOut, int iElement, int objectID );
// pData is the address of a data table.
void* SendProxy_DataTableToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID );
// pData is the address of a pointer to a data table.
void* SendProxy_DataTablePtrToDataTable( const SendProp *pProp, const void *pStructBase, const void *pData, CSendProxyRecipients *pRecipients, int objectID );
// Used on player entities - only sends the data to the local player (objectID-1).
void* SendProxy_SendLocalDataTable( const SendProp *pProp, const void *pStruct, const void *pVarData, CSendProxyRecipients *pRecipients, int objectID );
// ------------------------------------------------------------------------ //
// Use these functions to setup your data tables.
// ------------------------------------------------------------------------ //
SendProp SendPropFloat(
const char *pVarName, // Variable name.
int offset, // Offset into container structure.
int sizeofVar=SIZEOF_IGNORE,
int nBits=32, // Number of bits to use when encoding.
int flags=0,
float fLowValue=0.0f, // For floating point, low and high values.
float fHighValue=HIGH_DEFAULT, // High value. If HIGH_DEFAULT, it's (1<<nBits).
SendVarProxyFn varProxy=SendProxy_FloatToFloat
);
SendProp SendPropVector(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE,
int nBits=32, // Number of bits (for each floating-point component) to use when encoding.
int flags=SPROP_NOSCALE,
float fLowValue=0.0f, // For floating point, low and high values.
float fHighValue=HIGH_DEFAULT, // High value. If HIGH_DEFAULT, it's (1<<nBits).
SendVarProxyFn varProxy=SendProxy_VectorToVector
);
SendProp SendPropVectorXY(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE,
int nBits=32, // Number of bits (for each floating-point component) to use when encoding.
int flags=SPROP_NOSCALE,
float fLowValue=0.0f, // For floating point, low and high values.
float fHighValue=HIGH_DEFAULT, // High value. If HIGH_DEFAULT, it's (1<<nBits).
SendVarProxyFn varProxy=SendProxy_VectorXYToVectorXY
);
#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!!!
SendProp SendPropQuaternion(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE,
int nBits=32, // Number of bits (for each floating-point component) to use when encoding.
int flags=SPROP_NOSCALE,
float fLowValue=0.0f, // For floating point, low and high values.
float fHighValue=HIGH_DEFAULT, // High value. If HIGH_DEFAULT, it's (1<<nBits).
SendVarProxyFn varProxy=SendProxy_QuaternionToQuaternion
);
#endif
SendProp SendPropAngle(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE,
int nBits=32,
int flags=0,
SendVarProxyFn varProxy=SendProxy_AngleToFloat
);
SendProp SendPropQAngles(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE,
int nBits=32,
int flags=0,
SendVarProxyFn varProxy=SendProxy_QAngles
);
SendProp SendPropInt(
const char *pVarName,
int offset,
int sizeofVar=SIZEOF_IGNORE, // Handled by SENDINFO macro.
int nBits=-1, // Set to -1 to automatically pick (max) number of bits based on size of element.
int flags=0,
SendVarProxyFn varProxy=0
);
inline SendProp SendPropModelIndex( const char *pVarName, int offset, int sizeofVar=SIZEOF_IGNORE )
{
return SendPropInt( pVarName, offset, sizeofVar, SP_MODEL_INDEX_BITS, 0 );
}
SendProp SendPropString(
const char *pVarName,
int offset,
int bufferLen,
int flags=0,
SendVarProxyFn varProxy=SendProxy_StringToString);
// The data table encoder looks at DVariant::m_pData.
SendProp SendPropDataTable(
const char *pVarName,
int offset,
SendTable *pTable,
SendTableProxyFn varProxy=SendProxy_DataTableToDataTable
);
SendProp SendPropArray3(
const char *pVarName,
int offset,
int sizeofVar,
int elements,
SendProp pArrayProp,
SendTableProxyFn varProxy=SendProxy_DataTableToDataTable
);
// 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.
SendProp InternalSendPropArray(
const int elementCount,
const int elementStride,
const char *pName,
ArrayLengthSendProxyFn proxy
);
// Use this and pass the array name and it will figure out the count and stride automatically.
#define SendPropArray( varTemplate, arrayName ) \
SendPropVariableLengthArray( \
0, \
varTemplate, \
arrayName )
//
// Use this when you want to send a variable-length array of data but there is no physical array you can point it at.
// You need to provide:
// 1. A proxy function that returns the current length of the array.
// 2. The maximum length the array will ever be.
// 2. A SendProp describing what the elements are comprised of.
// 3. In the SendProp, you'll want to specify a proxy function so you can go grab the data from wherever it is.
// 4. A property name that matches the definition on the client.
//
#define SendPropVirtualArray( arrayLengthSendProxy, maxArrayLength, varTemplate, propertyName ) \
varTemplate, \
InternalSendPropArray( \
maxArrayLength, \
0, \
#propertyName, \
arrayLengthSendProxy \
)
#define SendPropVariableLengthArray( arrayLengthSendProxy, varTemplate, arrayName ) \
varTemplate, \
InternalSendPropArray( \
sizeof(((currentSendDTClass*)0)->arrayName) / PROPSIZEOF(currentSendDTClass, arrayName[0]), \
PROPSIZEOF(currentSendDTClass, arrayName[0]), \
#arrayName, \
arrayLengthSendProxy \
)
// Use this one to specify the element count and stride manually.
#define SendPropArray2( arrayLengthSendProxy, varTemplate, elementCount, elementStride, arrayName ) \
varTemplate, \
InternalSendPropArray( elementCount, elementStride, #arrayName, arrayLengthSendProxy )
// Use these to create properties that exclude other properties. This is useful if you want to use most of
// a base class's datatable data, but you want to override some of its variables.
SendProp SendPropExclude(
const char *pDataTableName, // Data table name (given to BEGIN_SEND_TABLE and BEGIN_RECV_TABLE).
const char *pPropName // Name of the property to exclude.
);
#endif // DATATABLE_SEND_H