rendered paste body/* * Copyright (C) 2005-2010 MaNGOS <http://getmangos.com/> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include "Common.h"#include "WorldPacket.h"#include "WorldSession.h"#include "Opcodes.h"#include "Log.h"#include "Corpse.h"#include "Player.h"#include "Vehicle.h"#include "SpellAuras.h"#include "MapManager.h"#include "Transports.h"#include "BattleGround.h"#include "WaypointMovementGenerator.h"#include "InstanceSaveMgr.h"#include "ObjectMgr.h"#include "World.h"#include "Language.h"//#define __ANTI_DEBUG__#ifdef __ANTI_DEBUG__#include "Chat.h"std::string FlagsToStr(const uint32 Flags){ std::string Ret=""; if(Flags==0) { Ret="None"; return Ret; } if(Flags & MOVEMENTFLAG_FORWARD) { Ret+="FW "; } if(Flags & MOVEMENTFLAG_BACKWARD) { Ret+="BW "; } if(Flags & MOVEMENTFLAG_STRAFE_LEFT) { Ret+="STL "; } if(Flags & MOVEMENTFLAG_STRAFE_RIGHT) { Ret+="STR "; } if(Flags & MOVEMENTFLAG_LEFT) { Ret+="LF "; } if(Flags & MOVEMENTFLAG_RIGHT) { Ret+="RI "; } if(Flags & MOVEMENTFLAG_PITCH_UP) { Ret+="PTUP "; } if(Flags & MOVEMENTFLAG_PITCH_DOWN) { Ret+="PTDW "; } if(Flags & MOVEMENTFLAG_WALK_MODE) { Ret+="WALK "; } if(Flags & MOVEMENTFLAG_ONTRANSPORT) { Ret+="TRANS "; } if(Flags & MOVEMENTFLAG_LEVITATING) { Ret+="LEVI "; } if(Flags & MOVEMENTFLAG_FLY_UNK1) { Ret+="FLYUNK1 "; } if(Flags & MOVEMENTFLAG_JUMPING) { Ret+="JUMP "; } if(Flags & MOVEMENTFLAG_UNK4) { Ret+="UNK4 "; } if(Flags & MOVEMENTFLAG_FALLING) { Ret+="FALL "; } if(Flags & MOVEMENTFLAG_SWIMMING) { Ret+="SWIM "; } if(Flags & MOVEMENTFLAG_FLY_UP) { Ret+="FLYUP "; } if(Flags & MOVEMENTFLAG_CAN_FLY) { Ret+="CFLY "; } if(Flags & MOVEMENTFLAG_FLYING) { Ret+="FLY "; } if(Flags & MOVEMENTFLAG_FLYING2) { Ret+="FLY2 "; } if(Flags & MOVEMENTFLAG_WATERWALKING) { Ret+="WTWALK "; } if(Flags & MOVEMENTFLAG_SAFE_FALL) { Ret+="SAFE "; } if(Flags & MOVEMENTFLAG_UNK3) { Ret+="UNK3 "; } if(Flags & MOVEMENTFLAG_SPLINE) { Ret+="SPLINE "; } if(Flags & MOVEMENTFLAG_SPLINE2) { Ret+="SPLINE2 "; } return Ret;}#endif // __ANTI_DEBUG__bool WorldSession::Anti__ReportCheat(const char* Reason,float Speed,const char* Op,float Val1,uint32 Val2){ if(!Reason) { sLog.outError("Anti__ReportCheat: Missing Reason parameter!"); return false; } const char* Player=GetPlayer()->GetName(); uint32 Acc=GetPlayer()->GetSession()->GetAccountId(); uint32 Map=GetPlayer()->GetMapId(); if(!Player) { sLog.outError("Anti__ReportCheat: Player with no name?!?"); return false; } QueryResult *Res=CharacterDatabase.PQuery("SELECT speed,Val1 FROM cheaters WHERE player='%s' AND reason LIKE '%s' AND Map='%u' AND last_date >= NOW()-300",Player,Reason,Map); if(Res) { Field* Fields = Res->Fetch(); std::stringstream Query; Query << "UPDATE cheaters SET count=count+1,last_date=NOW()"; Query.precision(5); if(Speed>0.0f && Speed > Fields[0].GetFloat()) { Query << ",speed='"; Query << std::fixed << Speed; Query << "'"; } if(Val1>0.0f && Val1 > Fields[1].GetFloat()) { Query << ",Val1='"; Query << std::fixed << Val1; Query << "'"; } Query << " WHERE player='" << Player << "' AND reason='" << Reason << "' AND Map='" << Map << "' AND last_date >= NOW()-300 ORDER BY entry DESC LIMIT 1"; CharacterDatabase.Execute(Query.str().c_str()); delete Res; } else { if(!Op) { Op=""; } std::stringstream Pos; Pos << "OldPos: " << GetPlayer()->GetPositionX() << " " << GetPlayer()->GetPositionY() << " " << GetPlayer()->GetPositionZ(); CharacterDatabase.PExecute("INSERT INTO cheaters (player,acctid,reason,speed,count,first_date,last_date,`Op`,Val1,Val2,Map,Pos,Level) " "VALUES ('%s','%u','%s','%f','1',NOW(),NOW(),'%s','%f','%u','%u','%s','%u')", Player,Acc,Reason,Speed,Op,Val1,Val2,Map, Pos.str().c_str(),GetPlayer()->getLevel()); } if(sWorld.GetMvAnticheatKill() && GetPlayer()->isAlive()) { GetPlayer()->DealDamage(GetPlayer(), GetPlayer()->GetHealth(), NULL, DIRECT_DAMAGE, SPELL_SCHOOL_MASK_NORMAL, NULL, false); } if(sWorld.GetMvAnticheatKick()) { GetPlayer()->GetSession()->KickPlayer(); } if(sWorld.GetMvAnticheatBan() & 1) { sWorld.BanAccount(BAN_CHARACTER,Player,sWorld.GetMvAnticheatBanTime(),"Cheat","Anticheat"); } if(sWorld.GetMvAnticheatBan() & 2) { QueryResult *result = loginDatabase.PQuery("SELECT last_ip FROM account WHERE id=%u", Acc); if(result) { Field *fields = result->Fetch(); std::string LastIP = fields[0].GetCppString(); if(!LastIP.empty()) { sWorld.BanAccount(BAN_IP,LastIP,sWorld.GetMvAnticheatBanTime(),"Cheat","Anticheat"); } delete result; } } return true;}bool WorldSession::Anti__CheatOccurred(uint32 CurTime,const char* Reason,float Speed,const char* Op, float Val1,uint32 Val2){ if(!Reason) { sLog.outError("Anti__CheatOccurred: Missing Reason parameter!"); return false; } GetPlayer()->m_anti_lastalarmtime = CurTime; GetPlayer()->m_anti_alarmcount = GetPlayer()->m_anti_alarmcount + 1; if (GetPlayer()->m_anti_alarmcount > sWorld.GetMvAnticheatAlarmCount()) { Anti__ReportCheat(Reason,Speed,Op,Val1,Val2); if(sWorld.GetMvAnticheatAnnounce()) sWorld.SendWorldText(LANG_ANNOUNCE_CHEAT, GetPlayer()->GetName(), Reason); return true; } return false;}void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ ){ DEBUG_LOG( "WORLD: got MSG_MOVE_WORLDPORT_ACK." ); HandleMoveWorldportAckOpcode();}void WorldSession::HandleMoveWorldportAckOpcode(){ // ignore unexpected far teleports if(!GetPlayer()->IsBeingTeleportedFar()) return; // get the teleport destination WorldLocation &loc = GetPlayer()->GetTeleportDest(); // possible errors in the coordinate validity check if(!MapManager::IsValidMapCoord(loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation)) { sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player %s (%d) was teleported far to a not valid location. (map:%u, x:%f, y:%f, " "z:%f) We port him to his homebind instead..", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z); // stop teleportation else we would try this again and again in LogoutPlayer... GetPlayer()->SetSemaphoreTeleportFar(false); // and teleport the player to a valid place GetPlayer()->TeleportToHomebind(); return; } // get the destination map entry, not the current one, this will fix homebind and reset greeting MapEntry const* mEntry = sMapStore.LookupEntry(loc.mapid); InstanceTemplate const* mInstance = ObjectMgr::GetInstanceTemplate(loc.mapid); // reset instance validity, except if going to an instance inside an instance if(GetPlayer()->m_InstanceValid == false && !mInstance) GetPlayer()->m_InstanceValid = true; GetPlayer()->SetSemaphoreTeleportFar(false); // relocate the player to the teleport destination GetPlayer()->SetMap(sMapMgr.CreateMap(loc.mapid, GetPlayer())); GetPlayer()->Relocate(loc.coord_x, loc.coord_y, loc.coord_z, loc.orientation); GetPlayer()->m_anti_TeleTime=time(NULL); GetPlayer()->SendInitialPacketsBeforeAddToMap(); // the CanEnter checks are done in TeleporTo but conditions may change // while the player is in transit, for example the map may get full if(!GetPlayer()->GetMap()->Add(GetPlayer())) { //if player wasn't added to map, reset his map pointer! GetPlayer()->ResetMap(); sLog.outError("WorldSession::HandleMoveWorldportAckOpcode: player %s (%d) was teleported far but couldn't be added to map. (map:%u, x:%f, y:%f, " "z:%f) We port him to his homebind instead..", GetPlayer()->GetName(), GetPlayer()->GetGUIDLow(), loc.mapid, loc.coord_x, loc.coord_y, loc.coord_z); // teleport the player home GetPlayer()->TeleportToHomebind(); return; } // battleground state prepare (in case join to BG), at relogin/tele player not invited // only add to bg group and object, if the player was invited (else he entered through command) if(_player->InBattleGround()) { // cleanup setting if outdated if(!mEntry->IsBattleGroundOrArena()) { // We're not in BG _player->SetBattleGroundId(0, BATTLEGROUND_TYPE_NONE); // reset destination bg team _player->SetBGTeam(0); } // join to bg case else if(BattleGround *bg = _player->GetBattleGround()) { if(_player->IsInvitedForBattleGroundInstance(_player->GetBattleGroundId())) bg->AddPlayer(_player); } } GetPlayer()->SendInitialPacketsAfterAddToMap(); // flight fast teleport case if(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) { if(!_player->InBattleGround()) { // short preparations to continue flight FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top()); flight->Reset(*GetPlayer()); return; } // battleground state prepare, stop flight GetPlayer()->GetMotionMaster()->MovementExpired(); GetPlayer()->m_taxi.ClearTaxiDestinations(); } // resurrect character at enter into instance where his corpse exist after add to map Corpse *corpse = GetPlayer()->GetCorpse(); if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId()) { if( mEntry->IsDungeon() ) { GetPlayer()->ResurrectPlayer(0.5f); GetPlayer()->SpawnCorpseBones(); } } if (mInstance) { Difficulty diff = GetPlayer()->GetDifficulty(mEntry->IsRaid()); if(MapDifficulty const* mapDiff = GetMapDifficultyData(mEntry->MapID,diff)) { if (mapDiff->resetTime) { if (time_t timeReset = sInstanceSaveMgr.GetScheduler().GetResetTimeFor(mEntry->MapID,diff)) { uint32 timeleft = uint32(timeReset - time(NULL)); GetPlayer()->SendInstanceResetWarning(mEntry->MapID, diff, timeleft); } } } } // mount allow check if(!mEntry->IsMountAllowed()) _player->RemoveSpellsCausingAura(SPELL_AURA_MOUNTED); // honorless target if(GetPlayer()->pvpInfo.inHostileArea) GetPlayer()->CastSpell(GetPlayer(), 2479, true); // resummon pet GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); GetPlayer()->Anti__SetLastTeleTime(::time(NULL)); GetPlayer()->m_anti_BeginFallZ=INVALID_HEIGHT; //lets process all delayed operations on successful teleport GetPlayer()->ProcessDelayedOperations();}void WorldSession::HandleMoveTeleportAckOpcode(WorldPacket& recv_data){ DEBUG_LOG("MSG_MOVE_TELEPORT_ACK"); ObjectGuid guid; recv_data >> guid.ReadAsPacked(); uint32 flags, time; recv_data >> flags >> time; DEBUG_LOG("Guid: %s", guid.GetString().c_str()); DEBUG_LOG("Flags %u, time %u", flags, time/IN_MILLISECONDS); Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; if(!plMover || !plMover->IsBeingTeleportedNear()) return; if(guid != plMover->GetObjectGuid()) return; plMover->SetSemaphoreTeleportNear(false); uint32 old_zone = plMover->GetZoneId(); WorldLocation const& dest = plMover->GetTeleportDest(); plMover->SetPosition(dest.coord_x, dest.coord_y, dest.coord_z, dest.orientation, true); uint32 newzone, newarea; plMover->GetZoneAndAreaId(newzone, newarea); plMover->UpdateZone(newzone, newarea); // new zone if(old_zone != newzone) { // honorless target if(plMover->pvpInfo.inHostileArea) plMover->CastSpell(plMover, 2479, true); } // resummon pet GetPlayer()->ResummonPetTemporaryUnSummonedIfAny(); if(plMover) { plMover->Anti__SetLastTeleTime(::time(NULL)); plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } //lets process all delayed operations on successful teleport GetPlayer()->ProcessDelayedOperations();}void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data ){ uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); recv_data.hexlike(); Unit *mover = _player->GetMover(); Player *plMover = mover->GetTypeId() == TYPEID_PLAYER ? (Player*)mover : NULL; // ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck if(plMover && plMover->IsBeingTeleported()) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> movementInfo; /*----------------*/ // ignore wrong guid (player attempt cheating own session for not own guid possible...) if (guid != mover->GetObjectGuid()) return; if (!MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o)) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /* handle special cases */ if (movementInfo.HasMovementFlag(MOVEFLAG_ONTRANSPORT)) { // transports size limited // (also received at zeppelin/lift leave by some reason with t_* as absolute in continent coordinates, can be safely skipped) if( movementInfo.GetTransportPos()->x > 50 || movementInfo.GetTransportPos()->y > 50 || movementInfo.GetTransportPos()->z > 100 ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } if( !MaNGOS::IsValidMapCoord(movementInfo.GetPos()->x + movementInfo.GetTransportPos()->x, movementInfo.GetPos()->y + movementInfo.GetTransportPos()->y, movementInfo.GetPos()->z + movementInfo.GetTransportPos()->z, movementInfo.GetPos()->o + movementInfo.GetTransportPos()->o) ) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } // if we boarded a transport, add us to it if (plMover && !plMover->m_transport) { float trans_rad = movementInfo.GetTransportPos()->x*movementInfo.GetTransportPos()->x + movementInfo.GetTransportPos()->y*movementInfo.GetTransportPos()->y + movementInfo.GetTransportPos()->z*movementInfo.GetTransportPos()->z; if (trans_rad > 3600.0f) // transport radius = 60 yards //cheater with on_transport_flag { return; } // elevators also cause the client to send MOVEFLAG_ONTRANSPORT - just unmount if the guid can be found in the transport list for (MapManager::TransportSet::const_iterator iter = sMapMgr.m_Transports.begin(); iter != sMapMgr.m_Transports.end(); ++iter) { if ((*iter)->GetObjectGuid() == movementInfo.GetTransportGuid()) { plMover->m_transport = (*iter); (*iter)->AddPassenger(plMover); break; } } } } else if (plMover && plMover->m_transport) // if we were on a transport, leave { plMover->m_transport->RemovePassenger(plMover); plMover->m_transport = NULL; movementInfo.ClearTransportData(); } // 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->IsTaxiFlying()) plMover->HandleFall(movementInfo); if (plMover && (movementInfo.HasMovementFlag(MOVEFLAG_SWIMMING) != plMover->IsInWater())) { // now client not include swimming flag in case jumping under water plMover->SetInWater( !plMover->IsInWater() || plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z) ); if(plMover->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f)) { plMover->m_anti_BeginFallZ=INVALID_HEIGHT; } } // ---- anti-cheat features -->>> uint32 Anti_TeleTimeDiff=plMover ? time(NULL) - plMover->Anti__GetLastTeleTime() : time(NULL); static const uint32 Anti_TeleTimeIgnoreDiff=sWorld.GetMvAnticheatIgnoreAfterTeleport(); if (plMover && (plMover->m_transport == 0) && sWorld.GetMvAnticheatEnable() && GetPlayer()->GetSession()->GetSecurity() <= sWorld.GetMvAnticheatGmLevel() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()!=FLIGHT_MOTION_TYPE && Anti_TeleTimeDiff>Anti_TeleTimeIgnoreDiff) { const uint32 CurTime=getMSTime(); if(getMSTimeDiff(GetPlayer()->m_anti_lastalarmtime,CurTime) > sWorld.GetMvAnticheatAlarmPeriod()) { GetPlayer()->m_anti_alarmcount = 0; } /* I really don't care about movement-type yet (todo) UnitMoveType move_type; if (movementInfo.flags & MOVEMENTFLAG_FLYING) move_type = MOVE_FLY; else if (movementInfo.flags & MOVEMENTFLAG_SWIMMING) move_type = MOVE_SWIM; else if (movementInfo.flags & MOVEMENTFLAG_WALK_MODE) move_type = MOVE_WALK; else move_type = MOVE_RUN;*/ float delta_x = GetPlayer()->GetPositionX() - movementInfo.GetPos()->x; float delta_y = GetPlayer()->GetPositionY() - movementInfo.GetPos()->y; float delta_z = GetPlayer()->GetPositionZ() - movementInfo.GetPos()->z; float delta = sqrt(delta_x * delta_x + delta_y * delta_y); // Len of movement-vector via Pythagoras (a^2+b^2=Len^2) float tg_z = 0.0f; //tangens float delta_t = getMSTimeDiff(GetPlayer()->m_anti_lastmovetime,CurTime); GetPlayer()->m_anti_lastmovetime = CurTime; GetPlayer()->m_anti_MovedLen += delta; if(delta_t > 15000.0f) { delta_t = 15000.0f; } // Tangens of walking angel if (!(movementInfo.GetMovementFlags() & (MOVEFLAG_FLYING | MOVEFLAG_SWIMMING))) { tg_z = ((delta !=0.0f) && (delta_z > 0.0f)) ? (atan((delta_z*delta_z) / delta) * 180.0f / M_PI) : 0.0f; } //antiOFF fall-damage, MOVEMENTFLAG_UNK4 seted by client if player try movement when falling and unset in this case the MOVEMENTFLAG_FALLING flag. if((!GetPlayer()->CanFly() && GetPlayer()->m_anti_BeginFallZ == INVALID_HEIGHT) && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLING | MOVEFLAG_FALLINGFAR)) != 0) { GetPlayer()->m_anti_BeginFallZ=(float)(movementInfo.GetPos()->z); } if(GetPlayer()->m_anti_NextLenCheck <= CurTime) { // Check every 500ms is a lot more advisable then 1000ms, because normal movment packet arrives every 500ms uint32 OldNextLenCheck=GetPlayer()->m_anti_NextLenCheck; float delta_xyt=GetPlayer()->m_anti_MovedLen/(float)(getMSTimeDiff(OldNextLenCheck-500,CurTime)); GetPlayer()->m_anti_NextLenCheck = CurTime+500; GetPlayer()->m_anti_MovedLen = 0.0f; static const float MaxDeltaXYT = sWorld.GetMvAnticheatMaxXYT(); if(delta_xyt > MaxDeltaXYT && delta<=100.0f && GetPlayer()->GetZoneId() != 2257) { if(sWorld.GetMvAnticheatSpeedCheck()) Anti__CheatOccurred(CurTime,"Speed hack",delta_xyt,LookupOpcodeName(opcode), (float)(GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType()), (float)(getMSTimeDiff(OldNextLenCheck-500,CurTime))); } } if(delta > 100.0f && GetPlayer()->GetZoneId() != 2257) { if(sWorld.GetMvAnticheatTeleportCheck()) Anti__ReportCheat("Tele hack",delta,LookupOpcodeName(opcode)); } // Check for waterwalking . Fix new way of checking for waterwalking by Darky88 if (movementInfo.HasMovementFlag(MOVEFLAG_WATERWALKING) && !(GetPlayer()->HasAuraType(SPELL_AURA_WATER_WALK) || GetPlayer()->HasAuraType(SPELL_AURA_GHOST))) { if(sWorld.GetMvAnticheatWaterCheck()) Anti__CheatOccurred(CurTime,"Water walking",0.0f,NULL,0.0f,(uint32)(movementInfo.GetMovementFlags())); } // Check for walking upwards a mountain while not beeing able to do that, New check by Darky88 if((delta_z < -2.3f) && (tg_z > 2.37f)) { if(sWorld.GetMvAnticheatMountainCheck()) Anti__CheatOccurred(CurTime,"Mountain hack",tg_z,NULL,delta,delta_z); } static const float DIFF_OVERGROUND = 10.0f; float Anti__GroundZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),MAX_HEIGHT); float Anti__FloorZ = GetPlayer()->GetMap()->GetHeight(GetPlayer()->GetPositionX(),GetPlayer()->GetPositionY(),GetPlayer()->GetPositionZ()); float Anti__MapZ = ((Anti__FloorZ <= (INVALID_HEIGHT+5.0f)) ? Anti__GroundZ : Anti__FloorZ) + DIFF_OVERGROUND; if(!GetPlayer()->CanFly() && !GetPlayer()->GetBaseMap()->IsUnderWater(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z-7.0f) && Anti__MapZ < GetPlayer()->GetPositionZ() && Anti__MapZ > (INVALID_HEIGHT+DIFF_OVERGROUND + 5.0f)) { static const float DIFF_AIRJUMP=25.0f; // 25 is realy high, but to many false positives... // Air-Jump-Detection definitively needs a better way to be detected... if((movementInfo.GetMovementFlags() & (MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING | MOVEFLAG_ROOT)) != 0) // Fly Hack { // Fix Aura 55164, 58600, 61243 Parachute Visual if (!GetPlayer()->HasAura(55164) || !GetPlayer()->HasAura(58600) || !GetPlayer()->HasAura(61243)) if(sWorld.GetMvAnticheatFlyCheck()) Anti__CheatOccurred(CurTime,"Fly hack", ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_FLY))) + ((uint8)(GetPlayer()->HasAuraType(SPELL_AURA_MOD_FLIGHT_SPEED_MOUNTED))*2), NULL,GetPlayer()->GetPositionZ()-Anti__MapZ); } // Need a better way to do that - currently a lot of fake alarms else if((Anti__MapZ+DIFF_AIRJUMP < GetPlayer()->GetPositionZ() && (movementInfo.GetMovementFlags() & (MOVEFLAG_FALLINGFAR | MOVEFLAG_PENDINGSTOP))==0) || (Anti__MapZ < GetPlayer()->GetPositionZ() && opcode==MSG_MOVE_JUMP) && !GetPlayer()->HasAuraType(SPELL_AURA_FEATHER_FALL)) { if(sWorld.GetMvAnticheatJumpCheck()) Anti__CheatOccurred(CurTime,"Possible Air Jump Hack",0.0f,LookupOpcodeName(opcode),0.0f,movementInfo.GetMovementFlags()); } } //Teleport To Plane checks if (movementInfo.GetPos()->z < 0.0001f && movementInfo.GetPos()->z > -0.0001f && (!movementInfo.HasMovementFlag(MovementFlags(MOVEFLAG_SWIMMING | MOVEFLAG_CAN_FLY | MOVEFLAG_FLYING)))) { if(sWorld.GetMvAnticheatTeleport2PlaneCheck()) { // Prevent using TeleportToPlan. Map *map = GetPlayer()->GetMap(); if (map) { float plane_z = map->GetHeight(movementInfo.GetPos()->x, movementInfo.GetPos()->y, MAX_HEIGHT) - movementInfo.GetPos()->z; plane_z = (plane_z < -500.0f) ? 0 : plane_z; //check holes in heigth map if(plane_z > 0.1f || plane_z < -0.1f) { if(sWorld.GetMvAnticheatTeleport2PlaneCheck()) Anti__CheatOccurred(CurTime,"Teleport2Plane hack",GetPlayer()->GetPositionZ(),NULL,plane_z); } } } } } // <<---- anti-cheat features /* process position-change */ movementInfo.UpdateTime(getMSTime()); WorldPacket data(opcode, recv_data.size()); data.appendPackGUID(mover->GetGUID()); // write guid movementInfo.Write(data); // write data mover->SendMessageToSetExcept(&data, _player); if(plMover) // nothing is charmed, or player charmed { plMover->SetPosition(movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); plMover->m_movementInfo = movementInfo; plMover->UpdateFallInformationIfNeed(movementInfo, opcode); // after move info set if ((opcode == MSG_MOVE_SET_WALK_MODE || opcode == MSG_MOVE_SET_RUN_MODE)) plMover->UpdateWalkMode(plMover, false); if(plMover->isMovingOrTurning()) plMover->RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH); if(movementInfo.GetPos()->z < -500.0f) { if(plMover->InBattleGround() && plMover->GetBattleGround() && plMover->GetBattleGround()->HandlePlayerUnderMap(_player)) { // do nothing, the handle already did if returned true } else { // NOTE: this is actually called many times while falling // even after the player has been teleported away // TODO: discard movement packets after the player is rooted if(plMover->isAlive()) { plMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, plMover->GetMaxHealth()); // pl can be alive if GM/etc if(!plMover->isAlive()) { // change the death state to CORPSE to prevent the death timer from // starting in the next player update plMover->KillPlayer(); plMover->BuildPlayerRepop(); } } // cancel the death timer here if started plMover->RepopAtGraveyard(); } } } else // creature charmed { if(mover->IsInWorld()) mover->GetMap()->CreatureRelocation((Creature*)mover, movementInfo.GetPos()->x, movementInfo.GetPos()->y, movementInfo.GetPos()->z, movementInfo.GetPos()->o); }}void WorldSession::HandleForceSpeedChangeAckOpcodes(WorldPacket &recv_data){ uint32 opcode = recv_data.GetOpcode(); DEBUG_LOG("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode); /* extract packet */ ObjectGuid guid; MovementInfo movementInfo; float newspeed; recv_data >> guid.ReadAsPacked(); recv_data >> Unused<uint32>(); // counter or moveEvent recv_data >> movementInfo; recv_data >> newspeed; // now can skip not our packet if(_player->GetObjectGuid() != guid) { recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } /*----------------*/ // client ACK send one packet for mounted/run case and need skip all except last from its // in other cases anti-cheat check can be fail in false case UnitMoveType move_type; UnitMoveType force_move_type; static char const* move_type_name[MAX_MOVE_TYPE] = { "Walk", "Run", "RunBack", "Swim", "SwimBack", "TurnRate", "Flight", "FlightBack", "PitchRate" }; switch(opcode) { case CMSG_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; force_move_type = MOVE_WALK; break; case CMSG_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; force_move_type = MOVE_RUN; break; case CMSG_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; force_move_type = MOVE_RUN_BACK; break; case CMSG_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; force_move_type = MOVE_SWIM; break; case CMSG_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; force_move_type = MOVE_SWIM_BACK; break; case CMSG_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; force_move_type = MOVE_TURN_RATE; break; case CMSG_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; force_move_type = MOVE_FLIGHT; break; case CMSG_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; force_move_type = MOVE_FLIGHT_BACK; break; case CMSG_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; force_move_type = MOVE_PITCH_RATE; break; default: sLog.outError("WorldSession::HandleForceSpeedChangeAck: Unknown move type opcode: %u", opcode); return; } // skip all forced speed changes except last and unexpected // in run/mounted case used one ACK and it must be skipped.m_forced_speed_changes[MOVE_RUN} store both. if(_player->m_forced_speed_changes[force_move_type] > 0) { --_player->m_forced_speed_changes[force_move_type]; if(_player->m_forced_speed_changes[force_move_type] > 0) return; } if (!_player->GetTransport() && fabs(_player->GetSpeed(move_type) - newspeed) > 0.01f) { if(_player->GetSpeed(move_type) > newspeed) // must be greater - just correct { sLog.outError("%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value", move_type_name[move_type], _player->GetName(), _player->GetSpeed(move_type), newspeed); _player->SetSpeedRate(move_type,_player->GetSpeedRate(move_type),true); } else // must be lesser - cheating { BASIC_LOG("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(); } }}void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data){ DEBUG_LOG("WORLD: Recvd CMSG_SET_ACTIVE_MOVER"); recv_data.hexlike(); ObjectGuid guid; recv_data >> guid; if(_player->GetMover()->GetObjectGuid() != guid) { sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s", _player->GetMover()->GetObjectGuid().GetString().c_str(), guid.GetString().c_str()); return; }}void WorldSession::HandleMoveNotActiveMoverOpcode(WorldPacket &recv_data){ DEBUG_LOG("WORLD: Recvd CMSG_MOVE_NOT_ACTIVE_MOVER"); recv_data.hexlike(); ObjectGuid old_mover_guid; MovementInfo mi; recv_data >> old_mover_guid.ReadAsPacked(); recv_data >> mi; if(_player->GetMover()->GetObjectGuid() == old_mover_guid) { sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is %s and should be %s instead of %s", _player->GetMover()->GetObjectGuid().GetString().c_str(), _player->GetObjectGuid().GetString().c_str(), old_mover_guid.GetString().c_str()); recv_data.rpos(recv_data.wpos()); // prevent warnings spam return; } _player->m_movementInfo = mi;}void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data){ DEBUG_LOG("WORLD: Recvd CMSG_DISMISS_CONTROLLED_VEHICLE"); recv_data.hexlike(); ObjectGuid guid; MovementInfo mi; recv_data >> guid.ReadAsPacked(); recv_data >> mi; uint64 vehicleGUID = _player->GetCharmGUID(); if(!vehicleGUID) // something wrong here... return; _player->m_movementInfo = mi; // using charm guid, because we don't have vehicle guid... if(Vehicle *vehicle = _player->GetMap()->GetVehicle(vehicleGUID)) { // Aura::HandleAuraControlVehicle will call Player::ExitVehicle vehicle->RemoveSpellsCausingAura(SPELL_AURA_CONTROL_VEHICLE); }}void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvdata*/){ //DEBUG_LOG("WORLD: Recvd CMSG_MOUNTSPECIAL_ANIM"); WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8); data << GetPlayer()->GetObjectGuid(); GetPlayer()->SendMessageToSet(&data, false);}void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data ){ DEBUG_LOG("CMSG_MOVE_KNOCK_BACK_ACK"); ObjectGuid guid; // guid - unused MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> Unused<uint32>(); // unk recv_data >> movementInfo;}void WorldSession::HandleMoveHoverAck( WorldPacket& recv_data ){ DEBUG_LOG("CMSG_MOVE_HOVER_ACK"); ObjectGuid guid; // guid - unused MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> Unused<uint32>(); // unk1 recv_data >> movementInfo; recv_data >> Unused<uint32>(); // unk2}void WorldSession::HandleMoveWaterWalkAck(WorldPacket& recv_data){ DEBUG_LOG("CMSG_MOVE_WATER_WALK_ACK"); ObjectGuid guid; // guid - unused MovementInfo movementInfo; recv_data >> guid.ReadAsPacked(); recv_data >> Unused<uint32>(); // unk1 recv_data >> movementInfo; recv_data >> Unused<uint32>(); // unk2}void WorldSession::HandleSummonResponseOpcode(WorldPacket& recv_data){ if(!_player->isAlive() || _player->isInCombat() ) return; uint64 summoner_guid; bool agree; recv_data >> summoner_guid; recv_data >> agree; _player->SummonIfPossible(agree);}