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

Add bxt_ch_trigger_tp_keeps_momentum #502

Merged
merged 2 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion BunnymodXT/cvars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,11 @@
X(bxt_ch_checkpoint_onground_only, "0") \
X(bxt_ch_fix_sticky_slide, "0") \
X(bxt_ch_fix_sticky_slide_offset, "0.01") \
X(bxt_ch_noclip_speed, "0")
X(bxt_ch_noclip_speed, "0") \
X(bxt_ch_trigger_tp_keeps_momentum, "0") \
X(bxt_ch_trigger_tp_keeps_momentum_velocity, "1") \
X(bxt_ch_trigger_tp_keeps_momentum_velocity_redirect, "0") \
X(bxt_ch_trigger_tp_keeps_momentum_viewangles, "1")

class CVarWrapper
{
Expand Down
146 changes: 143 additions & 3 deletions BunnymodXT/modules/ServerDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ extern "C" int __cdecl _ZN11CBaseEntity9IsInWorldEv(void *thisptr)
{
return ServerDLL::HOOKED_CBaseEntity__IsInWorld_Linux(thisptr);
}

extern "C" void __cdecl _ZN12CBaseTrigger13TeleportTouchEP11CBaseEntity(void* thisptr, void* pOther)
{
return ServerDLL::HOOKED_CBaseTrigger__TeleportTouch_Linux(thisptr, pOther);
}
#endif

void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* moduleBase, size_t moduleLength, bool needToIntercept)
Expand Down Expand Up @@ -172,7 +177,9 @@ void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* m
ORIG_PM_Duck, HOOKED_PM_Duck,
ORIG_PM_UnDuck, HOOKED_PM_UnDuck,
ORIG_CBaseEntity__IsInWorld, HOOKED_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux);
ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux,
ORIG_CBaseTrigger__TeleportTouch, HOOKED_CBaseTrigger__TeleportTouch,
ORIG_CBaseTrigger__TeleportTouch_Linux, HOOKED_CBaseTrigger__TeleportTouch_Linux);
}
}

Expand Down Expand Up @@ -227,7 +234,9 @@ void ServerDLL::Unhook()
ORIG_PM_Duck,
ORIG_PM_UnDuck,
ORIG_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux);
ORIG_CBaseEntity__IsInWorld_Linux,
ORIG_CBaseTrigger__TeleportTouch,
ORIG_CBaseTrigger__TeleportTouch_Linux);
}

Clear();
Expand Down Expand Up @@ -301,6 +310,8 @@ void ServerDLL::Clear()
ORIG_PM_UnDuck = nullptr;
ORIG_CBaseEntity__IsInWorld = nullptr;
ORIG_CBaseEntity__IsInWorld_Linux = nullptr;
ORIG_CBaseTrigger__TeleportTouch = nullptr;
ORIG_CBaseTrigger__TeleportTouch_Linux = nullptr;
ppmove = nullptr;
offPlayerIndex = 0;
offOldbuttons = 0;
Expand Down Expand Up @@ -1554,6 +1565,19 @@ void ServerDLL::FindStuff()
}
}

{
ORIG_CBaseTrigger__TeleportTouch = reinterpret_cast<_CBaseTrigger__TeleportTouch>(MemUtils::GetSymbolAddress(m_Handle, "?TeleportTouch@CBaseTrigger@@QAEXPAVCBaseEntity@@@Z"));
if (ORIG_CBaseTrigger__TeleportTouch)
EngineDevMsg("[server dll] Found CBaseTrigger::TriggerTouch at %p.\n", ORIG_CBaseTrigger__TeleportTouch);
else {
ORIG_CBaseTrigger__TeleportTouch_Linux = reinterpret_cast<_CBaseTrigger__TeleportTouch_Linux>(MemUtils::GetSymbolAddress(m_Handle, "_ZN12CBaseTrigger13TeleportTouchEP11CBaseEntity"));
if (ORIG_CBaseTrigger__TeleportTouch_Linux)
EngineDevMsg("[server dll] Found CBaseTrigger::TriggerTouch [Linux] at %p.\n", ORIG_CBaseTrigger__TeleportTouch_Linux);
else
EngineDevWarning("[server dll] Could not find CBaseTrigger::TriggerTouch.\n");
}
}

