Kamay Xutax
14717d8092
Prediction is fixed by me by adding two more functions in prediction class, there had before some issues because starttouch/endtouch weren't predicted. The result is that with lag, it restores touched entities, including the triggers touched entity list.
657 lines
18 KiB
C++
657 lines
18 KiB
C++
#include "cbase.h"
|
|
#include "cdll_client_int.h"
|
|
#include "shared_classnames.h"
|
|
#include "c_eventqueue.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// CEventQueue implementation
|
|
//
|
|
// Purpose: holds and executes a global prioritized queue of entity actions
|
|
//-----------------------------------------------------------------------------
|
|
DEFINE_FIXEDSIZE_ALLOCATOR( EventQueuePrioritizedEvent_t, 128, CUtlMemoryPool::GROW_SLOW );
|
|
|
|
CEventQueue g_EventQueue;
|
|
|
|
CEventQueue::CEventQueue()
|
|
{
|
|
m_Events.m_flFireTime = 0.0f;
|
|
m_Events.m_pNext = nullptr;
|
|
|
|
Init();
|
|
}
|
|
|
|
CEventQueue::~CEventQueue()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
// Robin: Left here for backwards compatability.
|
|
class CEventQueueSaveLoadProxy : public CBaseEntity
|
|
{
|
|
DECLARE_CLASS( CEventQueueSaveLoadProxy, CBaseEntity );
|
|
|
|
int Save( ISave &save )
|
|
{
|
|
if ( !BaseClass::Save(save) )
|
|
return 0;
|
|
|
|
// save out the message queue
|
|
return g_EventQueue.Save( save );
|
|
}
|
|
|
|
|
|
int Restore( IRestore &restore )
|
|
{
|
|
if ( !BaseClass::Restore(restore) )
|
|
return 0;
|
|
|
|
// restore the event queue
|
|
int iReturn = g_EventQueue.Restore( restore );
|
|
|
|
#ifdef GAME_DLL
|
|
// Now remove myself, because the CEventQueue_SaveRestoreBlockHandler
|
|
// will handle future saves.
|
|
UTIL_Remove( this );
|
|
#endif
|
|
return iReturn;
|
|
}
|
|
};
|
|
|
|
LINK_ENTITY_TO_CLASS(event_queue_saveload_proxy, CEventQueueSaveLoadProxy);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// EVENT QUEUE SAVE / RESTORE
|
|
//-----------------------------------------------------------------------------
|
|
static short EVENTQUEUE_SAVE_RESTORE_VERSION = 1;
|
|
|
|
class CEventQueue_SaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
|
|
{
|
|
public:
|
|
const char *GetBlockName()
|
|
{
|
|
return "EventQueue";
|
|
}
|
|
|
|
//---------------------------------
|
|
|
|
void Save( ISave *pSave )
|
|
{
|
|
g_EventQueue.Save( *pSave );
|
|
}
|
|
|
|
//---------------------------------
|
|
|
|
void WriteSaveHeaders( ISave *pSave )
|
|
{
|
|
pSave->WriteShort( &EVENTQUEUE_SAVE_RESTORE_VERSION );
|
|
}
|
|
|
|
//---------------------------------
|
|
|
|
void ReadRestoreHeaders( IRestore *pRestore )
|
|
{
|
|
// No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
|
|
short version;
|
|
pRestore->ReadShort( &version );
|
|
m_fDoLoad = ( version == EVENTQUEUE_SAVE_RESTORE_VERSION );
|
|
}
|
|
|
|
//---------------------------------
|
|
|
|
void Restore( IRestore *pRestore, bool createPlayers )
|
|
{
|
|
if ( m_fDoLoad )
|
|
{
|
|
g_EventQueue.Restore( *pRestore );
|
|
}
|
|
}
|
|
|
|
private:
|
|
bool m_fDoLoad;
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
CEventQueue_SaveRestoreBlockHandler g_EventQueue_SaveRestoreBlockHandler;
|
|
|
|
//-------------------------------------
|
|
|
|
ISaveRestoreBlockHandler *GetEventQueueSaveRestoreBlockHandler()
|
|
{
|
|
return &g_EventQueue_SaveRestoreBlockHandler;
|
|
}
|
|
|
|
|
|
void CEventQueue::Init( void )
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
void CEventQueue::Clear( void )
|
|
{
|
|
// delete all the events in the queue
|
|
EventQueuePrioritizedEvent_t *pe = m_Events.m_pNext;
|
|
|
|
while ( pe != NULL )
|
|
{
|
|
EventQueuePrioritizedEvent_t *next = pe->m_pNext;
|
|
delete pe;
|
|
pe = next;
|
|
}
|
|
|
|
m_Events.m_pNext = NULL;
|
|
}
|
|
|
|
void CEventQueue::Dump( void )
|
|
{
|
|
EventQueuePrioritizedEvent_t *pe = m_Events.m_pNext;
|
|
|
|
Msg("Dumping event queue. Current time is: %.2f\n",
|
|
gpGlobals->curtime
|
|
);
|
|
|
|
while ( pe != NULL )
|
|
{
|
|
EventQueuePrioritizedEvent_t *next = pe->m_pNext;
|
|
|
|
Msg(" (%f) Target: '%s', Input: '%s', Parameter '%s'. Activator: '%s', Caller '%s'. \n",
|
|
pe->m_flFireTime,
|
|
STRING(pe->m_iTarget),
|
|
STRING(pe->m_iTargetInput),
|
|
pe->m_VariantValue.String(),
|
|
pe->m_pActivator ? pe->m_pActivator->GetDebugName() : "None",
|
|
pe->m_pCaller ? pe->m_pCaller->GetDebugName() : "None" );
|
|
|
|
pe = next;
|
|
}
|
|
|
|
Msg("Finished dump.\n");
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: adds the action into the correct spot in the priority queue, targeting entity via string name
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::AddEvent( const char *target, const char *targetInput, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID )
|
|
{
|
|
// build the new event
|
|
EventQueuePrioritizedEvent_t *newEvent = new EventQueuePrioritizedEvent_t;
|
|
newEvent->m_flFireTime = gpGlobals->curtime + fireDelay * (1.0f / gpGlobals->frametime); // priority key in the priority queue
|
|
newEvent->m_iTarget = MAKE_STRING( target );
|
|
newEvent->m_pEntTarget = NULL;
|
|
newEvent->m_iTargetInput = MAKE_STRING( targetInput );
|
|
newEvent->m_pActivator = pActivator;
|
|
newEvent->m_pCaller = pCaller;
|
|
newEvent->m_VariantValue = Value;
|
|
newEvent->m_iOutputID = outputID;
|
|
|
|
AddEvent( newEvent );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: adds the action into the correct spot in the priority queue, targeting entity via pointer
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::AddEvent( CBaseEntity *target, const char *targetInput, variant_t Value, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID )
|
|
{
|
|
// build the new event
|
|
EventQueuePrioritizedEvent_t *newEvent = new EventQueuePrioritizedEvent_t;
|
|
newEvent->m_flFireTime = gpGlobals->curtime + fireDelay * (1.0f / gpGlobals->frametime); // priority key in the priority queue
|
|
newEvent->m_iTarget = NULL_STRING;
|
|
newEvent->m_pEntTarget = target;
|
|
newEvent->m_iTargetInput = MAKE_STRING( targetInput );
|
|
newEvent->m_pActivator = pActivator;
|
|
newEvent->m_pCaller = pCaller;
|
|
newEvent->m_VariantValue = Value;
|
|
newEvent->m_iOutputID = outputID;
|
|
|
|
AddEvent( newEvent );
|
|
}
|
|
|
|
void CEventQueue::AddEvent( CBaseEntity *target, const char *action, float fireDelay, CBaseEntity *pActivator, CBaseEntity *pCaller, int outputID )
|
|
{
|
|
variant_t Value;
|
|
Value.Set( FIELD_VOID, NULL );
|
|
AddEvent( target, action, Value, fireDelay, pActivator, pCaller, outputID );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: private function, adds an event into the list
|
|
// Input : *newEvent - the (already built) event to add
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::AddEvent( EventQueuePrioritizedEvent_t *newEvent )
|
|
{
|
|
// loop through the actions looking for a place to insert
|
|
EventQueuePrioritizedEvent_t *pe;
|
|
for ( pe = &m_Events; pe->m_pNext != NULL; pe = pe->m_pNext )
|
|
{
|
|
if ( pe->m_pNext->m_flFireTime > newEvent->m_flFireTime )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Assert( pe );
|
|
|
|
// insert
|
|
newEvent->m_pNext = pe->m_pNext;
|
|
newEvent->m_pPrev = pe;
|
|
pe->m_pNext = newEvent;
|
|
if ( newEvent->m_pNext )
|
|
{
|
|
newEvent->m_pNext->m_pPrev = newEvent;
|
|
}
|
|
}
|
|
|
|
void CEventQueue::RemoveEvent( EventQueuePrioritizedEvent_t *pe )
|
|
{
|
|
Assert( pe->m_pPrev );
|
|
pe->m_pPrev->m_pNext = pe->m_pNext;
|
|
if ( pe->m_pNext )
|
|
{
|
|
pe->m_pNext->m_pPrev = pe->m_pPrev;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: fires off any events in the queue who's fire time is (or before) the present time
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::ServiceEvents( void )
|
|
{
|
|
EventQueuePrioritizedEvent_t *pe = m_Events.m_pNext;
|
|
|
|
while ( pe != NULL && pe->m_flFireTime <= gpGlobals->curtime )
|
|
{
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
|
|
bool targetFound = false;
|
|
|
|
// find the targets
|
|
if ( pe->m_iTarget != NULL_STRING )
|
|
{
|
|
// In the context the event, the searching entity is also the caller
|
|
CBaseEntity *pSearchingEntity = pe->m_pCaller;
|
|
CBaseEntity *target = NULL;
|
|
while ( 1 )
|
|
{
|
|
target = UTIL_FindEntityByName( target, pe->m_iTarget, pSearchingEntity, pe->m_pActivator, pe->m_pCaller );
|
|
|
|
if ( !target )
|
|
break;
|
|
|
|
// pump the action into the target
|
|
target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
}
|
|
|
|
// direct pointer
|
|
if ( pe->m_pEntTarget != NULL )
|
|
{
|
|
pe->m_pEntTarget->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
|
|
if ( !targetFound )
|
|
{
|
|
// See if we can find a target if we treat the target as a classname
|
|
if ( pe->m_iTarget != NULL_STRING )
|
|
{
|
|
CBaseEntity *target = NULL;
|
|
while ( 1 )
|
|
{
|
|
target = UTIL_FindEntityByClassname( target, STRING(pe->m_iTarget) );
|
|
|
|
if ( !target )
|
|
break;
|
|
|
|
// pump the action into the target
|
|
target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !targetFound )
|
|
{
|
|
const char *pClass ="", *pName = "";
|
|
|
|
// might be NULL
|
|
if ( pe->m_pCaller )
|
|
{
|
|
pClass = STRING(pe->m_pCaller->m_iClassname);
|
|
pName = pe->m_pCaller->GetDebugName();
|
|
}
|
|
|
|
char szBuffer[256];
|
|
Q_snprintf( szBuffer, sizeof(szBuffer), "[Client] unhandled input: (%s) -> (%s), from (%s,%s); target entity not found\n", STRING(pe->m_iTargetInput), STRING(pe->m_iTarget), pClass, pName );
|
|
DevMsg( 2, "%s", szBuffer );
|
|
}
|
|
|
|
// remove the event from the list (remembering that the queue may have been added to)
|
|
RemoveEvent( pe );
|
|
delete pe;
|
|
|
|
// restart the list (to catch any new items have probably been added to the queue)
|
|
pe = m_Events.m_pNext;
|
|
}
|
|
}
|
|
|
|
void CEventQueue::ServiceEvent( CBaseEntity* pActivator )
|
|
{
|
|
EventQueuePrioritizedEvent_t *pe = m_Events.m_pNext;
|
|
|
|
while ( pe != NULL && pe->m_flFireTime <= gpGlobals->curtime )
|
|
{
|
|
if ( pe->m_pActivator != pActivator )
|
|
{
|
|
pe = pe->m_pNext;
|
|
continue;
|
|
}
|
|
|
|
MDLCACHE_CRITICAL_SECTION();
|
|
|
|
bool targetFound = false;
|
|
|
|
// find the targets
|
|
if ( pe->m_iTarget != NULL_STRING )
|
|
{
|
|
// In the context the event, the searching entity is also the caller
|
|
CBaseEntity *pSearchingEntity = pe->m_pCaller;
|
|
CBaseEntity *target = NULL;
|
|
while ( 1 )
|
|
{
|
|
target = UTIL_FindEntityByName( target, pe->m_iTarget, pSearchingEntity, pe->m_pActivator, pe->m_pCaller );
|
|
|
|
if ( !target )
|
|
break;
|
|
|
|
// pump the action into the target
|
|
target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
}
|
|
|
|
// direct pointer
|
|
if ( pe->m_pEntTarget != NULL )
|
|
{
|
|
pe->m_pEntTarget->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
|
|
if ( !targetFound )
|
|
{
|
|
// See if we can find a target if we treat the target as a classname
|
|
if ( pe->m_iTarget != NULL_STRING )
|
|
{
|
|
CBaseEntity *target = NULL;
|
|
while ( 1 )
|
|
{
|
|
target = UTIL_FindEntityByClassname( target, STRING(pe->m_iTarget) );
|
|
|
|
if ( !target )
|
|
break;
|
|
|
|
// pump the action into the target
|
|
target->AcceptInput( STRING(pe->m_iTargetInput), pe->m_pActivator, pe->m_pCaller, pe->m_VariantValue, pe->m_iOutputID );
|
|
targetFound = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !targetFound )
|
|
{
|
|
const char *pClass ="", *pName = "";
|
|
|
|
// might be NULL
|
|
if ( pe->m_pCaller )
|
|
{
|
|
pClass = STRING(pe->m_pCaller->m_iClassname);
|
|
pName = pe->m_pCaller->GetDebugName();
|
|
}
|
|
|
|
char szBuffer[256];
|
|
Q_snprintf( szBuffer, sizeof(szBuffer), "[Client] unhandled input: (%s) -> (%s), from (%s,%s); target entity not found\n", STRING(pe->m_iTargetInput), STRING(pe->m_iTarget), pClass, pName );
|
|
DevMsg( 2, "%s", szBuffer );
|
|
}
|
|
|
|
// remove the event from the list (remembering that the queue may have been added to)
|
|
RemoveEvent( pe );
|
|
delete pe;
|
|
|
|
// restart the list (to catch any new items have probably been added to the queue)
|
|
pe = m_Events.m_pNext;
|
|
}
|
|
}
|
|
|
|
#ifdef GAME_DLL
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Dumps the contents of the Entity I/O event queue to the console.
|
|
//-----------------------------------------------------------------------------
|
|
void CC_DumpEventQueue()
|
|
{
|
|
if ( !UTIL_IsCommandIssuedByServerAdmin() )
|
|
return;
|
|
|
|
g_EventQueue.Dump();
|
|
}
|
|
static ConCommand dumpeventqueue( "dumpeventqueue", CC_DumpEventQueue, "Dump the contents of the Entity I/O event queue to the console." );
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Removes all pending events from the I/O queue that were added by the
|
|
// given caller.
|
|
//
|
|
// TODO: This is only as reliable as callers are in passing the correct
|
|
// caller pointer when they fire the outputs. Make more foolproof.
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::CancelEvents( CBaseEntity *pCaller )
|
|
{
|
|
if (!pCaller)
|
|
return;
|
|
|
|
EventQueuePrioritizedEvent_t *pCur = m_Events.m_pNext;
|
|
|
|
while (pCur != NULL)
|
|
{
|
|
bool bDelete = false;
|
|
if (pCur->m_pCaller == pCaller)
|
|
{
|
|
// Pointers match; make sure everything else matches.
|
|
if (!stricmp(pCur->m_pCaller->GetDebugName(), pCaller->GetDebugName()) &&
|
|
!stricmp(pCur->m_pCaller->GetClassname(), pCaller->GetClassname()))
|
|
{
|
|
// Found a matching event; delete it from the queue.
|
|
bDelete = true;
|
|
}
|
|
}
|
|
|
|
EventQueuePrioritizedEvent_t *pCurSave = pCur;
|
|
pCur = pCur->m_pNext;
|
|
|
|
if (bDelete)
|
|
{
|
|
RemoveEvent( pCurSave );
|
|
delete pCurSave;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Removes all pending events of the specified type from the I/O queue of the specified target
|
|
//
|
|
// TODO: This is only as reliable as callers are in passing the correct
|
|
// caller pointer when they fire the outputs. Make more foolproof.
|
|
//-----------------------------------------------------------------------------
|
|
void CEventQueue::CancelEventOn( CBaseEntity *pTarget, const char *sInputName )
|
|
{
|
|
if (!pTarget)
|
|
return;
|
|
|
|
EventQueuePrioritizedEvent_t *pCur = m_Events.m_pNext;
|
|
const size_t inputNameSize = strlen(sInputName);
|
|
while (pCur != nullptr)
|
|
{
|
|
bool bDelete = false;
|
|
if (pCur->m_pEntTarget == pTarget)
|
|
{
|
|
if (!Q_strncmp(STRING(pCur->m_iTargetInput), sInputName, inputNameSize))
|
|
{
|
|
// Found a matching event; delete it from the queue.
|
|
bDelete = true;
|
|
}
|
|
}
|
|
|
|
EventQueuePrioritizedEvent_t *pCurSave = pCur;
|
|
pCur = pCur->m_pNext;
|
|
|
|
if (bDelete)
|
|
{
|
|
RemoveEvent( pCurSave );
|
|
delete pCurSave;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Return true if the target has any pending inputs.
|
|
// Input : *pTarget -
|
|
// *sInputName - NULL for any input, or a specified one
|
|
//-----------------------------------------------------------------------------
|
|
bool CEventQueue::HasEventPending( CBaseEntity *pTarget, const char *sInputName )
|
|
{
|
|
if (!pTarget)
|
|
return false;
|
|
|
|
EventQueuePrioritizedEvent_t *pCur = m_Events.m_pNext;
|
|
const size_t inputNameSize = strlen(sInputName);
|
|
while (pCur != nullptr)
|
|
{
|
|
if (pCur->m_pEntTarget == pTarget)
|
|
{
|
|
if (!sInputName || !Q_strncmp(STRING(pCur->m_iTargetInput), sInputName, inputNameSize))
|
|
return true;
|
|
}
|
|
|
|
pCur = pCur->m_pNext;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ServiceEventQueue( CBaseEntity* pActivator )
|
|
{
|
|
VPROF("ServiceEventQueue()");
|
|
|
|
if ( pActivator )
|
|
{
|
|
g_EventQueue.ServiceEvent( pActivator );
|
|
}
|
|
else
|
|
{
|
|
g_EventQueue.ServiceEvents();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// save data description for the event queue
|
|
BEGIN_SIMPLE_DATADESC( CEventQueue )
|
|
// These are saved explicitly in CEventQueue::Save below
|
|
// DEFINE_FIELD( m_Events, EventQueuePrioritizedEvent_t ),
|
|
|
|
DEFINE_FIELD( m_iListCount, FIELD_INTEGER ), // this value is only used during save/restore
|
|
END_DATADESC()
|
|
|
|
|
|
// save data for a single event in the queue
|
|
BEGIN_SIMPLE_DATADESC( EventQueuePrioritizedEvent_t )
|
|
DEFINE_FIELD( m_flFireTime, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_iTarget, FIELD_STRING ),
|
|
DEFINE_FIELD( m_iTargetInput, FIELD_STRING ),
|
|
DEFINE_FIELD( m_pActivator, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_pCaller, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_pEntTarget, FIELD_EHANDLE ),
|
|
DEFINE_FIELD( m_iOutputID, FIELD_INTEGER ),
|
|
DEFINE_CUSTOM_FIELD( m_VariantValue, variantFuncs ),
|
|
|
|
// DEFINE_FIELD( m_pNext, FIELD_??? ),
|
|
// DEFINE_FIELD( m_pPrev, FIELD_??? ),
|
|
END_DATADESC()
|
|
|
|
int CEventQueue::Save( ISave &save )
|
|
{
|
|
// count the number of items in the queue
|
|
EventQueuePrioritizedEvent_t *pe;
|
|
|
|
m_iListCount = 0;
|
|
for ( pe = m_Events.m_pNext; pe != NULL; pe = pe->m_pNext )
|
|
{
|
|
m_iListCount++;
|
|
}
|
|
|
|
// save that value out to disk, so we know how many to restore
|
|
if ( !save.WriteFields( "EventQueue", this, NULL, m_DataMap.dataDesc, m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
// cycle through all the events, saving them all
|
|
for ( pe = m_Events.m_pNext; pe != NULL; pe = pe->m_pNext )
|
|
{
|
|
if ( !save.WriteFields( "PEvent", pe, NULL, pe->m_DataMap.dataDesc, pe->m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int CEventQueue::Restore( IRestore &restore )
|
|
{
|
|
// clear the event queue
|
|
Clear();
|
|
|
|
// rebuild the event queue by restoring all the queue items
|
|
EventQueuePrioritizedEvent_t tmpEvent;
|
|
|
|
// load the number of items saved
|
|
if ( !restore.ReadFields( "EventQueue", this, NULL, m_DataMap.dataDesc, m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
for ( int i = 0; i < m_iListCount; i++ )
|
|
{
|
|
if ( !restore.ReadFields( "PEvent", &tmpEvent, NULL, tmpEvent.m_DataMap.dataDesc, tmpEvent.m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
// add the restored event into the list
|
|
if ( tmpEvent.m_pEntTarget )
|
|
{
|
|
AddEvent( tmpEvent.m_pEntTarget,
|
|
STRING(tmpEvent.m_iTargetInput),
|
|
tmpEvent.m_VariantValue,
|
|
#ifdef TF_DLL
|
|
tmpEvent.m_flFireTime - engine->GetServerTime(),
|
|
#else
|
|
tmpEvent.m_flFireTime - gpGlobals->curtime,
|
|
#endif
|
|
tmpEvent.m_pActivator,
|
|
tmpEvent.m_pCaller,
|
|
tmpEvent.m_iOutputID );
|
|
}
|
|
else
|
|
{
|
|
AddEvent( STRING(tmpEvent.m_iTarget),
|
|
STRING(tmpEvent.m_iTargetInput),
|
|
tmpEvent.m_VariantValue,
|
|
#ifdef TF_DLL
|
|
tmpEvent.m_flFireTime - engine->GetServerTime(),
|
|
#else
|
|
tmpEvent.m_flFireTime - gpGlobals->curtime,
|
|
#endif
|
|
tmpEvent.m_pActivator,
|
|
tmpEvent.m_pCaller,
|
|
tmpEvent.m_iOutputID );
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|