Core/Transports: Fixed crash happening during teleporting transports

Closes #11793
This commit is contained in:
Shauren
2014-06-13 11:16:17 +02:00
parent c75b7942a8
commit 5804372042
12 changed files with 71 additions and 98 deletions
@@ -48,18 +48,6 @@ DynamicObject::~DynamicObject()
delete _removedAura;
}
void DynamicObject::CleanupsBeforeDelete(bool finalCleanup /* = true */)
{
WorldObject::CleanupsBeforeDelete(finalCleanup);
if (Transport* transport = GetTransport())
{
transport->RemovePassenger(this);
SetTransport(NULL);
m_movementInfo.transport.Reset();
}
}
void DynamicObject::AddToWorld()
{
///- Register the dynamicObject for guid lookup and for caster
@@ -124,14 +112,11 @@ bool DynamicObject::CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spe
Transport* transport = caster->GetTransport();
if (transport)
{
m_movementInfo.transport.guid = GetGUID();
float x, y, z, o;
pos.GetPosition(x, y, z, o);
transport->CalculatePassengerOffset(x, y, z, &o);
m_movementInfo.transport.pos.Relocate(x, y, z, o);
SetTransport(transport);
// This object must be added to transport before adding to map for the client to properly display it
transport->AddPassenger(this);
}
@@ -41,8 +41,6 @@ class DynamicObject : public WorldObject, public GridObject<DynamicObject>, publ
void AddToWorld();
void RemoveFromWorld();
void CleanupsBeforeDelete(bool finalCleanup = true) override;
bool CreateDynamicObject(uint32 guidlow, Unit* caster, uint32 spellId, Position const& pos, float radius, DynamicObjectType type);
void Update(uint32 p_time);
void Remove();
@@ -98,20 +98,12 @@ std::string GameObject::GetAIName() const
return "";
}
void GameObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
void GameObject::CleanupsBeforeDelete(bool finalCleanup)
{
if (IsInWorld())
RemoveFromWorld();
WorldObject::CleanupsBeforeDelete(finalCleanup);
if (m_uint32Values) // field array can be not exist if GameOBject not loaded
RemoveFromOwner();
if (GetTransport() && !ToTransport())
{
GetTransport()->RemovePassenger(this);
SetTransport(NULL);
m_movementInfo.transport.Reset();
}
}
void GameObject::RemoveFromOwner()
@@ -705,7 +697,7 @@ void GameObject::getFishLoot(Loot* fishloot, Player* loot_owner)
{
//subzone no result,use zone loot
fishloot->FillLoot(zone, LootTemplates_Fishing, loot_owner, true, true);
//use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
//use zone 1 as default, somewhere fishing got nothing,becase subzone and zone not set, like Off the coast of Storm Peaks.
if (fishloot->empty())
fishloot->FillLoot(defaultzone, LootTemplates_Fishing, loot_owner, true, true);
}
+4 -1
View File
@@ -1163,6 +1163,9 @@ void WorldObject::CleanupsBeforeDelete(bool /*finalCleanup*/)
{
if (IsInWorld())
RemoveFromWorld();
if (Transport* transport = GetTransport())
transport->RemovePassenger(this);
}
void WorldObject::_Create(uint32 guidlow, HighGuid guidhigh, uint32 phaseMask)
@@ -1215,7 +1218,7 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool
float sizefactor = GetObjectSize() + obj->GetObjectSize();
float maxdist = dist2compare + sizefactor;
if (m_transport && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == m_transport->GetGUIDLow())
if (GetTransport() && obj->GetTransport() && obj->GetTransport()->GetGUIDLow() == GetTransport()->GetGUIDLow())
{
float dtx = m_movementInfo.transport.pos.m_positionX - obj->m_movementInfo.transport.pos.m_positionX;
float dty = m_movementInfo.transport.pos.m_positionY - obj->m_movementInfo.transport.pos.m_positionY;
+13 -21
View File
@@ -2131,11 +2131,9 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
{
TC_LOG_DEBUG("maps", "Player %s using client without required expansion tried teleport to non accessible map %u", GetName().c_str(), mapid);
if (GetTransport())
if (Transport* transport = GetTransport())
{
m_transport->RemovePassenger(this);
m_transport = NULL;
m_movementInfo.transport.Reset();
transport->RemovePassenger(this);
RepopAtGraveyard(); // teleport to near graveyard if on transport, looks blizz like :)
}
@@ -2153,16 +2151,12 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
SetUnitMovementFlags(GetUnitMovementFlags() & MOVEMENTFLAG_MASK_HAS_PLAYER_STATUS_OPCODE);
DisableSpline();
if (m_transport)
if (Transport* transport = GetTransport())
{
if (options & TELE_TO_NOT_LEAVE_TRANSPORT)
AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
else
{
m_transport->RemovePassenger(this);
m_transport = NULL;
m_movementInfo.transport.Reset();
}
transport->RemovePassenger(this);
}
// The player was ported to another map and loses the duel immediately.
@@ -2297,8 +2291,8 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
// send transfer packets
WorldPacket data(SMSG_TRANSFER_PENDING, 4 + 4 + 4);
data << uint32(mapid);
if (m_transport)
data << m_transport->GetEntry() << GetMapId();
if (Transport* transport = GetTransport())
data << transport->GetEntry() << GetMapId();
GetSession()->SendPacket(&data);
}
@@ -2316,7 +2310,7 @@ bool Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientati
{
WorldPacket data(SMSG_NEW_WORLD, 4 + 4 + 4 + 4 + 4);
data << uint32(mapid);
if (m_transport)
if (GetTransport())
data << m_movementInfo.transport.pos.PositionXYZOStream();
else
data << m_teleport_dest.PositionXYZOStream();
@@ -17401,15 +17395,15 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
{
uint64 transGUID = MAKE_NEW_GUID(transLowGUID, 0, HIGHGUID_MO_TRANSPORT);
Transport* transport = NULL;
if (GameObject* go = HashMapHolder<GameObject>::Find(transGUID))
m_transport = go->ToTransport();
transport = go->ToTransport();
if (m_transport)
if (transport)
{
m_movementInfo.transport.guid = transGUID;
float x = fields[26].GetFloat(), y = fields[27].GetFloat(), z = fields[28].GetFloat(), o = fields[29].GetFloat();
m_movementInfo.transport.pos.Relocate(x, y, z, o);
m_transport->CalculatePassengerPosition(x, y, z, &o);
transport->CalculatePassengerPosition(x, y, z, &o);
if (!Trinity::IsValidMapCoord(x, y, z, o) ||
// transport size limited
@@ -17420,7 +17414,6 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
TC_LOG_ERROR("entities.player", "Player (guidlow %d) have invalid transport coordinates (X: %f Y: %f Z: %f O: %f). Teleport to bind location.",
guid, x, y, z, o);
m_transport = NULL;
m_movementInfo.transport.Reset();
RelocateToHomebind();
@@ -17428,10 +17421,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
else
{
Relocate(x, y, z, o);
mapId = m_transport->GetMapId();
mapId = transport->GetMapId();
m_transport->AddPassenger(this);
AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
transport->AddPassenger(this);
}
}
else
@@ -35,7 +35,7 @@
Transport::Transport() : GameObject(),
_transportInfo(NULL), _isMoving(true), _pendingStop(false),
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false)
_triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengerTeleportItr(_passengers.begin())
{
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
}
@@ -107,9 +107,6 @@ void Transport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
while (!_passengers.empty())
{
WorldObject* obj = *_passengers.begin();
obj->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
obj->m_movementInfo.transport.Reset();
obj->SetTransport(NULL);
RemovePassenger(obj);
}
@@ -231,6 +228,9 @@ void Transport::AddPassenger(WorldObject* passenger)
if (_passengers.insert(passenger).second)
{
passenger->SetTransport(this);
passenger->m_movementInfo.AddMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
passenger->m_movementInfo.transport.guid = GetGUID();
TC_LOG_DEBUG("entities.transport", "Object %s boarded transport %s.", passenger->GetName().c_str(), GetName().c_str());
if (Player* plr = passenger->ToPlayer())
@@ -240,8 +240,27 @@ void Transport::AddPassenger(WorldObject* passenger)
void Transport::RemovePassenger(WorldObject* passenger)
{
if (_passengers.erase(passenger) || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
bool erased = false;
if (_passengerTeleportItr != _passengers.end())
{
PassengerSet::iterator itr = _passengers.find(passenger);
if (itr != _passengers.end())
{
if (itr == _passengerTeleportItr)
++_passengerTeleportItr;
_passengers.erase(itr);
erased = true;
}
}
else
erased = _passengers.erase(passenger) > 0;
if (erased || _staticPassengers.erase(passenger)) // static passenger can remove itself in case of grid unload
{
passenger->SetTransport(NULL);
passenger->m_movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
passenger->m_movementInfo.transport.Reset();
TC_LOG_DEBUG("entities.transport", "Object %s removed from transport %s.", passenger->GetName().c_str(), GetName().c_str());
if (Player* plr = passenger->ToPlayer())
@@ -570,9 +589,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
GetMap()->RemoveFromMap<Transport>(this, false);
SetMap(newMap);
for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end();)
for (_passengerTeleportItr = _passengers.begin(); _passengerTeleportItr != _passengers.end();)
{
WorldObject* obj = (*itr++);
WorldObject* obj = (*_passengerTeleportItr++);
float destX, destY, destZ, destO;
obj->m_movementInfo.transport.pos.GetPosition(destX, destY, destZ, destO);
@@ -595,7 +614,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
case TYPEID_PLAYER:
if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
_passengers.erase(obj);
RemovePassenger(obj);
break;
case TYPEID_DYNAMICOBJECT:
obj->AddObjectToRemoveList();
@@ -613,7 +632,7 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
else
{
// Teleport players, they need to know it
for (std::set<WorldObject*>::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
for (PassengerSet::iterator itr = _passengers.begin(); itr != _passengers.end(); ++itr)
{
if ((*itr)->GetTypeId() == TYPEID_PLAYER)
{
@@ -630,9 +649,9 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
}
void Transport::UpdatePassengerPositions(std::set<WorldObject*>& passengers)
void Transport::UpdatePassengerPositions(PassengerSet& passengers)
{
for (std::set<WorldObject*>::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
for (PassengerSet::iterator itr = passengers.begin(); itr != passengers.end(); ++itr)
{
WorldObject* passenger = *itr;
// transport teleported but passenger not yet (can happen for players)
@@ -31,6 +31,8 @@ class Transport : public GameObject, public TransportBase
Transport();
public:
typedef std::set<WorldObject*> PassengerSet;
~Transport();
bool Create(uint32 guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
@@ -42,7 +44,7 @@ class Transport : public GameObject, public TransportBase
void AddPassenger(WorldObject* passenger);
void RemovePassenger(WorldObject* passenger);
std::set<WorldObject*> const& GetPassengers() const { return _passengers; }
PassengerSet const& GetPassengers() const { return _passengers; }
Creature* CreateNPCPassenger(uint32 guid, CreatureData const* data);
GameObject* CreateGOPassenger(uint32 guid, GameObjectData const* data);
@@ -99,7 +101,7 @@ class Transport : public GameObject, public TransportBase
void MoveToNextWaypoint();
float CalculateSegmentPos(float perc);
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
void UpdatePassengerPositions(std::set<WorldObject*>& passengers);
void UpdatePassengerPositions(PassengerSet& passengers);
void DoEventIfAny(KeyFrame const& node, bool departure);
//! Helpers to know if stop frame was reached
@@ -118,8 +120,9 @@ class Transport : public GameObject, public TransportBase
bool _triggeredArrivalEvent;
bool _triggeredDepartureEvent;
std::set<WorldObject*> _passengers;
std::set<WorldObject*> _staticPassengers;
PassengerSet _passengers;
PassengerSet::iterator _passengerTeleportItr;
PassengerSet _staticPassengers;
};
#endif
+1 -6
View File
@@ -13555,12 +13555,7 @@ void Unit::CleanupsBeforeDelete(bool finalCleanup)
{
CleanupBeforeRemoveFromMap(finalCleanup);
if (GetTransport())
{
GetTransport()->RemovePassenger(this);
SetTransport(NULL);
m_movementInfo.transport.Reset();
}
WorldObject::CleanupsBeforeDelete(finalCleanup);
}
void Unit::UpdateCharmAI()
+1 -1
View File
@@ -1289,7 +1289,7 @@ class Unit : public WorldObject
void RemoveFromWorld();
void CleanupBeforeRemoveFromMap(bool finalCleanup);
void CleanupsBeforeDelete(bool finalCleanup = true); // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
void CleanupsBeforeDelete(bool finalCleanup = true) override; // used in ~Creature/~Player (or before mass creature delete to remove cross-references to already deleted units)
DiminishingLevels GetDiminishing(DiminishingGroup group);
void IncrDiminishing(DiminishingGroup group);
@@ -35,7 +35,8 @@ void VisibleNotifier::SendToSelf()
// at this moment i_clientGUIDs have guids that not iterate at grid level checks
// but exist one case when this possible and object not out of range: transports
if (Transport* transport = i_player.GetTransport())
for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end();++itr)
{
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
if (vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
{
@@ -54,11 +55,15 @@ void VisibleNotifier::SendToSelf()
case TYPEID_UNIT:
i_player.UpdateVisibilityOf((*itr)->ToCreature(), i_data, i_visibleNow);
break;
case TYPEID_DYNAMICOBJECT:
i_player.UpdateVisibilityOf((*itr)->ToDynObject(), i_data, i_visibleNow);
break;
default:
break;
}
}
}
}
for (Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it)
{
+5 -18
View File
@@ -285,7 +285,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
}
/* handle special cases */
if (movementInfo.flags & MOVEMENTFLAG_ONTRANSPORT)
if (movementInfo.HasMovementFlag(MOVEMENTFLAG_ONTRANSPORT))
{
// transports size limited
// (also received at zeppelin leave by some reason with t_* as absolute in continent coordinates, can be safely skipped)
@@ -308,27 +308,15 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
if (!plrMover->GetTransport())
{
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
{
plrMover->m_transport = transport;
transport->AddPassenger(plrMover);
}
}
else if (plrMover->GetTransport()->GetGUID() != movementInfo.transport.guid)
{
bool foundNewTransport = false;
plrMover->m_transport->RemovePassenger(plrMover);
plrMover->GetTransport()->RemovePassenger(plrMover);
if (Transport* transport = plrMover->GetMap()->GetTransport(movementInfo.transport.guid))
{
foundNewTransport = true;
plrMover->m_transport = transport;
transport->AddPassenger(plrMover);
}
if (!foundNewTransport)
{
plrMover->m_transport = NULL;
else
movementInfo.transport.Reset();
}
}
}
@@ -336,13 +324,12 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvData)
{
GameObject* go = mover->GetMap()->GetGameObject(movementInfo.transport.guid);
if (!go || go->GetGoType() != GAMEOBJECT_TYPE_TRANSPORT)
movementInfo.flags &= ~MOVEMENTFLAG_ONTRANSPORT;
movementInfo.RemoveMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
}
}
else if (plrMover && plrMover->GetTransport()) // if we were on a transport, leave
{
plrMover->m_transport->RemovePassenger(plrMover);
plrMover->m_transport = NULL;
plrMover->GetTransport()->RemovePassenger(plrMover);
movementInfo.transport.Reset();
}
+1 -7
View File
@@ -2506,15 +2506,9 @@ void Map::SendInitSelf(Player* player)
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (Transport* transport = player->GetTransport())
{
for (std::set<WorldObject*>::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
{
for (Transport::PassengerSet::const_iterator itr = transport->GetPassengers().begin(); itr != transport->GetPassengers().end(); ++itr)
if (player != (*itr) && player->HaveAtClient(*itr))
{
(*itr)->BuildCreateUpdateBlockForPlayer(&data, player);
}
}
}
WorldPacket packet;
data.BuildPacket(&packet);