Core/Transports: Localized transport objects within each map

Transports no longer move between maps, each map gets a separate copy of the transport object and players are moved between them when transferring to another map
This means they can no longer be globally looked up in HashMapHolder
This commit is contained in:
Shauren
2022-06-13 20:06:26 +02:00
parent 8f537b9686
commit cace414497
15 changed files with 220 additions and 212 deletions

View File

@@ -351,8 +351,8 @@ bool BattlegroundIC::SetupBattleground()
return false;
}
gunshipHorde = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, UI64LIT(0), GetBgMap());
gunshipAlliance = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, UI64LIT(0), GetBgMap());
gunshipHorde = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, GetBgMap());
gunshipAlliance = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, GetBgMap());
if (!gunshipAlliance || !gunshipHorde)
{

View File

@@ -443,7 +443,7 @@ bool Player::Create(ObjectGuid::LowType guidlow, WorldPackets::Character::Charac
if (position.TransportGuid)
{
if (Transport* transport = HashMapHolder<Transport>::Find(ObjectGuid::Create<HighGuid::Transport>(*position.TransportGuid)))
if (Transport* transport = ObjectAccessor::GetTransport(*this, ObjectGuid::Create<HighGuid::Transport>(*position.TransportGuid)))
{
transport->AddPassenger(this);
m_movementInfo.transport.pos.Relocate(position.Loc);
@@ -18224,8 +18224,22 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol
ObjectGuid transGUID = ObjectGuid::Create<HighGuid::Transport>(fields.transguid);
Transport* transport = nullptr;
if (Transport* go = HashMapHolder<Transport>::Find(transGUID))
transport = go;
if (Map* transportMap = sMapMgr->CreateMap(mapId, this, instanceId))
{
if (Transport* transportOnMap = transportMap->GetTransport(transGUID))
{
if (transportOnMap->GetExpectedMapId() != mapId)
{
mapId = transportOnMap->GetExpectedMapId();
instanceId = 0;
transportMap = sMapMgr->CreateMap(mapId, this, instanceId);
if (transportMap)
transport = transportMap->GetTransport(transGUID);
}
else
transport = transportOnMap;
}
}
if (transport)
{
@@ -20373,22 +20387,14 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
if (!ok && HasAtLoginFlag(AT_LOGIN_FIRST))
{
PlayerInfo::CreatePosition const& createPosition = m_createMode == PlayerCreateMode::NPE && info->createPositionNPE ? *info->createPositionNPE : info->createPosition;
m_homebind.WorldRelocate(createPosition.Loc);
if (createPosition.TransportGuid)
if (!createPosition.TransportGuid)
{
if (Transport* transport = HashMapHolder<Transport>::Find(ObjectGuid::Create<HighGuid::Transport>(*createPosition.TransportGuid)))
{
float orientation = m_homebind.GetOrientation();
transport->CalculatePassengerPosition(m_homebind.m_positionX, m_homebind.m_positionY, m_homebind.m_positionZ, &orientation);
m_homebind.SetOrientation(orientation);
}
m_homebind.WorldRelocate(createPosition.Loc);
m_homebindAreaId = sMapMgr->GetAreaId(PhasingHandler::GetEmptyPhaseShift(), m_homebind);
saveHomebindToDb();
ok = true;
}
m_homebindAreaId = sMapMgr->GetAreaId(PhasingHandler::GetEmptyPhaseShift(), m_homebind);
saveHomebindToDb();
ok = true;
}
if (!ok)

View File

@@ -107,7 +107,7 @@ Transport::~Transport()
UnloadStaticPassengers();
}
bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress)
bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float y, float z, float ang)
{
Relocate(x, y, z, ang);
@@ -123,7 +123,7 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid,
GameObjectTemplate const* goinfo = sObjectMgr->GetGameObjectTemplate(entry);
if (!goinfo)
{
TC_LOG_ERROR("sql.sql", "Transport not created: entry in `gameobject_template` not found, guidlow: " UI64FMTD " map: %u (X: %f Y: %f Z: %f) ang: %f", guidlow, mapid, x, y, z, ang);
TC_LOG_ERROR("sql.sql", "Transport not created: entry in `gameobject_template` not found, entry: %u", entry);
return false;
}
@@ -154,12 +154,19 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid,
SetDisplayId(goinfo->displayId);
SetGoState(!goinfo->moTransport.allowstopping ? GO_STATE_READY : GO_STATE_ACTIVE);
SetGoType(GAMEOBJECT_TYPE_MAP_OBJ_TRANSPORT);
SetGoAnimProgress(animprogress);
SetGoAnimProgress(255);
SetUpdateFieldValue(m_values.ModifyValue(&GameObject::m_gameObjectData).ModifyValue(&UF::GameObjectData::SpawnTrackingStateAnimID), sDB2Manager.GetEmptyAnimStateID());
SetName(goinfo->name);
SetLocalRotation(0.0f, 0.0f, 0.0f, 1.0f);
SetParentRotation(QuaternionData());
size_t legIndex;
if (Optional<Position> position = _transportInfo->ComputePosition(_pathProgress, nullptr, &legIndex))
{
Relocate(position->GetPositionX(), position->GetPositionY(), position->GetPositionZ(), position->GetOrientation());
_currentPathLeg = legIndex;
}
CreateModel();
return true;
}
@@ -212,7 +219,10 @@ void Transport::Update(uint32 diff)
{
while (eventToTriggerIndex < _transportInfo->Events.size() && _transportInfo->Events[eventToTriggerIndex].Timestamp < timer)
{
GameEvents::Trigger(_transportInfo->Events[eventToTriggerIndex].EventId, this, this);
if (TransportPathLeg const* leg = _transportInfo->GetLegForTime(_transportInfo->Events[eventToTriggerIndex].Timestamp))
if (leg->MapId == GetMapId())
GameEvents::Trigger(_transportInfo->Events[eventToTriggerIndex].EventId, this, this);
_eventsToTrigger->set(eventToTriggerIndex, false);
++eventToTriggerIndex;
}
@@ -236,13 +246,14 @@ void Transport::Update(uint32 diff)
if (legIndex != _currentPathLeg)
{
uint32 oldMapId = _transportInfo->PathLegs[_currentPathLeg].MapId;
_currentPathLeg = legIndex;
TeleportTransport(_transportInfo->PathLegs[legIndex].MapId, newPosition->GetPositionX(), newPosition->GetPositionY(), newPosition->GetPositionZ(), newPosition->GetOrientation());
TeleportTransport(oldMapId, _transportInfo->PathLegs[legIndex].MapId, newPosition->GetPositionX(), newPosition->GetPositionY(), newPosition->GetPositionZ(), newPosition->GetOrientation());
return;
}
// set position
if (_positionChangeTimer.Passed())
if (_positionChangeTimer.Passed() && GetExpectedMapId() == GetMapId())
{
_positionChangeTimer.Reset(positionUpdateDelay);
if (_movementState == TransportMovementState::Moving || justStopped)
@@ -276,11 +287,6 @@ void Transport::Update(uint32 diff)
}
}
void Transport::DelayedUpdate(uint32 /*diff*/)
{
DelayedTeleportTransport();
}
void Transport::AddPassenger(WorldObject* passenger)
{
if (!IsInWorld())
@@ -607,14 +613,12 @@ void Transport::EnableMovement(bool enabled)
}
}
bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, float o)
bool Transport::TeleportTransport(uint32 oldMapId, uint32 newMapId, float x, float y, float z, float o)
{
Map const* oldMap = GetMap();
if (oldMap->GetId() != newMapid)
if (oldMapId != newMapId)
{
_delayedTeleport.emplace(newMapid, x, y, z, o);
UnloadStaticPassengers();
TeleportPassengersAndHideTransport(newMapId, x, y, z, o);
return true;
}
else
@@ -643,21 +647,43 @@ bool Transport::TeleportTransport(uint32 newMapid, float x, float y, float z, fl
}
}
void Transport::DelayedTeleportTransport()
void Transport::TeleportPassengersAndHideTransport(uint32 newMapid, float x, float y, float z, float o)
{
if (!_delayedTeleport)
return;
if (newMapid == GetMapId())
{
AddToWorld();
Map* newMap = sMapMgr->CreateBaseMap(_delayedTeleport->GetMapId());
GetMap()->RemoveFromMap<Transport>(this, false);
SetMap(newMap);
for (MapReference const& ref : GetMap()->GetPlayers())
{
if (ref.GetSource()->GetTransport() != this && ref.GetSource()->IsInPhase(this))
{
UpdateData data(GetMap()->GetId());
BuildCreateUpdateBlockForPlayer(&data, ref.GetSource());
ref.GetSource()->m_visibleTransports.insert(GetGUID());
WorldPacket packet;
data.BuildPacket(&packet);
ref.GetSource()->SendDirectMessage(&packet);
}
}
}
else
{
UpdateData data(GetMap()->GetId());
BuildOutOfRangeUpdateBlock(&data);
float x = _delayedTeleport->GetPositionX(),
y = _delayedTeleport->GetPositionY(),
z = _delayedTeleport->GetPositionZ(),
o = _delayedTeleport->GetOrientation();
WorldPacket packet;
data.BuildPacket(&packet);
for (MapReference const& ref : GetMap()->GetPlayers())
{
if (ref.GetSource()->GetTransport() != this && ref.GetSource()->m_visibleTransports.count(GetGUID()))
{
ref.GetSource()->SendDirectMessage(&packet);
ref.GetSource()->m_visibleTransports.erase(GetGUID());
}
}
_delayedTeleport.reset();
RemoveFromWorld();
}
PassengerSet passengersToTeleport = _passengers;
for (WorldObject* obj : passengersToTeleport)
@@ -669,7 +695,7 @@ void Transport::DelayedTeleportTransport()
switch (obj->GetTypeId())
{
case TYPEID_PLAYER:
if (!obj->ToPlayer()->TeleportTo(newMap->GetId(), destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT, newMap->GetInstanceId()))
if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT))
RemovePassenger(obj);
break;
case TYPEID_DYNAMICOBJECT:
@@ -681,9 +707,6 @@ void Transport::DelayedTeleportTransport()
break;
}
}
Relocate(x, y, z, o);
GetMap()->AddToMap<Transport>(this);
}
void Transport::UpdatePassengerPositions(PassengerSet const& passengers)
@@ -716,3 +739,8 @@ std::string Transport::GetDebugInfo() const
sstr << GameObject::GetDebugInfo();
return sstr.str();
}
uint32 Transport::GetExpectedMapId() const
{
return _transportInfo->PathLegs[_currentPathLeg].MapId;
}

