mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-21 01:37:37 +01:00
Always send a Welcome type Instance Lock chat message when entering an instance instead of changing type based on remaining time. Fix scheduled warning message to always send "Your instance lock for ... will expire in 0 minutes." even if there are hours left, issue added in4193806dba, closes #11519 . Update warning messages based on remaining time so that the most meaning is always used (6 hours left, 59 minutes left, etc). (cherry picked from commitfae8269589) Conflicts: src/server/game/Handlers/MovementHandler.cpp src/server/game/Maps/Map.cpp
535 lines
20 KiB
C++
535 lines
20 KiB
C++
/*
|
|
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
|
|
* Copyright (C) 2005-2009 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, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "Common.h"
|
|
#include "WorldPacket.h"
|
|
#include "WorldSession.h"
|
|
#include "Opcodes.h"
|
|
#include "Log.h"
|
|
#include "Corpse.h"
|
|
#include "Player.h"
|
|
#include "Garrison.h"
|
|
#include "SpellAuras.h"
|
|
#include "MapManager.h"
|
|
#include "Transport.h"
|
|
#include "Battleground.h"
|
|
#include "WaypointMovementGenerator.h"
|
|
#include "InstanceSaveMgr.h"
|
|
#include "ObjectMgr.h"
|
|
#include "Vehicle.h"
|
|
#include "MovementPackets.h"
|
|
|
|
#define MOVEMENT_PACKET_TIME_DELAY 0
|
|
|
|
void WorldSession::HandleMoveWorldportAckOpcode(WorldPackets::Movement::WorldPortResponse& /*packet*/)
|
|
{
|
|
HandleMoveWorldportAckOpcode();
|
|
}
|
|
|
|
void WorldSession::HandleMoveWorldportAckOpcode()
|
|
{
|
|
// ignore unexpected far teleports
|
|
if (!GetPlayer()->IsBeingTeleportedFar())
|
|
return;
|
|
|
|
bool seamlessTeleport = GetPlayer()->IsBeingTeleportedSeamlessly();
|
|
GetPlayer()->SetSemaphoreTeleportFar(false);
|
|
|
|
// get the teleport destination
|
|
WorldLocation const& loc = GetPlayer()->GetTeleportDest();
|
|
|
|
// possible errors in the coordinate validity check
|
|
if (!MapManager::IsValidMapCoord(loc))
|
|
{
|
|
LogoutPlayer(false);
|
|
return;
|
|
}
|
|
|
|
// 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 = sObjectMgr->GetInstanceTemplate(loc.GetMapId());
|
|
|
|
// reset instance validity, except if going to an instance inside an instance
|
|
if (GetPlayer()->m_InstanceValid == false && !mInstance)
|
|
GetPlayer()->m_InstanceValid = true;
|
|
|
|
Map* oldMap = GetPlayer()->GetMap();
|
|
Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
|
|
|
|
if (GetPlayer()->IsInWorld())
|
|
{
|
|
TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
|
|
oldMap->RemovePlayerFromMap(GetPlayer(), false);
|
|
}
|
|
|
|
// relocate the player to the teleport destination
|
|
// 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 (!newMap || !newMap->CanEnter(GetPlayer()))
|
|
{
|
|
TC_LOG_ERROR("network", "Map %d (%s) could not be created for %s (%s), porting player to homebind", loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str());
|
|
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
|
return;
|
|
}
|
|
|
|
float z = loc.GetPositionZ();
|
|
if (GetPlayer()->HasUnitMovementFlag(MOVEMENTFLAG_HOVER))
|
|
z += GetPlayer()->GetFloatValue(UNIT_FIELD_HOVERHEIGHT);
|
|
|
|
GetPlayer()->Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation());
|
|
|
|
GetPlayer()->ResetMap();
|
|
GetPlayer()->SetMap(newMap);
|
|
|
|
if (!seamlessTeleport)
|
|
GetPlayer()->SendInitialPacketsBeforeAddToMap();
|
|
|
|
if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer(), !seamlessTeleport))
|
|
{
|
|
TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%s) to map %d (%s) because of unknown reason!",
|
|
GetPlayer()->GetName().c_str(), GetPlayer()->GetGUID().ToString().c_str(), loc.GetMapId(), newMap ? newMap->GetMapName() : "Unknown");
|
|
GetPlayer()->ResetMap();
|
|
GetPlayer()->SetMap(oldMap);
|
|
GetPlayer()->TeleportTo(GetPlayer()->m_homebindMapId, GetPlayer()->m_homebindX, GetPlayer()->m_homebindY, GetPlayer()->m_homebindZ, GetPlayer()->GetOrientation());
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (!seamlessTeleport)
|
|
GetPlayer()->SendInitialPacketsAfterAddToMap();
|
|
else
|
|
{
|
|
GetPlayer()->UpdateVisibilityForPlayer();
|
|
if (Garrison* garrison = GetPlayer()->GetGarrison())
|
|
garrison->SendRemoteInfo();
|
|
}
|
|
|
|
// flight fast teleport case
|
|
if (GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE)
|
|
{
|
|
if (!_player->InBattleground())
|
|
{
|
|
if (!seamlessTeleport)
|
|
{
|
|
// short preparations to continue flight
|
|
FlightPathMovementGenerator* flight = (FlightPathMovementGenerator*)(GetPlayer()->GetMotionMaster()->top());
|
|
flight->Initialize(GetPlayer());
|
|
}
|
|
return;
|
|
}
|
|
|
|
// battleground state prepare, stop flight
|
|
GetPlayer()->GetMotionMaster()->MovementExpired();
|
|
GetPlayer()->CleanupAfterTaxiFlight();
|
|
}
|
|
|
|
// 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, false);
|
|
GetPlayer()->SpawnCorpseBones();
|
|
}
|
|
}
|
|
|
|
bool allowMount = !mEntry->IsDungeon() || mEntry->IsBattlegroundOrArena();
|
|
if (mInstance)
|
|
{
|
|
Difficulty diff = GetPlayer()->GetDifficultyID(mEntry);
|
|
if (MapDifficultyEntry const* mapDiff = GetMapDifficultyData(mEntry->ID, diff))
|
|
{
|
|
if (mapDiff->RaidDuration)
|
|
{
|
|
if (time_t timeReset = sInstanceSaveMgr->GetResetTimeFor(mEntry->ID, diff))
|
|
{
|
|
uint32 timeleft = uint32(timeReset - time(NULL));
|
|
GetPlayer()->SendInstanceResetWarning(mEntry->ID, diff, timeleft, true);
|
|
}
|
|
}
|
|
}
|
|
allowMount = mInstance->AllowMount;
|
|
}
|
|
|
|
// mount allow check
|
|
if (!allowMount)
|
|
_player->RemoveAurasByType(SPELL_AURA_MOUNTED);
|
|
|
|
// update zone immediately, otherwise leave channel will cause crash in mtmap
|
|
uint32 newzone, newarea;
|
|
GetPlayer()->GetZoneAndAreaId(newzone, newarea);
|
|
GetPlayer()->UpdateZone(newzone, newarea);
|
|
|
|
// honorless target
|
|
if (GetPlayer()->pvpInfo.IsHostile)
|
|
GetPlayer()->CastSpell(GetPlayer(), 2479, true);
|
|
|
|
// in friendly area
|
|
else if (GetPlayer()->IsPvP() && !GetPlayer()->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
|
|
GetPlayer()->UpdatePvP(false, false);
|
|
|
|
// resummon pet
|
|
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
|
|
|
|
//lets process all delayed operations on successful teleport
|
|
GetPlayer()->ProcessDelayedOperations();
|
|
}
|
|
|
|
void WorldSession::HandleMoveTeleportAck(WorldPackets::Movement::MoveTeleportAck& packet)
|
|
{
|
|
TC_LOG_DEBUG("network", "CMSG_MOVE_TELEPORT_ACK: Guid: %s, Sequence: %u, Time: %u", packet.MoverGUID.ToString().c_str(), packet.AckIndex, packet.MoveTime);
|
|
|
|
Player* plMover = _player->m_mover->ToPlayer();
|
|
|
|
if (!plMover || !plMover->IsBeingTeleportedNear())
|
|
return;
|
|
|
|
if (packet.MoverGUID != plMover->GetGUID())
|
|
return;
|
|
|
|
plMover->SetSemaphoreTeleportNear(false);
|
|
|
|
uint32 old_zone = plMover->GetZoneId();
|
|
|
|
WorldLocation const& dest = plMover->GetTeleportDest();
|
|
|
|
plMover->UpdatePosition(dest, true);
|
|
|
|
uint32 newzone, newarea;
|
|
plMover->GetZoneAndAreaId(newzone, newarea);
|
|
plMover->UpdateZone(newzone, newarea);
|
|
|
|
// new zone
|
|
if (old_zone != newzone)
|
|
{
|
|
// honorless target
|
|
if (plMover->pvpInfo.IsHostile)
|
|
plMover->CastSpell(plMover, 2479, true);
|
|
|
|
// in friendly area
|
|
else if (plMover->IsPvP() && !plMover->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_IN_PVP))
|
|
plMover->UpdatePvP(false, false);
|
|
}
|
|
|
|
// resummon pet
|
|
GetPlayer()->ResummonPetTemporaryUnSummonedIfAny();
|
|
|
|
//lets process all delayed operations on successful teleport
|
|
GetPlayer()->ProcessDelayedOperations();
|
|
}
|
|
|
|
void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMovement& packet)
|
|
{
|
|
OpcodeClient opcode = packet.GetOpcode();
|
|
|
|
Unit* mover = _player->m_mover;
|
|
|
|
ASSERT(mover != nullptr); // there must always be a mover
|
|
|
|
Player* plrMover = mover->ToPlayer();
|
|
|
|
// ignore, waiting processing in WorldSession::HandleMoveWorldportAckOpcode and WorldSession::HandleMoveTeleportAck
|
|
if (plrMover && plrMover->IsBeingTeleported())
|
|
return;
|
|
|
|
GetPlayer()->ValidateMovementInfo(&packet.movementInfo);
|
|
|
|
MovementInfo& movementInfo = packet.movementInfo;
|
|
|
|
// prevent tampered movement data
|
|
if (movementInfo.guid != mover->GetGUID())
|
|
{
|
|
TC_LOG_ERROR("network", "HandleMovementOpcodes: guid error");
|
|
return;
|
|
}
|
|
|
|
if (!movementInfo.pos.IsPositionValid())
|
|
{
|
|
TC_LOG_ERROR("network", "HandleMovementOpcodes: Invalid Position");
|
|
return;
|
|
}
|
|
|
|
// stop some emotes at player move
|
|
if (plrMover && (plrMover->GetUInt32Value(UNIT_NPC_EMOTESTATE) != 0))
|
|
plrMover->SetUInt32Value(UNIT_NPC_EMOTESTATE, EMOTE_ONESHOT_NONE);
|
|
|
|
/* handle special cases */
|
|
if (!movementInfo.transport.guid.IsEmpty())
|
|
{
|
|
// transports size limited
|
|
// (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
|
|
if (movementInfo.transport.pos.GetPositionX() > 50 || movementInfo.transport.pos.GetPositionY() > 50 || movementInfo.transport.pos.GetPositionZ() > 50)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!Trinity::IsValidMapCoord(movementInfo.pos.GetPositionX() + movementInfo.transport.pos.GetPositionX(), movementInfo.pos.GetPositionY() + movementInfo.transport.pos.GetPositionY(),
|
|
movementInfo.pos.GetPositionZ() + movementInfo.transport.pos.GetPositionZ(), movementInfo.pos.GetOrientation() + movementInfo.transport.pos.GetOrientation()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if we boarded a transport, add us to it
|
|
if (plrMover)
|
|
{
|
|
if (!plrMover->GetTransport())
|
|
{
|
|
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
|
|
transport->AddPassenger(plrMover);
|
|
}
|
|
else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid)
|
|
{
|
|
plrMover->GetTransport()->RemovePassenger(plrMover);
|
|
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
|
|
transport->AddPassenger(plrMover);
|
|
else
|
|
movementInfo.ResetTransport();
|
|
}
|
|
}
|
|
|
|
if (!mover->GetTransport() && !mover->GetVehicle())
|
|
{
|
|
GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid);
|
|
if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT)
|
|
movementInfo.transport.guid.Clear();
|
|
}
|
|
}
|
|
else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave
|
|
plrMover->m_transport->RemovePassenger(plrMover);
|
|
|
|
// fall damage generation (ignore in flight case that can be triggered also at lags in moment teleportation to another map).
|
|
if (opcode == CMSG_MOVE_FALL_LAND && plrMover && !plrMover->IsInFlight())
|
|
plrMover->HandleFall(movementInfo);
|
|
|
|
if (plrMover && ((movementInfo.flags & MOVEMENTFLAG_SWIMMING) != 0) != plrMover->IsInWater())
|
|
{
|
|
// now client not include swimming flag in case jumping under water
|
|
plrMover->SetInWater(!plrMover->IsInWater() || plrMover->GetBaseMap()->IsUnderWater(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY(), movementInfo.pos.GetPositionZ()));
|
|
}
|
|
|
|
uint32 mstime = getMSTime();
|
|
/*----------------------*/
|
|
if (m_clientTimeDelay == 0)
|
|
m_clientTimeDelay = mstime - movementInfo.time;
|
|
|
|
/* process position-change */
|
|
movementInfo.time = movementInfo.time + m_clientTimeDelay + MOVEMENT_PACKET_TIME_DELAY;
|
|
|
|
movementInfo.guid = mover->GetGUID();
|
|
mover->m_movementInfo = movementInfo;
|
|
|
|
// Some vehicles allow the passenger to turn by himself
|
|
if (Vehicle* vehicle = mover->GetVehicle())
|
|
{
|
|
if (VehicleSeatEntry const* seat = vehicle->GetSeatForPassenger(mover))
|
|
{
|
|
if (seat->Flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING)
|
|
{
|
|
if (movementInfo.pos.GetOrientation() != mover->GetOrientation())
|
|
{
|
|
mover->SetOrientation(movementInfo.pos.GetOrientation());
|
|
mover->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_TURNING);
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
mover->UpdatePosition(movementInfo.pos);
|
|
|
|
WorldPackets::Movement::MoveUpdate moveUpdate;
|
|
moveUpdate.movementInfo = &mover->m_movementInfo;
|
|
mover->SendMessageToSet(moveUpdate.Write(), _player);
|
|
|
|
if (plrMover) // nothing is charmed, or player charmed
|
|
{
|
|
if (plrMover->IsSitState() && (movementInfo.flags & (MOVEMENTFLAG_MASK_MOVING | MOVEMENTFLAG_MASK_TURNING)))
|
|
plrMover->SetStandState(UNIT_STAND_STATE_STAND);
|
|
|
|
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
|
|
|
|
if (movementInfo.pos.GetPositionZ() < MAX_MAP_DEPTH)
|
|
{
|
|
if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player)))
|
|
{
|
|
// 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 (plrMover->IsAlive())
|
|
{
|
|
plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth());
|
|
// player can be alive if GM/etc
|
|
// change the death state to CORPSE to prevent the death timer from
|
|
// starting in the next player update
|
|
if (!plrMover->IsAlive())
|
|
plrMover->KillPlayer();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleForceSpeedChangeAck(WorldPackets::Movement::MovementSpeedAck& packet)
|
|
{
|
|
|
|
GetPlayer()->ValidateMovementInfo(&packet.Ack.movementInfo);
|
|
|
|
// now can skip not our packet
|
|
if (_player->GetGUID() != packet.Ack.movementInfo.guid)
|
|
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;
|
|
|
|
static char const* const move_type_name[MAX_MOVE_TYPE] =
|
|
{
|
|
"Walk",
|
|
"Run",
|
|
"RunBack",
|
|
"Swim",
|
|
"SwimBack",
|
|
"TurnRate",
|
|
"Flight",
|
|
"FlightBack",
|
|
"PitchRate"
|
|
};
|
|
|
|
OpcodeClient opcode = packet.GetOpcode();
|
|
switch (opcode)
|
|
{
|
|
|
|
case CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK: move_type = MOVE_WALK; break;
|
|
case CMSG_MOVE_FORCE_RUN_SPEED_CHANGE_ACK: move_type = MOVE_RUN; break;
|
|
case CMSG_MOVE_FORCE_RUN_BACK_SPEED_CHANGE_ACK: move_type = MOVE_RUN_BACK; break;
|
|
case CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK: move_type = MOVE_SWIM; break;
|
|
case CMSG_MOVE_FORCE_SWIM_BACK_SPEED_CHANGE_ACK: move_type = MOVE_SWIM_BACK; break;
|
|
case CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK: move_type = MOVE_TURN_RATE; break;
|
|
case CMSG_MOVE_FORCE_FLIGHT_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT; break;
|
|
case CMSG_MOVE_FORCE_FLIGHT_BACK_SPEED_CHANGE_ACK: move_type = MOVE_FLIGHT_BACK; break;
|
|
case CMSG_MOVE_FORCE_PITCH_RATE_CHANGE_ACK: move_type = MOVE_PITCH_RATE; break;
|
|
|
|
default:
|
|
TC_LOG_ERROR("network", "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[move_type] > 0)
|
|
{
|
|
--_player->m_forced_speed_changes[move_type];
|
|
if (_player->m_forced_speed_changes[move_type] > 0)
|
|
return;
|
|
}
|
|
|
|
if (!_player->GetTransport() && std::fabs(_player->GetSpeed(move_type) - packet.Speed) > 0.01f)
|
|
{
|
|
if (_player->GetSpeed(move_type) > packet.Speed) // must be greater - just correct
|
|
{
|
|
TC_LOG_ERROR("network", "%sSpeedChange player %s is NOT correct (must be %f instead %f), force set to correct value",
|
|
move_type_name[move_type], _player->GetName().c_str(), _player->GetSpeed(move_type), packet.Speed);
|
|
_player->SetSpeed(move_type, _player->GetSpeedRate(move_type), true);
|
|
}
|
|
else // must be lesser - cheating
|
|
{
|
|
TC_LOG_DEBUG("misc", "Player %s from account id %u kicked for incorrect speed (must be %f instead %f)",
|
|
_player->GetName().c_str(), _player->GetSession()->GetAccountId(), _player->GetSpeed(move_type), packet.Speed);
|
|
_player->GetSession()->KickPlayer();
|
|
}
|
|
}
|
|
}
|
|
|
|
void WorldSession::HandleSetActiveMoverOpcode(WorldPackets::Movement::SetActiveMover& packet)
|
|
{
|
|
if (GetPlayer()->IsInWorld())
|
|
if (_player->m_mover->GetGUID() != packet.ActiveMover)
|
|
TC_LOG_DEBUG("network", "HandleSetActiveMoverOpcode: incorrect mover guid: mover is %s and should be %s" , packet.ActiveMover.ToString().c_str(), _player->m_mover->GetGUID().ToString().c_str());
|
|
}
|
|
|
|
void WorldSession::HandleMountSpecialAnimOpcode(WorldPacket& /*recvData*/)
|
|
{
|
|
WorldPacket data(SMSG_SPECIAL_MOUNT_ANIM, 8);
|
|
data << GetPlayer()->GetGUID();
|
|
|
|
GetPlayer()->SendMessageToSet(&data, false);
|
|
}
|
|
|
|
void WorldSession::HandleMoveKnockBackAck(WorldPackets::Movement::MovementAckMessage& movementAck)
|
|
{
|
|
GetPlayer()->ValidateMovementInfo(&movementAck.Ack.movementInfo);
|
|
|
|
if (_player->m_mover->GetGUID() != movementAck.Ack.movementInfo.guid)
|
|
return;
|
|
|
|
_player->m_movementInfo = movementAck.Ack.movementInfo;
|
|
|
|
WorldPackets::Movement::MoveUpdateKnockBack updateKnockBack;
|
|
updateKnockBack.movementInfo = &_player->m_movementInfo;
|
|
_player->SendMessageToSet(updateKnockBack.Write(), false);
|
|
}
|
|
|
|
void WorldSession::HandleMovementAckMessage(WorldPackets::Movement::MovementAckMessage& movementAck)
|
|
{
|
|
GetPlayer()->ValidateMovementInfo(&movementAck.Ack.movementInfo);
|
|
}
|
|
|
|
void WorldSession::HandleSummonResponseOpcode(WorldPacket& recvData)
|
|
{
|
|
if (!_player->IsAlive() || _player->IsInCombat())
|
|
return;
|
|
|
|
ObjectGuid summoner_guid;
|
|
bool agree;
|
|
recvData >> summoner_guid;
|
|
recvData >> agree;
|
|
|
|
_player->SummonIfPossible(agree);
|
|
}
|
|
|
|
void WorldSession::HandleSetCollisionHeightAck(WorldPackets::Movement::MoveSetCollisionHeightAck& setCollisionHeightAck)
|
|
{
|
|
GetPlayer()->ValidateMovementInfo(&setCollisionHeightAck.Data.movementInfo);
|
|
}
|
|
|
|
void WorldSession::HandleMoveTimeSkippedOpcode(WorldPackets::Movement::MoveTimeSkipped& /*moveTimeSkipped*/)
|
|
{
|
|
}
|