diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt index 52a9d62b..92ae6d7a 100644 --- a/gamedata/cs2fixes.games.txt +++ b/gamedata/cs2fixes.games.txt @@ -216,6 +216,16 @@ { "windows" "173" "linux" "172" + } + "IsEntityPawn" + { + "windows" "152" + "linux" "151" + } + "IsEntityController" + { + "windows" "153" + "linux" "152" } } "Patches" diff --git a/sdk b/sdk index 11e4a8b7..f653b1ec 160000 --- a/sdk +++ b/sdk @@ -1 +1 @@ -Subproject commit 11e4a8b7f1af7b8477b17373f75e72e2f23d2986 +Subproject commit f653b1ec620913fe0bcee76f541fc4f347d470c7 diff --git a/src/commands.cpp b/src/commands.cpp index 16a1239b..677f3492 100644 --- a/src/commands.cpp +++ b/src/commands.cpp @@ -36,6 +36,9 @@ extern CEntitySystem *g_pEntitySystem; +extern IVEngineServer2* g_pEngineServer2; +extern int g_targetPawn; +extern int g_targetController; WeaponMapEntry_t WeaponMap[] = { {"bizon", "weapon_bizon", 1400, 26}, @@ -226,6 +229,16 @@ CON_COMMAND_CHAT(toggledecals, "toggle world decals, if you're into having 10 fp ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "You have %s world decals", pZEPlayer->IsUsingStopDecals() ? "disabled" : "enabled"); } +CON_COMMAND_CHAT(myuid, "test") +{ + if (!player) + return; + + int iPlayer = player->GetPlayerSlot(); + + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Your userid is %i, slot: %i, retrieved slot: %i", g_pEngineServer2->GetPlayerUserId(iPlayer).Get(), iPlayer, g_playerManager->GetSlotFromUserId(g_pEngineServer2->GetPlayerUserId(iPlayer).Get())); +} + CON_COMMAND_CHAT(ztele, "teleport to spawn") { if (!player) @@ -268,16 +281,9 @@ CON_COMMAND_CHAT(ztele, "teleport to spawn") { //Convert handle into controller so we can use it again, and check it isn't invalid CCSPlayerController* controller = (CCSPlayerController*)Z_CBaseEntity::EntityFromHandle(handle); - if (!controller) - { - ConMsg("Couldn't resolve entity handle\n"); - return; - } - if (controller->m_iConnected() != PlayerConnectedState::PlayerConnected) - { - ConMsg("Controller is not connected\n"); + + if (!controller || controller->m_iConnected() != PlayerConnectedState::PlayerConnected) return; - } //Get pawn (again) so we can do shit CBasePlayerPawn* pPawn2 = controller->m_hPawn(); @@ -303,7 +309,49 @@ CON_COMMAND_CHAT(ztele, "teleport to spawn") }); } -#ifdef _DEBUG +// TODO: Make this a convar when it's possible to do so +static constexpr int g_iMaxHideDistance = 2000; + +CON_COMMAND_CHAT(hide, "hides nearby teammates") +{ + if (!player) + return; + + if (args.ArgC() < 2) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Usage: !hide (0 to disable)"); + return; + } + + int distance = V_StringToInt32(args[1], -1); + + if (distance > g_iMaxHideDistance || distance < 0) + { + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "You can only hide players between 0 and %i units away.", g_iMaxHideDistance); + return; + } + + int iPlayer = player->GetPlayerSlot(); + + ZEPlayer *pZEPlayer = g_playerManager->GetPlayer(iPlayer); + + // Something has to really go wrong for this to happen + if (!pZEPlayer) + { + Warning("%s Tried to access a null ZEPlayer!!\n", player->GetPlayerName()); + return; + } + + pZEPlayer->SetHideDistance(distance); + + if (distance == 0) + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Hiding teammates is now disabled.", distance); + else + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Now hiding teammates within %i units.", distance); +} + + +#if _DEBUG CON_COMMAND_CHAT(message, "message someone") { if (!player) diff --git a/src/cs2_sdk/entity/cbaseentity.h b/src/cs2_sdk/entity/cbaseentity.h index 217fc8e9..49b801d2 100644 --- a/src/cs2_sdk/entity/cbaseentity.h +++ b/src/cs2_sdk/entity/cbaseentity.h @@ -22,7 +22,6 @@ #include "../schema.h" #include "ccollisionproperty.h" #include "mathlib/vector.h" -#include "baseentity.h" #include "ehandle.h" #include "../../gameconfig.h" @@ -132,6 +131,7 @@ class Z_CBaseEntity : public CBaseEntity SCHEMA_FIELD(MoveType_t, m_MoveType) SCHEMA_FIELD(uint32, m_spawnflags) SCHEMA_FIELD(uint32, m_fFlags) + SCHEMA_FIELD(LifeState_t, m_lifeState) int entindex() { return m_pEntity->m_EHandle.GetEntryIndex(); } @@ -140,7 +140,25 @@ class Z_CBaseEntity : public CBaseEntity void Teleport(Vector *position, QAngle *angles, Vector *velocity) { static int offset = g_GameConfig->GetOffset("Teleport"); CALL_VIRTUAL(void, offset, this, position, angles, velocity); } - void CollisionRulesChanged() { static int offset = g_GameConfig->GetOffset("CollisionRulesChanged"); CALL_VIRTUAL(void, offset, this); } + void CollisionRulesChanged() + { + static int offset = g_GameConfig->GetOffset("CollisionRulesChanged"); + CALL_VIRTUAL(void, offset, this); + } + + bool IsPawn() + { + static int offset = g_GameConfig->GetOffset("IsEntityPawn"); + CALL_VIRTUAL(bool, offset, this); + } + + bool IsController() + { + static int offset = g_GameConfig->GetOffset("IsEntityController"); + CALL_VIRTUAL(bool, offset, this); + } + + bool IsAlive() { return m_lifeState == LifeState_t::LIFE_ALIVE; } CHandle GetHandle() { return m_pEntity->m_EHandle; } diff --git a/src/cs2_sdk/schema.cpp b/src/cs2_sdk/schema.cpp index 6381d661..a1e3e6d3 100644 --- a/src/cs2_sdk/schema.cpp +++ b/src/cs2_sdk/schema.cpp @@ -21,7 +21,6 @@ #include "../common.h" #include "interfaces/cs2_interfaces.h" -//#include #include "tier1/utlmap.h" #include "tier0/memdbgon.h" #include "plat.h" @@ -72,7 +71,7 @@ static bool InitSchemaFieldsForClass(SchemaTableMap_t *tableMap, const char* cla { SchemaClassFieldData_t& field = pFields[i]; -#ifndef CS2_SDK_ENABLE_SCHEMA_FIELD_OFFSET_LOGGING +#ifdef _DEBUG Message("%s::%s found at -> 0x%X - %llx\n", className, field.m_name, field.m_offset, &field); #endif diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 4227623a..1599c302 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -96,10 +96,8 @@ SH_DECL_HOOK6(IServerGameClients, ClientConnect, SH_NOATTRIB, 0, bool, CPlayerSl SH_DECL_HOOK8_void(IGameEventSystem, PostEventAbstract, SH_NOATTRIB, 0, CSplitScreenSlot, bool, int, const uint64*, INetworkSerializable*, const void*, unsigned long, NetChannelBufType_t) SH_DECL_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t&, ISource2WorldSession*, const char*); - - -// , bool, IRecipientFilter*, INetworkSerializable*, void* data, unsigned long nSize -SH_DECL_HOOK2_void( IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CPlayerSlot, const CCommand & ); +SH_DECL_HOOK6_void(ISource2GameEntities, CheckTransmit, SH_NOATTRIB, 0, CCheckTransmitInfo **, int, CBitVec<16384> &, const Entity2Networkable_t **, const uint16 *, int); +SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CPlayerSlot, const CCommand &); CS2Fixes g_CS2Fixes; @@ -122,7 +120,7 @@ ConVar sample_cvar("sample_cvar", "42", 0); CON_COMMAND_F(sample_command, "Sample command", FCVAR_SPONLY | FCVAR_LINKED_CONCOMMAND) { - META_CONPRINTF( "Sample command called by %d. Command: %s\n", context.GetPlayerSlot(), args.GetCommandString() ); + Message( "Sample command called by %d. Command: %s\n", context.GetPlayerSlot(), args.GetCommandString() ); } CON_COMMAND_F(toggle_logs, "Toggle printing most logs and warnings", FCVAR_SPONLY | FCVAR_LINKED_CONCOMMAND) @@ -146,6 +144,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool GET_V_IFACE_CURRENT(GetEngineFactory, g_pEngineServer2, IVEngineServer2, SOURCE2ENGINETOSERVER_INTERFACE_VERSION); GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION); GET_V_IFACE_ANY(GetServerFactory, g_pSource2Server, ISource2Server, SOURCE2SERVER_INTERFACE_VERSION); + GET_V_IFACE_ANY(GetServerFactory, g_pSource2GameEntities, ISource2GameEntities, SOURCE2GAMEENTITIES_INTERFACE_VERSION); GET_V_IFACE_ANY(GetServerFactory, g_pSource2GameClients, IServerGameClients, SOURCE2GAMECLIENTS_INTERFACE_VERSION); GET_V_IFACE_ANY(GetEngineFactory, g_pNetworkServerService, INetworkServerService, NETWORKSERVERSERVICE_INTERFACE_VERSION); GET_V_IFACE_ANY(GetEngineFactory, g_gameEventSystem, IGameEventSystem, GAMEEVENTSYSTEM_INTERFACE_VERSION); @@ -155,7 +154,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool // this needs to run in case of a late load gpGlobals = GetGameGlobals(); - META_CONPRINTF( "Starting plugin.\n" ); + Message( "Starting plugin.\n" ); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, g_pSource2Server, this, &CS2Fixes::Hook_GameFrame, true); SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientActive, g_pSource2GameClients, this, &CS2Fixes::Hook_ClientActive, true); @@ -167,6 +166,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool SH_ADD_HOOK_MEMFUNC(IServerGameClients, ClientCommand, g_pSource2GameClients, this, &CS2Fixes::Hook_ClientCommand, false); SH_ADD_HOOK_MEMFUNC(IGameEventSystem, PostEventAbstract, g_gameEventSystem, this, &CS2Fixes::Hook_PostEvent, false); SH_ADD_HOOK_MEMFUNC(INetworkServerService, StartupServer, g_pNetworkServerService, this, &CS2Fixes::Hook_StartupServer, true); + SH_ADD_HOOK_MEMFUNC(ISource2GameEntities, CheckTransmit, g_pSource2GameEntities, this, &CS2Fixes::Hook_CheckTransmit, true); META_CONPRINTF( "All hooks started!\n" ); @@ -190,6 +190,8 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool addresses::Initialize(g_GameConfig); interfaces::Initialize(); + Message( "All hooks started!\n" ); + UnlockConVars(); UnlockConCommands(); @@ -217,6 +219,12 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool g_playerManager->TryAuthenticate(); }); + // Check hide distance + new CTimer(0.5f, true, true, []() + { + g_playerManager->CheckHideDistances(); + }); + // Check for the expiration of infractions like mutes or gags new CTimer(30.0f, true, true, []() { @@ -244,6 +252,7 @@ bool CS2Fixes::Unload(char *error, size_t maxlen) SH_REMOVE_HOOK_MEMFUNC(IServerGameClients, ClientCommand, g_pSource2GameClients, this, &CS2Fixes::Hook_ClientCommand, false); SH_REMOVE_HOOK_MEMFUNC(IGameEventSystem, PostEventAbstract, g_gameEventSystem, this, &CS2Fixes::Hook_PostEvent, false); SH_REMOVE_HOOK_MEMFUNC(INetworkServerService, StartupServer, g_pNetworkServerService, this, &CS2Fixes::Hook_StartupServer, true); + SH_REMOVE_HOOK_MEMFUNC(ISource2GameEntities, CheckTransmit, g_pSource2GameEntities, this, &CS2Fixes::Hook_CheckTransmit, true); ConVar_Unregister(); @@ -330,22 +339,26 @@ void CS2Fixes::AllPluginsLoaded() void CS2Fixes::Hook_ClientActive( CPlayerSlot slot, bool bLoadGame, const char *pszName, uint64 xuid ) { - META_CONPRINTF( "Hook_ClientActive(%d, %d, \"%s\", %lli)\n", slot, bLoadGame, pszName, xuid ); + Message( "Hook_ClientActive(%d, %d, \"%s\", %lli)\n", slot, bLoadGame, pszName, xuid ); } void CS2Fixes::Hook_ClientCommand( CPlayerSlot slot, const CCommand &args ) { - META_CONPRINTF( "Hook_ClientCommand(%d, \"%s\")\n", slot, args.GetCommandString() ); +#ifdef _DEBUG + Message( "Hook_ClientCommand(%d, \"%s\")\n", slot, args.GetCommandString() ); +#endif } void CS2Fixes::Hook_ClientSettingsChanged( CPlayerSlot slot ) { - META_CONPRINTF( "Hook_ClientSettingsChanged(%d)\n", slot ); +#ifdef _DEBUG + Message( "Hook_ClientSettingsChanged(%d)\n", slot ); +#endif } void CS2Fixes::Hook_OnClientConnected( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, const char *pszAddress, bool bFakePlayer ) { - META_CONPRINTF( "Hook_OnClientConnected(%d, \"%s\", %lli, \"%s\", \"%s\", %d)\n", slot, pszName, xuid, pszNetworkID, pszAddress, bFakePlayer ); + Message( "Hook_OnClientConnected(%d, \"%s\", %lli, \"%s\", \"%s\", %d)\n", slot, pszName, xuid, pszNetworkID, pszAddress, bFakePlayer ); if(bFakePlayer) g_playerManager->OnBotConnected(slot); @@ -353,7 +366,7 @@ void CS2Fixes::Hook_OnClientConnected( CPlayerSlot slot, const char *pszName, ui bool CS2Fixes::Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason ) { - META_CONPRINTF( "Hook_ClientConnect(%d, \"%s\", %lli, \"%s\", %d, \"%s\")\n", slot, pszName, xuid, pszNetworkID, unk1, pRejectReason->ToGrowable()->Get() ); + Message( "Hook_ClientConnect(%d, \"%s\", %lli, \"%s\", %d, \"%s\")\n", slot, pszName, xuid, pszNetworkID, unk1, pRejectReason->ToGrowable()->Get() ); g_playerManager->OnClientConnected(slot); @@ -362,12 +375,12 @@ bool CS2Fixes::Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 void CS2Fixes::Hook_ClientPutInServer( CPlayerSlot slot, char const *pszName, int type, uint64 xuid ) { - META_CONPRINTF( "Hook_ClientPutInServer(%d, \"%s\", %d, %d, %lli)\n", slot, pszName, type, xuid ); + Message( "Hook_ClientPutInServer(%d, \"%s\", %d, %d, %lli)\n", slot, pszName, type, xuid ); } void CS2Fixes::Hook_ClientDisconnect( CPlayerSlot slot, int reason, const char *pszName, uint64 xuid, const char *pszNetworkID ) { - META_CONPRINTF( "Hook_ClientDisconnect(%d, %d, \"%s\", %lli, \"%s\")\n", slot, reason, pszName, xuid, pszNetworkID ); + Message( "Hook_ClientDisconnect(%d, %d, \"%s\", %lli, \"%s\")\n", slot, reason, pszName, xuid, pszNetworkID ); g_playerManager->OnClientDisconnect(slot); } @@ -423,6 +436,55 @@ void CS2Fixes::Hook_GameFrame( bool simulating, bool bFirstTick, bool bLastTick } } +void CS2Fixes::Hook_CheckTransmit(CCheckTransmitInfo **ppInfoList, int infoCount, CBitVec<16384> &unionTransmitEdicts, + const Entity2Networkable_t **pNetworkables, const uint16 *pEntityIndicies, int nEntities) +{ + if (!g_pEntitySystem) + return; + + for (int i = 0; i < infoCount; i++) + { + auto &pInfo = ppInfoList[i]; + + // offset 560 happens to have a player index here, + // though this is probably part of the client class that contains the CCheckTransmitInfo + int iPlayerSlot = (int)*((uint8 *)pInfo + 560); + + auto pPlayer = g_playerManager->GetPlayer(iPlayerSlot); + + if (!pPlayer) + continue; + + auto pSelfController = (CBasePlayerController *)g_pEntitySystem->GetBaseEntity((CEntityIndex)(pPlayer->GetPlayerSlot().Get() + 1)); + + if (!pSelfController) + continue; + + auto pSelfPawn = pSelfController->GetPawn(); + + if (!pSelfPawn || !pSelfPawn->IsAlive()) + continue; + + for (int i = 1; i <= MAXPLAYERS; i++) + { + if (!pPlayer->ShouldBlockTransmit(i - 1)) + continue; + + auto pController = (CBasePlayerController *)g_pEntitySystem->GetBaseEntity((CEntityIndex)i); + + if (!pController) + continue; + + auto pPawn = pController->GetPawn(); + + if (!pPawn) + continue; + + pInfo->m_pTransmitEntity->Clear(pPawn->entindex()); + } + } +} + // Potentially might not work void CS2Fixes::OnLevelInit( char const *pMapName, char const *pMapEntities, @@ -431,13 +493,13 @@ void CS2Fixes::OnLevelInit( char const *pMapName, bool loadGame, bool background ) { - META_CONPRINTF("OnLevelInit(%s)\n", pMapName); + Message("OnLevelInit(%s)\n", pMapName); } // Potentially might not work void CS2Fixes::OnLevelShutdown() { - META_CONPRINTF("OnLevelShutdown()\n"); + Message("OnLevelShutdown()\n"); } bool CS2Fixes::Pause(char *error, size_t maxlen) @@ -452,7 +514,7 @@ bool CS2Fixes::Unpause(char *error, size_t maxlen) const char *CS2Fixes::GetLicense() { - return "MIT License"; + return "GPL v3 License"; } const char *CS2Fixes::GetVersion() diff --git a/src/cs2fixes.h b/src/cs2fixes.h index a710440b..fb856892 100644 --- a/src/cs2fixes.h +++ b/src/cs2fixes.h @@ -53,6 +53,9 @@ class CS2Fixes : public ISmmPlugin, public IMetamodListener void Hook_OnClientConnected( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, const char *pszAddress, bool bFakePlayer ); bool Hook_ClientConnect( CPlayerSlot slot, const char *pszName, uint64 xuid, const char *pszNetworkID, bool unk1, CBufferString *pRejectReason ); void Hook_ClientCommand( CPlayerSlot nSlot, const CCommand &_cmd ); + void Hook_CheckTransmit(CCheckTransmitInfo **ppInfoList, int infoCount, CBitVec<16384> &unionTransmitEdicts, + const Entity2Networkable_t **pNetworkables, const uint16 *pEntityIndicies, int nEntities); + public: const char *GetAuthor(); const char *GetName(); diff --git a/src/detours.cpp b/src/detours.cpp index 683b4e3d..01d654ef 100644 --- a/src/detours.cpp +++ b/src/detours.cpp @@ -121,7 +121,9 @@ void FASTCALL Detour_CCSWeaponBase_Spawn(CBaseEntity *pThis, void *a2) { const char *pszClassName = pThis->m_pEntity->m_designerName.String(); +#ifdef _DEBUG Message("Weapon spawn: %s\n", pszClassName); +#endif CCSWeaponBase_Spawn(pThis, a2); @@ -237,11 +239,15 @@ void ToggleLogs() if (!bBlock) { + Message("Logging is now OFF.\n"); + for (int i = 0; i < sizeof(g_LoggingDetours) / sizeof(*g_LoggingDetours); i++) g_LoggingDetours[i].EnableDetour(); } else { + Message("Logging is now ON.\n"); + for (int i = 0; i < sizeof(g_LoggingDetours) / sizeof(*g_LoggingDetours); i++) g_LoggingDetours[i].DisableDetour(); } diff --git a/src/detours.h b/src/detours.h index c400ac61..2b3400ba 100644 --- a/src/detours.h +++ b/src/detours.h @@ -20,6 +20,8 @@ #pragma once #include "cdetour.h" + +class CCheckTransmitInfo; class IRecipientFilter; class ISoundEmitterSystemBase; class CBaseEntity; diff --git a/src/playermanager.cpp b/src/playermanager.cpp index b04331f2..e89492ec 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -17,12 +17,14 @@ * this program. If not, see . */ +#include <../cs2fixes.h> #include "utlstring.h" #include "playermanager.h" #include "adminsystem.h" #include "entity/ccsplayercontroller.h" #include "ctime" + extern IVEngineServer2 *g_pEngineServer2; extern CEntitySystem *g_pEntitySystem; @@ -62,6 +64,7 @@ bool ZEPlayer::IsAdminFlagSet(uint64 iFlag) void CPlayerManager::OnBotConnected(CPlayerSlot slot) { m_vecPlayers[slot.Get()] = new ZEPlayer(slot, true); + m_UserIdLookup[g_pEngineServer2->GetPlayerUserId(slot).Get()] = slot.Get(); } void CPlayerManager::OnClientConnected(CPlayerSlot slot) @@ -70,12 +73,14 @@ void CPlayerManager::OnClientConnected(CPlayerSlot slot) Message("%d connected\n", slot.Get()); m_vecPlayers[slot.Get()] = new ZEPlayer(slot); + m_UserIdLookup[g_pEngineServer2->GetPlayerUserId(slot).Get()] = slot.Get(); } void CPlayerManager::OnClientDisconnect(CPlayerSlot slot) { Message("%d disconnected\n", slot.Get()); m_vecPlayers[slot.Get()] = nullptr; + m_UserIdLookup[g_pEngineServer2->GetPlayerUserId(slot).Get()] = -1; } void CPlayerManager::TryAuthenticate() @@ -109,6 +114,57 @@ void CPlayerManager::CheckInfractions() } } +void CPlayerManager::CheckHideDistances() +{ + if (!g_pEntitySystem) + return; + + for (int i = 0; i < MAXPLAYERS; i++) + { + auto player = GetPlayer(i); + + if (!player) + continue; + + player->ClearTransmit(); + auto hideDistance = player->GetHideDistance(); + + if (!hideDistance) + continue; + + auto pController = (CCSPlayerController *)g_pEntitySystem->GetBaseEntity((CEntityIndex)(i + 1)); + + if (!pController) + continue; + + auto pPawn = pController->GetPawn(); + + if (!pPawn || !pPawn->IsAlive()) + continue; + + auto vecPosition = pPawn->GetAbsOrigin(); + int team = pController->m_iTeamNum; + + for (int j = 1; j < MAXPLAYERS + 1; j++) + { + if (j - 1 == i) + continue; + + auto pTargetController = (CCSPlayerController *)g_pEntitySystem->GetBaseEntity((CEntityIndex)j); + + if (pTargetController) + { + auto pTargetPawn = pTargetController->GetPawn(); + + if (pTargetPawn && pTargetPawn->IsAlive() && pTargetController->m_iTeamNum == team) + { + player->SetTransmit(j - 1, pTargetPawn->GetAbsOrigin().DistToSqr(vecPosition) <= hideDistance * hideDistance); + } + } + } + } +} + ETargetType CPlayerManager::TargetPlayerString(int iCommandClient, const char* target, int& iNumClients, int *clients) { ETargetType targetType = ETargetType::NONE; @@ -184,6 +240,16 @@ ETargetType CPlayerManager::TargetPlayerString(int iCommandClient, const char* t clients[iNumClients++] = slot; } } + else if (*target == '#') + { + int userid = V_StringToUint16(target + 1, -1); + + if (userid != -1) + { + targetType = ETargetType::PLAYER; + clients[iNumClients++] = GetSlotFromUserId(userid).Get(); + } + } else { for (int i = 0; i < sizeof(m_vecPlayers) / sizeof(*m_vecPlayers); i++) @@ -200,9 +266,23 @@ ETargetType CPlayerManager::TargetPlayerString(int iCommandClient, const char* t { targetType = ETargetType::PLAYER; clients[iNumClients++] = i; + break; } } } return targetType; +} + +CPlayerSlot CPlayerManager::GetSlotFromUserId(int userid) +{ + return m_UserIdLookup[userid]; +} + +ZEPlayer *CPlayerManager::GetPlayerFromUserId(int userid) +{ + if (m_UserIdLookup[userid] == -1) + return nullptr; + + return m_vecPlayers[m_UserIdLookup[userid]]; } \ No newline at end of file diff --git a/src/playermanager.h b/src/playermanager.h index 9b64e868..95d41d08 100644 --- a/src/playermanager.h +++ b/src/playermanager.h @@ -22,6 +22,7 @@ #include "utlvector.h" #include "steam/steamclientpublic.h" #include +#include "bitvec.h" enum class ETargetType { NONE, @@ -47,6 +48,7 @@ class ZEPlayer m_SteamID = nullptr; m_bGagged = false; m_bMuted = false; + m_iHideDistance = 0; } bool IsFakeClient() { return m_bFakeClient; } @@ -61,6 +63,9 @@ class ZEPlayer void SetPlayerSlot(CPlayerSlot slot) { m_slot = slot; } void SetMuted(bool muted) { m_bMuted = muted; } void SetGagged(bool gagged) { m_bGagged = gagged; } + void SetTransmit(int index, bool shouldTransmit) { shouldTransmit ? m_shouldTransmit.Set(index) : m_shouldTransmit.Clear(index); } + void ClearTransmit() { m_shouldTransmit.ClearAll(); } + void SetHideDistance(int distance) { m_iHideDistance = distance; } void ToggleStopSound() { m_bStopSound = !m_bStopSound; } void ToggleStopDecals() { m_bStopDecals = !m_bStopDecals; } @@ -68,6 +73,8 @@ class ZEPlayer bool IsUsingStopDecals() { return m_bStopDecals; } bool IsMuted() { return m_bMuted; } bool IsGagged() { return m_bGagged; } + bool ShouldBlockTransmit(int index) { return m_shouldTransmit.Get(index); } + int GetHideDistance() { return m_iHideDistance; } CPlayerSlot GetPlayerSlot() { return m_slot; } void OnAuthenticated(); @@ -84,6 +91,8 @@ class ZEPlayer bool m_bGagged; CPlayerSlot m_slot; uint64 m_iAdminFlags; + int m_iHideDistance; + CBitVec m_shouldTransmit; }; class CPlayerManager @@ -92,6 +101,7 @@ class CPlayerManager CPlayerManager() { V_memset(m_vecPlayers, 0, sizeof(m_vecPlayers)); + V_memset(m_UserIdLookup, -1, sizeof(m_UserIdLookup)); } void OnClientConnected(CPlayerSlot slot); @@ -99,11 +109,15 @@ class CPlayerManager void OnBotConnected(CPlayerSlot slot); void TryAuthenticate(); void CheckInfractions(); + void CheckHideDistances(); + CPlayerSlot GetSlotFromUserId(int userid); + ZEPlayer *GetPlayerFromUserId(int userid); ETargetType TargetPlayerString(int iCommandClient, const char* target, int &iNumClients, int *clients); ZEPlayer *GetPlayer(CPlayerSlot slot) { return m_vecPlayers[slot.Get()]; }; private: ZEPlayer* m_vecPlayers[MAXPLAYERS]; + uint16 m_UserIdLookup[USHRT_MAX+1]; }; extern CPlayerManager *g_playerManager; \ No newline at end of file diff --git a/src/recipientfilters.h b/src/recipientfilters.h index 24668073..a0165a3c 100644 --- a/src/recipientfilters.h +++ b/src/recipientfilters.h @@ -34,7 +34,7 @@ class CSingleRecipientFilter : public IRecipientFilter int GetRecipientCount(void) const override { return 1; } - CEntityIndex GetRecipientIndex(int slot) const override { return CEntityIndex(m_iRecipient); } + CPlayerSlot GetRecipientIndex(int slot) const override { return CPlayerSlot(m_iRecipient); } private: bool m_bReliable; @@ -66,10 +66,10 @@ class CCopyRecipientFilter : public IRecipientFilter int GetRecipientCount(void) const override { return m_Recipients.Count(); } - CEntityIndex GetRecipientIndex(int slot) const override + CPlayerSlot GetRecipientIndex(int slot) const override { if (slot < 0 || slot >= GetRecipientCount()) - return CEntityIndex(-1); + return CPlayerSlot(-1); return m_Recipients[slot]; } @@ -77,5 +77,5 @@ class CCopyRecipientFilter : public IRecipientFilter private: bool m_bReliable; bool m_bInitMessage; - CUtlVectorFixed m_Recipients; + CUtlVectorFixed m_Recipients; }; \ No newline at end of file diff --git a/src/utils/entity.cpp b/src/utils/entity.cpp index 9c8b5cf9..79619d73 100644 --- a/src/utils/entity.cpp +++ b/src/utils/entity.cpp @@ -19,8 +19,11 @@ #include "entity.h" #include "../common.h" +#include "platform.h" #include "entitysystem.h" +#include "tier0/memdbgon.h" + extern CEntitySystem *g_pEntitySystem; CEntityInstance* UTIL_FindEntityByClassname(CEntityInstance* pStart, const char* name) diff --git a/src/utils/entity.h b/src/utils/entity.h index 10f363cc..15c35bf3 100644 --- a/src/utils/entity.h +++ b/src/utils/entity.h @@ -18,6 +18,7 @@ */ #pragma once -#include + +class CEntityInstance; CEntityInstance* UTIL_FindEntityByClassname(CEntityInstance* pStart, const char* name); \ No newline at end of file