mirror of
https://github.com/mangosfour/server.git
synced 2025-12-30 10:37:12 +00:00
Now movements of controlled unit are visible for nearby players, even when controller too far from controlled unit This new type of packet broadcasting used in HandleMovementOpcodes handler only, maybe it can be used somewhere else. (based on SilverIce's repo commit d2387ca) Signed-off-by: VladimirMangos <vladimir@getmangos.com>
553 lines
21 KiB
C++
553 lines
21 KiB
C++
/*
|
|
* 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"
|
|
|
|
void WorldSession::HandleMoveWorldportAckOpcode( WorldPacket & /*recv_data*/ )
|
|
{
|
|
sLog.outDebug( "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()->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.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();
|
|
|
|
//lets process all delayed operations on successful teleport
|
|
GetPlayer()->ProcessDelayedOperations();
|
|
}
|
|
|
|
void WorldSession::HandleMoveTeleportAck(WorldPacket& recv_data)
|
|
{
|
|
sLog.outDebug("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->m_mover;
|
|
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();
|
|
|
|
//lets process all delayed operations on successful teleport
|
|
GetPlayer()->ProcessDelayedOperations();
|
|
}
|
|
|
|
void WorldSession::HandleMovementOpcodes( WorldPacket & recv_data )
|
|
{
|
|
uint32 opcode = recv_data.GetOpcode();
|
|
sLog.outDebug("WORLD: Recvd %s (%u, 0x%X) opcode", LookupOpcodeName(opcode), opcode, opcode);
|
|
recv_data.hexlike();
|
|
|
|
Unit *mover = _player->m_mover;
|
|
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;
|
|
/*----------------*/
|
|
|
|
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)
|
|
{
|
|
// 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.SetTransportData(0, 0.0f, 0.0f, 0.0f, 0.0f, 0, -1);
|
|
}
|
|
|
|
// 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())
|
|
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) );
|
|
}
|
|
|
|
/*----------------------*/
|
|
|
|
/* 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, GetPlayer()->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::HandleForceSpeedChangeAck(WorldPacket &recv_data)
|
|
{
|
|
uint32 opcode = recv_data.GetOpcode();
|
|
sLog.outDebug("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
|
|
{
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleSetActiveMoverOpcode(WorldPacket &recv_data)
|
|
{
|
|
sLog.outDebug("WORLD: Recvd CMSG_SET_ACTIVE_MOVER");
|
|
recv_data.hexlike();
|
|
|
|
uint64 guid;
|
|
recv_data >> guid;
|
|
|
|
if(_player->m_mover->GetGUID() != guid)
|
|
{
|
|
sLog.outError("HandleSetActiveMoverOpcode: incorrect mover guid: mover is " I64FMT " and should be " I64FMT, _player->m_mover->GetGUID(), guid);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleMoveNotActiveMover(WorldPacket &recv_data)
|
|
{
|
|
sLog.outDebug("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->m_mover->GetObjectGuid() == old_mover_guid)
|
|
{
|
|
sLog.outError("HandleMoveNotActiveMover: incorrect mover guid: mover is " I64FMT " and should be " I64FMT " instead of " UI64FMTD, _player->m_mover->GetGUID(), _player->GetGUID(), old_mover_guid.GetRawValue());
|
|
recv_data.rpos(recv_data.wpos()); // prevent warnings spam
|
|
return;
|
|
}
|
|
|
|
_player->m_movementInfo = mi;
|
|
}
|
|
|
|
void WorldSession::HandleDismissControlledVehicle(WorldPacket &recv_data)
|
|
{
|
|
sLog.outDebug("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*/)
|
|
{
|
|
//sLog.outDebug("WORLD: Recvd CMSG_MOUNTSPECIAL_ANIM");
|
|
|
|
WorldPacket data(SMSG_MOUNTSPECIAL_ANIM, 8);
|
|
data << uint64(GetPlayer()->GetGUID());
|
|
|
|
GetPlayer()->SendMessageToSet(&data, false);
|
|
}
|
|
|
|
void WorldSession::HandleMoveKnockBackAck( WorldPacket & recv_data )
|
|
{
|
|
sLog.outDebug("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 )
|
|
{
|
|
sLog.outDebug("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)
|
|
{
|
|
sLog.outDebug("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);
|
|
}
|