summaryrefslogtreecommitdiff
path: root/engine/LocalNetworkBackdoor.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/LocalNetworkBackdoor.cpp
downloadarchived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz
archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip
Diffstat (limited to 'engine/LocalNetworkBackdoor.cpp')
-rw-r--r--engine/LocalNetworkBackdoor.cpp420
1 files changed, 420 insertions, 0 deletions
diff --git a/engine/LocalNetworkBackdoor.cpp b/engine/LocalNetworkBackdoor.cpp
new file mode 100644
index 0000000..038f965
--- /dev/null
+++ b/engine/LocalNetworkBackdoor.cpp
@@ -0,0 +1,420 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "LocalNetworkBackdoor.h"
+#include "server_class.h"
+#include "client_class.h"
+#include "server.h"
+#include "eiface.h"
+#include "cdll_engine_int.h"
+#include "dt_localtransfer.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CLocalNetworkBackdoor *g_pLocalNetworkBackdoor = NULL;
+
+#ifndef SWDS
+// This is called
+void CLocalNetworkBackdoor::InitFastCopy()
+{
+ if ( !cl.m_NetChannel->IsLoopback() )
+ return;
+
+
+ const CStandardSendProxies *pSendProxies = NULL;
+
+ // If the game server is greater than v4, then it is using the new proxy format.
+ if ( g_iServerGameDLLVersion >= 5 ) // check server version
+ {
+ pSendProxies = serverGameDLL->GetStandardSendProxies();
+ }
+ else
+ {
+ // If the game server is older than v4, it is using the old proxy; we set the new proxy members to the
+ // engine's copy.
+ static CStandardSendProxies compatSendProxy = *serverGameDLL->GetStandardSendProxies();
+
+ compatSendProxy.m_DataTableToDataTable = g_StandardSendProxies.m_DataTableToDataTable;
+ compatSendProxy.m_SendLocalDataTable = g_StandardSendProxies.m_SendLocalDataTable;
+ compatSendProxy.m_ppNonModifiedPointerProxies = g_StandardSendProxies.m_ppNonModifiedPointerProxies;
+
+ pSendProxies = &compatSendProxy;
+ }
+
+ const CStandardRecvProxies *pRecvProxies = g_ClientDLL->GetStandardRecvProxies();
+
+ int nFastCopyProps = 0;
+ int nSlowCopyProps = 0;
+
+ for ( int iClass=0; iClass < cl.m_nServerClasses; iClass++ )
+ {
+ ClientClass *pClientClass = cl.GetClientClass(iClass);
+ if ( !pClientClass )
+ Error( "InitFastCopy - missing client class %d (Should be equivelent of server class: %s)", iClass, cl.m_pServerClasses[iClass].m_ClassName );
+
+ ServerClass *pServerClass = SV_FindServerClass( pClientClass->GetName() );
+ if ( !pServerClass )
+ Error( "InitFastCopy - missing server class %s", pClientClass->GetName() );
+
+ LocalTransfer_InitFastCopy(
+ pServerClass->m_pTable,
+ pSendProxies,
+ pClientClass->m_pRecvTable,
+ pRecvProxies,
+ nSlowCopyProps,
+ nFastCopyProps
+ );
+ }
+
+ int percentFast = (nFastCopyProps * 100 ) / (nSlowCopyProps + nFastCopyProps + 1);
+ if ( percentFast <= 55 )
+ {
+ // This may not be a real problem, but at the time this code was added, 67% of the
+ // properties were able to be copied without proxies. If percentFast goes to 0 or some
+ // really low number suddenly, then something probably got screwed up.
+ Assert( false );
+ Warning( "InitFastCopy: only %d%% fast props. Bug?\n", percentFast );
+ }
+}
+#endif
+
+void CLocalNetworkBackdoor::StartEntityStateUpdate()
+{
+ m_EntsAlive.ClearAll();
+ m_nEntsCreated = 0;
+ m_nEntsChanged = 0;
+
+ // signal client that we start updating entities
+ ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_START );
+}
+
+void CLocalNetworkBackdoor::EndEntityStateUpdate()
+{
+ ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_START );
+
+ // Handle entities created.
+ int i;
+ for ( i=0; i < m_nEntsCreated; i++ )
+ {
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iEdict = m_EntsCreatedIndices[i];
+ CCachedEntState *pCached = &m_CachedEntState[iEdict];
+ IClientNetworkable *pNet = pCached->m_pNetworkable;
+
+ pNet->PostDataUpdate( DATA_UPDATE_CREATED );
+ pNet->NotifyShouldTransmit( SHOULDTRANSMIT_START );
+ pCached->m_bDormant = false;
+ }
+
+ // Handle entities changed.
+ for ( i=0; i < m_nEntsChanged; i++ )
+ {
+ MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
+
+ int iEdict = m_EntsChangedIndices[i];
+ m_CachedEntState[iEdict].m_pNetworkable->PostDataUpdate( DATA_UPDATE_DATATABLE_CHANGED );
+ }
+
+ ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_POSTDATAUPDATE_END );
+
+ // Handle entities removed (= SV_WriteDeletions() in normal mode)
+ int nDWords = m_PrevEntsAlive.GetNumDWords();
+
+ // Handle entities removed.
+ for ( i=0; i < nDWords; i++ )
+ {
+ unsigned long prevEntsAlive = m_PrevEntsAlive.GetDWord( i );
+ unsigned long entsAlive = m_EntsAlive.GetDWord( i );
+ unsigned long toDelete = (prevEntsAlive ^ entsAlive) & prevEntsAlive;
+
+ if ( toDelete )
+ {
+ for ( int iBit=0; iBit < 32; iBit++ )
+ {
+ if ( toDelete & (1 << iBit) )
+ {
+ int iEdict = (i<<5) + iBit;
+ if ( iEdict >= 0 && iEdict < MAX_EDICTS )
+ {
+ if ( m_CachedEntState[iEdict].m_pNetworkable )
+ {
+ m_CachedEntState[iEdict].m_pNetworkable->Release();
+ m_CachedEntState[iEdict].m_pNetworkable = NULL;
+ }
+ else
+ {
+ AssertOnce( !"EndEntityStateUpdate: Would have crashed with NULL m_pNetworkable\n" );
+ }
+ }
+ else
+ {
+ AssertOnce( !"EndEntityStateUpdate: Would have crashed with entity out of range\n" );
+ }
+ }
+ }
+ }
+ }
+
+ // Remember the previous state of which entities were around.
+ m_PrevEntsAlive = m_EntsAlive;
+
+ // end of all entity update activity
+ ClientDLL_FrameStageNotify( FRAME_NET_UPDATE_END );
+
+ /*
+ #ifdef _DEBUG
+ for ( i=0; i <= highest_index; i++ )
+ {
+ if ( !( m_EntsAlive[i>>5] & (1 << (i & 31)) ) )
+ Assert( !m_CachedEntState[i].m_pNetworkable );
+
+ if ( ( m_EntsAlive[i>>5] & (1 << (i & 31)) ) &&
+ ( m_EntsCreated[i>>5] & (1 << (i & 31)) ) )
+ {
+ Assert( FindInList( m_EntsCreatedIndices, m_nEntsCreated, i ) );
+ }
+
+ if ( (m_EntsAlive[i>>5] & (1 << (i & 31))) &&
+ !(m_EntsCreated[i>>5] & (1 << (i & 31))) &&
+ (m_EntsChanged[i>>5] & (1 << (i & 31)))
+ )
+ {
+ Assert( FindInList( m_EntsChangedIndices, m_nEntsChanged, i ) );
+ }
+ }
+ #endif
+ */
+}
+
+void CLocalNetworkBackdoor::EntityDormant( int iEnt, int iSerialNum )
+{
+ CCachedEntState *pCached = &m_CachedEntState[iEnt];
+
+ IClientNetworkable *pNet = pCached->m_pNetworkable;
+ Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
+ if ( pNet )
+ {
+ Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
+ if ( pCached->m_iSerialNumber == iSerialNum )
+ {
+ m_EntsAlive.Set( iEnt );
+
+ // Tell the game code that this guy is now dormant.
+ Assert( pCached->m_bDormant == pNet->IsDormant() );
+ if ( !pCached->m_bDormant )
+ {
+ pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
+ pCached->m_bDormant = true;
+ }
+ }
+ else
+ {
+ pNet->Release();
+ pCached->m_pNetworkable = NULL;
+ m_PrevEntsAlive.Clear( iEnt );
+ }
+ }
+}
+
+
+void CLocalNetworkBackdoor::AddToPendingDormantEntityList( unsigned short iEdict )
+{
+ edict_t *e = &sv.edicts[iEdict];
+ if ( !( e->m_fStateFlags & FL_EDICT_PENDING_DORMANT_CHECK ) )
+ {
+ e->m_fStateFlags |= FL_EDICT_PENDING_DORMANT_CHECK;
+ m_PendingDormantEntities.AddToTail( iEdict );
+ }
+}
+
+void CLocalNetworkBackdoor::ProcessDormantEntities()
+{
+ FOR_EACH_LL( m_PendingDormantEntities, i )
+ {
+ int iEdict = m_PendingDormantEntities[i];
+ edict_t *e = &sv.edicts[iEdict];
+
+ // Make sure the entity still exists and stil has the dontsend flag set.
+ if ( e->IsFree() || !(e->m_fStateFlags & FL_EDICT_DONTSEND) )
+ {
+ e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
+ continue;
+ }
+
+ EntityDormant( iEdict, e->m_NetworkSerialNumber );
+ e->m_fStateFlags &= ~FL_EDICT_PENDING_DORMANT_CHECK;
+ }
+ m_PendingDormantEntities.Purge();
+}
+
+void CLocalNetworkBackdoor::EntState(
+ int iEnt,
+ int iSerialNum,
+ int iClass,
+ const SendTable *pSendTable,
+ const void *pSourceEnt,
+ bool bChanged,
+ bool bShouldTransmit )
+{
+ CCachedEntState *pCached = &m_CachedEntState[iEnt];
+
+ // Remember that this ent is alive.
+ m_EntsAlive.Set(iEnt);
+
+ ClientClass *pClientClass = cl.GetClientClass(iClass);
+ if ( !pClientClass )
+ Error( "CLocalNetworkBackdoor::EntState - missing client class %d", iClass );
+
+ IClientNetworkable *pNet = pCached->m_pNetworkable;
+ Assert( pNet == entitylist->GetClientNetworkable( iEnt ) );
+
+ if ( !bShouldTransmit )
+ {
+ if ( pNet )
+ {
+ Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
+ if ( pCached->m_iSerialNumber == iSerialNum )
+ {
+ // Tell the game code that this guy is now dormant.
+ Assert( pCached->m_bDormant == pNet->IsDormant() );
+ if ( !pCached->m_bDormant )
+ {
+ pNet->NotifyShouldTransmit( SHOULDTRANSMIT_END );
+ pCached->m_bDormant = true;
+ }
+ }
+ else
+ {
+ pNet->Release();
+ pNet = NULL;
+ pCached->m_pNetworkable = NULL;
+ // Since we set this above, need to clear it now to avoid assertion in EndEntityStateUpdate()
+ m_EntsAlive.Clear(iEnt);
+ m_PrevEntsAlive.Clear( iEnt );
+ }
+ }
+ else
+ {
+ m_EntsAlive.Clear( iEnt );
+ }
+ return;
+ }
+ // Do we have an entity here already?
+ bool bExistedAndWasDormant = false;
+ if ( pNet )
+ {
+ // If the serial numbers are different, make it recreate the ent.
+ Assert( pCached->m_iSerialNumber == pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber() );
+ if ( iSerialNum == pCached->m_iSerialNumber )
+ {
+ bExistedAndWasDormant = pCached->m_bDormant;
+ }
+ else
+ {
+ pNet->Release();
+ pNet = NULL;
+ m_PrevEntsAlive.Clear(iEnt);
+ }
+ }
+
+ // Create the entity?
+ bool bCreated = false;
+ DataUpdateType_t updateType;
+ if ( pNet )
+ {
+ updateType = DATA_UPDATE_DATATABLE_CHANGED;
+ }
+ else
+ {
+ updateType = DATA_UPDATE_CREATED;
+ pNet = pClientClass->m_pCreateFn( iEnt, iSerialNum );
+ bCreated = true;
+ m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
+
+ pCached->m_iSerialNumber = iSerialNum;
+ pCached->m_pDataPointer = pNet->GetDataTableBasePtr();
+ pCached->m_pNetworkable = pNet;
+ // Tracker 73192: ywb 8/1/07: We used to get an assertion that the pCached->m_bDormant was not equal to pNet->IsDormant() in ProcessDormantEntities.
+ // This appears to be the case if when we get here, the entity is set for Transmit still, but is a dormant entity on the server.
+ // Seems safe to go ahead an fill in the cache with the correct data. Probably was just an oversight.
+ pCached->m_bDormant = pNet->IsDormant();
+ }
+
+ if ( bChanged || bCreated || bExistedAndWasDormant )
+ {
+ pNet->PreDataUpdate( updateType );
+
+ Assert( pCached->m_pDataPointer == pNet->GetDataTableBasePtr() );
+
+ LocalTransfer_TransferEntity(
+ &sv.edicts[iEnt],
+ pSendTable,
+ pSourceEnt,
+ pClientClass->m_pRecvTable,
+ pCached->m_pDataPointer,
+ bCreated,
+ bExistedAndWasDormant,
+ iEnt );
+
+ if ( bExistedAndWasDormant )
+ {
+ // Set this so we use DATA_UPDATE_CREATED logic
+ m_EntsCreatedIndices[m_nEntsCreated++] = iEnt;
+ }
+ else
+ {
+ if ( !bCreated )
+ {
+ m_EntsChangedIndices[m_nEntsChanged++] = iEnt;
+ }
+ }
+ }
+}
+
+
+void CLocalNetworkBackdoor::ClearState()
+{
+ // Clear the cache for all the entities.
+ for ( int i=0; i < MAX_EDICTS; i++ )
+ {
+ CCachedEntState &ces = m_CachedEntState[i];
+
+ ces.m_pNetworkable = NULL;
+ ces.m_iSerialNumber = -1;
+ ces.m_bDormant = false;
+ ces.m_pDataPointer = NULL;
+ }
+
+ m_PrevEntsAlive.ClearAll();
+}
+
+void CLocalNetworkBackdoor::StartBackdoorMode()
+{
+ ClearState();
+
+ for ( int i=0; i < MAX_EDICTS; i++ )
+ {
+ IClientNetworkable *pNet = entitylist->GetClientNetworkable( i );
+
+ CCachedEntState &ces = m_CachedEntState[i];
+
+ if ( pNet )
+ {
+ ces.m_pNetworkable = pNet;
+ ces.m_iSerialNumber = pNet->GetIClientUnknown()->GetRefEHandle().GetSerialNumber();
+ ces.m_bDormant = pNet->IsDormant();
+ ces.m_pDataPointer = pNet->GetDataTableBasePtr();
+ m_PrevEntsAlive.Set( i );
+ }
+ }
+}
+
+void CLocalNetworkBackdoor::StopBackdoorMode()
+{
+ ClearState();
+}
+