diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp index a6c77c3448..f17a6fe765 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundIC.cpp @@ -356,8 +356,8 @@ bool BattlegroundIC::SetupBattleground() return false; } - gunshipHorde = sTransportMgr->CreateTransport(GO_HORDE_GUNSHIP, 0, GetBgMap()); - gunshipAlliance = sTransportMgr->CreateTransport(GO_ALLIANCE_GUNSHIP, 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 a2aba66662..585cd1ae77 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -17312,8 +17312,22 @@ bool Player::LoadFromDB(ObjectGuid guid, CharacterDatabaseQueryHolder const& hol ObjectGuid transGUID(HighGuid::Mo_Transport, transLowGUID); Transport* transport = nullptr; - if (Transport* go = HashMapHolder::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) { diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 3971e6f7cd..42cda37bae 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -100,7 +100,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); @@ -116,7 +116,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: %u 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; } @@ -147,11 +147,18 @@ bool Transport::Create(ObjectGuid::LowType guidlow, uint32 entry, uint32 mapid, SetDisplayId(goinfo->displayId); SetGoState(!goinfo->moTransport.canBeStopped ? GO_STATE_READY : GO_STATE_ACTIVE); SetGoType(GAMEOBJECT_TYPE_MO_TRANSPORT); - SetGoAnimProgress(animprogress); + SetGoAnimProgress(255); SetName(goinfo->name); SetLocalRotation(0.0f, 0.0f, 0.0f, 1.0f); SetParentRotation(QuaternionData()); + size_t legIndex; + if (Optional position = _transportInfo->ComputePosition(_pathProgress, nullptr, &legIndex)) + { + Relocate(position->GetPositionX(), position->GetPositionY(), position->GetPositionZ(), position->GetOrientation()); + _currentPathLeg = legIndex; + } + m_model = CreateModel(); return true; } @@ -204,7 +211,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; } @@ -228,13 +238,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) @@ -267,11 +278,6 @@ void Transport::Update(uint32 diff) } } -void Transport::DelayedUpdate(uint32 /*diff*/) -{ - DelayedTeleportTransport(); -} - void Transport::AddPassenger(WorldObject* passenger) { if (!IsInWorld()) @@ -595,14 +601,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 @@ -631,21 +635,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(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) @@ -657,7 +683,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)) + if (!obj->ToPlayer()->TeleportTo(newMapid, destX, destY, destZ, destO, TELE_TO_NOT_LEAVE_TRANSPORT)) RemovePassenger(obj); break; case TYPEID_DYNAMICOBJECT: @@ -668,9 +694,6 @@ void Transport::DelayedTeleportTransport() break; } } - - Relocate(x, y, z, o); - GetMap()->AddToMap(this); } void Transport::UpdatePassengerPositions(PassengerSet const& passengers) @@ -696,3 +719,8 @@ void Transport::BuildUpdate(UpdateDataMapType& data_map) ClearUpdateMask(true); } + +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 cd069a07a5..f47fe49251 100644 --- a/src/server/game/Entities/Transport/Transport.h +++ b/src/server/game/Entities/Transport/Transport.h @@ -28,7 +28,7 @@ struct CreatureData; 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; @@ -103,8 +102,12 @@ class TC_GAME_API Transport : public GameObject, public TransportBase void SetDelayedAddModelToMap() { _delayedAddModel = true; } + //! 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); + 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 DelayedTeleportTransport(); void UpdatePassengerPositions(PassengerSet const& passengers); @@ -121,7 +124,6 @@ class TC_GAME_API Transport : public GameObject, public TransportBase PassengerSet _staticPassengers; bool _delayedAddModel; - Optional _delayedTeleport; }; #endif diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index 684e0a0690..e247209904 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -33,9 +33,8 @@ template void HashMapHolder::Insert(T* o) { - static_assert(std::is_same::value - || std::is_same::value, - "Only Player and Transport can be registered in global HashMapHolder"); + static_assert(std::is_same::value, + "Only Player can be registered in global HashMapHolder"); std::unique_lock lock(*GetLock()); @@ -79,7 +78,6 @@ HashMapHolder::MapType const& ObjectAccessor::GetPlayers() } template class TC_GAME_API HashMapHolder; -template class TC_GAME_API HashMapHolder; namespace PlayerNameMapHolder { diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index 76546e59a6..95b3da42de 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -77,6 +77,10 @@ void WorldSession::HandleMoveWorldportAck() Map* oldMap = GetPlayer()->GetMap(); Map* newMap = sMapMgr->CreateMap(loc.GetMapId(), GetPlayer()); + MovementInfo::TransportInfo transportInfo = GetPlayer()->m_movementInfo.transport; + if (TransportBase* transport = GetPlayer()->GetTransport()) + transport->RemovePassenger(GetPlayer()); + if (GetPlayer()->IsInWorld()) { TC_LOG_ERROR("network", "%s %s is still in world when teleported from map %s (%u) to new map %s (%u)", GetPlayer()->GetGUID().ToString().c_str(), GetPlayer()->GetName().c_str(), oldMap->GetMapName(), oldMap->GetId(), newMap ? newMap->GetMapName() : "Unknown", loc.GetMapId()); @@ -102,6 +106,14 @@ void WorldSession::HandleMoveWorldportAck() GetPlayer()->SetMap(newMap); GetPlayer()->SendInitialPacketsBeforeAddToMap(); + + // move player between transport copies on each map + if (Transport* newTransport = newMap->GetTransport(transportInfo.guid)) + { + GetPlayer()->m_movementInfo.transport = transportInfo; + newTransport->AddPassenger(GetPlayer()); + } + if (!GetPlayer()->GetMap()->AddPlayerToMap(GetPlayer())) { TC_LOG_ERROR("network", "WORLD: failed to teleport player %s (%d) 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 6fe0201d47..2dbffc1147 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -363,6 +363,9 @@ i_scriptLock(false), _respawnCheckTimer(0) Map::InitVisibilityDistance(); _weatherUpdateTimer.SetInterval(time_t(1 * IN_MILLISECONDS)); + + sTransportMgr->CreateTransportsForMap(this); + MMAP::MMapFactory::createOrGetMMapManager()->loadMapInstance(sWorld->GetDataPath(), GetId(), i_InstanceId); sScriptMgr->OnCreateMap(this); @@ -546,13 +549,6 @@ void Map::DeleteFromWorld(Player* player) delete player; } -template<> -void Map::DeleteFromWorld(Transport* transport) -{ - ObjectAccessor::RemoveObject(transport); - delete transport; -} - void Map::EnsureGridCreated(const GridCoord &p) { std::lock_guard lock(_gridLock); @@ -774,15 +770,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()); @@ -952,9 +949,6 @@ void Map::Update(uint32 t_diff) WorldObject* obj = *_transportsUpdateIter; ++_transportsUpdateIter; - if (!obj->IsInWorld()) - continue; - obj->Update(t_diff); } @@ -1123,18 +1117,19 @@ 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); + + 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()); @@ -2879,10 +2874,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()); @@ -2900,7 +2895,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()); @@ -2918,6 +2913,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)) { @@ -3451,17 +3449,6 @@ bool Map::IsSpawnGroupActive(uint32 groupId) const 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 efe736a0d5..3fbd7ded2f 100644 --- a/src/server/game/Maps/TransportMgr.cpp +++ b/src/server/game/Maps/TransportMgr.cpp @@ -45,21 +45,16 @@ Optional TransportTemplate::ComputePosition(uint32 time, TransportMove time %= TotalPathTime; // find leg - auto legItr = PathLegs.begin(); - while (legItr->StartTimestamp + legItr->Duration <= time) - { - ++legItr; - - if (legItr == PathLegs.end()) - return { }; - } + TransportPathLeg const* leg = GetLegForTime(time); + if (!leg) + 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; @@ -78,26 +73,54 @@ Optional 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) @@ -152,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; @@ -220,13 +224,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 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()); @@ -264,7 +262,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; @@ -314,6 +313,9 @@ void TransportMgr::LoadTransportSpawns() spawn.PhaseId = phaseId; spawn.PhaseGroup = phaseGroupId; + for (uint32 mapId : transportTemplate->MapIds) + _transportsByMap[mapId].insert(&spawn); + } while (result->NextRow()); } @@ -482,7 +484,7 @@ static void InitializeLeg(TransportPathLeg* leg, std::vector leg->Segments.resize(pauseItr + 1); } -void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport, std::set* mapsUsed) +void TransportMgr::GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport) { uint32 pathId = goInfo->moTransport.taxiPathId; TaxiPathNodeList const& path = sTaxiPathNodesByPath[pathId]; @@ -520,21 +522,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; } @@ -557,19 +559,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(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,7 +596,7 @@ Transport* TransportMgr::CreateTransport(uint32 entry, ObjectGuid::LowType guid // initialize the gameobject base ObjectGuid::LowType guidLow = guid ? guid : sObjectMgr->GetGenerator().Generate(); - if (!trans->Create(guidLow, entry, mapId, x, y, z, o, 255)) + if (!trans->Create(guidLow, entry, x, y, z, o)) { delete trans; return nullptr; @@ -617,41 +615,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::Insert(trans); - trans->GetMap()->AddToMap(trans); + map->AddToMap(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 diff --git a/src/server/game/Maps/TransportMgr.h b/src/server/game/Maps/TransportMgr.h index 8c3ab3ffda..8820313ac1 100644 --- a/src/server/game/Maps/TransportMgr.h +++ b/src/server/game/Maps/TransportMgr.h @@ -97,10 +97,12 @@ struct TransportTemplate std::vector Events; Optional 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 MapIds; bool InInstance = false; }; @@ -142,13 +144,10 @@ public: void LoadTransportSpawns(); // Creates a transport using given GameObject template entry - Transport* CreateTransport(uint32 entry, ObjectGuid::LowType guid = 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 @@ private: 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* mapsUsed); + void GeneratePath(GameObjectTemplate const* goInfo, TransportTemplate* transport); void AddPathNodeToTransport(uint32 transportEntry, uint32 timeSeg, TransportAnimationEntry const* node); @@ -173,7 +174,7 @@ private: std::unordered_map _transportTemplates; // Container storing transport entries to create for instanced maps - std::unordered_map> _instanceTransports; + std::unordered_map> _transportsByMap; std::map _transportAnimations; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 2a827f9d0d..ba7918261b 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2297,9 +2297,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/instance_halls_of_reflection.cpp b/src/server/scripts/Northrend/FrozenHalls/HallsOfReflection/instance_halls_of_reflection.cpp index 84f4a09842..eadb5a0ec2 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 @@ -393,7 +393,7 @@ class instance_halls_of_reflection : public InstanceMapScript _teamInInstance = player->GetTeam(); } - if (Transport* gunship = sTransportMgr->CreateTransport(_teamInInstance == HORDE ? GO_ORGRIMS_HAMMER : GO_THE_SKYBREAKER, 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 7fdf0e3088..3b4642ed4f 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/boss_icecrown_gunship_battle.cpp @@ -495,11 +495,10 @@ public: { _caster->CastSpell(_caster, _spellId, true); - if (Transport* go = HashMapHolder::Find(_transport)) + if (Transport* go = ObjectAccessor::GetTransport(*_caster, _transport)) go->AddObjectToRemoveList(); - - if (Transport* go = HashMapHolder::Find(_otherTransport)) + if (Transport* go = ObjectAccessor::GetTransport(*_caster, _otherTransport)) go->AddObjectToRemoveList(); return true; @@ -770,7 +769,7 @@ class npc_gunship : public CreatureScript if (isVictory) { - if (Transport* otherTransport = HashMapHolder::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(me->GetTransport())) @@ -998,7 +997,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript Talk(SAY_SAURFANG_INTRO_2); break; case EVENT_INTRO_SUMMON_SKYBREAKER: - sTransportMgr->CreateTransport(GO_THE_SKYBREAKER_H, 0, me->GetMap()); + sTransportMgr->CreateTransport(GO_THE_SKYBREAKER_H, me->GetMap()); break; case EVENT_INTRO_H_3: Talk(SAY_SAURFANG_INTRO_3); @@ -1032,7 +1031,7 @@ class npc_high_overlord_saurfang_igb : public CreatureScript if (Transport* orgrimsHammer = dynamic_cast(me->GetTransport())) orgrimsHammer->SummonPassenger(NPC_TELEPORT_PORTAL, OrgrimsHammerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000); - if (Transport* skybreaker = HashMapHolder::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, 6000); @@ -1264,7 +1263,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript Talk(SAY_MURADIN_INTRO_2); break; case EVENT_INTRO_SUMMON_ORGRIMS_HAMMER: - sTransportMgr->CreateTransport(GO_ORGRIMS_HAMMER_A, 0, me->GetMap()); + sTransportMgr->CreateTransport(GO_ORGRIMS_HAMMER_A, me->GetMap()); break; case EVENT_INTRO_A_3: Talk(SAY_MURADIN_INTRO_3); @@ -1301,7 +1300,7 @@ class npc_muradin_bronzebeard_igb : public CreatureScript if (Transport* skybreaker = dynamic_cast(me->GetTransport())) skybreaker->SummonPassenger(NPC_TELEPORT_PORTAL, SkybreakerTeleportPortal, TEMPSUMMON_TIMED_DESPAWN, nullptr, 21000); - if (Transport* orgrimsHammer = HashMapHolder::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, 6000); @@ -1447,7 +1446,7 @@ struct npc_gunship_boarding_addAI : public gunship_npc_AI if (!myTransport) return; - if (Transport* destTransport = HashMapHolder::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); @@ -2296,7 +2295,7 @@ class spell_igb_gunship_fall_teleport : public SpellScriptLoader void SelectTransport(WorldObject*& target) { if (InstanceScript* instance = target->GetInstanceScript()) - target = HashMapHolder::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 e5175d7489..069d512b50 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/instance_icecrown_citadel.cpp @@ -900,7 +900,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, 0, instance)) + if (Transport* gunship = sTransportMgr->CreateTransport(gunshipEntry, instance)) GunshipGUID = gunship->GetGUID(); } }