LagCompensation: fixes and improvements

This commit is contained in:
BotoX 2019-10-20 12:44:34 +02:00
parent 699deab40a
commit 9b22f87169
1 changed files with 62 additions and 28 deletions

View File

@ -22,7 +22,7 @@ bool g_bLateLoad = false;
#define MAX_EDICTS 2048 #define MAX_EDICTS 2048
#define MAX_RECORDS 32 #define MAX_RECORDS 32
#define MAX_ENTITIES 64 #define MAX_ENTITIES 128
//#define DEBUG //#define DEBUG
enum struct LagRecord enum struct LagRecord
@ -43,6 +43,7 @@ enum struct EntityLagData
int iNotMoving; int iNotMoving;
int iTouchStamp; int iTouchStamp;
bool bRestore; bool bRestore;
bool bLateKill;
LagRecord RestoreData; LagRecord RestoreData;
} }
@ -59,7 +60,7 @@ Handle g_hUTIL_Remove;
Handle g_hRestartRound; Handle g_hRestartRound;
char g_aBlockTriggerTouch[MAX_EDICTS] = {0, ...}; char g_aBlockTriggerTouch[MAX_EDICTS] = {0, ...};
char g_aaDeleted[MAXPLAYERS + 1][MAX_EDICTS]; char g_aaBlockTouch[MAXPLAYERS + 1][MAX_EDICTS];
public void OnPluginStart() public void OnPluginStart()
{ {
@ -131,14 +132,14 @@ public void OnPluginStart()
RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_RCON, "sm_unlag <entidx>"); RegAdminCmd("sm_unlag", Command_AddLagCompensation, ADMFLAG_RCON, "sm_unlag <entidx>");
RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_GENERIC, "sm_lagged"); RegAdminCmd("sm_lagged", Command_CheckLagCompensated, ADMFLAG_GENERIC, "sm_lagged");
FilterClientEntityMap(g_aaDeleted, true); FilterClientEntityMap(g_aaBlockTouch, true);
} }
public Action Command_AddLagCompensation(int client, int argc) public Action Command_AddLagCompensation(int client, int argc)
{ {
if(argc < 1) if(argc < 1)
{ {
ReplyToCommand(client, "[SM] Usage: sm_unlag <entidx>"); ReplyToCommand(client, "[SM] Usage: sm_unlag <entidx> [late]");
return Plugin_Handled; return Plugin_Handled;
} }
@ -147,7 +148,14 @@ public Action Command_AddLagCompensation(int client, int argc)
int entity = StringToInt(sArgs); int entity = StringToInt(sArgs);
AddEntityForLagCompensation(entity); bool late = false;
if(argc >= 2)
{
GetCmdArg(2, sArgs, sizeof(sArgs));
late = view_as<bool>(StringToInt(sArgs));
}
AddEntityForLagCompensation(entity, late);
g_aBlockTriggerTouch[entity] = 1; g_aBlockTriggerTouch[entity] = 1;
return Plugin_Handled; return Plugin_Handled;
@ -173,7 +181,7 @@ public Action Command_CheckLagCompensated(int client, int argc)
bool bDeleted = false; bool bDeleted = false;
for(int j = 1; j <= MaxClients; j++) for(int j = 1; j <= MaxClients; j++)
{ {
if(g_aaDeleted[j][i]) if(g_aaBlockTouch[j][i])
{ {
bDeleted = true; bDeleted = true;
break; break;
@ -214,7 +222,7 @@ public Action Command_CheckLagCompensated(int client, int argc)
public void OnPluginEnd() public void OnPluginEnd()
{ {
g_bCleaningUp = true; g_bCleaningUp = true;
FilterClientEntityMap(g_aaDeleted, false); FilterClientEntityMap(g_aaBlockTouch, false);
FilterTriggerTouchPlayers(g_aBlockTriggerTouch, false); FilterTriggerTouchPlayers(g_aBlockTriggerTouch, false);
DHookDisableDetour(g_hUTIL_Remove, false, Detour_OnUTIL_Remove); DHookDisableDetour(g_hUTIL_Remove, false, Detour_OnUTIL_Remove);
@ -251,6 +259,14 @@ public MRESReturn Detour_OnUTIL_Remove(Handle hParams)
if(g_aEntityLagData[i].iEntity != entity) if(g_aEntityLagData[i].iEntity != entity)
continue; continue;
// let it die
if(!g_aEntityLagData[i].bLateKill)
break;
// ignore sleeping entities
if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS)
break;
if(!g_aEntityLagData[i].iDeleted) if(!g_aEntityLagData[i].iDeleted)
{ {
g_aEntityLagData[i].iDeleted = GetGameTickCount(); g_aEntityLagData[i].iDeleted = GetGameTickCount();
@ -271,13 +287,13 @@ public MRESReturn Detour_OnRestartRound()
{ {
g_aBlockTriggerTouch[g_aEntityLagData[i].iEntity] = 0; g_aBlockTriggerTouch[g_aEntityLagData[i].iEntity] = 0;
for(int client = 1; client <= MaxClients; client++)
{
g_aaBlockTouch[client][g_aEntityLagData[i].iEntity] = 0;
}
if(g_aEntityLagData[i].iDeleted) 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)) if(IsValidEntity(g_aEntityLagData[i].iEntity))
RemoveEdict(g_aEntityLagData[i].iEntity); RemoveEdict(g_aEntityLagData[i].iEntity);
} }
@ -342,6 +358,7 @@ public void OnRunThinkFunctions(bool simulating)
// so the correct +1'd touchStamp is stored in the touchlink. // so the correct +1'd touchStamp is stored in the touchlink.
// After simulating the players we restore the old touchStamp (-1) and when the entity is simulated it will increase it again by 1 // After simulating the players we restore the old touchStamp (-1) and when the entity is simulated it will increase it again by 1
// Thus both touchlinks will have the correct touchStamp value. // Thus both touchlinks will have the correct touchStamp value.
// The touchStamp doesn't increase when the entity is idle, however it also doesn't check untouch so we're fine.
touchStamp++; touchStamp++;
SetEntProp(g_aEntityLagData[i].iEntity, Prop_Data, "touchStamp", touchStamp); SetEntProp(g_aEntityLagData[i].iEntity, Prop_Data, "touchStamp", touchStamp);
@ -380,22 +397,33 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
if(!IsPlayerAlive(client)) if(!IsPlayerAlive(client))
return Plugin_Continue; return Plugin_Continue;
int iDelta = GetGameTickCount() - tickcount; int iGameTick = GetGameTickCount();
int iDelta = iGameTick - tickcount;
if(iDelta < 0) if(iDelta < 0)
iDelta = 0; iDelta = 0;
if(iDelta > MAX_RECORDS) if(iDelta > MAX_RECORDS)
iDelta = MAX_RECORDS; iDelta = MAX_RECORDS;
int iPlayerSimTick = GetGameTickCount() + iDelta; int iPlayerSimTick = iGameTick + iDelta;
for(int i = 0; i < g_iNumEntities; i++) for(int i = 0; i < g_iNumEntities; i++)
{ {
if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS) int iEntity = g_aEntityLagData[i].iEntity;
continue;
// Entity too new, the client couldn't even see it yet. // Entity too new, the client couldn't even see it yet.
if(g_aEntityLagData[i].iSpawned < iPlayerSimTick) if(g_aEntityLagData[i].iSpawned < iPlayerSimTick)
{
g_aaBlockTouch[client][iEntity] = 1;
continue;
}
else if(g_aEntityLagData[i].iSpawned == iPlayerSimTick)
{
g_aaBlockTouch[client][iEntity] = 0;
}
if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS)
continue; continue;
if(iDelta >= g_aEntityLagData[i].iNumRecords) if(iDelta >= g_aEntityLagData[i].iNumRecords)
@ -403,10 +431,10 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
if(g_aEntityLagData[i].iDeleted) if(g_aEntityLagData[i].iDeleted)
{ {
int iEntitySimTick = GetGameTickCount() - iDelta; int iEntitySimTick = iGameTick - iDelta;
if(iEntitySimTick > g_aEntityLagData[i].iDeleted) if(iEntitySimTick > g_aEntityLagData[i].iDeleted)
{ {
g_aaDeleted[client][g_aEntityLagData[i].iEntity] = 1; g_aaBlockTouch[client][iEntity] = 1;
continue; continue;
} }
} }
@ -415,11 +443,11 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
if(iRecordIndex < 0) if(iRecordIndex < 0)
iRecordIndex += MAX_RECORDS; iRecordIndex += MAX_RECORDS;
RestoreEntityFromRecord(g_aEntityLagData[i].iEntity, g_aaLagRecords[i][iRecordIndex]); RestoreEntityFromRecord(iEntity, g_aaLagRecords[i][iRecordIndex]);
g_aEntityLagData[i].bRestore = !g_aEntityLagData[i].iDeleted; g_aEntityLagData[i].bRestore = !g_aEntityLagData[i].iDeleted;
#if defined DEBUG #if defined DEBUG
LogMessage("2 [%d] index %d, Entity %d -> iDelta = %d | Record = %d", GetGameTickCount(), i, g_aEntityLagData[i].iEntity, iDelta, iRecordIndex); LogMessage("2 [%d] index %d, Entity %d -> iDelta = %d | Record = %d", iGameTick, i, iEntity, iDelta, iRecordIndex);
LogMessage("%f %f %f", LogMessage("%f %f %f",
g_aaLagRecords[i][iRecordIndex].vecOrigin[0], g_aaLagRecords[i][iRecordIndex].vecOrigin[0],
g_aaLagRecords[i][iRecordIndex].vecOrigin[1], g_aaLagRecords[i][iRecordIndex].vecOrigin[1],
@ -487,6 +515,8 @@ public void OnRunThinkFunctionsPost(bool simulating)
g_aaLagRecords[i][iOldRecord].vecOrigin[2] == TmpRecord.vecOrigin[2]) g_aaLagRecords[i][iOldRecord].vecOrigin[2] == TmpRecord.vecOrigin[2])
{ {
g_aEntityLagData[i].iNotMoving++; g_aEntityLagData[i].iNotMoving++;
#if defined DEBUG
if(g_aEntityLagData[i].iNotMoving == MAX_RECORDS) if(g_aEntityLagData[i].iNotMoving == MAX_RECORDS)
{ {
char sClassname[64]; char sClassname[64];
@ -499,9 +529,11 @@ public void OnRunThinkFunctionsPost(bool simulating)
PrintToBoth("[%d] entity %d (%s)\"%s\"(#%d) index %d GOING TO SLEEP", GetGameTickCount(), g_aEntityLagData[i].iEntity, sClassname, sTargetname, iHammerID, i); PrintToBoth("[%d] entity %d (%s)\"%s\"(#%d) index %d GOING TO SLEEP", GetGameTickCount(), g_aEntityLagData[i].iEntity, sClassname, sTargetname, iHammerID, i);
} }
#endif
} }
else else
{ {
#if defined DEBUG
if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS) if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS)
{ {
char sClassname[64]; char sClassname[64];
@ -514,6 +546,8 @@ public void OnRunThinkFunctionsPost(bool simulating)
PrintToBoth("[%d] entity %d (%s)\"%s\"(#%d) index %d WAKING UP", GetGameTickCount(), g_aEntityLagData[i].iEntity, sClassname, sTargetname, iHammerID, i); PrintToBoth("[%d] entity %d (%s)\"%s\"(#%d) index %d WAKING UP", GetGameTickCount(), g_aEntityLagData[i].iEntity, sClassname, sTargetname, iHammerID, i);
} }
#endif
g_aEntityLagData[i].iNotMoving = 0; g_aEntityLagData[i].iNotMoving = 0;
} }
@ -558,7 +592,7 @@ void RestoreEntityFromRecord(int iEntity, LagRecord Record)
SetEntPropFloat(iEntity, Prop_Data, "m_flSimulationTime", Record.flSimulationTime); SetEntPropFloat(iEntity, Prop_Data, "m_flSimulationTime", Record.flSimulationTime);
} }
bool AddEntityForLagCompensation(int iEntity) bool AddEntityForLagCompensation(int iEntity, bool bLateKill)
{ {
if(g_bCleaningUp) if(g_bCleaningUp)
return false; return false;
@ -594,6 +628,7 @@ bool AddEntityForLagCompensation(int iEntity)
g_aEntityLagData[i].iDeleted = 0; g_aEntityLagData[i].iDeleted = 0;
g_aEntityLagData[i].iNotMoving = MAX_RECORDS; g_aEntityLagData[i].iNotMoving = MAX_RECORDS;
g_aEntityLagData[i].bRestore = false; g_aEntityLagData[i].bRestore = false;
g_aEntityLagData[i].bLateKill = bLateKill;
RecordDataIntoRecord(iEntity, g_aaLagRecords[i][0]); RecordDataIntoRecord(iEntity, g_aaLagRecords[i][0]);
@ -625,7 +660,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
if(!strncmp(classname, "func_physbox", 12)) if(!strncmp(classname, "func_physbox", 12))
{ {
AddEntityForLagCompensation(entity); AddEntityForLagCompensation(entity, false);
return; return;
} }
@ -648,6 +683,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
if(StrEqual(sParentClassname[5], "movelinear") || if(StrEqual(sParentClassname[5], "movelinear") ||
StrEqual(sParentClassname[5], "door") || StrEqual(sParentClassname[5], "door") ||
StrEqual(sParentClassname[5], "rotating") ||
StrEqual(sParentClassname[5], "tracktrain") || StrEqual(sParentClassname[5], "tracktrain") ||
!strncmp(sParentClassname[5], "physbox", 7)) !strncmp(sParentClassname[5], "physbox", 7))
{ {
@ -662,7 +698,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
if(!bGoodParents) if(!bGoodParents)
return; return;
if(!AddEntityForLagCompensation(entity)) if(!AddEntityForLagCompensation(entity, true))
return; return;
g_aBlockTriggerTouch[entity] = 1; g_aBlockTriggerTouch[entity] = 1;
@ -708,12 +744,9 @@ void RemoveRecord(int index)
g_aBlockTriggerTouch[g_aEntityLagData[index].iEntity] = 0; g_aBlockTriggerTouch[g_aEntityLagData[index].iEntity] = 0;
if(g_aEntityLagData[index].iDeleted) for(int client = 1; client <= MaxClients; client++)
{ {
for(int client = 1; client <= MaxClients; client++) g_aaBlockTouch[client][g_aEntityLagData[index].iEntity] = 0;
{
g_aaDeleted[client][g_aEntityLagData[index].iEntity] = 0;
}
} }
g_aEntityLagData[index].iEntity = INVALID_ENT_REFERENCE; g_aEntityLagData[index].iEntity = INVALID_ENT_REFERENCE;
@ -746,6 +779,7 @@ void EntityLagData_Copy(EntityLagData obj, const EntityLagData other)
obj.iNotMoving = other.iNotMoving; obj.iNotMoving = other.iNotMoving;
obj.iTouchStamp = other.iTouchStamp; obj.iTouchStamp = other.iTouchStamp;
obj.bRestore = other.bRestore; obj.bRestore = other.bRestore;
obj.bLateKill = other.bLateKill;
LagRecord_Copy(obj.RestoreData, other.RestoreData); LagRecord_Copy(obj.RestoreData, other.RestoreData);
} }