diff options
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/server/entities/character.cpp | 18 | ||||
| -rw-r--r-- | src/game/server/entities/character.h | 1 | ||||
| -rw-r--r-- | src/game/server/gamecontext.cpp | 105 | ||||
| -rw-r--r-- | src/game/server/gamecontext.h | 7 | ||||
| -rw-r--r-- | src/game/server/player.cpp | 13 | ||||
| -rw-r--r-- | src/game/server/player.h | 5 | ||||
| -rw-r--r-- | src/game/variables.h | 1 |
7 files changed, 114 insertions, 36 deletions
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 547eabce..27be82f8 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -158,6 +158,24 @@ bool CCharacter::AimedAtCharRecently(float aimX, float aimY, const CCharacter *c return false; } +float CCharacter::HowCloseToXRecently(vec2 x, const LastPosition *&pos, int firstTick) +{ + float lowest = 1000.0; + // start with the most recent position + firstTick = max(firstTick, Server()->Tick() - m_LastPositionsSize); + for(int lastTick = Server()->Tick(); lastTick > firstTick; --lastTick) + { + int i = lastTick % m_LastPositionsSize; + float d = distance(x, vec2(m_LastPositions[i].x, m_LastPositions[i].y)); + if(d < lowest) + { + pos = &m_LastPositions[i]; + lowest = d; + } + } + return lowest; +} + void CCharacter::SetWeapon(int W) { if(W == m_ActiveWeapon) diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index 4d615324..7b949e29 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -75,6 +75,7 @@ public: }; bool HasBeenThereRecently(float x, float y, const LastPosition *&pos, int firstTick, int lastTick) const; bool AimedAtCharRecently(float aimX, float aimY, const CCharacter *c, const LastPosition *&pos, const LastPosition *&posVictim, int firstTick); + float HowCloseToXRecently(vec2 x, const LastPosition *&pos, int firstTick); private: // player controlling this character diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 0ee29d40..5ad268cb 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -530,48 +530,85 @@ void CGameContext::OnTick() // bot detection // it is based on the behaviour of some bots to shoot at a player's _exact_ position // check each player - for(int i = 0; i < MAX_CLIENTS; ++i) + if(g_Config.m_SvBotDetection) { - CCharacter *ci, *cj; - CPlayer *p; - // abort if player is not ingame or already detected as a bot - if(!(p = m_apPlayers[i]) || p->m_IsBot || !(ci = GetPlayerChar(i))) - continue; - - // check against every other player - for(int j = 0; j < MAX_CLIENTS; ++j) + for(int i = 0; i < MAX_CLIENTS; ++i) { - const CCharacter::LastPosition *pos, *posVictim; - - // other placer needs to be ingame and in sight. don't detect the same position again - if(j != i && (cj = GetPlayerChar(j)) && cj->NetworkClipped(i) == 0 && ci->AimedAtCharRecently(p->m_LatestActivity.m_TargetX, p->m_LatestActivity.m_TargetY, cj, pos, posVictim, p->m_AimBotLastDetection) && !(pos->x == p->m_AimBotLastDetectionPos.x && pos->y == p->m_AimBotLastDetectionPos.y && posVictim->x == p->m_AimBotLastDetectionPosVictim.x && posVictim->y == p->m_AimBotLastDetectionPosVictim.y)) + CCharacter *ci, *cj; + CPlayer *p; + // abort if player is not ingame or already detected as a bot + if(!(p = m_apPlayers[i]) || p->m_IsAimBot || !(ci = GetPlayerChar(i))) + continue; + + // check against every other player + for(int j = 0; j < MAX_CLIENTS; ++j) { - p->m_AimBotLastDetection = Server()->Tick(); - p->m_AimBotLastDetectionPos = *pos; - p->m_AimBotLastDetectionPosVictim = *posVictim; - ++p->m_AimBotIndex; - // write to console - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "player=%d victim=%d a_index=%d", i, j, p->m_AimBotIndex); - Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "botdetect", aBuf); - // check if threshold is exceeded - if(p->m_AimBotIndex >= 10) + + if(j != i && (cj = GetPlayerChar(j))) { - p->m_IsBot = true; - // alert the chat - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "'%s' might be botting", Server()->ClientName(i)); - SendChat(-1, CGameContext::CHAT_ALL, aBuf); + const CCharacter::LastPosition *pos, *posVictim; + + // fast aiming bot detection + if(g_Config.m_SvBotDetection&BOT_DETECTION_FAST_AIM && p->m_AimBotTargetSpeed > 300.0 && !(p->m_AimBotLastDetectionPos.x == ci->m_Pos.x && p->m_AimBotLastDetectionPos.y == ci->m_Pos.y)) + { + vec2 t(ci->m_Pos.x + p->m_LatestActivity.m_TargetX, ci->m_Pos.y + p->m_LatestActivity.m_TargetY); + float hc = cj->HowCloseToXRecently(t, posVictim, p->m_AimBotLastDetection); + float precision = p->m_AimBotTargetSpeed * (256.0 - hc * hc); + // don't detect same position twice + if(precision > 0 && !(posVictim->x == p->m_AimBotLastDetectionPosVictim.x && posVictim->y == p->m_AimBotLastDetectionPosVictim.y)) + { + if(precision >= 50000.0) + { + p->m_AimBotLastDetection = Server()->Tick(); + p->m_AimBotLastDetectionPos.x = ci->m_Pos.x; + p->m_AimBotLastDetectionPos.y = ci->m_Pos.y; + p->m_AimBotLastDetectionPosVictim = *posVictim; + p->m_AimBotIndex += 2 * min(3, (int)(precision / 50000)); + // write to console + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "player=%d victim=%d a_index=%d precision=%d speed=%d distance=%d", i, j, p->m_AimBotIndex, (int)precision, (int)p->m_AimBotTargetSpeed, (int)hc); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "botdetect", aBuf); + // don't check other players + break; + } + } + } + + // follow bot detection + // other placer needs to be ingame and in sight. don't detect the same position again + else if(g_Config.m_SvBotDetection&BOT_DETECTION_FOLLOW && cj->NetworkClipped(i) == 0 && ci->AimedAtCharRecently(p->m_LatestActivity.m_TargetX, p->m_LatestActivity.m_TargetY, cj, pos, posVictim, p->m_AimBotLastDetection) && !(pos->x == p->m_AimBotLastDetectionPos.x && pos->y == p->m_AimBotLastDetectionPos.y && posVictim->x == p->m_AimBotLastDetectionPosVictim.x && posVictim->y == p->m_AimBotLastDetectionPosVictim.y)) + { + p->m_AimBotLastDetection = Server()->Tick(); + p->m_AimBotLastDetectionPos = *pos; + p->m_AimBotLastDetectionPosVictim = *posVictim; + ++p->m_AimBotIndex; + // write to console + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "player=%d victim=%d a_index=%d", i, j, p->m_AimBotIndex); + Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "botdetect", aBuf); + // don't check other players + break; + } + } - // don't check other players - break; } + // check if threshold is exceeded + if(p->m_AimBotIndex >= 10) + { + p->m_IsAimBot = Server()->Tick(); + // alert the admins + char aBuf[128]; + str_format(aBuf, sizeof(aBuf), "'%s' might be botting", Server()->ClientName(i)); + for(int j = 0; j < MAX_CLIENTS; ++j) + if(Server()->IsAuthed(j)) + SendChatTarget(j, aBuf); + } + + // reduce once every 2 seconds (tolerance) + if(((Server()->Tick() % (Server()->TickSpeed() * 2)) == 0) && p->m_AimBotIndex) + --p->m_AimBotIndex; } - - // reduce once every 2 seconds (tolerance) - if(((Server()->Tick() % (Server()->TickSpeed() * 2)) == 0) && p->m_AimBotIndex) - --p->m_AimBotIndex; } #ifdef CONF_DEBUG diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 27551ac8..eb73e019 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -195,6 +195,13 @@ public: virtual const char *GameType(); virtual const char *Version(); virtual const char *NetVersion(); + + // bot detection + enum + { + BOT_DETECTION_FAST_AIM=1, + BOT_DETECTION_FOLLOW=2, + }; }; inline int CmaskAll() { return -1; } diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 8fb62fa8..17fcd566 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -38,9 +38,14 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team) m_zCatchNumKillsInARow = 0; // bot detection - m_IsBot = false; + m_IsAimBot = 0; m_AimBotIndex = 0; m_AimBotLastDetection = 0; + m_AimBotTargetSpeed = .0; + m_CurrentTarget.x = 0; + m_CurrentTarget.y = 0; + m_LastTarget.x = 0; + m_LastTarget.y = 0; } CPlayer::~CPlayer() @@ -127,6 +132,12 @@ void CPlayer::Tick() ++m_LastActionTick; ++m_TeamChangeTick; } + + // bot detection + m_LastTarget = m_CurrentTarget; + m_CurrentTarget.x = m_LatestActivity.m_TargetX; + m_CurrentTarget.y = m_LatestActivity.m_TargetY; + m_AimBotTargetSpeed = abs(distance(m_CurrentTarget, m_LastTarget)); } void CPlayer::PostTick() diff --git a/src/game/server/player.h b/src/game/server/player.h index b3bf8c91..53466d0c 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -133,9 +133,12 @@ public: int LastZCatchVictim() { return HasZCatchVictims() ? m_ZCatchVictims->ClientID : -1; } // bot detection - int m_IsBot; + int m_IsAimBot; int m_AimBotIndex; int m_AimBotLastDetection; + float m_AimBotTargetSpeed; + vec2 m_CurrentTarget; + vec2 m_LastTarget; CCharacter::LastPosition m_AimBotLastDetectionPos; CCharacter::LastPosition m_AimBotLastDetectionPosVictim; diff --git a/src/game/variables.h b/src/game/variables.h index a588e6e6..8f247f25 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -118,4 +118,5 @@ MACRO_CONFIG_INT(SvKillPenalty, sv_kill_penalty, 5, 0, 50, CFGFLAG_SERVER, "The // zCatch/TeeVi MACRO_CONFIG_INT(SvLastStandingPlayers, sv_last_standing_players, 5, 2, 16, CFGFLAG_SERVER, "How many players are needed to have last standing rounds") +MACRO_CONFIG_INT(SvBotDetection, sv_bot_detection, 0, 0, 3, CFGFLAG_SERVER, "Bot detection (0=off, 1=fast aim, 2=follow, 3=all)") #endif |