diff --git a/conf/Anticheat.conf.dist b/conf/Anticheat.conf.dist index 254fb62..82c45f1 100644 --- a/conf/Anticheat.conf.dist +++ b/conf/Anticheat.conf.dist @@ -83,6 +83,7 @@ Anticheat.DetectZaxisHack =1 Anticheat.AntiSwimHack = 1 Anticheat.DetectGravityHack = 1 Anticheat.AntiKnockBack = 1 +Anticheat.NoFallDamage = 1 # Anticheat.StricterFlyHackCheck # Description: Checks moveflag ascending (may give false positives) diff --git a/sql/characters/base/charactersdb_anticheat.sql b/sql/characters/base/charactersdb_anticheat.sql index 67242f2..4e7dbe0 100644 --- a/sql/characters/base/charactersdb_anticheat.sql +++ b/sql/characters/base/charactersdb_anticheat.sql @@ -16,6 +16,7 @@ CREATE TABLE IF NOT EXISTS `daily_players_reports` ( `antiswim_reports` bigint unsigned NOT NULL DEFAULT 0, `gravity_reports` bigint unsigned NOT NULL DEFAULT 0, `antiknockback_reports` bigint unsigned NOT NULL DEFAULT 0, + `no_fall_damage_reports` bigint unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`guid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -37,5 +38,6 @@ CREATE TABLE IF NOT EXISTS `players_reports_status` ( `antiswim_reports` bigint unsigned NOT NULL DEFAULT 0, `gravity_reports` bigint unsigned NOT NULL DEFAULT 0, `antiknockback_reports` bigint unsigned NOT NULL DEFAULT 0, + `no_fall_damage_reports` bigint unsigned NOT NULL DEFAULT 0, PRIMARY KEY (`guid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; diff --git a/sql/updates/characters/2022_08_12_00.sql b/sql/updates/characters/2022_08_12_00.sql new file mode 100644 index 0000000..cb2b7b0 --- /dev/null +++ b/sql/updates/characters/2022_08_12_00.sql @@ -0,0 +1,6 @@ +-- run on character db +ALTER TABLE `daily_players_reports` + ADD COLUMN `no_fall_damage_reports` BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER `antiknockback_reports`; + +ALTER TABLE `players_reports_status` + ADD COLUMN `no_fall_damage_reports` BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER `antiknockback_reports`; diff --git a/src/AnticheatData.h b/src/AnticheatData.h index 0de85d2..0d1fa2e 100644 --- a/src/AnticheatData.h +++ b/src/AnticheatData.h @@ -27,7 +27,7 @@ #include "AnticheatMgr.h" -#define MAX_REPORT_TYPES 12 +#define MAX_REPORT_TYPES 13 class AnticheatData { diff --git a/src/AnticheatMgr.cpp b/src/AnticheatMgr.cpp index 2dcbacd..1bff633 100644 --- a/src/AnticheatMgr.cpp +++ b/src/AnticheatMgr.cpp @@ -89,7 +89,8 @@ void AnticheatMgr::StartHackDetection(Player* player, MovementInfo movementInfo, { AntiSwimHackDetection(player, movementInfo, opcode); } - AntiKnockBackHactDetection(player, movementInfo); + AntiKnockBackHackDetection(player, movementInfo); + NoFallDamageDetection(player, movementInfo); m_Players[key].SetLastMovementInfo(movementInfo); m_Players[key].SetLastOpcode(opcode); } @@ -702,7 +703,7 @@ void AnticheatMgr::AntiSwimHackDetection(Player* player, MovementInfo movementIn } // basic detection -void AnticheatMgr::AntiKnockBackHactDetection(Player* player, MovementInfo movementInfo) +void AnticheatMgr::AntiKnockBackHackDetection(Player* player, MovementInfo movementInfo) { if (!sConfigMgr->GetOption("Anticheat.AntiKnockBack", true)) return; @@ -728,6 +729,52 @@ void AnticheatMgr::AntiKnockBackHactDetection(Player* player, MovementInfo movem player->SetCanKnockback(false); } +// basic detection +void AnticheatMgr::NoFallDamageDetection(Player* player, MovementInfo movementInfo) +{ + if (!sConfigMgr->GetOption("Anticheat.NoFallDamage", true)) + return; + + // ghost can not get damaged + if (player->HasAuraType(SPELL_AURA_GHOST)) + return; + + // players with water walk aura jumping on to the water from ledge would not get damage and neither will safe fall and feather fall + if (player->HasAuraType(SPELL_AURA_WATER_WALK) && player->GetLiquidData().Status == LIQUID_MAP_WATER_WALK && !player->IsFlying() || + player->HasAuraType(SPELL_AURA_FEATHER_FALL) || player->HasAuraType(SPELL_AURA_SAFE_FALL)) + { + return; + } + + ObjectGuid key = player->GetGUID(); + + float lastZ = m_Players[key].GetLastMovementInfo().pos.GetPositionZ(); + float newZ = movementInfo.pos.GetPositionZ(); + float zDiff = fabs(lastZ - newZ); + int32 safe_fall = player->GetTotalAuraModifier(SPELL_AURA_SAFE_FALL); + float damageperc = 0.018f * (zDiff - safe_fall) - 0.2426f; + uint32 damage = (uint32)(damageperc * player->GetMaxHealth() * sWorld->getRate(RATE_DAMAGE_FALL)); + + // in the Player::Handlefall 14.57f is used to calculated the damageperc formula below to 0 for fall damamge + + if (movementInfo.pos.GetPositionZ() < m_Players[key].GetLastMovementInfo().pos.GetPositionZ() && zDiff > 14.57f) + { + if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING) || m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_FALLING)) + { + if (damage == 0 && !player->IsImmunedToDamageOrSchool(SPELL_SCHOOL_MASK_NORMAL)) + { + if (sConfigMgr->GetOption("Anticheat.WriteLog", true)) + { + uint32 latency = 0; + latency = player->GetSession()->GetLatency(); + LOG_INFO("anticheat.module", "AnticheatMgr:: No Fall Damage - Hack detected player {} ({}) - Latency: {} ms", player->GetName(), player->GetGUID().ToString(), latency); + } + BuildReport(player, NO_FALL_DAMAGE_HACK_REPORT); + } + } + } +} + void AnticheatMgr::HandlePlayerLogin(Player* player) { // we must delete this to prevent errors in case of crash @@ -753,15 +800,15 @@ void AnticheatMgr::HandlePlayerLogout(Player* player) void AnticheatMgr::SavePlayerData(Player* player) { AnticheatData playerData = m_Players[player->GetGUID()]; - // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - CharacterDatabase.Execute("REPLACE INTO players_reports_status (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetCreationTime()); + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + CharacterDatabase.Execute("REPLACE INTO players_reports_status (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,no_fall_damage_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetTypeReports(NO_FALL_DAMAGE_HACK_REPORT), playerData.GetCreationTime()); } void AnticheatMgr::SavePlayerDataDaily(Player* player) { AnticheatData playerData = m_Players[player->GetGUID()]; - // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - CharacterDatabase.Execute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetCreationTime()); + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + CharacterDatabase.Execute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,no_fall_damage_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetTypeReports(NO_FALL_DAMAGE_HACK_REPORT), playerData.GetCreationTime()); } uint32 AnticheatMgr::GetTotalReports(ObjectGuid guid) { @@ -795,6 +842,9 @@ bool AnticheatMgr::MustCheckTempReports(uint8 type) if (type == ANTIKNOCK_BACK_HACK_REPORT) return false; + if (type == NO_FALL_DAMAGE_HACK_REPORT) + return false; + return true; } @@ -860,8 +910,8 @@ void AnticheatMgr::BuildReport(Player* player, uint16 reportType) if (!m_Players[key].GetDailyReportState()) { AnticheatData playerData = m_Players[player->GetGUID()]; - // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - CharacterDatabase.Execute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetCreationTime()); + // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 + CharacterDatabase.Execute("REPLACE INTO daily_players_reports (guid,average,total_reports,speed_reports,fly_reports,jump_reports,waterwalk_reports,teleportplane_reports,climb_reports,teleport_reports,ignorecontrol_reports,zaxis_reports,antiswim_reports,gravity_reports,antiknockback_reports,no_fall_damage_reports,creation_time) VALUES ({},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{});", player->GetGUID().GetCounter(), playerData.GetAverage(), playerData.GetTotalReports(), playerData.GetTypeReports(SPEED_HACK_REPORT), playerData.GetTypeReports(FLY_HACK_REPORT), playerData.GetTypeReports(JUMP_HACK_REPORT), playerData.GetTypeReports(WALK_WATER_HACK_REPORT), playerData.GetTypeReports(TELEPORT_PLANE_HACK_REPORT), playerData.GetTypeReports(CLIMB_HACK_REPORT), playerData.GetTypeReports(TELEPORT_HACK_REPORT), playerData.GetTypeReports(IGNORE_CONTROL_REPORT), playerData.GetTypeReports(ZAXIS_HACK_REPORT), playerData.GetTypeReports(ANTISWIM_HACK_REPORT), playerData.GetTypeReports(GRAVITY_HACK_REPORT), playerData.GetTypeReports(ANTIKNOCK_BACK_HACK_REPORT), playerData.GetTypeReports(NO_FALL_DAMAGE_HACK_REPORT), playerData.GetCreationTime()); m_Players[key].SetDailyReportState(true); } } diff --git a/src/AnticheatMgr.h b/src/AnticheatMgr.h index d6dc0f5..2f26508 100644 --- a/src/AnticheatMgr.h +++ b/src/AnticheatMgr.h @@ -49,7 +49,8 @@ enum ReportTypes ZAXIS_HACK_REPORT = 8, ANTISWIM_HACK_REPORT = 9, GRAVITY_HACK_REPORT = 10, - ANTIKNOCK_BACK_HACK_REPORT = 11 + ANTIKNOCK_BACK_HACK_REPORT = 11, + NO_FALL_DAMAGE_HACK_REPORT = 12 // MAX_REPORT_TYPES }; @@ -97,7 +98,8 @@ class AnticheatMgr void WalkOnWaterHackDetection(Player* player, MovementInfo movementInfo); void ZAxisHackDetection(Player* player, MovementInfo movementInfo); void AntiSwimHackDetection(Player* player, MovementInfo movementInfo, uint32 opcode); - void AntiKnockBackHactDetection(Player* player, MovementInfo movementInfo); + void AntiKnockBackHackDetection(Player* player, MovementInfo movementInfo); + void NoFallDamageDetection(Player* player, MovementInfo movementInfo); void BuildReport(Player* player,uint16 reportType); bool MustCheckTempReports(uint8 type); uint32 _counter = 0; diff --git a/src/cs_anticheat.cpp b/src/cs_anticheat.cpp index f354009..baca52d 100644 --- a/src/cs_anticheat.cpp +++ b/src/cs_anticheat.cpp @@ -220,6 +220,7 @@ public: uint32 antiswim_reports = sAnticheatMgr->GetTypeReports(guid, 9); uint32 gravity_reports = sAnticheatMgr->GetTypeReports(guid, 10); uint32 antiknockback_reports = sAnticheatMgr->GetTypeReports(guid, 11); + uint32 no_fall_damage_reports = sAnticheatMgr->GetTypeReports(guid, 12); Player* playerTarget = player->GetConnectedPlayer(); uint32 latency = 0; latency = playerTarget->GetSession()->GetLatency(); @@ -230,7 +231,7 @@ public: handler->PSendSysMessage("Teleport Reports: %u || Climb Reports: %u", teleport_reports, climb_reports); handler->PSendSysMessage("Ignore Control Reports: %u || Ignore Z-Axis Reports: %u", ignorecontrol_reports, zaxis_reports); handler->PSendSysMessage("Ignore Anti-Swim Reports: %u || Gravity Reports: %u", antiswim_reports, gravity_reports); - handler->PSendSysMessage("Anti-Knock Back Reports: %u", antiknockback_reports); + handler->PSendSysMessage("Anti-Knock Back Reports: %u || No Fall Damage Reports: %u", antiknockback_reports, no_fall_damage_reports); return true; } else