fix(Core/Transports): Improve static transport visibility (#22660)

This commit is contained in:
Takenbacon
2025-08-10 12:15:55 -07:00
committed by GitHub
parent ba1fcf2424
commit 2485ff7f5f
9 changed files with 92 additions and 55 deletions

View File

@@ -156,8 +156,8 @@ public:
void SaveToDB(bool saveAddon = false); void SaveToDB(bool saveAddon = false);
void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool saveAddon = false); void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask, bool saveAddon = false);
bool LoadFromDB(ObjectGuid::LowType guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); } virtual bool LoadFromDB(ObjectGuid::LowType guid, Map* map) { return LoadGameObjectFromDB(guid, map, false); }
bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true); virtual bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true);
void DeleteFromDB(); void DeleteFromDB();
void SetOwnerGUID(ObjectGuid owner) void SetOwnerGUID(ObjectGuid owner)

View File

@@ -66,6 +66,10 @@ void ObjectVisibilityContainer::LinkWorldObjectVisibility(WorldObject* worldObje
if (worldObject == _selfObject) if (worldObject == _selfObject)
return; return;
// Transports are special and should not be added to our visibility map
if (worldObject->IsGameObject() && worldObject->ToGameObject()->IsTransport())
return;
// Only players can link visibility // Only players can link visibility
if (!_visibleWorldObjectsMap) if (!_visibleWorldObjectsMap)
return; return;

View File

@@ -1645,10 +1645,7 @@ template <>
inline void UpdateVisibilityOf_helper(Player* player, GameObject* target, inline void UpdateVisibilityOf_helper(Player* player, GameObject* target,
std::vector<Unit*>& /*v*/) std::vector<Unit*>& /*v*/)
{ {
// @HACK: This is to prevent objects like deeprun tram from disappearing player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
// when player moves far from its spawn point while riding it
if ((target->GetGOInfo()->type != GAMEOBJECT_TYPE_TRANSPORT))
player->GetObjectVisibilityContainer().LinkWorldObjectVisibility(target);
} }
template <> template <>

View File

@@ -607,12 +607,12 @@ void MotionTransport::DelayedTeleportTransport()
} }
Map* newMap = sMapMgr->CreateBaseMap(newMapId); Map* newMap = sMapMgr->CreateBaseMap(newMapId);
GetMap()->RemoveFromMap<MotionTransport>(this, false); GetMap()->RemoveFromMap<Transport>(this, false);
newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map newMap->LoadGrid(x, y); // xinef: load before adding passengers to new map
SetMap(newMap); SetMap(newMap);
Relocate(x, y, z, o); Relocate(x, y, z, o);
GetMap()->AddToMap<MotionTransport>(this); GetMap()->AddToMap<Transport>(this);
LoadStaticPassengers(); LoadStaticPassengers();
} }
@@ -690,6 +690,40 @@ StaticTransport::~StaticTransport()
ASSERT(_passengers.empty()); ASSERT(_passengers.empty());
} }
bool StaticTransport::LoadGameObjectFromDB(ObjectGuid::LowType spawnId, Map* map, bool addToMap)
{
GameObjectData const* data = sObjectMgr->GetGameObjectData(spawnId);
if (!data)
{
LOG_ERROR("sql.sql", "Gameobject (GUID: {}) not found in table `gameobject`, can't load. ", spawnId);
return false;
}
uint32 entry = data->id;
//uint32 map_id = data->mapid; // already used before call
uint32 phaseMask = data->phaseMask;
float x = data->posX;
float y = data->posY;
float z = data->posZ;
float ang = data->orientation;
uint32 animprogress = data->animprogress;
GOState go_state = data->go_state;
uint32 artKit = data->artKit;
m_goData = data;
m_spawnId = spawnId;
if (!Create(map->GenerateLowGuid<HighGuid::Transport>(), entry, map, phaseMask, x, y, z, ang, data->rotation, animprogress, go_state, artKit))
return false;
if (addToMap && !GetMap()->AddToMap<Transport>(this))
return false;
return true;
}
bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit) bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit)
{ {
ASSERT(map); ASSERT(map);
@@ -794,7 +828,6 @@ bool StaticTransport::Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* m
LastUsedScriptID = GetGOInfo()->ScriptId; LastUsedScriptID = GetGOInfo()->ScriptId;
AIM_Initialize(); AIM_Initialize();
this->setActive(true);
return true; return true;
} }
@@ -929,7 +962,9 @@ void StaticTransport::UpdatePosition(float x, float y, float z, float o)
if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case if (!GetMap()->IsGridLoaded(x, y)) // pussywizard: should not happen, but just in case
GetMap()->LoadGrid(x, y); GetMap()->LoadGrid(x, y);
GetMap()->GameObjectRelocation(this, x, y, z, o); // this also relocates the model Relocate(x, y, z, o);
UpdateModelPosition();
UpdatePassengerPositions(); UpdatePassengerPositions();
} }

