Skip to content

Commit

Permalink
Initial release
Browse files Browse the repository at this point in the history
  • Loading branch information
GAMMACASE committed May 30, 2021
1 parent 2653e08 commit b9c80a3
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 1 deletion.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
# HeadBugFix
# HeadBugFix
This plugin is a port from [momentum mod](https://momentum-mod.org/) that fixes the head boundary box poping up when you start ducking, this allows you to abuse it to reach the triggers that are above you and blocked by a thin ceiling, when it shouldn't be possible to reach otherwise.

This fix is a port of [this exact commit](https://github.com/momentum-mod/game/commit/dbcc8cc5f8dde2a4e049348dfbac761c8b8db7b7) in the momentum mod repository. So big thanks to that!

Currently there's a support for CSGO and CSS, and I'm not planning on supporting any other game.

# Video examples
[Video Example of the plugin](https://www.youtube.com/watch?v=6--_WFe5P3Q)

[Practical Video Example](https://www.youtube.com/watch?v=X9Cg42gFKtc)
38 changes: 38 additions & 0 deletions addons/sourcemod/gamedata/headbugfix.games.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"Games"
{
"csgo"
{
"Signatures"
{
"CBasePlayer::UpdateCollisionBounds"
{
"windows" "\x56\x57\x8B\xF9\x8B\x0D\x2A\x2A\x2A\x2A\xF6\x87\x2A\x2A\x2A\x2A\x2A\x8B\x01\x74\x24\xFF\x50\x78\x8B\x0D\x2A\x2A\x2A\x2A\x8D\x70\x30\x8B\x11\xFF\x52\x78\x83\xC0\x24\x8D\x8F"
"linux" "\x55\x89\xE5\x83\xEC\x18\x89\x5D\xF8\x8B\x5D\x08\x89\x75\xFC\xA1\x2A\x2A\x2A\x2A\xF6\x83\x2A\x2A\x2A\x2A\x2A\x8B\x10\x89\x04\x24\x75\x36\xFF\x52\x7C\x89\xC6\xA1\x2A\x2A\x2A\x2A"
}

"CCSGameMovement::Duck"
{
"windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x56\x57\x8B\xF9\x8B\x57\x04\x8B\x8A\x2A\x2A\x2A\x2A\x83\xF9\xFF\x74\x33\x0F\xB7\xC1\x8D\x04\x40\x8D\x04\xC5\x2A\x2A\x2A\x2A\x85\xC0\x74\x22"
"linux" "\x55\x89\xE5\x57\x56\x53\x81\xEC\x2A\x2A\x2A\x2A\x8B\x5D\x08\x8B\x43\x04\x89\x04\x24\xE8\x2A\x2A\x2A\x2A\xC6\x85\x2A\x2A\x2A\x2A\x2A\x85\xC0\x0F\x95\xC0"
}
}
}

"cstrike"
{
"Signatures"
{
"CCollisionProperty::SetCollisionBounds"
{
"windows" "\x55\x8B\xEC\x83\xEC\x2C\x53\x8B\x5D\x0C\x56\x57\x8B\x7D\x08\x8B\xF1\x8D\x56\x08\x89\x75\xFC\x8B\x07\x89\x45\xE0\xF3\x0F\x10\x45\x2A\x0F\x2E\x02\x8B\x47\x04\x89\x45\xE4"
"linux" "@_ZN18CCollisionProperty18SetCollisionBoundsERK6VectorS2_"
}

"CCSGameMovement::Duck"
{
"windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\x53\x56\x8B\xF1\x8B\x46\x04\x8B\x98\x2A\x2A\x2A\x2A\xF6\xC3\x01\x74\x59\x8B\x56\x08\x8B\x4A\x24\x8B\xC1\x83\xE0\x04"
"linux" "@_ZN15CCSGameMovement4DuckEv"
}
}
}
}
136 changes: 136 additions & 0 deletions addons/sourcemod/scripting/headbugfix.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#include "sourcemod"
#include "sdktools"
#include "sdkhooks"
#include "dhooks"
#include "glib/assertutils"
#include "glib/addressutils"

#define SNAME "[HeadBugFix] "

public Plugin myinfo =
{
name = "HeadBugFix",
description = "Fixes headbug bbox exploits",
author = "GAMMA CASE",
version = "1.0.0",
};

Handle gUpdateCollisionBounds;
Handle gSetCollisionBounds;
EngineVersion gEngineVersion;

int gFlagsPropOffset = -1;
bool gLate;

float gCSSStandingBBox[][] = {
{ -16.0, -16.0, 0.0 },
{ 16.0, 16.0, 62.0}
};

float gCSSDuckingBBox[][] = {
{ -16.0, -16.0, 0.0 },
{ 16.0, 16.0, 45.0}
};

public void OnPluginStart()
{
gEngineVersion = GetEngineVersion();
ASSERT_MSG(gEngineVersion == Engine_CSS || gEngineVersion == Engine_CSGO, "This plugin is only supported for CSGO and CSS.");

GameData gd = new GameData("headbugfix.games");

SetupSDKCalls(gd);
SetupDhooks(gd);

delete gd;

if(gLate)
{
for(int i = 1; i <= MaxClients; i++)
{
if(!IsClientInGame(i) || IsFakeClient(i))
continue;

OnClientPutInServer(i);
}
}
}

public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
gLate = late;
}

void SetupSDKCalls(GameData gd)
{
if(gEngineVersion == Engine_CSGO)
{
//CBasePlayer::UpdateCollisionBounds
StartPrepSDKCall(SDKCall_Raw);

ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CBasePlayer::UpdateCollisionBounds"), "Failed to find signature for \"CBasePlayer::UpdateCollisionBounds\".");

gUpdateCollisionBounds = EndPrepSDKCall();
ASSERT_MSG(gUpdateCollisionBounds, "Failed to setup sdkcall to \"CBasePlayer::UpdateCollisionBounds\".");
}
else
{
//CCollisionProperty::SetCollisionBounds
StartPrepSDKCall(SDKCall_Raw);

ASSERT_MSG(PrepSDKCall_SetFromConf(gd, SDKConf_Signature, "CCollisionProperty::SetCollisionBounds"), "Failed to find signature for \"CCollisionProperty::SetCollisionBounds\".");

PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef);
PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef);

gSetCollisionBounds = EndPrepSDKCall();
ASSERT_MSG(gSetCollisionBounds, "Failed to setup sdkcall to \"CCollisionProperty::SetCollisionBounds\".");
}
}

