All pastes #1740153 Raw Edit

Anticheat for TC2

public text v1 · immutable
#1740153 ·published 2010-01-06 14:05 UTC
rendered paste body
diff --git a/src/game/MovementHandler.cpp b/src/game/MovementHandler.cpp
--- a/src/game/MovementHandler.cpp
+++ b/src/game/MovementHandler.cpp
@@ -33,6 +33,12 @@
 #include "WaypointMovementGenerator.h"
 #include "InstanceSaveMgr.h"
 #include "ObjectMgr.h"
+#include "World.h"
+
+/*Movement anticheat DEBUG defines */
+//#define MOVEMENT_ANTICHEAT_DEBUG true
+//#define MOVEMENT_ANTICHEAT_DEBUG_FULL true
+/*end Movement anticheate defines*/
 
 void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ )
 {
@@ -56,6 +62,10 @@
         return;
     }
 
+	//movement anticheat
+    GetPlayer()->m_anti_JustTeleported = 1;
+    //end movement anticheat
+
     // get the destination map entry, not the current one, this will fix homebind and reset greeting
     MapEntry const* mEntry = sMapStore.LookupEntry(loc.GetMapId());
     InstanceTemplate const* mInstance = objmgr.GetInstanceTemplate(loc.GetMapId());
@@ -239,8 +249,14 @@
     assert(mover != NULL);                                  // there must always be a mover
 
     Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL;
+	Vehicle *vehMover = mover->GetVehicleKit();
+		if (vehMover)			
+			if (mover->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
+				if (Unit *charmer = mover->GetCharmer())
+					if (charmer->GetTypeId() == TYPEID_PLAYER)
+						plMover = (Player*)charmer;
 
     // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck
     if (plMover && plMover->IsBeingTeleported())
     {
         recv_data.rpos(recv_data.wpos());                   // prevent warnings spam
@@ -242,8 +258,11 @@
 
     // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck
     if (plMover && plMover->IsBeingTeleported())
     {
         recv_data.rpos(recv_data.wpos());                   // prevent warnings spam
+		// movement anticheat
+        plMover->m_anti_JustTeleported = 1;
+        // end movement anticheat
         return;
     }
 
@@ -277,7 +296,7 @@
     {
         // transports size limited
         // (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
-        if (movementInfo.t_x > 50 || movementInfo.t_y > 50 || movementInfo.t_z > 50)
+        if( movementInfo.t_x > 60 || movementInfo.t_y > 60 || movementInfo.t_x < -60 ||  movementInfo.t_y < -60 )
         {
             recv_data.rpos(recv_data.wpos());                   // prevent warnings spam
             return;
@@ -290,18 +309,31 @@
             return;
         }
 
-        // if we boarded a transport, add us to it
-        if (plMover && !plMover->GetTransport())
-        {
-            // elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list
-            for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
-            {
-                if ((*iter)->GetGUID() == movementInfo.t_guid)
-                {
-                    plMover->m_transport = (*iter);
-                    (*iter)->AddPassenger(plMover);
-                    break;
-                }
-            }
-        }
+		if (plMover && plMover->m_anti_TransportGUID == 0 && (movementInfo.t_guid !=0))
+		{
+			// if we boarded a transport, add us to it
+			if (plMover && !plMover->GetTransport())
+			{
+				// elevators also cause the client to send MOVEMENTFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list
+				for (MapManager::TransportSet::const_iterator iter = MapManager::Instance().m_Transports.begin(); iter != MapManager::Instance().m_Transports.end(); ++iter)
+				{
+					if ((*iter)->GetGUID() == movementInfo.t_guid)
+					{
+						plMover->m_transport = (*iter);
+						(*iter)->AddPassenger(plMover);
+						break;
+					}
+				}
+			}
+		}
+			//movement anticheat;
+            //Correct finding GO guid in DB (thanks to GriffonHeart)
+		
+		if (plMover)
+		{
+            GameObject *obj = HashMapHolder<GameObject>::Find(movementInfo.t_guid);
+            if(obj)
+                plMover->m_anti_TransportGUID = obj->GetDBTableGUIDLow();
+            else
+				plMover->m_anti_TransportGUID = GUID_LOPART(movementInfo.t_guid);
 
@@ -307,4 +339,9 @@
 
-        if (!mover->GetTransport() && !mover->GetVehicle())
+		}
+			
+			
+            // end movement anticheat
+
+        if ( (!plMover && !mover->GetTransport() && !mover->GetVehicle()) || (plMover && !plMover->GetTransport() && !plMover->GetVehicle()) )
             movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
     }
@@ -309,16 +346,20 @@
             movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
     }
-    else if (plMover && plMover->GetTransport())                // if we were on a transport, leave
-    {
-        plMover->m_transport->RemovePassenger(plMover);
-        plMover->m_transport = NULL;
-        movementInfo.t_x = 0.0f;
-        movementInfo.t_y = 0.0f;
-        movementInfo.t_z = 0.0f;
-        movementInfo.t_o = 0.0f;
-        movementInfo.t_time = 0;
-        movementInfo.t_seat = -1;
-    }
+	else if (plMover && plMover->m_anti_TransportGUID != 0)
+	{
+		if (plMover && plMover->GetTransport())                // if we were on a transport, leave
+		{
+			plMover->m_transport->RemovePassenger(plMover);
+			plMover->m_transport = NULL;
+		}
+			movementInfo.t_x = 0.0f;
+			movementInfo.t_y = 0.0f;
+			movementInfo.t_z = 0.0f;
+			movementInfo.t_o = 0.0f;
+			movementInfo.t_time = 0;
+			movementInfo.t_seat = -1;
+			plMover->m_anti_TransportGUID = 0;		
+	}
 
     // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
     if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight())
