Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: player physics simulate list shuffle #318

Merged
merged 14 commits into from
Nov 16, 2024
1 change: 1 addition & 0 deletions cfg/cs2fixes/cs2fixes.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ cs2f_disable_subtick_move 0 // Whether to disable subtick movement
cs2f_disable_subtick_shooting 0 // Whether to disable subtick shooting, experimental (WARNING: add "log_flags Shooting +DoNotEcho" to your cfg to prevent console spam on every shot fired)
cs2f_full_alltalk 0 // Whether to enforce sv_full_alltalk 1
cs2f_drop_map_weapons 0 // Whether to force drop map-spawned weapons on death
cs2f_shuffle_player_physics_sim 0 // Whether to enable shuffle player list in physics simulate
cs2f_prevent_using_players 0 // Whether to prevent +use from hitting players (0=can use players, 1=cannot use players)
cs2f_map_steamids_enable 0 // Whether to make Steam ID's available to maps

Expand Down
7 changes: 7 additions & 0 deletions gamedata/cs2fixes.games.txt
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,13 @@
"windows" "128"
"linux" "129"
}

// server.dll -> xref 'sv_phys_stop_at_collision' first __fastcall
"CVPhys2World::GetTouchingList"
{
"windows" "23"
"linux" "24"
}
}
"Patches"
{
Expand Down
1 change: 1 addition & 0 deletions src/addresses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig)
modules::schemasystem = new CModule(ROOTBIN, "schemasystem");
modules::vscript = new CModule(ROOTBIN, "vscript");
modules::networksystem = new CModule(ROOTBIN, "networksystem");
modules::vphysics2 = new CModule(ROOTBIN, "vphysics2");
modules::client = nullptr;

if (!CommandLine()->HasParm("-dedicated"))
Expand Down
5 changes: 3 additions & 2 deletions src/addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ namespace modules
inline CModule *vscript;
inline CModule *client;
inline CModule* networksystem;
inline CModule* vphysics2;
#ifdef _WIN32
inline CModule *hammer;
#endif
}
} // namespace modules

