|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
//#define LOG_DELTA_BITS_TO_FILE
#ifdef LOG_DELTA_BITS_TO_FILE
#undef fopen
#endif
#include "tier1/tokenset.h"
#include <algorithm>
#include <stdarg.h>
#include "dt_send.h"
#include "dt.h"
#include "dt_recv.h"
#include "dt_encode.h"
#include "convar.h"
#include "commonmacros.h"
#include "tier1/strtools.h"
#include "tier0/dbg.h"
#include "dt_stack.h"
#include "filesystem_engine.h"
#include "filesystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PROPINDEX_NUMBITS 12
#define MAX_TOTAL_SENDTABLE_PROPS ( (1 << PROPINDEX_NUMBITS) - 1 ) // one value reserved for end marker
#define PROPINDEX_END_MARKER ( ( 1 << PROPINDEX_NUMBITS ) - 1 )
ConVar g_CV_DTWatchEnt( "dtwatchent", "-1", 0, "Watch this entities data table encoding." ); ConVar g_CV_DTWatchVar( "dtwatchvar", "", 0, "Watch the named variable." ); ConVar g_CV_DTWarning( "dtwarning", "0", 0, "Print data table warnings?" ); ConVar g_CV_DTWatchClass( "dtwatchclass", "", 0, "Watch all fields encoded with this table." ); ConVar g_CV_DTEncode( "dtwatchencode", "1", 0, "When watching show encode." ); ConVar g_CV_DTDecode( "dtwatchdecode", "1", 0, "When watching show decode." ); ConVar sv_new_delta_bits( "sv_new_delta_bits", "1" );
#ifdef LOG_DELTA_BITS_TO_FILE
class CDeltaBitsRun { public: CUtlVector<int> m_Props; CUtlVector<int> m_BitCounts; };
CUtlVector<CDeltaBitsRun*> g_DeltaBitsRuns; CDeltaBitsRun *g_pDeltaBitsRun = NULL;
inline void LogDeltaBitsStart() { if ( g_pDeltaBitsRun ) Error( "LogDeltaBitsStart" );
g_pDeltaBitsRun = new CDeltaBitsRun; g_DeltaBitsRuns.AddToTail( g_pDeltaBitsRun ); }
inline void LogDeltaBitsEnd() { if ( !g_pDeltaBitsRun ) Error( "LogDeltaBitsEnd" );
g_pDeltaBitsRun = NULL; }
inline void LogDeltaBitsEntry( int iProp, int nBits ) { g_pDeltaBitsRun->m_Props.AddToTail( iProp ); g_pDeltaBitsRun->m_BitCounts.AddToTail( nBits ); }
void FlushDeltaBitsTrackingData() { FILE *fp = fopen( "c:\\deltabits.txt", "wt" ); fprintf( fp, "%d\n", g_DeltaBitsRuns.Count() );
for ( int i=0; i < g_DeltaBitsRuns.Count(); i++ ) { CDeltaBitsRun *pRun = g_DeltaBitsRuns[i];
fprintf( fp, "%d ", pRun->m_Props.Count() ); for ( int z=0; z < pRun->m_Props.Count(); z++ ) { fprintf( fp, "%d %d ", pRun->m_Props[z], pRun->m_BitCounts[z] ); } fprintf( fp, "\n" ); }
fclose( fp ); }
#else
inline void LogDeltaBitsStart() {} inline void LogDeltaBitsEnd() {} inline void LogDeltaBitsEntry( int iProp, int nBits ) {} void FlushDeltaBitsTrackingData() {}
#endif
// ----------------------------------------------------------------------------- //
//
// CBuildHierarchyStruct
//
// Used while building a CSendNode hierarchy.
//
// ----------------------------------------------------------------------------- //
class CBuildHierarchyStruct { public: const ExcludeProp *m_pExcludeProps; int m_nExcludeProps;
const SendProp *m_pDatatableProps[MAX_TOTAL_SENDTABLE_PROPS]; int m_nDatatableProps; const SendProp *m_pProps[MAX_TOTAL_SENDTABLE_PROPS]; unsigned char m_PropProxyIndices[MAX_TOTAL_SENDTABLE_PROPS]; int m_nProps;
unsigned char m_nPropProxies; };
// ------------------------------------------------------------------------------------ //
// CDeltaBitsWriter.
// ------------------------------------------------------------------------------------ //
static FORCEINLINE unsigned int ReadPropIndex( bf_read *pBuf, bool bNewScheme ) { if ( bNewScheme ) { if ( pBuf->ReadOneBit() ) { return pBuf->ReadUBitLong( 3 ); } }
int ret = pBuf->ReadUBitLong( 7 ); switch( ret & ( 32 | 64 ) ) { case 32: ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 2 ) << 5 ); Assert( ret >= 32); break; case 64: ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 4 ) << 5 ); Assert( ret >= 128); break; case 96: ret = ( ret &~96 ) | ( pBuf->ReadUBitLong( 7 ) << 5 ); Assert( ret >= 512); break; }
return ret; }
FORCEINLINE void WritePropIndex( bf_write *pBuf, unsigned int n, bool bNewScheme ) { Assert( n < (1 << PROPINDEX_NUMBITS ) ); Assert( ( n & 0xfff ) == n );
if ( bNewScheme ) { if ( n < 8 ) { pBuf->WriteOneBit( 1 ); pBuf->WriteUBitLong( n, 3 ); return; } else { pBuf->WriteOneBit( 0 ); } }
if ( n < 32 ) pBuf->WriteUBitLong( n, 7 ); else if ( n < 128 ) pBuf->WriteUBitLong( ( n & 31 ) | 32 | ( ( n & ( 64 | 32 ) ) << 2 ), 9 ); else if ( n < 512 ) pBuf->WriteUBitLong( ( n & 31 ) | 64 | ( ( n & ( 256 | 128 | 64 | 32 ) ) << 2 ), 11 ); else pBuf->WriteUBitLong( ( n & 31 ) | 96 | ( ( n & ( 2048 | 1024 | 512 | 256 | 128 | 64 | 32 ) ) << 2 ), 14 ); }
CDeltaBitsWriter::CDeltaBitsWriter( bf_write *pBuf ) { m_pBuf = pBuf; m_iLastProp = -1; LogDeltaBitsStart(); //TODO: Get rid of this..
m_bUsingNewScheme = sv_new_delta_bits.GetBool(); if ( m_bUsingNewScheme ) pBuf->WriteOneBit( 1 ); else pBuf->WriteOneBit( 0 ); }
CDeltaBitsWriter::~CDeltaBitsWriter() { if ( m_pBuf ) Finish(); }
void CDeltaBitsWriter::Finish() { m_pBuf->WriteOneBit( 0 ); ::WritePropIndex( m_pBuf, PROPINDEX_END_MARKER, m_bUsingNewScheme ); LogDeltaBitsEnd(); m_pBuf = NULL; }
void CDeltaBitsWriter::WritePropIndex( int iProp ) { int diff = iProp - m_iLastProp; m_iLastProp = iProp;
Assert( iProp < MAX_DATATABLE_PROPS ); Assert( diff > 0 && diff < MAX_DATATABLE_PROPS ); --diff; // It's always at least 1 so subtract 1.
int startbit = m_pBuf->GetNumBitsWritten();
if ( m_bUsingNewScheme ) { if ( diff == 0 ) { m_pBuf->WriteOneBit( 1 ); } else { m_pBuf->WriteOneBit( 0 ); ::WritePropIndex( m_pBuf, diff, m_bUsingNewScheme ); } } else { ::WritePropIndex( m_pBuf, diff, m_bUsingNewScheme ); }
int nBitsToEncode = m_pBuf->GetNumBitsWritten() - startbit;
LogDeltaBitsEntry( iProp, nBitsToEncode ); }
// ------------------------------------------------------------------------------------ //
// CDeltaBitsReader.
// ------------------------------------------------------------------------------------ //
CDeltaBitsReader::CDeltaBitsReader( bf_read *pBuf ) : m_nLastFieldPathBits( 0 ) { m_pBuf = pBuf; m_bFinished = false; m_iLastProp = -1; if ( pBuf ) m_bUsingNewScheme = (pBuf->ReadOneBit() != 0); else m_bUsingNewScheme = false; }
CDeltaBitsReader::~CDeltaBitsReader() { // Make sure they read to the end unless they specifically said they don't care.
if ( m_pBuf ) { Assert( m_bFinished ); } }
int CDeltaBitsReader::GetFieldPathBits() const { return m_nLastFieldPathBits; }
int CDeltaBitsReader::ReadNextPropIndex() { Assert( !m_bFinished );
if ( m_bUsingNewScheme ) { if ( m_pBuf->ReadOneBit() ) { m_iLastProp++; m_nLastFieldPathBits = 1; return m_iLastProp; } }
int nStartBit = m_pBuf->GetNumBitsRead(); int nRead = ReadPropIndex( m_pBuf, m_bUsingNewScheme ); m_nLastFieldPathBits = m_pBuf->GetNumBitsRead() - nStartBit; if ( nRead == PROPINDEX_END_MARKER ) { m_bFinished = true; return -1; }
int prop = 1 + nRead; prop += m_iLastProp; m_iLastProp = prop;
Assert( m_iLastProp < MAX_DATATABLE_PROPS );
return prop; }
void CDeltaBitsReader::ForceFinished() { m_bFinished = true; m_pBuf = NULL; }
// ----------------------------------------------------------------------------- //
// CSendNode.
// ----------------------------------------------------------------------------- //
CSendNode::CSendNode() { m_iDatatableProp = -1; m_pTable = NULL; m_iFirstRecursiveProp = m_nRecursiveProps = 0;
m_DataTableProxyIndex = DATATABLE_PROXY_INDEX_INVALID; // set it to a questionable value.
}
CSendNode::~CSendNode() { int c = GetNumChildren(); for ( int i = c - 1 ; i >= 0 ; i-- ) { delete GetChild( i ); } m_Children.Purge(); }
// ----------------------------------------------------------------------------- //
// CSendTablePrecalc
// ----------------------------------------------------------------------------- //
bool PropOffsetLT( const unsigned short &a, const unsigned short &b ) { return a < b; }
CSendTablePrecalc::CSendTablePrecalc() : m_PropOffsetToIndexMap( 0, 0, PropOffsetLT ) { m_pDTITable = NULL; m_pSendTable = 0; m_nDataTableProxies = 0; }
CSendTablePrecalc::~CSendTablePrecalc() { if ( m_pSendTable ) m_pSendTable->m_pPrecalc = 0; }
const ExcludeProp* FindExcludeProp( char const *pTableName, char const *pPropName, const ExcludeProp *pExcludeProps, int nExcludeProps) { for ( int i=0; i < nExcludeProps; i++ ) { if ( stricmp(pExcludeProps[i].m_pTableName, pTableName) == 0 && stricmp(pExcludeProps[i].m_pPropName, pPropName ) == 0 ) return &pExcludeProps[i]; }
return NULL; }
// Fill in a list of all the excluded props.
static bool SendTable_GetPropsExcluded( const SendTable *pTable, ExcludeProp *pExcludeProps, int &nExcludeProps, int nMaxExcludeProps ) { for(int i=0; i < pTable->m_nProps; i++) { SendProp *pProp = &pTable->m_pProps[i];
if ( pProp->IsExcludeProp() ) { char const *pName = pProp->GetExcludeDTName();
ErrorIfNot( pName, ("Found an exclude prop missing a name.") ); ErrorIfNot( nExcludeProps < nMaxExcludeProps, ("SendTable_GetPropsExcluded: Overflowed max exclude props with %s.", pName) );
pExcludeProps[nExcludeProps].m_pTableName = pName; pExcludeProps[nExcludeProps].m_pPropName = pProp->GetName(); nExcludeProps++; } else if ( pProp->GetDataTable() ) { if( !SendTable_GetPropsExcluded( pProp->GetDataTable(), pExcludeProps, nExcludeProps, nMaxExcludeProps ) ) return false; } }
return true; }
// Set the datatable proxy indices in all datatable SendProps.
static void SetDataTableProxyIndices_R( CSendTablePrecalc *pMainTable, CSendNode *pCurTable, CBuildHierarchyStruct *bhs ) { for ( int i=0; i < pCurTable->GetNumChildren(); i++ ) { CSendNode *pNode = pCurTable->GetChild( i ); const SendProp *pProp = bhs->m_pDatatableProps[pNode->m_iDatatableProp];
if ( pProp->GetFlags() & SPROP_PROXY_ALWAYS_YES ) { pNode->SetDataTableProxyIndex( DATATABLE_PROXY_INDEX_NOPROXY ); } else { pNode->SetDataTableProxyIndex( pMainTable->GetNumDataTableProxies() ); pMainTable->SetNumDataTableProxies( pMainTable->GetNumDataTableProxies() + 1 ); }
SetDataTableProxyIndices_R( pMainTable, pNode, bhs ); } }
// Set the datatable proxy indices in all datatable SendProps.
static void SetRecursiveProxyIndices_R( SendTable *pBaseTable, CSendNode *pCurTable, int &iCurProxyIndex ) { if ( iCurProxyIndex >= CDatatableStack::MAX_PROXY_RESULTS ) Error( "Too many proxies for datatable %s.", pBaseTable->GetName() );
pCurTable->SetRecursiveProxyIndex( iCurProxyIndex ); iCurProxyIndex++; for ( int i=0; i < pCurTable->GetNumChildren(); i++ ) { CSendNode *pNode = pCurTable->GetChild( i ); SetRecursiveProxyIndices_R( pBaseTable, pNode, iCurProxyIndex ); } }
void SendTable_BuildHierarchy( CSendNode *pNode, const SendTable *pTable, CBuildHierarchyStruct *bhs );
void SendTable_BuildHierarchy_IterateProps( CSendNode *pNode, const SendTable *pTable, CBuildHierarchyStruct *bhs, const SendProp *pNonDatatableProps[MAX_TOTAL_SENDTABLE_PROPS], int &nNonDatatableProps ) { int i; for ( i=0; i < pTable->m_nProps; i++ ) { const SendProp *pProp = &pTable->m_pProps[i];
if ( pProp->IsExcludeProp() || pProp->IsInsideArray() || FindExcludeProp( pTable->GetName(), pProp->GetName(), bhs->m_pExcludeProps, bhs->m_nExcludeProps ) ) { continue; }
if ( pProp->GetType() == DPT_DataTable ) { if ( pProp->GetFlags() & SPROP_COLLAPSIBLE ) { // This is a base class.. no need to make a new CSendNode (and trigger a bunch of
// unnecessary send proxy calls in the datatable stacks).
SendTable_BuildHierarchy_IterateProps( pNode, pProp->GetDataTable(), bhs, pNonDatatableProps, nNonDatatableProps ); } else { // Setup a child datatable reference.
CSendNode *pChild = new CSendNode;
// Setup a datatable prop for this node to reference (so the recursion
// routines can get at the proxy).
if ( bhs->m_nDatatableProps >= ARRAYSIZE( bhs->m_pDatatableProps ) ) Error( "Overflowed datatable prop list in SendTable '%s'.", pTable->GetName() ); bhs->m_pDatatableProps[bhs->m_nDatatableProps] = pProp; pChild->m_iDatatableProp = bhs->m_nDatatableProps; ++bhs->m_nDatatableProps;
pNode->m_Children.AddToTail( pChild );
// Recurse into the new child datatable.
SendTable_BuildHierarchy( pChild, pProp->GetDataTable(), bhs ); } } else { if ( nNonDatatableProps >= MAX_TOTAL_SENDTABLE_PROPS ) Error( "SendTable_BuildHierarchy: overflowed non-datatable props with '%s'.", pProp->GetName() ); pNonDatatableProps[nNonDatatableProps] = pProp; ++nNonDatatableProps; } } }
void SendTable_BuildHierarchy( CSendNode *pNode, const SendTable *pTable, CBuildHierarchyStruct *bhs ) { pNode->m_pTable = pTable; pNode->m_iFirstRecursiveProp = bhs->m_nProps; if ( bhs->m_nPropProxies >= 255 ) { Error( "Exceeded max number of datatable proxies in SendTable_BuildHierarchy()" ); }
unsigned char curPropProxy = bhs->m_nPropProxies; ++bhs->m_nPropProxies;
const SendProp *pNonDatatableProps[MAX_TOTAL_SENDTABLE_PROPS]; int nNonDatatableProps = 0; // First add all the child datatables.
SendTable_BuildHierarchy_IterateProps( pNode, pTable, bhs, pNonDatatableProps, nNonDatatableProps );
// Now add the properties.
// Make sure there's room, then just copy the pointers from the loop above.
ErrorIfNot( bhs->m_nProps + nNonDatatableProps < ARRAYSIZE( bhs->m_pProps ), ("SendTable_BuildHierarchy: overflowed prop buffer.") ); for ( int i=0; i < nNonDatatableProps; i++ ) { bhs->m_pProps[bhs->m_nProps] = pNonDatatableProps[i]; bhs->m_PropProxyIndices[bhs->m_nProps] = curPropProxy; ++bhs->m_nProps; }
pNode->m_nRecursiveProps = bhs->m_nProps - pNode->m_iFirstRecursiveProp; }
static int __cdecl SendProp_SortPriorities( const byte *p1, const byte *p2 ) { return *p1 > *p2; }
void SendTable_SortByPriority(CBuildHierarchyStruct *bhs) { CUtlVector<byte> priorities;
// Build a list of priorities
// Default entry for SPROP_CHANGES_OFTEN
priorities.AddToTail( SENDPROP_CHANGES_OFTEN_PRIORITY );
for ( int i = 0; i < bhs->m_nProps; i++ ) { const SendProp *p = bhs->m_pProps[i];
if ( priorities.Find( p->GetPriority() ) < 0 ) { priorities.AddToTail( p->GetPriority() ); } }
// We're using this one because CUtlVector::Sort utilizes qsort, which has different behavior on Windows than on Linux
std::stable_sort( priorities.Base(), priorities.Base() + priorities.Count() );
int start = 0;
for ( int priorityIndex = 0; priorityIndex < priorities.Count(); ++priorityIndex ) { byte priority = priorities[priorityIndex]; int i; while( true ) { for ( i = start; i < bhs->m_nProps; i++ ) { const SendProp *p = bhs->m_pProps[i]; unsigned char c = bhs->m_PropProxyIndices[i];
if ( p->GetPriority() == priority || ( ( p->GetFlags() & SPROP_CHANGES_OFTEN ) && priority == SENDPROP_CHANGES_OFTEN_PRIORITY ) ) { if ( i != start ) { bhs->m_pProps[i] = bhs->m_pProps[start]; bhs->m_PropProxyIndices[i] = bhs->m_PropProxyIndices[start]; bhs->m_pProps[start] = p; bhs->m_PropProxyIndices[start] = c; } start++; break; } } if ( i == bhs->m_nProps ) break; } } }
void CalcPathLengths_R( CSendNode *pNode, CUtlVector<int> &pathLengths, int curPathLength, int &totalPathLengths ) { pathLengths[pNode->GetRecursiveProxyIndex()] = curPathLength; totalPathLengths += curPathLength; for ( int i=0; i < pNode->GetNumChildren(); i++ ) { CalcPathLengths_R( pNode->GetChild( i ), pathLengths, curPathLength+1, totalPathLengths ); } }
void FillPathEntries_R( CSendTablePrecalc *pPrecalc, CSendNode *pNode, CSendNode *pParent, int &iCurEntry ) { // Fill in this node's path.
CSendTablePrecalc::CProxyPath &outProxyPath = pPrecalc->m_ProxyPaths[ pNode->GetRecursiveProxyIndex() ]; outProxyPath.m_iFirstEntry = (unsigned short)iCurEntry;
// Copy all the proxies leading to the parent.
if ( pParent ) { CSendTablePrecalc::CProxyPath &parentProxyPath = pPrecalc->m_ProxyPaths[pParent->GetRecursiveProxyIndex()]; outProxyPath.m_nEntries = parentProxyPath.m_nEntries + 1;
for ( int i=0; i < parentProxyPath.m_nEntries; i++ ) pPrecalc->m_ProxyPathEntries[iCurEntry++] = pPrecalc->m_ProxyPathEntries[parentProxyPath.m_iFirstEntry+i]; // Now add this node's own proxy.
pPrecalc->m_ProxyPathEntries[iCurEntry].m_iProxy = pNode->GetRecursiveProxyIndex(); pPrecalc->m_ProxyPathEntries[iCurEntry].m_iDatatableProp = pNode->m_iDatatableProp; ++iCurEntry; } else { outProxyPath.m_nEntries = 0; }
for ( int i=0; i < pNode->GetNumChildren(); i++ ) { FillPathEntries_R( pPrecalc, pNode->GetChild( i ), pNode, iCurEntry ); } }
void SendTable_GenerateProxyPaths( CSendTablePrecalc *pPrecalc, int nProxyIndices ) { // Initialize the array.
pPrecalc->m_ProxyPaths.SetSize( nProxyIndices ); for ( int i=0; i < nProxyIndices; i++ ) pPrecalc->m_ProxyPaths[i].m_iFirstEntry = pPrecalc->m_ProxyPaths[i].m_nEntries = 0xFFFF; // Figure out how long the path down the tree is to each node.
int totalPathLengths = 0; CUtlVector<int> pathLengths; pathLengths.SetSize( nProxyIndices ); memset( pathLengths.Base(), 0, sizeof( pathLengths[0] ) * nProxyIndices ); CalcPathLengths_R( pPrecalc->GetRootNode(), pathLengths, 0, totalPathLengths ); //
int iCurEntry = 0; pPrecalc->m_ProxyPathEntries.SetSize( totalPathLengths ); FillPathEntries_R( pPrecalc, pPrecalc->GetRootNode(), NULL, iCurEntry ); }
bool CSendTablePrecalc::SetupFlatPropertyArray() { SendTable *pTable = GetSendTable();
// First go through and set SPROP_INSIDEARRAY when appropriate, and set array prop pointers.
SetupArrayProps_R<SendTable, SendTable::PropType>( pTable );
// Make a list of which properties are excluded.
ExcludeProp excludeProps[MAX_EXCLUDE_PROPS]; int nExcludeProps = 0; if( !SendTable_GetPropsExcluded( pTable, excludeProps, nExcludeProps, MAX_EXCLUDE_PROPS ) ) return false;
// Now build the hierarchy.
CBuildHierarchyStruct bhs; bhs.m_pExcludeProps = excludeProps; bhs.m_nExcludeProps = nExcludeProps; bhs.m_nProps = bhs.m_nDatatableProps = 0; bhs.m_nPropProxies = 0; SendTable_BuildHierarchy( GetRootNode(), pTable, &bhs );
SendTable_SortByPriority( &bhs );
// Copy the SendProp pointers into the precalc.
MEM_ALLOC_CREDIT(); m_Props.CopyArray( bhs.m_pProps, bhs.m_nProps ); m_DatatableProps.CopyArray( bhs.m_pDatatableProps, bhs.m_nDatatableProps ); m_PropProxyIndices.CopyArray( bhs.m_PropProxyIndices, bhs.m_nProps );
// Assign the datatable proxy indices.
SetNumDataTableProxies( 0 ); SetDataTableProxyIndices_R( this, GetRootNode(), &bhs ); int nProxyIndices = 0; SetRecursiveProxyIndices_R( pTable, GetRootNode(), nProxyIndices );
SendTable_GenerateProxyPaths( this, nProxyIndices );
return true; }
// ---------------------------------------------------------------------------------------- //
// Helpers.
// ---------------------------------------------------------------------------------------- //
// Compares two arrays of bits.
// Returns true if they are equal.
bool AreBitArraysEqual( void const *pvBits1, void const *pvBits2, int nBits ) { int i, nBytes, bit1, bit2;
unsigned char const *pBits1 = (unsigned char*)pvBits1; unsigned char const *pBits2 = (unsigned char*)pvBits2;
// Compare bytes.
nBytes = nBits >> 3; if( memcmp( pBits1, pBits2, nBytes ) != 0 ) return false;
// Compare remaining bits.
for(i=nBytes << 3; i < nBits; i++) { bit1 = pBits1[i >> 3] & (1 << (i & 7)); bit2 = pBits2[i >> 3] & (1 << (i & 7)); if(bit1 != bit2) return false; }
return true; }
// Does a fast memcmp-based test to determine if the two bit arrays are different.
// Returns true if they are equal.
bool CompareBitArrays( void const *pPacked1, void const *pPacked2, int nBits1, int nBits2 ) { if( nBits1 >= 0 && nBits1 == nBits2 ) { if ( pPacked1 == pPacked2 ) { return true; } else { return AreBitArraysEqual( pPacked1, pPacked2, nBits1 ); } } else return false; }
// Looks at the DTWatchEnt and DTWatchProp console variables and returns true
// if the user wants to watch this property.
bool ShouldWatchThisProp( const SendTable *pTable, int objectID, const char *pPropName ) { if ( !g_CV_DTEncode.GetBool() ) { return false; }
if(g_CV_DTWatchEnt.GetInt() != -1 && g_CV_DTWatchEnt.GetInt() == objectID) { const char *pStr = g_CV_DTWatchVar.GetString(); if ( pStr && pStr[0] != 0 ) { return stricmp( pStr, pPropName ) == 0; } else { return true; } }
if ( g_CV_DTWatchClass.GetString()[ 0 ] && Q_stristr( pTable->GetName(), g_CV_DTWatchClass.GetString() ) ) return true;
return false; }
// Looks at the DTWatchEnt and DTWatchProp console variables and returns true
// if the user wants to watch this property.
bool ShouldWatchThisProp( const RecvTable *pTable, int objectID, const char *pPropName ) { if ( !g_CV_DTDecode.GetBool() ) { return false; }
if(g_CV_DTWatchEnt.GetInt() != -1 && g_CV_DTWatchEnt.GetInt() == objectID) { const char *pStr = g_CV_DTWatchVar.GetString(); if ( pStr && pStr[0] != 0 ) { return stricmp( pStr, pPropName ) == 0; } else { return true; } }
if ( g_CV_DTWatchClass.GetString()[ 0 ] && Q_stristr( pTable->GetName(), g_CV_DTWatchClass.GetString() ) ) return true;
return false; }
bool Sendprop_UsingDebugWatch() { if ( g_CV_DTWatchEnt.GetInt() != -1 ) return true;
if ( g_CV_DTWatchClass.GetString()[ 0 ] ) return true;
return false; }
// Prints a datatable warning into the console.
void DataTable_Warning( const char *pInMessage, ... ) { char msg[4096]; va_list marker; #if 0
#if !defined(_DEBUG)
if(!g_CV_DTWarning.GetInt()) return; #endif
#endif
va_start(marker, pInMessage); Q_vsnprintf( msg, sizeof( msg ), pInMessage, marker); va_end(marker);
Warning( "DataTable warning: %s", msg ); }
|