diff --git a/src/Combat.cpp b/src/Combat.cpp index 1320be7..c8a665d 100644 --- a/src/Combat.cpp +++ b/src/Combat.cpp @@ -56,14 +56,10 @@ static std::pair getDamage(int attackPower, int defensePower, bool shou return ret; } -static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) { - auto pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf; +static bool checkRapidFire(CNSocket *sock, int targetCount) { Player *plr = PlayerManager::getPlayer(sock); - auto targets = (int32_t*)data->trailers; - - // rapid fire anti-cheat - // TODO: move this out of here, when generalizing packet frequency validation time_t currTime = getTime(); + if (currTime - plr->lastShot < plr->fireRate * 80) plr->suspicionRating += plr->fireRate * 100 + plr->lastShot - currTime; // gain suspicion for rapid firing else if (currTime - plr->lastShot < plr->fireRate * 180 && plr->suspicionRating > 0) @@ -71,15 +67,28 @@ static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) { plr->lastShot = currTime; - if (pkt->iNPCCnt > 3) // 3+ targets should never be possible + // 3+ targets should never be possible + if (targetCount > 3) plr->suspicionRating += 10000; - if (plr->suspicionRating > 10000) { // kill the socket when the player is too suspicious + // kill the socket when the player is too suspicious + if (plr->suspicionRating > 10000) { sock->kill(); CNShardServer::_killConnection(sock); - return; + return true; } - + + return false; +} + +static void pcAttackNpcs(CNSocket *sock, CNPacketData *data) { + auto pkt = (sP_CL2FE_REQ_PC_ATTACK_NPCs*)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + auto targets = (int32_t*)data->trailers; + + // kick the player if firing too rapidly + if (settings::ANTICHEAT && checkRapidFire(sock, pkt->iNPCCnt)) + return; /* * IMPORTANT: This validates memory safety in addition to preventing diff --git a/src/settings.cpp b/src/settings.cpp index 3413bea..14d8de4 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -20,6 +20,7 @@ bool settings::LOCALHOSTWORKAROUND = true; time_t settings::TIMEOUT = 60000; int settings::VIEWDISTANCE = 25600; bool settings::SIMULATEMOBS = true; +bool settings::ANTICHEAT = true; // default spawn point #ifndef ACADEMY @@ -108,6 +109,7 @@ void settings::init() { ACCLEVEL = reader.GetInteger("shard", "accountlevel", ACCLEVEL); EVENTMODE = reader.GetInteger("shard", "eventmode", EVENTMODE); DISABLEFIRSTUSEFLAG = reader.GetBoolean("shard", "disablefirstuseflag", DISABLEFIRSTUSEFLAG); + ANTICHEAT = reader.GetBoolean("shard", "anticheat", ANTICHEAT); MONITORENABLED = reader.GetBoolean("monitor", "enabled", MONITORENABLED); MONITORPORT = reader.GetInteger("monitor", "port", MONITORPORT); MONITORINTERVAL = reader.GetInteger("monitor", "interval", MONITORINTERVAL); diff --git a/src/settings.hpp b/src/settings.hpp index e5295c7..1ea3a43 100644 --- a/src/settings.hpp +++ b/src/settings.hpp @@ -10,6 +10,7 @@ namespace settings { extern int SHARDPORT; extern std::string SHARDSERVERIP; extern bool LOCALHOSTWORKAROUND; + extern bool ANTICHEAT; extern time_t TIMEOUT; extern int VIEWDISTANCE; extern bool SIMULATEMOBS; diff --git a/tdata b/tdata index 8230fb8..cc65dbb 160000 --- a/tdata +++ b/tdata @@ -1 +1 @@ -Subproject commit 8230fb8649d6da8de71e918c24efbb55d1c08a88 +Subproject commit cc65dbb402b5baa2b604ed66132edd88cc82a52a