· 8 years ago · Apr 06, 2018, 04:06 AM
1diff --git a/sql/anticheat.sql b/sql/anticheat.sql
2new file mode 100644
3index 0000000000..a732673844
4--- /dev/null
5+++ b/sql/anticheat.sql
6@@ -0,0 +1,30 @@
7+DROP TABLE IF EXISTS `players_reports_status`;
8+
9+CREATE TABLE `players_reports_status` (
10+ `guid` int(10) unsigned NOT NULL DEFAULT '0',
11+ `creation_time` int(10) unsigned NOT NULL DEFAULT '0',
12+ `average` float NOT NULL DEFAULT '0',
13+ `total_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
14+ `speed_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
15+ `fly_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
16+ `jump_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
17+ `waterwalk_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
18+ `teleportplane_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
19+ `climb_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
20+ PRIMARY KEY (`guid`)
21+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='';
22+
23+DROP TABLE IF EXISTS `daily_players_reports`;
24+CREATE TABLE `daily_players_reports` (
25+ `guid` int(10) unsigned NOT NULL DEFAULT '0',
26+ `creation_time` int(10) unsigned NOT NULL DEFAULT '0',
27+ `average` float NOT NULL DEFAULT '0',
28+ `total_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
29+ `speed_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
30+ `fly_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
31+ `jump_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
32+ `waterwalk_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
33+ `teleportplane_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
34+ `climb_reports` bigint(20) unsigned NOT NULL DEFAULT '0',
35+ PRIMARY KEY (`guid`)
36+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='';
37diff --git a/src/server/game/Anticheat/AnticheatData.cpp b/src/server/game/Anticheat/AnticheatData.cpp
38new file mode 100644
39index 0000000000..0a61473966
40--- /dev/null
41+++ b/src/server/game/Anticheat/AnticheatData.cpp
42@@ -0,0 +1,132 @@
43+/*
44+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
45+ *
46+ * This program is free software; you can redistribute it and/or modify it
47+ * under the terms of the GNU General Public License as published by the
48+ * Free Software Foundation; either version 2 of the License, or (at your
49+ * option) any later version.
50+ *
51+ * This program is distributed in the hope that it will be useful, but WITHOUT
52+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
53+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
54+ * more details.
55+ *
56+ * You should have received a copy of the GNU General Public License along
57+ * with this program. If not, see <http://www.gnu.org/licenses/>.
58+ */
59+
60+#include "AnticheatData.h"
61+
62+AnticheatData::AnticheatData()
63+{
64+ lastOpcode = 0;
65+ totalReports = 0;
66+ for (uint8 i = 0; i < MAX_REPORT_TYPES; i++)
67+ {
68+ typeReports[i] = 0;
69+ tempReports[i] = 0;
70+ tempReportsTimer[i] = 0;
71+ }
72+ average = 0;
73+ creationTime = 0;
74+ hasDailyReport = false;
75+}
76+
77+AnticheatData::~AnticheatData()
78+{
79+}
80+
81+void AnticheatData::SetDailyReportState(bool b)
82+{
83+ hasDailyReport = b;
84+}
85+
86+bool AnticheatData::GetDailyReportState()
87+{
88+ return hasDailyReport;
89+}
90+
91+void AnticheatData::SetLastOpcode(uint32 opcode)
92+{
93+ lastOpcode = opcode;
94+}
95+
96+void AnticheatData::SetPosition(float x, float y, float z, float o)
97+{
98+ lastMovementInfo.pos = { x, y, z, o };
99+}
100+
101+uint32 AnticheatData::GetLastOpcode() const
102+{
103+ return lastOpcode;
104+}
105+
106+const MovementInfo& AnticheatData::GetLastMovementInfo() const
107+{
108+ return lastMovementInfo;
109+}
110+
111+void AnticheatData::SetLastMovementInfo(MovementInfo& moveInfo)
112+{
113+ lastMovementInfo = moveInfo;
114+}
115+
116+uint32 AnticheatData::GetTotalReports() const
117+{
118+ return totalReports;
119+}
120+
121+void AnticheatData::SetTotalReports(uint32 _totalReports)
122+{
123+ totalReports = _totalReports;
124+}
125+
126+void AnticheatData::SetTypeReports(uint32 type, uint32 amount)
127+{
128+ typeReports[type] = amount;
129+}
130+
131+uint32 AnticheatData::GetTypeReports(uint32 type) const
132+{
133+ return typeReports[type];
134+}
135+
136+float AnticheatData::GetAverage() const
137+{
138+ return average;
139+}
140+
141+void AnticheatData::SetAverage(float _average)
142+{
143+ average = _average;
144+}
145+
146+uint32 AnticheatData::GetCreationTime() const
147+{
148+ return creationTime;
149+}
150+
151+void AnticheatData::SetCreationTime(uint32 _creationTime)
152+{
153+ creationTime = _creationTime;
154+}
155+
156+void AnticheatData::SetTempReports(uint32 amount, uint8 type)
157+{
158+ tempReports[type] = amount;
159+}
160+
161+uint32 AnticheatData::GetTempReports(uint8 type)
162+{
163+ return tempReports[type];
164+}
165+
166+void AnticheatData::SetTempReportsTimer(uint32 time, uint8 type)
167+{
168+ tempReportsTimer[type] = time;
169+}
170+
171+uint32 AnticheatData::GetTempReportsTimer(uint8 type)
172+{
173+ return tempReportsTimer[type];
174+}
175diff --git a/src/server/game/Anticheat/AnticheatData.h b/src/server/game/Anticheat/AnticheatData.h
176new file mode 100644
177index 0000000000..876c0543be
178--- /dev/null
179+++ b/src/server/game/Anticheat/AnticheatData.h
180@@ -0,0 +1,74 @@
181+/*
182+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
183+ *
184+ * This program is free software; you can redistribute it and/or modify it
185+ * under the terms of the GNU General Public License as published by the
186+ * Free Software Foundation; either version 2 of the License, or (at your
187+ * option) any later version.
188+ *
189+ * This program is distributed in the hope that it will be useful, but WITHOUT
190+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
191+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
192+ * more details.
193+ *
194+ * You should have received a copy of the GNU General Public License along
195+ * with this program. If not, see <http://www.gnu.org/licenses/>.
196+ */
197+
198+#ifndef SC_ACDATA_H
199+#define SC_ACDATA_H
200+
201+#include "AnticheatMgr.h"
202+#include "Player.h"
203+
204+#define MAX_REPORT_TYPES 6
205+
206+class AnticheatData
207+{
208+public:
209+ AnticheatData();
210+ ~AnticheatData();
211+
212+ void SetLastOpcode(uint32 opcode);
213+ uint32 GetLastOpcode() const;
214+
215+ const MovementInfo& GetLastMovementInfo() const;
216+ void SetLastMovementInfo(MovementInfo& moveInfo);
217+
218+ void SetPosition(float x, float y, float z, float o);
219+
220+ uint32 GetTotalReports() const;
221+ void SetTotalReports(uint32 _totalReports);
222+
223+ uint32 GetTypeReports(uint32 type) const;
224+ void SetTypeReports(uint32 type, uint32 amount);
225+
226+ float GetAverage() const;
227+ void SetAverage(float _average);
228+
229+ uint32 GetCreationTime() const;
230+ void SetCreationTime(uint32 creationTime);
231+
232+ void SetTempReports(uint32 amount, uint8 type);
233+ uint32 GetTempReports(uint8 type);
234+
235+ void SetTempReportsTimer(uint32 time, uint8 type);
236+ uint32 GetTempReportsTimer(uint8 type);
237+
238+ void SetDailyReportState(bool b);
239+ bool GetDailyReportState();
240+private:
241+ uint32 lastOpcode;
242+ MovementInfo lastMovementInfo;
243+ //bool disableACCheck;
244+ //uint32 disableACCheckTimer;
245+ uint32 totalReports;
246+ uint32 typeReports[MAX_REPORT_TYPES];
247+ float average;
248+ uint32 creationTime;
249+ uint32 tempReports[MAX_REPORT_TYPES];
250+ uint32 tempReportsTimer[MAX_REPORT_TYPES];
251+ bool hasDailyReport;
252+};
253+
254+#endif
255diff --git a/src/server/game/Anticheat/AnticheatMgr.cpp b/src/server/game/Anticheat/AnticheatMgr.cpp
256new file mode 100644
257index 0000000000..6420034ef1
258--- /dev/null
259+++ b/src/server/game/Anticheat/AnticheatMgr.cpp
260@@ -0,0 +1,435 @@
261+/*
262+ * This program is free software; you can redistribute it and/or modify it
263+ * under the terms of the GNU General Public License as published by the
264+ * Free Software Foundation; either version 2 of the License, or (at your
265+ * option) any later version.
266+ *
267+ * This program is distributed in the hope that it will be useful, but WITHOUT
268+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
269+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
270+ * more details.
271+ *
272+ * You should have received a copy of the GNU General Public License along
273+ * with this program. If not, see <http://www.gnu.org/licenses/>.
274+ */
275+
276+#include "AnticheatMgr.h"
277+#include "AnticheatScripts.h"
278+#include "DatabaseEnv.h"
279+#include "Log.h"
280+#include "MapManager.h"
281+#include "ObjectAccessor.h"
282+#include "Player.h"
283+#include "World.h"
284+
285+#define CLIMB_ANGLE 1.9f
286+
287+AnticheatMgr::AnticheatMgr()
288+{
289+}
290+
291+AnticheatMgr::~AnticheatMgr()
292+{
293+ m_Players.clear();
294+}
295+
296+void AnticheatMgr::JumpHackDetection(Player* player, MovementInfo /* movementInfo */,uint32 opcode)
297+{
298+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & JUMP_HACK_DETECTION) == 0)
299+ return;
300+
301+ uint32 key = player->GetGUID().GetCounter();
302+
303+ if (m_Players[key].GetLastOpcode() == MSG_MOVE_JUMP && opcode == MSG_MOVE_JUMP)
304+ {
305+ BuildReport(player,JUMP_HACK_REPORT);
306+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Jump-Hack detected player GUID (low) %u",player->GetGUID().GetCounter());
307+ }
308+}
309+
310+void AnticheatMgr::WalkOnWaterHackDetection(Player* player, MovementInfo /* movementInfo */)
311+{
312+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & WALK_WATER_HACK_DETECTION) == 0)
313+ return;
314+
315+ uint32 key = player->GetGUID().GetCounter();
316+ if (!m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_WATERWALKING))
317+ return;
318+
319+ // if we are a ghost we can walk on water
320+ if (!player->IsAlive())
321+ return;
322+
323+ if (player->HasAuraType(SPELL_AURA_FEATHER_FALL) ||
324+ player->HasAuraType(SPELL_AURA_SAFE_FALL) ||
325+ player->HasAuraType(SPELL_AURA_WATER_WALK))
326+ return;
327+
328+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Walk on Water - Hack detected player GUID (low) %u",player->GetGUID().GetCounter());
329+ BuildReport(player,WALK_WATER_HACK_REPORT);
330+
331+}
332+
333+void AnticheatMgr::FlyHackDetection(Player* player, MovementInfo /* movementInfo */)
334+{
335+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & FLY_HACK_DETECTION) == 0)
336+ return;
337+
338+ uint32 key = player->GetGUID().GetCounter();
339+ if (!m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_FLYING))
340+ return;
341+
342+ if (player->HasAuraType(SPELL_AURA_FLY) ||
343+ player->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) ||
344+ player->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED))
345+ return;
346+
347+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Fly-Hack detected player GUID (low) %u",player->GetGUID().GetCounter());
348+ BuildReport(player,FLY_HACK_REPORT);
349+}
350+
351+void AnticheatMgr::TeleportPlaneHackDetection(Player* player, MovementInfo movementInfo)
352+{
353+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & TELEPORT_PLANE_HACK_DETECTION) == 0)
354+ return;
355+
356+ uint32 key = player->GetGUID().GetCounter();
357+
358+ if (m_Players[key].GetLastMovementInfo().pos.GetPositionZ() != 0 ||
359+ movementInfo.pos.GetPositionZ() != 0)
360+ return;
361+
362+ if (movementInfo.HasMovementFlag(MOVEMENTFLAG_FALLING))
363+ return;
364+
365+ float x, y, z;
366+ player->GetPosition(x, y, z);
367+ float ground_Z = player->GetMap()->GetHeight(x, y, z);
368+ float z_diff = fabs(ground_Z - z);
369+
370+ // we are not really walking there
371+ if (z_diff > 1.0f)
372+ {
373+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Teleport To Plane - Hack detected player GUID (low) %u",player->GetGUID().GetCounter());
374+ BuildReport(player,TELEPORT_PLANE_HACK_REPORT);
375+ }
376+}
377+
378+void AnticheatMgr::StartHackDetection(Player* player, MovementInfo movementInfo, uint32 opcode)
379+{
380+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
381+ return;
382+
383+ if (player->IsGameMaster())
384+ return;
385+
386+ uint32 key = player->GetGUID().GetCounter();
387+
388+ if (player->IsInFlight() || player->GetTransport() || player->GetVehicle())
389+ {
390+ m_Players[key].SetLastMovementInfo(movementInfo);
391+ m_Players[key].SetLastOpcode(opcode);
392+ return;
393+ }
394+
395+ SpeedHackDetection(player,movementInfo);
396+ FlyHackDetection(player,movementInfo);
397+ WalkOnWaterHackDetection(player,movementInfo);
398+ JumpHackDetection(player,movementInfo,opcode);
399+ TeleportPlaneHackDetection(player, movementInfo);
400+ ClimbHackDetection(player,movementInfo,opcode);
401+
402+ m_Players[key].SetLastMovementInfo(movementInfo);
403+ m_Players[key].SetLastOpcode(opcode);
404+}
405+
406+// basic detection
407+void AnticheatMgr::ClimbHackDetection(Player *player, MovementInfo movementInfo, uint32 opcode)
408+{
409+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & CLIMB_HACK_DETECTION) == 0)
410+ return;
411+
412+ uint32 key = player->GetGUID().GetCounter();
413+
414+ if (opcode != MSG_MOVE_HEARTBEAT ||
415+ m_Players[key].GetLastOpcode() != MSG_MOVE_HEARTBEAT)
416+ return;
417+
418+ // in this case we don't care if they are "legal" flags, they are handled in another parts of the Anticheat Manager.
419+ if (player->IsInWater() ||
420+ player->IsFlying() ||
421+ player->IsFalling())
422+ return;
423+
424+ Position playerPos;
425+
426+ float deltaZ = fabs(playerPos.GetPositionZ() - movementInfo.pos.GetPositionZ());
427+ float deltaXY = movementInfo.pos.GetExactDist2d(&playerPos);
428+
429+ float angle = Position::NormalizeOrientation(tan(deltaZ/deltaXY));
430+
431+ if (angle > CLIMB_ANGLE)
432+ {
433+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Climb-Hack detected player GUID (low) %u", player->GetGUID().GetCounter());
434+ BuildReport(player,CLIMB_HACK_REPORT);
435+ }
436+}
437+
438+void AnticheatMgr::SpeedHackDetection(Player* player,MovementInfo movementInfo)
439+{
440+ if ((sWorld->getIntConfig(CONFIG_ANTICHEAT_DETECTIONS_ENABLED) & SPEED_HACK_DETECTION) == 0)
441+ return;
442+
443+ uint32 key = player->GetGUID().GetCounter();
444+
445+ // We also must check the map because the movementFlag can be modified by the client.
446+ // If we just check the flag, they could always add that flag and always skip the speed hacking detection.
447+ // 369 == DEEPRUN TRAM
448+ if (m_Players[key].GetLastMovementInfo().HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT) && player->GetMapId() == 369)
449+ return;
450+
451+ uint32 distance2D = (uint32)movementInfo.pos.GetExactDist2d(&m_Players[key].GetLastMovementInfo().pos);
452+ uint8 moveType = 0;
453+
454+ // we need to know HOW is the player moving
455+ // TO-DO: Should we check the incoming movement flags?
456+ if (player->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING))
457+ moveType = MOVE_SWIM;
458+ else if (player->IsFlying())
459+ moveType = MOVE_FLIGHT;
460+ else if (player->HasUnitMovementFlag(MOVEMENTFLAG_WALKING))
461+ moveType = MOVE_WALK;
462+ else
463+ moveType = MOVE_RUN;
464+
465+ // how many yards the player can do in one sec.
466+ uint32 speedRate = (uint32)(player->GetSpeed(UnitMoveType(moveType)) + movementInfo.jump.xyspeed);
467+
468+ // how long the player took to move to here.
469+ uint32 timeDiff = getMSTimeDiff(m_Players[key].GetLastMovementInfo().time,movementInfo.time);
470+
471+ if (!timeDiff)
472+ timeDiff = 1;
473+
474+ // this is the distance doable by the player in 1 sec, using the time done to move to this point.
475+ uint32 clientSpeedRate = distance2D * 1000 / timeDiff;
476+
477+ // we did the (uint32) cast to accept a margin of tolerance
478+ if (clientSpeedRate > speedRate)
479+ {
480+ BuildReport(player,SPEED_HACK_REPORT);
481+ TC_LOG_DEBUG("entities.player.character", "AnticheatMgr:: Speed-Hack detected player GUID (low) %u",player->GetGUID().GetCounter());
482+ }
483+}
484+
485+void AnticheatMgr::StartScripts()
486+{
487+ new AnticheatScripts();
488+}
489+
490+void AnticheatMgr::HandlePlayerLogin(Player* player)
491+{
492+ // we must delete this to prevent errors in case of crash
493+ CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u",player->GetGUID().GetCounter());
494+ // we initialize the pos of lastMovementPosition var.
495+ m_Players[player->GetGUID().GetCounter()].SetPosition(player->GetPositionX(),player->GetPositionY(),player->GetPositionZ(),player->GetOrientation());
496+ QueryResult resultDB = CharacterDatabase.PQuery("SELECT * FROM daily_players_reports WHERE guid=%u;",player->GetGUID().GetCounter());
497+
498+ if (resultDB)
499+ m_Players[player->GetGUID().GetCounter()].SetDailyReportState(true);
500+}
501+
502+void AnticheatMgr::HandlePlayerLogout(Player* player)
503+{
504+ // TO-DO Make a table that stores the cheaters of the day, with more detailed information.
505+
506+ // 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)
507+ CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u",player->GetGUID().GetCounter());
508+ // Delete not needed data from the memory.
509+ m_Players.erase(player->GetGUID().GetCounter());
510+}
511+
512+void AnticheatMgr::SavePlayerData(Player* player)
513+{
514+ 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->GetGUID().GetCounter(),m_Players[player->GetGUID().GetCounter()].GetAverage(),m_Players[player->GetGUID().GetCounter()].GetTotalReports(), m_Players[player->GetGUID().GetCounter()].GetTypeReports(SPEED_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(FLY_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(JUMP_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(WALK_WATER_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(CLIMB_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetCreationTime());
515+}
516+
517+uint32 AnticheatMgr::GetTotalReports(uint32 lowGUID)
518+{
519+ return m_Players[lowGUID].GetTotalReports();
520+}
521+
522+float AnticheatMgr::GetAverage(uint32 lowGUID)
523+{
524+ return m_Players[lowGUID].GetAverage();
525+}
526+
527+uint32 AnticheatMgr::GetTypeReports(uint32 lowGUID, uint8 type)
528+{
529+ return m_Players[lowGUID].GetTypeReports(type);
530+}
531+
532+bool AnticheatMgr::MustCheckTempReports(uint8 type)
533+{
534+ if (type == JUMP_HACK_REPORT)
535+ return false;
536+
537+ return true;
538+}
539+
540+void AnticheatMgr::BuildReport(Player* player,uint8 reportType)
541+{
542+ uint32 key = player->GetGUID().GetCounter();
543+
544+ if (MustCheckTempReports(reportType))
545+ {
546+ uint32 actualTime = getMSTime();
547+
548+ if (!m_Players[key].GetTempReportsTimer(reportType))
549+ m_Players[key].SetTempReportsTimer(actualTime,reportType);
550+
551+ if (getMSTimeDiff(m_Players[key].GetTempReportsTimer(reportType),actualTime) < 3000)
552+ {
553+ m_Players[key].SetTempReports(m_Players[key].GetTempReports(reportType)+1,reportType);
554+
555+ if (m_Players[key].GetTempReports(reportType) < 3)
556+ return;
557+ } else
558+ {
559+ m_Players[key].SetTempReportsTimer(actualTime,reportType);
560+ m_Players[key].SetTempReports(1,reportType);
561+ return;
562+ }
563+ }
564+
565+ // generating creationTime for average calculation
566+ if (!m_Players[key].GetTotalReports())
567+ m_Players[key].SetCreationTime(getMSTime());
568+
569+ // increasing total_reports
570+ m_Players[key].SetTotalReports(m_Players[key].GetTotalReports()+1);
571+ // increasing specific cheat report
572+ m_Players[key].SetTypeReports(reportType,m_Players[key].GetTypeReports(reportType)+1);
573+
574+ // diff time for average calculation
575+ uint32 diffTime = getMSTimeDiff(m_Players[key].GetCreationTime(),getMSTime()) / IN_MILLISECONDS;
576+
577+ if (diffTime > 0)
578+ {
579+ // Average == Reports per second
580+ float average = float(m_Players[key].GetTotalReports()) / float(diffTime);
581+ m_Players[key].SetAverage(average);
582+ }
583+
584+ if (sWorld->getIntConfig(CONFIG_ANTICHEAT_MAX_REPORTS_FOR_DAILY_REPORT) < m_Players[key].GetTotalReports())
585+ {
586+ if (!m_Players[key].GetDailyReportState())
587+ {
588+ 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->GetGUID().GetCounter(),m_Players[player->GetGUID().GetCounter()].GetAverage(),m_Players[player->GetGUID().GetCounter()].GetTotalReports(), m_Players[player->GetGUID().GetCounter()].GetTypeReports(SPEED_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(FLY_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(JUMP_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(WALK_WATER_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(TELEPORT_PLANE_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetTypeReports(CLIMB_HACK_REPORT),m_Players[player->GetGUID().GetCounter()].GetCreationTime());
589+ m_Players[key].SetDailyReportState(true);
590+ }
591+ }
592+
593+ if (m_Players[key].GetTotalReports() > sWorld->getIntConfig(CONFIG_ANTICHEAT_REPORTS_INGAME_NOTIFICATION))
594+ {
595+ // display warning at the center of the screen, hacky way?
596+ std::string str = "";
597+ str = "|cFFFFFC00[AC]|cFF00FFFF[|cFF60FF00" + std::string(player->GetName().c_str()) + "|cFF00FFFF] Possible cheater!";
598+ WorldPacket data(SMSG_NOTIFICATION, (str.size()+1));
599+ data << str;
600+ sWorld->SendGlobalGMMessage(&data);
601+ }
602+}
603+
604+void AnticheatMgr::AnticheatGlobalCommand(ChatHandler* handler)
605+{
606+ // 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!.
607+ ObjectAccessor::SaveAllPlayers();
608+
609+ QueryResult resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY average ASC LIMIT 3;");
610+ if (!resultDB)
611+ {
612+ handler->PSendSysMessage("No players found.");
613+ return;
614+ } else
615+ {
616+ handler->SendSysMessage("=============================");
617+ handler->PSendSysMessage("Players with the lowest averages:");
618+ do
619+ {
620+ Field *fieldsDB = resultDB->Fetch();
621+
622+ uint32 guid = fieldsDB[0].GetUInt32();
623+ float average = fieldsDB[1].GetFloat();
624+ uint32 total_reports = fieldsDB[2].GetUInt32();
625+
626+ if (Player* player = ObjectAccessor::FindPlayerByLowGUID(guid))
627+ handler->PSendSysMessage("Player: %s Average: %f Total Reports: %u",player->GetName().c_str(),average,total_reports);
628+
629+ } while (resultDB->NextRow());
630+ }
631+
632+ resultDB = CharacterDatabase.Query("SELECT guid,average,total_reports FROM players_reports_status WHERE total_reports != 0 ORDER BY total_reports DESC LIMIT 3;");
633+
634+ // this should never happen
635+ if (!resultDB)
636+ {
637+ handler->PSendSysMessage("No players found.");
638+ return;
639+ } else
640+ {
641+ handler->SendSysMessage("=============================");
642+ handler->PSendSysMessage("Players with the more reports:");
643+ do
644+ {
645+ Field *fieldsDB = resultDB->Fetch();
646+
647+ uint32 guid = fieldsDB[0].GetUInt32();
648+ float average = fieldsDB[1].GetFloat();
649+ uint32 total_reports = fieldsDB[2].GetUInt32();
650+
651+ if (Player* player = ObjectAccessor::FindPlayerByLowGUID(guid))
652+ handler->PSendSysMessage("Player: %s Total Reports: %u Average: %f",player->GetName().c_str(),total_reports,average);
653+
654+ } while (resultDB->NextRow());
655+ }
656+}
657+
658+void AnticheatMgr::AnticheatDeleteCommand(uint32 guid)
659+{
660+ if (!guid)
661+ {
662+ for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it)
663+ {
664+ (*it).second.SetTotalReports(0);
665+ (*it).second.SetAverage(0);
666+ (*it).second.SetCreationTime(0);
667+ for (uint8 i = 0; i < MAX_REPORT_TYPES; i++)
668+ {
669+ (*it).second.SetTempReports(0,i);
670+ (*it).second.SetTempReportsTimer(0,i);
671+ (*it).second.SetTypeReports(i,0);
672+ }
673+ }
674+ CharacterDatabase.PExecute("DELETE FROM players_reports_status;");
675+ }
676+ else
677+ {
678+ m_Players[guid].SetTotalReports(0);
679+ m_Players[guid].SetAverage(0);
680+ m_Players[guid].SetCreationTime(0);
681+ for (uint8 i = 0; i < MAX_REPORT_TYPES; i++)
682+ {
683+ m_Players[guid].SetTempReports(0,i);
684+ m_Players[guid].SetTempReportsTimer(0,i);
685+ m_Players[guid].SetTypeReports(i,0);
686+ }
687+ CharacterDatabase.PExecute("DELETE FROM players_reports_status WHERE guid=%u;",guid);
688+ }
689+}
690+
691+void AnticheatMgr::ResetDailyReportStates()
692+{
693+ for (AnticheatPlayersDataMap::iterator it = m_Players.begin(); it != m_Players.end(); ++it)
694+ m_Players[(*it).first].SetDailyReportState(false);
695+}
696diff --git a/src/server/game/Anticheat/AnticheatMgr.h b/src/server/game/Anticheat/AnticheatMgr.h
697new file mode 100644
698index 0000000000..3cfbb5e810
699--- /dev/null
700+++ b/src/server/game/Anticheat/AnticheatMgr.h
701@@ -0,0 +1,102 @@
702+/*
703+ * This program is free software; you can redistribute it and/or modify it
704+ * under the terms of the GNU General Public License as published by the
705+ * Free Software Foundation; either version 2 of the License, or (at your
706+ * option) any later version.
707+ *
708+ * This program is distributed in the hope that it will be useful, but WITHOUT
709+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
710+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
711+ * more details.
712+ *
713+ * You should have received a copy of the GNU General Public License along
714+ * with this program. If not, see <http://www.gnu.org/licenses/>.
715+ */
716+
717+#ifndef SC_ACMGR_H
718+#define SC_ACMGR_H
719+
720+#include "Common.h"
721+#include "SharedDefines.h"
722+#include "ScriptMgr.h"
723+#include "AnticheatData.h"
724+#include "Chat.h"
725+#include "Player.h"
726+
727+class Player;
728+class AnticheatData;
729+
730+enum ReportTypes
731+{
732+ SPEED_HACK_REPORT = 0,
733+ FLY_HACK_REPORT,
734+ WALK_WATER_HACK_REPORT,
735+ JUMP_HACK_REPORT,
736+ TELEPORT_PLANE_HACK_REPORT,
737+ CLIMB_HACK_REPORT,
738+
739+ // MAX_REPORT_TYPES
740+};
741+
742+enum DetectionTypes
743+{
744+ SPEED_HACK_DETECTION = 1,
745+ FLY_HACK_DETECTION = 2,
746+ WALK_WATER_HACK_DETECTION = 4,
747+ JUMP_HACK_DETECTION = 8,
748+ TELEPORT_PLANE_HACK_DETECTION = 16,
749+ CLIMB_HACK_DETECTION = 32
750+};
751+
752+// GUIDLow is the key.
753+typedef std::map<uint32, AnticheatData> AnticheatPlayersDataMap;
754+
755+class AnticheatMgr
756+{
757+ AnticheatMgr();
758+ ~AnticheatMgr();
759+
760+ public:
761+ static AnticheatMgr* instance()
762+ {
763+ static AnticheatMgr* instance = new AnticheatMgr();
764+ return instance;
765+ }
766+
767+ void StartHackDetection(Player* player, MovementInfo movementInfo, uint32 opcode);
768+ void DeletePlayerReport(Player* player, bool login);
769+ void DeletePlayerData(Player* player);
770+ void CreatePlayerData(Player* player);
771+ void SavePlayerData(Player* player);
772+
773+ void StartScripts();
774+
775+ void HandlePlayerLogin(Player* player);
776+ void HandlePlayerLogout(Player* player);
777+
778+ uint32 GetTotalReports(uint32 lowGUID);
779+ float GetAverage(uint32 lowGUID);
780+ uint32 GetTypeReports(uint32 lowGUID, uint8 type);
781+
782+ void AnticheatGlobalCommand(ChatHandler* handler);
783+ void AnticheatDeleteCommand(uint32 guid);
784+
785+ void ResetDailyReportStates();
786+ private:
787+ void SpeedHackDetection(Player* player, MovementInfo movementInfo);
788+ void FlyHackDetection(Player* player, MovementInfo movementInfo);
789+ void WalkOnWaterHackDetection(Player* player, MovementInfo movementInfo);
790+ void JumpHackDetection(Player* player, MovementInfo movementInfo,uint32 opcode);
791+ void TeleportPlaneHackDetection(Player* player, MovementInfo);
792+ void ClimbHackDetection(Player* player,MovementInfo movementInfo,uint32 opcode);
793+
794+ void BuildReport(Player* player,uint8 reportType);
795+
796+ bool MustCheckTempReports(uint8 type);
797+
798+ AnticheatPlayersDataMap m_Players; ///< Player data
799+};
800+
801+#define sAnticheatMgr AnticheatMgr::instance()
802+
803+#endif
804diff --git a/src/server/game/Anticheat/AnticheatScripts.cpp b/src/server/game/Anticheat/AnticheatScripts.cpp
805new file mode 100644
806index 0000000000..538db2c8eb
807--- /dev/null
808+++ b/src/server/game/Anticheat/AnticheatScripts.cpp
809@@ -0,0 +1,31 @@
810+/*
811+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
812+ *
813+ * This program is free software; you can redistribute it and/or modify it
814+ * under the terms of the GNU General Public License as published by the
815+ * Free Software Foundation; either version 2 of the License, or (at your
816+ * option) any later version.
817+ *
818+ * This program is distributed in the hope that it will be useful, but WITHOUT
819+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
820+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
821+ * more details.
822+ *
823+ * You should have received a copy of the GNU General Public License along
824+ * with this program. If not, see <http://www.gnu.org/licenses/>.
825+ */
826+
827+#include "AnticheatScripts.h"
828+#include "AnticheatMgr.h"
829+
830+AnticheatScripts::AnticheatScripts(): PlayerScript("AnticheatScripts") {}
831+
832+void AnticheatScripts::OnLogout(Player* player)
833+{
834+ sAnticheatMgr->HandlePlayerLogout(player);
835+}
836+
837+void AnticheatScripts::OnLogin(Player* player,bool)
838+{
839+ sAnticheatMgr->HandlePlayerLogin(player);
840+}
841diff --git a/src/server/game/Anticheat/AnticheatScripts.h b/src/server/game/Anticheat/AnticheatScripts.h
842new file mode 100644
843index 0000000000..1e6aa764db
844--- /dev/null
845+++ b/src/server/game/Anticheat/AnticheatScripts.h
846@@ -0,0 +1,32 @@
847+/*
848+ * Copyright (C) 2008-2018 TrinityCore <https://www.trinitycore.org/>
849+ *
850+ * This program is free software; you can redistribute it and/or modify it
851+ * under the terms of the GNU General Public License as published by the
852+ * Free Software Foundation; either version 2 of the License, or (at your
853+ * option) any later version.
854+ *
855+ * This program is distributed in the hope that it will be useful, but WITHOUT
856+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
857+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
858+ * more details.
859+ *
860+ * You should have received a copy of the GNU General Public License along
861+ * with this program. If not, see <http://www.gnu.org/licenses/>.
862+ */
863+
864+#ifndef SC_ACSCRIPTS_H
865+#define SC_ACSCRIPTS_H
866+
867+#include "ScriptMgr.h"
868+
869+class AnticheatScripts: public PlayerScript
870+{
871+ public:
872+ AnticheatScripts();
873+
874+ void OnLogout(Player* player);
875+ void OnLogin(Player* player,bool);
876+};
877+
878+#endif
879diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
880index 4605960fff..2eefc303dd 100644
881--- a/src/server/game/Entities/Player/Player.cpp
882+++ b/src/server/game/Entities/Player/Player.cpp
883@@ -23,6 +23,7 @@
884 // 5
885 // 6
886 // 7
887+#include "AnticheatMgr.h"
888 // 8
889 // 9
890 // 10
891@@ -19407,6 +19408,12 @@ void Player::SaveToDB(bool create /*=false*/)
892
893 CharacterDatabase.CommitTransaction(trans);
894
895+ // we save the data here to prevent spamming
896+ sAnticheatMgr->SavePlayerData(this);
897+
898+ // in this way we prevent to spam the db by each report made!
899+ // sAnticheatMgr->SavePlayerData(this);
900+
901 // save pet (hunter pet level and experience and all type pets health/mana).
902 if (Pet* pet = GetPet())
903 pet->SavePetToDB(PET_SAVE_AS_CURRENT);
904diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
905index 5f641d6951..be54f3a53f 100644
906--- a/src/server/game/Handlers/MovementHandler.cpp
907+++ b/src/server/game/Handlers/MovementHandler.cpp
908@@ -16,6 +16,7 @@
909 * with this program. If not, see <http://www.gnu.org/licenses/>.
910 */
911
912+#include "AnticheatMgr.h"
913 #include "Common.h"
914 #include "WorldPacket.h"
915 #include "WorldSession.h"
916@@ -360,6 +361,9 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
917 plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ()));
918 }
919
920+ if (plrMover)
921+ sAnticheatMgr->StartHackDetection(plrMover, movementInfo, opcode);
922+
923 uint32 mstime = GameTime::GetGameTimeMS();
924 /*----------------------*/
925 if (m_clientTimeDelay == 0)
926diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
927index 542b7e7d51..b296fd0a12 100644
928--- a/src/server/game/World/World.cpp
929+++ b/src/server/game/World/World.cpp
930@@ -29,6 +29,7 @@
931 #include "AuctionHouseMgr.h"
932 #include "BattlefieldMgr.h"
933 #include "BattlegroundMgr.h"
934+#include "AnticheatMgr.h"
935 #include "CalendarMgr.h"
936 #include "Channel.h"
937 #include "CharacterCache.h"
938@@ -1424,6 +1425,11 @@ void World::LoadConfigSettings(bool reload)
939 m_bool_configs[CONFIG_PDUMP_NO_OVERWRITE] = sConfigMgr->GetBoolDefault("PlayerDump.DisallowOverwrite", true);
940 m_bool_configs[CONFIG_UI_QUESTLEVELS_IN_DIALOGS] = sConfigMgr->GetBoolDefault("UI.ShowQuestLevelsInDialogs", false);
941
942+ m_bool_configs[CONFIG_ANTICHEAT_ENABLE] = sConfigMgr->GetBoolDefault("Anticheat.Enable", true);
943+ m_int_configs[CONFIG_ANTICHEAT_REPORTS_INGAME_NOTIFICATION] = sConfigMgr->GetIntDefault("Anticheat.ReportsForIngameWarnings", 70);
944+ m_int_configs[CONFIG_ANTICHEAT_DETECTIONS_ENABLED] = sConfigMgr->GetIntDefault("Anticheat.DetectionsEnabled",31);
945+ m_int_configs[CONFIG_ANTICHEAT_MAX_REPORTS_FOR_DAILY_REPORT] = sConfigMgr->GetIntDefault("Anticheat.MaxReportsForDailyReport",70);
946+
947 // Wintergrasp battlefield
948 m_bool_configs[CONFIG_WINTERGRASP_ENABLE] = sConfigMgr->GetBoolDefault("Wintergrasp.Enable", false);
949 m_int_configs[CONFIG_WINTERGRASP_PLR_MAX] = sConfigMgr->GetIntDefault("Wintergrasp.PlayerMax", 100);
950@@ -3201,6 +3207,8 @@ void World::ResetDailyQuests()
951
952 // change available dailies
953 sPoolMgr->ChangeDailyQuests();
954+
955+ sAnticheatMgr->ResetDailyReportStates();
956 }
957
958 void World::LoadDBAllowedSecurityLevel()
959diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
960index 6d0bc44205..de5609df5d 100644
961--- a/src/server/game/World/World.h
962+++ b/src/server/game/World/World.h
963@@ -149,6 +149,7 @@ enum WorldBoolConfigs
964 CONFIG_DELETE_CHARACTER_TICKET_TRACE,
965 CONFIG_DBC_ENFORCE_ITEM_ATTRIBUTES,
966 CONFIG_PRESERVE_CUSTOM_CHANNELS,
967+ CONFIG_ANTICHEAT_ENABLE,
968 CONFIG_PDUMP_NO_PATHS,
969 CONFIG_PDUMP_NO_OVERWRITE,
970 CONFIG_QUEST_IGNORE_AUTO_ACCEPT,
971@@ -346,7 +347,10 @@ enum WorldIntConfigs
972 CONFIG_PRESERVE_CUSTOM_CHANNEL_DURATION,
973 CONFIG_PERSISTENT_CHARACTER_CLEAN_FLAGS,
974 CONFIG_LFG_OPTIONSMASK,
975+ CONFIG_ANTICHEAT_REPORTS_INGAME_NOTIFICATION,
976+ CONFIG_ANTICHEAT_MAX_REPORTS_FOR_DAILY_REPORT,
977 CONFIG_MAX_INSTANCES_PER_HOUR,
978+ CONFIG_ANTICHEAT_DETECTIONS_ENABLED,
979 CONFIG_WARDEN_CLIENT_RESPONSE_DELAY,
980 CONFIG_WARDEN_CLIENT_CHECK_HOLDOFF,
981 CONFIG_WARDEN_CLIENT_FAIL_ACTION,
982diff --git a/src/server/scripts/Commands/cs_anticheat.cpp b/src/server/scripts/Commands/cs_anticheat.cpp
983new file mode 100644
984index 0000000000..3a1b076bd7
985--- /dev/null
986+++ b/src/server/scripts/Commands/cs_anticheat.cpp
987@@ -0,0 +1,265 @@
988+/*
989+ * This program is free software; you can redistribute it and/or modify it
990+ * under the terms of the GNU General Public License as published by the
991+ * Free Software Foundation; either version 2 of the License, or (at your
992+ * option) any later version.
993+ *
994+ * This program is distributed in the hope that it will be useful, but WITHOUT
995+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
996+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
997+ * more details.
998+ *
999+ * You should have received a copy of the GNU General Public License along
1000+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1001+ */
1002+
1003+#include "Language.h"
1004+#include "ScriptMgr.h"
1005+#include "ObjectMgr.h"
1006+#include "ObjectAccessor.h"
1007+#include "Chat.h"
1008+#include "AnticheatMgr.h"
1009+#include "Player.h"
1010+#include "World.h"
1011+#include "WorldSession.h"
1012+
1013+class anticheat_commandscript : public CommandScript
1014+{
1015+public:
1016+ anticheat_commandscript() : CommandScript("anticheat_commandscript") { }
1017+
1018+ std::vector<ChatCommand> GetCommands() const override
1019+ {
1020+ static std::vector<ChatCommand> anticheatCommandTable =
1021+ {
1022+ { "global", SEC_GAMEMASTER, true, &HandleAntiCheatGlobalCommand, "" },
1023+ { "player", SEC_GAMEMASTER, true, &HandleAntiCheatPlayerCommand, "" },
1024+ { "delete", SEC_ADMINISTRATOR, true, &HandleAntiCheatDeleteCommand, "" },
1025+ { "handle", SEC_ADMINISTRATOR, true, &HandleAntiCheatHandleCommand, "" },
1026+ { "jail", SEC_GAMEMASTER, true, &HandleAnticheatJailCommand, "" },
1027+ { "warn", SEC_GAMEMASTER, true, &HandleAnticheatWarnCommand, "" },
1028+ };
1029+
1030+ static std::vector<ChatCommand> commandTable =
1031+ {
1032+ { "anticheat", SEC_GAMEMASTER, true, NULL, "", anticheatCommandTable},
1033+ };
1034+
1035+ return commandTable;
1036+ }
1037+
1038+ static bool HandleAnticheatWarnCommand(ChatHandler* handler, const char* args)
1039+ {
1040+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
1041+ return false;
1042+
1043+ Player* pTarget = NULL;
1044+
1045+ std::string strCommand;
1046+
1047+ char* command = strtok((char*)args, " ");
1048+
1049+ if (command)
1050+ {
1051+ strCommand = command;
1052+ normalizePlayerName(strCommand);
1053+
1054+ pTarget = ObjectAccessor::FindPlayerByName(strCommand.c_str()); // get player by name
1055+ }else
1056+ pTarget = handler->getSelectedPlayer();
1057+
1058+ if (!pTarget)
1059+ return false;
1060+
1061+ WorldPacket data;
1062+
1063+ // need copy to prevent corruption by strtok call in LineFromMessage original string
1064+ char* buf = strdup("The anticheat system has reported several times that you may be cheating. You will be monitored to confirm if this is accurate.");
1065+ char* pos = buf;
1066+
1067+ while (char* line = handler->LineFromMessage(pos))
1068+ {
1069+ handler->BuildChatPacket(data, CHAT_MSG_SYSTEM, LANG_UNIVERSAL, NULL, NULL, line);
1070+ pTarget->GetSession()->SendPacket(&data);
1071+ }
1072+
1073+ free(buf);
1074+ return true;
1075+ }
1076+
1077+ static bool HandleAnticheatJailCommand(ChatHandler* handler, const char* args)
1078+ {
1079+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
1080+ return false;
1081+
1082+ Player* pTarget = NULL;
1083+
1084+ std::string strCommand;
1085+
1086+ char* command = strtok((char*)args, " ");
1087+
1088+ if (command)
1089+ {
1090+ strCommand = command;
1091+ normalizePlayerName(strCommand);
1092+
1093+ pTarget = ObjectAccessor::FindPlayerByName(strCommand.c_str()); // get player by name
1094+ }else
1095+ pTarget = handler->getSelectedPlayer();
1096+
1097+ if (!pTarget)
1098+ {
1099+ handler->SendSysMessage(LANG_PLAYER_NOT_FOUND);
1100+ handler->SetSentErrorMessage(true);
1101+ return false;
1102+ }
1103+
1104+ if (pTarget == handler->GetSession()->GetPlayer())
1105+ return false;
1106+
1107+ // teleport both to jail.
1108+ pTarget->TeleportTo(1,16226.5f,16403.6f,-64.5f,3.2f);
1109+ handler->GetSession()->GetPlayer()->TeleportTo(1,16226.5f,16403.6f,-64.5f,3.2f);
1110+
1111+
1112+
1113+ // the player should be already there, but no :(
1114+ // pTarget->GetPosition(&loc);
1115+
1116+ WorldLocation loc;
1117+ loc = WorldLocation(1, 16226.5f, 16403.6f, -64.5f, 3.2f);
1118+ pTarget->SetHomebind(loc, 876);
1119+
1120+
1121+
1122+ pTarget->SetHomebind(loc,876);
1123+ return true;
1124+ }
1125+
1126+ static bool HandleAntiCheatDeleteCommand(ChatHandler* handler, const char* args)
1127+ {
1128+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
1129+ return false;
1130+
1131+ std::string strCommand;
1132+
1133+ char* command = strtok((char*)args, " "); // get entered name
1134+
1135+ if (!command)
1136+ return true;
1137+
1138+ strCommand = command;
1139+
1140+ if (strCommand.compare("deleteall") == 0)
1141+ sAnticheatMgr->AnticheatDeleteCommand(0);
1142+ else
1143+ {
1144+ normalizePlayerName(strCommand);
1145+ Player* player = ObjectAccessor::FindPlayerByName(strCommand.c_str()); // get player by name
1146+ if (!player)
1147+ handler->PSendSysMessage("Player doesn't exist");
1148+ else
1149+ sAnticheatMgr->AnticheatDeleteCommand(player->GetGUID().GetCounter());
1150+ }
1151+
1152+ return true;
1153+ }
1154+
1155+ static bool HandleAntiCheatPlayerCommand(ChatHandler* handler, const char* args)
1156+ {
1157+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
1158+ return false;
1159+
1160+ std::string strCommand;
1161+
1162+ char* command = strtok((char*)args, " ");
1163+
1164+ uint32 guid = 0;
1165+ Player* player = NULL;
1166+
1167+ if (command)
1168+ {
1169+ strCommand = command;
1170+
1171+ normalizePlayerName(strCommand);
1172+ player = ObjectAccessor::FindPlayerByName(strCommand.c_str()); // get player by name
1173+
1174+ if (player)
1175+ guid = player->GetGUID().GetCounter();
1176+ }else
1177+ {
1178+ player = handler->getSelectedPlayer();
1179+ if (player)
1180+ guid = player->GetGUID().GetCounter();
1181+ }
1182+
1183+ if (!guid)
1184+ {
1185+ handler->PSendSysMessage("There is no player.");
1186+ return true;
1187+ }
1188+
1189+ float average = sAnticheatMgr->GetAverage(guid);
1190+ uint32 total_reports = sAnticheatMgr->GetTotalReports(guid);
1191+ uint32 speed_reports = sAnticheatMgr->GetTypeReports(guid,0);
1192+ uint32 fly_reports = sAnticheatMgr->GetTypeReports(guid,1);
1193+ uint32 jump_reports = sAnticheatMgr->GetTypeReports(guid,3);
1194+ uint32 waterwalk_reports = sAnticheatMgr->GetTypeReports(guid,2);
1195+ uint32 teleportplane_reports = sAnticheatMgr->GetTypeReports(guid,4);
1196+ uint32 climb_reports = sAnticheatMgr->GetTypeReports(guid,5);
1197+
1198+ handler->PSendSysMessage("Information about player %s",player->GetName().c_str());
1199+ handler->PSendSysMessage("Average: %f || Total Reports: %u ",average,total_reports);
1200+ handler->PSendSysMessage("Speed Reports: %u || Fly Reports: %u || Jump Reports: %u ",speed_reports,fly_reports,jump_reports);
1201+ handler->PSendSysMessage("Walk On Water Reports: %u || Teleport To Plane Reports: %u",waterwalk_reports,teleportplane_reports);
1202+ handler->PSendSysMessage("Climb Reports: %u", climb_reports);
1203+
1204+ return true;
1205+ }
1206+
1207+ static bool HandleAntiCheatHandleCommand(ChatHandler* handler, const char* args)
1208+ {
1209+ std::string strCommand;
1210+
1211+ char* command = strtok((char*)args, " ");
1212+
1213+ if (!command)
1214+ return true;
1215+
1216+ if (!handler->GetSession()->GetPlayer())
1217+ return true;
1218+
1219+ strCommand = command;
1220+
1221+ if (strCommand.compare("on") == 0)
1222+ {
1223+ sWorld->setBoolConfig(CONFIG_ANTICHEAT_ENABLE,true);
1224+ handler->SendSysMessage("The Anticheat System is now: Enabled!");
1225+ }
1226+ else if (strCommand.compare("off") == 0)
1227+ {
1228+ sWorld->setBoolConfig(CONFIG_ANTICHEAT_ENABLE,false);
1229+ handler->SendSysMessage("The Anticheat System is now: Disabled!");
1230+ }
1231+
1232+ return true;
1233+ }
1234+
1235+ static bool HandleAntiCheatGlobalCommand(ChatHandler* handler, const char* /* args */)
1236+ {
1237+ if (!sWorld->getBoolConfig(CONFIG_ANTICHEAT_ENABLE))
1238+ {
1239+ handler->PSendSysMessage("The Anticheat System is disabled.");
1240+ return true;
1241+ }
1242+
1243+ sAnticheatMgr->AnticheatGlobalCommand(handler);
1244+
1245+ return true;
1246+ }
1247+};
1248+
1249+void AddSC_anticheat_commandscript()
1250+{
1251+ new anticheat_commandscript();
1252+}
1253diff --git a/src/server/scripts/Commands/cs_script_loader.cpp b/src/server/scripts/Commands/cs_script_loader.cpp
1254index 35d5b7c792..c4283fb815 100644
1255--- a/src/server/scripts/Commands/cs_script_loader.cpp
1256+++ b/src/server/scripts/Commands/cs_script_loader.cpp
1257@@ -15,10 +15,15 @@
1258 * with this program. If not, see <http://www.gnu.org/licenses/>.
1259 */
1260
1261+#include "ScriptLoader.h"
1262+#include "World.h"
1263+#include "AnticheatMgr.h"
1264+
1265 // This is where scripts' loading functions should be declared:
1266 void AddSC_account_commandscript();
1267 void AddSC_achievement_commandscript();
1268 void AddSC_ahbot_commandscript();
1269+void AddSC_anticheat_commandscript();
1270 void AddSC_arena_commandscript();
1271 void AddSC_ban_commandscript();
1272 void AddSC_bf_commandscript();
1273@@ -64,6 +69,7 @@ void AddCommandsScripts()
1274 AddSC_account_commandscript();
1275 AddSC_achievement_commandscript();
1276 AddSC_ahbot_commandscript();
1277+ AddSC_anticheat_commandscript();
1278 AddSC_arena_commandscript();
1279 AddSC_ban_commandscript();
1280 AddSC_bf_commandscript();
1281@@ -101,4 +107,5 @@ void AddCommandsScripts()
1282 AddSC_ticket_commandscript();
1283 AddSC_titles_commandscript();
1284 AddSC_wp_commandscript();
1285+ sAnticheatMgr->StartScripts();
1286 }
1287diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist
1288index d645eb55ac..181a7c502d 100644
1289--- a/src/server/worldserver/worldserver.conf.dist
1290+++ b/src/server/worldserver/worldserver.conf.dist
1291@@ -3192,6 +3192,40 @@ LevelReq.Auction = 1
1292 LevelReq.Mail = 1
1293
1294 #
1295+# Anticheat.Enable
1296+# Description: Enables or disables the Anticheat System functionality
1297+# Default: 1 - (Enabled)
1298+# 0 - (Disabled)
1299+
1300+Anticheat.Enable = 1
1301+
1302+# Anticheat.ReportsForIngameWarnings
1303+# Description: How many reports the player must have to notify to GameMasters ingame when he generates a new report.
1304+# Default: 70
1305+
1306+Anticheat.ReportsForIngameWarnings = 70
1307+
1308+# Anticheat.DetectionsEnabled
1309+# Description: It represents which detections are enabled.
1310+#
1311+# SPEED_HACK_DETECTION = 1
1312+# FLY_HACK_DETECTION = 2
1313+# WALK_WATER_HACK_DETECTION = 4
1314+# JUMP_HACK_DETECTION = 8
1315+# TELEPORT_PLANE_HACK_DETECTION = 16
1316+# CLIMB_HACK_DETECTION = 32
1317+#
1318+# Default: 31
1319+
1320+Anticheat.DetectionsEnabled = 31
1321+
1322+# Anticheat.MaxReportsForDailyReport
1323+# Description: How many reports must the player have to make a report that it is in DB for a day (not only during the player's session).
1324+# Default: 70
1325+
1326+Anticheat.MaxReportsForDailyReport = 70
1327+
1328+#
1329 # PlayerDump.DisallowPaths
1330 # Description: Disallow using paths in PlayerDump output files
1331 # Default: 1