if (!pEngfuncs)
{
pEngfuncs = reinterpret_cast<enginefuncs_t*>(MemUtils::GetSymbolAddress(m_Handle, "g_engfuncs"));
Expand Down Expand Up @@ -1617,6 +1641,12 @@ void ServerDLL::RegisterCVarsAndCommands()
REG(bxt_cof_allow_skipping_all_cutscenes);
if (ORIG_PM_Move)
REG(bxt_ch_noclip_speed);
if (ORIG_CBaseTrigger__TeleportTouch || ORIG_CBaseTrigger__TeleportTouch_Linux) {
REG(bxt_ch_trigger_tp_keeps_momentum);
REG(bxt_ch_trigger_tp_keeps_momentum_velocity);
REG(bxt_ch_trigger_tp_keeps_momentum_velocity_redirect);
REG(bxt_ch_trigger_tp_keeps_momentum_viewangles);
}

REG(bxt_splits_print);
REG(bxt_splits_print_times_at_end);
Expand Down Expand Up @@ -3347,4 +3377,114 @@ HOOK_DEF_1(ServerDLL, int, __cdecl, CBaseEntity__IsInWorld_Linux, void*, thisptr
return ORIG_CBaseEntity__IsInWorld_Linux(thisptr);
}

#undef ALERT
bool ServerDLL::IsPlayer(edict_t *ent)
{
// https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/player.cpp#L2850

auto &hw = HwDLL::GetInstance();

if (strcmp(hw.GetString(ent->v.classname), "player") != 0)
return false;

if (!(ent->v.flags & FL_CLIENT))
return false;

if (pEngfuncs && hw.ppGlobals)
{
int index = pEngfuncs->pfnIndexOfEdict(ent);

if ((index < 1) || (index > hw.ppGlobals->maxClients)) // gGlobalVariables.maxClients = svs.maxclients
return false;
}

return true;
}

void TriggerTpKeepsMomentumRestore(Vector prev_vel, Vector prev_view, Vector prev_angles, Vector prev_basevelocity, entvars_t *pev, enginefuncs_t *pEngfuncs)
{
// Set velocity before viewangles because viewangles will mess with the velocity angle for redirection
if (CVars::bxt_ch_trigger_tp_keeps_momentum_velocity.GetBool()) {
if (CVars::bxt_ch_trigger_tp_keeps_momentum_velocity_redirect.GetBool()) {
// https://github.com/fireblizzard/agmod/blob/bf06e4ffd31c1427784685118820e15552803bcb/dlls/triggers.cpp#L1935
// After teleportation, pevToucher has the same viewangles as pentTarget.
Vector vecAngles = Vector(0, pev->v_angle.y, 0);
Vector vecForward;

pEngfuncs->pfnAngleVectors(vecAngles, vecForward, nullptr, nullptr);

// For velocity
float xy_vel = prev_vel.Length2D();

pev->velocity.x = vecForward.x * xy_vel;
pev->velocity.y = vecForward.y * xy_vel;

// For base velocity
float xy_basevel = prev_basevelocity.Length2D();

pev->basevelocity.x = vecForward.x * xy_basevel;
pev->basevelocity.y = vecForward.y * xy_basevel;
} else {
pev->velocity = prev_vel;
pev->basevelocity = prev_basevelocity;
}
}

if (CVars::bxt_ch_trigger_tp_keeps_momentum_viewangles.GetBool()) {
// In HLSDK, due to some inheritance stuffs, pevToucher's viewangles is changed differently.
// In and only in TeleportTouch, pev->fixangle is set to 1.
// If not set back to 0, we cannot set our viewangles, due to inheritance stuffs.
pev->fixangle = 0;
pev->v_angle = prev_view;
pev->angles = prev_angles;
}
}

HOOK_DEF_3(ServerDLL, void, __fastcall, CBaseTrigger__TeleportTouch, void*, thisptr, int, edx, void*, pOther)
{
auto is_bxt_ch_trigger_tp_keeps_momentum_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_keeps_momentum.GetBool();

entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(pOther) + 4);
Vector prev_vel;
Vector prev_view;
Vector prev_angles;
Vector prev_basevelocity;

if (pev) {
khanghugo marked this conversation as resolved.
Show resolved Hide resolved
prev_vel = pev->velocity;
prev_view = pev->v_angle;
prev_angles = pev->angles;
prev_basevelocity = pev->basevelocity;
}

ORIG_CBaseTrigger__TeleportTouch(thisptr, edx, pOther);

if (is_bxt_ch_trigger_tp_keeps_momentum_enabled && pev && pEngfuncs && IsPlayer(pev->pContainingEntity)) {
TriggerTpKeepsMomentumRestore(prev_vel, prev_vel, prev_angles, prev_basevelocity, pev, pEngfuncs);
}
}

HOOK_DEF_2(ServerDLL, void, __cdecl, CBaseTrigger__TeleportTouch_Linux, void*, thisptr, void*, pOther)
{
auto is_bxt_ch_trigger_tp_keeps_momentum_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_keeps_momentum.GetBool();

entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(pOther) + 4);
Vector prev_vel;
Vector prev_view;
Vector prev_angles;
Vector prev_basevelocity;

if (pev) {
prev_vel = pev->velocity;
prev_view = pev->v_angle;
khanghugo marked this conversation as resolved.
Show resolved Hide resolved
prev_angles = pev->angles;
prev_basevelocity = pev->basevelocity;
}

ORIG_CBaseTrigger__TeleportTouch_Linux(thisptr, pOther);

if (is_bxt_ch_trigger_tp_keeps_momentum_enabled && pev && pEngfuncs && IsPlayer(pev->pContainingEntity)) {
TriggerTpKeepsMomentumRestore(prev_vel, prev_vel, prev_angles, prev_basevelocity, pev, pEngfuncs);
}
}

#undef ALERT
4 changes: 4 additions & 0 deletions BunnymodXT/modules/ServerDLL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ class ServerDLL : public IHookableDirFilter
HOOK_DECL(void, __fastcall, CTriggerCamera__FollowTarget, void* thisptr)
HOOK_DECL(int, __fastcall, CBaseEntity__IsInWorld, void* thisptr)
HOOK_DECL(int, __cdecl, CBaseEntity__IsInWorld_Linux, void* thisptr)
HOOK_DECL(void, __fastcall, CBaseTrigger__TeleportTouch, void* thisptr, int edx, void* pOther)
HOOK_DECL(void, __cdecl, CBaseTrigger__TeleportTouch_Linux, void* thisptr, void* pOther)

public:
static ServerDLL& GetInstance()
Expand Down Expand Up @@ -117,6 +119,8 @@ class ServerDLL : public IHookableDirFilter

void GiveNamedItem(entvars_t *pev, int istr);

bool IsPlayer(edict_t *ent);

private:
ServerDLL() : IHookableDirFilter({ L"dlls", L"cl_dlls"}) {};
ServerDLL(const ServerDLL&);
Expand Down