@@ -322,4 +363,9 @@
 
     // fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
     if (opcode == MSG_MOVE_FALL_LAND && plMover && !plMover->isInFlight())
+	{
+        //movement anticheat
+        plMover->m_anti_JustJumped = 0;
+        plMover->m_anti_JumpBaseZ = 0;
+        //end movement anticheat
         plMover->HandleFall(movementInfo);
@@ -325,4 +371,5 @@
         plMover->HandleFall(movementInfo);
+	}
 
     if (plMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plMover->IsInWater())
     {
@@ -331,4 +378,22 @@
     }
 
     /*----------------------*/
+	//---- anti-cheat features -->>>
+	#define FROSTBROOD_VANQUISHER 28670
+    bool check_passed = true;
+    #ifdef MOVEMENT_ANTICHEAT_DEBUG_FULL
+    if (plMover){
+        sLog.outBasic("JAH-%s > client-time:%d fall-time:%d | xyzo: %f,%f,%fo(%f) flags[%X] opcode[%s]| transport (xyzo): %f,%f,%fo(%f)",
+                    plMover->GetName(),movementInfo.time,movementInfo.fallTime,movementInfo.x,movementInfo.y,movementInfo.z,movementInfo.o,
+                    movementInfo.flags, LookupOpcodeName(opcode),movementInfo.t_x,movementInfo.t_y,movementInfo.t_z,movementInfo.t_o);
+        sLog.outBasic("JAH-%s Transport > server GUID: %d |  client GUID: (lo)%d - (hi)%d",
+                    plMover->GetName(),plMover->m_anti_TransportGUID, GUID_LOPART(movementInfo.t_guid), GUID_HIPART(movementInfo.t_guid));
+    } else {
+        sLog.outBasic("JAH > client-time:%d fall-time:%d | xyzo: %f,%f,%fo(%f) flags[%X] opcode[%s]| transport (xyzo): %f,%f,%fo(%f)",
+                    movementInfo.time,movementInfo.fallTime,movementInfo.x,movementInfo.y,movementInfo.z,movementInfo.o,
+                    movementInfo.flags, LookupOpcodeName(opcode),movementInfo.t_x,movementInfo.t_y,movementInfo.t_z,movementInfo.t_o);
+        sLog.outBasic("JAH Transport > server GUID:  |  client GUID: (lo)%d - (hi)%d",
+                    GUID_LOPART(movementInfo.t_guid), GUID_HIPART(movementInfo.t_guid));
+    }
+    #endif
 
@@ -334,2 +399,338 @@
 