class CEntityInstance;
class CEntityIdentity;
Expand Down Expand Up @@ -91,4 +92,4 @@ namespace addresses
inline void(FASTCALL *CTakeDamageInfo_Constructor)(CTakeDamageInfo *pThis, CBaseEntity *pInflictor, CBaseEntity *pAttacker, CBaseEntity *pAbility,
const Vector *vecDamageForce, const Vector *vecDamagePosition, float flDamage, int bitsDamageType, int iCustomDamage, void *a10);
inline void(FASTCALL *CNetworkStringTable_DeleteAllStrings)(INetworkStringTable *pThis);
}
}
92 changes: 87 additions & 5 deletions src/cs2fixes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ SH_DECL_MANUALHOOK1(OnTakeDamage_Alive, 0, 0, 0, bool, CTakeDamageInfoContainer
SH_DECL_MANUALHOOK1_void(CheckMovingGround, 0, 0, 0, double);
SH_DECL_HOOK2(IGameEventManager2, LoadEventsFromFile, SH_NOATTRIB, 0, int, const char *, bool);
SH_DECL_MANUALHOOK1_void(GoToIntermission, 0, 0, 0, bool);
SH_DECL_MANUALHOOK2_void(PhysicsTouchShuffle, 0, 0, 0, CUtlVector<TouchLinked_t>*, bool);

CS2Fixes g_CS2Fixes;

Expand All @@ -139,6 +140,7 @@ int g_iOnTakeDamageAliveId = -1;
int g_iCheckMovingGroundId = -1;
int g_iLoadEventsFromFileId = -1;
int g_iGoToIntermissionId = -1;
int g_iPhysicsTouchShuffle = -1;

CGameEntitySystem *GameEntitySystem()
{
Expand Down Expand Up @@ -266,6 +268,17 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
SH_MANUALHOOK_RECONFIGURE(CheckMovingGround, offset, 0, 0);
g_iCheckMovingGroundId = SH_ADD_MANUALDVPHOOK(CheckMovingGround, pCCSPlayer_MovementServicesVTable, SH_MEMBER(this, &CS2Fixes::Hook_CheckMovingGround), false);

auto pCVPhys2WorldVTable = modules::vphysics2->FindVirtualTable("CVPhys2World");

offset = g_GameConfig->GetOffset("CVPhys2World::GetTouchingList");
if (offset == -1)
{
snprintf(error, maxlen, "Failed to find CVPhys2World::GetTouchingList\n");
bRequiredInitLoaded = false;
}
SH_MANUALHOOK_RECONFIGURE(PhysicsTouchShuffle, offset, 0, 0);
g_iPhysicsTouchShuffle = SH_ADD_MANUALDVPHOOK(PhysicsTouchShuffle, pCVPhys2WorldVTable, SH_MEMBER(this, &CS2Fixes::Hook_PhysicsTouchShuffle), true);

auto pCGameEventManagerVTable = (IGameEventManager2*)modules::server->FindVirtualTable("CGameEventManager");

g_iLoadEventsFromFileId = SH_ADD_DVPHOOK(IGameEventManager2, LoadEventsFromFile, pCGameEventManagerVTable, SH_MEMBER(this, &CS2Fixes::Hook_LoadEventsFromFile), false);
Expand Down Expand Up @@ -368,6 +381,7 @@ bool CS2Fixes::Unload(char *error, size_t maxlen)
SH_REMOVE_HOOK_ID(g_iCreateWorkshopMapGroupId);
SH_REMOVE_HOOK_ID(g_iOnTakeDamageAliveId);
SH_REMOVE_HOOK_ID(g_iCheckMovingGroundId);
SH_REMOVE_HOOK_ID(g_iPhysicsTouchShuffle);

if (g_iGoToIntermissionId != -1)
SH_REMOVE_HOOK_ID(g_iGoToIntermissionId);
Expand Down Expand Up @@ -547,7 +561,7 @@ void CS2Fixes::Hook_GameServerSteamAPIActivated()
g_http = g_steamAPI.SteamHTTP();

g_playerManager->OnSteamAPIActivated();

if (g_bVoteManagerEnable && !g_pMapVoteSystem->IsMapListLoaded())
g_pMapVoteSystem->LoadMapList();

Expand Down Expand Up @@ -622,7 +636,7 @@ void CS2Fixes::Hook_PostEvent(CSplitScreenSlot nSlot, bool bLocalOnly, int nClie
if (g_bEnableNoShake)
*(uint64 *)clients &= ~g_playerManager->GetNoShakeMask();
}

}

void CS2Fixes::AllPluginsLoaded()
Expand Down Expand Up @@ -843,7 +857,6 @@ void CS2Fixes::Hook_CheckTransmit(CCheckTransmitInfo **ppInfoList, int infoCount
for (int j = 0; j < gpGlobals->maxClients; j++)
{
CCSPlayerController* pController = CCSPlayerController::FromSlot(j);

// Always transmit to themselves
if (!pController || pController->m_bIsHLTV || j == iPlayerSlot)
continue;
Expand All @@ -856,7 +869,6 @@ void CS2Fixes::Hook_CheckTransmit(CCheckTransmitInfo **ppInfoList, int infoCount
{
pInfo->m_pTransmitEntity->Clear(pFlashLight->entindex());
}

// Always transmit other players if spectating
if (!g_bEnableHide || pSelfController->GetPawnState() == STATE_OBSERVER_MODE)
continue;
Expand Down Expand Up @@ -929,6 +941,76 @@ bool CS2Fixes::Hook_OnTakeDamage_Alive(CTakeDamageInfoContainer *pInfoContainer)
RETURN_META_VALUE(MRES_IGNORED, true);
}

bool g_bFixPhysicsPlayerShuffle = false;
FAKE_BOOL_CVAR(cs2f_shuffle_player_physics_sim, "Whether to enable shuffle player list in physics simulate", g_bFixPhysicsPlayerShuffle, false, false);

struct TouchLinked_t
{
uint32_t TouchFlags;

private:
uint8_t padding_0[20];

public:
CBaseHandle SourceHandle;
CBaseHandle TargetHandle;

private:
uint8_t padding_1[208];

public:
[[nodiscard]] bool IsUnTouching() const
{
return !!(TouchFlags & 0x10);
}

[[nodiscard]] bool IsTouching() const
{
return (!!(TouchFlags & 4)) || (!!(TouchFlags & 8));
}
};
static_assert(sizeof(TouchLinked_t) == 240, "Touch_t size mismatch");
void CS2Fixes::Hook_PhysicsTouchShuffle(CUtlVector<TouchLinked_t>* pList, bool unknown)
{
if (!g_bFixPhysicsPlayerShuffle || g_SHPtr->GetStatus() == MRES_SUPERCEDE || pList->Count() <= 1)
return;

// [Kxnrl]
// seems it sorted by flags?

std::srand(gpGlobals->tickcount);

// Fisher-Yates shuffle

std::vector<TouchLinked_t> touchingLinks;
std::vector<TouchLinked_t> unTouchLinks;

FOR_EACH_VEC(*pList, i)
{
const auto& link = pList->Element(i);
if (link.IsUnTouching())
unTouchLinks.push_back(link);
else
touchingLinks.push_back(link);
}

if (touchingLinks.size() <= 1)
return;

for (size_t i = touchingLinks.size() - 1; i > 0; --i)
{
const auto j = std::rand() % (i + 1);
std::swap(touchingLinks[i], touchingLinks[j]);
}

pList->Purge();

for (const auto link : touchingLinks)
pList->AddToTail(link);
for (const auto link : unTouchLinks)
pList->AddToTail(link);
}

void CS2Fixes::Hook_CheckMovingGround(double frametime)
{
CCSPlayer_MovementServices *pMove = META_IFACEPTR(CCSPlayer_MovementServices);
Expand Down Expand Up @@ -1046,4 +1128,4 @@ const char *CS2Fixes::GetName()
const char *CS2Fixes::GetURL()
{
return "https://github.com/Source2ZE/CS2Fixes";
}
}
2 changes: 2 additions & 0 deletions src/cs2fixes.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
struct CTakeDamageInfoContainer;
class CCSPlayer_MovementServices;
class CServerSideClient;
struct TouchLinked_t;

class CS2Fixes : public ISmmPlugin, public IMetamodListener
{
Expand Down Expand Up @@ -67,6 +68,7 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener
void Hook_CreateWorkshopMapGroup(const char* name, const CUtlStringList& mapList);
void Hook_GoToIntermission(bool bAbortedMatch);
bool Hook_OnTakeDamage_Alive(CTakeDamageInfoContainer *pInfoContainer);
void Hook_PhysicsTouchShuffle(CUtlVector<TouchLinked_t>* pList, bool unknown);
#ifdef PLATFORM_WINDOWS
Vector* Hook_GetEyePosition(Vector*);
QAngle* Hook_GetEyeAngles(QAngle*);
Expand Down
2 changes: 1 addition & 1 deletion src/detours.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -696,4 +696,4 @@ bool InitDetours(CGameConfig *gameConfig)
void FlushAllDetours()
{
g_vecDetours.Purge();
}
}