Skip to content

Commit

Permalink
feature: landmark for trigger_teleport (#510)
Browse files Browse the repository at this point in the history
* Add bxt_ch_trigger_tp_landmark

* clear landmark without any conditions

* changes suggested

* changes requested
  • Loading branch information
khanghugo authored Jul 27, 2024
1 parent 5b4d5d1 commit 56bb64c
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 4 deletions.
3 changes: 2 additions & 1 deletion BunnymodXT/cvars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@
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")
X(bxt_ch_trigger_tp_keeps_momentum_viewangles, "1") \
X(bxt_ch_trigger_tp_landmark, "0")

class CVarWrapper
{
Expand Down
3 changes: 3 additions & 0 deletions BunnymodXT/modules/HwDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7669,6 +7669,9 @@ HOOK_DEF_0(HwDLL, void, __cdecl, R_DrawSkyBox)
HOOK_DEF_3(HwDLL, int, __cdecl, SV_SpawnServer, int, bIsDemo, char*, server, char*, startspot)
{
auto ret = ORIG_SV_SpawnServer(bIsDemo, server, startspot);

ServerDLL::GetInstance().ClearTPLandmarks();

if (ret) {
Interprocess::WriteMapChange(CustomHud::GetTime(), server);
lastLoadedMap = server;
Expand Down
99 changes: 96 additions & 3 deletions BunnymodXT/modules/ServerDLL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ extern "C" void __cdecl _ZN12CBaseTrigger13TeleportTouchEP11CBaseEntity(void* th
{
return ServerDLL::HOOKED_CBaseTrigger__TeleportTouch_Linux(thisptr, pOther);
}

extern "C" void __cdecl _Z16DispatchKeyValueP7edict_sP14KeyValueData_s(edict_t* pentKeyvalue, KeyValueData* pkvd)
{
return ServerDLL::HOOKED_DispatchKeyValue(pentKeyvalue, pkvd);
}
#endif

void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* moduleBase, size_t moduleLength, bool needToIntercept)
Expand Down Expand Up @@ -180,7 +185,8 @@ void ServerDLL::Hook(const std::wstring& moduleName, void* moduleHandle, void* m
ORIG_CBaseEntity__IsInWorld, HOOKED_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux, HOOKED_CBaseEntity__IsInWorld_Linux,
ORIG_CBaseTrigger__TeleportTouch, HOOKED_CBaseTrigger__TeleportTouch,
ORIG_CBaseTrigger__TeleportTouch_Linux, HOOKED_CBaseTrigger__TeleportTouch_Linux);
ORIG_CBaseTrigger__TeleportTouch_Linux, HOOKED_CBaseTrigger__TeleportTouch_Linux,
ORIG_DispatchKeyValue, HOOKED_DispatchKeyValue);
}
}

Expand Down Expand Up @@ -237,7 +243,8 @@ void ServerDLL::Unhook()
ORIG_CBaseEntity__IsInWorld,
ORIG_CBaseEntity__IsInWorld_Linux,
ORIG_CBaseTrigger__TeleportTouch,
ORIG_CBaseTrigger__TeleportTouch_Linux);
ORIG_CBaseTrigger__TeleportTouch_Linux,
ORIG_DispatchKeyValue);
}

Clear();
Expand Down Expand Up @@ -296,6 +303,7 @@ void ServerDLL::Clear()
ORIG_CBaseEntity__FireBullets = nullptr;
ORIG_DispatchSpawn = nullptr;
ORIG_DispatchTouch = nullptr;
ORIG_DispatchKeyValue = nullptr;
ORIG_CBaseEntity__FireBullets_Linux = nullptr;
ORIG_CBaseEntity__FireBulletsPlayer = nullptr;
ORIG_CBaseEntity__FireBulletsPlayer_Linux = nullptr;
Expand Down Expand Up @@ -361,6 +369,8 @@ void ServerDLL::Clear()
offm_fStamina = 0;
offm_old_iAmmo = 0;
offm_iPlayerSaveLock = 0;

tpLandmarks.clear();
}

bool ServerDLL::CanHook(const std::wstring& moduleFullName)
Expand Down Expand Up @@ -1223,17 +1233,19 @@ void ServerDLL::FindStuff()