void SetupDhooks(GameData gd)
{
//CCSGameMovement::Duck
DynamicDetour dhook = new DynamicDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_Address);

ASSERT_MSG(dhook.SetFromConf(gd, SDKConf_Signature, "CCSGameMovement::Duck"), "Failed to find signature for \"CCSGameMovement::Duck\".");

ASSERT_MSG(dhook.Enable(Hook_Post, Duck_Dhook), "Failed to enable detour for \"CCSGameMovement::Duck\".");
}

public MRESReturn Duck_Dhook(Address pThis)
{
// pThis + 4 refers to player member of gamemovement instance.
if(gEngineVersion == Engine_CSGO)
{
SDKCall(gUpdateCollisionBounds, LoadFromAddress(pThis + 4, NumberType_Int32));
}
else if(gFlagsPropOffset != -1)
{
static int collision_offset = -1;

if(collision_offset == -1)
{
collision_offset = FindSendPropInfo("CBasePlayer", "m_Collision");
ASSERT_MSG(collision_offset != -1, "Failed to find \"CBasePlayer::m_Collision\" prop.");
}

Address player = view_as<Address>(LoadFromAddress(pThis + 4, NumberType_Int32));
int buttons = LoadFromAddress(player + gFlagsPropOffset, NumberType_Int32);

if(buttons & FL_DUCKING)
SDKCall(gSetCollisionBounds, player + collision_offset, gCSSDuckingBBox[0], gCSSDuckingBBox[1]);
else
SDKCall(gSetCollisionBounds, player + collision_offset, gCSSStandingBBox[0], gCSSStandingBBox[1]);
}
}

