diff options
| author | Marius "Teelevision" Neugebauer <marius@teele.eu> | 2014-04-02 02:41:20 +0200 |
|---|---|---|
| committer | Marius "Teelevision" Neugebauer <marius@teele.eu> | 2014-04-02 02:41:20 +0200 |
| commit | 461e9be9a6dc90e9ef5c1b365205906c1d6c8431 (patch) | |
| tree | 61bd1e3bc91a868cb930682c8db1da164a2ab4b7 | |
| parent | c207f70e19fa4cc9389f547b1bf5470634fa2af1 (diff) | |
| download | zcatch-461e9be9a6dc90e9ef5c1b365205906c1d6c8431.tar.gz zcatch-461e9be9a6dc90e9ef5c1b365205906c1d6c8431.zip | |
started bot detection
| -rw-r--r-- | src/game/server/entities/character.cpp | 55 | ||||
| -rw-r--r-- | src/game/server/entities/character.h | 12 | ||||
| -rw-r--r-- | src/game/server/gamecontext.cpp | 46 | ||||
| -rw-r--r-- | src/game/server/player.cpp | 5 | ||||
| -rw-r--r-- | src/game/server/player.h | 7 |
5 files changed, 125 insertions, 0 deletions
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 01ed8693..547eabce 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -46,6 +46,10 @@ CCharacter::CCharacter(CGameWorld *pWorld) m_Health = 0; m_Armor = 0; m_FreezeTicks = 0; + + // last positions + m_LastPositionsSize = Server()->TickSpeed() / 4; + m_LastPositions = new LastPosition[m_LastPositionsSize](); } void CCharacter::Reset() @@ -106,6 +110,52 @@ void CCharacter::Destroy() { GameServer()->m_World.m_Core.m_apCharacters[m_pPlayer->GetCID()] = 0; m_Alive = false; + + // delete last positions + delete[] m_LastPositions; +} + +// checks whether the player has been at those coords recently (like a few ticks ago) +bool CCharacter::HasBeenThereRecently(float x, float y, const LastPosition *&pos, int firstTick, int lastTick) const +{ + // start with the most recent position + float dx, dy, dxp = 0, dyp = 0; + for(; lastTick > firstTick; --lastTick) + { + int i = lastTick % m_LastPositionsSize; + dx = abs(m_LastPositions[i].x - x); + dy = abs(m_LastPositions[i].y - y); + if(dx <= 1.0 && dy <= 1.0) + { + pos = &m_LastPositions[i]; + return true; + } + // abort if too far away or if distance getting bigger + if(dx > 100.0 || dy > 100.0 || (dxp > 0 && dx > dxp && dy > dyp)) return false; + // write previous vals + dxp = dx; + dyp = dy; + } + return false; +} + +// checks whether the player has been aiming at another character recently (like a few ticks ago) +bool CCharacter::AimedAtCharRecently(float aimX, float aimY, const CCharacter *c, const LastPosition *&pos, const LastPosition *&posVictim, int firstTick) +{ + // The last few positions of both characters are saved. Since you cannot tell (due to the network) _when_ the player aimed at the other player, or even where he was when he aimed, we need to check each position of the one player against each position of the other player in the time before. + // start with the most recent position + firstTick = max(firstTick, Server()->Tick() - m_LastPositionsSize); + for(int lastTick = Server()->Tick(); lastTick > firstTick; --lastTick) + { + int b = lastTick % m_LastPositionsSize; + // check if the other player has been where the player aimed + if(c->HasBeenThereRecently(m_LastPositions[b].x + aimX, m_LastPositions[b].y + aimY, posVictim, firstTick, lastTick)) + { + pos = &m_LastPositions[b]; + return true; + } + } + return false; } void CCharacter::SetWeapon(int W) @@ -641,6 +691,11 @@ void CCharacter::Tick() // Previnput m_PrevInput = m_Input; + + // save position + m_LastPositions[Server()->Tick() % m_LastPositionsSize].x = m_Pos.x; + m_LastPositions[Server()->Tick() % m_LastPositionsSize].y = m_Pos.y; + return; } diff --git a/src/game/server/entities/character.h b/src/game/server/entities/character.h index ece33e45..4d615324 100644 --- a/src/game/server/entities/character.h +++ b/src/game/server/entities/character.h @@ -67,6 +67,14 @@ public: void Freeze(int Tick); int m_FreezeTicks; + + // bot detection + struct LastPosition { + float x; + float y; + }; + 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); private: // player controlling this character @@ -134,6 +142,10 @@ private: int m_ReckoningTick; // tick that we are performing dead reckoning From CCharacterCore m_SendCore; // core that we should send CCharacterCore m_ReckoningCore; // the dead reckoning core + + // bot detection + LastPosition *m_LastPositions; + int m_LastPositionsSize; }; diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index fa36187b..0ee29d40 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -527,6 +527,52 @@ 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) + { + 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) + { + 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)) + { + 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) + { + 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); + } + // don't check other players + break; + } + + } + + // reduce once every 2 seconds (tolerance) + if(((Server()->Tick() % (Server()->TickSpeed() * 2)) == 0) && p->m_AimBotIndex) + --p->m_AimBotIndex; + } #ifdef CONF_DEBUG if(g_Config.m_DbgDummies) diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index d3e00f9c..8fb62fa8 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -36,6 +36,11 @@ CPlayer::CPlayer(CGameContext *pGameServer, int ClientID, int Team) m_ZCatchVictims = NULL; m_zCatchNumVictims = 0; m_zCatchNumKillsInARow = 0; + + // bot detection + m_IsBot = false; + m_AimBotIndex = 0; + m_AimBotLastDetection = 0; } CPlayer::~CPlayer() diff --git a/src/game/server/player.h b/src/game/server/player.h index 51deaa5e..b3bf8c91 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -132,6 +132,13 @@ public: bool HasZCatchVictims() { return (m_ZCatchVictims != NULL); } int LastZCatchVictim() { return HasZCatchVictims() ? m_ZCatchVictims->ClientID : -1; } + // bot detection + int m_IsBot; + int m_AimBotIndex; + int m_AimBotLastDetection; + CCharacter::LastPosition m_AimBotLastDetectionPos; + CCharacter::LastPosition m_AimBotLastDetectionPosVictim; + private: CCharacter *m_pCharacter; CGameContext *m_pGameServer; |