diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 495645eda5..f104d4ce89 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -68,6 +68,7 @@ #include "MiscPackets.h" #include "MotionMaster.h" #include "MovementStructures.h" +#include "MovementPackets.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -1534,6 +1535,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // this will be used instead of the current location in SaveToDB m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); + m_teleport_options = options; SetFallInformation(0, GetPositionZ()); m_teleport_transport = transport; @@ -1558,6 +1560,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati // far teleport to another map Map* oldmap = IsInWorld() ? GetMap() : nullptr; + // check if we can enter before stopping combat / removing pet / totems / interrupting spells // Check enter rights before map getting to avoid creating instance copy for player @@ -1631,18 +1634,16 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati if (!GetSession()->PlayerLogout()) { // send transfer packets - WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4); - data.WriteBit(0); // unknown + WorldPackets::Movement::TransferPending transferPending; + transferPending.MapID = mapid; if (Transport* transport = GetTransport()) { - data.WriteBit(1); // has transport - data << GetMapId() << transport->GetEntry(); + transferPending.Ship = boost::in_place(); + transferPending.Ship->ID = transport->GetEntry(); + transferPending.Ship->OriginMapID = GetMapId(); } - else - data.WriteBit(0); // has transport - data << uint32(mapid); - SendDirectMessage(&data); + SendDirectMessage(transferPending.Write()); } // remove from old map now @@ -1651,21 +1652,17 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati m_teleport_dest = WorldLocation(mapid, x, y, z, orientation); m_teleport_transport = transport; + m_teleport_options = options; SetFallInformation(0, GetPositionZ()); // if the player is saved before worldportack (at logout for example) // this will be used instead of the current location in SaveToDB if (!GetSession()->PlayerLogout()) { - WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4); - data << float(m_teleport_dest.GetPositionX()); - data << float(m_teleport_dest.GetOrientation()); - data << float(m_teleport_dest.GetPositionZ()); - data << uint32(mapid); - data << float(m_teleport_dest.GetPositionY()); - - SendDirectMessage(&data); - SendSavedInstances(); + WorldPackets::Movement::SuspendToken suspendToken; + suspendToken.SequenceIndex = m_movementCounter; // not incrementing + suspendToken.Unk = false; + SendDirectMessage(suspendToken.Write()); } // move packet sent by client always after far teleport diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 2079bebb3b..506c7dda80 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -25,11 +25,12 @@ #include "MapManager.h" #include "MotionMaster.h" #include "MovementGenerator.h" +#include "MovementPackets.h" +#include "MovementStructures.h" #include "Transport.h" #include "Battleground.h" #include "InstanceSaveMgr.h" #include "ObjectMgr.h" -#include "MovementStructures.h" #include "Vehicle.h" #include "GameTime.h" #include "SpellAuraEffects.h" @@ -217,6 +218,20 @@ void WorldSession::HandleMoveWorldportAck() GetPlayer()->ProcessDelayedOperations(); } +void WorldSession::HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTokenResponse& /*suspendTokenResponse*/) +{ + if (!_player->IsBeingTeleportedFar()) + return; + + WorldLocation const& loc = GetPlayer()->GetTeleportDest(); + WorldPackets::Movement::NewWorld packet; + packet.MapID = loc.GetMapId(); + packet.Pos = loc; + SendPacket(packet.Write()); + + _player->SendSavedInstances(); +} + void WorldSession::HandleMoveTeleportAck(WorldPacket& recvPacket) { TC_LOG_DEBUG("network", "MSG_MOVE_TELEPORT_ACK"); diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index e7cabd97a0..3df8ba1680 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -23,6 +23,7 @@ #include "GuildPackets.h" #include "LFGPackets.h" #include "MiscPackets.h" +#include "MovementPackets.h" #include "NPCPackets.h" #include "QuestPackets.h" #include "SystemPackets.h" diff --git a/src/server/game/Server/Packets/MovementPackets.cpp b/src/server/game/Server/Packets/MovementPackets.cpp new file mode 100644 index 0000000000..791c0841e6 --- /dev/null +++ b/src/server/game/Server/Packets/MovementPackets.cpp @@ -0,0 +1,66 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 . + */ + +#include "MovementPackets.h" +#include "MoveSpline.h" +#include "MoveSplineFlag.h" +#include "MovementTypedefs.h" +#include "PacketUtilities.h" +#include "Unit.h" + +WorldPacket const* WorldPackets::Movement::TransferPending::Write() +{ + _worldPacket.WriteBit(TransferSpellID.is_initialized()); + _worldPacket.WriteBit(Ship.is_initialized()); + if (Ship) + { + _worldPacket << int32(Ship->OriginMapID); + _worldPacket << uint32(Ship->ID); + } + + if (TransferSpellID) + _worldPacket << int32(*TransferSpellID); + + _worldPacket << int32(MapID); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +WorldPacket const* WorldPackets::Movement::SuspendToken::Write() +{ + _worldPacket.WriteBit(Unk); + _worldPacket << uint32(SequenceIndex); + _worldPacket.FlushBits(); + + return &_worldPacket; +} + +void WorldPackets::Movement::SuspendTokenResponse::Read() +{ + _worldPacket >> SequenceIndex; +} + +WorldPacket const* WorldPackets::Movement::NewWorld::Write() +{ + _worldPacket << Pos.GetPositionX(); + _worldPacket << Pos.GetOrientation(); + _worldPacket << Pos.GetPositionY(); + _worldPacket << int32(MapID); + _worldPacket << Pos.GetPositionZ(); + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/MovementPackets.h b/src/server/game/Server/Packets/MovementPackets.h new file mode 100644 index 0000000000..9304a61e9d --- /dev/null +++ b/src/server/game/Server/Packets/MovementPackets.h @@ -0,0 +1,81 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * 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 . + */ + +#ifndef MovementPackets_h__ +#define MovementPackets_h__ + +#include "Packet.h" +#include "Object.h" +#include "Optional.h" + +namespace WorldPackets +{ + namespace Movement + { + class TransferPending final : public ServerPacket + { + struct ShipTransferPending + { + uint32 ID = 0; ///< gameobject_template.entry of the transport the player is teleporting on + int32 OriginMapID = -1; ///< Map id the player is currently on (before teleport) + }; + + public: + TransferPending() : ServerPacket(SMSG_TRANSFER_PENDING, 12) { } + + WorldPacket const* Write() override; + + int32 MapID = -1; + Optional Ship; + Optional TransferSpellID; + }; + + class SuspendToken final : public ServerPacket + { + public: + SuspendToken() : ServerPacket(SMSG_SUSPEND_TOKEN, 4 + 1) { } + + WorldPacket const* Write() override; + + uint32 SequenceIndex = 1; + bool Unk = false; + }; + + class SuspendTokenResponse final : public ClientPacket + { + public: + SuspendTokenResponse(WorldPacket&& packet) : ClientPacket(CMSG_SUSPEND_TOKEN_RESPONSE, std::move(packet)) { } + + void Read() override; + + uint32 SequenceIndex = 0; + }; + + class NewWorld final : public ServerPacket + { + public: + NewWorld() : ServerPacket(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + int32 MapID = 0; + Position Pos; + }; + } +} + +#endif // MovementPackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index a86be935b8..5e7cc41d99 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -603,7 +603,7 @@ void OpcodeTable::Initialize() DEFINE_HANDLER(CMSG_SUBMIT_COMPLAIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SUGGESTION_SUBMIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_SUMMON_RESPONSE, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); - DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_HANDLER(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_TRANSFER, PROCESS_THREADUNSAFE, &WorldSession::HandleSuspendTokenResponse ); DEFINE_HANDLER(CMSG_SWAP_INV_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSwapInvItemOpcode ); DEFINE_HANDLER(CMSG_SWAP_ITEM, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandleSwapItem ); DEFINE_HANDLER(CMSG_SYNC_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -1279,7 +1279,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_NEVER, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, CONNECTION_TYPE_INSTANCE); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 68aea619be..51718bf910 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -139,6 +139,11 @@ namespace WorldPackets class OpeningCinematic; } + namespace Movement + { + class SuspendTokenResponse; + } + namespace NPC { class Hello; @@ -700,6 +705,7 @@ class TC_GAME_API WorldSession void HandleMoveWorldportAckOpcode(WorldPacket& recvPacket); void HandleMoveWorldportAck(); // for server-side calls + void HandleSuspendTokenResponse(WorldPackets::Movement::SuspendTokenResponse& suspendTokenResponse); void HandleMovementOpcodes(WorldPacket& recvPacket); void HandleSetActiveMoverOpcode(WorldPacket& recvData);