eluna-scripts-ornfelt/lua/WowEmulationScriptPack/patch/Passive Anti-cheat.patch
2024-09-23 07:59:23 +02:00

760 lines
29 KiB
Diff

/*
#################################################################
#################################################################
#################################################################
##########Patch by: ??
##########Fixed by: JunkyBulgaria and SymbolixDEV
##########Cheat Type: SpeedHack
##########Cheat Type: FlyHack
##########Cheat Type: WalkOnWaterHack
#################################################################
#################################################################
#################################################################
/*
diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp
--- a/src/server/game/Chat/Chat.cpp
+++ b/src/server/game/Chat/Chat.cpp
@@ -690,6 +690,15 @@
{ NULL, 0, false, NULL, "", NULL }
};
+ static ChatCommand anticheatCommandTable[] =
+ {
+ { "global", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAntiCheatGlobalCommand, "", NULL },
+ { "player", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAntiCheatPlayerCommand, "", NULL },
+ { "delete", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAntiCheatDeleteCommand, "", NULL },
+ { "handle", SEC_ADMINISTRATOR, false, &ChatHandler::HandleAntiCheatHandleCommand, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
+ };
+
static ChatCommand commandTable[] =
{
{ "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
@@ -693,6 +702,7 @@
static ChatCommand commandTable[] =
{
{ "account", SEC_PLAYER, true, NULL, "", accountCommandTable },
+ { "character", SEC_GAMEMASTER, true, NULL, "", characterCommandTable},
{ "gm", SEC_MODERATOR, true, NULL, "", gmCommandTable },
{ "npc", SEC_MODERATOR, false, NULL, "", npcCommandTable },
{ "go", SEC_MODERATOR, false, NULL, "", goCommandTable },
diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h
--- a/src/server/game/Chat/Chat.h
+++ b/src/server/game/Chat/Chat.h
@@ -601,6 +601,12 @@
bool HandleTempGameObjectCommand(const char* args);
bool HandleTempAddSpwCommand(const char* args);
+ // ANTICHEAT
+ bool HandleAntiCheatGlobalCommand(const char* args); // top3 : Amount || Average || (Amount && Average)
+ bool HandleAntiCheatPlayerCommand(const char* args); // returns especific player's average and amount
+ bool HandleAntiCheatDeleteCommand(const char* args); // if no player name as parameter, deletes all logs else deletes specific player's log
+ bool HandleAntiCheatHandleCommand(const char* args); // turn it on, turn it off
+
//! Development Commands
/*bool HandleQuestAdd(const char * args);
diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp
--- a/src/server/game/Chat/Commands/Level3.cpp
+++ b/src/server/game/Chat/Commands/Level3.cpp
@@ -7194,6 +7194,173 @@
PSendSysMessage(LANG_COMMAND_PLAYED_TO_ALL, soundId);
return true;
}
+// ADD BY ANTICHEAT
+bool ChatHandler::HandleAntiCheatDeleteCommand(const char *args)
+{
+ std::string strCommand;
+
+ char* command = strtok((char*)args, " "); //get entered name
+
+ if (!command)
+ return true;
+
+ strCommand = command;
+
+ if (strCommand.compare("deleteall") == 0)
+ {
+
+ for (uint8 uiI = 0; uiI < 3; uiI++)
+ {
+ CharacterDatabase.PExecute("DELETE FROM cheat_first_report");
+ CharacterDatabase.PExecute("DELETE FROM cheat_temp_reports");
+ CharacterDatabase.PExecute("DELETE FROM cheat_reports");
+ }
+
+ } else
+ {
+ normalizePlayerName(strCommand);
+ Player* pPlayer = sObjectMgr.GetPlayer(strCommand.c_str()); //get player by name
+
+ if (!pPlayer)
+ PSendSysMessage("Player doesn't exist");
+ else
+ {
+ for (uint8 uiI = 0; uiI < 3; uiI++)
+ {
+ CharacterDatabase.PExecute("DELETE FROM cheat_reports WHERE guid = %u",pPlayer->GetGUIDLow());
+ CharacterDatabase.PExecute("DELETE FROM cheat_temp_reports WHERE guid = %u",pPlayer->GetGUIDLow());
+ CharacterDatabase.PExecute("DELETE FROM cheat_first_report WHERE guid = %u",pPlayer->GetGUIDLow());
+ }
+ }
+ }
+
+ return true;
+}
+// ADD BY ANTICHEAT
+bool ChatHandler::HandleAntiCheatPlayerCommand(const char *args)
+{
+ std::string strCommand;
+
+ char* command = strtok((char*)args, " ");
+
+ uint32 uiGUID = 0;
+ Player* pPlayer = NULL;
+
+ if (command)
+ {
+ strCommand = command;
+
+ normalizePlayerName(strCommand);
+
+ pPlayer = sObjectMgr.GetPlayer(strCommand.c_str()); //get player by name
+
+ if (pPlayer)
+ uiGUID = pPlayer->GetGUIDLow();
+ }else
+ {
+ pPlayer = getSelectedPlayer();
+ if (pPlayer)
+ uiGUID = pPlayer->GetGUIDLow();
+ }
+
+ if (uiGUID == 0)
+ {
+ PSendSysMessage("There is no player.");
+ return true;
+ }
+
+ QueryResult result = CharacterDatabase.PQuery("SELECT count( * ) AS 'Repeticiones' FROM `characters` AS A, `cheat_reports` AS B WHERE A.`online` =1 AND A.`guid` = B.`guid` AND A.`guid`=%u GROUP BY B.`guid` ORDER BY Repeticiones DESC LIMIT 0 , 1",uiGUID);
+
+ if (result)
+ {
+ do
+ {
+ Field* fields=result->Fetch();
+ uint32 warnings = fields[0].GetUInt32();
+ PSendSysMessage("Amount: %u", warnings);
+ }
+ while (result->NextRow());
+ } else
+ PSendSysMessage("Player's amount log is empty!.");
+
+ QueryResult resultw = CharacterDatabase.PQuery("SELECT CAST((SUM(B.time ) / count( * ) ) - C.time AS UNSIGNED) AS 'promedio' , CAST(count( * ) AS UNSIGNED) AS 'Repeticiones' FROM `characters` AS A, `cheat_temp_reports` AS B, cheat_first_report AS C WHERE A.`online` =1 AND A.`guid` = B.`guid` AND A.guid = C.guid AND A.`guid`=%u GROUP BY B.`guid` ORDER BY Repeticiones DESC LIMIT 0 , 1",uiGUID);
+
+ if (resultw)
+ {
+ do
+ {
+ Field* fields=resultw->Fetch();
+ uint32 average = fields[0].GetUInt32();
+ uint32 warnings = fields[1].GetUInt32();
+
+ PSendSysMessage("Average: %u Warnings: %u", average, warnings);
+ }
+ while (resultw->NextRow());
+ } else
+ PSendSysMessage("Player's average log is empty!.");
+
+ return true;
+}
+// ADD BY ANTICHEAT
+bool ChatHandler::HandleAntiCheatHandleCommand(const char *args)
+{
+ std::string strCommand;
+
+ char* command = strtok((char*)args, " ");
+
+ if (!command)
+ return true;
+
+ strCommand = command;
+
+ if (strCommand.compare("on") == 0)
+ sWorld.setBoolConfig(CONFIG_ANTICHEAT_ENABLE,true);
+ else if (strCommand.compare("off") == 0)
+ sWorld.setBoolConfig(CONFIG_ANTICHEAT_ENABLE,false);
+
+ return true;
+}
+// ADD BY ANTICHEAT
+bool ChatHandler::HandleAntiCheatGlobalCommand(const char *args)
+{
+ QueryResult result = CharacterDatabase.PQuery("SELECT A.`name` , count( * ) AS 'Repeticiones' FROM `characters` AS A, `cheat_reports` AS B WHERE A.`online` =1 AND A.`guid` = B.`guid` GROUP BY B.`guid` ORDER BY Repeticiones DESC LIMIT 0 , 3");
+
+ PSendSysMessage("Cheaters by Amount: -------------");
+ if (result)
+ {
+ do
+ {
+ Field* fields=result->Fetch();
+ std::string name = fields[0].GetCppString();
+ uint32 warnings = fields[1].GetUInt32();
+
+ PSendSysMessage("Name: %s Warnings: %u", name.c_str(), warnings);
+ }
+ while (result->NextRow());
+ } else
+ PSendSysMessage("Cheaters amount log empty!.");
+
+ PSendSysMessage("Cheaters by Average: -------------");
+
+ QueryResult results = CharacterDatabase.PQuery("SELECT A.`name` , CAST((SUM(B.time ) / count( * ) ) - C.time AS UNSIGNED) AS 'promedio' , CAST(count( * ) AS UNSIGNED) AS 'Repeticiones' FROM `characters` AS A, `cheat_temp_reports` AS B, cheat_first_report AS C WHERE A.`online` =1 AND A.`guid` = B.`guid` AND A.guid = C.guid GROUP BY B.`guid` ORDER BY Repeticiones DESC LIMIT 0 , 3;");
+
+ if (results)
+ {
+ do
+ {
+ Field* fields=results->Fetch();
+ std::string name = fields[0].GetCppString();
+ uint32 average = fields[1].GetUInt32();
+ uint32 warnings = fields[2].GetUInt32();
+
+ PSendSysMessage("Name: %s Average: %u Warnings: %u", name.c_str(), average, warnings);
+ }
+ while (results->NextRow());
+ } else
+ PSendSysMessage("Cheaters average log empty!.");
+
+ return true;
+}
bool ChatHandler::HandleFreezeCommand(const char *args)
{
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -619,6 +619,10 @@
Player::~Player ()
{
+ // anticheat
+ if (sWorld.getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
+ CleanTempCheatReports();
+
// it must be unloaded already in PlayerLogout and accessed only for loggined player
//m_social = NULL;
@@ -654,6 +658,202 @@
sWorld.DecreasePlayerCount();
}
+bool Player::HasFirstReport()
+{
+ QueryResult result = CharacterDatabase.PQuery("SELECT * FROM cheat_first_report WHERE guid = %u",GetGUIDLow());
+
+ if (result)
+ return true;
+ else
+ return false;
+}
+
+void Player::CleanTempCheatReports()
+{
+ for (uint8 uiI = 0; uiI < 2; uiI++)
+ {
+
+ if (uiI == 0)
+ {
+ // QueryResult result = CharacterDatabase.PQuery( "DELETE FROM cheat_first_report WHERE guid = %u",GetGUIDLow());
+ }
+ else
+ QueryResult result = CharacterDatabase.PQuery("DELETE FROM cheat_temp_reports WHERE guid = %u",GetGUIDLow());
+
+ }
+}
+
+void Player::ElaborateCheatReport(Player* pPlayer, uint8 uiCheatType)
+{
+ if (!pPlayer)
+ return;
+
+ // cheatType 1 == SpeedHack
+ // cheatType 2 == FlyHack
+ // cheatType 3 == WalkOnWaterHack
+
+ std::string strReportType;
+
+
+ switch(uiCheatType)
+ {
+ case 1:
+ strReportType = "Speed-Hack";
+ break;
+ case 2:
+ strReportType = "Fly-Hack";
+ case 3:
+ strReportType = "WalkOnWater-Hack";
+ break;
+ default:
+ strReportType = "";
+ break;
+ }
+
+ std::string name = pPlayer->GetName();
+ CharacterDatabase.escape_string(name);
+
+ if (!HasFirstReport())
+ {
+ CharacterDatabase.PExecute("INSERT INTO cheat_first_report (`guid`,`name`,`latency`,`time`) VALUES (%u,'%s',%u,NOW())",
+ pPlayer->GetGUIDLow(),
+ name.c_str(),
+ pPlayer->GetSession()->GetLatency());
+ ChatHandler(pPlayer).PSendSysMessage("You have been cought cheating and was reported , The Punishment for This offence is a lifetime ip and account and similer accounts ban , you will be punished automaticly if you continue.");
+ }
+
+ for (uint8 uiI = 0; uiI < 2; uiI++)
+ {
+ if (uiI == 0)
+ {
+ CharacterDatabase.PExecute("INSERT INTO cheat_reports (`guid`,`name`,`latency`,`mapid`,`position_x`,`position_y`,`position_z`,`report`,`time`) VALUES (%u,'%s',%u,%u,%f,%f,%f,'%s',NOW())",
+ pPlayer->GetGUIDLow(),
+ name.c_str(),
+ pPlayer->GetSession()->GetLatency(),
+ pPlayer->GetMapId(),
+ pPlayer->GetPositionX(),
+ pPlayer->GetPositionY(),
+ pPlayer->GetPositionZ(),
+ strReportType.c_str());
+
+ uint32 charcount = 0;
+ // check character count
+ QueryResult count = CharacterDatabase.PQuery("SELECT COUNT(*) FROM cheat_reports WHERE guid = '%d'", pPlayer->GetGUIDLow());
+ if (count)
+ {
+ Field *fields=count->Fetch();
+ charcount = fields[0].GetUInt32();
+ }
+
+ // If Its Speed Hacking
+ if(uiCheatType == 1)
+ {
+ if(charcount >= 2 && charcount << 4)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("You have continued to cheat and you will be killed , if you still continue to cheat you will be automaticly banned , be careful !");
+ }
+ if(charcount >= 4 && charcount << 6)
+ {
+ if(pPlayer->isDead())
+ {
+ pPlayer->GetSession()->KickPlayer();
+ }else
+ {
+ pPlayer->Kill(pPlayer,true);
+ }
+ ChatHandler(pPlayer).PSendSysMessage("Next Time Its More then that !");
+ }
+ if(charcount >= 6 && charcount << 8)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ }
+ if(charcount >= 8 && charcount << 10)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("Why Do You Continue to cheat , do you think you will get better at the game , get items using cheats , this is the third time you are warned , one more time and you will be banned for life automaticly ! ");
+ }
+ if(charcount >= 10 && charcount << 12)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 'Anti-Cheat System', '%s', '1')",
+ pPlayer->GetSession()->GetAccountId(),
+ strReportType.c_str());
+ }
+ if(charcount >= 12 && charcount << 14)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("It seems you just do not understand how this works , more cheating will result in an IP Ban , Now Stop it you Idoit ! ");
+ }
+ if(charcount >= 16)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP(),'Anti-Cheat System','%s')",
+ pPlayer->GetSession()->GetPlayerName(),
+ strReportType.c_str());
+ }
+ }
+ // if its Fly hacking
+ if(uiCheatType == 2 || 3)
+ {
+ if(charcount >= 4 && charcount << 6)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("You have continued to cheat and you will be killed , if you still continue to cheat you will be automaticly banned , be careful !");
+ }
+ if(charcount >= 8 && charcount << 10)
+ {
+ if(pPlayer->isDead())
+ {
+ pPlayer->GetSession()->KickPlayer();
+ }else
+ {
+ pPlayer->Kill(pPlayer,true);
+ }
+ ChatHandler(pPlayer).PSendSysMessage("Next Time Its More then that !");
+ }
+ if(charcount >= 10 && charcount << 14)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ }
+ if(charcount >= 16 && charcount << 18)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("Why Do You Continue to cheat , do you think you will get better at the game , get items using cheats , this is the third time you are warned , one more time and you will be banned for life automaticly ! ");
+ }
+ if(charcount >= 20 && charcount << 24)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ LoginDatabase.PExecute("INSERT INTO account_banned VALUES ('%u', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 'Anti-Cheat System', '%s', '1')",
+ pPlayer->GetSession()->GetAccountId(),
+ strReportType.c_str());
+ }
+ if(charcount >= 26 && charcount << 28)
+ {
+ ChatHandler(pPlayer).PSendSysMessage("It seems you just do not understand how this works , more cheating will result in an IP Ban , Now Stop it you Idoit ! ");
+ }
+ if(charcount >= 30)
+ {
+ pPlayer->GetSession()->KickPlayer();
+ LoginDatabase.PExecute("INSERT INTO ip_banned VALUES ('%s',UNIX_TIMESTAMP(),UNIX_TIMESTAMP(),'Anti-Cheat System','%s')",
+ pPlayer->GetSession()->GetPlayerName(),
+ strReportType.c_str());
+ }
+ }
+ }
+ else
+ {
+ CharacterDatabase.PExecute("INSERT INTO cheat_temp_reports (`guid`,`name`,`mapid`,`position_x`,`position_y`,`position_z`,`report`,`time`) VALUES (%u,'%s',%u,%f,%f,%f,'%s',NOW())",
+ pPlayer->GetGUIDLow(),
+ name.c_str(),
+ pPlayer->GetMapId(),
+ pPlayer->GetPositionX(),
+ pPlayer->GetPositionY(),
+ pPlayer->GetPositionZ(),
+ strReportType.c_str());
+ // End of Else
+ }
+ // End of For
+ }
+
+ // End of Void
+}
+
void Player::CleanupsBeforeDelete(bool finalCleanup)
{
TradeCancel(false);
@@ -19862,6 +20062,24 @@
}
}
+bool Player::CanFlyAnticheat(MovementInfo& pMovementInfo)
+{
+ if (IsUnderWater())
+ return false;
+
+ if (HasAuraType(SPELL_AURA_FLY) || HasAuraType(SPELL_AURA_WATER_WALK) || HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))
+ return false;
+
+ if (Creature* pCreature = GetVehicleCreatureBase())
+ if (pCreature->GetCreatureInfo()->InhabitType & INHABIT_AIR)
+ return false;
+
+ if (HasUnitMovementFlag(MOVEMENTFLAG_JUMPING) || pMovementInfo.HasMovementFlag(MOVEMENTFLAG_JUMPING) || GetMap()->GetGameObject(pMovementInfo.t_guid))
+ return false;
+
+ return true;
+}
+
void Player::UpdatePvPState(bool onlyFFA)
{
// TODO: should we always synchronize UNIT_FIELD_BYTES_2, 1 of controller and controlled?
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -2375,6 +2375,19 @@
float GetAverageItemLevel();
+ /********************************************************************/
+ /*** ANTICHEAT SYSTEM SymbolixDEV ***/
+ /********************************************************************/
+ uint32 GetLastPacketTime() { return uiLastPacketTime;}
+ uint32 GetLastOpcode() { return uiLastOpcode; }
+ float GetLastSpeedRate() { return fLastSpeedRate; }
+ void SetLastPacketTime(uint32 uiTime) { uiLastPacketTime = uiTime; }
+ void SetLastSpeedRate(float fSpeedRateRate) { fLastSpeedRate = fSpeedRateRate; }
+ void SetLastOpcode(uint32 uiOpcode) { uiLastOpcode = uiOpcode; }
+ void ElaborateCheatReport(Player* pPlayer, uint8 uiReportType);
+ bool CanFlyAnticheat(MovementInfo& pMovementInfo);
+ bool HasFirstReport();
+ void CleanTempCheatReports();
protected:
uint32 m_AreaID;
uint32 m_regenTimerCount;
@@ -2614,4 +2627,6 @@
DeclinedName *m_declinedname;
Runes *m_runes;
EquipmentSets m_EquipmentSets;
+
+ bool isAlwaysDetectableFor(WorldObject const* seer) const;
private:
@@ -2617,4 +2632,11 @@
private:
+ /********************************************************************/
+ /*** ANTICHEAT SYSTEM SymboliXDEV ***/
+ /********************************************************************/
+ uint32 uiLastPacketTime;
+ float fLastSpeedRate;
+ uint32 uiLastOpcode;
+
// internal common parts for CanStore/StoreItem functions
uint8 _CanStoreItem_InSpecificSlot(uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem) const;
uint8 _CanStoreItem_InBag(uint8 bag, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool merge, bool non_specialized, Item *pSrcItem, uint8 skip_bag, uint8 skip_slot) const;
diff --git a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp
--- a/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp
+++ b/src/server/game/Server/Protocol/Handlers/MovementHandler.cpp
@@ -348,6 +348,129 @@
}
/*----------------------*/
+
+ // ANTICHEAT CHECKS
+ if (sWorld.getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
+ {
+ /* Hack Detection doesn't work if:
+ * player is in flight/transport
+ * player is teleporting
+ * when can't free move
+ */
+
+ if (plMover &&
+ !plMover->IsInFlight() &&
+ !plMover->GetTransport() &&
+ !plMover->IsBeingTeleported() &&
+ plMover->CanFreeMove() &&
+ !plMover->IsGameMaster())
+ {
+ // fly hack detection
+ // PosZ is checked to see if the player is going up when it should not.
+ // we need a better way :(
+ if (plMover->CanFlyAnticheat(movementInfo))
+ {
+ if (movementInfo.pos.GetPositionZ() > plMover->GetPositionZ() && fabs(movementInfo.pos.GetPositionZ() - plMover->GetPositionZ()) > 1.5f)
+ {
+ float ground_Z = plMover->GetMap()->GetHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ());
+ if (movementInfo.pos.GetPositionZ() > ground_Z && fabs(movementInfo.pos.GetPositionZ() - ground_Z) >= 5.0f)
+ plMover->ElaborateCheatReport(plMover,2);
+ }
+ }
+ // speed hack detection
+ if (plMover->GetLastPacketTime() > 0 &&
+ movementInfo.GetMovementFlags() == plMover->GetUnitMovementFlags() &&
+ opcode == MSG_MOVE_HEARTBEAT &&
+ plMover->GetLastOpcode() == opcode &&
+ !plMover->GetVehicle() &&
+ plMover->GetMotionMaster()->GetCurrentMovementGeneratorType() != TARGETED_MOTION_TYPE)
+ {
+ uint8 uiMoveType = 0;
+
+ if (plMover->IsFlying())
+ uiMoveType = MOVE_FLIGHT;
+ else if (plMover->IsUnderWater())
+ uiMoveType = MOVE_SWIM;
+ else
+ uiMoveType = MOVE_RUN;
+
+ // this is the distance doable by a player in 1000 ms.
+ float fSpeedRate = plMover->GetSpeedRate(UnitMoveType(uiMoveType));
+
+ // in my opinion this var must be constant in each check to avoid false reports
+ if (plMover->GetLastSpeedRate() == fSpeedRate)
+ {
+ // Calculate Distance2D
+ float fDeltaX = pow((movementInfo.pos.GetPositionX() - plMover->GetPositionX()),2);
+ float fDeltaY = pow(movementInfo.pos.GetPositionY() - plMover->GetPositionY(),2);
+ // final distance
+ float fDistance2d = fabs(sqrt(fDeltaX + fDeltaY) - plMover->GetObjectSize() - plMover->GetObjectSize());
+
+ // time between packets
+ uint32 uiDiffTime = getMSTimeDiff(plMover->GetLastPacketTime(), movementInfo.time);
+
+ // this is the distance doable by the player in 1 sec using the time between the packets
+ float fCoreDistance = uiDiffTime * 7.0f * fSpeedRate / 1000;
+
+ /* SPEED HACK DETECTION */
+ if (uiDiffTime < sWorld.getIntConfig(CONFIG_ANTICHEAT_MAX_DIFF_TIME) && uiDiffTime > sWorld.getIntConfig(CONFIG_ANTICHEAT_MIN_DIFF_TIME))
+ {
+ // some times (i dont know why) fCoreDistance is 0
+ if (fCoreDistance > 0.0f && fDistance2d > 0)
+ {
+ if (fDistance2d > fCoreDistance)
+ {
+ if (fabs(fCoreDistance - fDistance2d) > sWorld.getFloatConfig(CONFIG_ANTICHEAT_MAX_DISTANCE_DIFF_ALLOWED))
+ {
+ TC_LOG_INFO("server.worldserver", "Cheater! guid %u name %s fCoreDistance %f fDistance2d %f uiDiffTime %u fSpeedRate %f Latency %u",plMover->GetGUIDLow(),plMover->GetName(),fCoreDistance,fDistance2d,uiDiffTime,fSpeedRate, plMover->GetSession()->GetLatency());
+ plMover->ElaborateCheatReport(plMover,1);
+ }
+ }
+ }
+ }
+ }
+ }
+ // just to prevent false reports when we switch (off/on) for example the aura or something.
+ if (movementInfo.GetMovementFlags() == plMover->GetUnitMovementFlags())
+ {
+ // walk on water hack detection
+ // AFAIK the player can only do this if has some aura that allows it...
+ if (!plMover->HasAuraType(SPELL_AURA_WATER_WALK) &&
+ plMover->HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING))
+ {
+ TC_LOG_INFO("server.worldserver", "Cheater! guid %u name %s Latency %u",plMover->GetGUIDLow(),plMover->GetName(), plMover->GetSession()->GetLatency());
+ plMover->ElaborateCheatReport(plMover,3);
+ }
+
+ // walk on water hack detection
+ // AFAIK the player can only do this if has some aura that allows it...
+ if (plMover->IsFlying() &&
+ !plMover->HasAuraType(SPELL_AURA_FLY)
+ && !plMover->GetVehicle())
+ {
+ TC_LOG_INFO("server.worldserver", "Cheater! guid %u name %s Latency %u",plMover->GetGUIDLow(),plMover->GetName(), plMover->GetSession()->GetLatency());
+ plMover->ElaborateCheatReport(plMover,2);
+ }
+ }
+ }
+
+ // save packet time for next control.
+ if (plMover)
+ {
+ uint8 uiMoveType = 0;
+
+ if (plMover->IsFlying())
+ uiMoveType = MOVE_FLIGHT;
+ else if (plMover->IsUnderWater())
+ uiMoveType = MOVE_SWIM;
+ else
+ uiMoveType = MOVE_RUN;
+
+ plMover->SetLastPacketTime(movementInfo.time);
+ plMover->SetLastSpeedRate(plMover->GetSpeedRate(UnitMoveType(uiMoveType)));
+ plMover->SetLastOpcode(opcode);
+ }
+ }
/* process position-change */
WorldPacket data(opcode, recv_data.size());
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1222,6 +1222,12 @@
m_int_configs[CONFIG_AUTOBROADCAST_CENTER] = sConfig.GetIntDefault("AutoBroadcast.Center", 0);
m_int_configs[CONFIG_AUTOBROADCAST_INTERVAL] = sConfig.GetIntDefault("AutoBroadcast.Timer", 60000);
+ // anticheat configs
+ m_bool_configs[CONFIG_ANTICHEAT_ENABLE] = sConfig.GetBoolDefault("Anticheat.Enable", false);
+ m_int_configs[CONFIG_ANTICHEAT_MAX_DIFF_TIME] = sConfig.GetIntDefault("Anticheat.MaxDiffTime", 1000);
+ m_int_configs[CONFIG_ANTICHEAT_MIN_DIFF_TIME] = sConfig.GetIntDefault("Anticheat.MinDiffTime", 50);
+ m_float_configs[CONFIG_ANTICHEAT_MAX_DISTANCE_DIFF_ALLOWED] = sConfig.GetFloatDefault("Anticheat.MaxMaxAllowedDistance",1.0f);
+
sScriptMgr.OnConfigLoad(reload);
}
@@ -2597,6 +2603,10 @@
for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
if (itr->second->GetPlayer())
itr->second->GetPlayer()->ResetDailyQuestStatus();
+
+ //ANTICHEAT
+ //CharacterDatabase.Execute("DELETE FROM cheat_reports;");
+ //CharacterDatabase.Execute("DELETE FROM cheat_first_report;");
}
void World::LoadDBAllowedSecurityLevel()
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -163,6 +163,7 @@
CONFIG_CHATLOG_BGROUND,
CONFIG_DUNGEON_FINDER_ENABLE,
CONFIG_AUTOBROADCAST,
+ CONFIG_ANTICHEAT_ENABLE,
BOOL_CONFIG_VALUE_COUNT
};
@@ -179,6 +180,7 @@
CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS,
CONFIG_THREAT_RADIUS,
CONFIG_CHANCE_OF_GM_SURVEY,
+ CONFIG_ANTICHEAT_MAX_DISTANCE_DIFF_ALLOWED,
FLOAT_CONFIG_VALUE_COUNT
};
@@ -307,6 +309,8 @@
CONFIG_AUTOBROADCAST_CENTER,
CONFIG_AUTOBROADCAST_INTERVAL,
CONFIG_MAX_RESULTS_LOOKUP_COMMANDS,
+ CONFIG_ANTICHEAT_MAX_DIFF_TIME,
+ CONFIG_ANTICHEAT_MIN_DIFF_TIME,
INT_CONFIG_VALUE_COUNT
};
diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
--- a/src/server/worldserver/worldserver.conf.dist
+++ b/src/server/worldserver/worldserver.conf.dist
@@ -2069,6 +2069,16 @@
# Default: 0 - off
# 1 - on
#
+# SymbolixDEV Anticheat.Enable
+# Enable Anticheat System
+# Default: 0 - off
+# 1 - on
+# Anticheat.MaxDiffTime
+# Default: 1000 ms
+# Anticheat.MinDiffTime
+# Default: 350 ms
+# Anticheat.MaxMaxAllowedDistance
+# Default: 1.0 f
###############################################################################
PlayerStart.AllReputation = 0
@@ -2092,3 +2102,7 @@
LevelReq.Auction = 1
LevelReq.Mail = 1
DungeonFinder.Enable = 0
+Anticheat.Enable = 0
+Anticheat.MaxDiffTime = 1000
+Anticheat.MinDiffTime = 50
+Anticheat.MaxMaxAllowedDistance = 1.0