aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2020-05-24 22:34:25 +0200
committerShauren <shauren.trinity@gmail.com>2020-05-24 22:34:25 +0200
commiteba31dea27b7fdc4a49c024898ef3a01bcbc7295 (patch)
tree4be401cb2969769c92b571e1b8d04555f633693e /src/server/game
parentebb6f12db811d78a538982cca9b8cc1887fc2527 (diff)
Core/Maps: Improvements to terrain swap handling
* Fixed memory leak when unloading grids * Handle child maps being entered * Allow chaining more child maps (Draenor -> Tanaan Jungle -> Tanaan Jungle - No Hubs Phase)
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Entities/Player/Player.cpp4
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp2
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp2
-rw-r--r--src/server/game/Maps/Map.cpp210
-rw-r--r--src/server/game/Maps/Map.h53
-rw-r--r--src/server/game/Maps/MapManager.cpp19
-rw-r--r--src/server/game/Maps/MapManager.h12
-rw-r--r--src/server/game/Phasing/PhasingHandler.cpp13
-rw-r--r--src/server/game/World/World.cpp8
9 files changed, 177 insertions, 146 deletions
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 2ad9cd137b6..dbe5e69ed8a 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -4791,7 +4791,7 @@ void Player::RepopAtGraveyard()
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId());
// Such zones are considered unreachable as a ghost and the player must be automatically revived
- if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
+ if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPhaseShift(), GetPositionX(), GetPositionY()))
{
ResurrectPlayer(0.5f);
SpawnCorpseBones();
@@ -4826,7 +4826,7 @@ void Player::RepopAtGraveyard()
GetSession()->SendPacket(packet.Write());
}
}
- else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY()))
+ else if (GetPositionZ() < GetMap()->GetMinHeight(GetPhaseShift(), GetPositionX(), GetPositionY()))
TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation());
RemovePlayerFlag(PLAYER_FLAGS_IS_OUT_OF_BOUNDS);
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 25eacce03f9..c4df3ff421c 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -429,7 +429,7 @@ void WorldSession::HandleMovementOpcode(OpcodeClient opcode, MovementInfo& movem
plrMover->UpdateFallInformationIfNeed(movementInfo, opcode);
- if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
+ if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(plrMover->GetPhaseShift(), movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY()))
{
if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player)))
{
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 6d635c8ffdb..7df727bfec1 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -144,7 +144,7 @@ void WorldSession::HandleQueryCorpseLocation(WorldPackets::Query::QueryCorpseLoc
if (corpseMapEntry->IsDungeon() && corpseMapEntry->CorpseMapID >= 0)
{
// if corpse map have entrance
- if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->CorpseMapID))
+ if (Map* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->CorpseMapID))
{
mapID = corpseMapEntry->CorpseMapID;
x = corpseMapEntry->Corpse.X;
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 24392412710..5e00ed3b83e 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -90,7 +90,23 @@ Map::~Map()
MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId);
}
-bool Map::ExistMap(uint32 mapid, int gx, int gy)
+void Map::DiscoverGridMapFiles()
+{
+ for (uint32 gx = 0; gx < MAX_NUMBER_OF_GRIDS; ++gx)
+ for (uint32 gy = 0; gy < MAX_NUMBER_OF_GRIDS; ++gy)
+ i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = ExistMap(GetId(), gx, gy, false);
+}
+
+Map* Map::GetRootParentTerrainMap()
+{
+ Map* map = this;
+ while (map != map->m_parentTerrainMap)
+ map = map->m_parentTerrainMap;
+
+ return map;
+}
+
+bool Map::ExistMap(uint32 mapid, int gx, int gy, bool log /*= true*/)
{
std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), mapid, gx, gy);
@@ -98,8 +114,11 @@ bool Map::ExistMap(uint32 mapid, int gx, int gy)
FILE* file = fopen(fileName.c_str(), "rb");
if (!file)
{
- TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName.c_str());
- TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath()+"maps/").c_str());
+ if (log)
+ {
+ TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName.c_str());
+ TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "maps/").c_str());
+ }
}
else
{
@@ -107,8 +126,11 @@ bool Map::ExistMap(uint32 mapid, int gx, int gy)
if (fread(&header, sizeof(header), 1, file) == 1)
{
if (header.mapMagic.asUInt != MapMagic.asUInt || header.versionMagic.asUInt != MapVersionMagic.asUInt)
- TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.",
- fileName.c_str(), 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar);
+ {
+ if (log)
+ TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.",
+ fileName.c_str(), 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar);
+ }
else
ret = true;
}
@@ -181,6 +203,7 @@ void Map::LoadVMap(int gx, int gy)
void Map::LoadMap(int gx, int gy)
{
LoadMapImpl(this, gx, gy);
+
for (Map* childBaseMap : *m_childTerrainMaps)
childBaseMap->LoadMap(gx, gy);
}
@@ -190,29 +213,32 @@ void Map::LoadMapImpl(Map* map, int gx, int gy)
if (map->GridMaps[gx][gy])
return;
- Map* parent = map->m_parentMap;
- ++parent->GridMapReference[gx][gy];
-
- // load grid map for base map
- if (parent != map)
- {
- GridCoord ngridCoord = GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy);
- if (!parent->GridMaps[gx][gy])
- parent->EnsureGridCreated(ngridCoord);
-
- map->GridMaps[gx][gy] = parent->GridMaps[gx][gy];
- return;
- }
-
// map file name
std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), map->GetId(), gx, gy);
TC_LOG_DEBUG("maps", "Loading map %s", fileName.c_str());
// loading data
- map->GridMaps[gx][gy] = new GridMap();
- if (!map->GridMaps[gx][gy]->loadData(fileName.c_str()))
- TC_LOG_ERROR("maps", "Error loading map file: %s", fileName.c_str());
+ std::shared_ptr<GridMap> gridMap = std::make_shared<GridMap>();
+ GridMap::LoadResult gridMapLoadResult = gridMap->loadData(fileName.c_str());
+ if (gridMapLoadResult == GridMap::LoadResult::Ok)
+ map->GridMaps[gx][gy] = std::move(gridMap);
+ else
+ {
+ map->i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = false;
+ Map* parentTerrain = map;
+ while (parentTerrain != parentTerrain->m_parentTerrainMap)
+ {
+ map->GridMaps[gx][gy] = parentTerrain->m_parentTerrainMap->GridMaps[gx][gy];
+ if (map->GridMaps[gx][gy])
+ break;
- sScriptMgr->OnLoadGridMap(map, map->GridMaps[gx][gy], gx, gy);
+ parentTerrain = parentTerrain->m_parentTerrainMap;
+ }
+ }
+
+ if (map->GridMaps[gx][gy])
+ sScriptMgr->OnLoadGridMap(map, map->GridMaps[gx][gy].get(), gx, gy);
+ else if (gridMapLoadResult == GridMap::LoadResult::InvalidFile)
+ TC_LOG_ERROR("maps", "Error loading map file: %s", fileName.c_str());
}
void Map::UnloadMap(int gx, int gy)
@@ -225,25 +251,18 @@ void Map::UnloadMap(int gx, int gy)
void Map::UnloadMapImpl(Map* map, int gx, int gy)
{
- if (map->GridMaps[gx][gy])
- {
- Map* parent = map->m_parentMap;
- if (!--parent->GridMapReference[gx][gy])
- {
- parent->GridMaps[gx][gy]->unloadData();
- delete parent->GridMaps[gx][gy];
- parent->GridMaps[gx][gy] = nullptr;
- }
- }
-
map->GridMaps[gx][gy] = nullptr;
}
void Map::LoadMapAndVMap(int gx, int gy)
{
LoadMap(gx, gy);
- LoadVMap(gx, gy);
- LoadMMap(gx, gy);
+ // Only load the data for the base map
+ if (this == m_parentMap)
+ {
+ LoadVMap(gx, gy);
+ LoadMMap(gx, gy);
+ }
}
void Map::LoadAllCells()
@@ -517,7 +536,7 @@ void Map::EnsureGridCreated_i(const GridCoord &p)
{
TC_LOG_DEBUG("maps", "Creating grid[%u, %u] for map %u instance %u", p.x_coord, p.y_coord, GetId(), i_InstanceId);
- NGridType* ngrid = new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld->getBoolConfig(CONFIG_GRID_UNLOAD));
+ NGridType* ngrid = new NGridType(p.x_coord * MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld->getBoolConfig(CONFIG_GRID_UNLOAD));
setNGrid(ngrid, p.x_coord, p.y_coord);
// build a linkage between this map and NGridType
@@ -530,7 +549,22 @@ void Map::EnsureGridCreated_i(const GridCoord &p)
int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord;
if (!GridMaps[gx][gy])
- m_parentTerrainMap->LoadMapAndVMap(gx, gy);
+ {
+ Map* rootParentTerrainMap = m_parentMap->GetRootParentTerrainMap();
+ // because LoadMapAndVMap is always entered using rootParentTerrainMap, we can only lock that once and not have to do it for every child map
+ std::unique_lock<std::mutex> lock(rootParentTerrainMap->_gridLock, std::defer_lock);
+ if (this != rootParentTerrainMap)
+ lock.lock();
+
+ if (!m_parentMap->GridMaps[gx][gy])
+ rootParentTerrainMap->LoadMapAndVMap(gx, gy);
+
+ if (m_parentMap->GridMaps[gx][gy])
+ {
+ GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy];
+ ++rootParentTerrainMap->GridMapReference[gx][gy];
+ }
+ }
}
}
@@ -1827,9 +1861,13 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
// delete grid map, but don't delete if it is from parent map (and thus only reference)
if (GridMaps[gx][gy])
{
- m_parentTerrainMap->UnloadMap(gx, gy);
- VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(m_parentTerrainMap->GetId(), gx, gy);
- MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(m_parentTerrainMap->GetId(), gx, gy);
+ Map* terrainRoot = m_parentMap->GetRootParentTerrainMap();
+ if (!--terrainRoot->GridMapReference[gx][gy])
+ {
+ m_parentMap->GetRootParentTerrainMap()->UnloadMap(gx, gy);
+ VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(terrainRoot->GetId(), gx, gy);
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(terrainRoot->GetId(), gx, gy);
+ }
}
TC_LOG_DEBUG("maps", "Unloading grid[%u, %u] for map %u finished", x, y, GetId());
@@ -1916,7 +1954,6 @@ GridMap::GridMap()
_liquidEntry = nullptr;
_liquidFlags = nullptr;
_liquidMap = nullptr;
- _fileExists = false;
}
GridMap::~GridMap()
@@ -1924,7 +1961,7 @@ GridMap::~GridMap()
unloadData();
}
-bool GridMap::loadData(const char* filename)
+GridMap::LoadResult GridMap::loadData(const char* filename)
{
// Unload old data if exist
unloadData();
@@ -1933,13 +1970,12 @@ bool GridMap::loadData(const char* filename)
// Not return error if file not found
FILE* in = fopen(filename, "rb");
if (!in)
- return true;
+ return LoadResult::FileDoesNotExist;
- _fileExists = true;
if (fread(&header, sizeof(header), 1, in) != 1)
{
fclose(in);
- return false;
+ return LoadResult::InvalidFile;
}
if (header.mapMagic.asUInt == MapMagic.asUInt && header.versionMagic.asUInt == MapVersionMagic.asUInt)
@@ -1949,30 +1985,30 @@ bool GridMap::loadData(const char* filename)
{
TC_LOG_ERROR("maps", "Error loading map area data\n");
fclose(in);
- return false;
+ return LoadResult::InvalidFile;
}
// load up height data
if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize))
{
TC_LOG_ERROR("maps", "Error loading map height data\n");
fclose(in);
- return false;
+ return LoadResult::InvalidFile;
}
// load up liquid data
if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize))
{
TC_LOG_ERROR("maps", "Error loading map liquids data\n");
fclose(in);
- return false;
+ return LoadResult::InvalidFile;
}
fclose(in);
- return true;
+ return LoadResult::Ok;
}
TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s %.*s), %.*s %.*s is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.",
filename, 4, header.mapMagic.asChar, 4, header.versionMagic.asChar, 4, MapMagic.asChar, 4, MapVersionMagic.asChar);
fclose(in);
- return false;
+ return LoadResult::InvalidFile;
}
void GridMap::unloadData()
@@ -1992,7 +2028,6 @@ void GridMap::unloadData()
_liquidFlags = nullptr;
_liquidMap = nullptr;
_gridGetHeight = &GridMap::getHeightFromFlat;
- _fileExists = false;
}
bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/)
@@ -2524,23 +2559,8 @@ inline ZLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 R
return LIQUID_MAP_ABOVE_WATER;
}
-inline GridMap* Map::GetGrid(float x, float y)
-{
- // half opt method
- int gx=(int)(CENTER_GRID_ID - x/SIZE_OF_GRIDS); //grid x
- int gy=(int)(CENTER_GRID_ID - y/SIZE_OF_GRIDS); //grid y
-
- // ensure GridMap is loaded
- EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy));
-
- return GridMaps[gx][gy];
-}
-
GridMap* Map::GetGrid(uint32 mapId, float x, float y)
{
- if (GetId() == mapId)
- return GetGrid(x, y);
-
// half opt method
int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS); //grid x
int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); //grid y
@@ -2548,23 +2568,23 @@ GridMap* Map::GetGrid(uint32 mapId, float x, float y)
// ensure GridMap is loaded
EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy));
- GridMap* grid = GridMaps[gx][gy];
+ GridMap* grid = GridMaps[gx][gy].get();
auto childMapItr = std::find_if(m_childTerrainMaps->begin(), m_childTerrainMaps->end(), [mapId](Map* childTerrainMap) { return childTerrainMap->GetId() == mapId; });
- if (childMapItr != m_childTerrainMaps->end() && (*childMapItr)->GridMaps[gx][gy]->fileExists())
- grid = (*childMapItr)->GridMaps[gx][gy];
+ if (childMapItr != m_childTerrainMaps->end() && (*childMapItr)->GridMaps[gx][gy])
+ grid = (*childMapItr)->GridMaps[gx][gy].get();
return grid;
}
-bool Map::HasGrid(uint32 mapId, int32 gx, int32 gy) const
+bool Map::HasChildMapGridFile(uint32 mapId, int32 gx, int32 gy) const
{
auto childMapItr = std::find_if(m_childTerrainMaps->begin(), m_childTerrainMaps->end(), [mapId](Map* childTerrainMap) { return childTerrainMap->GetId() == mapId; });
- return childMapItr != m_childTerrainMaps->end() && (*childMapItr)->GridMaps[gx][gy] && (*childMapItr)->GridMaps[gx][gy]->fileExists();
+ return childMapItr != m_childTerrainMaps->end() && (*childMapItr)->i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy];
}
-float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/) const
+float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/)
{
- if (const_cast<Map*>(this)->GetGrid(x, y))
+ if (GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
{
// we need ground level (including grid height version) for proper return water level in point
float ground_z = GetHeight(phaseShift, x, y, z, true, 50.0f);
@@ -2580,12 +2600,12 @@ float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y,
return VMAP_INVALID_HEIGHT_VALUE;
}
-float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
+float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/)
{
// find raw .map surface under Z coordinates
float mapHeight = VMAP_INVALID_HEIGHT_VALUE;
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
+ if (GridMap* gmap = GetGrid(terrainMapId, x, y))
{
float gridHeight = gmap->getHeight(x, y);
// look from a bit higher pos to find the floor, ignore under surface case
@@ -2623,9 +2643,9 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float
return mapHeight; // explicitly use map data
}
-float Map::GetMinHeight(float x, float y) const
+float Map::GetMinHeight(PhaseShift const& phaseShift, float x, float y)
{
- if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y))
+ if (GridMap const* grid = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
return grid->getMinHeight(x, y);
return -500.0f;
@@ -2655,7 +2675,7 @@ inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, in
return outdoor;
}
-bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) const
+bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z)
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
@@ -2674,7 +2694,7 @@ bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) co
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
}
-bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
+bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId)
{
float vmap_z = z;
float dynamic_z = z;
@@ -2710,7 +2730,7 @@ bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, u
if (hasVmapAreaInfo || hasDynamicAreaInfo)
{
// check if there's terrain between player height and object height
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
+ if (GridMap* gmap = GetGrid(terrainMapId, x, y))
{
float mapHeight = gmap->getHeight(x, y);
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
@@ -2722,7 +2742,7 @@ bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, u
return false;
}
-uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const
+uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors)
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
@@ -2744,7 +2764,7 @@ uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, b
if (!areaId)
{
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
+ if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
areaId = gmap->getArea(x, y);
// this used while not all *.map files generated (instances)
@@ -2762,12 +2782,12 @@ uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, b
return areaId;
}
-uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const
+uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z)
{
return GetAreaId(phaseShift, x, y, z, nullptr);
}
-uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) const
+uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z)
{
uint32 areaId = GetAreaId(phaseShift, x, y, z);
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId))
@@ -2777,7 +2797,7 @@ uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) c
return areaId;
}
-void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z) const
+void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z)
{
areaid = zoneid = GetAreaId(phaseShift, x, y, z);
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid))
@@ -2785,15 +2805,15 @@ void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32&
zoneid = area->ParentAreaID;
}
-uint8 Map::GetTerrainType(PhaseShift const& phaseShift, float x, float y) const
+uint8 Map::GetTerrainType(PhaseShift const& phaseShift, float x, float y)
{
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
+ if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
return gmap->getTerrainType(x, y);
else
return 0;
}
-ZLiquidStatus Map::getLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const
+ZLiquidStatus Map::getLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data)
{
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
@@ -2858,7 +2878,7 @@ ZLiquidStatus Map::getLiquidStatus(PhaseShift const& phaseShift, float x, float
}
}
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
+ if (GridMap* gmap = GetGrid(terrainMapId, x, y))
{
LiquidData map_data;
ZLiquidStatus map_result = gmap->getLiquidStatus(x, y, z, ReqLiquidType, &map_data);
@@ -2879,9 +2899,9 @@ ZLiquidStatus Map::getLiquidStatus(PhaseShift const& phaseShift, float x, float
return result;
}
-float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const
+float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y)
{
- if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
+ if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
return gmap->getLiquidLevel(x, y);
else
return 0;
@@ -2907,19 +2927,19 @@ bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, floa
return result;
}
-float Map::GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
+float Map::GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/)
{
return std::max<float>(GetStaticHeight(phaseShift, x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift));
}
-bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float pZ, LiquidData* data) const
+bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float pZ, LiquidData* data)
{
LiquidData liquid_status;
LiquidData* liquid_ptr = data ? data : &liquid_status;
return (getLiquidStatus(phaseShift, x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0;
}
-bool Map::IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z) const
+bool Map::IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z)
{
return (getLiquidStatus(phaseShift, x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN) & LIQUID_MAP_UNDER_WATER) != 0;
}
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 0326e5ae698..396867684f9 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -200,7 +200,6 @@ class TC_GAME_API GridMap
uint8 _liquidOffY;
uint8 _liquidWidth;
uint8 _liquidHeight;
- bool _fileExists;
bool loadAreaData(FILE* in, uint32 offset, uint32 size);
bool loadHeightData(FILE* in, uint32 offset, uint32 size);
@@ -217,7 +216,15 @@ class TC_GAME_API GridMap
public:
GridMap();
~GridMap();
- bool loadData(const char* filename);
+
+ enum class LoadResult
+ {
+ Ok,
+ FileDoesNotExist,
+ InvalidFile
+ };
+
+ LoadResult loadData(const char* filename);
void unloadData();
uint16 getArea(float x, float y) const;
@@ -226,7 +233,6 @@ public:
float getLiquidLevel(float x, float y) const;
uint8 getTerrainType(float x, float y) const;
ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0);
- bool fileExists() const { return _fileExists; }
};
#pragma pack(push, 1)
@@ -326,35 +332,38 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
time_t GetGridExpiry() const { return i_gridExpiry; }
- bool HasGrid(uint32 mapId, int32 gx, int32 gy) const;
- static bool ExistMap(uint32 mapid, int gx, int gy);
+ bool HasChildMapGridFile(uint32 mapId, int32 gx, int32 gy) const;
+ static bool ExistMap(uint32 mapid, int gx, int gy, bool log = true);
static bool ExistVMap(uint32 mapid, int gx, int gy);
static void InitStateMachine();
static void DeleteStateMachine();
+ void DiscoverGridMapFiles();
+
+ Map* GetRootParentTerrainMap();
void AddChildTerrainMap(Map* map) { m_childTerrainMaps->push_back(map); map->m_parentTerrainMap = this; }
void UnlinkAllChildTerrainMaps() { m_childTerrainMaps->clear(); }
// some calls like isInWater should not use vmaps due to processor power
// can return INVALID_HEIGHT if under z+2 z coord not found height
- float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
- float GetMinHeight(float x, float y) const;
+ float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH);
+ float GetMinHeight(PhaseShift const& phaseShift, float x, float y);
- ZLiquidStatus getLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const;
+ ZLiquidStatus getLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr);
- uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const;
- bool GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
- uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const;
- uint32 GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) const;
- void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z) const;
+ uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors);
+ bool GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId);
+ uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z);
+ uint32 GetZoneId(PhaseShift const& phaseShift, float x, float y, float z);
+ void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z);
- bool IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) const;
+ bool IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z);
- uint8 GetTerrainType(PhaseShift const& phaseShift, float x, float y) const;
- float GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const;
- bool IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data = nullptr) const;
- bool IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z) const;
+ uint8 GetTerrainType(PhaseShift const& phaseShift, float x, float y);
+ float GetWaterLevel(PhaseShift const& phaseShift, float x, float y);
+ bool IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data = nullptr);
+ bool IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z);
void MoveAllCreaturesInMoveList();
void MoveAllGameObjectsInMoveList();
@@ -493,8 +502,8 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
BattlegroundMap* ToBattlegroundMap() { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap*>(this); else return NULL; }
BattlegroundMap const* ToBattlegroundMap() const { if (IsBattlegroundOrArena()) return reinterpret_cast<BattlegroundMap const*>(this); return NULL; }
- float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false) const;
- float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
+ float GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground = nullptr, bool swim = false);
+ float GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH);
bool isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const;
void Balance() { _dynamicTree.balance(); }
void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); }
@@ -580,7 +589,6 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
void UnloadMap(int gx, int gy);
static void UnloadMapImpl(Map* map, int gx, int gy);
void LoadMMap(int gx, int gy);
- GridMap* GetGrid(float x, float y);
GridMap* GetGrid(uint32 mapId, float x, float y);
void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
@@ -682,8 +690,9 @@ class TC_GAME_API Map : public GridRefManager<NGridType>
std::vector<Map*>* m_childTerrainMaps; // contains m_parentMap of maps that have MapEntry::ParentMapID == GetId()
NGridType* i_grids[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
- GridMap* GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
+ std::shared_ptr<GridMap> GridMaps[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
uint16 GridMapReference[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS];
+ std::bitset<MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS> i_gridFileExists; // cache what grids are available for this map (not including parent/child maps)
std::bitset<TOTAL_NUMBER_OF_CELLS_PER_MAP*TOTAL_NUMBER_OF_CELLS_PER_MAP> marked_cells;
//these functions used to process player/mob aggro reactions and
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index e6ba2294f3d..e01d2dc05b6 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -78,9 +78,9 @@ Map* MapManager::CreateBaseMap(uint32 id)
if (!map)
{
MapEntry const* entry = sMapStore.AssertEntry(id);
- if (entry->ParentMapID != -1)
+ if (entry->ParentMapID != -1 || entry->CosmeticParentMapID != -1)
{
- CreateBaseMap(entry->ParentMapID);
+ CreateBaseMap(entry->ParentMapID != -1 ? entry->ParentMapID : entry->CosmeticParentMapID);
// must have been created by parent map
map = FindBaseMap(id);
@@ -103,6 +103,8 @@ Map* MapManager::CreateBaseMap_i(MapEntry const* mapEntry)
else
map = new Map(mapEntry->ID, i_gridCleanUpDelay, 0, DIFFICULTY_NONE);
+ map->DiscoverGridMapFiles();
+
i_maps[mapEntry->ID] = map;
for (uint32 childMapId : _parentMapData[mapEntry->ID])
@@ -280,16 +282,15 @@ bool MapManager::IsValidMAP(uint32 mapid, bool startUp)
void MapManager::UnloadAll()
{
- // first unlink child maps
+ // first unload maps
for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter)
- iter->second->UnlinkAllChildTerrainMaps();
-
- for (MapMapType::iterator iter = i_maps.begin(); iter != i_maps.end();)
- {
iter->second->UnloadAll();
+
+ // then delete them
+ for (auto iter = i_maps.begin(); iter != i_maps.end(); ++iter)
delete iter->second;
- i_maps.erase(iter++);
- }
+
+ i_maps.clear();
if (m_updater.activated())
m_updater.deactivate();
diff --git a/src/server/game/Maps/MapManager.h b/src/server/game/Maps/MapManager.h
index f1bed487e19..204a81e2182 100644
--- a/src/server/game/Maps/MapManager.h
+++ b/src/server/game/Maps/MapManager.h
@@ -38,23 +38,23 @@ class TC_GAME_API MapManager
Map* CreateMap(uint32 mapId, Player* player, uint32 loginInstanceId=0);
Map* FindMap(uint32 mapId, uint32 instanceId) const;
- uint32 GetAreaId(PhaseShift const& phaseShift, uint32 mapid, float x, float y, float z) const
+ uint32 GetAreaId(PhaseShift const& phaseShift, uint32 mapid, float x, float y, float z)
{
- Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ Map* m = CreateBaseMap(mapid);
return m->GetAreaId(phaseShift, x, y, z);
}
- uint32 GetZoneId(PhaseShift const& phaseShift, uint32 mapid, float x, float y, float z) const
+ uint32 GetZoneId(PhaseShift const& phaseShift, uint32 mapid, float x, float y, float z)
{
- Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ Map* m = CreateBaseMap(mapid);
return m->GetZoneId(phaseShift, x, y, z);
}
void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, uint32 mapid, float x, float y, float z)
{
- Map const* m = const_cast<MapManager*>(this)->CreateBaseMap(mapid);
+ Map* m = CreateBaseMap(mapid);
m->GetZoneAndAreaId(phaseShift, zoneid, areaid, x, y, z);
}
- void Initialize(void);
+ void Initialize();
void InitializeParentMapData(std::unordered_map<uint32, std::vector<uint32>> const& mapData);
void Update(uint32);
diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp
index edb176de644..ad725bade8d 100644
--- a/src/server/game/Phasing/PhasingHandler.cpp
+++ b/src/server/game/Phasing/PhasingHandler.cpp
@@ -487,16 +487,9 @@ uint32 PhasingHandler::GetTerrainMapId(PhaseShift const& phaseShift, Map const*
int32 gx = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.x_coord;
int32 gy = (MAX_NUMBER_OF_GRIDS - 1) - gridCoord.y_coord;
- int32 gxbegin = std::max(gx - 1, 0);
- int32 gxend = std::min(gx + 1, MAX_NUMBER_OF_GRIDS);
- int32 gybegin = std::max(gy - 1, 0);
- int32 gyend = std::min(gy + 1, MAX_NUMBER_OF_GRIDS);
-
- for (auto itr = phaseShift.VisibleMapIds.rbegin(); itr != phaseShift.VisibleMapIds.rend(); ++itr)
- for (int32 gxi = gxbegin; gxi < gxend; ++gxi)
- for (int32 gyi = gybegin; gyi < gyend; ++gyi)
- if (map->HasGrid(itr->first, gxi, gyi))
- return itr->first;
+ for (std::pair<uint32 const, PhaseShift::VisibleMapIdRef> const& visibleMap : phaseShift.VisibleMapIds)
+ if (map->HasChildMapGridFile(visibleMap.first, gx, gy))
+ return visibleMap.first;
return map->GetId();
}
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 03ca4dbf205..fc45fa83113 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1594,7 +1594,15 @@ void World::SetInitialWorldSettings()
{
mapData.emplace(std::piecewise_construct, std::forward_as_tuple(mapEntry->ID), std::forward_as_tuple());
if (mapEntry->ParentMapID != -1)
+ {
+ ASSERT(mapEntry->CosmeticParentMapID == -1 || mapEntry->ParentMapID == mapEntry->CosmeticParentMapID,
+ "Inconsistent parent map data for map %u (ParentMapID = %hd, CosmeticParentMapID = %hd)",
+ mapEntry->ID, mapEntry->ParentMapID, mapEntry->CosmeticParentMapID);
+
mapData[mapEntry->ParentMapID].push_back(mapEntry->ID);
+ }
+ else if (mapEntry->CosmeticParentMapID != -1)
+ mapData[mapEntry->CosmeticParentMapID].push_back(mapEntry->ID);
}
sMapMgr->InitializeParentMapData(mapData);