2019-10-01 21:45:39 +02:00
# include <sourcemod>
# include <sdkhooks>
# include <sdktools>
# include <CSSFixes>
# include <dhooks>
# pragma semicolon 1
# pragma newdecls required
public Plugin myinfo =
{
name = " LagCompensation " ,
author = " BotoX " ,
description = " " ,
version = " 0.0 " ,
url = " "
} ;
bool g_bLateLoad = false ;
2019-10-02 18:54:19 +02:00
# define MAX_RECORDS 32
2019-10-03 22:09:53 +02:00
# define MAX_ENTITIES 64
2019-10-02 23:28:20 +02:00
//#define DEBUG
2019-10-01 21:45:39 +02:00
enum struct LagRecord
{
float vecOrigin [ 3 ] ;
float vecAngles [ 3 ] ;
}
enum struct EntityLagData
{
int iEntity ;
int iRecordIndex ;
int iNumRecords ;
2019-10-02 23:28:20 +02:00
int iRecordsValid ;
int iDeleted ;
2019-10-03 12:02:23 +02:00
int iNotMoving ;
2019-10-01 21:45:39 +02:00
bool bRestore ;
LagRecord RestoreData ;
}
LagRecord g_aaLagRecords [ MAX_ENTITIES ] [ MAX_RECORDS ] ;
EntityLagData g_aEntityLagData [ MAX_ENTITIES ] ;
int g_iNumEntities = 0 ;
2019-10-02 23:28:20 +02:00
Handle g_hGetAbsOrigin ;
2019-10-02 18:54:19 +02:00
Handle g_hSetAbsOrigin ;
2019-10-02 23:28:20 +02:00
Handle g_hGetAbsAngles ;
2019-10-02 18:54:19 +02:00
Handle g_hSetAbsAngles ;
2019-10-01 21:45:39 +02:00
2019-10-02 23:28:20 +02:00
bool g_bBlockPhysics = false ;
bool g_bNoPhysics [ 2048 ] ;
Handle g_hPhysicsTouchTriggers ;
Handle g_hUTIL_Remove ;
2019-10-03 22:09:53 +02:00
Handle g_hRestartRound ;
2019-10-02 23:28:20 +02:00
2019-10-01 21:45:39 +02:00
public void OnPluginStart ( )
{
Handle hGameData = LoadGameConfigFile ( " LagCompensation.games " ) ;
if ( ! hGameData )
SetFailState ( " Failed to load LagCompensation gamedata. " ) ;
2019-10-02 23:28:20 +02:00
// CBaseEntity::GetAbsOrigin
StartPrepSDKCall ( SDKCall_Entity ) ;
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " GetAbsOrigin " ) )
{
delete hGameData ;
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" GetAbsOrigin \" ) failed! " ) ;
}
PrepSDKCall_SetReturnInfo ( SDKType_Vector , SDKPass_ByRef ) ;
g_hGetAbsOrigin = EndPrepSDKCall ( ) ;
2019-10-02 18:54:19 +02:00
// CBaseEntity::SetAbsOrigin
2019-10-01 21:45:39 +02:00
StartPrepSDKCall ( SDKCall_Entity ) ;
2019-10-02 18:54:19 +02:00
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " SetAbsOrigin " ) )
2019-10-01 21:45:39 +02:00
{
delete hGameData ;
2019-10-02 18:54:19 +02:00
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" SetAbsOrigin \" ) failed! " ) ;
2019-10-01 21:45:39 +02:00
}
PrepSDKCall_AddParameter ( SDKType_Vector , SDKPass_ByRef ) ;
2019-10-02 18:54:19 +02:00
g_hSetAbsOrigin = EndPrepSDKCall ( ) ;
2019-10-01 21:45:39 +02:00
2019-10-02 23:28:20 +02:00
// CBaseEntity::GetAbsAngles
StartPrepSDKCall ( SDKCall_Entity ) ;
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " GetAbsAngles " ) )
{
delete hGameData ;
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" GetAbsAngles \" ) failed! " ) ;
}
PrepSDKCall_AddParameter ( SDKType_QAngle , SDKPass_ByRef ) ;
g_hGetAbsAngles = EndPrepSDKCall ( ) ;
2019-10-02 18:54:19 +02:00
// CBaseEntity::SetAbsAngles
2019-10-01 21:45:39 +02:00
StartPrepSDKCall ( SDKCall_Entity ) ;
2019-10-02 18:54:19 +02:00
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " SetAbsAngles " ) )
2019-10-01 21:45:39 +02:00
{
delete hGameData ;
2019-10-02 18:54:19 +02:00
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" SetAbsAngles \" ) failed! " ) ;
2019-10-01 21:45:39 +02:00
}
PrepSDKCall_AddParameter ( SDKType_QAngle , SDKPass_ByRef ) ;
2019-10-02 18:54:19 +02:00
g_hSetAbsAngles = EndPrepSDKCall ( ) ;
2019-10-01 21:45:39 +02:00
2019-10-02 23:28:20 +02:00
// CBaseEntity::PhysicsTouchTriggers
2019-10-01 21:45:39 +02:00
g_hPhysicsTouchTriggers = DHookCreateFromConf ( hGameData , " CBaseEntity__PhysicsTouchTriggers " ) ;
if ( ! g_hPhysicsTouchTriggers )
2019-10-02 23:28:20 +02:00
{
delete hGameData ;
2019-10-01 21:45:39 +02:00
SetFailState ( " Failed to setup detour for CBaseEntity__PhysicsTouchTriggers " ) ;
2019-10-02 23:28:20 +02:00
}
2019-10-01 21:45:39 +02:00
if ( ! DHookEnableDetour ( g_hPhysicsTouchTriggers , false , Detour_OnPhysicsTouchTriggers ) )
2019-10-02 23:28:20 +02:00
{
delete hGameData ;
2019-10-01 21:45:39 +02:00
SetFailState ( " Failed to detour CBaseEntity__PhysicsTouchTriggers. " ) ;
2019-10-02 23:28:20 +02:00
}
2019-10-03 22:09:53 +02:00
// ::UTIL_Remove
2019-10-02 23:28:20 +02:00
g_hUTIL_Remove = DHookCreateFromConf ( hGameData , " UTIL_Remove " ) ;
if ( ! g_hUTIL_Remove )
{
delete hGameData ;
SetFailState ( " Failed to setup detour for UTIL_Remove " ) ;
}
if ( ! DHookEnableDetour ( g_hUTIL_Remove , false , Detour_OnUTIL_Remove ) )
2019-10-03 22:09:53 +02:00
{
delete hGameData ;
2019-10-02 23:28:20 +02:00
SetFailState ( " Failed to detour UTIL_Remove. " ) ;
2019-10-03 22:09:53 +02:00
}
2019-10-02 23:28:20 +02:00
2019-10-03 22:09:53 +02:00
// CCSGameRules::RestartRound
g_hRestartRound = DHookCreateFromConf ( hGameData , " CCSGameRules__RestartRound " ) ;
if ( ! g_hRestartRound )
{
delete hGameData ;
SetFailState ( " Failed to setup detour for CCSGameRules__RestartRound " ) ;
}
delete hGameData ;
2019-10-02 23:28:20 +02:00
2019-10-03 22:09:53 +02:00
if ( ! DHookEnableDetour ( g_hRestartRound , false , Detour_OnRestartRound ) )
SetFailState ( " Failed to detour CCSGameRules__RestartRound. " ) ;
2019-10-02 23:28:20 +02:00
}
2019-10-03 22:09:53 +02:00
public void OnPluginEnd ( )
{
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-02 23:28:20 +02:00
{
2019-10-03 22:09:53 +02:00
if ( ! IsValidEntity ( g_aEntityLagData [ i ] . iEntity ) )
continue ;
2019-10-03 12:02:23 +02:00
2019-10-03 22:09:53 +02:00
if ( g_aEntityLagData [ i ] . iDeleted )
{
PrintToBoth ( " [%d] !!!!!!!!!!! RemoveEdict: %d / ent: %d " , GetGameTickCount ( ) , i , g_aEntityLagData [ i ] . iEntity ) ;
// calls OnEntityDestroyed right away
// which calls RemoveRecord
// which moves the next element to our current position
RemoveEdict ( g_aEntityLagData [ i ] . iEntity ) ;
i - - ; continue ;
}
}
2019-10-02 23:28:20 +02:00
}
2019-10-03 22:09:53 +02:00
public APLRes AskPluginLoad2 ( Handle myself , bool late , char [ ] error , int err_max )
2019-10-02 23:28:20 +02:00
{
2019-10-03 22:09:53 +02:00
g_bLateLoad = late ;
return APLRes_Success ;
2019-10-01 21:45:39 +02:00
}
public MRESReturn Detour_OnPhysicsTouchTriggers ( int entity , Handle hReturn , Handle hParams )
{
2019-10-02 12:22:35 +02:00
if ( ! g_bBlockPhysics )
return MRES_Ignored ;
2019-10-01 21:45:39 +02:00
if ( entity < 0 | | entity > sizeof ( g_bNoPhysics ) )
return MRES_Ignored ;
if ( g_bNoPhysics [ entity ] )
{
2019-10-02 14:19:09 +02:00
//LogMessage("blocked physics on %d", entity);
2019-10-01 21:45:39 +02:00
return MRES_Supercede ;
}
return MRES_Ignored ;
}
2019-10-02 23:28:20 +02:00
public MRESReturn Detour_OnUTIL_Remove ( Handle hParams )
2019-10-01 21:45:39 +02:00
{
2019-10-02 23:28:20 +02:00
int entity = DHookGetParam ( hParams , 1 ) ;
if ( entity < 0 | | entity > sizeof ( g_bNoPhysics ) )
return MRES_Ignored ;
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-02 23:28:20 +02:00
{
if ( g_aEntityLagData [ i ] . iEntity ! = entity )
continue ;
SetEntPropEnt ( entity , Prop_Data , " m_pParent " , 0 ) ;
if ( ! g_aEntityLagData [ i ] . iDeleted )
g_aEntityLagData [ i ] . iDeleted = GetGameTickCount ( ) ;
2019-10-03 22:09:53 +02:00
PrintToBoth ( " [%d] !!!!!!!!!!! Detour_OnUTIL_Remove: %d / ent: %d " , GetGameTickCount ( ) , i , entity ) ;
2019-10-02 23:28:20 +02:00
return MRES_Supercede ;
}
return MRES_Ignored ;
2019-10-01 21:45:39 +02:00
}
2019-10-03 22:09:53 +02:00
public MRESReturn Detour_OnRestartRound ( )
{
PrintToBoth ( " Detour_OnRestartRound with %d entries. " , g_iNumEntities ) ;
for ( int i = 0 ; i < g_iNumEntities ; i + + )
{
g_aEntityLagData [ i ] . iEntity = - 1 ;
}
g_iNumEntities = 0 ;
return MRES_Ignored ;
}
2019-10-01 21:45:39 +02:00
public void OnMapStart ( )
{
bool bLate = g_bLateLoad ;
g_bLateLoad = false ;
/* Late Load */
if ( bLate )
{
for ( int client = 1 ; client < = MaxClients ; client + + )
{
if ( IsClientInGame ( client ) )
OnClientPutInServer ( client ) ;
}
int entity = INVALID_ENT_REFERENCE ;
while ( ( entity = FindEntityByClassname ( entity , " * " ) ) ! = INVALID_ENT_REFERENCE )
{
char sClassname [ 64 ] ;
if ( GetEntityClassname ( entity , sClassname , sizeof ( sClassname ) ) )
OnEntitySpawned ( entity , sClassname ) ;
}
}
}
public void OnClientPutInServer ( int client )
{
}
public void OnRunThinkFunctions ( bool simulating )
{
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
2019-10-03 12:02:23 +02:00
if ( g_aEntityLagData [ i ] . iNotMoving > = MAX_RECORDS )
2019-10-01 21:45:39 +02:00
continue ;
if ( ! IsValidEntity ( g_aEntityLagData [ i ] . iEntity ) )
{
2019-10-03 22:09:53 +02:00
PrintToBoth ( " !!!!!!!!!!! OnRunThinkFunctions SHIT deleted: %d / %d " , i , g_aEntityLagData [ i ] . iEntity ) ;
2019-10-03 12:02:23 +02:00
RemoveRecord ( i ) ;
i - - ; continue ;
2019-10-01 21:45:39 +02:00
}
2019-10-02 23:28:20 +02:00
if ( g_aEntityLagData [ i ] . iDeleted )
{
if ( g_aEntityLagData [ i ] . iDeleted + MAX_RECORDS < GetGameTickCount ( ) )
{
2019-10-03 22:09:53 +02:00
PrintToBoth ( " [%d] !!!!!!!!!!! RemoveEdict: %d / ent: %d " , GetGameTickCount ( ) , i , g_aEntityLagData [ i ] . iEntity ) ;
2019-10-03 12:02:23 +02:00
// calls OnEntityDestroyed right away
// which calls RemoveRecord
// which moves the next element to our current position
2019-10-02 23:28:20 +02:00
RemoveEdict ( g_aEntityLagData [ i ] . iEntity ) ;
2019-10-03 12:02:23 +02:00
i - - ; continue ;
2019-10-02 23:28:20 +02:00
}
continue ;
}
2019-10-01 21:45:39 +02:00
RecordDataIntoRecord ( g_aEntityLagData [ i ] . iEntity , g_aEntityLagData [ i ] . RestoreData ) ;
2019-10-03 10:39:27 +02:00
2019-10-02 14:19:09 +02:00
# if defined DEBUG
2019-10-02 18:54:19 +02:00
LogMessage ( " 1 [%d] [%d] index %d, RECORD entity %d " , GetGameTickCount ( ) , i , simulating , g_aEntityLagData [ i ] . iEntity , g_aEntityLagData [ i ] . iRecordIndex ) ;
2019-10-02 14:19:09 +02:00
LogMessage ( " %f %f %f " ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 0 ] ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 1 ] ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 2 ]
) ;
# endif
2019-10-01 21:45:39 +02:00
}
}
public Action OnPlayerRunCmd ( int client , int & buttons , int & impulse , float vel [ 3 ] , float angles [ 3 ] , int & weapon , int & subtype , int & cmdnum , int & tickcount , int & seed , int mouse [ 2 ] )
{
2019-10-02 12:22:35 +02:00
if ( ! IsPlayerAlive ( client ) )
return Plugin_Continue ;
2019-10-01 21:45:39 +02:00
int delta = GetGameTickCount ( ) - tickcount ;
if ( delta < 0 )
delta = 0 ;
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
2019-10-03 12:02:23 +02:00
if ( g_aEntityLagData [ i ] . iNotMoving > = MAX_RECORDS )
2019-10-01 21:45:39 +02:00
continue ;
if ( delta > = g_aEntityLagData [ i ] . iNumRecords )
delta = g_aEntityLagData [ i ] . iNumRecords - 1 ;
2019-10-02 23:28:20 +02:00
if ( g_aEntityLagData [ i ] . iDeleted )
{
int simtick = GetGameTickCount ( ) - delta ;
if ( simtick > g_aEntityLagData [ i ] . iDeleted )
{
// TODO: completly block player from touching trigger
continue ;
}
}
2019-10-01 21:45:39 +02:00
int iRecordIndex = g_aEntityLagData [ i ] . iRecordIndex - delta ;
if ( iRecordIndex < 0 )
iRecordIndex + = MAX_RECORDS ;
2019-10-02 12:22:35 +02:00
RestoreEntityFromRecord ( g_aEntityLagData [ i ] . iEntity , client , g_aaLagRecords [ i ] [ iRecordIndex ] ) ;
2019-10-03 22:09:53 +02:00
g_aEntityLagData [ i ] . bRestore = true ; //!g_aEntityLagData[i].iDeleted;
2019-10-01 21:45:39 +02:00
# if defined DEBUG
2019-10-02 18:54:19 +02:00
LogMessage ( " 2 [%d] index %d, Entity %d -> delta = %d | Record = %d " , GetGameTickCount ( ) , i , g_aEntityLagData [ i ] . iEntity , delta , iRecordIndex ) ;
2019-10-01 21:45:39 +02:00
LogMessage ( " %f %f %f " ,
g_aaLagRecords [ i ] [ iRecordIndex ] . vecOrigin [ 0 ] ,
g_aaLagRecords [ i ] [ iRecordIndex ] . vecOrigin [ 1 ] ,
g_aaLagRecords [ i ] [ iRecordIndex ] . vecOrigin [ 2 ]
) ;
# endif
}
return Plugin_Continue ;
}
2019-10-02 18:54:19 +02:00
public void OnPostPlayerThinkFunctions ( )
2019-10-01 21:45:39 +02:00
{
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
2019-10-03 10:39:27 +02:00
if ( ! g_aEntityLagData [ i ] . bRestore )
2019-10-01 21:45:39 +02:00
continue ;
2019-10-02 12:22:35 +02:00
RestoreEntityFromRecord ( g_aEntityLagData [ i ] . iEntity , 0 , g_aEntityLagData [ i ] . RestoreData ) ;
2019-10-01 21:45:39 +02:00
g_aEntityLagData [ i ] . bRestore = false ;
# if defined DEBUG
2019-10-02 18:54:19 +02:00
LogMessage ( " 3 [%d] index %d, RESTORE entity %d " , GetGameTickCount ( ) , i , g_aEntityLagData [ i ] . iEntity , g_aEntityLagData [ i ] . iRecordIndex ) ;
2019-10-01 21:45:39 +02:00
LogMessage ( " %f %f %f " ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 0 ] ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 1 ] ,
g_aEntityLagData [ i ] . RestoreData . vecOrigin [ 2 ]
) ;
# endif
}
2019-10-02 14:19:09 +02:00
g_bBlockPhysics = true ;
2019-10-01 21:45:39 +02:00
}
public void OnRunThinkFunctionsPost ( bool simulating )
{
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
2019-10-02 23:28:20 +02:00
if ( g_aEntityLagData [ i ] . iDeleted )
2019-10-01 21:45:39 +02:00
{
2019-10-02 23:28:20 +02:00
if ( g_aEntityLagData [ i ] . iRecordsValid )
{
g_aEntityLagData [ i ] . iRecordIndex + + ;
if ( g_aEntityLagData [ i ] . iRecordIndex > = MAX_RECORDS )
g_aEntityLagData [ i ] . iRecordIndex = 0 ;
g_aEntityLagData [ i ] . iRecordsValid - - ;
}
2019-10-01 21:45:39 +02:00
continue ;
}
2019-10-03 12:02:23 +02:00
LagRecord TmpRecord ;
RecordDataIntoRecord ( g_aEntityLagData [ i ] . iEntity , TmpRecord ) ;
2019-10-03 22:09:53 +02:00
// sleep detection
2019-10-02 18:54:19 +02:00
{
2019-10-03 12:02:23 +02:00
int iOldRecord = g_aEntityLagData [ i ] . iRecordIndex ;
2019-10-02 18:54:19 +02:00
2019-10-03 12:02:23 +02:00
if ( g_aaLagRecords [ i ] [ iOldRecord ] . vecOrigin [ 0 ] = = TmpRecord . vecOrigin [ 0 ] & &
g_aaLagRecords [ i ] [ iOldRecord ] . vecOrigin [ 1 ] = = TmpRecord . vecOrigin [ 1 ] & &
g_aaLagRecords [ i ] [ iOldRecord ] . vecOrigin [ 2 ] = = TmpRecord . vecOrigin [ 2 ] )
{
g_aEntityLagData [ i ] . iNotMoving + + ;
if ( g_aEntityLagData [ i ] . iNotMoving = = MAX_RECORDS )
2019-10-03 22:09:53 +02:00
{
char sClassname [ 64 ] ;
GetEntityClassname ( g_aEntityLagData [ i ] . iEntity , sClassname , sizeof ( sClassname ) ) ;
char sTargetname [ 64 ] ;
GetEntPropString ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
int iHammerID = GetEntProp ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iHammerID " ) ;
PrintToBoth ( " [%d] entity %d (%s) \" %s \" (#%d) index %d GOING TO SLEEP " , GetGameTickCount ( ) , g_aEntityLagData [ i ] . iEntity , sClassname , sTargetname , iHammerID , i ) ;
}
2019-10-03 12:02:23 +02:00
}
else
{
if ( g_aEntityLagData [ i ] . iNotMoving > = MAX_RECORDS )
2019-10-03 22:09:53 +02:00
{
char sClassname [ 64 ] ;
GetEntityClassname ( g_aEntityLagData [ i ] . iEntity , sClassname , sizeof ( sClassname ) ) ;
char sTargetname [ 64 ] ;
GetEntPropString ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
int iHammerID = GetEntProp ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iHammerID " ) ;
PrintToBoth ( " [%d] entity %d (%s) \" %s \" (#%d) index %d WAKING UP " , GetGameTickCount ( ) , g_aEntityLagData [ i ] . iEntity , sClassname , sTargetname , iHammerID , i ) ;
}
2019-10-03 12:02:23 +02:00
g_aEntityLagData [ i ] . iNotMoving = 0 ;
2019-10-02 18:54:19 +02:00
}
2019-10-03 12:02:23 +02:00
if ( g_aEntityLagData [ i ] . iNotMoving > = MAX_RECORDS )
continue ;
2019-10-02 18:54:19 +02:00
}
2019-10-01 21:45:39 +02:00
g_aEntityLagData [ i ] . iRecordIndex + + ;
if ( g_aEntityLagData [ i ] . iRecordIndex > = MAX_RECORDS )
g_aEntityLagData [ i ] . iRecordIndex = 0 ;
if ( g_aEntityLagData [ i ] . iNumRecords < MAX_RECORDS )
2019-10-02 23:28:20 +02:00
g_aEntityLagData [ i ] . iRecordsValid = + + g_aEntityLagData [ i ] . iNumRecords ;
2019-10-01 21:45:39 +02:00
2019-10-03 12:02:23 +02:00
LagRecord_Copy ( g_aaLagRecords [ i ] [ g_aEntityLagData [ i ] . iRecordIndex ] , TmpRecord ) ;
2019-10-01 21:45:39 +02:00
# if defined DEBUG
2019-10-02 18:54:19 +02:00
LogMessage ( " 4 [%d] index %d, RECORD entity %d into %d " , GetGameTickCount ( ) , i , g_aEntityLagData [ i ] . iEntity , g_aEntityLagData [ i ] . iRecordIndex ) ;
2019-10-01 21:45:39 +02:00
LogMessage ( " %f %f %f " ,
2019-10-03 12:02:23 +02:00
TmpRecord . vecOrigin [ 0 ] ,
TmpRecord . vecOrigin [ 1 ] ,
TmpRecord . vecOrigin [ 2 ]
2019-10-01 21:45:39 +02:00
) ;
# endif
}
2019-10-02 14:19:09 +02:00
g_bBlockPhysics = false ;
2019-10-01 21:45:39 +02:00
}
void RecordDataIntoRecord ( int iEntity , LagRecord Record )
{
2019-10-02 23:28:20 +02:00
SDKCall ( g_hGetAbsOrigin , iEntity , Record . vecOrigin ) ;
SDKCall ( g_hGetAbsAngles , iEntity , Record . vecAngles ) ;
2019-10-01 21:45:39 +02:00
}
2019-10-02 12:22:35 +02:00
void RestoreEntityFromRecord ( int iEntity , int iFilter , LagRecord Record )
2019-10-01 21:45:39 +02:00
{
2019-10-02 12:22:35 +02:00
FilterTriggerMoved ( iFilter ) ;
2019-10-03 22:09:53 +02:00
BlockSolidMoved ( iFilter ) ;
2019-10-02 14:19:09 +02:00
2019-10-02 18:54:19 +02:00
SDKCall ( g_hSetAbsAngles , iEntity , Record . vecAngles ) ;
SDKCall ( g_hSetAbsOrigin , iEntity , Record . vecOrigin ) ;
2019-10-02 14:19:09 +02:00
2019-10-03 22:09:53 +02:00
BlockSolidMoved ( - 1 ) ;
2019-10-02 12:22:35 +02:00
FilterTriggerMoved ( - 1 ) ;
2019-10-01 21:45:39 +02:00
}
bool AddEntityForLagCompensation ( int iEntity )
{
2019-10-03 10:39:27 +02:00
if ( g_iNumEntities = = MAX_ENTITIES )
return false ;
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
if ( g_aEntityLagData [ i ] . iEntity = = iEntity )
return true ;
}
2019-10-03 12:02:23 +02:00
int i = g_iNumEntities ;
g_iNumEntities + + ;
2019-10-01 21:45:39 +02:00
2019-10-03 12:02:23 +02:00
g_aEntityLagData [ i ] . iEntity = iEntity ;
2019-10-03 22:09:53 +02:00
g_aEntityLagData [ i ] . iRecordIndex = 0 ;
g_aEntityLagData [ i ] . iNumRecords = 1 ;
g_aEntityLagData [ i ] . iRecordsValid = 1 ;
2019-10-03 12:02:23 +02:00
g_aEntityLagData [ i ] . iDeleted = 0 ;
g_aEntityLagData [ i ] . iNotMoving = MAX_RECORDS ;
g_aEntityLagData [ i ] . bRestore = false ;
2019-10-02 23:28:20 +02:00
2019-10-03 22:09:53 +02:00
RecordDataIntoRecord ( g_aEntityLagData [ i ] . iEntity , g_aaLagRecords [ i ] [ 0 ] ) ;
2019-10-03 12:02:23 +02:00
{
char sClassname [ 64 ] ;
GetEntityClassname ( g_aEntityLagData [ i ] . iEntity , sClassname , sizeof ( sClassname ) ) ;
2019-10-02 23:28:20 +02:00
2019-10-03 12:02:23 +02:00
char sTargetname [ 64 ] ;
GetEntPropString ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
2019-10-02 23:28:20 +02:00
2019-10-03 12:02:23 +02:00
int iHammerID = GetEntProp ( g_aEntityLagData [ i ] . iEntity , Prop_Data , " m_iHammerID " ) ;
2019-10-03 10:39:27 +02:00
2019-10-03 22:09:53 +02:00
PrintToBoth ( " [%d] added entity %d (%s) \" %s \" (#%d) under index %d " , GetGameTickCount ( ) , iEntity , sClassname , sTargetname , iHammerID , i ) ;
2019-10-01 21:45:39 +02:00
}
2019-10-03 10:39:27 +02:00
2019-10-03 12:02:23 +02:00
return true ;
2019-10-01 21:45:39 +02:00
}
public void OnEntitySpawned ( int entity , const char [ ] classname )
{
if ( entity < 0 | | entity > sizeof ( g_bNoPhysics ) )
return ;
2019-10-03 10:39:27 +02:00
if ( ! strncmp ( classname , " func_physbox " , 12 ) )
2019-10-02 23:28:20 +02:00
{
AddEntityForLagCompensation ( entity ) ;
return ;
}
2019-10-03 22:09:53 +02:00
if ( ! ( StrEqual ( classname , " trigger_hurt " ) ) )
2019-10-01 21:45:39 +02:00
return ;
2019-10-02 18:54:19 +02:00
int iParent = entity ;
2019-10-01 21:45:39 +02:00
char sParentClassname [ 64 ] ;
2019-10-02 18:54:19 +02:00
bool bGoodParents = false ;
for ( ; ; )
{
iParent = GetEntPropEnt ( iParent , Prop_Data , " m_pParent " ) ;
if ( iParent = = - 1 )
break ;
2019-10-01 21:45:39 +02:00
2019-10-02 18:54:19 +02:00
GetEntityClassname ( iParent , sParentClassname , sizeof ( sParentClassname ) ) ;
2019-10-03 10:39:27 +02:00
if ( strncmp ( sParentClassname , " func_ " , 5 ) )
continue ;
if ( StrEqual ( sParentClassname [ 5 ] , " movelinear " ) | |
StrEqual ( sParentClassname [ 5 ] , " door " ) | |
StrEqual ( sParentClassname [ 5 ] , " tracktrain " ) | |
! strncmp ( sParentClassname [ 5 ] , " physbox " , 7 ) )
2019-10-02 18:54:19 +02:00
{
bGoodParents = true ;
break ;
}
}
if ( iParent = = - 1 )
return ;
2019-10-01 21:45:39 +02:00
2019-10-02 18:54:19 +02:00
if ( ! bGoodParents )
2019-10-01 21:45:39 +02:00
return ;
2019-10-02 18:54:19 +02:00
if ( ! AddEntityForLagCompensation ( entity ) )
2019-10-01 21:45:39 +02:00
return ;
g_bNoPhysics [ entity ] = true ;
2019-10-03 22:09:53 +02:00
{
char sTargetname [ 64 ] ;
GetEntPropString ( entity , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
char sParentTargetname [ 64 ] ;
GetEntPropString ( iParent , Prop_Data , " m_iName " , sParentTargetname , sizeof ( sParentTargetname ) ) ;
PrintToBoth ( " added %s %s | parent: %s %s " , classname , sTargetname , sParentClassname , sParentTargetname ) ;
}
2019-10-01 21:45:39 +02:00
}
public void OnEntityDestroyed ( int entity )
{
if ( entity < 0 | | entity > sizeof ( g_bNoPhysics ) )
return ;
g_bNoPhysics [ entity ] = false ;
2019-10-03 12:02:23 +02:00
for ( int i = 0 ; i < g_iNumEntities ; i + + )
2019-10-01 21:45:39 +02:00
{
2019-10-03 10:39:27 +02:00
if ( g_aEntityLagData [ i ] . iEntity ! = entity )
continue ;
2019-10-03 12:02:23 +02:00
RemoveRecord ( i ) ;
2019-10-03 10:39:27 +02:00
return ;
2019-10-01 21:45:39 +02:00
}
}
2019-10-03 12:02:23 +02:00
void RemoveRecord ( int index )
{
2019-10-03 22:09:53 +02:00
{
char sClassname [ 64 ] ;
GetEntityClassname ( g_aEntityLagData [ index ] . iEntity , sClassname , sizeof ( sClassname ) ) ;
char sTargetname [ 64 ] ;
GetEntPropString ( g_aEntityLagData [ index ] . iEntity , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
int iHammerID = GetEntProp ( g_aEntityLagData [ index ] . iEntity , Prop_Data , " m_iHammerID " ) ;
PrintToBoth ( " [%d] RemoveRecord %d / %d (%s) \" %s \" (#%d), num: %d " , GetGameTickCount ( ) , index , g_aEntityLagData [ index ] . iEntity , sClassname , sTargetname , iHammerID , g_iNumEntities ) ;
}
g_aEntityLagData [ index ] . iEntity = - 1 ;
2019-10-03 12:02:23 +02:00
for ( int src = index + 1 ; src < g_iNumEntities ; src + + )
{
int dest = src - 1 ;
EntityLagData_Copy ( g_aEntityLagData [ dest ] , g_aEntityLagData [ src ] ) ;
2019-10-03 22:09:53 +02:00
g_aEntityLagData [ src ] . iEntity = - 1 ;
2019-10-03 12:02:23 +02:00
int iNumRecords = g_aEntityLagData [ dest ] . iNumRecords ;
for ( int i = 0 ; i < iNumRecords ; i + + )
{
LagRecord_Copy ( g_aaLagRecords [ dest ] [ i ] , g_aaLagRecords [ src ] [ i ] ) ;
}
}
g_iNumEntities - - ;
}
void EntityLagData_Copy ( EntityLagData obj , const EntityLagData other )
{
obj . iEntity = other . iEntity ;
obj . iRecordIndex = other . iRecordIndex ;
obj . iNumRecords = other . iNumRecords ;
obj . iRecordsValid = other . iRecordsValid ;
obj . iDeleted = other . iDeleted ;
obj . iNotMoving = other . iNotMoving ;
obj . bRestore = other . bRestore ;
LagRecord_Copy ( obj . RestoreData , other . RestoreData ) ;
}
void LagRecord_Copy ( LagRecord obj , const LagRecord other )
{
obj . vecOrigin [ 0 ] = other . vecOrigin [ 0 ] ;
obj . vecOrigin [ 1 ] = other . vecOrigin [ 1 ] ;
obj . vecOrigin [ 2 ] = other . vecOrigin [ 2 ] ;
obj . vecAngles [ 0 ] = other . vecAngles [ 0 ] ;
obj . vecAngles [ 1 ] = other . vecAngles [ 1 ] ;
obj . vecAngles [ 2 ] = other . vecAngles [ 2 ] ;
}
2019-10-03 22:09:53 +02:00
stock void PrintToBoth ( const char [ ] format , any . . . )
{
char buffer [ 254 ] ;
VFormat ( buffer , sizeof ( buffer ) , format , 2 ) ;
LogMessage ( buffer ) ;
for ( int i = 1 ; i < = MaxClients ; i + + )
{
if ( IsClientInGame ( i ) )
{
PrintToConsole ( i , " %s " , buffer ) ;
}
}
}