//----------------------------------------------------------------------------- // 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::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; } } }
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(); }
//----------------------------------------------------------------------------- // 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::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; }
//----------------------------------------------------------------------------- // 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; } }