View File

@@ -28,7 +28,7 @@ struct SummonPropertiesEntry;
class TC_GAME_API Transport : public GameObject, public TransportBase
{
friend Transport* TransportMgr::CreateTransport(uint32, ObjectGuid::LowType, Map*, uint8, uint32, uint32);
friend Transport* TransportMgr::CreateTransport(uint32, Map*, ObjectGuid::LowType, uint8, uint32, uint32);
Transport();
public:
@@ -36,11 +36,10 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
~Transport();
bool Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, float x, float y, float z, float ang, uint32 animprogress);
bool Create(ObjectGuid::LowType guidlow, uint32 entry, float x, float y, float z, float ang);
void CleanupsBeforeDelete(bool finalCleanup = true) override;
void Update(uint32 diff) override;
void DelayedUpdate(uint32 diff);
void BuildUpdate(UpdateDataMapType& data_map) override;
@@ -105,9 +104,12 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
std::string GetDebugInfo() const override;
//! Returns id of the map that transport is expected to be on, according to current path progress
uint32 GetExpectedMapId() const;
private:
bool TeleportTransport(uint32 newMapid, float x, float y, float z, float o);
void DelayedTeleportTransport();
bool TeleportTransport(uint32 oldMapId, uint32 newMapId, float x, float y, float z, float o);
void TeleportPassengersAndHideTransport(uint32 newMapid, float x, float y, float z, float o);
void UpdatePassengerPositions(PassengerSet const& passengers);
TransportTemplate const* _transportInfo;
@@ -122,7 +124,6 @@ class TC_GAME_API Transport : public GameObject, public TransportBase
PassengerSet _staticPassengers;
bool _delayedAddModel;
Optional<WorldLocation> _delayedTeleport;
};
#endif

