diff options
15 files changed, 220 insertions, 212 deletions
diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index 4af2912c388..f27c00e387b 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -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) { diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 481f18c4b82..b72333f397a 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -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); - m_homebindAreaId = sMapMgr->GetAreaId(PhasingHandler::GetEmptyPhaseShift(), m_homebind); - - saveHomebindToDb(); - ok = true; + saveHomebindToDb(); + ok = true; + } } if (!ok) diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 906fd3793a0..4c9f6964ae7 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -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; +} diff --git a/src/server/game/Entities/Transport/Transport.h b/src/server/game/Entities/Transport/Transport.h index f5e5a30e369..46edfebd082 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -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 diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index f2b70f43303..35160618084 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -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); diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h index 1ff11bb6b77..8c1ce2d5645 100644 --- a/src/server/game/Globals/ObjectAccessor.h +++ b/src/server/game/Globals/ObjectAccessor.h @@ -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); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index a8cd953abb7..ce38b918519 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -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!", diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 41d3d2a9abc..174b3fda99a 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -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 ! diff --git a/src/server/game/Maps/TransportMgr.cpp b/src/server/game/Maps/TransportMgr.cpp index 3c8fcc3498a..21d41d189ed 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -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() -{ - 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) +void TransportMgr::CreateTransportsForMap(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 diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 66f6d59e35c..cdf5841a851 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -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; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index c483947f5bf..e58ce88ef86 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -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(); diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp index 96025b629b1..a6e17d673be 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/halls_of_reflection.cpp @@ -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: diff --git a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index b4c055fb5ac..f9deeeaa26b 100644 --- a/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp @@ -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); } diff --git a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp index 0831cda0605..ef221739675 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -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*/) diff --git a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp index 4a737757efb..21fb4a3b25c 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -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(); } } |