diff --git a/inc/hooks.h b/inc/hooks.h index 0e81d11..3397326 100644 --- a/inc/hooks.h +++ b/inc/hooks.h @@ -87,7 +87,7 @@ private: using SendToProto = decltype (sendto); private: - Detour m_sendToDetour { }; + Detour m_sendToDetour { }, m_sendToDetourSys {}; public: ServerQueryHook () = default; @@ -100,6 +100,7 @@ public: public: // disables send hook bool disable () { + m_sendToDetourSys.restore (); return m_sendToDetour.restore (); } diff --git a/inc/support.h b/inc/support.h index 18908be..ec6641b 100644 --- a/inc/support.h +++ b/inc/support.h @@ -88,6 +88,9 @@ public: // get the current date and time as string String getCurrentDateTime (); + // generates fake steam id from bot name + StringRef getFakeSteamId (edict_t *ent); + // get's the wave length float getWaveLength (StringRef filename); diff --git a/src/hooks.cpp b/src/hooks.cpp index 8caa8e7..1b026a2 100644 --- a/src/hooks.cpp +++ b/src/hooks.cpp @@ -68,6 +68,11 @@ void ServerQueryHook::init () { return; } + // do not detour twice + if (m_sendToDetour.detoured () || m_sendToDetourSys.detoured ()) { + return; + } + // do not enable on not dedicated server if (!game.isDedicated ()) { return; @@ -83,12 +88,17 @@ void ServerQueryHook::init () { sendToAddress = address; } } + m_sendToDetourSys.initialize ("ws2_32.dll", "sendto", sendto); } m_sendToDetour.initialize ("ws2_32.dll", "sendto", sendToAddress); // enable only on modern games if (!game.is (GameFlags::Legacy) && (plat.nix || plat.win) && !plat.isNonX86 () && !m_sendToDetour.detoured ()) { m_sendToDetour.install (reinterpret_cast (BotSupport::sendTo), true); + + if (!m_sendToDetourSys.detoured ()) { + m_sendToDetourSys.install (reinterpret_cast (BotSupport::sendTo), true); + } } } diff --git a/src/linkage.cpp b/src/linkage.cpp index 9133321..8cc4c9e 100644 --- a/src/linkage.cpp +++ b/src/linkage.cpp @@ -534,6 +534,22 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) { }; } + table->pfnGetPlayerAuthId = [] (edict_t *e) -> const char * { + if (bots[e]) { + auto authid = util.getFakeSteamId (e); + + if (game.is (GameFlags::Metamod)) { + RETURN_META_VALUE (MRES_SUPERCEDE, authid.chars ()); + } + return authid.chars (); + } + + if (game.is (GameFlags::Metamod)) { + RETURN_META_VALUE (MRES_IGNORED, nullptr); + } + return engfuncs.pfnGetPlayerAuthId (e); + }; + table->pfnEmitSound = [] (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { // this function tells the engine that the entity pointed to by "entity", is emitting a sound // which fileName is "sample", at level "channel" (CHAN_VOICE, etc...), with "volume" as diff --git a/src/support.cpp b/src/support.cpp index 3de7dfe..073df3b 100644 --- a/src/support.cpp +++ b/src/support.cpp @@ -10,6 +10,7 @@ ConVar cv_display_welcome_text ("display_welcome_text", "1", "Enables or disables showing welcome message to host entity on game start."); ConVar cv_enable_query_hook ("enable_query_hook", "0", "Enables or disables fake server queries response, that shows bots as real players in server browser."); ConVar cv_breakable_health_limit ("breakable_health_limit", "500.0", "Specifies the maximum health of breakable object, that bot will consider to destroy.", true, 1.0f, 3000.0); +ConVar cv_enable_fake_steamids ("enable_fake_steamids", "0", "Allows or disallows bots to return fake steam id."); BotSupport::BotSupport () { m_needToSendWelcome = false; @@ -530,6 +531,16 @@ String BotSupport::getCurrentDateTime () { return String (timebuf); } +StringRef BotSupport::getFakeSteamId (edict_t *ent) { + if (!cv_enable_fake_steamids.bool_ () || !isPlayer (ent)) { + return "BOT"; + } + auto botNameHash = StringRef::fnv1a32 (ent->v.netname.chars ()); + + // just fake steam id a d return it with get player authid function + return strings.format ("STEAM_0:1:%d", cr::abs (static_cast (botNameHash) & 0xffff00)); +} + StringRef BotSupport::weaponIdToAlias (int32_t id) { StringRef none = "none";