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.
380 lines
No EOL
9.2 KiB
C++
380 lines
No EOL
9.2 KiB
C++
#include "cbase.h"
|
|
#include "c_entityoutput.h"
|
|
#include "predictable_entity.h"
|
|
|
|
BEGIN_SIMPLE_DATADESC( C_EventAction )
|
|
DEFINE_FIELD( m_iTarget, FIELD_STRING ),
|
|
DEFINE_FIELD( m_iTargetInput, FIELD_STRING ),
|
|
DEFINE_FIELD( m_iParameter, FIELD_STRING ),
|
|
DEFINE_FIELD( m_flDelay, FIELD_FLOAT ),
|
|
DEFINE_FIELD( m_nTimesToFire, FIELD_INTEGER ),
|
|
DEFINE_FIELD( m_iIDStamp, FIELD_INTEGER ),
|
|
|
|
// This is dealt with by the Restore method
|
|
// DEFINE_FIELD( m_pNext, C_EventAction ),
|
|
END_DATADESC();
|
|
|
|
// ID Stamp used to uniquely identify every output
|
|
int C_EventAction::s_iNextIDStamp = 0;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Creates an event action and assigns it an unique ID stamp.
|
|
// Input : ActionData - the map file data block descibing the event action.
|
|
//-----------------------------------------------------------------------------
|
|
C_EventAction::C_EventAction( const char *ActionData )
|
|
{
|
|
ConColorMsg(Color(0, 255, 0, 255), "C_EventAction::C_EventAction: %s\n", ActionData);
|
|
|
|
m_pNext = NULL;
|
|
m_iIDStamp = ++s_iNextIDStamp;
|
|
|
|
m_flDelay = 0;
|
|
m_iTarget = NULL_STRING;
|
|
m_iParameter = NULL_STRING;
|
|
m_iTargetInput = NULL_STRING;
|
|
m_nTimesToFire = EVENT_FIRE_ALWAYS;
|
|
|
|
if (ActionData == NULL)
|
|
return;
|
|
|
|
char szToken[256];
|
|
|
|
//
|
|
// Parse the target name.
|
|
//
|
|
const char *psz = nexttoken(szToken, ActionData, ',', sizeof(szToken));
|
|
if (szToken[0] != '\0')
|
|
{
|
|
m_iTarget = AllocPooledString(szToken);
|
|
}
|
|
|
|
//
|
|
// Parse the input name.
|
|
//
|
|
psz = nexttoken(szToken, psz, ',', sizeof(szToken));
|
|
if (szToken[0] != '\0')
|
|
{
|
|
m_iTargetInput = AllocPooledString(szToken);
|
|
}
|
|
else
|
|
{
|
|
m_iTargetInput = AllocPooledString("Use");
|
|
}
|
|
|
|
//
|
|
// Parse the parameter override.
|
|
//
|
|
psz = nexttoken(szToken, psz, ',', sizeof(szToken));
|
|
if (szToken[0] != '\0')
|
|
{
|
|
m_iParameter = AllocPooledString(szToken);
|
|
}
|
|
|
|
//
|
|
// Parse the delay.
|
|
//
|
|
psz = nexttoken(szToken, psz, ',', sizeof(szToken));
|
|
if (szToken[0] != '\0')
|
|
{
|
|
m_flDelay = atof(szToken);
|
|
}
|
|
|
|
//
|
|
// Parse the number of times to fire.
|
|
//
|
|
nexttoken(szToken, psz, ',', sizeof(szToken));
|
|
if (szToken[0] != '\0')
|
|
{
|
|
m_nTimesToFire = atoi(szToken);
|
|
if (m_nTimesToFire == 0)
|
|
{
|
|
m_nTimesToFire = EVENT_FIRE_ALWAYS;
|
|
}
|
|
}
|
|
}
|
|
|
|
#include "tier0/memdbgoff.h"
|
|
|
|
void *C_EventAction::operator new( size_t stAllocateBlock )
|
|
{
|
|
return g_EntityListPool.Alloc( stAllocateBlock );
|
|
}
|
|
|
|
void *C_EventAction::operator new( size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine )
|
|
{
|
|
return g_EntityListPool.Alloc( stAllocateBlock );
|
|
}
|
|
|
|
void C_EventAction::operator delete( void *pMem )
|
|
{
|
|
g_EntityListPool.Free( pMem );
|
|
}
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Returns the highest-valued delay in our list of event actions.
|
|
//-----------------------------------------------------------------------------
|
|
float C_BaseEntityOutput::GetMaxDelay(void)
|
|
{
|
|
float flMaxDelay = 0;
|
|
C_EventAction *ev = m_ActionList;
|
|
|
|
while (ev != NULL)
|
|
{
|
|
if (ev->m_flDelay > flMaxDelay)
|
|
{
|
|
flMaxDelay = ev->m_flDelay;
|
|
}
|
|
ev = ev->m_pNext;
|
|
}
|
|
|
|
return(flMaxDelay);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Destructor.
|
|
//-----------------------------------------------------------------------------
|
|
C_BaseEntityOutput::~C_BaseEntityOutput()
|
|
{
|
|
C_EventAction *ev = m_ActionList;
|
|
while (ev != NULL)
|
|
{
|
|
C_EventAction *pNext = ev->m_pNext;
|
|
delete ev;
|
|
ev = pNext;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Fires the event, causing a sequence of action to occur in other ents.
|
|
// Input : pActivator - Entity that initiated this sequence of actions.
|
|
// pCaller - Entity that is actually causing the event.
|
|
//-----------------------------------------------------------------------------
|
|
void C_BaseEntityOutput::FireOutput(variant_t Value, CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay)
|
|
{
|
|
//
|
|
// Iterate through all eventactions and fire them off.
|
|
//
|
|
C_EventAction *ev = m_ActionList;
|
|
C_EventAction *prev = NULL;
|
|
|
|
while (ev != NULL)
|
|
{
|
|
if (ev->m_iParameter == NULL_STRING)
|
|
{
|
|
//
|
|
// Post the event with the default parameter.
|
|
//
|
|
g_EventQueue.AddEvent( STRING(ev->m_iTarget), STRING(ev->m_iTargetInput), Value, ev->m_flDelay + fDelay, pActivator, pCaller, ev->m_iIDStamp );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Post the event with a parameter override.
|
|
//
|
|
variant_t ValueOverride;
|
|
ValueOverride.SetString( ev->m_iParameter );
|
|
g_EventQueue.AddEvent( STRING(ev->m_iTarget), STRING(ev->m_iTargetInput), ValueOverride, ev->m_flDelay, pActivator, pCaller, ev->m_iIDStamp );
|
|
}
|
|
|
|
if ( ev->m_flDelay )
|
|
{
|
|
char szBuffer[256];
|
|
Q_snprintf( szBuffer,
|
|
sizeof(szBuffer),
|
|
"(%0.2f) output: (%s,%s) -> (%s,%s,%.1f)(%s)\n",
|
|
gpGlobals->curtime,
|
|
pCaller ? STRING(pCaller->m_iClassname) : "NULL",
|
|
pCaller ? pCaller->GetDebugName() : "NULL",
|
|
STRING(ev->m_iTarget),
|
|
STRING(ev->m_iTargetInput),
|
|
ev->m_flDelay,
|
|
STRING(ev->m_iParameter) );
|
|
|
|
DevMsg( 2, "%s", szBuffer );
|
|
#ifdef GAME_DLL
|
|
ADD_DEBUG_HISTORY( HISTORY_ENTITY_IO, szBuffer );
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
char szBuffer[256];
|
|
Q_snprintf( szBuffer,
|
|
sizeof(szBuffer),
|
|
"(%0.2f) output: (%s,%s) -> (%s,%s)(%s)\n",
|
|
gpGlobals->curtime,
|
|
pCaller ? STRING(pCaller->m_iClassname) : "NULL",
|
|
pCaller ? pCaller->GetDebugName() : "NULL", STRING(ev->m_iTarget),
|
|
STRING(ev->m_iTargetInput),
|
|
STRING(ev->m_iParameter) );
|
|
|
|
DevMsg( 2, "%s", szBuffer );
|
|
#ifdef GAME_DLL
|
|
ADD_DEBUG_HISTORY( HISTORY_ENTITY_IO, szBuffer );
|
|
#endif
|
|
}
|
|
#ifdef GAME_DLL
|
|
if ( pCaller && pCaller->m_debugOverlays & OVERLAY_MESSAGE_BIT)
|
|
{
|
|
pCaller->DrawOutputOverlay(ev);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Remove the event action from the list if it was set to be fired a finite
|
|
// number of times (and has been).
|
|
//
|
|
bool bRemove = false;
|
|
if (ev->m_nTimesToFire != EVENT_FIRE_ALWAYS)
|
|
{
|
|
ev->m_nTimesToFire--;
|
|
if (ev->m_nTimesToFire == 0)
|
|
{
|
|
char szBuffer[256];
|
|
Q_snprintf( szBuffer,
|
|
sizeof(szBuffer),
|
|
"Removing from action list: (%s,%s) -> (%s,%s)\n",
|
|
pCaller ? STRING(pCaller->m_iClassname) : "NULL",
|
|
pCaller ? pCaller->GetDebugName() : "NULL",
|
|
STRING(ev->m_iTarget), STRING(ev->m_iTargetInput) );
|
|
DevMsg( 2, "%s", szBuffer );
|
|
#ifdef GAME_DLL
|
|
ADD_DEBUG_HISTORY( HISTORY_ENTITY_IO, szBuffer );
|
|
#endif
|
|
bRemove = true;
|
|
}
|
|
}
|
|
|
|
if (!bRemove)
|
|
{
|
|
prev = ev;
|
|
ev = ev->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
if (prev != NULL)
|
|
{
|
|
prev->m_pNext = ev->m_pNext;
|
|
}
|
|
else
|
|
{
|
|
m_ActionList = ev->m_pNext;
|
|
}
|
|
|
|
C_EventAction *next = ev->m_pNext;
|
|
delete ev;
|
|
ev = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Parameterless firing of an event
|
|
// Input : pActivator -
|
|
// pCaller -
|
|
//-----------------------------------------------------------------------------
|
|
void C_OutputEvent::FireOutput(CBaseEntity *pActivator, CBaseEntity *pCaller, float fDelay)
|
|
{
|
|
variant_t Val;
|
|
Val.Set( FIELD_VOID, NULL );
|
|
C_BaseEntityOutput::FireOutput(Val, pActivator, pCaller, fDelay);
|
|
}
|
|
|
|
|
|
void C_BaseEntityOutput::ParseEventAction( const char *EventData )
|
|
{
|
|
AddEventAction( new C_EventAction( EventData ) );
|
|
}
|
|
|
|
void C_BaseEntityOutput::AddEventAction( C_EventAction *pEventAction )
|
|
{
|
|
pEventAction->m_pNext = m_ActionList;
|
|
m_ActionList = pEventAction;
|
|
}
|
|
|
|
// save data description for the event queue
|
|
BEGIN_SIMPLE_DATADESC( C_BaseEntityOutput )
|
|
DEFINE_CUSTOM_FIELD( m_Value, variantFuncs ),
|
|
|
|
// This is saved manually by C_BaseEntityOutput::Save
|
|
// DEFINE_FIELD( m_ActionList, C_EventAction ),
|
|
END_DATADESC()
|
|
|
|
int C_BaseEntityOutput::Save( ISave &save )
|
|
{
|
|
// save that value out to disk, so we know how many to restore
|
|
if ( !save.WriteFields( "Value", this, NULL, m_DataMap.dataDesc, m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
for ( C_EventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext )
|
|
{
|
|
if ( !save.WriteFields( "EntityOutput", ev, NULL, ev->m_DataMap.dataDesc, ev->m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int C_BaseEntityOutput::Restore( IRestore &restore, int elementCount )
|
|
{
|
|
// load the number of items saved
|
|
if ( !restore.ReadFields( "Value", this, NULL, m_DataMap.dataDesc, m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
m_ActionList = NULL;
|
|
|
|
// read in all the fields
|
|
C_EventAction *lastEv = NULL;
|
|
for ( int i = 0; i < elementCount; i++ )
|
|
{
|
|
C_EventAction *ev = new C_EventAction(NULL);
|
|
|
|
if ( !restore.ReadFields( "EntityOutput", ev, NULL, ev->m_DataMap.dataDesc, ev->m_DataMap.dataNumFields ) )
|
|
return 0;
|
|
|
|
// add it to the list in the same order it was saved in
|
|
if ( lastEv )
|
|
{
|
|
lastEv->m_pNext = ev;
|
|
}
|
|
else
|
|
{
|
|
m_ActionList = ev;
|
|
}
|
|
ev->m_pNext = NULL;
|
|
lastEv = ev;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int C_BaseEntityOutput::NumberOfElements( void )
|
|
{
|
|
int count = 0;
|
|
for ( C_EventAction *ev = m_ActionList; ev != NULL; ev = ev->m_pNext )
|
|
{
|
|
count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/// Delete every single action in the action list.
|
|
void C_BaseEntityOutput::DeleteAllElements( void )
|
|
{
|
|
// walk front to back, deleting as we go. We needn't fix up pointers because
|
|
// EVERYTHING will die.
|
|
|
|
C_EventAction *pNext = m_ActionList;
|
|
// wipe out the head
|
|
m_ActionList = NULL;
|
|
while (pNext)
|
|
{
|
|
C_EventAction *strikeThis = pNext;
|
|
pNext = pNext->m_pNext;
|
|
delete strikeThis;
|
|
}
|
|
|
|
} |