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

feature: landmark for trigger_teleport #510

Merged
merged 4 commits into from
Jul 27, 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
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
khanghugo marked this conversation as resolved.
Show resolved Hide resolved
&& 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")
Comment on lines +3463 to +3464
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a lot of string comparisons that happen all the time (?), especially for an optional feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made me paranoid so I debug print it. This is only called when a new server is started. Every time a new server is started, a lot of string comparisons like this happen to parse entities in BSP. This one is just one extra entity available in the game.

) {

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