diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index beb0bc431..9e481658b 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -417,6 +417,8 @@ Player::Player(WorldSession* session): Unit(), m_mover(this) GetObjectVisibilityContainer().InitForPlayer(); sScriptMgr->OnConstructPlayer(this); + + m_expectingChangeTransport = false; } Player::~Player() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 11bb75df4..b7e35ca53 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2633,6 +2633,9 @@ public: std::string GetDebugInfo() const override; + bool IsExpectingChangeTransport() const { return m_expectingChangeTransport; } + void SetExpectingChangeTransport(bool state) { m_expectingChangeTransport = state; } + /*********************************************************/ /*** SPELL QUEUE SYSTEM ***/ /*********************************************************/ @@ -3013,6 +3016,8 @@ private: PlayerSettingMap m_charSettingsMap; Seconds m_creationTime; + + bool m_expectingChangeTransport; }; void AddItemsSetItem(Player* player, Item* item); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4c9d6b60c..7bd1f97f8 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -19542,6 +19542,9 @@ void Unit::_ExitVehicle(Position const* exitPosition) if (!vehicleBase) return; + if (IsPlayer()) + ToPlayer()->SetExpectingChangeTransport(true); + SetControlled(false, UNIT_STATE_ROOT); // SMSG_MOVE_FORCE_UNROOT, ~MOVEMENTFLAG_ROOT Position pos; diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp index b0752ecd2..65ef2bdec 100644 --- a/src/server/game/Entities/Vehicle/Vehicle.cpp +++ b/src/server/game/Entities/Vehicle/Vehicle.cpp @@ -423,7 +423,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId) if (_me->IsInWorld()) { unit->SendClearTarget(); // SMSG_BREAK_TARGET - unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures) + unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures) + if (unit->IsPlayer()) + unit->ToPlayer()->SetExpectingChangeTransport(true); // also adds MOVEMENTFLAG_ROOT Movement::MoveSplineInit init(unit); init.DisableTransportPathTransformations(); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 537756706..66aa1b590 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -376,6 +376,9 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData) return; } + if (opcode == CMSG_MOVE_FALL_RESET || opcode == CMSG_MOVE_CHNG_TRANSPORT) + return; + /* process position-change */ WorldPacket data(opcode, recvData.size()); WriteMovementInfo(&data, &movementInfo); @@ -516,7 +519,10 @@ bool WorldSession::VerifyMovementInfo(MovementInfo const& movementInfo, Player* } if (!mover->movespline->Finalized()) - return false; + { + if (!mover->movespline->isBoarding() || (opcode != CMSG_FORCE_MOVE_UNROOT_ACK && opcode != CMSG_FORCE_MOVE_ROOT_ACK)) + return false; + } // Xinef: do not allow to move with UNIT_FLAG_DISABLE_MOVE if (mover->HasUnitFlag(UNIT_FLAG_DISABLE_MOVE)) @@ -958,7 +964,8 @@ void WorldSession::ComputeNewClockDelta() void WorldSession::HandleMoveRootAck(WorldPacket& recvData) { - LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging((Opcodes)recvData.GetOpcode())); + Opcodes opcode = (Opcodes)recvData.GetOpcode(); + LOG_DEBUG("network", "WORLD: {}", GetOpcodeNameForLogging(opcode)); ObjectGuid guid; uint32 counter; @@ -973,7 +980,7 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData) if (mover->GetGUID() != guid) return; - if (recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case + if (opcode == CMSG_FORCE_MOVE_UNROOT_ACK) // unroot case { if (!mover->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT)) return; @@ -987,7 +994,10 @@ void WorldSession::HandleMoveRootAck(WorldPacket& recvData) if (!ProcessMovementInfo(movementInfo, mover, _player, recvData)) return; - WorldPacket data(recvData.GetOpcode() == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT); + if (_player->IsExpectingChangeTransport()) + return; + + WorldPacket data(opcode == CMSG_FORCE_MOVE_UNROOT_ACK ? MSG_MOVE_UNROOT : MSG_MOVE_ROOT); WriteMovementInfo(&data, &movementInfo); mover->SendMessageToSet(&data, _player); } diff --git a/src/server/game/Handlers/TaxiHandler.cpp b/src/server/game/Handlers/TaxiHandler.cpp index 8a76a2bd6..03a5ba89c 100644 --- a/src/server/game/Handlers/TaxiHandler.cpp +++ b/src/server/game/Handlers/TaxiHandler.cpp @@ -198,54 +198,70 @@ void WorldSession::HandleActivateTaxiExpressOpcode(WorldPacket& recvData) void WorldSession::HandleMoveSplineDoneOpcode(WorldPacket& recvData) { - ObjectGuid guid; // used only for proper packet read + ObjectGuid guid; // used only for proper packet read + MovementInfo movementInfo; // used only for proper packet read + uint32 movementCounter; // spline counter + + Unit* mover = _player->m_mover; + recvData >> guid.ReadAsPacked(); - - MovementInfo movementInfo; // used only for proper packet read - movementInfo.guid = guid; ReadMovementInfo(recvData, &movementInfo); + recvData >> movementCounter; - recvData.read_skip(); // spline id - - // in taxi flight packet received in 2 case: - // 1) end taxi path in far (multi-node) flight - // 2) switch from one map to other in case multim-map taxi path - // we need process only (1) - - uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); - if (curDest) + if (_player->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_TAXI_FLIGHT)) // taxi spline case { - TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); + // in taxi flight packet received in 2 case: + // 1) end taxi path in far (multi-node) flight + // 2) switch from one map to other in case multim-map taxi path + // we need process only (1) - // far teleport case - if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + uint32 curDest = GetPlayer()->m_taxi.GetTaxiDestination(); + if (curDest) { - if (FlightPathMovementGenerator* flight = dynamic_cast(GetPlayer()->GetMotionMaster()->top())) - { - // short preparations to continue flight - flight->SetCurrentNodeAfterTeleport(); - TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; - flight->SkipCurrentNode(); + TaxiNodesEntry const* curDestNode = sTaxiNodesStore.LookupEntry(curDest); - GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI); + // far teleport case + if (curDestNode && curDestNode->map_id != GetPlayer()->GetMapId() && GetPlayer()->GetMotionMaster()->GetCurrentMovementGeneratorType() == FLIGHT_MOTION_TYPE) + { + if (FlightPathMovementGenerator* flight = dynamic_cast(GetPlayer()->GetMotionMaster()->top())) + { + // short preparations to continue flight + flight->SetCurrentNodeAfterTeleport(); + TaxiPathNodeEntry const* node = flight->GetPath()[flight->GetCurrentNode()]; + flight->SkipCurrentNode(); + + GetPlayer()->TeleportTo(curDestNode->map_id, node->x, node->y, node->z, GetPlayer()->GetOrientation(), TELE_TO_NOT_LEAVE_TAXI); + } } + + return; } + // at this point only 1 node is expected (final destination) + if (GetPlayer()->m_taxi.GetPath().size() != 1) + { + return; + } + + GetPlayer()->CleanupAfterTaxiFlight(); + GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ()); + if (GetPlayer()->pvpInfo.IsHostile) + { + GetPlayer()->CastSpell(GetPlayer(), 2479, true); + } return; } - // at this point only 1 node is expected (final destination) - if (GetPlayer()->m_taxi.GetPath().size() != 1) - { + if (mover->GetGUID() != guid) return; - } - GetPlayer()->CleanupAfterTaxiFlight(); - GetPlayer()->SetFallInformation(GameTime::GetGameTime().count(), GetPlayer()->GetPositionZ()); - if (GetPlayer()->pvpInfo.IsHostile) - { - GetPlayer()->CastSpell(GetPlayer(), 2479, true); - } + if (!_player->IsExpectingChangeTransport() || !mover->movespline || mover->movespline->GetId() != movementCounter) + return; + + _player->SetExpectingChangeTransport(false); + WorldPacket data(_player->m_movementInfo.HasMovementFlag(MOVEMENTFLAG_ROOT) ? MSG_MOVE_ROOT : MSG_MOVE_UNROOT, recvData.size()); + WriteMovementInfo(&data, &movementInfo); + mover->SendMessageToSet(&data, _player); } void WorldSession::HandleActivateTaxiOpcode(WorldPacket& recvData) diff --git a/src/server/game/Movement/Spline/MoveSpline.h b/src/server/game/Movement/Spline/MoveSpline.h index 5ebe5f5aa..eaba1d53f 100644 --- a/src/server/game/Movement/Spline/MoveSpline.h +++ b/src/server/game/Movement/Spline/MoveSpline.h @@ -117,6 +117,7 @@ namespace Movement [[nodiscard]] bool isCyclic() const { return splineflags.cyclic; } [[nodiscard]] bool isFalling() const { return splineflags.falling; } [[nodiscard]] bool isWalking() const { return splineflags.walkmode; } + [[nodiscard]] bool isBoarding() const { return splineflags.transportEnter || splineflags.transportExit; } [[nodiscard]] Vector3 FinalDestination() const { return Initialized() ? spline.getPoint(spline.last()) : Vector3(); } [[nodiscard]] Vector3 CurrentDestination() const { return Initialized() ? spline.getPoint(point_Idx + 1) : Vector3(); } [[nodiscard]] int32 currentPathIdx() const;