aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Maps
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2022-06-13 20:06:26 +0200
committerShauren <shauren.trinity@gmail.com>2022-06-13 20:06:26 +0200
commitcace41449771bbe692e1a45c4d38b15a12f6496e (patch)
treebb4dda1bd73f71f846916617a75e41a5075aaf4d /src/server/game/Maps
parent8f537b96868647d73aacd576bbe90bda138dd589 (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/server/game/Maps')
-rw-r--r--src/server/game/Maps/Map.cpp59
-rw-r--r--src/server/game/Maps/TransportMgr.cpp153
-rw-r--r--src/server/game/Maps/TransportMgr.h17
3 files changed, 101 insertions, 128 deletions
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;