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 ] ;
2019-10-06 20:24:43 +02:00
float flSimulationTime ;
2019-10-01 21:45:39 +02:00
}
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 ;
2019-10-06 20:24:43 +02:00
bool bDoPhysics ;
2019-10-01 21:45:39 +02:00
LagRecord RestoreData ;
}
LagRecord g_aaLagRecords [ MAX_ENTITIES ] [ MAX_RECORDS ] ;
EntityLagData g_aEntityLagData [ MAX_ENTITIES ] ;
int g_iNumEntities = 0 ;
2019-10-05 15:17:10 +02:00
bool g_bCleaningUp = false ;
2019-10-01 21:45:39 +02:00
2019-10-05 15:17:10 +02:00
Handle g_hPhysicsTouchTriggers ;
2019-10-02 23:28:20 +02:00
Handle g_hGetAbsOrigin ;
2019-10-02 18:54:19 +02:00
Handle g_hSetAbsOrigin ;
2019-10-06 20:24:43 +02:00
Handle g_hSetLocalAngles ;
2019-10-01 21:45:39 +02:00
2019-10-05 15:17:10 +02:00
Handle g_hPhysicsTouchTriggersDetour ;
2019-10-02 23:28:20 +02:00
Handle g_hUTIL_Remove ;
2019-10-03 22:09:53 +02:00
Handle g_hRestartRound ;
2019-10-05 15:17:10 +02:00
bool g_bBlockPhysics = false ;
2019-10-06 20:24:43 +02:00
char g_aBlockPhysics [ 2048 ] = { 0 , . . . } ;
2019-10-05 15:17:10 +02:00
char g_aaDeleted [ MAXPLAYERS + 1 ] [ 2048 ] ;
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-05 15:17:10 +02:00
// CBaseEntity::PhysicsTouchTriggers
StartPrepSDKCall ( SDKCall_Entity ) ;
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " CBaseEntity::PhysicsTouchTriggers " ) )
{
delete hGameData ;
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" CBaseEntity::PhysicsTouchTriggers \" ) failed! " ) ;
}
PrepSDKCall_AddParameter ( SDKType_Vector , SDKPass_ByRef ) ;
g_hPhysicsTouchTriggers = EndPrepSDKCall ( ) ;
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-06 20:24:43 +02:00
// CBaseEntity::SetLocalAngles
2019-10-01 21:45:39 +02:00
StartPrepSDKCall ( SDKCall_Entity ) ;
2019-10-06 20:24:43 +02:00
if ( ! PrepSDKCall_SetFromConf ( hGameData , SDKConf_Signature , " SetLocalAngles " ) )
2019-10-01 21:45:39 +02:00
{
delete hGameData ;
2019-10-06 20:24:43 +02:00
SetFailState ( " PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, \" SetLocalAngles \" ) failed! " ) ;
2019-10-01 21:45:39 +02:00
}
PrepSDKCall_AddParameter ( SDKType_QAngle , SDKPass_ByRef ) ;
2019-10-06 20:24:43 +02:00
g_hSetLocalAngles = EndPrepSDKCall ( ) ;
2019-10-01 21:45:39 +02:00
2019-10-02 23:28:20 +02:00
// CBaseEntity::PhysicsTouchTriggers
2019-10-05 15:17:10 +02:00
g_hPhysicsTouchTriggersDetour = DHookCreateFromConf ( hGameData , " CBaseEntity__PhysicsTouchTriggers " ) ;
if ( ! g_hPhysicsTouchTriggersDetour )
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
2019-10-05 15:17:10 +02:00
if ( ! DHookEnableDetour ( g_hPhysicsTouchTriggersDetour , 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 " ) ;
}
2019-10-02 23:28:20 +02:00
2019-10-03 22:09:53 +02:00
if ( ! DHookEnableDetour ( g_hRestartRound , false , Detour_OnRestartRound ) )
2019-10-05 15:17:10 +02:00
{
delete hGameData ;
2019-10-03 22:09:53 +02:00
SetFailState ( " Failed to detour CCSGameRules__RestartRound. " ) ;
2019-10-05 15:17:10 +02:00
}
delete hGameData ;
2019-10-06 20:24:43 +02:00
RegAdminCmd ( " sm_unlag " , Command_AddLagCompensation , ADMFLAG_RCON , " sm_unlag <entidx> [trigger 0/1] " ) ;
RegAdminCmd ( " sm_lagged " , Command_CheckLagCompensated , ADMFLAG_GENERIC , " sm_lagged " ) ;
2019-10-05 15:17:10 +02:00
FilterClientEntityMap ( g_aaDeleted , true ) ;
2019-10-02 23:28:20 +02:00
}
2019-10-05 15:17:10 +02:00
public Action Command_AddLagCompensation ( int client , int argc )
{
if ( argc < 1 )
{
ReplyToCommand ( client , " [SM] Usage: sm_unlag <entidx> " ) ;
return Plugin_Handled ;
}
char sArgs [ 32 ] ;
GetCmdArg ( 1 , sArgs , sizeof ( sArgs ) ) ;
int entity = StringToInt ( sArgs ) ;
2019-10-06 20:24:43 +02:00
int physics = 0 ;
if ( argc > = 2 )
{
GetCmdArg ( 2 , sArgs , sizeof ( sArgs ) ) ;
physics = StringToInt ( sArgs ) ;
}
2019-10-05 15:17:10 +02:00
2019-10-06 20:24:43 +02:00
AddEntityForLagCompensation ( entity , view_as < bool > ( physics ) ) ;
2019-10-05 15:17:10 +02:00
g_aBlockPhysics [ entity ] = 1 ;
return Plugin_Handled ;
}
2019-10-02 23:28:20 +02:00
2019-10-06 20:24:43 +02:00
public Action Command_CheckLagCompensated ( int client , int argc )
{
for ( int i = 0 ; i < g_iNumEntities ; i + + )
{
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 " ) ;
PrintToConsole ( client , " %2d. #%d %s \" %s \" (#%d) " , i , g_aEntityLagData [ i ] . iEntity , sClassname , sTargetname , iHammerID ) ;
}
for ( int i = 0 ; i < 2048 ; i + + )
{
bool bDeleted = false ;
for ( int j = 1 ; j < = MaxClients ; j + + )
{
if ( g_aaDeleted [ j ] [ i ] )
{
bDeleted = true ;
break ;
}
}
if ( g_aBlockPhysics [ i ] | | bDeleted )
{
int index = - 1 ;
for ( int j = 0 ; j < g_iNumEntities ; j + + )
{
if ( g_aEntityLagData [ j ] . iEntity = = i )
{
index = j ;
break ;
}
}
char sClassname [ 64 ] = " INVALID " ;
char sTargetname [ 64 ] = " INVALID " ;
int iHammerID = - 1 ;
if ( IsValidEntity ( i ) )
{
GetEntityClassname ( i , sClassname , sizeof ( sClassname ) ) ;
GetEntPropString ( i , Prop_Data , " m_iName " , sTargetname , sizeof ( sTargetname ) ) ;
iHammerID = GetEntProp ( i , Prop_Data , " m_iHammerID " ) ;
}
bool bBlockPhysics = g_aBlockPhysics [ i ] ;
PrintToConsole ( client , " %2d. #%d %s \" %s \" (#%d) -> BlockPhysics: %d / Deleted: %d " , index , i , sClassname , sTargetname , iHammerID , bBlockPhysics , bDeleted ) ;
}
}
return Plugin_Handled ;
}
2019-10-03 22:09:53 +02:00
public void OnPluginEnd ( )
{
2019-10-05 15:17:10 +02:00
g_bCleaningUp = true ;
FilterClientEntityMap ( g_aaDeleted , false ) ;
2019-10-04 11:23:05 +02:00
DHookDisableDetour ( g_hUTIL_Remove , false , Detour_OnUTIL_Remove ) ;
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 )
{
RemoveEdict ( g_aEntityLagData [ i ] . iEntity ) ;
}
}
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-05 15:17:10 +02:00
if ( entity < 0 | | entity > sizeof ( g_aBlockPhysics ) )
2019-10-01 21:45:39 +02:00
return MRES_Ignored ;
2019-10-05 15:17:10 +02:00
if ( g_aBlockPhysics [ entity ] )
2019-10-01 21:45:39 +02:00
{
return MRES_Supercede ;
}
2019-10-06 20:24:43 +02:00
2019-10-01 21:45:39 +02:00
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-05 15:17:10 +02:00
if ( g_bCleaningUp )
return MRES_Ignored ;
2019-10-02 23:28:20 +02:00
int entity = DHookGetParam ( hParams , 1 ) ;
2019-10-05 15:17:10 +02:00
if ( entity < 0 | | entity > sizeof ( g_aBlockPhysics ) )
2019-10-02 23:28:20 +02:00
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 ;
if ( ! g_aEntityLagData [ i ] . iDeleted )
2019-10-05 15:17:10 +02:00
{
2019-10-02 23:28:20 +02:00
g_aEntityLagData [ i ] . iDeleted = GetGameTickCount ( ) ;
2019-10-06 20:24:43 +02:00
PrintToBoth ( " [%d] !!!!!!!!!!! Detour_OnUTIL_Remove: %d / ent: %d " , GetGameTickCount ( ) , i , entity ) ;
2019-10-05 15:17:10 +02:00
}
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 ( )
{
2019-10-05 15:17:10 +02:00
g_bCleaningUp = true ;
2019-10-03 22:09:53 +02:00
PrintToBoth ( " Detour_OnRestartRound with %d entries. " , g_iNumEntities ) ;
for ( int i = 0 ; i < g_iNumEntities ; i + + )
{
2019-10-05 15:17:10 +02:00
g_aBlockPhysics [ g_aEntityLagData [ i ] . iEntity ] = 0 ;
if ( g_aEntityLagData [ i ] . iDeleted )
{
for ( int client = 1 ; client < = MaxClients ; client + + )
{
g_aaDeleted [ client ] [ g_aEntityLagData [ i ] . iEntity ] = 0 ;
}
if ( IsValidEntity ( g_aEntityLagData [ i ] . iEntity ) )
RemoveEdict ( g_aEntityLagData [ i ] . iEntity ) ;
}
2019-10-06 20:24:43 +02:00
g_aEntityLagData [ i ] . iEntity = INVALID_ENT_REFERENCE ;
2019-10-03 22:09:53 +02:00
}
g_iNumEntities = 0 ;
2019-10-05 15:17:10 +02:00
g_bCleaningUp = false ;
2019-10-03 22:09:53 +02:00
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
{
if ( ! IsValidEntity ( g_aEntityLagData [ i ] . iEntity ) )
{
2019-10-06 20:24:43 +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-05 15:17:10 +02:00
if ( g_aEntityLagData [ i ] . iNotMoving > = MAX_RECORDS )
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 )
2019-10-05 15:17:10 +02:00
{
g_aaDeleted [ client ] [ g_aEntityLagData [ i ] . iEntity ] = 1 ;
2019-10-02 23:28:20 +02:00
continue ;
2019-10-05 15:17:10 +02:00
}
2019-10-02 23:28:20 +02:00
}
2019-10-01 21:45:39 +02:00
int iRecordIndex = g_aEntityLagData [ i ] . iRecordIndex - delta ;
if ( iRecordIndex < 0 )
iRecordIndex + = MAX_RECORDS ;
2019-10-06 20:24:43 +02:00
RestoreEntityFromRecord ( g_aEntityLagData [ i ] . iEntity , client , g_aEntityLagData [ i ] . bDoPhysics , g_aaLagRecords [ i ] [ iRecordIndex ] ) ;
2019-10-04 11:23:05 +02:00
g_aEntityLagData [ i ] . bRestore = ! 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-06 20:24:43 +02:00
RestoreEntityFromRecord ( g_aEntityLagData [ i ] . iEntity , 0 , false , 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 ) ;
2019-10-06 20:24:43 +02:00
GetEntPropVector ( iEntity , Prop_Data , " m_angRotation " , Record . vecAngles ) ;
Record . flSimulationTime = GetEntPropFloat ( iEntity , Prop_Data , " m_flSimulationTime " ) ;
2019-10-01 21:45:39 +02:00
}
2019-10-06 20:24:43 +02:00
void RestoreEntityFromRecord ( int iEntity , int iFilter , bool bDoPhysics , LagRecord Record )
2019-10-01 21:45:39 +02:00
{
2019-10-02 12:22:35 +02:00
FilterTriggerMoved ( iFilter ) ;
2019-10-06 20:24:43 +02:00
//BlockSolidMoved(iEntity);
2019-10-02 14:19:09 +02:00
2019-10-06 20:24:43 +02:00
SDKCall ( g_hSetLocalAngles , iEntity , Record . vecAngles ) ;
2019-10-02 18:54:19 +02:00
SDKCall ( g_hSetAbsOrigin , iEntity , Record . vecOrigin ) ;
2019-10-06 20:24:43 +02:00
SetEntPropFloat ( iEntity , Prop_Data , " m_flSimulationTime " , Record . flSimulationTime ) ;
/ *
if ( iFilter & & bDoPhysics )
2019-10-05 15:17:10 +02:00
{
SDKCall ( g_hPhysicsTouchTriggers , iEntity , Record . vecOrigin ) ;
}
2019-10-06 20:24:43 +02:00
* /
//BlockSolidMoved(-1);
2019-10-02 12:22:35 +02:00
FilterTriggerMoved ( - 1 ) ;
2019-10-01 21:45:39 +02:00
}
2019-10-06 20:24:43 +02:00
bool AddEntityForLagCompensation ( int iEntity , bool bDoPhysics )
2019-10-01 21:45:39 +02:00
{
2019-10-05 15:17:10 +02:00
if ( g_bCleaningUp )
return false ;
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-06 20:24:43 +02:00
g_aEntityLagData [ i ] . bDoPhysics = bDoPhysics ;
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 )
{
2019-10-05 15:17:10 +02:00
if ( g_bCleaningUp )
return ;
if ( entity < 0 | | entity > sizeof ( g_aBlockPhysics ) )
2019-10-01 21:45:39 +02:00
return ;
2019-10-06 20:24:43 +02:00
if ( ! IsValidEntity ( entity ) )
return ;
2019-10-03 10:39:27 +02:00
if ( ! strncmp ( classname , " func_physbox " , 12 ) )
2019-10-02 23:28:20 +02:00
{
2019-10-06 20:24:43 +02:00
int iParent = GetEntPropEnt ( iParent , Prop_Data , " m_pParent " ) ;
if ( iParent ! = INVALID_ENT_REFERENCE )
{
AddEntityForLagCompensation ( entity , false ) ;
}
2019-10-02 23:28:20 +02:00
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 " ) ;
2019-10-06 20:24:43 +02:00
if ( iParent = = INVALID_ENT_REFERENCE )
2019-10-02 18:54:19 +02:00
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 ;
}
}
2019-10-06 20:24:43 +02:00
if ( iParent = = INVALID_ENT_REFERENCE )
2019-10-02 18:54:19 +02:00
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-06 20:24:43 +02:00
if ( ! AddEntityForLagCompensation ( entity , true ) )
2019-10-01 21:45:39 +02:00
return ;
2019-10-05 15:17:10 +02:00
g_aBlockPhysics [ entity ] = 1 ;
2019-10-01 21:45:39 +02:00
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 )
{
2019-10-05 15:17:10 +02:00
if ( g_bCleaningUp )
2019-10-01 21:45:39 +02:00
return ;
2019-10-05 15:17:10 +02:00
if ( entity < 0 | | entity > sizeof ( g_aBlockPhysics ) )
return ;
2019-10-01 21:45:39 +02:00
2019-10-06 20:24:43 +02:00
if ( ! IsValidEntity ( entity ) )
return ;
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-05 15:17:10 +02:00
if ( g_bCleaningUp )
return ;
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 ) ;
}
2019-10-05 15:17:10 +02:00
g_aBlockPhysics [ g_aEntityLagData [ index ] . iEntity ] = 0 ;
if ( g_aEntityLagData [ index ] . iDeleted )
{
for ( int client = 1 ; client < = MaxClients ; client + + )
{
g_aaDeleted [ client ] [ g_aEntityLagData [ index ] . iEntity ] = 0 ;
}
}
2019-10-06 20:24:43 +02:00
g_aEntityLagData [ index ] . iEntity = INVALID_ENT_REFERENCE ;
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-06 20:24:43 +02:00
g_aEntityLagData [ src ] . iEntity = INVALID_ENT_REFERENCE ;
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 ;
2019-10-06 20:24:43 +02:00
obj . bDoPhysics = other . bDoPhysics ;
2019-10-03 12:02:23 +02:00
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-06 20:24:43 +02:00
obj . flSimulationTime = other . flSimulationTime ;
2019-10-03 12:02:23 +02:00
}
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 ) ;
}
}
}