+	if ( plMover && World::GetEnableMvAnticheat() && !plMover->HasAuraType(SPELL_AURA_MOD_POSSESS) )
+    {
+        //calc time deltas
+        int32 cClientTimeDelta = 1500;
+        if (plMover->m_anti_LastClientTime !=0){
+            cClientTimeDelta = movementInfo.time - plMover->m_anti_LastClientTime;
+            plMover->m_anti_DeltaClientTime += cClientTimeDelta;
+            plMover->m_anti_LastClientTime = movementInfo.time;
+        } else {
+            plMover->m_anti_LastClientTime = movementInfo.time;
+        }
+
+        uint32 cServerTime=getMSTime();
+        uint32 cServerTimeDelta = 1500;
+        if (plMover->m_anti_LastServerTime != 0){
+            cServerTimeDelta = cServerTime - plMover->m_anti_LastServerTime;
+            plMover->m_anti_DeltaServerTime += cServerTimeDelta;
+            plMover->m_anti_LastServerTime = cServerTime;
+        } else {
+            plMover->m_anti_LastServerTime = cServerTime;
+        }
+
+        //resync times on client login (first 15 sec for heavy areas)
+        if (plMover->m_anti_DeltaServerTime < 15000 && plMover->m_anti_DeltaClientTime < 15000)
+            plMover->m_anti_DeltaClientTime = plMover->m_anti_DeltaServerTime;
+
+        int32 sync_time = plMover->m_anti_DeltaClientTime - plMover->m_anti_DeltaServerTime;
+
+        #ifdef MOVEMENT_ANTICHEAT_DEBUG_FULL
+        sLog.outBasic("JAH-%s Time > cClientTimeDelta: %d, cServerTime: %d || deltaC: %d - deltaS: %d || SyncTime: %d",
+                        plMover->GetName(),cClientTimeDelta, cServerTime,
+                        plMover->m_anti_DeltaClientTime, plMover->m_anti_DeltaServerTime, sync_time);
+        #endif
+
+        //mistiming checks
+        int32 gmd = World::GetMistimingDelta();
+        if (sync_time > gmd || sync_time < -gmd){
+            cClientTimeDelta = cServerTimeDelta;
+            plMover->m_anti_MistimingCount++;
+
+            sLog.outError("JAH-%s, mistiming exception. #:%d, mistiming: %dms ",
+                            plMover->GetName(), plMover->m_anti_MistimingCount, sync_time);
+
+            if (plMover->m_anti_MistimingCount > World::GetMistimingAlarms())
+                return;
+
+			check_passed = false;
+			if (vehMover)
+				vehMover->Dismiss();
+        }
+        // end mistiming checks
+
+
+        uint32 curDest = plMover->m_taxi.GetTaxiDestination(); //check taxi flight
+        if ( (plMover->m_anti_TransportGUID == 0) && !curDest )
+        {
+            UnitMoveType move_type;
+
+            // calculating section ---------------------
+            //current speed
+            if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_FLIGHT_BACK : MOVE_FLIGHT;
+            else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_SWIM_BACK : MOVE_SWIM;
+            else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK;
+            //hmm... in first time after login player has MOVE_SWIMBACK instead MOVE_WALKBACK
+            else move_type = movementInfo.flags & MOVEMENTFLAG_BACKWARD ? MOVE_SWIM_BACK : MOVE_RUN;
+
+            float current_speed = plMover->GetSpeed(move_type);
+
+			uint32 vehicleEntry = 0;
+
+			if ( plMover->GetVehicle() )
+			{
+				vehicleEntry = plMover->GetVehicleCreatureBase()->GetEntry();
+				current_speed = plMover->GetVehicleBase()->GetSpeed(move_type);
+			}
+            // end current speed
+
+            // movement distance
+            float allowed_delta= 0;
+
+            float delta_x = plMover->GetPositionX() - movementInfo.x;
+            float delta_y = plMover->GetPositionY() - movementInfo.y;
+            float delta_z = plMover->GetPositionZ() - movementInfo.z;
+            float real_delta = delta_x * delta_x + delta_y * delta_y;
+            float tg_z = -99999; //tangens
+            // end movement distance
+
+            if ( cClientTimeDelta < 0 ) {cClientTimeDelta = 0;}
+            float time_delta = (cClientTimeDelta < 1500) ? (float)cClientTimeDelta/1000 : 1.5f; //normalize time - 1.5 second allowed for heavy loaded server
+
+            if ( !(movementInfo.flags & (MOVEMENTFLAG_FLYING | MOVEMENTFLAG_SWIMMING)) )
+              tg_z = (real_delta !=0) ? (delta_z*delta_z / real_delta) : -99999;
+
+            if ( current_speed < plMover->m_anti_Last_HSpeed )
+            {
+                allowed_delta = plMover->m_anti_Last_HSpeed;
+                if (plMover->m_anti_LastSpeedChangeTime == 0 )
+                    plMover->m_anti_LastSpeedChangeTime = movementInfo.time + (uint32)floor(((plMover->m_anti_Last_HSpeed / current_speed) * 1500)) + 100; //100ms above for random fluctuating =)))
+            } else {
+                allowed_delta = current_speed;
+            }
+			
+            allowed_delta = allowed_delta * time_delta;
+            allowed_delta = allowed_delta * allowed_delta + 2;
+            if ( tg_z > 2.2 )
+                allowed_delta = allowed_delta + (delta_z*delta_z)/2.37; // mountain fall allowed speed
+
+            if ( movementInfo.time>plMover->m_anti_LastSpeedChangeTime )
+            {
+                plMover->m_anti_Last_HSpeed = current_speed; // store current speed
+                plMover->m_anti_Last_VSpeed = -2.3f;
+                if (plMover->m_anti_LastSpeedChangeTime != 0) plMover->m_anti_LastSpeedChangeTime = 0;
+            }
+
+			if ( plMover->GetVehicle() )
+			{
+				allowed_delta = allowed_delta*1.1;
+			}
+            // end calculating section ---------------------
+
+            //AntiGravitation
+            float JumpHeight = plMover->m_anti_JumpBaseZ - movementInfo.z;
+            if ( (plMover->m_anti_JumpBaseZ != 0 )
+                    && !(movementInfo.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_FLY_MODE | MOVEMENTFLAG_FLYING))
+                    && (JumpHeight < plMover->m_anti_Last_VSpeed))
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, GraviJump exception. JumpHeight = %f, Allowed Veritcal Speed = %f",
+                                plMover->GetName(), JumpHeight, plMover->m_anti_Last_VSpeed);
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+ 
+            //multi jump checks
+            if (opcode == MSG_MOVE_JUMP && !plMover->IsInWater())
+            {
+                if (plMover->m_anti_JustJumped >= 1){
+                    check_passed = false; //don't process new jump packet
+					if (vehMover)
+					vehMover->Dismiss();
+                } else {
+                    plMover->m_anti_JustJumped += 1;
+                    plMover->m_anti_JumpBaseZ = movementInfo.z;
+                }
+            } else if (plMover->IsInWater()) {
+                 plMover->m_anti_JustJumped = 0;
+            }
+
+            //speed hack checks
+            if ( (real_delta > allowed_delta) )
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, speed exception | cDelta=%f aDelta=%f | cSpeed=%f lSpeed=%f deltaTime=%f",
+                                plMover->GetName(), real_delta, allowed_delta, current_speed, plMover->m_anti_Last_HSpeed,time_delta);
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+            //teleport hack checks
+            if ( (real_delta>4900.0f) && !(real_delta < allowed_delta) )
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, is teleport exception | cDelta=%f aDelta=%f | cSpeed=%f lSpeed=%f deltaToime=%f",
+                                plMover->GetName(),real_delta, allowed_delta, current_speed, plMover->m_anti_Last_HSpeed,time_delta);
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+
+            //mountian hack checks // 1.56f (delta_z < GetPlayer()->m_anti_Last_VSpeed))
+            if ((delta_z < plMover->m_anti_Last_VSpeed) && (plMover->m_anti_JustJumped == 0) && (tg_z > 2.37f))
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, mountain exception | tg_z=%f", plMover->GetName(),tg_z);
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+            //Fly hack checks
+            if (((movementInfo.flags & (MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLY_MODE | MOVEMENTFLAG_FLYING)) != 0)
+                  && !plMover->isGameMaster()
+				  && !(movementInfo.flags & (MOVEMENTFLAG_SWIMMING)) // allow X button in water
+                  && !(plMover->HasAuraType(SPELL_AURA_FLY) || plMover->HasAuraType(SPELL_AURA_MOD_INCREASE_VEHICLE_FLIGHT_SPEED)
+                    || plMover->HasAuraType(SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED) || plMover->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED)
+					|| plMover->HasAuraType(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS) || plMover->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK) || ( plMover->GetVehicle() && vehicleEntry == FROSTBROOD_VANQUISHER )) )
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, flight exception. {SPELL_AURA_FLY=[%X]} {SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED=[%X]} {SPELL_AURA_MOD_SPEED_FLIGHT=[%X]} {SPELL_AURA_MOD_FLIGHT_SPEED_ALWAYS=[%X]} {SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK=[%X]}",
+                   plMover->GetName(),
+                   plMover->HasAuraType(SPELL_AURA_FLY), plMover->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED),
+                   plMover->HasAuraType(SPELL_AURA_MOD_INCREASE_FLIGHT_SPEED), plMover->HasAuraType(SPELL_AURA_MOD_MOUNTED_FLIGHT_SPEED_ALWAYS),
+                   plMover->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_NOT_STACK));
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+            //Water-Walk checks
+            if (((movementInfo.flags & MOVEMENTFLAG_WATERWALKING) != 0)
+                  && !plMover->isGameMaster()
+                  && !(plMover->HasAuraType(SPELL_AURA_WATER_WALK) | plMover->HasAuraType(SPELL_AURA_GHOST)))
+            {
+                #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                sLog.outError("JAH-%s, water-walk exception. [%X]{SPELL_AURA_WATER_WALK=[%X]}",
+                                plMover->GetName(), movementInfo.flags, plMover->HasAuraType(SPELL_AURA_WATER_WALK));
+                #endif
+                check_passed = false;
+				if (vehMover)
+				vehMover->Dismiss();
+            }
+            //Teleport To Plane checks
+            if (movementInfo.z < 0.0001f && movementInfo.z > -0.0001f
+                && ((movementInfo.flags & (MOVEMENTFLAG_SWIMMING | MOVEMENTFLAG_CAN_FLY | MOVEMENTFLAG_FLY_MODE | MOVEMENTFLAG_FLYING)) == 0)
+                && !plMover->isGameMaster())
+            {
+                // Prevent using TeleportToPlan.
+                Map *map = plMover->GetMap();
+                if (map){
+                    float plane_z = map->GetHeight(movementInfo.x, movementInfo.y, MAX_HEIGHT) - movementInfo.z;
+                    plane_z = (plane_z < -500.0f) ? 0 : plane_z; //check holes in heigth map
+                    if(plane_z > 0.1f || plane_z < -0.1f)
+                    {
+                        plMover->m_anti_TeleToPlane_Count++;
+                        check_passed = false;
+						if (vehMover)
+						vehMover->Dismiss();
+                        #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                        sLog.outDebug("JAH-%s, teleport to plan exception. plane_z: %f ",
+                                        plMover->GetName(), plane_z);
+                        #endif
+                        if (plMover->m_anti_TeleToPlane_Count > World::GetTeleportToPlaneAlarms())
+                        {
+                            sLog.outError("JAH-%s, teleport to plan exception. Exception count: %d ",
+                                            plMover->GetName(), plMover->m_anti_TeleToPlane_Count);
+                            return;
+                        }
+                    }
+                }
+            } else {
+                if (plMover->m_anti_TeleToPlane_Count != 0)
+                    plMover->m_anti_TeleToPlane_Count = 0;
+            }
+        } else if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT) {
+            //antiwrap checks
+			if ( plMover->GetTransport() )
+            {
+                float trans_rad = movementInfo.t_x*movementInfo.t_x + movementInfo.t_y*movementInfo.t_y + movementInfo.t_z*movementInfo.t_z;
+                if (trans_rad > 3600.0f){
+                    check_passed = false;
+					if (vehMover)
+					vehMover->Dismiss();
+                    #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                    sLog.outError("JAH-%s, leave transport.", plMover->GetName());
+                    #endif
+                }
+            } else {
+                if (GameObjectData const* go_data = objmgr.GetGOData(plMover->m_anti_TransportGUID))
+                {
+                    float delta_gox = go_data->posX - movementInfo.x;
+                    float delta_goy = go_data->posY - movementInfo.y;
+                    float delta_goz = go_data->posZ - movementInfo.z;
+                    int mapid = go_data->mapid;
+                    #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                    sLog.outError("JAH-%s, transport movement. GO xyzo: %f,%f,%f",
+                                    plMover->GetName(), go_data->posX,go_data->posY,go_data->posZ);
+                    #endif
+                    if (plMover->GetMapId() != mapid){
+                        check_passed = false;
+						if (vehMover)
+						vehMover->Dismiss();
+                    } else if (mapid !=369) {
+                        float delta_go = delta_gox*delta_gox + delta_goy*delta_goy;
+                        if (delta_go > 3600.0f) {
+                            check_passed = false;
+							if (vehMover)
+							vehMover->Dismiss();
+                            #ifdef MOVEMENT_ANTICHEAT_DEBUG
+                            sLog.outError("JAH-%s, leave transport. GO xyzo: %f,%f,%f",
+                                            plMover->GetName(), go_data->posX,go_data->posY,go_data->posZ);
+                            #endif
+                        }
+                    }
+
+				} else if ( plMover->GetVehicle() )
+				{
+					if ( !plMover->GetVehicle()->GetVehicleInfo() )
+					{
+						#ifdef MOVEMENT_ANTICHEAT_DEBUG
+						sLog.outError("JAH-%s, undefined vehicle.", plMover->GetName());
+						#endif
+						check_passed = false;
+						if (vehMover)
+						vehMover->Dismiss();
+					}
+
+					#ifdef MOVEMENT_ANTICHEAT_DEBUG
+						sLog.outError("JAH-%s on vehicle %u", plMover->GetName(), plMover->GetVehicleCreatureBase()->GetEntry() );
+					#endif
+                }
+				else
+				{
+					#ifdef MOVEMENT_ANTICHEAT_DEBUG
+                    sLog.outError("JAH-%s, undefined transport.", plMover->GetName());
+                    #endif
+                    check_passed = false;
+					if (vehMover)
+					vehMover->Dismiss();
+				}
+            }
+            if (!check_passed){
+				if ( plMover->GetTransport() && !plMover->GetVehicle() )
+                    {
+                        plMover->m_transport->RemovePassenger(plMover);
+                        plMover->m_transport = NULL;
+						plMover->m_anti_TransportGUID = 0;
+                    }
+				else if ( plMover->GetVehicle() && !plMover->GetVehicle()->GetVehicleInfo() )
+				{
+					plMover->m_transport->RemovePassenger(plMover);
+                    plMover->m_transport = NULL;
+					plMover->GetVehicle()->Dismiss();
+					plMover->m_anti_TransportGUID = 0;
+				}
+                    movementInfo.t_x = 0.0f;
+                    movementInfo.t_y = 0.0f;
+                    movementInfo.t_z = 0.0f;
+                    movementInfo.t_o = 0.0f;
+                    movementInfo.t_time = 0;                    
+            }
+        }
+    }
     /* process position-change */