View File

@@ -31,9 +31,8 @@
template<class T>
void HashMapHolder<T>::Insert(T* o)
{
static_assert(std::is_same<Player, T>::value
|| std::is_same<Transport, T>::value,
"Only Player and Transport can be registered in global HashMapHolder");
static_assert(std::is_same<Player, T>::value,
"Only Player can be registered in global HashMapHolder");
std::unique_lock<std::shared_mutex> lock(*GetLock());
@@ -72,7 +71,6 @@ std::shared_mutex* HashMapHolder<T>::GetLock()
}
template class TC_GAME_API HashMapHolder<Player>;
template class TC_GAME_API HashMapHolder<Transport>;
namespace PlayerNameMapHolder
{
@@ -180,16 +178,11 @@ GameObject* ObjectAccessor::GetGameObject(WorldObject const& u, ObjectGuid const
return u.GetMap()->GetGameObject(guid);
}
Transport* ObjectAccessor::GetTransportOnMap(WorldObject const& u, ObjectGuid const& guid)
Transport* ObjectAccessor::GetTransport(WorldObject const& u, ObjectGuid const& guid)
{
return u.GetMap()->GetTransport(guid);
}
Transport* ObjectAccessor::GetTransport(ObjectGuid const& guid)
{
return HashMapHolder<Transport>::Find(guid);
}
DynamicObject* ObjectAccessor::GetDynamicObject(WorldObject const& u, ObjectGuid const& guid)
{
return u.GetMap()->GetDynamicObject(guid);

View File

@@ -65,8 +65,7 @@ namespace ObjectAccessor
TC_GAME_API Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask);
TC_GAME_API Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API Transport* GetTransportOnMap(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API Transport* GetTransport(ObjectGuid const& guid);
TC_GAME_API Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API AreaTrigger* GetAreaTrigger(WorldObject const& u, ObjectGuid const& guid);
TC_GAME_API SceneObject* GetSceneObject(WorldObject const& u, ObjectGuid const& guid);

View File

@@ -79,6 +79,10 @@ void WorldSession::HandleMoveWorldportAck()
sMapMgr->FindMap(loc.GetMapId(), *GetPlayer()->GetTeleportDestInstanceId()) :
sMapMgr->CreateMap(loc.GetMapId(), GetPlayer());
MovementInfo::TransportInfo transportInfo = player->m_movementInfo.transport;
if (TransportBase* transport = player->GetTransport())
transport->RemovePassenger(player);
if (player->IsInWorld())
{
TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", player->GetGUID().ToString().c_str(), player->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId());
@@ -110,6 +114,13 @@ void WorldSession::HandleMoveWorldportAck()
if (!seamlessTeleport)
player->SendInitialPacketsBeforeAddToMap();
// move player between transport copies on each map
if (Transport* newTransport = newMap->GetTransport(transportInfo.guid))
{
player->m_movementInfo.transport = transportInfo;
newTransport->AddPassenger(player);
}
if (!player->GetMap()->AddPlayerToMap(player, !seamlessTeleport))
{
TC_LOG_ERROR("network", "WORLD: failed to teleport player %s %s to map %d (%s) because of unknown reason!",

View File

@@ -367,6 +367,8 @@ i_scriptLock(false), _respawnCheckTimer(0)
_poolData = sPoolMgr->InitPoolsForMap(this);
sTransportMgr->CreateTransportsForMap(this);
MMAP::MMapFactory::createOrGetMMapManager()->loadMapInstance(sWorld->GetDataPath(), GetId(), i_InstanceId);
sScriptMgr->OnCreateMap(this);
@@ -514,13 +516,6 @@ void Map::DeleteFromWorld(Player* player)
delete player;
}
template<>
void Map::DeleteFromWorld(Transport* transport)
{
ObjectAccessor::RemoveObject(transport);
delete transport;
}
void Map::EnsureGridCreated(GridCoord const& p)
{
std::lock_guard<std::mutex> lock(_gridLock);
@@ -765,15 +760,16 @@ bool Map::AddToMap(Transport* obj)
return false; //Should delete object
}
obj->AddToWorld();
_transports.insert(obj);
// Broadcast creation to players
if (!GetPlayers().isEmpty())
if (obj->GetExpectedMapId() == GetId())
{
obj->AddToWorld();
// Broadcast creation to players
for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{
if (itr->GetSource()->GetTransport() != obj)
if (itr->GetSource()->GetTransport() != obj && itr->GetSource()->IsInPhase(obj))
{
UpdateData data(GetId());
obj->BuildCreateUpdateBlockForPlayer(&data, itr->GetSource());
@@ -944,10 +940,6 @@ void Map::Update(uint32 t_diff)
{
WorldObject* obj = *_transportsUpdateIter;
++_transportsUpdateIter;
if (!obj->IsInWorld())
continue;
obj->Update(t_diff);
}
@@ -1131,18 +1123,21 @@ void Map::RemoveFromMap(T *obj, bool remove)
template<>
void Map::RemoveFromMap(Transport* obj, bool remove)
{
obj->RemoveFromWorld();
Map::PlayerList const& players = GetPlayers();
if (!players.isEmpty())
if (obj->IsInWorld())
{
obj->RemoveFromWorld();
UpdateData data(GetId());
obj->BuildOutOfRangeUpdateBlock(&data);
if (obj->IsDestroyedObject())
obj->BuildDestroyUpdateBlock(&data);
else
obj->BuildOutOfRangeUpdateBlock(&data);
WorldPacket packet;
data.BuildPacket(&packet);
for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr)
for (Map::PlayerList::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
{
if (itr->GetSource()->GetTransport() != obj)
if (itr->GetSource()->GetTransport() != obj && itr->GetSource()->m_visibleTransports.count(obj->GetGUID()))
{
itr->GetSource()->SendDirectMessage(&packet);
itr->GetSource()->m_visibleTransports.erase(obj->GetGUID());
@@ -3049,10 +3044,10 @@ void Map::SendInitSelf(Player* player)
void Map::SendInitTransports(Player* player)
{
// Hack to send out transports
UpdateData transData(player->GetMapId());
UpdateData transData(GetId());
for (Transport* transport : _transports)
{
if (transport != player->GetTransport() && player->IsInPhase(transport))
if (transport->IsInWorld() && transport != player->GetTransport() && player->IsInPhase(transport))
{
transport->BuildCreateUpdateBlockForPlayer(&transData, player);
player->m_visibleTransports.insert(transport->GetGUID());
@@ -3070,7 +3065,7 @@ void Map::SendRemoveTransports(Player* player)
UpdateData transData(player->GetMapId());
for (Transport* transport : _transports)
{
if (transport != player->GetTransport())
if (player->m_visibleTransports.count(transport->GetGUID()) && transport != player->GetTransport())
{
transport->BuildOutOfRangeUpdateBlock(&transData);
player->m_visibleTransports.erase(transport->GetGUID());
@@ -3088,6 +3083,9 @@ void Map::SendUpdateTransportVisibility(Player* player)
UpdateData transData(player->GetMapId());
for (Transport* transport : _transports)
{
if (!transport->IsInWorld())
continue;
auto transportItr = player->m_visibleTransports.find(transport->GetGUID());
if (player->IsInPhase(transport))
{
@@ -3658,17 +3656,6 @@ void Map::DelayedUpdate(uint32 t_diff)
}
}
for (_transportsUpdateIter = _transports.begin(); _transportsUpdateIter != _transports.end();)
{
Transport* transport = *_transportsUpdateIter;
++_transportsUpdateIter;
if (!transport->IsInWorld())
continue;
transport->DelayedUpdate(t_diff);
}
RemoveAllObjectsInRemoveList();
// Don't unload grids if it's battleground, since we may have manually added GOs, creatures, those doesn't load from DB at grid re-load !

View File

@@ -44,21 +44,17 @@ Optional<Position> TransportTemplate::ComputePosition(uint32 time, TransportMove
time %= TotalPathTime;
// find leg
auto legItr = PathLegs.begin();
while (legItr->StartTimestamp + legItr->Duration <= time)
{
++legItr;
TransportPathLeg const* leg = GetLegForTime(time);
if (!leg)
return {};
if (legItr == PathLegs.end())
return {};
}
// find segment
uint32 prevSegmentTime = legItr->StartTimestamp;
auto segmentItr = legItr->Segments.begin();
uint32 prevSegmentTime = leg->StartTimestamp;
auto segmentItr = leg->Segments.begin();
double distanceMoved = 0.0;
bool isOnPause = false;
for (; segmentItr != std::prev(legItr->Segments.end()); ++segmentItr)
for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
{
if (time < segmentItr->SegmentEndArrivalTimestamp)
break;
@@ -77,26 +73,54 @@ Optional<Position> TransportTemplate::ComputePosition(uint32 time, TransportMove
distanceMoved += CalculateDistanceMoved(
double(time - prevSegmentTime) * 0.001,
double(segmentItr->SegmentEndArrivalTimestamp - prevSegmentTime) * 0.001,
segmentItr == legItr->Segments.begin(),
segmentItr == std::prev(legItr->Segments.end()));
segmentItr == leg->Segments.begin(),
segmentItr == std::prev(leg->Segments.end()));
Movement::SplineBase::index_type splineIndex;
float splinePointProgress;
legItr->Spline->computeIndex(std::fmin(distanceMoved / legItr->Spline->length(), 1.0), splineIndex, splinePointProgress);
leg->Spline->computeIndex(std::fmin(distanceMoved / leg->Spline->length(), 1.0), splineIndex, splinePointProgress);
G3D::Vector3 pos, dir;
legItr->Spline->evaluate_percent(splineIndex, splinePointProgress, pos);
legItr->Spline->evaluate_derivative(splineIndex, splinePointProgress, dir);
leg->Spline->evaluate_percent(splineIndex, splinePointProgress, pos);
leg->Spline->evaluate_derivative(splineIndex, splinePointProgress, dir);
if (moveState)
*moveState = isOnPause ? TransportMovementState::WaitingOnPauseWaypoint : TransportMovementState::Moving;
if (legIndex)
*legIndex = std::distance(PathLegs.begin(), legItr);
*legIndex = std::distance(PathLegs.data(), leg);
return Position(pos.x, pos.y, pos.z, std::atan2(dir.y, dir.x) + float(M_PI));
}
TransportPathLeg const* TransportTemplate::GetLegForTime(uint32 time) const
{
auto legItr = PathLegs.begin();
while (legItr->StartTimestamp + legItr->Duration <= time)
{
++legItr;
if (legItr == PathLegs.end())
return nullptr;
}
return &*legItr;
}
uint32 TransportTemplate::GetNextPauseWaypointTimestamp(uint32 time) const
{
TransportPathLeg const* leg = GetLegForTime(time);
if (!leg)
return time;
auto segmentItr = leg->Segments.begin();
for (; segmentItr != std::prev(leg->Segments.end()); ++segmentItr)
if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
break;
return segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
}
double TransportTemplate::CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const
{
if (isFirstSegment)
@@ -151,25 +175,6 @@ double TransportTemplate::CalculateDistanceMoved(double timePassedInSegment, dou
}
}
uint32 TransportTemplate::GetNextPauseWaypointTimestamp(uint32 time) const
{
auto legItr = PathLegs.begin();
while (legItr->StartTimestamp + legItr->Duration <= time)
{
++legItr;
if (legItr == PathLegs.end())
return time;
}
auto segmentItr = legItr->Segments.begin();
for (; segmentItr != std::prev(legItr->Segments.end()); ++segmentItr)
if (time < segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay)
break;
return segmentItr->SegmentEndArrivalTimestamp + segmentItr->Delay;
}
TransportMgr::TransportMgr() = default;
TransportMgr::~TransportMgr() = default;
@@ -222,13 +227,7 @@ void TransportMgr::LoadTransportTemplates()
// paths are generated per template, saves us from generating it again in case of instanced transports
TransportTemplate& transport = _transportTemplates[entry];
std::set<uint32> mapsUsed;
GeneratePath(goInfo, &transport, &mapsUsed);
// transports in instance are only on one map
if (transport.InInstance)
_instanceTransports[*mapsUsed.begin()].insert(entry);
GeneratePath(goInfo, &transport);
++count;
} while (result->NextRow());
@@ -266,7 +265,8 @@ void TransportMgr::LoadTransportSpawns()
uint32 phaseId = fields[3].GetUInt32();
uint32 phaseGroupId = fields[4].GetUInt32();
if (!GetTransportTemplate(entry))
TransportTemplate const* transportTemplate = GetTransportTemplate(entry);
if (!transportTemplate)
{
TC_LOG_ERROR("sql.sql", "Table `transports` have transport (GUID: " UI64FMTD " Entry: %u) with unknown gameobject `entry` set, skipped.", guid, entry);
continue;
@@ -316,6 +316,9 @@ void TransportMgr::LoadTransportSpawns()
spawn.PhaseId = phaseId;
spawn.PhaseGroup = phaseGroupId;
for (uint32 mapId : transportTemplate->MapIds)
_transportsByMap[mapId].insert(&spawn);
} while (result->NextRow());
}
@@ -484,7 +487,7 @@ static void InitializeLeg(TransportPathLeg* leg, std::vector<TransportPathEvent>
leg->Segments.resize(pauseItr + 1);
}
void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport, std::set<uint32>* mapsUsed)
void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport)
{
uint32 pathId = goInfo->moTransport.taxiPathID;
TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathId];
@@ -522,21 +525,21 @@ void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTempl
if (node->ArrivalEventID || node->DepartureEventID)
events.push_back(node);
mapsUsed->insert(node->ContinentID);
transport->MapIds.insert(node->ContinentID);
}
if (!leg->Spline)
InitializeLeg(leg, &transport->Events, pathPoints, pauses, events, goInfo, totalTime);
if (mapsUsed->size() > 1)
if (transport->MapIds.size() > 1)
{
for (uint32 mapId : *mapsUsed)
for (uint32 mapId : transport->MapIds)
ASSERT(!sMapStore.LookupEntry(mapId)->Instanceable());
transport->InInstance = false;
}
else
transport->InInstance = sMapStore.LookupEntry(*mapsUsed->begin())->Instanceable();
transport->InInstance = sMapStore.LookupEntry(*transport->MapIds.begin())->Instanceable();
transport->TotalPathTime = totalTime;
}
@@ -559,19 +562,15 @@ void TransportMgr::AddPathRotationToTransport(uint32 transportEntry, uint32 time
animNode.TotalTime = timeSeg;
}
Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid /*= 0*/, Map* map /*= nullptr*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
Transport* TransportMgr::CreateTransport(uint32 entry, Map* map, ObjectGuid::LowType guid /*= 0*/, uint8 phaseUseFlags /*= 0*/, uint32 phaseId /*= 0*/, uint32 phaseGroupId /*= 0*/)
{
// instance case, execute GetGameObjectEntry hook
if (map)
{
// SetZoneScript() is called after adding to map, so fetch the script using map
if (map->IsDungeon())
if (InstanceScript* instance = static_cast<InstanceMap*>(map)->GetInstanceScript())
entry = instance->GetGameObjectEntry(0, entry);
// SetZoneScript() is called after adding to map, so fetch the script using map
if (InstanceMap* instanceMap = map->ToInstanceMap())
if (InstanceScript* instance = instanceMap->GetInstanceScript())
entry = instance->GetGameObjectEntry(0, entry);
if (!entry)
return nullptr;
}
if (!entry)
return nullptr;
TransportTemplate const* tInfo = GetTransportTemplate(entry);
if (!tInfo)
@@ -598,8 +597,8 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid
float o = startingPosition->GetOrientation();
// initialize the gameobject base
ObjectGuid::LowType guidLow = guid ? guid : ASSERT_NOTNULL(map)->GenerateLowGuid<HighGuid::Transport>();
if (!trans->Create(guidLow, entry, mapId, x, y, z, o, 255))
ObjectGuid::LowType guidLow = guid ? guid : map->GenerateLowGuid<HighGuid::Transport>();
if (!trans->Create(guidLow, entry, x, y, z, o))
{
delete trans;
return nullptr;
@@ -618,40 +617,26 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid
}
// use preset map for instances (need to know which instance)
trans->SetMap(map ? map : sMapMgr->CreateMap(mapId, nullptr));
if (map && map->IsDungeon())
trans->m_zoneScript = map->ToInstanceMap()->GetInstanceScript();
trans->SetMap(map);
if (InstanceMap* instanceMap = map->ToInstanceMap())
trans->m_zoneScript = instanceMap->GetInstanceScript();
// Passengers will be loaded once a player is near
HashMapHolder<Transport>::Insert(trans);
trans->GetMap()->AddToMap<Transport>(trans);
map->AddToMap<Transport>(trans);
return trans;
}
void TransportMgr::SpawnContinentTransports()
void TransportMgr::CreateTransportsForMap(Map* map)
{
uint32 oldMSTime = getMSTime();
uint32 count = 0;
for (auto itr = _transportSpawns.begin(); itr != _transportSpawns.end(); ++itr)
if (!ASSERT_NOTNULL(GetTransportTemplate(itr->second.TransportGameObjectId))->InInstance)
if (CreateTransport(itr->second.TransportGameObjectId, itr->second.SpawnId, nullptr, itr->second.PhaseUseFlags, itr->second.PhaseId, itr->second.PhaseGroup))
++count;
TC_LOG_INFO("server.loading", ">> Spawned %u continent transports in %u ms", count, GetMSTimeDiffToNow(oldMSTime));
}
void TransportMgr::CreateInstanceTransports(Map* map)
{
auto mapTransports = _instanceTransports.find(map->GetId());
auto mapTransports = _transportsByMap.find(map->GetId());
// no transports here
if (mapTransports == _instanceTransports.end())
if (mapTransports == _transportsByMap.end())
return;
// create transports
for (uint32 transportGameObjectId : mapTransports->second)
CreateTransport(transportGameObjectId, UI64LIT(0), map);
for (TransportSpawn const* transport : mapTransports->second)
CreateTransport(transport->TransportGameObjectId, map, transport->SpawnId, transport->PhaseUseFlags, transport->PhaseId, transport->PhaseGroup);
}
TransportTemplate const* TransportMgr::GetTransportTemplate(uint32 entry) const

View File

@@ -97,10 +97,12 @@ struct TransportTemplate
std::vector<TransportPathEvent> Events;
Optional<Position> ComputePosition(uint32 time, TransportMovementState* moveState, size_t* legIndex) const;
TransportPathLeg const* GetLegForTime(uint32 time) const;
uint32 GetNextPauseWaypointTimestamp(uint32 time) const;
double CalculateDistanceMoved(double timePassedInSegment, double segmentDuration, bool isFirstSegment, bool isLastSegment) const;
std::set<uint32> MapIds;
bool InInstance = false;
};
@@ -142,13 +144,10 @@ class TC_GAME_API TransportMgr
void LoadTransportSpawns();
// Creates a transport using given GameObject template entry
Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = UI64LIT(0), Map* map = nullptr, uint8 phaseUseFlags = 0, uint32 phaseId = 0, uint32 phaseGroupId = 0);
Transport* CreateTransport(uint32 entry, Map* map, ObjectGuid::LowType guid = 0, uint8 phaseUseFlags = 0, uint32 phaseId = 0, uint32 phaseGroupId = 0);
// Spawns all continent transports, used at core startup
void SpawnContinentTransports();
// creates all transports for instance
void CreateInstanceTransports(Map* map);
// creates all transports for map
void CreateTransportsForMap(Map* map);
TransportTemplate const* GetTransportTemplate(uint32 entry) const;
@@ -160,10 +159,12 @@ class TC_GAME_API TransportMgr
TransportMgr();
~TransportMgr();
TransportMgr(TransportMgr const&) = delete;
TransportMgr(TransportMgr&&) = delete;
TransportMgr& operator=(TransportMgr const&) = delete;
TransportMgr& operator=(TransportMgr&&) = delete;
// Generates and precaches a path for transport to avoid generation each time transport instance is created
void GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport, std::set<uint32>* mapsUsed);
void GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport);
void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node);
@@ -173,7 +174,7 @@ class TC_GAME_API TransportMgr
std::unordered_map<uint32, TransportTemplate> _transportTemplates;
// Container storing transport entries to create for instanced maps
std::unordered_map<uint32, std::set<uint32>> _instanceTransports;
std::unordered_map<uint32, std::set<TransportSpawn*>> _transportsByMap;
std::map<uint32, TransportAnimation> _transportAnimations;

View File

@@ -2420,9 +2420,6 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Starting Battlefield System");
sBattlefieldMgr->InitBattlefield();
TC_LOG_INFO("server.loading", "Loading Transports...");
sTransportMgr->SpawnContinentTransports();
///- Initialize Warden
TC_LOG_INFO("server.loading", "Loading Warden Checks...");
sWardenCheckMgr->LoadWardenChecks();

View File

@@ -1144,7 +1144,7 @@ class npc_jaina_or_sylvanas_escape_hor : public CreatureScript
me->RemoveAurasDueToSpell(SPELL_HARVEST_SOUL);
if (_instance->GetData(DATA_TEAM_IN_INSTANCE) == ALLIANCE)
Talk(SAY_JAINA_ESCAPE_9);
if (Transport* gunship = ObjectAccessor::GetTransportOnMap(*me, _instance->GetGuidData(DATA_GUNSHIP)))
if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_GUNSHIP)))
gunship->EnableMovement(true);
_instance->SetBossState(DATA_THE_LICH_KING_ESCAPE, DONE);
break;
@@ -1216,7 +1216,7 @@ class npc_the_lich_king_escape_hor : public CreatureScript
if (Creature* target = ObjectAccessor::GetCreature(*me, _instance->GetGuidData(DATA_ESCAPE_LEADER)))
DoCast(target, SPELL_HARVEST_SOUL);
if (Transport* gunship = ObjectAccessor::GetTransportOnMap(*me, _instance->GetGuidData(DATA_GUNSHIP)))
if (Transport* gunship = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_GUNSHIP)))
gunship->EnableMovement(true);
break;
default:

