aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/client_thinklist.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/client_thinklist.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/client_thinklist.cpp')
-rw-r--r--mp/src/game/client/client_thinklist.cpp804
1 files changed, 402 insertions, 402 deletions
diff --git a/mp/src/game/client/client_thinklist.cpp b/mp/src/game/client/client_thinklist.cpp
index 07a77784..eae2d880 100644
--- a/mp/src/game/client/client_thinklist.cpp
+++ b/mp/src/game/client/client_thinklist.cpp
@@ -1,402 +1,402 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-
-#include "tier0/vprof.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-CClientThinkList g_ClientThinkList;
-
-
-CClientThinkList::CClientThinkList()
-{
-}
-
-
-CClientThinkList::~CClientThinkList()
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// Methods of IGameSystem
-//-----------------------------------------------------------------------------
-bool CClientThinkList::Init()
-{
- m_nIterEnum = 0;
- m_bInThinkLoop = false;
- return true;
-}
-
-
-void CClientThinkList::Shutdown()
-{
-}
-
-
-void CClientThinkList::LevelInitPreEntity()
-{
- m_nIterEnum = 0;
-}
-
-void CClientThinkList::LevelShutdownPreEntity()
-{
-}
-
-
-void CClientThinkList::LevelShutdownPostEntity()
-{
-}
-
-
-void CClientThinkList::PreRender()
-{
-}
-
-
-void CClientThinkList::Update( float frametime )
-{
-}
-
-
-//-----------------------------------------------------------------------------
-// Sets the client think
-//-----------------------------------------------------------------------------
-void CClientThinkList::SetNextClientThink( ClientThinkHandle_t hThink, float flNextTime )
-{
- if ( hThink == INVALID_THINK_HANDLE )
- return;
-
- if ( m_bInThinkLoop )
- {
- // Queue up all changes
- int i = m_aChangeList.AddToTail();
- m_aChangeList[i].m_hEnt = INVALID_CLIENTENTITY_HANDLE;
- m_aChangeList[i].m_hThink = hThink;
- m_aChangeList[i].m_flNextTime = flNextTime;
- return;
- }
-
- if ( flNextTime == CLIENT_THINK_NEVER )
- {
- RemoveThinkable( hThink );
- }
- else
- {
- GetThinkEntry( hThink )->m_flNextClientThink = flNextTime;
- }
-}
-
-void CClientThinkList::SetNextClientThink( ClientEntityHandle_t hEnt, float flNextTime )
-{
- if ( flNextTime == CLIENT_THINK_NEVER )
- {
- RemoveThinkable( hEnt );
- return;
- }
-
- IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt );
- if ( !pThink )
- return;
-
- ClientThinkHandle_t hThink = pThink->GetThinkHandle();
-
- if ( m_bInThinkLoop )
- {
- // Queue up all changes
- int i = m_aChangeList.AddToTail();
- m_aChangeList[i].m_hEnt = hEnt;
- m_aChangeList[i].m_hThink = hThink;
- m_aChangeList[i].m_flNextTime = flNextTime;
- return;
- }
-
- // Add it to the list if it's not already in there.
- if ( hThink == INVALID_THINK_HANDLE )
- {
- hThink = (ClientThinkHandle_t)(uintp)m_ThinkEntries.AddToTail();
- pThink->SetThinkHandle( hThink );
-
- ThinkEntry_t *pEntry = GetThinkEntry( hThink );
- pEntry->m_hEnt = hEnt;
- pEntry->m_nIterEnum = -1;
- pEntry->m_flLastClientThink = 0.0f;
- }
-
- Assert( GetThinkEntry( hThink )->m_hEnt == hEnt );
- GetThinkEntry( hThink )->m_flNextClientThink = flNextTime;
-}
-
-
-//-----------------------------------------------------------------------------
-// Removes the thinkable from the list
-//-----------------------------------------------------------------------------
-void CClientThinkList::RemoveThinkable( ClientThinkHandle_t hThink )
-{
- if ( hThink == INVALID_THINK_HANDLE )
- return;
-
- if ( m_bInThinkLoop )
- {
- // Queue up all changes
- int i = m_aChangeList.AddToTail();
- m_aChangeList[i].m_hEnt = INVALID_CLIENTENTITY_HANDLE;
- m_aChangeList[i].m_hThink = hThink;
- m_aChangeList[i].m_flNextTime = CLIENT_THINK_NEVER;
- return;
- }
-
- ThinkEntry_t *pEntry = GetThinkEntry( hThink );
- IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( pEntry->m_hEnt );
- if ( pThink )
- {
- pThink->SetThinkHandle( INVALID_THINK_HANDLE );
- }
- m_ThinkEntries.Remove( (unsigned long)hThink );
-}
-
-
-//-----------------------------------------------------------------------------
-// Removes the thinkable from the list
-//-----------------------------------------------------------------------------
-void CClientThinkList::RemoveThinkable( ClientEntityHandle_t hEnt )
-{
- IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt );
- if ( pThink )
- {
- ClientThinkHandle_t hThink = pThink->GetThinkHandle();
- if ( hThink != INVALID_THINK_HANDLE )
- {
- Assert( GetThinkEntry( hThink )->m_hEnt == hEnt );
- RemoveThinkable( hThink );
- }
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Performs the think function
-//-----------------------------------------------------------------------------
-void CClientThinkList::PerformThinkFunction( ThinkEntry_t *pEntry, float flCurtime )
-{
- IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( pEntry->m_hEnt );
- if ( !pThink )
- {
- RemoveThinkable( pEntry->m_hEnt );
- return;
- }
-
- if ( pEntry->m_flNextClientThink == CLIENT_THINK_ALWAYS )
- {
- // NOTE: The Think function here could call SetNextClientThink
- // which would cause it to be removed + readded into the list
- pThink->ClientThink();
- }
- else if ( pEntry->m_flNextClientThink == FLT_MAX )
- {
- // This is an entity that doesn't need to think again; remove it
- RemoveThinkable( pEntry->m_hEnt );
- }
- else
- {
- Assert( pEntry->m_flNextClientThink <= flCurtime );
-
- // Indicate we're not going to think again
- pEntry->m_flNextClientThink = FLT_MAX;
-
- // NOTE: The Think function here could call SetNextClientThink
- // which would cause it to be readded into the list
- pThink->ClientThink();
- }
-
- // Set this after the Think calls in case they look at LastClientThink
- pEntry->m_flLastClientThink = flCurtime;
-}
-
-
-//-----------------------------------------------------------------------------
-// Add entity to frame think list
-//-----------------------------------------------------------------------------
-void CClientThinkList::AddEntityToFrameThinkList( ThinkEntry_t *pEntry, bool bAlwaysChain, int &nCount, ThinkEntry_t **ppFrameThinkList )
-{
- // We may already have processed this owing to hierarchy rules
- if ( pEntry->m_nIterEnum == m_nIterEnum )
- return;
-
- // If we're not thinking this frame, we don't have to worry about thinking after our parents
- bool bThinkThisInterval = ( pEntry->m_flNextClientThink == CLIENT_THINK_ALWAYS ) ||
- ( pEntry->m_flNextClientThink <= gpGlobals->curtime );
-
- // This logic makes it so that if a child thinks,
- // *all* hierarchical parents + grandparents will think first, even if some
- // of the parents don't need to think this frame
- if ( !bThinkThisInterval && !bAlwaysChain )
- return;
-
- // Respect hierarchy
- C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( pEntry->m_hEnt );
- if ( pEntity )
- {
- C_BaseEntity *pParent = pEntity->GetMoveParent();
- if ( pParent && (pParent->GetThinkHandle() != INVALID_THINK_HANDLE) )
- {
- ThinkEntry_t *pParentEntry = GetThinkEntry( pParent->GetThinkHandle() );
- AddEntityToFrameThinkList( pParentEntry, true, nCount, ppFrameThinkList );
- }
- }
-
- if ( !bThinkThisInterval )
- return;
-
- // Add the entry into the list
- pEntry->m_nIterEnum = m_nIterEnum;
- ppFrameThinkList[nCount++] = pEntry;
-}
-
-
-//-----------------------------------------------------------------------------
-// Think for all entities that need it
-//-----------------------------------------------------------------------------
-void CClientThinkList::PerformThinkFunctions()
-{
- VPROF_("Client Thinks", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
-
- int nMaxList = m_ThinkEntries.Count();
- if ( nMaxList == 0 )
- return;
-
- ++m_nIterEnum;
-
- // Build a list of entities to think this frame, in order of hierarchy.
- // Do this because the list may be modified during the thinking and also to
- // prevent bad situations where an entity can think more than once in a frame.
- ThinkEntry_t **ppThinkEntryList = (ThinkEntry_t**)stackalloc( nMaxList * sizeof(ThinkEntry_t*) );
- int nThinkCount = 0;
- for ( unsigned short iCur=m_ThinkEntries.Head(); iCur != m_ThinkEntries.InvalidIndex(); iCur = m_ThinkEntries.Next( iCur ) )
- {
- AddEntityToFrameThinkList( &m_ThinkEntries[iCur], false, nThinkCount, ppThinkEntryList );
- Assert( nThinkCount <= nMaxList );
- }
-
- // While we're in the loop, no changes to the think list are allowed
- m_bInThinkLoop = true;
-
- // Perform thinks on all entities that need it
- int i;
- for ( i = 0; i < nThinkCount; ++i )
- {
- PerformThinkFunction( ppThinkEntryList[i], gpGlobals->curtime );
- }
-
- m_bInThinkLoop = false;
-
- // Apply changes to the think list
- int nCount = m_aChangeList.Count();
- for ( i = 0; i < nCount; ++i )
- {
- ClientThinkHandle_t hThink = m_aChangeList[i].m_hThink;
- if ( hThink != INVALID_THINK_HANDLE )
- {
- // This can happen if the same think handle was removed twice
- if ( !m_ThinkEntries.IsInList( (unsigned long)hThink ) )
- continue;
-
- // NOTE: This is necessary for the case where the client entity handle
- // is slammed to NULL during a think interval; the hThink will get stuck
- // in the list and can never leave.
- SetNextClientThink( hThink, m_aChangeList[i].m_flNextTime );
- }
- else
- {
- SetNextClientThink( m_aChangeList[i].m_hEnt, m_aChangeList[i].m_flNextTime );
- }
- }
- m_aChangeList.RemoveAll();
-
- // Clear out the client-side entity deletion list.
- CleanUpDeleteList();
-}
-
-
-//-----------------------------------------------------------------------------
-// Queued-up entity deletion
-//-----------------------------------------------------------------------------
-void CClientThinkList::AddToDeleteList( ClientEntityHandle_t hEnt )
-{
- // Sanity check!
- Assert( hEnt != ClientEntityList().InvalidHandle() );
- if ( hEnt == ClientEntityList().InvalidHandle() )
- return;
-
- // Check to see if entity is networkable -- don't let it release!
- C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( hEnt );
- if ( pEntity )
- {
- // Check to see if the entity is already being removed!
- if ( pEntity->IsMarkedForDeletion() )
- return;
-
- // Don't add networkable entities to delete list -- the server should
- // take care of this. The delete list is for client-side only entities.
- if ( !pEntity->GetClientNetworkable() )
- {
- m_aDeleteList.AddToTail( hEnt );
- pEntity->SetRemovalFlag( true );
- }
- }
-}
-
-void CClientThinkList::RemoveFromDeleteList( ClientEntityHandle_t hEnt )
-{
- // Sanity check!
- Assert( hEnt != ClientEntityList().InvalidHandle() );
- if ( hEnt == ClientEntityList().InvalidHandle() )
- return;
-
- int nSize = m_aDeleteList.Count();
- for ( int iHandle = 0; iHandle < nSize; ++iHandle )
- {
- if ( m_aDeleteList[iHandle] == hEnt )
- {
- m_aDeleteList[iHandle] = ClientEntityList().InvalidHandle();
-
- C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( hEnt );
- if ( pEntity )
- {
- pEntity->SetRemovalFlag( false );
- }
- }
- }
-}
-
-void CClientThinkList::CleanUpDeleteList()
-{
- int nThinkCount = m_aDeleteList.Count();
- for ( int iThink = 0; iThink < nThinkCount; ++iThink )
- {
- ClientEntityHandle_t handle = m_aDeleteList[iThink];
- if ( handle != ClientEntityList().InvalidHandle() )
- {
- C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( handle );
- if ( pEntity )
- {
- pEntity->SetRemovalFlag( false );
- }
-
- IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( handle );
- if ( pThink )
- {
- pThink->Release();
- }
- }
- }
-
- m_aDeleteList.RemoveAll();
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+
+#include "tier0/vprof.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CClientThinkList g_ClientThinkList;
+
+
+CClientThinkList::CClientThinkList()
+{
+}
+
+
+CClientThinkList::~CClientThinkList()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Methods of IGameSystem
+//-----------------------------------------------------------------------------
+bool CClientThinkList::Init()
+{
+ m_nIterEnum = 0;
+ m_bInThinkLoop = false;
+ return true;
+}
+
+
+void CClientThinkList::Shutdown()
+{
+}
+
+
+void CClientThinkList::LevelInitPreEntity()
+{
+ m_nIterEnum = 0;
+}
+
+void CClientThinkList::LevelShutdownPreEntity()
+{
+}
+
+
+void CClientThinkList::LevelShutdownPostEntity()
+{
+}
+
+
+void CClientThinkList::PreRender()
+{
+}
+
+
+void CClientThinkList::Update( float frametime )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the client think
+//-----------------------------------------------------------------------------
+void CClientThinkList::SetNextClientThink( ClientThinkHandle_t hThink, float flNextTime )
+{
+ if ( hThink == INVALID_THINK_HANDLE )
+ return;
+
+ if ( m_bInThinkLoop )
+ {
+ // Queue up all changes
+ int i = m_aChangeList.AddToTail();
+ m_aChangeList[i].m_hEnt = INVALID_CLIENTENTITY_HANDLE;
+ m_aChangeList[i].m_hThink = hThink;
+ m_aChangeList[i].m_flNextTime = flNextTime;
+ return;
+ }
+
+ if ( flNextTime == CLIENT_THINK_NEVER )
+ {
+ RemoveThinkable( hThink );
+ }
+ else
+ {
+ GetThinkEntry( hThink )->m_flNextClientThink = flNextTime;
+ }
+}
+
+void CClientThinkList::SetNextClientThink( ClientEntityHandle_t hEnt, float flNextTime )
+{
+ if ( flNextTime == CLIENT_THINK_NEVER )
+ {
+ RemoveThinkable( hEnt );
+ return;
+ }
+
+ IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt );
+ if ( !pThink )
+ return;
+
+ ClientThinkHandle_t hThink = pThink->GetThinkHandle();
+
+ if ( m_bInThinkLoop )
+ {
+ // Queue up all changes
+ int i = m_aChangeList.AddToTail();
+ m_aChangeList[i].m_hEnt = hEnt;
+ m_aChangeList[i].m_hThink = hThink;
+ m_aChangeList[i].m_flNextTime = flNextTime;
+ return;
+ }
+
+ // Add it to the list if it's not already in there.
+ if ( hThink == INVALID_THINK_HANDLE )
+ {
+ hThink = (ClientThinkHandle_t)(uintp)m_ThinkEntries.AddToTail();
+ pThink->SetThinkHandle( hThink );
+
+ ThinkEntry_t *pEntry = GetThinkEntry( hThink );
+ pEntry->m_hEnt = hEnt;
+ pEntry->m_nIterEnum = -1;
+ pEntry->m_flLastClientThink = 0.0f;
+ }
+
+ Assert( GetThinkEntry( hThink )->m_hEnt == hEnt );
+ GetThinkEntry( hThink )->m_flNextClientThink = flNextTime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes the thinkable from the list
+//-----------------------------------------------------------------------------
+void CClientThinkList::RemoveThinkable( ClientThinkHandle_t hThink )
+{
+ if ( hThink == INVALID_THINK_HANDLE )
+ return;
+
+ if ( m_bInThinkLoop )
+ {
+ // Queue up all changes
+ int i = m_aChangeList.AddToTail();
+ m_aChangeList[i].m_hEnt = INVALID_CLIENTENTITY_HANDLE;
+ m_aChangeList[i].m_hThink = hThink;
+ m_aChangeList[i].m_flNextTime = CLIENT_THINK_NEVER;
+ return;
+ }
+
+ ThinkEntry_t *pEntry = GetThinkEntry( hThink );
+ IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( pEntry->m_hEnt );
+ if ( pThink )
+ {
+ pThink->SetThinkHandle( INVALID_THINK_HANDLE );
+ }
+ m_ThinkEntries.Remove( (unsigned long)hThink );
+}
+
+
+//-----------------------------------------------------------------------------
+// Removes the thinkable from the list
+//-----------------------------------------------------------------------------
+void CClientThinkList::RemoveThinkable( ClientEntityHandle_t hEnt )
+{
+ IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt );
+ if ( pThink )
+ {
+ ClientThinkHandle_t hThink = pThink->GetThinkHandle();
+ if ( hThink != INVALID_THINK_HANDLE )
+ {
+ Assert( GetThinkEntry( hThink )->m_hEnt == hEnt );
+ RemoveThinkable( hThink );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Performs the think function
+//-----------------------------------------------------------------------------
+void CClientThinkList::PerformThinkFunction( ThinkEntry_t *pEntry, float flCurtime )
+{
+ IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( pEntry->m_hEnt );
+ if ( !pThink )
+ {
+ RemoveThinkable( pEntry->m_hEnt );
+ return;
+ }
+
+ if ( pEntry->m_flNextClientThink == CLIENT_THINK_ALWAYS )
+ {
+ // NOTE: The Think function here could call SetNextClientThink
+ // which would cause it to be removed + readded into the list
+ pThink->ClientThink();
+ }
+ else if ( pEntry->m_flNextClientThink == FLT_MAX )
+ {
+ // This is an entity that doesn't need to think again; remove it
+ RemoveThinkable( pEntry->m_hEnt );
+ }
+ else
+ {
+ Assert( pEntry->m_flNextClientThink <= flCurtime );
+
+ // Indicate we're not going to think again
+ pEntry->m_flNextClientThink = FLT_MAX;
+
+ // NOTE: The Think function here could call SetNextClientThink
+ // which would cause it to be readded into the list
+ pThink->ClientThink();
+ }
+
+ // Set this after the Think calls in case they look at LastClientThink
+ pEntry->m_flLastClientThink = flCurtime;
+}
+
+
+//-----------------------------------------------------------------------------
+// Add entity to frame think list
+//-----------------------------------------------------------------------------
+void CClientThinkList::AddEntityToFrameThinkList( ThinkEntry_t *pEntry, bool bAlwaysChain, int &nCount, ThinkEntry_t **ppFrameThinkList )
+{
+ // We may already have processed this owing to hierarchy rules
+ if ( pEntry->m_nIterEnum == m_nIterEnum )
+ return;
+
+ // If we're not thinking this frame, we don't have to worry about thinking after our parents
+ bool bThinkThisInterval = ( pEntry->m_flNextClientThink == CLIENT_THINK_ALWAYS ) ||
+ ( pEntry->m_flNextClientThink <= gpGlobals->curtime );
+
+ // This logic makes it so that if a child thinks,
+ // *all* hierarchical parents + grandparents will think first, even if some
+ // of the parents don't need to think this frame
+ if ( !bThinkThisInterval && !bAlwaysChain )
+ return;
+
+ // Respect hierarchy
+ C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( pEntry->m_hEnt );
+ if ( pEntity )
+ {
+ C_BaseEntity *pParent = pEntity->GetMoveParent();
+ if ( pParent && (pParent->GetThinkHandle() != INVALID_THINK_HANDLE) )
+ {
+ ThinkEntry_t *pParentEntry = GetThinkEntry( pParent->GetThinkHandle() );
+ AddEntityToFrameThinkList( pParentEntry, true, nCount, ppFrameThinkList );
+ }
+ }
+
+ if ( !bThinkThisInterval )
+ return;
+
+ // Add the entry into the list
+ pEntry->m_nIterEnum = m_nIterEnum;
+ ppFrameThinkList[nCount++] = pEntry;
+}
+
+
+//-----------------------------------------------------------------------------
+// Think for all entities that need it
+//-----------------------------------------------------------------------------
+void CClientThinkList::PerformThinkFunctions()
+{
+ VPROF_("Client Thinks", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT);
+
+ int nMaxList = m_ThinkEntries.Count();
+ if ( nMaxList == 0 )
+ return;
+
+ ++m_nIterEnum;
+
+ // Build a list of entities to think this frame, in order of hierarchy.
+ // Do this because the list may be modified during the thinking and also to
+ // prevent bad situations where an entity can think more than once in a frame.
+ ThinkEntry_t **ppThinkEntryList = (ThinkEntry_t**)stackalloc( nMaxList * sizeof(ThinkEntry_t*) );
+ int nThinkCount = 0;
+ for ( unsigned short iCur=m_ThinkEntries.Head(); iCur != m_ThinkEntries.InvalidIndex(); iCur = m_ThinkEntries.Next( iCur ) )
+ {
+ AddEntityToFrameThinkList( &m_ThinkEntries[iCur], false, nThinkCount, ppThinkEntryList );
+ Assert( nThinkCount <= nMaxList );
+ }
+
+ // While we're in the loop, no changes to the think list are allowed
+ m_bInThinkLoop = true;
+
+ // Perform thinks on all entities that need it
+ int i;
+ for ( i = 0; i < nThinkCount; ++i )
+ {
+ PerformThinkFunction( ppThinkEntryList[i], gpGlobals->curtime );
+ }
+
+ m_bInThinkLoop = false;
+
+ // Apply changes to the think list
+ int nCount = m_aChangeList.Count();
+ for ( i = 0; i < nCount; ++i )
+ {
+ ClientThinkHandle_t hThink = m_aChangeList[i].m_hThink;
+ if ( hThink != INVALID_THINK_HANDLE )
+ {
+ // This can happen if the same think handle was removed twice
+ if ( !m_ThinkEntries.IsInList( (unsigned long)hThink ) )
+ continue;
+
+ // NOTE: This is necessary for the case where the client entity handle
+ // is slammed to NULL during a think interval; the hThink will get stuck
+ // in the list and can never leave.
+ SetNextClientThink( hThink, m_aChangeList[i].m_flNextTime );
+ }
+ else
+ {
+ SetNextClientThink( m_aChangeList[i].m_hEnt, m_aChangeList[i].m_flNextTime );
+ }
+ }
+ m_aChangeList.RemoveAll();
+
+ // Clear out the client-side entity deletion list.
+ CleanUpDeleteList();
+}
+
+
+//-----------------------------------------------------------------------------
+// Queued-up entity deletion
+//-----------------------------------------------------------------------------
+void CClientThinkList::AddToDeleteList( ClientEntityHandle_t hEnt )
+{
+ // Sanity check!
+ Assert( hEnt != ClientEntityList().InvalidHandle() );
+ if ( hEnt == ClientEntityList().InvalidHandle() )
+ return;
+
+ // Check to see if entity is networkable -- don't let it release!
+ C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( hEnt );
+ if ( pEntity )
+ {
+ // Check to see if the entity is already being removed!
+ if ( pEntity->IsMarkedForDeletion() )
+ return;
+
+ // Don't add networkable entities to delete list -- the server should
+ // take care of this. The delete list is for client-side only entities.
+ if ( !pEntity->GetClientNetworkable() )
+ {
+ m_aDeleteList.AddToTail( hEnt );
+ pEntity->SetRemovalFlag( true );
+ }
+ }
+}
+
+void CClientThinkList::RemoveFromDeleteList( ClientEntityHandle_t hEnt )
+{
+ // Sanity check!
+ Assert( hEnt != ClientEntityList().InvalidHandle() );
+ if ( hEnt == ClientEntityList().InvalidHandle() )
+ return;
+
+ int nSize = m_aDeleteList.Count();
+ for ( int iHandle = 0; iHandle < nSize; ++iHandle )
+ {
+ if ( m_aDeleteList[iHandle] == hEnt )
+ {
+ m_aDeleteList[iHandle] = ClientEntityList().InvalidHandle();
+
+ C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( hEnt );
+ if ( pEntity )
+ {
+ pEntity->SetRemovalFlag( false );
+ }
+ }
+ }
+}
+
+void CClientThinkList::CleanUpDeleteList()
+{
+ int nThinkCount = m_aDeleteList.Count();
+ for ( int iThink = 0; iThink < nThinkCount; ++iThink )
+ {
+ ClientEntityHandle_t handle = m_aDeleteList[iThink];
+ if ( handle != ClientEntityList().InvalidHandle() )
+ {
+ C_BaseEntity *pEntity = ClientEntityList().GetBaseEntityFromHandle( handle );
+ if ( pEntity )
+ {
+ pEntity->SetRemovalFlag( false );
+ }
+
+ IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( handle );
+ if ( pThink )
+ {
+ pThink->Release();
+ }
+ }
+ }
+
+ m_aDeleteList.RemoveAll();
+}
+