View File

@@ -38,6 +38,8 @@ public:
virtual void RemovePassenger(WorldObject* passenger, bool withAll = false) = 0; virtual void RemovePassenger(WorldObject* passenger, bool withAll = false) = 0;
PassengerSet const& GetPassengers() const { return _passengers; } PassengerSet const& GetPassengers() const { return _passengers; }
virtual void DelayedUpdate(uint32 /*diff*/) {}
uint32 GetPathProgress() const { return GetGOValue()->Transport.PathProgress; } uint32 GetPathProgress() const { return GetGOValue()->Transport.PathProgress; }
void SetPathProgress(uint32 val) { m_goValue.Transport.PathProgress = val; } void SetPathProgress(uint32 val) { m_goValue.Transport.PathProgress = val; }
@@ -57,7 +59,7 @@ public:
void BuildUpdate(UpdateDataMapType& data_map) override; void BuildUpdate(UpdateDataMapType& data_map) override;
void Update(uint32 diff) override; void Update(uint32 diff) override;
void DelayedUpdate(uint32 diff); void DelayedUpdate(uint32 diff) override;
void UpdatePosition(float x, float y, float z, float o); void UpdatePosition(float x, float y, float z, float o);
void AddPassenger(WorldObject* passenger, bool withAll = false) override; void AddPassenger(WorldObject* passenger, bool withAll = false) override;
@@ -115,6 +117,8 @@ public:
StaticTransport(); StaticTransport();
~StaticTransport() override; ~StaticTransport() override;
bool LoadFromDB(ObjectGuid::LowType guid, Map* map) override { return LoadGameObjectFromDB(guid, map, false); }
bool LoadGameObjectFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true) override;
bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit = 0) override; bool Create(ObjectGuid::LowType guidlow, uint32 name_id, Map* map, uint32 phaseMask, float x, float y, float z, float ang, G3D::Quat const& rotation, uint32 animprogress, GOState go_state, uint32 artKit = 0) override;
void CleanupsBeforeDelete(bool finalCleanup = true) override; void CleanupsBeforeDelete(bool finalCleanup = true) override;
void BuildUpdate(UpdateDataMapType& data_map) override; void BuildUpdate(UpdateDataMapType& data_map) override;

View File

@@ -64,15 +64,28 @@ void GridObjectLoader::LoadGameObjects(CellGuidSet const& guid_set, Map* map)
for (ObjectGuid::LowType const& guid : guid_set) for (ObjectGuid::LowType const& guid : guid_set)
{ {
GameObjectData const* data = sObjectMgr->GetGameObjectData(guid); GameObjectData const* data = sObjectMgr->GetGameObjectData(guid);
GameObject* obj = data && sObjectMgr->IsGameObjectStaticTransport(data->id) ? new StaticTransport() : new GameObject();
if (!obj->LoadFromDB(guid, map)) if (data && sObjectMgr->IsGameObjectStaticTransport(data->id))
{ {
delete obj; StaticTransport* transport = new StaticTransport();
continue;
}
AddObjectHelper<GameObject>(map, obj); // Special case for static transports - we are loaded via grids
// but we do not want to actually be stored in the grid
if (!transport->LoadGameObjectFromDB(guid, map, true))
delete transport;
}
else
{
GameObject* obj = new GameObject();
if (!obj->LoadFromDB(guid, map))
{
delete obj;
continue;
}
AddObjectHelper<GameObject>(map, obj);
}
} }
} }

View File

