//-----------------------------------------------------------------------------
// 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;
	}
}