ORIG_DispatchSpawn = reinterpret_cast<_DispatchSpawn>(MemUtils::GetSymbolAddress(m_Handle, "_Z13DispatchSpawnP7edict_s"));
ORIG_DispatchTouch = reinterpret_cast<_DispatchTouch>(MemUtils::GetSymbolAddress(m_Handle, "_Z13DispatchTouchP7edict_sS0_"));
ORIG_DispatchKeyValue = reinterpret_cast<_DispatchKeyValue>(MemUtils::GetSymbolAddress(m_Handle, "_Z16DispatchKeyValueP7edict_sP14KeyValueData_s"));
ORIG_ClientCommand = reinterpret_cast<_ClientCommand>(MemUtils::GetSymbolAddress(m_Handle, "_Z13ClientCommandP7edict_s"));
ORIG_PlayerPostThink = reinterpret_cast<_PlayerPostThink>(MemUtils::GetSymbolAddress(m_Handle, "_Z15PlayerPostThinkP7edict_s"));
ORIG_PM_Move = reinterpret_cast<_PM_Move>(MemUtils::GetSymbolAddress(m_Handle, "PM_Move"));
ORIG_AddToFullPack = reinterpret_cast<_AddToFullPack>(MemUtils::GetSymbolAddress(m_Handle, "_Z13AddToFullPackP14entity_state_siP7edict_sS2_iiPh"));
ORIG_CmdStart = reinterpret_cast<_CmdStart>(MemUtils::GetSymbolAddress(m_Handle, "_Z8CmdStartPK7edict_sPK9usercmd_sj"));
ORIG_CmdEnd = reinterpret_cast<_CmdEnd>(MemUtils::GetSymbolAddress(m_Handle, "_Z6CmdEndPK7edict_s"));

if (ORIG_DispatchSpawn && ORIG_DispatchTouch && ORIG_ClientCommand && ORIG_PlayerPostThink &&
if (ORIG_DispatchSpawn && ORIG_DispatchTouch && ORIG_DispatchKeyValue && ORIG_ClientCommand && ORIG_PlayerPostThink &&
ORIG_PM_Move && ORIG_AddToFullPack && ORIG_CmdStart && ORIG_CmdEnd) {
EngineDevMsg("[server dll] Found DispatchSpawn at %p.\n", ORIG_DispatchSpawn);
EngineDevMsg("[server dll] Found DispatchTouch at %p.\n", ORIG_DispatchTouch);
EngineDevMsg("[server dll] Found DispatchKeyValue at %p.\n", ORIG_DispatchKeyValue);
EngineDevMsg("[server dll] Found ClientCommand at %p.\n", ORIG_ClientCommand);
EngineDevMsg("[server dll] Found PlayerPostThink at %p.\n", ORIG_PlayerPostThink);
EngineDevMsg("[server dll] Found PM_Move at %p.\n", ORIG_PM_Move);
Expand All @@ -1248,10 +1260,12 @@ void ServerDLL::FindStuff()
// Gets our hooked addresses on Windows.
ORIG_DispatchSpawn = funcs.pfnSpawn;
ORIG_DispatchTouch = funcs.pfnTouch;
ORIG_DispatchKeyValue = funcs.pfnKeyValue;
ORIG_ClientCommand = funcs.pfnClientCommand;
ORIG_PlayerPostThink = funcs.pfnPlayerPostThink;
EngineDevMsg("[server dll] Found DispatchSpawn at %p.\n", ORIG_DispatchSpawn);
EngineDevMsg("[server dll] Found DispatchTouch at %p.\n", ORIG_DispatchTouch);
EngineDevMsg("[server dll] Found DispatchKeyValue at %p.\n", ORIG_DispatchKeyValue);
EngineDevMsg("[server dll] Found ClientCommand at %p.\n", ORIG_ClientCommand);
EngineDevMsg("[server dll] Found PlayerPostThink at %p.\n", ORIG_PlayerPostThink);
if (INTERFACE_VERSION == 140)
Expand Down Expand Up @@ -1647,6 +1661,7 @@ void ServerDLL::RegisterCVarsAndCommands()
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_ch_trigger_tp_landmark);
}

REG(bxt_splits_print);
Expand Down Expand Up @@ -3440,10 +3455,74 @@ void TriggerTpKeepsMomentumRestore(Vector prev_vel, Vector prev_view, Vector pre
}
}

HOOK_DEF_2(ServerDLL, void, __cdecl, DispatchKeyValue, edict_t*, pentKeyvalue, KeyValueData*, pkvd)
{
if (pkvd && pentKeyvalue
&& pkvd->szClassName // some entities don't have classname, this avoids crash.
&& pkvd->szKeyName && pkvd->szValue // just to make sure
&& !strcmp(pkvd->szClassName, "trigger_teleport")
&& !strcmp(pkvd->szKeyName, "landmark")
) {

edict_t *edicts;
HwDLL::GetInstance().GetEdicts(&edicts);
const auto index = pentKeyvalue - edicts;

tpLandmarks[index] = pkvd->szValue;
// Don't set pkvd->fHandled = 1,
// as some games could handle the same cases for the same entities,
// which means you won't give the game a chance to read that data!
// -- _Smiley
// pkvd->fHandled = 1;
}

ORIG_DispatchKeyValue(pentKeyvalue, pkvd);
}

