diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-06-13 20:06:26 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-06-13 20:06:26 +0200 |
commit | cace41449771bbe692e1a45c4d38b15a12f6496e (patch) | |
tree | bb4dda1bd73f71f846916617a75e41a5075aaf4d /src | |
parent | 8f537b96868647d73aacd576bbe90bda138dd589 (diff) |
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
Diffstat (limited to 'src')
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(); } } |