View File

@@ -391,7 +391,7 @@ class instance_halls_of_reflection : public InstanceMapScript
_teamInInstance = player->GetTeam();
}
if (Transport* gunship = sTransportMgr->CreateTransport(_teamInInstance == HORDE ? GO_ORGRIMS_HAMMER : GO_THE_SKYBREAKER, UI64LIT(0), instance))
if (Transport* gunship = sTransportMgr->CreateTransport(_teamInInstance == HORDE ? GO_ORGRIMS_HAMMER : GO_THE_SKYBREAKER, instance))
gunship->EnableMovement(GetBossState(DATA_THE_LICH_KING_ESCAPE) == DONE);
}

View File

@@ -499,10 +499,10 @@ public:
{
_caster->CastSpell(_caster, _spellId, true);
if (Transport* go = HashMapHolder<Transport>::Find(_transport))
if (Transport* go = ObjectAccessor::GetTransport(*_caster, _transport))
go->AddObjectToRemoveList();
if (Transport* go = HashMapHolder<Transport>::Find(_otherTransport))
if (Transport* go = ObjectAccessor::GetTransport(*_caster, _otherTransport))
go->AddObjectToRemoveList();
return true;
@@ -775,7 +775,7 @@ class npc_gunship : public CreatureScript
if (isVictory)
{
if (Transport* otherTransport = HashMapHolder<Transport>::Find(instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
if (Transport* otherTransport = ObjectAccessor::GetTransport(*me, instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
otherTransport->EnableMovement(true);
if (Transport* transport = dynamic_cast<Transport*>(me->GetTransport()))
@@ -1000,7 +1000,7 @@ struct npc_high_overlord_saurfang_igb : public ScriptedAI
Talk(SAY_SAURFANG_INTRO_2);
break;
case EVENT_INTRO_SUMMON_SKYBREAKER:
sTransportMgr->CreateTransport(GO_THE_SKYBREAKER_H, UI64LIT(0), me->GetMap());
sTransportMgr->CreateTransport(GO_THE_SKYBREAKER_H, me->GetMap());
break;
case EVENT_INTRO_H_3:
Talk(SAY_SAURFANG_INTRO_3);
@@ -1034,7 +1034,7 @@ struct npc_high_overlord_saurfang_igb : public ScriptedAI
if (Transport* orgrimsHammer = dynamic_cast<Transport*>(me->GetTransport()))
orgrimsHammer->SummonPassenger(NPC_TELEPORT_PORTAL, OrgrimsHammerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000);
if (Transport* skybreaker = HashMapHolder<Transport>::Find(_instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
if (Transport* skybreaker = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
skybreaker->SummonPassenger(NPC_TELEPORT_EXIT, SkybreakerTeleportExit, TEMPSUMMON_TIMED_DESPAWN, nullptr, 23000);
_events.ScheduleEvent(EVENT_ADDS_BOARD_YELL, 6s);
@@ -1257,7 +1257,7 @@ struct npc_muradin_bronzebeard_igb : public ScriptedAI
Talk(SAY_MURADIN_INTRO_2);
break;
case EVENT_INTRO_SUMMON_ORGRIMS_HAMMER:
sTransportMgr->CreateTransport(GO_ORGRIMS_HAMMER_A, UI64LIT(0), me->GetMap());
sTransportMgr->CreateTransport(GO_ORGRIMS_HAMMER_A, me->GetMap());
break;
case EVENT_INTRO_A_3:
Talk(SAY_MURADIN_INTRO_3);
@@ -1294,7 +1294,7 @@ struct npc_muradin_bronzebeard_igb : public ScriptedAI
if (Transport* skybreaker = dynamic_cast<Transport*>(me->GetTransport()))
skybreaker->SummonPassenger(NPC_TELEPORT_PORTAL, SkybreakerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000);
if (Transport* orgrimsHammer = HashMapHolder<Transport>::Find(_instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
if (Transport* orgrimsHammer = ObjectAccessor::GetTransport(*me, _instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
orgrimsHammer->SummonPassenger(NPC_TELEPORT_EXIT, OrgrimsHammerTeleportExit, TEMPSUMMON_TIMED_DESPAWN, nullptr, 23000);
_events.ScheduleEvent(EVENT_ADDS_BOARD_YELL, 6s);
@@ -1421,7 +1421,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI
if (!myTransport)
return;
if (Transport* destTransport = HashMapHolder<Transport>::Find(Instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
if (Transport* destTransport = ObjectAccessor::GetTransport(*me, Instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE)))
destTransport->CalculatePassengerPosition(x, y, z, &o);
float angle = frand(0, float(M_PI) * 2.0f);
@@ -2133,7 +2133,7 @@ class spell_igb_gunship_fall_teleport : public SpellScript
void SelectTransport(WorldObject*& target)
{
if (InstanceScript* instance = target->GetInstanceScript())
target = HashMapHolder<Transport>::Find(instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE));
target = ObjectAccessor::GetTransport(*GetCaster(), instance->GetGuidData(DATA_ICECROWN_GUNSHIP_BATTLE));
}
void RelocateDest(SpellEffIndex /*effIndex*/)

View File

@@ -1036,7 +1036,7 @@ class instance_icecrown_citadel : public InstanceMapScript
{
SetBossState(DATA_ICECROWN_GUNSHIP_BATTLE, NOT_STARTED);
uint32 gunshipEntry = TeamInInstance == HORDE ? GO_ORGRIMS_HAMMER_H : GO_THE_SKYBREAKER_A;
if (Transport* gunship = sTransportMgr->CreateTransport(gunshipEntry, UI64LIT(0), instance))
if (Transport* gunship = sTransportMgr->CreateTransport(gunshipEntry, instance))
GunshipGUID = gunship->GetGUID();
}
}