css_enhanced_waf/game/client/css_enhanced/c_entityoutput.cpp
Kamay Xutax 14717d8092 Added prediction for triggers, thanks oblivious
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.
2024-08-23 00:42:58 +02:00

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