diff --git a/conf/Anticheat.conf.dist b/conf/Anticheat.conf.dist index 8eca4d3..f26cb09 100644 --- a/conf/Anticheat.conf.dist +++ b/conf/Anticheat.conf.dist @@ -9,6 +9,8 @@ # 0 - (Disabled) Anticheat.Enabled = 1 +#Enable detection for GM accounts +Anticheat.EnabledOnGmAccounts = 0 # Anticheat.ReportsForIngameWarnings # Description: How many reports the player must have to notify to GameMasters ingame when he generates a new report. @@ -26,7 +28,13 @@ Anticheat.LoginMessage = 1 # Description: It represents which detections are enabled. # Default 1 (climbhack = 0 by default) Anticheat.DetectFlyHack = 1 -Anticheat.DetectWaterWalk = 1 +#Checks moveflag ascending (may give flase positives) +Anticheat.StricterFlyHackCheck = 0 +#kick option for first detect on flyhack, if false positives disable(disabled by default) +Anticheat.KickPlayerFlyHack = 0 +Anticheat.DetectWaterWalkHack = 1 +#kick option for first detect on waterwalkhack, if false positives disable(disabled by default) +Anticheat.KickPlayerWaterWalkHack = 0 Anticheat.DetectJumpHack = 1 Anticheat.DetectTelePlaneHack = 1 Anticheat.DetectSpeedHack = 1 diff --git a/src/AnticheatMgr.cpp b/src/AnticheatMgr.cpp index b5808a9..940eb61 100644 --- a/src/AnticheatMgr.cpp +++ b/src/AnticheatMgr.cpp @@ -25,406 +25,425 @@ AnticheatMgr::AnticheatMgr() AnticheatMgr::~AnticheatMgr() { - m_Players.clear(); + m_Players.clear(); } -void AnticheatMgr::JumpHackDetection(Player* player, MovementInfo /* movementInfo */,uint32 opcode) +void AnticheatMgr::JumpHackDetection(Player* player, MovementInfo /* movementInfo */, uint32 opcode) { - if (!sConfigMgr->GetBoolDefault("Anticheat.DetectJumpHack", true)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.DetectJumpHack", true)) + return; - uint32 key = player->GetGUIDLow(); + uint32 key = player->GetGUIDLow(); - if (m_Players[key].GetLastOpcode() == MSG_MOVE_JUMP && opcode == MSG_MOVE_JUMP) - { - BuildReport(player,JUMP_HACK_REPORT); - sLog->outString( "AnticheatMgr:: Jump-Hack detected player GUID (low) %u",player->GetGUIDLow()); - } + if (m_Players[key].GetLastOpcode() == MSG_MOVE_JUMP && opcode == MSG_MOVE_JUMP) + { + BuildReport(player, JUMP_HACK_REPORT); + sLog->outString("AnticheatMgr:: Jump-Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); + } } -void AnticheatMgr::WalkOnWaterHackDetection(Player* player, MovementInfo /* movementInfo */) +void AnticheatMgr::WalkOnWaterHackDetection(Player* player, MovementInfo movementInfo) { - if (!sConfigMgr->GetBoolDefault("Anticheat.DetectWaterWalk", true)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.DetectWaterWalkHack", true)) + return; - uint32 key = player->GetGUIDLow(); - if (!m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_WATERWALKING)) - return; + uint32 key = player->GetGUIDLow(); + /* Thanks to @LilleCarl */ + if (!m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_WATERWALKING) && !movementInfo.HasMovementFlag(MOVEMENTFLAG_WATERWALKING)) + return; - // if we are a ghost we can walk on water - if (!player->IsAlive()) - return; + // if we are a ghost we can walk on water + if (!player->IsAlive()) + return; - if (player->HasAuraType(SPELL_AURA_FEATHER_FALL) || - player->HasAuraType(SPELL_AURA_SAFE_FALL) || - player->HasAuraType(SPELL_AURA_WATER_WALK)) - return; - - sLog->outString( "AnticheatMgr:: Walk on Water - Hack detected player GUID (low) %u",player->GetGUIDLow()); - BuildReport(player,WALK_WATER_HACK_REPORT); + if (player->HasAuraType(SPELL_AURA_FEATHER_FALL) || + player->HasAuraType(SPELL_AURA_SAFE_FALL) || + player->HasAuraType(SPELL_AURA_WATER_WALK)) + return; + if (sConfigMgr->GetBoolDefault("Anticheat.KickPlayerWaterWalkHack", false)) + { + /* cheap hack for now, look at "applyfortargets" later*/ + /*player->AddAura(SPELL_AURA_WATER_WALK, player); + player->RemoveAura(SPELL_AURA_WATER_WALK);*/ + //cba to double check this, just adding a kick option + player->GetSession()->KickPlayer(true); + sLog->outString("AnticheatMgr:: Walk on Water - Hack detected and counteracted by kicking player %s (%u)", player->GetName(), player->GetGUIDLow()); + } + else { + sLog->outString("AnticheatMgr:: Walk on Water - Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); + } + BuildReport(player, WALK_WATER_HACK_REPORT); } -void AnticheatMgr::FlyHackDetection(Player* player, MovementInfo /* movementInfo */) +void AnticheatMgr::FlyHackDetection(Player* player, MovementInfo movementInfo) { if (!sConfigMgr->GetBoolDefault("Anticheat.DetectFlyHack", true)) return; uint32 key = player->GetGUIDLow(); - if (!m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_FLYING)) + if (player->HasAuraType(SPELL_AURA_FLY) || player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || player->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))//overkill but wth return; - - if (player->HasAuraType(SPELL_AURA_FLY) || - player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || - player->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED)) - return; - - sLog->outString( "AnticheatMgr:: Fly-Hack detected player GUID (low) %u",player->GetGUIDLow()); + /*Thanks to @LilleCarl for info to check extra flag*/ + bool stricterChecks = true; + if (sConfigMgr->GetBoolDefault("Anticheat.StricterFlyHackCheck", false)) + stricterChecks = !(movementInfo.HasMovementFlag(MOVEMENTFLAG_ASCENDING) && !player->IsInWater()); + if (!movementInfo.HasMovementFlag(MOVEMENTFLAG_CAN_FLY) && !movementInfo.HasMovementFlag(MOVEMENTFLAG_FLYING) && stricterChecks) + return; + if (sConfigMgr->GetBoolDefault("Anticheat.KickPlayerFlyHack", false)) + { + sLog->outString("AnticheatMgr:: Fly-Hack detected and counteracted by kicking player %s (%u)", player->GetName(), player->GetGUIDLow()); + player->GetSession()->KickPlayer(true); + }else + sLog->outString( "AnticheatMgr:: Fly-Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); BuildReport(player,FLY_HACK_REPORT); } void AnticheatMgr::TeleportPlaneHackDetection(Player* player, MovementInfo movementInfo) { - if (!sConfigMgr->GetBoolDefault("Anticheat.DetectTelePlaneHack", true)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.DetectTelePlaneHack", true)) + return; uint32 key = player->GetGUIDLow(); - if (m_Players[key].GetLastMovementInfo().pos.GetPositionZ() != 0 || - movementInfo.pos.GetPositionZ() != 0) - return; + if (m_Players[key].GetLastMovementInfo().pos.GetPositionZ() != 0 || + movementInfo.pos.GetPositionZ() != 0) + return; - if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING)) - return; + if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING)) + return; - // DEAD_FALLING was deprecated - //if (player->getDeathState() == DEAD_FALLING) - // return; - float x, y, z; - player->GetPosition(x, y, z); - float ground_Z = player->GetMap()->GetHeight(x, y, z); - float z_diff = fabs(ground_Z - z); + // DEAD_FALLING was deprecated + //if (player->getDeathState() == DEAD_FALLING) + // return; + float x, y, z; + player->GetPosition(x, y, z); + float ground_Z = player->GetMap()->GetHeight(x, y, z); + float z_diff = fabs(ground_Z - z); - // we are not really walking there - if (z_diff > 1.0f) - { - sLog->outString( "AnticheatMgr:: Teleport To Plane - Hack detected player GUID (low) %u",player->GetGUIDLow()); - BuildReport(player,TELEPORT_PLANE_HACK_REPORT); - } + // we are not really walking there + if (z_diff > 1.0f) + { + sLog->outString("AnticheatMgr:: Teleport To Plane - Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); + BuildReport(player, TELEPORT_PLANE_HACK_REPORT); + } } void AnticheatMgr::StartHackDetection(Player* player, MovementInfo movementInfo, uint32 opcode) { - if (!sConfigMgr->GetBoolDefault("Anticheat.Enabled", 0)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.Enabled", 0)) + return; - if (player->IsGameMaster()) - return; + if (player->IsGameMaster()) + return; - uint32 key = player->GetGUIDLow(); + uint32 key = player->GetGUIDLow(); - if (player->IsInFlight() || player->GetTransport() || player->GetVehicle()) - { - m_Players[key].SetLastMovementInfo(movementInfo); - m_Players[key].SetLastOpcode(opcode); - return; - } + if (player->IsInFlight() || player->GetTransport() || player->GetVehicle()) + { + m_Players[key].SetLastMovementInfo(movementInfo); + m_Players[key].SetLastOpcode(opcode); + return; + } - SpeedHackDetection(player,movementInfo); - FlyHackDetection(player,movementInfo); - WalkOnWaterHackDetection(player,movementInfo); - JumpHackDetection(player,movementInfo,opcode); - TeleportPlaneHackDetection(player, movementInfo); - ClimbHackDetection(player,movementInfo,opcode); + SpeedHackDetection(player, movementInfo); + FlyHackDetection(player, movementInfo); + WalkOnWaterHackDetection(player, movementInfo); + JumpHackDetection(player, movementInfo, opcode); + TeleportPlaneHackDetection(player, movementInfo); + ClimbHackDetection(player, movementInfo, opcode); - m_Players[key].SetLastMovementInfo(movementInfo); - m_Players[key].SetLastOpcode(opcode); + m_Players[key].SetLastMovementInfo(movementInfo); + m_Players[key].SetLastOpcode(opcode); } // basic detection void AnticheatMgr::ClimbHackDetection(Player *player, MovementInfo movementInfo, uint32 opcode) { - if (!sConfigMgr->GetBoolDefault("Anticheat.DetectClimbHack", false)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.DetectClimbHack", false)) + return; - uint32 key = player->GetGUIDLow(); + uint32 key = player->GetGUIDLow(); - if (opcode != MSG_MOVE_HEARTBEAT || - m_Players[key].GetLastOpcode() != MSG_MOVE_HEARTBEAT) - return; + if (opcode != MSG_MOVE_HEARTBEAT || + m_Players[key].GetLastOpcode() != MSG_MOVE_HEARTBEAT) + return; - // in this case we don't care if they are "legal" flags, they are handled in another parts of the Anticheat Manager. - if (player->IsInWater() || - player->IsFlying() || - player->IsFalling()) - return; + // in this case we don't care if they are "legal" flags, they are handled in another parts of the Anticheat Manager. + if (player->IsInWater() || + player->IsFlying() || + player->IsFalling()) + return; - Position playerPos; - // Position pos = player->GetPosition(); + Position playerPos; + // Position pos = player->GetPosition(); - float deltaZ = fabs(playerPos.GetPositionZ() - movementInfo.pos.GetPositionZ()); - float deltaXY = movementInfo.pos.GetExactDist2d(&playerPos); + float deltaZ = fabs(playerPos.GetPositionZ() - movementInfo.pos.GetPositionZ()); + float deltaXY = movementInfo.pos.GetExactDist2d(&playerPos); - float angle = Position::NormalizeOrientation(tan(deltaZ/deltaXY)); + float angle = Position::NormalizeOrientation(tan(deltaZ / deltaXY)); - if (angle > CLIMB_ANGLE) - { - sLog->outString( "AnticheatMgr:: Climb-Hack detected player GUID (low) %u", player->GetGUIDLow()); - BuildReport(player,CLIMB_HACK_REPORT); - } + if (angle > CLIMB_ANGLE) + { + sLog->outString("AnticheatMgr:: Climb-Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); + BuildReport(player, CLIMB_HACK_REPORT); + } } -void AnticheatMgr::SpeedHackDetection(Player* player,MovementInfo movementInfo) +void AnticheatMgr::SpeedHackDetection(Player* player, MovementInfo movementInfo) { - if (!sConfigMgr->GetBoolDefault("Anticheat.DetectSpeedHack", true)) - return; + if (!sConfigMgr->GetBoolDefault("Anticheat.DetectSpeedHack", true)) + return; - uint32 key = player->GetGUIDLow(); + uint32 key = player->GetGUIDLow(); - // We also must check the map because the movementFlag can be modified by the client. - // If we just check the flag, they could always add that flag and always skip the speed hacking detection. - // 369 == DEEPRUN TRAM - if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && player->GetMapId() == 369) - return; + // We also must check the map because the movementFlag can be modified by the client. + // If we just check the flag, they could always add that flag and always skip the speed hacking detection. + // 369 == DEEPRUN TRAM + if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && player->GetMapId() == 369) + return; - uint32 distance2D = (uint32)movementInfo.pos.GetExactDist2d(&m_Players[key].GetLastMovementInfo().pos); - uint8 moveType = 0; + uint32 distance2D = (uint32)movementInfo.pos.GetExactDist2d(&m_Players[key].GetLastMovementInfo().pos); + uint8 moveType = 0; - // we need to know HOW is the player moving - // TO-DO: Should we check the incoming movement flags? - if (player->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING)) - moveType = MOVE_SWIM; - else if (player->IsFlying()) - moveType = MOVE_FLIGHT; - else if (player->HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) - moveType = MOVE_WALK; - else - moveType = MOVE_RUN; + // we need to know HOW is the player moving + // TO-DO: Should we check the incoming movement flags? + if (player->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING)) + moveType = MOVE_SWIM; + else if (player->IsFlying()) + moveType = MOVE_FLIGHT; + else if (player->HasUnitMovementFlag(MOVEMENTFLAG_WALKING)) + moveType = MOVE_WALK; + else + moveType = MOVE_RUN; - // how many yards the player can do in one sec. - uint32 speedRate = (uint32)(player->GetSpeed(UnitMoveType(moveType)) + movementInfo.jump.xyspeed); + // how many yards the player can do in one sec. + uint32 speedRate = (uint32)(player->GetSpeed(UnitMoveType(moveType)) + movementInfo.jump.xyspeed); - // how long the player took to move to here. - uint32 timeDiff = getMSTimeDiff(m_Players[key].GetLastMovementInfo().time,movementInfo.time); + // how long the player took to move to here. + uint32 timeDiff = getMSTimeDiff(m_Players[key].GetLastMovementInfo().time, movementInfo.time); - if (!timeDiff) - timeDiff = 1; + if (!timeDiff) + timeDiff = 1; - // this is the distance doable by the player in 1 sec, using the time done to move to this point. - uint32 clientSpeedRate = distance2D * 1000 / timeDiff; + // this is the distance doable by the player in 1 sec, using the time done to move to this point. + uint32 clientSpeedRate = distance2D * 1000 / timeDiff; - // we did the (uint32) cast to accept a margin of tolerance - if (clientSpeedRate > speedRate) - { - BuildReport(player,SPEED_HACK_REPORT); - sLog->outString( "AnticheatMgr:: Speed-Hack detected player GUID (low) %u",player->GetGUIDLow()); - } + // we did the (uint32) cast to accept a margin of tolerance + if (clientSpeedRate > speedRate) + { + BuildReport(player, SPEED_HACK_REPORT); + sLog->outString("AnticheatMgr:: Speed-Hack detected player %s (%u)", player->GetName(), player->GetGUIDLow()); + } } void AnticheatMgr::HandlePlayerLogin(Player* player) { - // we must delete this to prevent errors in case of crash - CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u",player->GetGUIDLow()); - // we initialize the pos of lastMovementPosition var. - m_Players[player->GetGUIDLow()].SetPosition(player->GetPositionX(),player->GetPositionY(),player->GetPositionZ(),player->GetOrientation()); - QueryResult resultDB = CharacterDatabase.PQuery("SELECT * FROM daily_players_reports WHERE guid=%u;",player->GetGUIDLow()); + // we must delete this to prevent errors in case of crash + CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u", player->GetGUIDLow()); + // we initialize the pos of lastMovementPosition var. + m_Players[player->GetGUIDLow()].SetPosition(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetOrientation()); + QueryResult resultDB = CharacterDatabase.PQuery("SELECT * FROM daily_players_reports WHERE guid=%u;", player->GetGUIDLow()); - if (resultDB) - m_Players[player->GetGUIDLow()].SetDailyReportState(true); + if (resultDB) + m_Players[player->GetGUIDLow()].SetDailyReportState(true); } void AnticheatMgr::HandlePlayerLogout(Player* player) { - // TO-DO Make a table that stores the cheaters of the day, with more detailed information. + // TO-DO Make a table that stores the cheaters of the day, with more detailed information. - // We must also delete it at logout to prevent have data of offline players in the db when we query the database (IE: The GM Command) - CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u",player->GetGUIDLow()); - // Delete not needed data from the memory. - m_Players.erase(player->GetGUIDLow()); + // We must also delete it at logout to prevent have data of offline players in the db when we query the database (IE: The GM Command) + CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u", player->GetGUIDLow()); + // Delete not needed data from the memory. + m_Players.erase(player->GetGUIDLow()); } void AnticheatMgr::SavePlayerData(Player* player) { - CharacterDatabase.PExecute("REPLACE INTO players_reports_status (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,creation_time) VALUES (%u,%f,%u,%u,%u,%u,%u,%u,%u,%u);",player->GetGUIDLow(),m_Players[player->GetGUIDLow()].GetAverage(),m_Players[player->GetGUIDLow()].GetTotalReports(), m_Players[player->GetGUIDLow()].GetTypeReports(SPEED_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(FLY_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(JUMP_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(WALK_WATER_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(CLIMB_HACK_REPORT),m_Players[player->GetGUIDLow()].GetCreationTime()); + CharacterDatabase.PExecute("REPLACE INTO players_reports_status (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,creation_time) VALUES (%u,%f,%u,%u,%u,%u,%u,%u,%u,%u);", player->GetGUIDLow(), m_Players[player->GetGUIDLow()].GetAverage(), m_Players[player->GetGUIDLow()].GetTotalReports(), m_Players[player->GetGUIDLow()].GetTypeReports(SPEED_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(FLY_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(JUMP_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(WALK_WATER_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(CLIMB_HACK_REPORT), m_Players[player->GetGUIDLow()].GetCreationTime()); } uint32 AnticheatMgr::GetTotalReports(uint32 lowGUID) { - return m_Players[lowGUID].GetTotalReports(); + return m_Players[lowGUID].GetTotalReports(); } float AnticheatMgr::GetAverage(uint32 lowGUID) { - return m_Players[lowGUID].GetAverage(); + return m_Players[lowGUID].GetAverage(); } uint32 AnticheatMgr::GetTypeReports(uint32 lowGUID, uint8 type) { - return m_Players[lowGUID].GetTypeReports(type); + return m_Players[lowGUID].GetTypeReports(type); } bool AnticheatMgr::MustCheckTempReports(uint8 type) { - if (type == JUMP_HACK_REPORT) - return false; + if (type == JUMP_HACK_REPORT) + return false; - return true; + return true; } -void AnticheatMgr::BuildReport(Player* player,uint8 reportType) +void AnticheatMgr::BuildReport(Player* player, uint8 reportType) { - uint32 key = player->GetGUIDLow(); + uint32 key = player->GetGUIDLow(); - if (MustCheckTempReports(reportType)) - { - uint32 actualTime = getMSTime(); + if (MustCheckTempReports(reportType)) + { + uint32 actualTime = getMSTime(); - if (!m_Players[key].GetTempReportsTimer(reportType)) - m_Players[key].SetTempReportsTimer(actualTime,reportType); + if (!m_Players[key].GetTempReportsTimer(reportType)) + m_Players[key].SetTempReportsTimer(actualTime, reportType); - if (getMSTimeDiff(m_Players[key].GetTempReportsTimer(reportType),actualTime) < 3000) - { - m_Players[key].SetTempReports(m_Players[key].GetTempReports(reportType)+1,reportType); + if (getMSTimeDiff(m_Players[key].GetTempReportsTimer(reportType), actualTime) < 3000) + { + m_Players[key].SetTempReports(m_Players[key].GetTempReports(reportType) + 1, reportType); - if (m_Players[key].GetTempReports(reportType) < 3) - return; - } else - { - m_Players[key].SetTempReportsTimer(actualTime,reportType); - m_Players[key].SetTempReports(1,reportType); - return; - } - } + if (m_Players[key].GetTempReports(reportType) < 3) + return; + } + else + { + m_Players[key].SetTempReportsTimer(actualTime, reportType); + m_Players[key].SetTempReports(1, reportType); + return; + } + } - // generating creationTime for average calculation - if (!m_Players[key].GetTotalReports()) - m_Players[key].SetCreationTime(getMSTime()); + // generating creationTime for average calculation + if (!m_Players[key].GetTotalReports()) + m_Players[key].SetCreationTime(getMSTime()); - // increasing total_reports - m_Players[key].SetTotalReports(m_Players[key].GetTotalReports()+1); - // increasing specific cheat report - m_Players[key].SetTypeReports(reportType,m_Players[key].GetTypeReports(reportType)+1); + // increasing total_reports + m_Players[key].SetTotalReports(m_Players[key].GetTotalReports() + 1); + // increasing specific cheat report + m_Players[key].SetTypeReports(reportType, m_Players[key].GetTypeReports(reportType) + 1); - // diff time for average calculation - uint32 diffTime = getMSTimeDiff(m_Players[key].GetCreationTime(),getMSTime()) / IN_MILLISECONDS; + // diff time for average calculation + uint32 diffTime = getMSTimeDiff(m_Players[key].GetCreationTime(), getMSTime()) / IN_MILLISECONDS; - if (diffTime > 0) - { - // Average == Reports per second - float average = float(m_Players[key].GetTotalReports()) / float(diffTime); - m_Players[key].SetAverage(average); - } + if (diffTime > 0) + { + // Average == Reports per second + float average = float(m_Players[key].GetTotalReports()) / float(diffTime); + m_Players[key].SetAverage(average); + } - if ((uint32)sConfigMgr->GetIntDefault("Anticheat.MaxReportsForDailyReport", 70) < m_Players[key].GetTotalReports()) - { - if (!m_Players[key].GetDailyReportState()) - { - CharacterDatabase.PExecute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,creation_time) VALUES (%u,%f,%u,%u,%u,%u,%u,%u,%u,%u);",player->GetGUIDLow(),m_Players[player->GetGUIDLow()].GetAverage(),m_Players[player->GetGUIDLow()].GetTotalReports(), m_Players[player->GetGUIDLow()].GetTypeReports(SPEED_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(FLY_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(JUMP_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(WALK_WATER_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT),m_Players[player->GetGUIDLow()].GetTypeReports(CLIMB_HACK_REPORT),m_Players[player->GetGUIDLow()].GetCreationTime()); - m_Players[key].SetDailyReportState(true); - } - } + if ((uint32)sConfigMgr->GetIntDefault("Anticheat.MaxReportsForDailyReport", 70) < m_Players[key].GetTotalReports()) + { + if (!m_Players[key].GetDailyReportState()) + { + CharacterDatabase.PExecute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,creation_time) VALUES (%u,%f,%u,%u,%u,%u,%u,%u,%u,%u);", player->GetGUIDLow(), m_Players[player->GetGUIDLow()].GetAverage(), m_Players[player->GetGUIDLow()].GetTotalReports(), m_Players[player->GetGUIDLow()].GetTypeReports(SPEED_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(FLY_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(JUMP_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(WALK_WATER_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT), m_Players[player->GetGUIDLow()].GetTypeReports(CLIMB_HACK_REPORT), m_Players[player->GetGUIDLow()].GetCreationTime()); + m_Players[key].SetDailyReportState(true); + } + } - if (m_Players[key].GetTotalReports() > (uint32)sConfigMgr->GetIntDefault("Anticheat.ReportsForIngameWarnings", 70)) - { - // display warning at the center of the screen, hacky way? - std::string str = ""; - str = "|cFFFFFC00[AC]|cFF00FFFF[|cFF60FF00" + std::string(player->GetName().c_str()) + "|cFF00FFFF] Possible cheater!"; - WorldPacket data(SMSG_NOTIFICATION, (str.size()+1)); - data << str; - sWorld->SendGlobalGMMessage(&data); - } + if (m_Players[key].GetTotalReports() > (uint32)sConfigMgr->GetIntDefault("Anticheat.ReportsForIngameWarnings", 70)) + { + // display warning at the center of the screen, hacky way? + std::string str = ""; + str = "|cFFFFFC00[Playername:|cFF00FFFF[|cFF60FF00" + std::string(player->GetName().c_str()) + "|cFF00FFFF] Possible cheater!"; + WorldPacket data(SMSG_NOTIFICATION, (str.size() + 1)); + data << str; + sWorld->SendGlobalGMMessage(&data); + } } void AnticheatMgr::AnticheatGlobalCommand(ChatHandler* handler) { - // MySQL will sort all for us, anyway this is not the best way we must only save the anticheat data not whole player's data!. - ObjectAccessor::SaveAllPlayers(); + // MySQL will sort all for us, anyway this is not the best way we must only save the anticheat data not whole player's data!. + ObjectAccessor::SaveAllPlayers(); - QueryResult resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY average ASC LIMIT 3;"); - if (!resultDB) - { - handler->PSendSysMessage("No players found."); - return; - } else - { - handler->SendSysMessage("============================="); - handler->PSendSysMessage("Players with the lowest averages:"); - do - { - Field *fieldsDB = resultDB->Fetch(); + QueryResult resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY average ASC LIMIT 3;"); + if (!resultDB) + { + handler->PSendSysMessage("No players found."); + return; + } + else + { + handler->SendSysMessage("============================="); + handler->PSendSysMessage("Players with the lowest averages:"); + do + { + Field *fieldsDB = resultDB->Fetch(); - uint32 guid = fieldsDB[0].GetUInt32(); - float average = fieldsDB[1].GetFloat(); - uint32 total_reports = fieldsDB[2].GetUInt32(); + uint32 guid = fieldsDB[0].GetUInt32(); + float average = fieldsDB[1].GetFloat(); + uint32 total_reports = fieldsDB[2].GetUInt32(); - if (Player* player = sObjectMgr->GetPlayerByLowGUID(guid)) - handler->PSendSysMessage("Player: %s Average: %f Total Reports: %u",player->GetName().c_str(),average,total_reports); + if (Player* player = sObjectMgr->GetPlayerByLowGUID(guid)) + handler->PSendSysMessage("Player: %s Average: %f Total Reports: %u", player->GetName().c_str(), average, total_reports); - } while (resultDB->NextRow()); - } + } while (resultDB->NextRow()); + } - resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY total_reports DESC LIMIT 3;"); + resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY total_reports DESC LIMIT 3;"); - // this should never happen - if (!resultDB) - { - handler->PSendSysMessage("No players found."); - return; - } else - { - handler->PSendSysMessage("============================="); - handler->PSendSysMessage("Players with the more reports:"); - do - { - Field *fieldsDB = resultDB->Fetch(); + // this should never happen + if (!resultDB) + { + handler->PSendSysMessage("No players found."); + return; + } + else + { + handler->PSendSysMessage("============================="); + handler->PSendSysMessage("Players with the more reports:"); + do + { + Field *fieldsDB = resultDB->Fetch(); - uint32 guid = fieldsDB[0].GetUInt32(); - float average = fieldsDB[1].GetFloat(); - uint32 total_reports = fieldsDB[2].GetUInt32(); + uint32 guid = fieldsDB[0].GetUInt32(); + float average = fieldsDB[1].GetFloat(); + uint32 total_reports = fieldsDB[2].GetUInt32(); - if (Player* player = sObjectMgr->GetPlayerByLowGUID(guid)) - handler->PSendSysMessage("Player: %s Total Reports: %u Average: %f",player->GetName().c_str(),total_reports,average); + if (Player* player = sObjectMgr->GetPlayerByLowGUID(guid)) + handler->PSendSysMessage("Player: %s Total Reports: %u Average: %f", player->GetName().c_str(), total_reports, average); - } while (resultDB->NextRow()); - } + } while (resultDB->NextRow()); + } } void AnticheatMgr::AnticheatDeleteCommand(uint32 guid) { - if (!guid) - { - for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it) - { - (*it).second.SetTotalReports(0); - (*it).second.SetAverage(0); - (*it).second.SetCreationTime(0); - for (uint8 i = 0; i < MAX_REPORT_TYPES; i++) - { - (*it).second.SetTempReports(0,i); - (*it).second.SetTempReportsTimer(0,i); - (*it).second.SetTypeReports(i,0); - } - } - CharacterDatabase.PExecute("DELETE FROM players_reports_status;"); - } - else - { - m_Players[guid].SetTotalReports(0); - m_Players[guid].SetAverage(0); - m_Players[guid].SetCreationTime(0); - for (uint8 i = 0; i < MAX_REPORT_TYPES; i++) - { - m_Players[guid].SetTempReports(0,i); - m_Players[guid].SetTempReportsTimer(0,i); - m_Players[guid].SetTypeReports(i,0); - } - CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u;",guid); - } + if (!guid) + { + for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it) + { + (*it).second.SetTotalReports(0); + (*it).second.SetAverage(0); + (*it).second.SetCreationTime(0); + for (uint8 i = 0; i < MAX_REPORT_TYPES; i++) + { + (*it).second.SetTempReports(0, i); + (*it).second.SetTempReportsTimer(0, i); + (*it).second.SetTypeReports(i, 0); + } + } + CharacterDatabase.PExecute("DELETE FROM players_reports_status;"); + } + else + { + m_Players[guid].SetTotalReports(0); + m_Players[guid].SetAverage(0); + m_Players[guid].SetCreationTime(0); + for (uint8 i = 0; i < MAX_REPORT_TYPES; i++) + { + m_Players[guid].SetTempReports(0, i); + m_Players[guid].SetTempReportsTimer(0, i); + m_Players[guid].SetTypeReports(i, 0); + } + CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u;", guid); + } } void AnticheatMgr::ResetDailyReportStates() { - for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it) - m_Players[(*it).first].SetDailyReportState(false); + for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it) + m_Players[(*it).first].SetDailyReportState(false); } diff --git a/src/AnticheatScripts.cpp b/src/AnticheatScripts.cpp index b037f76..f1cc2e4 100644 --- a/src/AnticheatScripts.cpp +++ b/src/AnticheatScripts.cpp @@ -1,6 +1,7 @@ #include "Configuration/Config.h" #include "AnticheatMgr.h" #include "Object.h" +#include "AccountMgr.h" int64 resetTime = 0; int64 lastIterationPlayer = sWorld->GetUptime() + 30;//TODO: change 30 secs static to a configurable option @@ -80,10 +81,11 @@ class AnticheatMovementHandlerScript : public MovementHandlerScript : MovementHandlerScript("AnticheatMovementHandlerScript") { } - void AnticheatMovementHandlerScript::OnPlayerMove(Player* player, MovementInfo mi, uint32 opcode) override - { - sAnticheatMgr->StartHackDetection(player, mi, opcode); - } + void AnticheatMovementHandlerScript::OnPlayerMove(Player* player, MovementInfo mi, uint32 opcode) override + { + if (!AccountMgr::IsGMAccount(player->GetSession()->GetSecurity()) || sConfigMgr->GetBoolDefault("Anticheat.EnabledOnGmAccounts", false)) + sAnticheatMgr->StartHackDetection(player, mi, opcode); + } }; void startAnticheatScripts() {