void CClientThinkList::SetNextClientThink( ClientEntityHandle_t hEnt, float nextTime ) { if ( nextTime == CLIENT_THINK_NEVER ) { RemoveThinkable( hEnt ); } else { IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt ); if ( pThink ) { ClientThinkHandle_t hThink = pThink->GetThinkHandle(); // Add it to the list if it's not already in there. if ( hThink == INVALID_THINK_HANDLE ) { hThink = (ClientThinkHandle_t)m_ThinkEntries.AddToTail(); pThink->SetThinkHandle( hThink ); GetThinkEntry( hThink )->m_hEnt = hEnt; } // Set the next think time.. GetThinkEntry( hThink )->m_flNextClientThink = nextTime; } } }
//----------------------------------------------------------------------------- // 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; }
void CClientThinkList::PerformThinkFunctions() { float curtime = gpGlobals->curtime; unsigned long iNext; for ( unsigned long iCur=m_ThinkEntries.Head(); iCur != m_ThinkEntries.InvalidIndex(); iCur = iNext ) { iNext = m_ThinkEntries.Next( iCur ); CThinkEntry *pEntry = &m_ThinkEntries[iCur]; IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( pEntry->m_hEnt ); if ( pThink ) { 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(); // NOTE: The Think() call can cause other things to be added to the Think // list, which could reallocate memory and invalidate the pEntry pointer pEntry = &m_ThinkEntries[iCur]; } else if ( pEntry->m_flNextClientThink < curtime ) { pEntry->m_flNextClientThink = curtime; // NOTE: The Think function here could call SetNextClientThink // which would cause it to be readded into the list pThink->ClientThink(); // NOTE: The Think() call can cause other things to be added to the Think // list, which could reallocate memory and invalidate the pEntry pointer pEntry = &m_ThinkEntries[iCur]; // If they haven't changed the think time, then it should be removed. if ( pEntry->m_flNextClientThink == curtime ) { RemoveThinkable( pEntry->m_hEnt ); } } Assert( pEntry == &m_ThinkEntries[iCur] ); // Set this after the Think calls in case they look at LastClientThink m_ThinkEntries[iCur].m_flLastClientThink = curtime; } else { // This should be almost impossible. When ClientEntityHandle_t's are versioned, // this should be totally impossible. Assert( false ); m_ThinkEntries.Remove( iCur ); } } // Clear out the client-side entity deletion list. CleanUpDeleteList(); }
//----------------------------------------------------------------------------- // Purpose: Clears all entity lists and releases entities //----------------------------------------------------------------------------- void CClientEntityList::Release( void ) { // Free all the entities. ClientEntityHandle_t iter = FirstHandle(); ClientEntityHandle_t next; while( iter != InvalidHandle() ) { next = NextHandle( iter ); // Try to call release on anything we can. IClientNetworkable *pNet = GetClientNetworkableFromHandle( iter ); if ( pNet ) { pNet->Release(); } else { // Try to call release on anything we can. IClientThinkable *pThinkable = GetClientThinkableFromHandle( iter ); if ( pThinkable ) { pThinkable->Release(); } } RemoveEntity( iter ); iter = next; } m_iNumServerEnts = 0; m_iMaxServerEnts = 0; m_iMaxUsedServerIndex = -1; }
//----------------------------------------------------------------------------- // 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 ); } } }
void CClientThinkList::RemoveThinkable( ClientEntityHandle_t hEnt ) { IClientThinkable *pThink = ClientEntityList().GetClientThinkableFromHandle( hEnt ); if ( pThink ) { ClientThinkHandle_t hThink = pThink->GetThinkHandle(); // It will never think so make sure it's NOT in the list. if ( hThink != INVALID_THINK_HANDLE ) { m_ThinkEntries.Remove( (unsigned long)hThink ); pThink->SetThinkHandle( INVALID_THINK_HANDLE ); } } }
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)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 ); }
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(); }