@@ -335,4 +736,6 @@
     /* process position-change */
+	if (check_passed)
+	{
     WorldPacket data(opcode, recv_data.size());
     movementInfo.time = getMSTime();
     movementInfo.guid = mover->GetGUID();
@@ -348,7 +751,7 @@
         return;
     }
 
-    if (plMover)                                            // nothing is charmed, or player charmed
+    if (plMover && !vehMover)                                            // nothing is charmed, or player charmed
     {
         plMover->SetPosition(movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
         plMover->UpdateFallInformationIfNeed(movementInfo, opcode);
@@ -383,8 +786,14 @@
                 plMover->RepopAtGraveyard();
             }
         }
+	//movement anticheat >>>
+        if (plMover->m_anti_AlarmCount > 0){
+            sLog.outError("JAH-%s produce %d anticheat alarms",plMover->GetName(),plMover->m_anti_AlarmCount);
+            plMover->m_anti_AlarmCount = 0;
+        }
+    // end movement anticheat
     }
     else                                                    // creature charmed
     {
         mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
 
@@ -386,14 +795,16 @@
     }
     else                                                    // creature charmed
     {
         mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.x, movementInfo.y, movementInfo.z, movementInfo.o);
 
-        /*if(mover->canFly())
-        {
-            bool flying = mover->IsFlying();
-            if(flying != ((mover->GetByteValue(UNIT_FIELD_BYTES_1, 3) & 0x02) ? true : false))
-                mover->SetFlying(flying);
-        }*/
+    }
+	} else if (plMover) {
+        plMover->m_anti_AlarmCount++;
+        WorldPacket data;
+        plMover->SetUnitMovementFlags(0);
+        plMover->SendTeleportAckMsg();
+        plMover->BuildHeartBeatMsg(&data);
+        plMover->SendMessageToSet(&data, true);
     }
 
     //sLog.outString("Receive Movement Packet %s:", opcodeTable[recv_data.GetOpcode()]);
