Update LagCompensation to 1.0.4

This commit is contained in:
xen 2020-03-16 13:57:35 +02:00
parent 9d5e2707ec
commit c4ecc7f2df
2 changed files with 98 additions and 85 deletions

View File

@ -110,6 +110,12 @@
"linux" "8" "linux" "8"
"windows" "8" "windows" "8"
} }
"CGameRules::EndGameFrame"
{
"linux" "49"
"windows" "48"
}
} }
} }
@ -167,10 +173,6 @@
"signature" "::UTIL_Remove" "signature" "::UTIL_Remove"
"return" "void" "return" "void"
"callconv" "cdecl" "callconv" "cdecl"
"windows"
{
"callconv" "fastcall"
}
"arguments" "arguments"
{ {
"oldObj" "oldObj"
@ -178,6 +180,10 @@
"type" "objectptr" "type" "objectptr"
} }
} }
"windows"
{
"callconv" "fastcall"
}
} }
"CCSGameRules__RestartRound" "CCSGameRules__RestartRound"
@ -232,6 +238,12 @@
"linux" "8" "linux" "8"
"windows" "8" "windows" "8"
} }
"CGameRules::EndGameFrame"
{
"linux" "48"
"windows" "47"
}
} }
} }
} }

View File

@ -5,7 +5,7 @@
#include <dhooks> #include <dhooks>
#include <clientprefs> #include <clientprefs>
#define PLUGIN_VERSION "1.0.1" #define PLUGIN_VERSION "1.0.4"
#define SetBit(%1,%2) ((%1)[(%2) >> 5] |= (1 << ((%2) & 31))) #define SetBit(%1,%2) ((%1)[(%2) >> 5] |= (1 << ((%2) & 31)))
#define ClearBit(%1,%2) ((%1)[(%2) >> 5] &= ~(1 << ((%2) & 31))) #define ClearBit(%1,%2) ((%1)[(%2) >> 5] &= ~(1 << ((%2) & 31)))
@ -19,12 +19,13 @@ public Plugin myinfo =
name = "LagCompensation", name = "LagCompensation",
author = "BotoX", author = "BotoX",
description = "", description = "",
version = "1.0", version = PLUGIN_VERSION,
url = "" url = ""
}; };
bool g_bLateLoad = false; bool g_bLateLoad = false;
bool g_bHasPhysHooks = true; bool g_bHasPhysHooks = true;
bool g_bHasOnEntitySpawned = false;
// Don't change this. // Don't change this.
#define MAX_EDICTS 2048 #define MAX_EDICTS 2048
@ -85,6 +86,8 @@ enum struct LagRecord
float vecAbsOrigin[3]; float vecAbsOrigin[3];
float angRotation[3]; float angRotation[3];
float angAbsRotation[3]; float angAbsRotation[3];
float vecMins[3];
float vecMaxs[3];
float flSimulationTime; float flSimulationTime;
float rgflCoordinateFrame[COORDINATE_FRAME_SIZE]; float rgflCoordinateFrame[COORDINATE_FRAME_SIZE];
} }
@ -100,7 +103,6 @@ enum struct EntityLagData
int iNotMoving; int iNotMoving;
bool bRestore; bool bRestore;
bool bLateKill; bool bLateKill;
LagRecord RestoreData;
} }
LagRecord g_aaLagRecords[MAX_ENTITIES][MAX_RECORDS]; LagRecord g_aaLagRecords[MAX_ENTITIES][MAX_RECORDS];
@ -108,18 +110,26 @@ EntityLagData g_aEntityLagData[MAX_ENTITIES];
int g_iNumEntities = 0; int g_iNumEntities = 0;
bool g_bCleaningUp = true; bool g_bCleaningUp = true;
bool g_bHasOnEntitySpawned = false; // Cache
int g_iGameTick;
float g_fTickInterval;
int g_aLerpTicks[MAXPLAYERS + 1];
// SDKCall
Handle g_hCalcAbsolutePosition; Handle g_hCalcAbsolutePosition;
Handle g_hMarkPartitionHandleDirty; Handle g_hMarkPartitionHandleDirty;
// DHooks Detour
Handle g_hUTIL_Remove; Handle g_hUTIL_Remove;
Handle g_hRestartRound; Handle g_hRestartRound;
Handle g_hSetTarget; Handle g_hSetTarget;
Handle g_hSetTargetPost; Handle g_hSetTargetPost;
Handle g_hFrameUpdatePostEntityThink; Handle g_hFrameUpdatePostEntityThink;
// DHooks Virtual
Handle g_hActivate; Handle g_hActivate;
Handle g_hAcceptInput; Handle g_hAcceptInput;
Handle g_hEndGameFrame;
int g_iNetworkableOuter; int g_iNetworkableOuter;
int g_iParent; int g_iParent;
@ -129,12 +139,13 @@ int g_iSolidFlags;
int g_iSolidType; int g_iSolidType;
int g_iSurroundType; int g_iSurroundType;
int g_iEFlags; int g_iEFlags;
int g_iLerpTime = -1;
int g_iVecOrigin; int g_iVecOrigin;
int g_iVecAbsOrigin; int g_iVecAbsOrigin;
int g_iAngRotation; int g_iAngRotation;
int g_iAngAbsRotation; int g_iAngAbsRotation;
int g_iVecMins;
int g_iVecMaxs;
int g_iSimulationTime; int g_iSimulationTime;
int g_iCoordinateFrame; int g_iCoordinateFrame;
@ -253,6 +264,21 @@ public void OnPluginStart()
SetFailState("GameConfGetOffset(hGameData, \"CServerNetworkableProperty::m_pOuter\") failed!"); SetFailState("GameConfGetOffset(hGameData, \"CServerNetworkableProperty::m_pOuter\") failed!");
} }
int offset = GameConfGetOffset(hGameData, "CGameRules::EndGameFrame");
if(offset == -1)
{
delete hGameData;
SetFailState("Failed to find CGameRules::EndGameFrame offset.");
}
// CGameRules::EndGameFrame
g_hEndGameFrame = DHookCreate(offset, HookType_GameRules, ReturnType_Void, ThisPointer_Ignore, Hook_EndGameFrame);
if(g_hEndGameFrame == INVALID_HANDLE)
{
delete hGameData;
SetFailState("Failed to DHook CGameRules::EndGameFrame.");
}
delete hGameData; delete hGameData;
@ -260,23 +286,35 @@ public void OnPluginStart()
if(!hGameData) if(!hGameData)
SetFailState("Failed to load sdktools gamedata."); SetFailState("Failed to load sdktools gamedata.");
int offset = GameConfGetOffset(hGameData, "Activate"); offset = GameConfGetOffset(hGameData, "Activate");
if(offset == -1) if(offset == -1)
{
delete hGameData;
SetFailState("Failed to find Activate offset"); SetFailState("Failed to find Activate offset");
}
// CPhysForce::Activate // CPhysForce::Activate
g_hActivate = DHookCreate(offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, Hook_CPhysForce_Activate); g_hActivate = DHookCreate(offset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, Hook_CPhysForce_Activate);
if(g_hActivate == INVALID_HANDLE) if(g_hActivate == INVALID_HANDLE)
{
delete hGameData;
SetFailState("Failed to DHookCreate Activate"); SetFailState("Failed to DHookCreate Activate");
}
offset = GameConfGetOffset(hGameData, "AcceptInput"); offset = GameConfGetOffset(hGameData, "AcceptInput");
if(offset == -1) if(offset == -1)
{
delete hGameData;
SetFailState("Failed to find AcceptInput offset."); SetFailState("Failed to find AcceptInput offset.");
}
// CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID ) // CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
g_hAcceptInput = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, OnAcceptInput); g_hAcceptInput = DHookCreate(offset, HookType_Entity, ReturnType_Bool, ThisPointer_CBaseEntity, Hook_AcceptInput);
if(g_hAcceptInput == INVALID_HANDLE) if(g_hAcceptInput == INVALID_HANDLE)
{
delete hGameData;
SetFailState("Failed to DHook AcceptInput."); SetFailState("Failed to DHook AcceptInput.");
}
DHookAddParam(g_hAcceptInput, HookParamType_CharPtr); DHookAddParam(g_hAcceptInput, HookParamType_CharPtr);
DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity); DHookAddParam(g_hAcceptInput, HookParamType_CBaseEntity);
@ -342,8 +380,12 @@ public void OnMapStart()
{ {
bool bLate = g_bLateLoad; bool bLate = g_bLateLoad;
DHookGamerules(g_hEndGameFrame, true);
g_bCleaningUp = false; g_bCleaningUp = false;
g_fTickInterval = GetTickInterval();
g_iParent = FindDataMapInfo(0, "m_pParent"); g_iParent = FindDataMapInfo(0, "m_pParent");
g_iSpawnFlags = FindDataMapInfo(0, "m_spawnflags"); g_iSpawnFlags = FindDataMapInfo(0, "m_spawnflags");
g_iCollision = FindDataMapInfo(0, "m_Collision"); g_iCollision = FindDataMapInfo(0, "m_Collision");
@ -356,6 +398,8 @@ public void OnMapStart()
g_iVecAbsOrigin = FindDataMapInfo(0, "m_vecAbsOrigin"); g_iVecAbsOrigin = FindDataMapInfo(0, "m_vecAbsOrigin");
g_iAngRotation = FindDataMapInfo(0, "m_angRotation"); g_iAngRotation = FindDataMapInfo(0, "m_angRotation");
g_iAngAbsRotation = FindDataMapInfo(0, "m_angAbsRotation"); g_iAngAbsRotation = FindDataMapInfo(0, "m_angAbsRotation");
g_iVecMins = FindDataMapInfo(0, "m_vecMins");
g_iVecMaxs = FindDataMapInfo(0, "m_vecMaxs");
g_iSimulationTime = FindDataMapInfo(0, "m_flSimulationTime"); g_iSimulationTime = FindDataMapInfo(0, "m_flSimulationTime");
g_iCoordinateFrame = FindDataMapInfo(0, "m_rgflCoordinateFrame"); g_iCoordinateFrame = FindDataMapInfo(0, "m_rgflCoordinateFrame");
@ -369,7 +413,7 @@ public void OnMapStart()
OnClientConnected(client); OnClientConnected(client);
if(AreClientCookiesCached(client)) if(AreClientCookiesCached(client))
OnClientCookiesCached(client); OnClientCookiesCached(client);
OnClientPutInServer(client); OnClientSettingsChanged(client);
} }
} }
@ -407,20 +451,11 @@ public void OnClientConnected(int client)
public void OnClientCookiesCached(int client) public void OnClientCookiesCached(int client)
{ {
char sBuffer[16]; if(!IsClientInGame(client))
GetClientCookie(client, g_hCookie_DisableLagComp, sBuffer, sizeof(sBuffer)); return;
if(sBuffer[0])
g_bDisableLagComp[client] = true;
else
g_bDisableLagComp[client] = false;
}
public void OnClientPutInServer(int client) float fLerpTime = GetEntPropFloat(client, Prop_Data, "m_fLerpTime");
{ g_aLerpTicks[client] = RoundToNearest(fLerpTime / g_fTickInterval);
if(g_iLerpTime == -1)
{
g_iLerpTime = FindDataMapInfo(client, "m_fLerpTime");
}
} }
public void OnClientDisconnect(int client) public void OnClientDisconnect(int client)
@ -465,7 +500,7 @@ public void OnEntitySpawned(int entity, const char[] classname)
CheckEntityForLagComp(entity, classname); CheckEntityForLagComp(entity, classname);
} }
public MRESReturn OnAcceptInput(int entity, Handle hReturn, Handle hParams) public MRESReturn Hook_AcceptInput(int entity, Handle hReturn, Handle hParams)
{ {
if(!IsValidEntity(entity)) if(!IsValidEntity(entity))
return MRES_Ignored; return MRES_Ignored;
@ -782,65 +817,21 @@ public MRESReturn Detour_OnFrameUpdatePostEntityThink()
public void OnRunThinkFunctions(bool simulating) public void OnRunThinkFunctions(bool simulating)
{ {
g_iGameTick = GetGameTickCount();
BlockTriggerTouchPlayers(g_aBlockTriggerTouchPlayers, false); BlockTriggerTouchPlayers(g_aBlockTriggerTouchPlayers, false);
for(int i = 0; i < g_iNumEntities; i++)
{
if(!IsValidEntity(g_aEntityLagData[i].iEntity))
{
PrintToBoth("!!!!!!!!!!! OnRunThinkFunctions SHIT deleted: %d / %d", i, g_aEntityLagData[i].iEntity);
RemoveRecord(i);
i--; continue;
}
if(g_aEntityLagData[i].iDeleted)
{
if(g_aEntityLagData[i].iDeleted + MAX_RECORDS <= GetGameTickCount())
{
// calls OnEntityDestroyed right away
// which calls RemoveRecord
// which moves the next element to our current position
RemoveEdict(g_aEntityLagData[i].iEntity);
i--; continue;
}
continue;
}
if(g_aEntityLagData[i].iNotMoving >= MAX_RECORDS)
continue;
RecordDataIntoRecord(g_aEntityLagData[i].iEntity, g_aEntityLagData[i].RestoreData);
}
} }
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]) 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])
{ {
if(!IsPlayerAlive(client)) if(!IsPlayerAlive(client) || IsFakeClient(client))
return Plugin_Continue; return Plugin_Continue;
int iTargetTick = tickcount - g_aLerpTicks[client];
// -1 because the newest record in the list is one tick old // -1 because the newest record in the list is one tick old
// this is because we simulate players first // this is because we simulate players first
// hence no new entity record was inserted on the current tick // hence no new entity record was inserted on the current tick
int iGameTick = GetGameTickCount() - 1; int iDelta = g_iGameTick - iTargetTick - 1;
float fTickInterval = GetTickInterval();
float fLerpTime = GetEntDataFloat(client, g_iLerpTime);
// -1 lerp ticks was determined by analyzing hits visually at host_timescale 0.01 and debug_touchlinks 1
int iLerpTicks = RoundToFloor(0.5 + (fLerpTime / fTickInterval)) - 1;
int iTargetTick = tickcount - iLerpTicks;
int iDelta = iGameTick - iTargetTick;
float fCorrect = 0.0;
fCorrect += GetClientLatency(client, NetFlow_Outgoing);
fCorrect += iLerpTicks * fTickInterval;
float fDeltaTime = fCorrect - iDelta * fTickInterval;
if(FloatAbs(fDeltaTime) > 0.2)
{
// difference between cmd time and latency is too big > 200ms, use time correction based on latency
iDelta = RoundToFloor(0.5 + (fCorrect / fTickInterval));
}
// The player is stupid and doesn't want lag compensation. // The player is stupid and doesn't want lag compensation.
// To get the original behavior back lets assume they actually have 0 latency. // To get the original behavior back lets assume they actually have 0 latency.
@ -853,7 +844,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3
if(iDelta > MAX_RECORDS) if(iDelta > MAX_RECORDS)
iDelta = MAX_RECORDS; iDelta = MAX_RECORDS;
int iPlayerSimTick = iGameTick - iDelta; int iPlayerSimTick = g_iGameTick - iDelta;
for(int i = 0; i < g_iNumEntities; i++) for(int i = 0; i < g_iNumEntities; i++)
{ {
@ -904,19 +895,28 @@ public void OnPostPlayerThinkFunctions()
if(!g_aEntityLagData[i].bRestore) if(!g_aEntityLagData[i].bRestore)
continue; continue;
RestoreEntityFromRecord(g_aEntityLagData[i].iEntity, g_aEntityLagData[i].RestoreData); RestoreEntityFromRecord(g_aEntityLagData[i].iEntity, g_aaLagRecords[i][g_aEntityLagData[i].iRecordIndex]);
g_aEntityLagData[i].bRestore = false; g_aEntityLagData[i].bRestore = false;
} }
BlockTriggerTouchPlayers(g_aBlockTriggerTouchPlayers, true); BlockTriggerTouchPlayers(g_aBlockTriggerTouchPlayers, true);
} }
public void OnRunThinkFunctionsPost(bool simulating) public MRESReturn Hook_EndGameFrame()
{ {
for(int i = 0; i < g_iNumEntities; i++) for(int i = 0; i < g_iNumEntities; i++)
{ {
if(g_aEntityLagData[i].iDeleted) if(g_aEntityLagData[i].iDeleted)
{ {
if(g_aEntityLagData[i].iDeleted + MAX_RECORDS <= g_iGameTick)
{
// calls OnEntityDestroyed right away
// which calls RemoveRecord
// which moves the next element to our current position
RemoveEdict(g_aEntityLagData[i].iEntity);
i--; continue;
}
if(g_aEntityLagData[i].iRecordsValid) if(g_aEntityLagData[i].iRecordsValid)
{ {
g_aEntityLagData[i].iRecordIndex++; g_aEntityLagData[i].iRecordIndex++;
@ -961,6 +961,8 @@ public void OnRunThinkFunctionsPost(bool simulating)
LagRecord_Copy(g_aaLagRecords[i][g_aEntityLagData[i].iRecordIndex], TmpRecord); LagRecord_Copy(g_aaLagRecords[i][g_aEntityLagData[i].iRecordIndex], TmpRecord);
} }
return MRES_Ignored;
} }
@ -977,6 +979,8 @@ void RecordDataIntoRecord(int iEntity, LagRecord Record)
GetEntDataVector(iEntity, g_iVecAbsOrigin, Record.vecAbsOrigin); GetEntDataVector(iEntity, g_iVecAbsOrigin, Record.vecAbsOrigin);
GetEntDataVector(iEntity, g_iAngRotation, Record.angRotation); GetEntDataVector(iEntity, g_iAngRotation, Record.angRotation);
GetEntDataVector(iEntity, g_iAngAbsRotation, Record.angAbsRotation); GetEntDataVector(iEntity, g_iAngAbsRotation, Record.angAbsRotation);
GetEntDataVector(iEntity, g_iVecMins, Record.vecMins);
GetEntDataVector(iEntity, g_iVecMaxs, Record.vecMaxs);
GetEntDataArray(iEntity, g_iCoordinateFrame, view_as<int>(Record.rgflCoordinateFrame), COORDINATE_FRAME_SIZE); GetEntDataArray(iEntity, g_iCoordinateFrame, view_as<int>(Record.rgflCoordinateFrame), COORDINATE_FRAME_SIZE);
Record.flSimulationTime = GetEntDataFloat(iEntity, g_iSimulationTime); Record.flSimulationTime = GetEntDataFloat(iEntity, g_iSimulationTime);
} }
@ -1021,11 +1025,6 @@ bool DoesRotationInvalidateSurroundingBox(int iEntity)
void InvalidatePhysicsRecursive(int iEntity) void InvalidatePhysicsRecursive(int iEntity)
{ {
// NetworkProp()->MarkPVSInformationDirty()
int fStateFlags = GetEdictFlags(iEntity);
fStateFlags |= FL_EDICT_DIRTY_PVS_INFORMATION;
SetEdictFlags(iEntity, fStateFlags);
// CollisionProp()->MarkPartitionHandleDirty(); // CollisionProp()->MarkPartitionHandleDirty();
Address CollisionProp = GetEntityAddress(iEntity) + view_as<Address>(g_iCollision); Address CollisionProp = GetEntityAddress(iEntity) + view_as<Address>(g_iCollision);
SDKCall(g_hMarkPartitionHandleDirty, CollisionProp); SDKCall(g_hMarkPartitionHandleDirty, CollisionProp);
@ -1045,6 +1044,8 @@ void RestoreEntityFromRecord(int iEntity, LagRecord Record)
SetEntDataVector(iEntity, g_iVecAbsOrigin, Record.vecAbsOrigin); SetEntDataVector(iEntity, g_iVecAbsOrigin, Record.vecAbsOrigin);
SetEntDataVector(iEntity, g_iAngRotation, Record.angRotation); SetEntDataVector(iEntity, g_iAngRotation, Record.angRotation);
SetEntDataVector(iEntity, g_iAngAbsRotation, Record.angAbsRotation); SetEntDataVector(iEntity, g_iAngAbsRotation, Record.angAbsRotation);
SetEntDataVector(iEntity, g_iVecMins, Record.vecMins);
SetEntDataVector(iEntity, g_iVecMaxs, Record.vecMaxs);
SetEntDataArray(iEntity, g_iCoordinateFrame, view_as<int>(Record.rgflCoordinateFrame), COORDINATE_FRAME_SIZE); SetEntDataArray(iEntity, g_iCoordinateFrame, view_as<int>(Record.rgflCoordinateFrame), COORDINATE_FRAME_SIZE);
SetEntDataFloat(iEntity, g_iSimulationTime, Record.flSimulationTime); SetEntDataFloat(iEntity, g_iSimulationTime, Record.flSimulationTime);
@ -1181,8 +1182,6 @@ void EntityLagData_Copy(EntityLagData obj, const EntityLagData other)
obj.iNotMoving = other.iNotMoving; obj.iNotMoving = other.iNotMoving;
obj.bRestore = other.bRestore; obj.bRestore = other.bRestore;
obj.bLateKill = other.bLateKill; obj.bLateKill = other.bLateKill;
LagRecord_Copy(obj.RestoreData, other.RestoreData);
} }
void LagRecord_Copy(LagRecord obj, const LagRecord other) void LagRecord_Copy(LagRecord obj, const LagRecord other)
@ -1193,6 +1192,8 @@ void LagRecord_Copy(LagRecord obj, const LagRecord other)
obj.vecAbsOrigin[i] = other.vecAbsOrigin[i]; obj.vecAbsOrigin[i] = other.vecAbsOrigin[i];
obj.angRotation[i] = other.angRotation[i]; obj.angRotation[i] = other.angRotation[i];
obj.angAbsRotation[i] = other.angAbsRotation[i]; obj.angAbsRotation[i] = other.angAbsRotation[i];
obj.vecMins[i] = other.vecMins[i];
obj.vecMaxs[i] = other.vecMaxs[i];
} }
obj.flSimulationTime = other.flSimulationTime; obj.flSimulationTime = other.flSimulationTime;