From 215172fcf9cf5a94286bba5dbf542aa5ab60fafb Mon Sep 17 00:00:00 2001 From: "zer0.k" Date: Tue, 4 Oct 2022 01:40:19 +0200 Subject: [PATCH 1/2] Only increment timer and record replays if movement processing happens, fix abuse with zones and low fps --- addons/sourcemod/gamedata/gokz-core.games.txt | 8 + addons/sourcemod/scripting/gokz-core.sp | 21 ++- .../scripting/gokz-core/timer/timer.sp | 2 +- .../gokz-core/timer/virtual_buttons.sp | 8 +- .../scripting/gokz-core/triggerfix.sp | 152 ++++++++++-------- addons/sourcemod/scripting/gokz-replays.sp | 13 +- .../scripting/gokz-replays/recording.sp | 23 ++- 7 files changed, 153 insertions(+), 74 deletions(-) diff --git a/addons/sourcemod/gamedata/gokz-core.games.txt b/addons/sourcemod/gamedata/gokz-core.games.txt index a42f7547..cec56b83 100644 --- a/addons/sourcemod/gamedata/gokz-core.games.txt +++ b/addons/sourcemod/gamedata/gokz-core.games.txt @@ -59,6 +59,14 @@ "linux" "222" } } + "Signatures" + { + "PhysicsCheckForEntityUntouch" + { + "windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\xD0\x00\x00\x00" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\x8B\x5D\x08\xC7\x44\x24\x04\x01\x00\x00\x00\x89\x1C\x24" + } + } } "cstrike" diff --git a/addons/sourcemod/scripting/gokz-core.sp b/addons/sourcemod/scripting/gokz-core.sp index 04943eb3..c6ceadc7 100644 --- a/addons/sourcemod/scripting/gokz-core.sp +++ b/addons/sourcemod/scripting/gokz-core.sp @@ -189,9 +189,7 @@ public void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float { return; } - - OnPlayerRunCmdPost_VirtualButtons(client, buttons, cmdnum); // Emulate buttons first - OnPlayerRunCmdPost_Timer(client); // This should be first after emulating buttons + OnPlayerRunCmdPost_VirtualButtons(client, cmdnum); OnPlayerRunCmdPost_ValidJump(client); UpdateTrackingVariables(client, cmdnum, buttons); // This should be last } @@ -270,7 +268,7 @@ public MRESReturn DHooks_OnSetModel(int client, Handle params) return MRES_Handled; } -public void OnCSPlayerSpawnPost(int client) +public void Hook_PlayerSpawnPost(int client) { if (GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") == -1) { @@ -278,6 +276,17 @@ public void OnCSPlayerSpawnPost(int client) } } +public void Hook_PlayerPostThink(int client) +{ + Hook_PlayerPostThink_Triggerfix(client); +} + +public void Hook_PlayerPostThinkPost(int client) +{ + Hook_PlayerPostThinkPost_VirtualButtons(client); + Hook_PlayerPostThinkPost_Timer(client); // This should be first after emulating buttons +} + public void Movement_OnChangeMovetype(int client, MoveType oldMovetype, MoveType newMovetype) { OnChangeMovetype_Timer(client, newMovetype); @@ -509,7 +518,9 @@ static void HookClientEvents(int client) { DHookEntity(gH_DHooks_OnTeleport, true, client); DHookEntity(gH_DHooks_SetModel, true, client); - SDKHook(client, SDKHook_SpawnPost, OnCSPlayerSpawnPost); + SDKHook(client, SDKHook_PostThink, Hook_PlayerPostThink); + SDKHook(client, SDKHook_PostThinkPost, Hook_PlayerPostThinkPost); + SDKHook(client, SDKHook_SpawnPost, Hook_PlayerSpawnPost); } static void UpdateTrackingVariables(int client, int cmdnum, int buttons) diff --git a/addons/sourcemod/scripting/gokz-core/timer/timer.sp b/addons/sourcemod/scripting/gokz-core/timer/timer.sp index 9086852b..1c6f0f7f 100644 --- a/addons/sourcemod/scripting/gokz-core/timer/timer.sp +++ b/addons/sourcemod/scripting/gokz-core/timer/timer.sp @@ -213,7 +213,7 @@ void OnClientPutInServer_Timer(int client) lastStartMode[client] = MODE_COUNT; // So it won't equal any mode } -void OnPlayerRunCmdPost_Timer(int client) +void Hook_PlayerPostThinkPost_Timer(int client) { if (IsPlayerAlive(client) && GetTimerRunning(client) && !GetPaused(client)) { diff --git a/addons/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp b/addons/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp index e1172225..0e56828d 100644 --- a/addons/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp +++ b/addons/sourcemod/scripting/gokz-core/timer/virtual_buttons.sp @@ -131,9 +131,13 @@ void OnEndButtonPress_VirtualButtons(int client, int course) } } -void OnPlayerRunCmdPost_VirtualButtons(int client, int buttons, int cmdnum) +void Hook_PlayerPostThinkPost_VirtualButtons(int client) +{ + CheckForAndHandleUsage(client, GetClientButtons(client)); +} + +void OnPlayerRunCmdPost_VirtualButtons(int client, int cmdnum) { - CheckForAndHandleUsage(client, buttons); UpdateIndicators(client, cmdnum); } diff --git a/addons/sourcemod/scripting/gokz-core/triggerfix.sp b/addons/sourcemod/scripting/gokz-core/triggerfix.sp index 0379a950..387429c0 100644 --- a/addons/sourcemod/scripting/gokz-core/triggerfix.sp +++ b/addons/sourcemod/scripting/gokz-core/triggerfix.sp @@ -7,6 +7,7 @@ // Engine constants, NOT settings (do not change) #define LAND_HEIGHT 2.0 // Maximum height above ground at which you can "land" #define MIN_STANDABLE_ZNRM 0.7 // Minimum surface normal Z component of a walkable surface +#define EFL_CHECK_UNTOUCH 1<<24 static int processMovementTicks[MAXPLAYERS+1]; static float playerFrameTime[MAXPLAYERS+1]; @@ -21,6 +22,7 @@ static float jumpBugOrigin[MAXPLAYERS + 1][3]; static ConVar cvGravity; +static Handle physicsCheckForEntityUntouch; static Handle acceptInputHookPre; static Handle processMovementHookPre; static Address serverGameEnts; @@ -43,6 +45,15 @@ public void OnPluginStart_Triggerfix() SetFailState("Failed to load gokz-core gamedata"); } + // EndTouch Fix + // Thanks rumour and mev + StartPrepSDKCall(SDKCall_Entity); + if(!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Signature, "PhysicsCheckForEntityUntouch")) + { + SetFailState("Failed to get PhysicsCheckForEntityUntouch"); + } + + physicsCheckForEntityUntouch = EndPrepSDKCall(); // PassesTriggerFilters StartPrepSDKCall(SDKCall_Entity); if (!PrepSDKCall_SetFromConf(gamedataConf, SDKConf_Virtual, "CBaseTrigger::PassesTriggerFilters")) @@ -177,7 +188,6 @@ public void OnClientConnected_Triggerfix(int client) public void OnClientPutInServer_Triggerfix(int client) { - SDKHook(client, SDKHook_PostThink, Hook_PlayerPostThink); DHookEntity(acceptInputHookPre, false, client); } @@ -403,87 +413,95 @@ static bool DoTriggerjumpFix(int client, const float landingPoint[3], const floa } // PostThink works a little better than a ProcessMovement post hook because we need to wait for ProcessImpacts (trigger activation) -static void Hook_PlayerPostThink(int client) +void Hook_PlayerPostThink_Triggerfix(int client) { - if (!IsPlayerAlive(client) - || GetEntityMoveType(client) != MOVETYPE_WALK - || CheckWater(client)) + if (!IsPlayerAlive(client)) { return; } - - bool landed = (GetEntPropEnt(client, Prop_Data, "m_hGroundEntity") != -1 - && lastGroundEnt[client] == -1) - || jumpBugged[client]; - - float landingMins[3], landingMaxs[3], landingPoint[3]; - - // Get info about the ground we landed on (if we need to do landing fixes). - if (landed) + + // Trigger jump fix + if (GetEntityMoveType(client) == MOVETYPE_WALK && !CheckWater(client)) { - float origin[3], nrm[3], velocity[3]; - GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin); - GetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity); + bool landed = (GetEntPropEnt(client, Prop_Data, "m_hGroundEntity") != -1 + && lastGroundEnt[client] == -1) + || jumpBugged[client]; - if (jumpBugged[client]) - { - origin = jumpBugOrigin[client]; - } + float landingMins[3], landingMaxs[3], landingPoint[3]; - GetEntPropVector(client, Prop_Data, "m_vecMins", landingMins); - GetEntPropVector(client, Prop_Data, "m_vecMaxs", landingMaxs); - - float originBelow[3]; - originBelow[0] = origin[0]; - originBelow[1] = origin[1]; - originBelow[2] = origin[2] - LAND_HEIGHT; - - TR_TraceHullFilter(origin, originBelow, landingMins, landingMaxs, MASK_PLAYERSOLID, PlayerFilter); - - if (!TR_DidHit()) - { - // This should never happen, since we know we are on the ground. - landed = false; - } - else + // Get info about the ground we landed on (if we need to do landing fixes). + if (landed) { - TR_GetPlaneNormal(null, nrm); + float origin[3], nrm[3], velocity[3]; + GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", origin); + GetEntPropVector(client, Prop_Data, "m_vecVelocity", velocity); + + if (jumpBugged[client]) + { + origin = jumpBugOrigin[client]; + } + + GetEntPropVector(client, Prop_Data, "m_vecMins", landingMins); + GetEntPropVector(client, Prop_Data, "m_vecMaxs", landingMaxs); - if (nrm[2] < MIN_STANDABLE_ZNRM) + float originBelow[3]; + originBelow[0] = origin[0]; + originBelow[1] = origin[1]; + originBelow[2] = origin[2] - LAND_HEIGHT; + + TR_TraceHullFilter(origin, originBelow, landingMins, landingMaxs, MASK_PLAYERSOLID, PlayerFilter); + + if (!TR_DidHit()) { - // This is rare, and how the incline fix should behave isn't entirely clear because maybe we should - // collide with multiple faces at once in this case, but let's just get the ground we officially - // landed on and use that for our ground normal. + // This should never happen, since we know we are on the ground. + landed = false; + } + else + { + TR_GetPlaneNormal(null, nrm); - // landingMins and landingMaxs will contain the final values used to find the ground after returning. - if (TracePlayerBBoxForGround(origin, originBelow, landingMins, landingMaxs)) - { - TR_GetPlaneNormal(null, nrm); - } - else + if (nrm[2] < MIN_STANDABLE_ZNRM) { - // This should also never happen. - landed = false; + // This is rare, and how the incline fix should behave isn't entirely clear because maybe we should + // collide with multiple faces at once in this case, but let's just get the ground we officially + // landed on and use that for our ground normal. + + // landingMins and landingMaxs will contain the final values used to find the ground after returning. + if (TracePlayerBBoxForGround(origin, originBelow, landingMins, landingMaxs)) + { + TR_GetPlaneNormal(null, nrm); + } + else + { + // This should also never happen. + landed = false; + } } + + TR_GetEndPosition(landingPoint); + } + } + + // reset it here because we don't need it again + jumpBugged[client] = false; + + // Must use TR_DidHit because if the unduck origin is closer than 0.03125 units from the ground, + // the trace fraction would return 0.0. + if (landed && TR_DidHit()) + { + DoTriggerjumpFix(client, landingPoint, landingMins, landingMaxs); + // Check if a trigger we just touched put us in the air (probably due to a teleport). + if (GetEntityFlags(client) & FL_ONGROUND == 0) + { + landed = false; } - - TR_GetEndPosition(landingPoint); } } - // reset it here because we don't need it again - jumpBugged[client] = false; - - // Must use TR_DidHit because if the unduck origin is closer than 0.03125 units from the ground, - // the trace fraction would return 0.0. - if (landed && TR_DidHit()) + // End touch fix + if (GetCheckUntouch(client)) { - DoTriggerjumpFix(client, landingPoint, landingMins, landingMaxs); - // Check if a trigger we just touched put us in the air (probably due to a teleport). - if (GetEntityFlags(client) & FL_ONGROUND == 0) - { - landed = false; - } + SDKCall(physicsCheckForEntityUntouch, client); } } @@ -608,3 +626,9 @@ static bool TracePlayerBBoxForGround(const float origin[3], const float originBe return false; } + +static bool GetCheckUntouch(int client) +{ + int flags = GetEntProp(client, Prop_Data, "m_iEFlags"); + return (flags & EFL_CHECK_UNTOUCH) != 0; +} \ No newline at end of file diff --git a/addons/sourcemod/scripting/gokz-replays.sp b/addons/sourcemod/scripting/gokz-replays.sp index 20c15788..ce026e94 100644 --- a/addons/sourcemod/scripting/gokz-replays.sp +++ b/addons/sourcemod/scripting/gokz-replays.sp @@ -175,13 +175,13 @@ public Action Hook_SayText2(UserMsg msg_id, any msg, const int[] players, int pl } - // =====[ CLIENT EVENTS ]===== public void OnClientPutInServer(int client) { OnClientPutInServer_Playback(client); OnClientPutInServer_Recording(client); + HookClientEvents(client); } public void OnClientAuthorized(int client, const char[] auth) @@ -197,10 +197,16 @@ public void OnClientDisconnect(int client) 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]) { + OnPlayerRunCmd_Recording(client); OnPlayerRunCmd_Playback(client, buttons); return Plugin_Continue; } +public void Hook_PlayerPostThinkPost(int client) +{ + Hook_PlayerPostThinkPost_Recording(client); +} + public void OnPlayerRunCmdPost(int client, int buttons, int impulse, const float vel[3], const float angles[3], int weapon, int subtype, int cmdnum, int tickcount, int seed, const int mouse[2]) { OnPlayerRunCmdPost_Recording(client, buttons, tickcount, vel, mouse); @@ -278,6 +284,11 @@ static void HookEvents() HookUserMessage(GetUserMessageId("SayText2"), Hook_SayText2, true); } +static void HookClientEvents(int client) +{ + SDKHook(client, SDKHook_PostThinkPost, Hook_PlayerPostThinkPost); +} + static void UpdateCurrentMap() { GetCurrentMapDisplayName(gC_CurrentMap, sizeof(gC_CurrentMap)); diff --git a/addons/sourcemod/scripting/gokz-replays/recording.sp b/addons/sourcemod/scripting/gokz-replays/recording.sp index 07a5aab8..35d1db5f 100644 --- a/addons/sourcemod/scripting/gokz-replays/recording.sp +++ b/addons/sourcemod/scripting/gokz-replays/recording.sp @@ -30,6 +30,7 @@ static ArrayList recordedRunData[MAXPLAYERS + 1]; static ArrayList recordedPostRunData[MAXPLAYERS + 1]; static Handle runningRunBreatherTimer[MAXPLAYERS + 1]; static ArrayList runningJumpstatTimers[MAXPLAYERS + 1]; +static bool movementProcessed[MAXPLAYERS + 1]; // =====[ EVENTS ]===== @@ -97,12 +98,32 @@ void OnClientDisconnect_Recording(int client) ClearClientRecordingState(client); } -void OnPlayerRunCmdPost_Recording(int client, int buttons, int tickCount, const float vel[3], const int mouse[2]) +void OnPlayerRunCmd_Recording(int client) +{ + if (!IsValidClient(client) || IsFakeClient(client) || !IsPlayerAlive(client) || recordingPaused[client]) + { + return; + } + movementProcessed[client] = false; +} + +void Hook_PlayerPostThinkPost_Recording(int client) { if (!IsValidClient(client) || IsFakeClient(client) || !IsPlayerAlive(client) || recordingPaused[client]) { return; } + // If movement is processed, then this function will be called. + // We don't record ticks where no movement processing happens. + movementProcessed[client] = true; +} + +void OnPlayerRunCmdPost_Recording(int client, int buttons, int tickCount, const float vel[3], const int mouse[2]) +{ + if (!IsValidClient(client) || IsFakeClient(client) || !IsPlayerAlive(client) || recordingPaused[client] || !movementProcessed[client]) + { + return; + } ReplayTickData tickData; From 560df85cc4e78b60349361db65a7f451545ba5ed Mon Sep 17 00:00:00 2001 From: "zer0.k" Date: Fri, 3 Feb 2023 22:19:27 +0100 Subject: [PATCH 2/2] Fix linux signature --- addons/sourcemod/gamedata/gokz-core.games.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sourcemod/gamedata/gokz-core.games.txt b/addons/sourcemod/gamedata/gokz-core.games.txt index cec56b83..c05763aa 100644 --- a/addons/sourcemod/gamedata/gokz-core.games.txt +++ b/addons/sourcemod/gamedata/gokz-core.games.txt @@ -64,7 +64,7 @@ "PhysicsCheckForEntityUntouch" { "windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x86\xD0\x00\x00\x00" - "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x2C\x8B\x5D\x08\xC7\x44\x24\x04\x01\x00\x00\x00\x89\x1C\x24" + "linux" "\x55\x89\xE5\x57\x56\x53\x83\xEC\x24\x8B\x75\x2A\x6A\x01\x56" } } }