// std::optional is at least C++17 :DDDDDDDDDDDDDDDDDDDDDDD
std::tuple<bool, Vector> TriggerTpLandmarkBefore(bool enabled, entvars_t *this_pev, entvars_t *pev, enginefuncs_t *pEngfuncs)
{
if (!enabled)
return std::make_tuple(false, Vector());

const auto index = ServerDLL::GetInstance().pEngfuncs->pfnIndexOfEdict(this_pev->pContainingEntity);
const auto tpLandmarks = ServerDLL::GetInstance().tpLandmarks;

if (!tpLandmarks.count(index))
return std::make_tuple(false, Vector());

const auto landmarkName = tpLandmarks.at(index);
const edict_t *landmark = pEngfuncs->pfnFindEntityByString(NULL, "targetname", landmarkName.c_str());

if (HwDLL::GetInstance().IsValidEdict(landmark))
return std::make_tuple(true, Vector(pev->origin) - Vector(landmark->v.origin));

return std::make_tuple(false, Vector());
}

void TriggerTpLandmarkAfter(entvars_t *pev, Vector offset)
{
pev->origin = pev->origin + offset;
// have to offset by some HULL because of origin z diff
const auto is_duck = pev->bInDuck || pev->flags & (FL_DUCKING);
const auto hull_offset = is_duck ? VEC_DUCK_HULL_MIN : VEC_HULL_MIN;

pev->origin[2] += hull_offset[2];
// https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/triggers.cpp#L1908
pev->origin[2] -= 1;
}

void ServerDLL::ClearTPLandmarks()
{
tpLandmarks.clear();
}

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();
auto is_bxt_ch_trigger_tp_landmark_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_landmark.GetBool() && HwDLL::GetInstance().ppGlobals;

entvars_t *this_pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(thisptr) + 4);
entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(pOther) + 4);
Vector prev_vel;
Vector prev_view;
Expand All @@ -3457,17 +3536,25 @@ HOOK_DEF_3(ServerDLL, void, __fastcall, CBaseTrigger__TeleportTouch, void*, this
prev_basevelocity = pev->basevelocity;
}

const auto landmark_info = TriggerTpLandmarkBefore(is_bxt_ch_trigger_tp_landmark_enabled, this_pev, pev, pEngfuncs);

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);
}

if (is_bxt_ch_trigger_tp_landmark_enabled && std::get<0>(landmark_info)) {
TriggerTpLandmarkAfter(pev, std::get<1>(landmark_info));
}
}

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();
auto is_bxt_ch_trigger_tp_landmark_enabled = CVars::sv_cheats.GetBool() && CVars::bxt_ch_trigger_tp_landmark.GetBool() && pEngfuncs && HwDLL::GetInstance().ppGlobals;

entvars_t *this_pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(thisptr) + 4);
entvars_t *pev = *reinterpret_cast<entvars_t**>(reinterpret_cast<uintptr_t>(pOther) + 4);
Vector prev_vel;
Vector prev_view;
Expand All @@ -3481,11 +3568,17 @@ HOOK_DEF_2(ServerDLL, void, __cdecl, CBaseTrigger__TeleportTouch_Linux, void*, t
prev_basevelocity = pev->basevelocity;
}

const auto landmark_info = TriggerTpLandmarkBefore(is_bxt_ch_trigger_tp_landmark_enabled, this_pev, pev, pEngfuncs);

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);
}

if (is_bxt_ch_trigger_tp_landmark_enabled && std::get<0>(landmark_info)) {
TriggerTpLandmarkAfter(pev, std::get<1>(landmark_info));
}
}

#undef ALERT
5 changes: 5 additions & 0 deletions BunnymodXT/modules/ServerDLL.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class ServerDLL : public IHookableDirFilter
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)
HOOK_DECL(void, __cdecl, DispatchKeyValue, edict_t* pentKeyvalue, KeyValueData* pkvd)

public:
static ServerDLL& GetInstance()
Expand Down Expand Up @@ -248,4 +249,8 @@ class ServerDLL : public IHookableDirFilter

float ch_noclip_vel_prev_maxspeed;
float ch_noclip_vel_prev_clientmaxspeed;

public:
std::unordered_map<int, std::string> tpLandmarks;
void ClearTPLandmarks();
};

0 comments on commit 56bb64c

Please sign in to comment.