summaryrefslogtreecommitdiff
path: root/engine/dt.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/dt.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/dt.cpp')
-rw-r--r--engine/dt.cpp567
1 files changed, 567 insertions, 0 deletions
diff --git a/engine/dt.cpp b/engine/dt.cpp
new file mode 100644
index 0000000..f97b249
--- /dev/null
+++ b/engine/dt.cpp
@@ -0,0 +1,567 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#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"
+
+// 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)
+
+
+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." );
+
+
+
+// ----------------------------------------------------------------------------- //
+//
+// 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;
+};
+
+
+// ----------------------------------------------------------------------------- //
+// 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;
+
+ Assert( bhs->m_nPropProxies < 255 );
+ 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;
+}
+
+void SendTable_SortByPriority(CBuildHierarchyStruct *bhs)
+{
+ int i, start = 0;
+
+ 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->GetFlags() & SPROP_CHANGES_OFTEN )
+ {
+ 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 )
+ return;
+ }
+}
+
+
+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 )
+{
+ unsigned int const *pBits1 = (unsigned int const *)pvBits1;
+ unsigned int const *pBits2 = (unsigned int const *)pvBits2;
+
+ // Compare words.
+ int nWords = nBits >> 5;
+ for ( int i = 0 ; i < nWords; ++i )
+ {
+ if ( pBits1[i] != pBits2[i] )
+ return false;
+ }
+
+ if ( nBits & 31 )
+ {
+ // Compare remaining bits.
+ unsigned int mask = (1 << (nBits & 31)) - 1;
+ return ((pBits1[nWords] ^ pBits2[nWords]) & mask) == 0;
+ }
+
+ 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_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 );
+}
+
+
+
+
+
+
+