@@ -475,7 +886,6 @@
         {
             sLog.outBasic("Player %s from account id %u kicked for incorrect speed (must be %f instead %f)",
                 _player->GetName(),_player->GetSession()->GetAccountId(),_player->GetSpeed(move_type), newspeed);
-            _player->GetSession()->KickPlayer();
         }
     }
 }
@@ -487,9 +897,7 @@
     uint64 guid;
     recv_data >> guid;
 
-    if(guid == GetPlayer()->m_mover->GetGUID())
-        return;
-
+    if(GetPlayer()->IsInWorld())
     if(Unit *mover = ObjectAccessor::GetUnit(*GetPlayer(), guid))
     {
         GetPlayer()->SetMover(mover);
@@ -625,6 +1033,18 @@
 
     MovementInfo movementInfo;
     ReadMovementInfo(recv_data, &movementInfo);
+	_player->m_movementInfo.flags = movementInfo.GetMovementFlags();
+
+	#ifdef MOVEMENT_ANTICHEAT_DEBUG
+    sLog.outBasic("%s CMSG_MOVE_KNOCK_BACK_ACK: tm:%d ftm:%d | %f,%f,%fo(%f) [%X]",GetPlayer()->GetName(),movementInfo.time,movementInfo.fallTime,movementInfo.x,movementInfo.y,movementInfo.z,movementInfo.o,movementInfo.flags);
+	sLog.outBasic("%s CMSG_MOVE_KNOCK_BACK_ACK additional: vspeed:%f, hspeed:%f",GetPlayer()->GetName(), movementInfo.j_zspeed, movementInfo.j_xyspeed);
+    #endif
+
+    _player->m_movementInfo = movementInfo;
+    _player->m_anti_Last_HSpeed = movementInfo.j_xyspeed;
+    _player->m_anti_Last_VSpeed = movementInfo.j_zspeed < 3.2f ? movementInfo.j_zspeed - 1.0f : 3.2f;
+	uint32 dt = (_player->m_anti_Last_VSpeed < 0) ? (int)(ceil(_player->m_anti_Last_VSpeed/-25)*1000) : (int)(ceil(_player->m_anti_Last_VSpeed/25)*1000);
+    _player->m_anti_LastSpeedChangeTime = movementInfo.time + dt + 1000;
 }
 
 void WorldSession::HandleMoveHoverAck( WorldPacket& recv_data )
