diff --git a/LagCompensation/gamedata/LagCompensation.games.txt b/LagCompensation/gamedata/LagCompensation.games.txt index d7d3f8d..046db6c 100644 --- a/LagCompensation/gamedata/LagCompensation.games.txt +++ b/LagCompensation/gamedata/LagCompensation.games.txt @@ -10,17 +10,38 @@ "linux" "@_ZN11CBaseEntity20PhysicsTouchTriggersEPK6Vector" } + "GetAbsOrigin" + { + "library" "server" + "linux" "@_ZNK11CBaseEntity12GetAbsOriginEv" + } + "SetAbsOrigin" { "library" "server" "linux" "@_ZN11CBaseEntity12SetAbsOriginERK6Vector" } + // CBaseEntity::GetAbsAngles is inlined + // so we use CBaseEntity::EyeAngles + // which does -> return GetAbsAngles(); + "GetAbsAngles" + { + "library" "server" + "linux" "@_ZN11CBaseEntity9EyeAnglesEv" + } + "SetAbsAngles" { "library" "server" "linux" "@_ZN11CBaseEntity12SetAbsAnglesERK6QAngle" } + + "::UTIL_Remove" + { + "library" "server" + "linux" "@_Z11UTIL_RemoveP11CBaseEntity" + } } "Functions" @@ -39,6 +60,20 @@ } } } + + "UTIL_Remove" + { + "signature" "::UTIL_Remove" + "callconv" "cdecl" + "return" "void" + "arguments" + { + "oldObj" + { + "type" "cbaseentity" + } + } + } } } } diff --git a/LagCompensation/scripting/LagCompensation.sp b/LagCompensation/scripting/LagCompensation.sp index 80d27c1..4987abd 100644 --- a/LagCompensation/scripting/LagCompensation.sp +++ b/LagCompensation/scripting/LagCompensation.sp @@ -17,11 +17,10 @@ public Plugin myinfo = }; bool g_bLateLoad = false; -bool g_bBlockPhysics = false; -bool g_bNoPhysics[2048]; #define MAX_RECORDS 32 -#define MAX_ENTITIES 16 +#define MAX_ENTITIES 32 +//#define DEBUG enum struct LagRecord { @@ -34,6 +33,8 @@ enum struct EntityLagData int iEntity; int iRecordIndex; int iNumRecords; + int iRecordsValid; + int iDeleted; bool bRestore; bool bMoving; LagRecord RestoreData; @@ -43,16 +44,35 @@ LagRecord g_aaLagRecords[MAX_ENTITIES][MAX_RECORDS]; EntityLagData g_aEntityLagData[MAX_ENTITIES]; int g_iNumEntities = 0; -Handle g_hPhysicsTouchTriggers; +Handle g_hGetAbsOrigin; Handle g_hSetAbsOrigin; +Handle g_hGetAbsAngles; Handle g_hSetAbsAngles; +bool g_bBlockPhysics = false; +bool g_bNoPhysics[2048]; +Handle g_hPhysicsTouchTriggers; + +bool g_bRoundEnded = false; +Handle g_hUTIL_Remove; + public void OnPluginStart() { Handle hGameData = LoadGameConfigFile("LagCompensation.games"); if(!hGameData) SetFailState("Failed to load LagCompensation gamedata."); + + // 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(); + // CBaseEntity::SetAbsOrigin StartPrepSDKCall(SDKCall_Entity); if(!PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "SetAbsOrigin")) @@ -63,6 +83,17 @@ public void OnPluginStart() PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); g_hSetAbsOrigin = EndPrepSDKCall(); + + // 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(); + // CBaseEntity::SetAbsAngles StartPrepSDKCall(SDKCall_Entity); if(!PrepSDKCall_SetFromConf(hGameData, SDKConf_Signature, "SetAbsAngles")) @@ -74,13 +105,61 @@ public void OnPluginStart() g_hSetAbsAngles = EndPrepSDKCall(); + // CBaseEntity::PhysicsTouchTriggers g_hPhysicsTouchTriggers = DHookCreateFromConf(hGameData, "CBaseEntity__PhysicsTouchTriggers"); if(!g_hPhysicsTouchTriggers) + { + delete hGameData; SetFailState("Failed to setup detour for CBaseEntity__PhysicsTouchTriggers"); - delete hGameData; + } if(!DHookEnableDetour(g_hPhysicsTouchTriggers, false, Detour_OnPhysicsTouchTriggers)) + { + delete hGameData; SetFailState("Failed to detour CBaseEntity__PhysicsTouchTriggers."); + } + + // UTIL_Remove + g_hUTIL_Remove = DHookCreateFromConf(hGameData, "UTIL_Remove"); + if(!g_hUTIL_Remove) + { + delete hGameData; + SetFailState("Failed to setup detour for UTIL_Remove"); + } + delete hGameData; + + if(!DHookEnableDetour(g_hUTIL_Remove, false, Detour_OnUTIL_Remove)) + SetFailState("Failed to detour UTIL_Remove."); + + HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy); + HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); +} + +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +{ + g_bLateLoad = late; + return APLRes_Success; +} + +public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) +{ + g_bRoundEnded = true; + + for(int i = 0; i < MAX_ENTITIES; i++) + { + if(g_aEntityLagData[i].iEntity) + { + LogMessage("[%d] round_end deleted: %d / %d", GetGameTickCount(), i, g_aEntityLagData[i].iEntity); + g_aEntityLagData[i].iEntity = 0; + g_iNumEntities--; + return; + } + } +} + +public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) +{ + g_bRoundEnded = false; } public MRESReturn Detour_OnPhysicsTouchTriggers(int entity, Handle hReturn, Handle hParams) @@ -99,10 +178,30 @@ public MRESReturn Detour_OnPhysicsTouchTriggers(int entity, Handle hReturn, Hand return MRES_Ignored; } -public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) +public MRESReturn Detour_OnUTIL_Remove(Handle hParams) { - g_bLateLoad = late; - return APLRes_Success; + if(g_bRoundEnded) + return MRES_Ignored; + + int entity = DHookGetParam(hParams, 1); + if(entity < 0 || entity > sizeof(g_bNoPhysics)) + return MRES_Ignored; + + for(int i = 0; i < MAX_ENTITIES; i++) + { + if(g_aEntityLagData[i].iEntity != entity) + continue; + + SetEntPropEnt(entity, Prop_Data, "m_pParent", 0); + + if(!g_aEntityLagData[i].iDeleted) + g_aEntityLagData[i].iDeleted = GetGameTickCount(); + + LogMessage("[%d] !!!!!!!!!!! Detour_OnUTIL_Remove: %d / ent: %d", GetGameTickCount(), i, entity); + return MRES_Supercede; + } + + return MRES_Ignored; } public void OnMapStart() @@ -135,7 +234,7 @@ public void OnClientPutInServer(int client) public void OnRunThinkFunctions(bool simulating) { - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == 0 || !g_aEntityLagData[i].bMoving) continue; @@ -148,6 +247,16 @@ public void OnRunThinkFunctions(bool simulating) continue; } + if(g_aEntityLagData[i].iDeleted) + { + if(g_aEntityLagData[i].iDeleted + MAX_RECORDS < GetGameTickCount()) + { + LogMessage("[%d] !!!!!!!!!!! RemoveEdict: %d / ent: %d", GetGameTickCount(), i, g_aEntityLagData[i].iEntity); + RemoveEdict(g_aEntityLagData[i].iEntity); + } + continue; + } + RecordDataIntoRecord(g_aEntityLagData[i].iEntity, g_aEntityLagData[i].RestoreData); #if defined DEBUG LogMessage("1 [%d] [%d] index %d, RECORD entity %d", GetGameTickCount(), i, simulating, g_aEntityLagData[i].iEntity, g_aEntityLagData[i].iRecordIndex); @@ -169,28 +278,30 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 if(delta < 0) delta = 0; - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == 0 || !g_aEntityLagData[i].bMoving) continue; - if(!IsValidEntity(g_aEntityLagData[i].iEntity)) - { - LogMessage("!!!!!!!!!!! OnPlayerRunCmd SHIT deleted: %d", g_aEntityLagData[i].iEntity); - g_aEntityLagData[i].iEntity = 0; - g_iNumEntities--; - continue; - } - if(delta >= g_aEntityLagData[i].iNumRecords) delta = g_aEntityLagData[i].iNumRecords - 1; + if(g_aEntityLagData[i].iDeleted) + { + int simtick = GetGameTickCount() - delta; + if(simtick > g_aEntityLagData[i].iDeleted) + { + // TODO: completly block player from touching trigger + continue; + } + } + int iRecordIndex = g_aEntityLagData[i].iRecordIndex - delta; if(iRecordIndex < 0) iRecordIndex += MAX_RECORDS; RestoreEntityFromRecord(g_aEntityLagData[i].iEntity, client, g_aaLagRecords[i][iRecordIndex]); - g_aEntityLagData[i].bRestore = true; + g_aEntityLagData[i].bRestore = !g_aEntityLagData[i].iDeleted; #if defined DEBUG LogMessage("2 [%d] index %d, Entity %d -> delta = %d | Record = %d", GetGameTickCount(), i, g_aEntityLagData[i].iEntity, delta, iRecordIndex); @@ -207,19 +318,11 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 public void OnPostPlayerThinkFunctions() { - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == 0 || !g_aEntityLagData[i].bRestore) continue; - if(!IsValidEntity(g_aEntityLagData[i].iEntity)) - { - LogMessage("!!!!!!!!!!! OnRunThinkFunctions2 SHIT deleted: %d", g_aEntityLagData[i].iEntity); - g_aEntityLagData[i].iEntity = 0; - g_iNumEntities--; - continue; - } - RestoreEntityFromRecord(g_aEntityLagData[i].iEntity, 0, g_aEntityLagData[i].RestoreData); g_aEntityLagData[i].bRestore = false; @@ -238,16 +341,23 @@ public void OnPostPlayerThinkFunctions() public void OnRunThinkFunctionsPost(bool simulating) { - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == 0) continue; - if(!IsValidEntity(g_aEntityLagData[i].iEntity)) + if(g_aEntityLagData[i].iDeleted) { - LogMessage("!!!!!!!!!!! OnRunThinkFunctionsPost SHIT deleted: %d", g_aEntityLagData[i].iEntity); - g_aEntityLagData[i].iEntity = 0; - g_iNumEntities--; + 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--; + } + continue; } @@ -276,7 +386,9 @@ public void OnRunThinkFunctionsPost(bool simulating) g_aEntityLagData[i].iRecordIndex = 0; if(g_aEntityLagData[i].iNumRecords < MAX_RECORDS) - g_aEntityLagData[i].iNumRecords++; + { + g_aEntityLagData[i].iRecordsValid = ++g_aEntityLagData[i].iNumRecords; + } RecordDataIntoRecord(g_aEntityLagData[i].iEntity, g_aaLagRecords[i][g_aEntityLagData[i].iRecordIndex]); @@ -295,8 +407,8 @@ public void OnRunThinkFunctionsPost(bool simulating) void RecordDataIntoRecord(int iEntity, LagRecord Record) { - GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", Record.vecOrigin); - GetEntPropVector(iEntity, Prop_Data, "m_angAbsRotation", Record.vecAngles); + SDKCall(g_hGetAbsOrigin, iEntity, Record.vecOrigin); + SDKCall(g_hGetAbsAngles, iEntity, Record.vecAngles); } void RestoreEntityFromRecord(int iEntity, int iFilter, LagRecord Record) @@ -311,7 +423,7 @@ void RestoreEntityFromRecord(int iEntity, int iFilter, LagRecord Record) bool AddEntityForLagCompensation(int iEntity) { - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == iEntity) return true; @@ -327,9 +439,22 @@ bool AddEntityForLagCompensation(int iEntity) g_aEntityLagData[i].iEntity = iEntity; g_aEntityLagData[i].iRecordIndex = -1; g_aEntityLagData[i].iNumRecords = 0; + g_aEntityLagData[i].iRecordsValid = 0; + g_aEntityLagData[i].iDeleted = 0; + g_aEntityLagData[i].bRestore = false; g_aEntityLagData[i].bMoving = false; - LogMessage("[%d] added %d under index %d", GetGameTickCount(), iEntity, 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"); + + LogMessage("[%d] added entity %d (%s)\"%s\"(#%d) under index %d", GetGameTickCount(), iEntity, sClassname, sTargetname, iHammerID, i); + } float vecOrigin[3]; GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", vecOrigin); @@ -348,6 +473,12 @@ public void OnEntitySpawned(int entity, const char[] classname) if(entity < 0 || entity > sizeof(g_bNoPhysics)) return; + if(StrEqual(classname, "func_physbox")) + { + AddEntityForLagCompensation(entity); + return; + } + if(!StrEqual(classname, "trigger_hurt")) return; @@ -361,7 +492,7 @@ public void OnEntitySpawned(int entity, const char[] classname) break; GetEntityClassname(iParent, sParentClassname, sizeof(sParentClassname)); - if(StrEqual(sParentClassname, "func_movelinear") || StrEqual(sParentClassname, "func_door") || StrEqual(sParentClassname, "func_tracktrain")) + if(StrEqual(sParentClassname, "func_movelinear") || StrEqual(sParentClassname, "func_door") || StrEqual(sParentClassname, "func_tracktrain") || StrEqual(sParentClassname, "func_physbox")) { bGoodParents = true; break; @@ -388,7 +519,6 @@ public void OnEntitySpawned(int entity, const char[] classname) if(!(SolidFlags & 0x0004) && false) // FSOLID_NOT_SOLID return; - if(!AddEntityForLagCompensation(entity)) return; @@ -404,11 +534,11 @@ public void OnEntityDestroyed(int entity) g_bNoPhysics[entity] = false; - for(int i = 0, j = g_iNumEntities; i < MAX_ENTITIES, j; i++, j--) + for(int i = 0; i < MAX_ENTITIES; i++) { if(g_aEntityLagData[i].iEntity == entity) { - LogMessage("normal deleted: %d", entity); + LogMessage("[%d] normal deleted: %d / %d", GetGameTickCount(), i, entity); g_aEntityLagData[i].iEntity = 0; g_iNumEntities--; return;