@@ -345,7 +345,7 @@ bool Map::AddToMap(T* obj, bool checkTransport)
} }
template<> template<>
bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/) bool Map::AddToMap(Transport* obj, bool /*checkTransport*/)
{ {
//TODO: Needs clean up. An object should not be added to map twice. //TODO: Needs clean up. An object should not be added to map twice.
if (obj->IsInWorld()) if (obj->IsInWorld())
@@ -360,26 +360,22 @@ bool Map::AddToMap(MotionTransport* obj, bool /*checkTransport*/)
} }
Cell cell(cellCoord); Cell cell(cellCoord);
if (obj->isActiveObject()) EnsureGridLoaded(cell);
EnsureGridLoaded(cell);
obj->AddToWorld(); obj->AddToWorld();
_transports.insert(obj); _transports.insert(obj);
// Broadcast creation to players // Broadcast creation to players
if (!GetPlayers().IsEmpty()) for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{ {
for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr) if (itr->GetSource()->GetTransport() != obj)
{ {
if (itr->GetSource()->GetTransport() != obj) UpdateData data;
{ obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
UpdateData data; WorldPacket packet;
obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource()); data.BuildPacket(packet);
WorldPacket packet; itr->GetSource()->SendDirectMessage(&packet);
data.BuildPacket(packet);
itr->GetSource()->SendDirectMessage(&packet);
}
} }
} }
@@ -667,7 +663,7 @@ void Map::RemoveFromMap(T* obj, bool remove)
} }
template<> template<>
void Map::RemoveFromMap(MotionTransport* obj, bool remove) void Map::RemoveFromMap(Transport* obj, bool remove)
{ {
obj->RemoveFromWorld(); obj->RemoveFromWorld();
@@ -697,8 +693,6 @@ void Map::RemoveFromMap(MotionTransport* obj, bool remove)
obj->ResetMap(); obj->ResetMap();
// Transports are never actually deleted, but it *should* be safe to clear
// from update list when removing from world
RemoveObjectFromMapUpdateList(obj); RemoveObjectFromMapUpdateList(obj);
if (remove) if (remove)
@@ -966,11 +960,10 @@ void Map::UnloadAll()
for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end();) for (TransportsContainer::iterator itr = _transports.begin(); itr != _transports.end();)
{ {
MotionTransport* transport = *itr; Transport* transport = *itr;
++itr; ++itr;
transport->RemoveFromWorld(); RemoveFromMap<Transport>(transport, true);
delete transport;
} }
_transports.clear(); _transports.clear();
@@ -1589,6 +1582,9 @@ void Map::SendInitSelf(Player* player)
void Map::SendInitTransports(Player* player) void Map::SendInitTransports(Player* player)
{ {
if (_transports.empty())
return;
// Hack to send out transports // Hack to send out transports
UpdateData transData; UpdateData transData;
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr) for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
@@ -1605,24 +1601,15 @@ void Map::SendInitTransports(Player* player)
void Map::SendRemoveTransports(Player* player) void Map::SendRemoveTransports(Player* player)
{ {
if (_transports.empty())
return;
// Hack to send out transports // Hack to send out transports
UpdateData transData; UpdateData transData;
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr) for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
if (*itr != player->GetTransport()) if (*itr != player->GetTransport())
(*itr)->BuildOutOfRangeUpdateBlock(&transData); (*itr)->BuildOutOfRangeUpdateBlock(&transData);
// pussywizard: remove static transports from client
/*for (GuidUnorderedSet::const_iterator it = player->m_clientGUIDs.begin(); it != player->m_clientGUIDs.end(); )
{
if ((*it).IsTransport())
{
transData.AddOutOfRangeGUID(*it);
it = player->m_clientGUIDs.erase(it);
}
else
++it;
}*/
if (!transData.HasData()) if (!transData.HasData())
return; return;
@@ -1693,7 +1680,7 @@ void Map::DelayedUpdate(const uint32 t_diff)
{ {
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();) for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
{ {
MotionTransport* transport = *_transportsUpdateIter; Transport* transport = *_transportsUpdateIter;
++_transportsUpdateIter; ++_transportsUpdateIter;
if (!transport->IsInWorld()) if (!transport->IsInWorld())
@@ -1738,7 +1725,7 @@ void Map::RemoveAllObjectsInRemoveList()
RemoveFromMap((DynamicObject*)obj, true); RemoveFromMap((DynamicObject*)obj, true);
break; break;
case TYPEID_GAMEOBJECT: case TYPEID_GAMEOBJECT:
if (MotionTransport* transport = obj->ToGameObject()->ToMotionTransport()) if (Transport* transport = obj->ToGameObject()->ToTransport())
RemoveFromMap(transport, true); RemoveFromMap(transport, true);
else else
RemoveFromMap(obj->ToGameObject(), true); RemoveFromMap(obj->ToGameObject(), true);

View File

@@ -146,7 +146,7 @@ struct ZoneDynamicInfo
typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType; typedef std::map<uint32/*leaderDBGUID*/, CreatureGroup*> CreatureGroupHolderType;
typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap; typedef std::unordered_map<uint32 /*zoneId*/, ZoneDynamicInfo> ZoneDynamicInfoMap;
typedef std::set<MotionTransport*> TransportsContainer; typedef std::unordered_set<Transport*> TransportsContainer;
enum EncounterCreditType : uint8 enum EncounterCreditType : uint8
{ {
@@ -535,7 +535,6 @@ protected:
MapRefMgr m_mapRefMgr; MapRefMgr m_mapRefMgr;
MapRefMgr::iterator m_mapRefIter; MapRefMgr::iterator m_mapRefIter;
// Objects that must update even in inactive grids without activating them
TransportsContainer _transports; TransportsContainer _transports;
TransportsContainer::iterator _transportsUpdateIter; TransportsContainer::iterator _transportsUpdateIter;

View File

@@ -412,10 +412,8 @@ MotionTransport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType
if (map && map->IsDungeon()) if (map && map->IsDungeon())
trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript(); trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
// xinef: transports are active so passengers can be relocated (grids must be loaded)
trans->setActive(true);
HashMapHolder<MotionTransport>::Insert(trans); HashMapHolder<MotionTransport>::Insert(trans);
trans->GetMap()->AddToMap<MotionTransport>(trans); trans->GetMap()->AddToMap<Transport>(trans);
return trans; return trans;
} }