diff --git a/src/game/ObjectMgr.cpp b/src/game/ObjectMgr.cpp
--- a/src/game/ObjectMgr.cpp
+++ b/src/game/ObjectMgr.cpp
@@ -5268,6 +5268,11 @@
         }
     }
 
+	//movement anticheat fix
+    if (dist > 3600)
+       id = 0;
+    //movement anticheat fix
+
     return id;
 }
 
@@ -8959,4 +8964,4 @@
 
     sLog.outString();
     sLog.outString( ">> Loaded %u creature base stats.", counter);
-}
+}
\ No newline at end of file
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -412,6 +412,31 @@
     rest_type=REST_TYPE_NO;
     ////////////////////Rest System/////////////////////
 
+	//movement anticheat
+    m_anti_LastClientTime  = 0;   //last movement client time
+    m_anti_LastServerTime  = 0;   //last movement server time
+    m_anti_DeltaClientTime = 0;   //client side session time
+    m_anti_DeltaServerTime = 0;   //server side session time
+    m_anti_MistimingCount  = 0;   //mistiming counts before kick
+ 
+    m_anti_LastSpeedChangeTime = 0;  //last speed change time
+    m_anti_BeginFallTime = 0;     //alternative falling begin time (obsolete)
+
+    m_anti_Last_HSpeed =  7.0f;   //horizontal speed, default RUN speed
+    m_anti_Last_VSpeed = -2.3f;   //vertical speed, default max jump height
+
+    m_anti_TransportGUID = 0;     //current transport GUID
+
+    m_anti_JustTeleported = 0;    //seted when player was teleported
+    m_anti_TeleToPlane_Count = 0; //Teleport To Plane alarm counter
+
+    m_anti_AlarmCount = 0;        //alarm counter
+
+    m_anti_JustJumped = 0;        //Jump already began, anti air jump check
+    m_anti_JumpBaseZ = 0;          //Z coord before jump (AntiGrav)
+    // << movement anticheat
+    /////////////////////////////////
+
     m_mailsLoaded = false;
     m_mailsUpdated = false;
     unReadMails = 0;
