refactor(Core/Collision): Store collision data on map context (#25049)

This commit is contained in:
Takenbacon 2026-03-22 18:33:04 -07:00 committed by GitHub
parent 80b6984274
commit 27b0ecc6dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 527 additions and 992 deletions

View file

@ -17,7 +17,6 @@
#include "DisableMgr.h"
#include "GameEventMgr.h"
#include "MMapFactory.h"
#include "ObjectMgr.h"
#include "OutdoorPvP.h"
#include "Player.h"
@ -448,5 +447,17 @@ bool DisableMgr::IsPathfindingEnabled(Map const* map)
if (!map)
return false;
return !MMAP::MMapFactory::forbiddenMaps[map->GetId()] && (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena());
// Still not an ideal solution but removes the extra awful forbiddenMaps hack
// int32 f[] = {616 /*EoE*/, 649 /*ToC25*/, 650 /*ToC5*/, -1};
switch (map->GetId())
{
case 616: // EoE
case 649: // ToC25
case 650: // ToC5
return false;
default:
break;
}
return (sWorld->getBoolConfig(CONFIG_ENABLE_MMAPS) ? true : map->IsBattlegroundOrArena());
}

View file

@ -1,6 +1,6 @@
#include "DisableMgr.h"
#include "GridTerrainLoader.h"
#include "MMapFactory.h"
#include "IVMapMgr.h"
#include "Map.h"
#include "MMapMgr.h"
#include "ScriptMgr.h"
#include "VMapFactory.h"
@ -9,6 +9,7 @@
void GridTerrainLoader::LoadTerrain()
{
LoadMap();
if (_map->GetInstanceId() == 0)
{
LoadVMap();
@ -18,13 +19,10 @@ void GridTerrainLoader::LoadTerrain()
void GridTerrainLoader::LoadMap()
{
// Instances will point to the parent maps terrain data
// Instances will point to the parent maps terrain data, no need to load anything.
if (_map->GetInstanceId() != 0)
{
// load grid map for base map
Map* parentMap = const_cast<Map*>(_map->GetParent());
// GetGridTerrainData will create the parent map grid
_grid.SetTerrainData(parentMap->GetGridTerrainDataSharedPtr(GridCoord(_grid.GetX(), _grid.GetY())));
return;
}
@ -51,7 +49,7 @@ void GridTerrainLoader::LoadMap()
void GridTerrainLoader::LoadVMap()
{
int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapMgr()->loadMap((sWorld->GetDataPath() + "vmaps").c_str(), _map->GetId(), _grid.GetX(), _grid.GetY());
int const vmapLoadResult = _map->GetMapCollisionData().LoadVMapTile(_grid.GetX(), _grid.GetY());
switch (vmapLoadResult)
{
case VMAP::VMAP_LOAD_RESULT_OK:
@ -66,15 +64,14 @@ void GridTerrainLoader::LoadVMap()
LOG_DEBUG("maps", "Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
break;
default:
break;
}
}
void GridTerrainLoader::LoadMMap()
{
if (!DisableMgr::IsPathfindingEnabled(_map))
return;
int mmapLoadResult = MMAP::MMapFactory::createOrGetMMapMgr()->loadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
int const mmapLoadResult = _map->GetMapCollisionData().LoadMMapTile(_grid.GetX(), _grid.GetY());
switch (mmapLoadResult)
{
case MMAP::MMAP_LOAD_RESULT_OK:
@ -89,6 +86,8 @@ void GridTerrainLoader::LoadMMap()
LOG_DEBUG("maps", "Ignored MMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
_map->GetMapName(), _map->GetId(), _grid.GetX(), _grid.GetY(), _grid.GetX(), _grid.GetY());
break;
default:
break;
}
}
@ -145,13 +144,3 @@ bool GridTerrainLoader::ExistVMap(uint32 mapid, int gx, int gy)
return true;
}
void GridTerrainUnloader::UnloadTerrain()
{
// Only parent maps manage terrain data
if (_map->GetInstanceId() != 0)
return;
VMAP::VMapFactory::createOrGetVMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMap(_map->GetId(), _grid.GetX(), _grid.GetY());
}

View file

@ -20,6 +20,8 @@
#include "GridDefines.h"
class Map;
class GridTerrainLoader
{
public:
@ -40,17 +42,4 @@ private:
Map* _map;
};
class GridTerrainUnloader
{
public:
GridTerrainUnloader(MapGridType& grid, Map* map)
: _grid(grid), _map(map) { }
void UnloadTerrain();
private:
MapGridType& _grid;
Map* _map;
};
#endif

View file

@ -8,9 +8,19 @@ void MapGridManager::CreateGrid(uint16 const x, uint16 const y)
if (IsGridCreated(x, y))
return;
// If we are an instance, ensure parent map has already created the grid before proceeding.
// Note: grid loading is locked and is safe across multiple map threads in the
// event of multiple child maps attempting to create the same parent map grid
if (_map->GetInstanceId() != 0)
{
Map* parentMap = const_cast<Map*>(_map->GetParent());
parentMap->EnsureGridCreated(GridCoord(x, y));
}
std::unique_ptr<MapGridType> grid = std::make_unique<MapGridType>(x, y);
grid->link(_map);
// Terrain is loading during create (should/can we move this to LoadGrid?)
GridTerrainLoader loader(*grid, _map);
loader.LoadTerrain();
@ -19,6 +29,7 @@ void MapGridManager::CreateGrid(uint16 const x, uint16 const y)
++_createdGridsCount;
}
// Loads objects, terrain already loaded in CreateGrid
bool MapGridManager::LoadGrid(uint16 const x, uint16 const y)
{
MapGridType* grid = GetGrid(x, y);
@ -55,9 +66,6 @@ void MapGridManager::UnloadGrid(uint16 const x, uint16 const y)
grid->VisitAllCells(visitor);
}
GridTerrainUnloader terrainUnloader(*grid, _map);
terrainUnloader.UnloadTerrain();
_mapGrid[x][y] = nullptr;
}

View file

@ -32,7 +32,6 @@
#include "MapInstanced.h"
#include "Metric.h"
#include "MiscPackets.h"
#include "MMapFactory.h"
#include "Object.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
@ -62,13 +61,12 @@ Map::~Map()
if (!m_scriptSchedule.empty())
sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
MMAP::MMapFactory::createOrGetMMapMgr()->unloadMapInstance(GetId(), i_InstanceId);
}
Map::Map(uint32 id, uint32 InstanceId, uint8 SpawnMode, Map* _parent) :
_mapGridManager(this), i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId),
m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0),
_mapGridManager(this), i_mapEntry(sMapStore.LookupEntry(id)), _mapCollisionData(*this, _parent),
i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0),
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), _instanceResetPeriod(0),
_transportsUpdateIter(_transports.end()), i_scriptLock(false), _defaultLight(GetDefaultMapLight(id))
{
m_parentMap = (_parent ? _parent : this);
@ -432,7 +430,7 @@ void Map::UpdatePlayerZoneStats(uint32 oldZone, uint32 newZone)
void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
{
if (t_diff)
_dynamicTree.update(t_diff);
_mapCollisionData.GetDynamicTree().update(t_diff);
// Update world sessions and players
for (m_mapRefIter = m_mapRefMgr.begin(); m_mapRefIter != m_mapRefMgr.end(); ++m_mapRefIter)
@ -1074,9 +1072,9 @@ void Map::UnloadAll()
std::shared_ptr<GridTerrainData> Map::GetGridTerrainDataSharedPtr(GridCoord const& gridCoord)
{
// ensure GridMap is created
EnsureGridCreated(gridCoord);
return _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord)->GetTerrainDataSharedPtr();
MapGridType* grid = _mapGridManager.GetGrid(gridCoord.x_coord, gridCoord.y_coord);
ASSERT(grid); // Grid should always exist during this call
return grid->GetTerrainDataSharedPtr();
}
GridTerrainData* Map::GetGridTerrainData(GridCoord const& gridCoord)
@ -1153,10 +1151,7 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
float vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
if (checkVMap)
{
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist); // look from a bit higher pos to find the floor
}
vmapHeight = _mapCollisionData.GetStaticTree().getHeight(x, y, z, maxSearchDist); // look from a bit higher pos to find the floor
// mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
// vmapheight set for any under Z value or <= INVALID_HEIGHT
@ -1204,12 +1199,11 @@ static inline bool IsInWMOInterior(uint32 mogpFlags)
bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
{
float check_z = z;
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
VMAP::AreaAndLiquidData vdata;
VMAP::AreaAndLiquidData ddata;
bool hasVmapAreaInfo = vmgr->GetAreaAndLiquidData(GetId(), x, y, z, {}, vdata) && vdata.areaInfo.has_value();
bool hasDynamicAreaInfo = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value();
bool hasVmapAreaInfo = _mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, {}, vdata) && vdata.areaInfo.has_value();
bool hasDynamicAreaInfo = _mapCollisionData.GetDynamicTree().GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value();
auto useVmap = [&] { check_z = vdata.floorZ; groupId = vdata.areaInfo->groupId; adtId = vdata.areaInfo->adtId; rootId = vdata.areaInfo->rootId; flags = vdata.areaInfo->mogpFlags; };
auto useDyn = [&] { check_z = ddata.floorZ; groupId = ddata.areaInfo->groupId; adtId = ddata.areaInfo->adtId; rootId = ddata.areaInfo->rootId; flags = ddata.areaInfo->mogpFlags; };
if (hasVmapAreaInfo)
@ -1300,10 +1294,9 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z,
LiquidData liquidData;
liquidData.Status = LIQUID_MAP_NO_WATER;
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
VMAP::AreaAndLiquidData vmapData;
bool useGridLiquid = true;
if (vmgr->GetAreaAndLiquidData(GetId(), x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo)
if (_mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo)
{
useGridLiquid = !vmapData.areaInfo || !IsInWMOInterior(vmapData.areaInfo->mogpFlags);
LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", vmapData.liquidInfo->level, vmapData.floorZ, vmapData.liquidInfo->type);
@ -1383,11 +1376,10 @@ void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y
{
GridTerrainData* gmap = GetGridTerrainData(x, y);
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
VMAP::AreaAndLiquidData vmapData;
// VMAP::AreaAndLiquidData dynData;
VMAP::AreaAndLiquidData* wmoData = nullptr;
vmgr->GetAreaAndLiquidData(GetId(), x, y, z, reqLiquidType, vmapData);
_mapCollisionData.GetStaticTree().GetAreaAndLiquidData(x, y, z, reqLiquidType, vmapData);
// _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, reqLiquidType, dynData);
uint32 gridAreaId = 0;
@ -1548,7 +1540,7 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa
}
}
if ((checks & LINEOFSIGHT_CHECK_VMAP) && !VMAP::VMapFactory::createOrGetVMapMgr()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags))
if ((checks & LINEOFSIGHT_CHECK_VMAP) && !_mapCollisionData.GetStaticTree().isInLineOfSight(x1, y1, z1, x2, y2, z2, ignoreFlags))
{
return false;
}
@ -1561,7 +1553,7 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa
ignoreFlags = VMAP::ModelIgnoreFlags::M2;
}
if (!_dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask, ignoreFlags))
if (!_mapCollisionData.GetDynamicTree().isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask, ignoreFlags))
{
return false;
}
@ -1570,25 +1562,11 @@ bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, floa
return true;
}
bool Map::GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist)
{
G3D::Vector3 startPos(x1, y1, z1);
G3D::Vector3 dstPos(x2, y2, z2);
G3D::Vector3 resultPos;
bool result = _dynamicTree.GetObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist);
rx = resultPos.x;
ry = resultPos.y;
rz = resultPos.z;
return result;
}
float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
{
float h1, h2;
h1 = GetHeight(x, y, z, vmap, maxSearchDist);
h2 = _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask);
h2 = _mapCollisionData.GetDynamicTree().getHeight(x, y, z, maxSearchDist, phasemask);
return std::max<float>(h1, h2);
}
@ -3050,8 +3028,7 @@ bool Map::CheckCollisionAndGetValidCoords(WorldObject const* source, float start
// Unit is not on the ground, check for potential collision via vmaps
if (notOnGround)
{
bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(source->GetMapId(),
startX, startY, startZ + halfHeight,
bool col = _mapCollisionData.GetStaticTree().GetObjectHitPos(startX, startY, startZ + halfHeight,
destX, destY, destZ + halfHeight,
destX, destY, destZ, -CONTACT_DISTANCE);
@ -3065,7 +3042,7 @@ bool Map::CheckCollisionAndGetValidCoords(WorldObject const* source, float start
}
// check dynamic collision
bool col = source->GetMap()->GetObjectHitPos(source->GetPhaseMask(),
bool col = _mapCollisionData.GetDynamicTree().GetObjectHitPos(source->GetPhaseMask(),
startX, startY, startZ + halfHeight,
destX, destY, destZ + halfHeight,
destX, destY, destZ, -CONTACT_DISTANCE);

View file

@ -27,6 +27,7 @@
#include "GameObjectModel.h"
#include "GridDefines.h"
#include "GridRefMgr.h"
#include "MapCollisionData.h"
#include "MapGridManager.h"
#include "MapRefMgr.h"
#include "ObjectDefines.h"
@ -230,8 +231,6 @@ public:
[[nodiscard]] Map const* GetParent() const { return m_parentMap; }
// pussywizard: movemaps, mmaps
[[nodiscard]] std::shared_mutex& GetMMapLock() const { return *(const_cast<std::shared_mutex*>(&MMapLock)); }
// pussywizard:
std::unordered_set<Unit*> i_objectsForDelayedVisibility;
void HandleDelayedVisibility();
@ -389,15 +388,14 @@ public:
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float startX, float startY, float startZ, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
bool CheckCollisionAndGetValidCoords(WorldObject const* source, float startX, float startY, float startZ, float &destX, float &destY, float &destZ, bool failOnCollision = true) const;
void Balance() { _dynamicTree.balance(); }
void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); }
void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); }
[[nodiscard]] bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);}
[[nodiscard]] DynamicMapTree const& GetDynamicMapTree() const { return _dynamicTree; }
bool GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist);
void Balance() { _mapCollisionData.GetDynamicTree().balance(); }
void RemoveGameObjectModel(const GameObjectModel& model) { _mapCollisionData.GetDynamicTree().remove(model); }
void InsertGameObjectModel(const GameObjectModel& model) { _mapCollisionData.GetDynamicTree().insert(model); }
[[nodiscard]] bool ContainsGameObjectModel(const GameObjectModel& model) const { return _mapCollisionData.GetDynamicTree().contains(model);}
[[nodiscard]] DynamicMapTree const& GetDynamicMapTree() const { return _mapCollisionData.GetDynamicTree(); }
[[nodiscard]] float GetGameObjectFloor(uint32 phasemask, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const
{
return _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask);
return _mapCollisionData.GetDynamicTree().getHeight(x, y, z, maxSearchDist, phasemask);
}
/*
RESPAWN TIMES
@ -524,6 +522,9 @@ public:
return 0;
};
MapCollisionData& GetMapCollisionData() { return _mapCollisionData; }
MapCollisionData const& GetMapCollisionData() const { return _mapCollisionData; }
private:
template<class T> void InitializeObject(T* obj);
@ -551,15 +552,14 @@ protected:
void AddToGrid(T* object, Cell const& cell);
std::mutex Lock;
std::shared_mutex MMapLock;
MapGridManager _mapGridManager;
MapEntry const* i_mapEntry;
MapCollisionData _mapCollisionData;
uint8 i_spawnMode;
uint32 i_InstanceId;
uint32 m_unloadTimer;
float m_VisibleDistance;
DynamicMapTree _dynamicTree;
time_t _instanceResetPeriod; // pussywizard
MapRefMgr m_mapRefMgr;

View file

@ -0,0 +1,183 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "DBCStores.h"
#include "DetourNavMeshQuery.h"
#include "DisableMgr.h"
#include "MapCollisionData.h"
#include "MapTree.h"
#include "ModelInstance.h"
#include "VMapFactory.h"
#include "VMapMgr2.h"
#include "World.h"
#include "WorldModel.h"
#include <G3D/Vector3.h>
MapCollisionData::MapCollisionData(Map const& map, Map const* parentMap) :
_map(map), _staticVMapData(map.GetId())
{
if (parentMap)
{
// If we have a parent map, point our static tree and mmap nav mesh to the parent maps
_staticVMapData._staticTree = parentMap->GetMapCollisionData().GetStaticTreeSharedPtr();
_mmapData._navMesh = parentMap->GetMapCollisionData().GetMMapNavMeshSharedPtr();
}
else
{
// If we are a base map create a new static tree and mmap nav mesh
std::string const mapFileName = VMAP::VMapMgr2::getMapFileName(map.GetId());
std::shared_ptr<VMAP::StaticMapTree> newTree = std::make_shared<VMAP::StaticMapTree>(map.GetId(), (sWorld->GetDataPath() + "vmaps"));
if (newTree->InitMap(mapFileName))
_staticVMapData._staticTree = newTree;
_mmapData._navMesh = MMAP::MMapMgr::LoadNavMesh(map.GetId());
}
}
int MapCollisionData::LoadVMapTile(uint32 tileX, uint32 tileY)
{
if (!VMAP::VMapFactory::createOrGetVMapMgr()->isMapLoadingEnabled() || !_staticVMapData._staticTree)
return VMAP::VMAP_LOAD_RESULT_IGNORED;
if (!_staticVMapData._staticTree->LoadMapTile(tileX, tileY))
return VMAP::VMAP_LOAD_RESULT_ERROR;
return VMAP::VMAP_LOAD_RESULT_OK;
}
int MapCollisionData::LoadMMapTile(uint32 tileX, uint32 tileY)
{
if (!DisableMgr::IsPathfindingEnabled(&_map) || !_mmapData._navMesh)
return MMAP::MMAP_LOAD_RESULT_IGNORED;
return MMAP::MMapMgr::LoadTile(_mmapData._navMesh.get(), _map.GetId(), tileX, tileY);
}
bool StaticVMapCollisionData::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const
{
#if defined(ENABLE_VMAP_CHECKS)
if (!sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_LOS) || DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LOS))
return true;
#endif
if (!_staticTree)
return true;
G3D::Vector3 const pos1 = VMAP::VMapMgr2::convertPositionToInternalRep(x1, y1, z1);
G3D::Vector3 const pos2 = VMAP::VMapMgr2::convertPositionToInternalRep(x2, y2, z2);
if (pos1 != pos2)
return _staticTree->isInLineOfSight(pos1, pos2, ignoreFlags);
return true;
}
bool StaticVMapCollisionData::GetObjectHitPos(float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const
{
#if defined(ENABLE_VMAP_CHECKS)
if (sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_LOS) && !DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LOS))
#endif
{
if (_staticTree)
{
G3D::Vector3 const pos1 = VMAP::VMapMgr2::convertPositionToInternalRep(x1, y1, z1);
G3D::Vector3 const pos2 = VMAP::VMapMgr2::convertPositionToInternalRep(x2, y2, z2);
G3D::Vector3 resultPos;
bool result = _staticTree->GetObjectHitPos(pos1, pos2, resultPos, modifyDist);
resultPos = VMAP::VMapMgr2::convertPositionToInternalRep(resultPos.x, resultPos.y, resultPos.z);
rx = resultPos.x;
ry = resultPos.y;
rz = resultPos.z;
return result;
}
}
rx = x2;
ry = y2;
rz = z2;
return false;
}
float StaticVMapCollisionData::getHeight(float x, float y, float z, float maxSearchDist) const
{
#if defined(ENABLE_VMAP_CHECKS)
if (sWorld->getBoolConfig(CONFIG_VMAP_ENABLE_HEIGHT) && !DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_HEIGHT))
#endif
{
if (_staticTree)
{
G3D::Vector3 const pos = VMAP::VMapMgr2::convertPositionToInternalRep(x, y, z);
float height = _staticTree->getHeight(pos, maxSearchDist);
if (height >= G3D::finf())
return VMAP_INVALID_HEIGHT_VALUE; // No height
return height;
}
}
return VMAP_INVALID_HEIGHT_VALUE;
}
bool StaticVMapCollisionData::GetAreaAndLiquidData(float x, float y, float z, Optional<uint8> reqLiquidType, VMAP::AreaAndLiquidData& data) const
{
if (_staticTree)
{
VMAP::LocationInfo info;
G3D::Vector3 const pos = VMAP::VMapMgr2::convertPositionToInternalRep(x, y, z);
if (_staticTree->GetLocationInfo(pos, info))
{
data.floorZ = info.ground_Z;
if (!DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_LIQUIDSTATUS))
{
uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
float liquidLevel;
if (!reqLiquidType || (GetLiquidFlags(liquidType) & *reqLiquidType))
if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel))
data.liquidInfo.emplace(liquidType, liquidLevel);
}
if (!DisableMgr::IsVMAPDisabledFor(_mapId, VMAP::VMAP_DISABLE_AREAFLAG))
data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID);
return true;
}
}
return false;
}
bool DynamicVMapCollisionData::GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const
{
G3D::Vector3 startPos(x1, y1, z1);
G3D::Vector3 dstPos(x2, y2, z2);
G3D::Vector3 resultPos;
bool result = DynamicMapTree::GetObjectHitPos(phasemask, startPos, dstPos, resultPos, modifyDist);
rx = resultPos.x;
ry = resultPos.y;
rz = resultPos.z;
return result;
}
dtNavMeshQuery const* MMapData::GetNavMeshQuery()
{
if (_navMesh && !_navMeshQuery)
_navMeshQuery = MMAP::MMapMgr::CreateNavMeshQuery(_navMesh.get());
return _navMeshQuery.get();
}

View file

@ -0,0 +1,100 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MAP_COLLISION_DATA_H
#define MAP_COLLISION_DATA_H
#include "DynamicTree.h"
#include "MapTree.h"
#include "MMapMgr.h"
#include "IVMapMgr.h"
class Map;
namespace VMAP
{
enum class ModelIgnoreFlags : uint32;
}
// Simple wrappers for vmap static & dynamic trees to enable clear separation of use for increased readability
class StaticVMapCollisionData
{
friend class MapCollisionData;
public:
StaticVMapCollisionData(uint32 mapId) : _mapId(mapId) {}
bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, VMAP::ModelIgnoreFlags ignoreFlags) const;
bool GetObjectHitPos(float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const;
float getHeight(float x, float y, float z, float maxSearchDist) const;
bool GetAreaAndLiquidData(float x, float y, float z, Optional<uint8> reqLiquidType, VMAP::AreaAndLiquidData& data) const;
protected:
// _staticTree is a shared_ptr as it will point to a parent maps static tree (if exists) to save on memory
std::shared_ptr<VMAP::StaticMapTree> _staticTree;
uint32 _mapId;
};
class DynamicVMapCollisionData : public DynamicMapTree
{
public:
bool GetObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) const;
};
class MMapData
{
friend class MapCollisionData;
public:
dtNavMesh const* GetNavMesh() const { return _navMesh.get(); }
dtNavMeshQuery const* GetNavMeshQuery();
protected:
// _navMesh is a shared_ptr as it will point to a parent maps nav mesh (if exists) to save on memory
std::shared_ptr<dtNavMesh> _navMesh;
// navMeshQuery is not thread safe and needs its own instance per map
MMAP::ManagedNavMeshQuery _navMeshQuery;
};
// Map collision data holders (dynamic&static vmap, mmaps)
class MapCollisionData
{
public:
MapCollisionData(Map const& map, Map const* parentMap);
~MapCollisionData() = default;
int LoadVMapTile(uint32 tileX, uint32 tileY);
int LoadMMapTile(uint32 tileX, uint32 tileY);
DynamicVMapCollisionData& GetDynamicTree() { return _dynamicVMapData; }
DynamicVMapCollisionData const& GetDynamicTree() const { return _dynamicVMapData; }
StaticVMapCollisionData& GetStaticTree() { return _staticVMapData; }
StaticVMapCollisionData const& GetStaticTree() const { return _staticVMapData; }
MMapData& GetMMapData() { return _mmapData; }
MMapData const& GetMMapData() const { return _mmapData; }
std::shared_ptr<VMAP::StaticMapTree> const GetStaticTreeSharedPtr() const { return _staticVMapData._staticTree; }
std::shared_ptr<dtNavMesh> const GetMMapNavMeshSharedPtr() const { return _mmapData._navMesh; }
private:
Map const& _map;
DynamicVMapCollisionData _dynamicVMapData;
StaticVMapCollisionData _staticVMapData;
MMapData _mmapData;
};
#endif

View file

@ -20,7 +20,6 @@
#include "DetourCommon.h"
#include "Geometry.h"
#include "Log.h"
#include "MMapFactory.h"
#include "MMapMgr.h"
#include "Map.h"
#include "Metric.h"
@ -34,12 +33,10 @@ PathGenerator::PathGenerator(WorldObject const* owner) :
{
memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs));
uint32 mapId = _source->GetMapId();
//if (sDisableMgr->IsPathfindingEnabled(_sourceUnit->FindMap()))
{
MMAP::MMapMgr* mmap = MMAP::MMapFactory::createOrGetMMapMgr();
_navMesh = mmap->GetNavMesh(mapId);
_navMeshQuery = mmap->GetNavMeshQuery(mapId, _source->GetInstanceId());
_navMesh = _source->GetMap()->GetMapCollisionData().GetMMapData().GetNavMesh();
_navMeshQuery = _source->GetMap()->GetMapCollisionData().GetMMapData().GetNavMeshQuery();
}
CreateFilter();

View file

@ -1414,7 +1414,6 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
{
float distance = m_spellInfo->Effects[effIndex].CalcRadius(m_caster);
Map* map = m_caster->GetMap();
uint32 mapid = m_caster->GetMapId();
uint32 phasemask = m_caster->GetPhaseMask();
float collisionHeight = m_caster->GetCollisionHeight();
float destz = 0.0f, startx = 0.0f, starty = 0.0f, startz = 0.0f, starto = 0.0f;
@ -1556,9 +1555,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
//LOG_ERROR("spells", "total path > than distance in 3D , need to move back a bit for save distance, total path = {}, overdistance = {}", totalpath, overdistance);
}
bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f);
bool col = m_caster->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos(prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f);
// check dynamic collision
bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f);
bool dcol = m_caster->GetMap()->GetMapCollisionData().GetDynamicTree().GetObjectHitPos(phasemask, prevX, prevY, prevZ + 0.5f, tstX, tstY, tstZ + 0.5f, tstX, tstY, tstZ, -0.5f);
// collision occured
if (col || dcol || (overdistance > 0.0f && !map->IsInWater(phasemask, tstX, tstY, ground, collisionHeight)) || (fabs(prevZ - tstZ) > maxtravelDistZ && (tstZ > prevZ)))
@ -1620,9 +1619,9 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
else
{
float z = pos.GetPositionZ();
bool col = VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(mapid, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
bool col = m_caster->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos(pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
// check dynamic collision
bool dcol = m_caster->GetMap()->GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
bool dcol = m_caster->GetMap()->GetMapCollisionData().GetDynamicTree().GetObjectHitPos(phasemask, pos.GetPositionX(), pos.GetPositionY(), z, destx, desty, z, destx, desty, z, -0.5f);
// collision occured
if (col || dcol)

View file

@ -60,7 +60,6 @@
#include "LootItemStorage.h"
#include "LootMgr.h"
#include "M2Stores.h"
#include "MMapFactory.h"
#include "MapMgr.h"
#include "Metric.h"
#include "MotdMgr.h"
@ -139,7 +138,6 @@ World::~World()
delete command;
VMAP::VMapFactory::clear();
MMAP::MMapFactory::clear();
}
std::unique_ptr<IWorld>& getWorldInstance()
@ -284,9 +282,9 @@ void World::LoadConfigSettings(bool reload)
}
bool const enableIndoor = getBoolConfig(CONFIG_VMAP_INDOOR_CHECK);
bool const enableLOS = sConfigMgr->GetOption<bool>("vmap.enableLOS", true);
bool const enableLOS = getBoolConfig(CONFIG_VMAP_ENABLE_LOS);
bool const enablePetLOS = getBoolConfig(CONFIG_PET_LOS);
bool const enableHeight = sConfigMgr->GetOption<bool>("vmap.enableHeight", true);
bool const enableHeight = getBoolConfig(CONFIG_VMAP_ENABLE_HEIGHT);
if (!enableHeight)
LOG_ERROR("server.loading", "VMap height checking disabled! Creatures movements and other various things WILL be broken! Expect no support.");
@ -294,8 +292,6 @@ void World::LoadConfigSettings(bool reload)
VMAP::VMapFactory::createOrGetVMapMgr()->setEnableHeightCalc(enableHeight);
LOG_INFO("server.loading", "WORLD: VMap support included. LineOfSight:{}, getHeight:{}, indoorCheck:{} PetLOS:{}", enableLOS, enableHeight, enableIndoor, enablePetLOS);
MMAP::MMapFactory::InitializeDisabledMaps();
// call ScriptMgr if we're reloading the configuration
sScriptMgr->OnAfterConfigLoad(reload);
}
@ -392,17 +388,6 @@ void World::SetInitialWorldSettings()
// Load IP Location Database
sIPLocation->Load();
std::vector<uint32> mapIds;
for (auto const& map : sMapStore)
{
mapIds.emplace_back(map->MapID);
}
vmmgr2->InitializeThreadUnsafe(mapIds);
MMAP::MMapMgr* mmmgr = MMAP::MMapFactory::createOrGetMMapMgr();
mmmgr->InitializeThreadUnsafe(mapIds);
LOG_INFO("server.loading", "Loading Game Graveyard...");
sGraveyard->LoadGraveyardFromDB();

View file

@ -523,6 +523,8 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<uint32>(CONFIG_RESPAWN_DYNAMICMINIMUM_GAMEOBJECT, "Respawn.DynamicMinimumGameObject", 10);
SetConfigValue<bool>(CONFIG_VMAP_INDOOR_CHECK, "vmap.enableIndoorCheck", true);
SetConfigValue<bool>(CONFIG_VMAP_ENABLE_LOS, "vmap.enableLOS", true);
SetConfigValue<bool>(CONFIG_VMAP_ENABLE_HEIGHT, "vmap.enableHeight", true);
SetConfigValue<bool>(CONFIG_PET_LOS, "vmap.petLOS", true);
SetConfigValue<bool>(CONFIG_VMAP_BLIZZLIKE_PVP_LOS, "vmap.BlizzlikePvPLOS", true);

View file

@ -80,6 +80,8 @@ enum ServerConfigs
CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN,
CONFIG_CREATURE_REPOSITION_AGAINST_NPCS,
CONFIG_VMAP_INDOOR_CHECK,
CONFIG_VMAP_ENABLE_LOS,
CONFIG_VMAP_ENABLE_HEIGHT,
CONFIG_PET_LOS,
CONFIG_START_CUSTOM_SPELLS,
CONFIG_START_ALL_EXPLORED,

View file

@ -36,7 +36,6 @@
#include "Language.h"
#include "MapMgr.h"
#include "MiscPackets.h"
#include "MMapFactory.h"
#include "MovementGenerator.h"
#include "ObjectAccessor.h"
#include "Pet.h"
@ -630,7 +629,7 @@ public:
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
uint32 haveMMAP = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()) ? 1 : 0;
uint32 haveMMAP = handler->GetSession()->GetPlayer()->GetMap()->GetMapCollisionData().GetMMapData().GetNavMesh() ? 1 : 0;
if (haveVMap)
{

View file

@ -28,7 +28,6 @@
#include "CommandScript.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "MMapFactory.h"
#include "MMapMgr.h"
#include "Map.h"
#include "PathGenerator.h"
@ -62,7 +61,8 @@ public:
static bool HandleMmapPathCommand(ChatHandler* handler, Optional<std::string> param)
{
if (!MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
Map* map = handler->GetSession()->GetPlayer()->GetMap();
if (!map->GetMapCollisionData().GetMMapData().GetNavMesh())
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
return true;
@ -173,9 +173,11 @@ public:
handler->PSendSysMessage("gridloc [{}, {}]", gridCoord.x_coord, gridCoord.y_coord);
Map* map = handler->GetSession()->GetPlayer()->GetMap();
// calculate navmesh tile location
dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh();
dtNavMeshQuery const* navmeshquery = map->GetMapCollisionData().GetMMapData().GetNavMeshQuery();
if (!navmesh || !navmeshquery)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
@ -225,9 +227,9 @@ public:
static bool HandleMmapLoadedTilesCommand(ChatHandler* handler)
{
uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId();
dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMesh(mapid);
dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapMgr()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
Map* map = handler->GetSession()->GetPlayer()->GetMap();
dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh();
dtNavMeshQuery const* navmeshquery = map->GetMapCollisionData().GetMMapData().GetNavMeshQuery();
if (!navmesh || !navmeshquery)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
@ -250,12 +252,14 @@ public:
static bool HandleMmapStatsCommand(ChatHandler* handler)
{
handler->PSendSysMessage("mmap stats:");
//handler->PSendSysMessage(" global mmap pathfinding is {}abled", sDisableMgr->IsPathfindingEnabled(mapId) ? "en" : "dis");
MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr();
handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
Map* map = handler->GetSession()->GetPlayer()->GetMap();
dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
//handler->PSendSysMessage("mmap stats:");
//handler->PSendSysMessage(" global mmap pathfinding is {}abled", sDisableMgr->IsPathfindingEnabled(mapId) ? "en" : "dis");
//MMAP::MMapMgr* manager = MMAP::MMapFactory::createOrGetMMapMgr();
//handler->PSendSysMessage(" {} maps loaded with {} tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
dtNavMesh const* navmesh = map->GetMapCollisionData().GetMMapData().GetNavMesh();
if (!navmesh)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");

View file

@ -434,8 +434,7 @@ class spell_entropius_black_hole_effect : public SpellScript
float targetX = baseX + maxDist * cos(angle);
float targetY = baseY + maxDist * sin(angle);
float hitX, hitY, hitZ;
if (VMAP::VMapFactory::createOrGetVMapMgr()->GetObjectHitPos(
unit->GetMapId(),
if (unit->GetMap()->GetMapCollisionData().GetStaticTree().GetObjectHitPos(
baseX, baseY, z,
targetX, targetY, z,
hitX, hitY, hitZ,