diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 1daef4759..007dd7924 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -3863,15 +3863,15 @@ namespace Game.Entities } else { - stmt.AddValue(index++, (ushort)GetTeleportDest().GetMapId()); + stmt.AddValue(index++, (ushort)GetTeleportDest().Location.GetMapId()); stmt.AddValue(index++, 0); stmt.AddValue(index++, (byte)GetDungeonDifficultyID()); stmt.AddValue(index++, (byte)GetRaidDifficultyID()); stmt.AddValue(index++, (byte)GetLegacyRaidDifficultyID()); - stmt.AddValue(index++, finiteAlways(GetTeleportDest().GetPositionX())); - stmt.AddValue(index++, finiteAlways(GetTeleportDest().GetPositionY())); - stmt.AddValue(index++, finiteAlways(GetTeleportDest().GetPositionZ())); - stmt.AddValue(index++, finiteAlways(GetTeleportDest().GetOrientation())); + stmt.AddValue(index++, finiteAlways(GetTeleportDest().Location.GetPositionX())); + stmt.AddValue(index++, finiteAlways(GetTeleportDest().Location.GetPositionY())); + stmt.AddValue(index++, finiteAlways(GetTeleportDest().Location.GetPositionZ())); + stmt.AddValue(index++, finiteAlways(GetTeleportDest().Location.GetOrientation())); } stmt.AddValue(index++, finiteAlways(GetTransOffsetX())); diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index a19284efc..e96ce697a 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -82,8 +82,7 @@ namespace Game.Entities public byte m_movementForceModMagnitudeChanges; uint m_lastFallTime; float m_lastFallZ; - WorldLocation teleportDest; - uint? m_teleport_instanceId; + TeleportLocation teleportDest; TeleportToOptions m_teleport_options; bool mSemaphoreTeleport_Near; bool mSemaphoreTeleport_Far; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index f9b268ced..1ce41496c 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -1951,33 +1951,42 @@ namespace Game.Entities //Movement bool IsCanDelayTeleport() { return m_bCanDelayTeleport; } + void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; } + bool IsHasDelayedTeleport() { return m_bHasDelayedTeleport; } + void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; } - public bool TeleportTo(WorldLocation loc, TeleportToOptions options = 0, uint? instanceId = null) + + public bool TeleportTo(uint mapid, float x, float y, float z, float orientation, TeleportToOptions options = TeleportToOptions.None, uint? instanceId = null) { - return TeleportTo(loc.GetMapId(), loc.posX, loc.posY, loc.posZ, loc.Orientation, options, instanceId); + return TeleportTo(new TeleportLocation() { Location = new WorldLocation(mapid, x, y, z, orientation), InstanceId = instanceId }, options); } - public bool TeleportTo(uint mapid, float x, float y, float z, float orientation, TeleportToOptions options = 0, uint? instanceId = null) + + public bool TeleportTo(WorldLocation loc, TeleportToOptions options = TeleportToOptions.None, uint? instanceId = null) { - if (!GridDefines.IsValidMapCoord(mapid, x, y, z, orientation)) + return TeleportTo(new TeleportLocation() { Location = loc, InstanceId = instanceId }, options); + } + + public bool TeleportTo(TeleportLocation teleportLocation, TeleportToOptions options = TeleportToOptions.None) + { + if (!GridDefines.IsValidMapCoord(teleportLocation.Location)) { - Log.outError(LogFilter.Maps, "TeleportTo: invalid map ({0}) or invalid coordinates (X: {1}, Y: {2}, Z: {3}, O: {4}) given when teleporting player (GUID: {5}, name: {6}, map: {7}, {8}).", - mapid, x, y, z, orientation, GetGUID().ToString(), GetName(), GetMapId(), GetPosition().ToString()); + Log.outError(LogFilter.Maps, $"Player::TeleportTo: Invalid map ({teleportLocation.Location.GetMapId()}) or invalid coordinates ({teleportLocation.Location.ToString()}) given when teleporting player '{GetGUID()}' ({GetName()}, MapID: {GetMapId()}, {GetPosition()})."); return false; } - if (!GetSession().HasPermission(RBACPermissions.SkipCheckDisableMap) && DisableMgr.IsDisabledFor(DisableType.Map, mapid, this)) + if (!GetSession().HasPermission(RBACPermissions.SkipCheckDisableMap) && DisableMgr.IsDisabledFor(DisableType.Map, teleportLocation.Location.GetMapId(), this)) { - Log.outError(LogFilter.Maps, "Player (GUID: {0}, name: {1}) tried to enter a forbidden map {2}", GetGUID().ToString(), GetName(), mapid); - SendTransferAborted(mapid, TransferAbortReason.MapNotAllowed); + Log.outError(LogFilter.Maps, $"Player::TeleportTo: Player '{GetGUID()}' ({GetName()}) tried to enter a forbidden map (MapID: {teleportLocation.Location.GetMapId()})"); + SendTransferAborted(teleportLocation.Location.GetMapId(), TransferAbortReason.MapNotAllowed); return false; } // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later) Pet pet = GetPet(); - MapRecord mEntry = CliDB.MapStorage.LookupByKey(mapid); + MapRecord mEntry = CliDB.MapStorage.LookupByKey(teleportLocation.Location.GetMapId()); // don't let enter Battlegrounds without assigned Battlegroundid (for example through areatrigger)... // don't let gm level > 1 either @@ -1987,7 +1996,7 @@ namespace Game.Entities // client without expansion support if (GetSession().GetExpansion() < mEntry.Expansion()) { - Log.outDebug(LogFilter.Maps, "Player {0} using client without required expansion tried teleport to non accessible map {1}", GetName(), mapid); + Log.outDebug(LogFilter.Maps, $"Player {GetName()} using client without required expansion tried teleport to non accessible map {teleportLocation.Location.GetMapId()}"); ITransport _transport = GetTransport(); if (_transport != null) @@ -1996,11 +2005,11 @@ namespace Game.Entities RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :) } - SendTransferAborted(mapid, TransferAbortReason.InsufExpanLvl, (byte)mEntry.Expansion()); + SendTransferAborted(teleportLocation.Location.GetMapId(), TransferAbortReason.InsufExpanLvl, (byte)mEntry.Expansion()); return false; // normal client can't teleport to this map... } else - Log.outDebug(LogFilter.Maps, "Player {0} is being teleported to map {1}", GetName(), mapid); + Log.outDebug(LogFilter.Maps, $"Player {GetName()} is being teleported to map {teleportLocation.Location.GetMapId()}"); if (m_vehicle != null) ExitVehicle(); @@ -2013,18 +2022,17 @@ namespace Game.Entities ITransport transport = GetTransport(); if (transport != null) - { - if (!options.HasAnyFlag(TeleportToOptions.NotLeaveTransport)) - transport.RemovePassenger(this); - } + if (!teleportLocation.TransportGuid.HasValue || teleportLocation.TransportGuid != transport.GetTransportGUID()) + if (!options.HasFlag(TeleportToOptions.NotLeaveTransport)) + transport.RemovePassenger(this); // The player was ported to another map and loses the duel immediately. // We have to perform this check before the teleport, otherwise the // ObjectAccessor won't find the flag. - if (duel != null && GetMapId() != mapid && GetMap().GetGameObject(m_playerData.DuelArbiter) != null) + if (duel != null && GetMapId() != teleportLocation.Location.GetMapId() && GetMap().GetGameObject(m_playerData.DuelArbiter) != null) DuelComplete(DuelCompleteType.Fled); - if (GetMapId() == mapid && (!instanceId.HasValue || GetInstanceId() == instanceId)) + if (GetMapId() == teleportLocation.Location.GetMapId() && (!teleportLocation.InstanceId.HasValue || GetInstanceId() == teleportLocation.InstanceId)) { //lets reset far teleport flag if it wasn't reset during chained teleports SetSemaphoreTeleportFar(false); @@ -2036,8 +2044,7 @@ namespace Game.Entities { SetSemaphoreTeleportNear(true); //lets save teleport destination for player - teleportDest = new WorldLocation(mapid, x, y, z, orientation); - m_teleport_instanceId = null; + teleportDest = teleportLocation; m_teleport_options = options; return true; } @@ -2045,7 +2052,7 @@ namespace Game.Entities if (!options.HasAnyFlag(TeleportToOptions.NotUnSummonPet)) { //same map, only remove pet if out of range for new position - if (pet != null && !pet.IsWithinDist3d(x, y, z, GetMap().GetVisibilityRange())) + if (pet != null && !pet.IsWithinDist3d(teleportLocation.Location, GetMap().GetVisibilityRange())) UnsummonPetTemporaryIfAny(); } @@ -2056,8 +2063,7 @@ namespace Game.Entities CombatStop(); // this will be used instead of the current location in SaveToDB - teleportDest = new WorldLocation(mapid, x, y, z, orientation); - m_teleport_instanceId = null; + teleportDest = teleportLocation; m_teleport_options = options; SetFallInformation(0, GetPositionZ()); @@ -2072,7 +2078,7 @@ namespace Game.Entities { if (GetClass() == Class.Deathknight && GetMapId() == 609 && !IsGameMaster() && !HasSpell(50977)) { - SendTransferAborted(mapid, TransferAbortReason.UniqueMessage, 1); + SendTransferAborted(teleportLocation.Location.GetMapId(), TransferAbortReason.UniqueMessage, 1); return false; } @@ -2082,15 +2088,15 @@ namespace Game.Entities // Check enter rights before map getting to avoid creating instance copy for player // this check not dependent from map instance copy and same for all instance copies of selected map - TransferAbortParams abortParams = Map.PlayerCannotEnter(mapid, this); + TransferAbortParams abortParams = Map.PlayerCannotEnter(teleportLocation.Location.GetMapId(), this); if (abortParams != null) { - SendTransferAborted(mapid, abortParams.Reason, abortParams.Arg, abortParams.MapDifficultyXConditionId); + SendTransferAborted(teleportLocation.Location.GetMapId(), abortParams.Reason, abortParams.Arg, abortParams.MapDifficultyXConditionId); return false; } // Seamless teleport can happen only if cosmetic maps match - if (oldmap == null || (oldmap.GetEntry().CosmeticParentMapID != mapid && GetMapId() != mEntry.CosmeticParentMapID && + if (oldmap == null || (oldmap.GetEntry().CosmeticParentMapID != teleportLocation.Location.GetMapId() && GetMapId() != mEntry.CosmeticParentMapID && !((oldmap.GetEntry().CosmeticParentMapID != -1) ^ (oldmap.GetEntry().CosmeticParentMapID != mEntry.CosmeticParentMapID)))) options &= ~TeleportToOptions.Seamless; @@ -2104,8 +2110,7 @@ namespace Game.Entities { SetSemaphoreTeleportFar(true); //lets save teleport destination for player - teleportDest = new(mapid, x, y, z, orientation); - m_teleport_instanceId = instanceId; + teleportDest = teleportLocation; m_teleport_options = options; return true; } @@ -2123,7 +2128,7 @@ namespace Game.Entities // Note: at Battlegroundjoin Battlegroundid set before teleport // and we already will found "current" Battleground // just need check that this is targeted map or leave - if (bg.GetMapId() != mapid) + if (bg.GetMapId() != teleportLocation.Location.GetMapId()) LeaveBattleground(false); // don't teleport to entry point } @@ -2159,15 +2164,21 @@ namespace Game.Entities { // send transfer packets TransferPending transferPending = new(); - transferPending.MapID = (int)mapid; - transferPending.OldMapPosition = GetPosition(); + transferPending.MapID = (int)teleportLocation.Location.GetMapId(); + transferPending.OldMapPosition = teleportLocation.Location.GetPosition(); - Transport transport1 = (Transport)GetTransport(); - if (transport1 != null) + if (teleportLocation.TransportGuid.HasValue) { TransferPending.ShipTransferPending shipTransferPending = new(); - shipTransferPending.Id = transport1.GetEntry(); - shipTransferPending.OriginMapID = (int)GetMapId(); + TransportSpawn transportSpawn = TransportMgr.GetTransportSpawn(teleportLocation.TransportGuid.Value.GetCounter()); + if (transportSpawn != null) + { + shipTransferPending.Id = transportSpawn.TransportGameObjectId; + if (GetTransport() != null) + shipTransferPending.OriginMapID = (int)GetMapId(); + else + shipTransferPending.OriginMapID = -1; + } transferPending.Ship = shipTransferPending; } @@ -2181,8 +2192,7 @@ namespace Game.Entities if (oldmap != null) oldmap.RemovePlayerFromMap(this, false); - teleportDest = new WorldLocation(mapid, x, y, z, orientation); - m_teleport_instanceId = instanceId; + teleportDest = teleportLocation; m_teleport_options = options; SetFallInformation(0, GetPositionZ()); // if the player is saved before worldportack (at logout for example) @@ -2203,6 +2213,7 @@ namespace Game.Entities } return true; } + public bool TeleportToBGEntryPoint() { if (m_bgData.joinPos.GetMapId() == 0xFFFFFFFF) @@ -7403,7 +7414,6 @@ namespace Game.Entities return false; } - void SetActiveCombatTraitConfigID(int traitConfigId) { SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.ActiveCombatTraitConfigID), (uint)traitConfigId); } void InitPrimaryProfessions() @@ -7629,16 +7639,11 @@ namespace Game.Entities } } - public WorldLocation GetTeleportDest() + public TeleportLocation GetTeleportDest() { return teleportDest; } - public uint? GetTeleportDestInstanceId() - { - return m_teleport_instanceId; - } - public WorldLocation GetHomebind() { return homebind; @@ -7973,4 +7978,11 @@ namespace Game.Entities SetUpdateFieldValue(personalTabard.ModifyValue(personalTabard.BackgroundColor), backgroundColor); } } + + public class TeleportLocation + { + public WorldLocation Location; + public uint? InstanceId; + public ObjectGuid? TransportGuid; + } } \ No newline at end of file diff --git a/Source/Game/Entities/Transport.cs b/Source/Game/Entities/Transport.cs index cd3842cc0..943da30c7 100644 --- a/Source/Game/Entities/Transport.cs +++ b/Source/Game/Entities/Transport.cs @@ -643,7 +643,7 @@ namespace Game.Entities if (oldMapId != newMapId) { UnloadStaticPassengers(); - TeleportPassengersAndHideTransport(newMapId, x, y, z, o); + TeleportPassengersAndHideTransport(newMapId); return true; } else @@ -673,7 +673,7 @@ namespace Game.Entities } } - void TeleportPassengersAndHideTransport(uint newMapid, float x, float y, float z, float o) + void TeleportPassengersAndHideTransport(uint newMapid) { if (newMapid == GetMapId()) { @@ -714,12 +714,11 @@ namespace Game.Entities { float destX, destY, destZ, destO; obj.m_movementInfo.transport.pos.GetPosition(out destX, out destY, out destZ, out destO); - ITransport.CalculatePassengerPosition(ref destX, ref destY, ref destZ, ref destO, x, y, z, o); switch (obj.GetTypeId()) { case TypeId.Player: - if (!obj.ToPlayer().TeleportTo(newMapid, destX, destY, destZ, destO, TeleportToOptions.NotLeaveTransport)) + if (!obj.ToPlayer().TeleportTo(new TeleportLocation() { Location = new WorldLocation(newMapid, destX, destY, destZ, destO), TransportGuid = GetTransGUID() }, TeleportToOptions.NotLeaveTransport)) RemovePassenger(obj); break; case TypeId.DynamicObject: diff --git a/Source/Game/Entities/Unit/Unit.Movement.cs b/Source/Game/Entities/Unit/Unit.Movement.cs index 6684ff02f..ab44ddc6f 100644 --- a/Source/Game/Entities/Unit/Unit.Movement.cs +++ b/Source/Game/Entities/Unit/Unit.Movement.cs @@ -1203,17 +1203,18 @@ namespace Game.Entities } public void NearTeleportTo(float x, float y, float z, float orientation, bool casting = false) { NearTeleportTo(new Position(x, y, z, orientation), casting); } + public void NearTeleportTo(Position pos, bool casting = false) { DisableSpline(); - if (IsTypeId(TypeId.Player)) + TeleportLocation target = new() { Location = new(GetMapId(), pos) }; + if (IsPlayer()) { - WorldLocation target = new(GetMapId(), pos); ToPlayer().TeleportTo(target, (TeleportToOptions.NotLeaveTransport | TeleportToOptions.NotLeaveCombat | TeleportToOptions.NotUnSummonPet | (casting ? TeleportToOptions.Spell : 0))); } else { - SendTeleportPacket(pos); + SendTeleportPacket(target); UpdatePosition(pos, true); UpdateObjectVisibility(); } @@ -1881,7 +1882,7 @@ namespace Game.Entities } //Teleport - public void SendTeleportPacket(Position pos) + public void SendTeleportPacket(TeleportLocation teleportLocation) { // SMSG_MOVE_UPDATE_TELEPORT is sent to nearby players to signal the teleport // SMSG_MOVE_TELEPORT is sent to self in order to trigger CMSG_MOVE_TELEPORT_ACK and update the position server side @@ -1896,20 +1897,11 @@ namespace Game.Entities Player playerMover = GetUnitBeingMoved()?.ToPlayer(); if (playerMover != null) { - float x, y, z, o; - pos.GetPosition(out x, out y, out z, out o); - - ITransport transportBase = GetDirectTransport(); - if (transportBase != null) - transportBase.CalculatePassengerOffset(ref x, ref y, ref z, ref o); - MoveTeleport moveTeleport = new(); moveTeleport.MoverGUID = GetGUID(); - moveTeleport.Pos = new Position(x, y, z, o); - if (GetTransGUID() != ObjectGuid.Empty) - moveTeleport.TransportGUID = GetTransGUID(); - - moveTeleport.Facing = o; + moveTeleport.Pos = teleportLocation.Location; + moveTeleport.TransportGUID = teleportLocation.TransportGuid; + moveTeleport.Facing = teleportLocation.Location.GetOrientation(); moveTeleport.SequenceIndex = m_movementCounter++; playerMover.SendPacket(moveTeleport); @@ -1920,15 +1912,21 @@ namespace Game.Entities // This is the only packet sent for creatures which contains MovementInfo structure // we do not update m_movementInfo for creatures so it needs to be done manually here moveUpdateTeleport.Status.Guid = GetGUID(); - moveUpdateTeleport.Status.Pos.Relocate(pos); moveUpdateTeleport.Status.Time = Time.GetMSTime(); - var transportBase = GetDirectTransport(); - if (transportBase != null) + + if (teleportLocation.TransportGuid.HasValue) { - pos.GetPosition(out float tx, out float ty, out float tz, out float to); - transportBase.CalculatePassengerOffset(ref tx, ref ty, ref tz, ref to); - moveUpdateTeleport.Status.transport.pos.Relocate(tx, ty, tz, to); + Transport transport = GetMap().GetTransport(teleportLocation.TransportGuid.Value); + if (transport == null) + return; + + teleportLocation.Location.GetPosition(out float x, out float y, out float z, out float o); + transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o); + moveUpdateTeleport.Status.Pos.Relocate(x, y, z, o); + moveUpdateTeleport.Status.transport.pos.Relocate(teleportLocation.Location); } + else + moveUpdateTeleport.Status.Pos.Relocate(teleportLocation.Location); } // Broadcast the packet to everyone except self. diff --git a/Source/Game/Handlers/MovementHandler.cs b/Source/Game/Handlers/MovementHandler.cs index 7828d0855..848a9d284 100644 --- a/Source/Game/Handlers/MovementHandler.cs +++ b/Source/Game/Handlers/MovementHandler.cs @@ -246,33 +246,32 @@ namespace Game player.SetSemaphoreTeleportFar(false); // get the teleport destination - WorldLocation loc = player.GetTeleportDest(); + var loc = player.GetTeleportDest(); // possible errors in the coordinate validity check - if (!GridDefines.IsValidMapCoord(loc)) + if (!GridDefines.IsValidMapCoord(loc.Location)) { LogoutPlayer(false); return; } // get the destination map entry, not the current one, this will fix homebind and reset greeting - MapRecord mapEntry = CliDB.MapStorage.LookupByKey(loc.GetMapId()); + MapRecord mapEntry = CliDB.MapStorage.LookupByKey(loc.Location.GetMapId()); // reset instance validity, except if going to an instance inside an instance if (!player.m_InstanceValid && !mapEntry.IsDungeon()) player.m_InstanceValid = true; Map oldMap = player.GetMap(); - Map newMap = GetPlayer().GetTeleportDestInstanceId().HasValue ? Global.MapMgr.FindMap(loc.GetMapId(), GetPlayer().GetTeleportDestInstanceId().Value) : Global.MapMgr.CreateMap(loc.GetMapId(), GetPlayer()); + Map newMap = loc.InstanceId.HasValue ? Global.MapMgr.FindMap(loc.Location.GetMapId(), loc.InstanceId.Value) : Global.MapMgr.CreateMap(loc.Location.GetMapId(), GetPlayer()); - MovementInfo.TransportInfo transportInfo = player.m_movementInfo.transport; ITransport transport = player.GetTransport(); if (transport != null) transport.RemovePassenger(player); if (player.IsInWorld) { - Log.outError(LogFilter.Network, $"Player (Name {player.GetName()}) is still in world when teleported from map {oldMap.GetId()} to new map {loc.GetMapId()}"); + Log.outError(LogFilter.Network, $"Player (Name {player.GetName()}) is still in world when teleported from map {oldMap.GetId()} to new map {loc.Location.GetMapId()}"); oldMap.RemovePlayerFromMap(player, false); } @@ -281,13 +280,13 @@ namespace Game // while the player is in transit, for example the map may get full if (newMap == null || newMap.CannotEnter(player) != null) { - Log.outError(LogFilter.Network, $"Map {loc.GetMapId()} could not be created for {(newMap != null ? newMap.GetMapName() : "Unknown")} ({player.GetGUID()}), porting player to homebind"); + Log.outError(LogFilter.Network, $"Map {loc.Location.GetMapId()} could not be created for {(newMap != null ? newMap.GetMapName() : "Unknown")} ({player.GetGUID()}), porting player to homebind"); player.TeleportTo(player.GetHomebind()); return; } - float z = loc.GetPositionZ() + player.GetHoverOffset(); - player.Relocate(loc.GetPositionX(), loc.GetPositionY(), z, loc.GetOrientation()); + float zOffset = loc.Location.GetPositionZ() + player.GetHoverOffset(); + player.Relocate(loc.Location.GetPositionX(), loc.Location.GetPositionY(), zOffset, loc.Location.GetOrientation()); player.SetFallInformation(0, player.GetPositionZ()); player.ResetMap(); @@ -301,17 +300,27 @@ namespace Game if (!seamlessTeleport) player.SendInitialPacketsBeforeAddToMap(); - // move player between transport copies on each map - Transport newTransport = newMap.GetTransport(transportInfo.guid); - if (newTransport != null) + if (loc.TransportGuid.HasValue) { - player.m_movementInfo.transport = transportInfo; - newTransport.AddPassenger(player); + Transport newTransport = newMap.GetTransport(loc.TransportGuid.Value); + if (newTransport != null) + { + newTransport.AddPassenger(player); + player.m_movementInfo.transport.pos.Relocate(loc.Location); + loc.Location.GetPosition(out float x, out float y, out float z, out float o); + newTransport.CalculatePassengerPosition(ref x, ref y, ref z, ref o); + player.Relocate(x, y, z, o); + } + } + else + { + if (transport != null) + transport.RemovePassenger(player); } if (!player.GetMap().AddPlayerToMap(player, !seamlessTeleport)) { - Log.outError(LogFilter.Network, $"WORLD: failed to teleport player {player.GetName()} ({player.GetGUID()}) to map {loc.GetMapId()} ({(newMap != null ? newMap.GetMapName() : "Unknown")}) because of unknown reason!"); + Log.outError(LogFilter.Network, $"WORLD: failed to teleport player {player.GetName()} ({player.GetGUID()}) to map {loc.Location.GetMapId()} ({(newMap != null ? newMap.GetMapName() : "Unknown")}) because of unknown reason!"); player.ResetMap(); player.SetMap(oldMap); player.TeleportTo(player.GetHomebind()); @@ -440,18 +449,18 @@ namespace Game if (!_player.IsBeingTeleportedFar()) return; - WorldLocation loc = GetPlayer().GetTeleportDest(); + var loc = GetPlayer().GetTeleportDest(); - if (CliDB.MapStorage.LookupByKey(loc.GetMapId()).IsDungeon()) + if (CliDB.MapStorage.LookupByKey(loc.Location.GetMapId()).IsDungeon()) { UpdateLastInstance updateLastInstance = new(); - updateLastInstance.MapID = loc.GetMapId(); + updateLastInstance.MapID = loc.Location.GetMapId(); SendPacket(updateLastInstance); } NewWorld packet = new(); - packet.MapID = loc.GetMapId(); - packet.Loc.Pos = loc; + packet.MapID = loc.Location.GetMapId(); + packet.Loc.Pos = loc.Location; packet.Reason = (uint)(!_player.IsBeingTeleportedSeamlessly() ? NewWorldReason.Normal : NewWorldReason.Seamless); SendPacket(packet); @@ -474,9 +483,21 @@ namespace Game uint old_zone = plMover.GetZoneId(); - WorldLocation dest = plMover.GetTeleportDest(); + var dest = plMover.GetTeleportDest(); - plMover.UpdatePosition(dest, true); + dest.Location.GetPosition(out float x, out float y, out float z, out float o); + if (dest.TransportGuid.HasValue) + { + Transport transport = plMover.GetMap().GetTransport(dest.TransportGuid.Value); + if (transport != null) + { + transport.AddPassenger(plMover); + plMover.m_movementInfo.transport.pos.Relocate(dest.Location.GetPosition()); + transport.CalculatePassengerPosition(ref x, ref y, ref z, ref o); + } + } + + plMover.UpdatePosition(dest.Location, true); plMover.SetFallInformation(0, GetPlayer().GetPositionZ()); uint newzone, newarea;