@@ -1676,6 +1701,10 @@
         return false;
     }
 
+	//movement anticheat
+    m_anti_JustTeleported = 1;
+    //end movement anticheat
+
     // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later)
     Pet* pet = GetPet();
 
@@ -1730,6 +1759,7 @@
 
     if (GetMapId() == mapid && !m_transport)
     {
+		m_anti_JumpBaseZ = 0;
         //lets reset far teleport flag if it wasn't reset during chained teleports
         SetSemaphoreTeleportFar(false);
         //setup delayed teleport flag
@@ -1880,6 +1910,7 @@
 
             m_teleport_dest = WorldLocation(mapid, final_x, final_y, final_z, final_o);
             SetFallInformation(0, final_z);
+			m_anti_JumpBaseZ = 0;
             // if the player is saved before worldportack (at logout for example)
             // this will be used instead of the current location in SaveToDB
 
diff --git a/src/game/Player.h b/src/game/Player.h
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -2482,6 +2482,31 @@
         float m_rest_bonus;
         RestType rest_type;
         ////////////////////Rest System/////////////////////
+
+        //movement anticheat
+        uint32 m_anti_LastClientTime;     //last movement client time
+        uint32 m_anti_LastServerTime;     //last movement server time
+        uint32 m_anti_DeltaClientTime;    //client side session time
+        uint32 m_anti_DeltaServerTime;    //server side session time
+        uint32 m_anti_MistimingCount;     //mistiming counts before kick
+
+        uint32 m_anti_LastSpeedChangeTime;//last speed change time
+        uint32 m_anti_BeginFallTime;      //alternative falling begin time (obsolete)
+
+        float  m_anti_Last_HSpeed;        //horizontal speed, default RUN speed
+        float  m_anti_Last_VSpeed;        //vertical speed, default max jump height
+
+        uint64 m_anti_TransportGUID;      //current transport GUID
+
+        uint32 m_anti_JustTeleported;     //seted when player was teleported
+        uint32 m_anti_TeleToPlane_Count;  //Teleport To Plane alarm counter
+
+        uint64 m_anti_AlarmCount;         //alarm counter
+
+        uint32 m_anti_JustJumped;         //Jump already began, anti air jump check
+        float  m_anti_JumpBaseZ;           //Z coord before jump
+        // << movement anticheat
+
         uint32 m_resetTalentsCost;
         time_t m_resetTalentsTime;
         uint32 m_usedTalentCount;
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp
--- a/src/game/SpellEffects.cpp
+++ b/src/game/SpellEffects.cpp
@@ -6748,7 +6748,10 @@
 
     float x, y, z;
     target->GetContactPoint(m_caster, x, y, z);
-    m_caster->GetMotionMaster()->MoveCharge(x, y, z);
+    if (m_caster->GetTypeId() == TYPEID_PLAYER)
+        ((Player*)m_caster)->SetPosition(x, y, z, m_caster->GetOrientation());
+    else
+        m_caster->GetMotionMaster()->MoveCharge(x, y, z);
 
     // not all charge effects used in negative spells
     if ( !IsPositiveSpell(m_spellInfo->Id) && m_caster->GetTypeId() == TYPEID_PLAYER)
diff --git a/src/game/World.cpp b/src/game/World.cpp
--- a/src/game/World.cpp
+++ b/src/game/World.cpp
@@ -88,6 +88,12 @@
 int32 World::m_visibility_notify_periodInInstances  = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
 int32 World::m_visibility_notify_periodInBGArenas   = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
 
+//movement anticheat
+bool World::m_EnableMvAnticheat = true;
+uint32 World::m_TeleportToPlaneAlarms = 50;
+uint32 World::m_MistimingAlarms = 20;
+uint32 World::m_MistimingDelta = 2000;
+
 /// World constructor
 World::World()
 {
@@ -592,6 +598,37 @@
         sLog.outError("DurabilityLossChance.Block (%f) must be >=0. Using 0.0 instead.",rate_values[RATE_DURABILITY_LOSS_BLOCK]);
         rate_values[RATE_DURABILITY_LOSS_BLOCK] = 0.0f;
     }
+
+	// movement anticheat
+    m_EnableMvAnticheat = sConfig.GetBoolDefault("Anticheat.Movement.Enable",true);
+    m_TeleportToPlaneAlarms = sConfig.GetIntDefault("Anticheat.Movement.TeleportToPlaneAlarms", 50);
+    if (m_TeleportToPlaneAlarms<20){
+        sLog.outError("Anticheat.Movement.TeleportToPlaneAlarms (%d) must be >=20. Using 20 instead.",m_TeleportToPlaneAlarms);
+        m_TeleportToPlaneAlarms = 20;
+    }
+    if (m_TeleportToPlaneAlarms>100){
+        sLog.outError("Anticheat.Movement.TeleportToPlaneAlarms (%d) must be <=100. Using 100 instead.",m_TeleportToPlaneAlarms);
+        m_TeleportToPlaneAlarms = 100;
+    }
+    m_MistimingDelta = sConfig.GetIntDefault("Anticheat.Movement.MistimingDelta",10000);
+    if (m_MistimingDelta<1000){
+        sLog.outError("Anticheat.Movement.m_MistimingDelta (%d) must be >=1000ms. Using 1000 instead.",m_TeleportToPlaneAlarms);
+        m_MistimingDelta = 1000;
+    }
+    if (m_MistimingDelta>15000){
+        sLog.outError("Anticheat.Movement.m_MistimingDelta (%d) must be <=15000ms. Using 15000 instead.",m_TeleportToPlaneAlarms);
+        m_MistimingDelta = 15000;
+    }
+    m_MistimingAlarms = sConfig.GetIntDefault("Anticheat.Movement.MistimingAlarms",20);
+    if (m_MistimingAlarms<10) {
+        sLog.outError("Anticheat.Movement.MistimingAlarms (%d) must be >=20. Using 10 instead.",m_TeleportToPlaneAlarms);
+        m_MistimingAlarms = 10;
+    }
+    if (m_MistimingAlarms>50){
+        sLog.outError("Anticheat.Movement.m_MistimingAlarms (%d) must be <=50. Using 50 instead.",m_TeleportToPlaneAlarms);
+        m_MistimingAlarms = 50;
+    }
+
     ///- Read other configuration items from the config file
 
     m_configs[CONFIG_DURABILITY_LOSS_IN_PVP] = sConfig.GetBoolDefault("DurabilityLoss.InPvP", false);
diff --git a/src/game/World.h b/src/game/World.h
--- a/src/game/World.h
+++ b/src/game/World.h
@@ -631,6 +631,13 @@
      uint32 m_WintergrapsTimer;
      uint32 m_WintergrapsState;
 
+		//movement anticheat
+        static bool GetEnableMvAnticheat()     {return m_EnableMvAnticheat;}
+        static uint32 GetTeleportToPlaneAlarms()  {return m_TeleportToPlaneAlarms;}
+        static uint32 GetMistimingDelta()  {return m_MistimingDelta;}
+        static uint32 GetMistimingAlarms() {return m_MistimingAlarms;}
+        //<<< end movement anticheat
+
         void ProcessCliCommands();
         void QueueCliCommand( CliCommandHolder::Print* zprintf, char const* input ) { cliCmdQueue.add(new CliCommandHolder(input, zprintf)); }
 
@@ -732,6 +739,12 @@
         static int32 m_visibility_notify_periodInInstances;
         static int32 m_visibility_notify_periodInBGArenas;
 
+		//movement anticheat enable flag
+        static bool m_EnableMvAnticheat;
+        static uint32 m_TeleportToPlaneAlarms;
+        static uint32 m_MistimingDelta;
+        static uint32 m_MistimingAlarms;
+
         // CLI command holder to be thread safe
         ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;
         SqlResultQueue *m_resultQueue;
diff --git a/src/trinitycore/trinitycore.conf.dist b/src/trinitycore/trinitycore.conf.dist
--- a/src/trinitycore/trinitycore.conf.dist
+++ b/src/trinitycore/trinitycore.conf.dist
@@ -2024,6 +2024,30 @@
 Ra.Secure = 1
 
 ###############################################################################
+# MOVEMENT ANTICHEAT
+#
+#    Anticheat.Movement.Enable
+#        Enable Movement Anticheat
+#        Default: 0 - off
+#                 1 - on
+#
+#    Anticheat.Movement.TeleportToPlaneAlarms
+#        maximum alarms before player will be kicked (default 50, allowed 20 - 100)
+#
+#    Anticheat.Movement.MistimingDelta
+#        mistiming intelval between client and serverside (default 10000 ms, allowed 1000 - 15000 ms)
+#
+#    Anticheat.Movement.MistimingAlarms
+#        mistiming alarms before player will be kicked (default 20, allowed 10 - 50)
+#
+###############################################################################
+
+Anticheat.Movement.Enable = 1
+Anticheat.Movement.TeleportToPlaneAlarms = 50
+Anticheat.Movement.MistimingDelta = 10000
+Anticheat.Movement.MistimingAlarms = 20
+
+###############################################################################
 # CUSTOM SERVER OPTIONS
 #
 #    PlayerStart.AllReputation