public void OnClientPutInServer(int client)
{
if(gFlagsPropOffset == -1)
{
gFlagsPropOffset = FindDataMapInfo(client, "m_fFlags");
ASSERT_MSG(gFlagsPropOffset != -1, "Failed to find \"m_fFlags\" prop.");
}
}

54 changes: 54 additions & 0 deletions addons/sourcemod/scripting/include/glib/addressutils.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#if defined _addressutils_included
#endinput
#endif
#define _addressutils_included

methodmap AddressBase
{
property Address Address
{
public get() { return view_as<Address>(this); }
}
}

//-==Operator overloadings
stock Address operator+(Address l, int r)
{
return l + view_as<Address>(r);
}

stock Address operator+(int l, Address r)
{
return view_as<Address>(l) + r;
}

stock Address operator-(Address l, int r)
{
return l - view_as<Address>(r);
}

stock Address operator-(int l, Address r)
{
return view_as<Address>(l) - r;
}

stock Address operator*(Address l, int r)
{
return l * view_as<Address>(r);
}

stock Address operator*(int l, Address r)
{
return view_as<Address>(l) * r;
}

stock Address operator/(Address l, int r)
{
return l / view_as<Address>(r);
}

stock Address operator/(int l, Address r)
{
return view_as<Address>(l) / r;
}
//Operator overloadings==-
58 changes: 58 additions & 0 deletions addons/sourcemod/scripting/include/glib/assertutils.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#if defined _assertutils_included
#endinput
#endif
#define _assertutils_included

/* Compile time settings for this include. Should be defined before including this file.
* #define ASSERTUTILS_DISABLE //Disables all assertions
* #define ASSERTUTILS_FAILSTATE_FUNC //Define the name of the function that should be called when assertion is hit
*/

#if !defined SNAME
#define __SNAME ""
#else
#define __SNAME SNAME
#endif

#define ASSERT_FMT_STRING_LEN 512

#if defined ASSERTUTILS_DISABLE

#define ASSERT(%1)%2;
#define ASSERT_MSG(%1,%2)%3;
#define ASSERT_FINAL(%1)%2;
#define ASSERT_FINAL_MSG(%1,%2)%3;

#elseif defined ASSERTUTILS_FAILSTATE_FUNC

#define ASSERT(%1) if(!(%1)) ASSERTUTILS_FAILSTATE_FUNC(__SNAME..."Assertion failed: \""...#%1..."\"")
#define ASSERT_MSG(%1,%2) if(!(%1)) ASSERTUTILS_FAILSTATE_FUNC(__SNAME...%2)
#define ASSERT_FINAL(%1) if(!(%1)) SetFailState(__SNAME..."Assertion failed: \""...#%1..."\"")
#define ASSERT_FINAL_MSG(%1,%2) if(!(%1)) SetFailState(__SNAME...%2)

#else

#define ASSERT(%1) if(!(%1)) SetFailState(__SNAME..."Assertion failed: \""...#%1..."\"")
#define ASSERT_MSG(%1,%2) if(!(%1)) SetFailState(__SNAME...%2)
#define ASSERT_FINAL(%1) ASSERT(%1)
#define ASSERT_FINAL_MSG(%1,%2) ASSERT_MSG(%1,%2)

#endif

// Might be redundant as default ASSERT_MSG accept format arguments just fine.
#if 0
stock void ASSERT_FMT(bool result, char[] fmt, any ...)
{
#if !defined ASSERTUTILS_DISABLE
if(!result)
{
char buff[ASSERT_FMT_STRING_LEN];
VFormat(buff, sizeof(buff), fmt, 3);

SetFailState(__SNAME..."%s", buff);
}
#endif
}
#endif

#undef ASSERT_FMT_STRING_LEN

0 comments on commit b9c80a3

Please sign in to comment.