aboutsummaryrefslogtreecommitdiff
path: root/src/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/server')
-rw-r--r--src/server/collision/Management/MMapFactory.cpp18
-rw-r--r--src/server/collision/Management/MMapFactory.h8
-rw-r--r--src/server/collision/Management/MMapManager.cpp175
-rw-r--r--src/server/collision/Management/MMapManager.h29
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.cpp4
-rw-r--r--src/server/game/Instances/InstanceSaveMgr.h8
-rw-r--r--src/server/game/Maps/Map.cpp20
-rw-r--r--src/server/game/Maps/MapInstanced.cpp2
-rw-r--r--src/server/game/Miscellaneous/SharedDefines.h2
-rwxr-xr-xsrc/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp1
-rw-r--r--src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp1
-rw-r--r--src/server/game/Movement/PathGenerator.cpp834
-rw-r--r--src/server/game/Movement/PathGenerator.h65
-rw-r--r--src/server/game/Spells/Spell.cpp1
-rw-r--r--src/server/game/World/World.cpp2
-rw-r--r--src/server/scripts/Commands/cs_misc.cpp2
-rw-r--r--src/server/scripts/Commands/cs_mmaps.cpp257
17 files changed, 896 insertions, 533 deletions
diff --git a/src/server/collision/Management/MMapFactory.cpp b/src/server/collision/Management/MMapFactory.cpp
index 43c726d9989..b08cd92d638 100644
--- a/src/server/collision/Management/MMapFactory.cpp
+++ b/src/server/collision/Management/MMapFactory.cpp
@@ -25,14 +25,14 @@ namespace MMAP
{
// ######################## MMapFactory ########################
// our global singleton copy
- MMapManager* _manager = NULL;
+ MMapManager* g_MMapManager = NULL;
- MMapManager* MMapFactory::CreateOrGetMMapManager()
+ MMapManager* MMapFactory::createOrGetMMapManager()
{
- if (_manager == NULL)
- _manager = new MMapManager();
+ if (g_MMapManager == NULL)
+ g_MMapManager = new MMapManager();
- return _manager;
+ return g_MMapManager;
}
bool MMapFactory::IsPathfindingEnabled(uint32 mapId)
@@ -41,12 +41,12 @@ namespace MMAP
&& !DisableMgr::IsDisabledFor(DISABLE_TYPE_MMAP, mapId, NULL, MMAP_DISABLE_PATHFINDING);
}
- void MMapFactory::Clear()
+ void MMapFactory::clear()
{
- if (_manager)
+ if (g_MMapManager)
{
- delete _manager;
- _manager = NULL;
+ delete g_MMapManager;
+ g_MMapManager = NULL;
}
}
} \ No newline at end of file
diff --git a/src/server/collision/Management/MMapFactory.h b/src/server/collision/Management/MMapFactory.h
index 890befdff04..837c893f038 100644
--- a/src/server/collision/Management/MMapFactory.h
+++ b/src/server/collision/Management/MMapFactory.h
@@ -20,6 +20,10 @@
#define _MMAP_FACTORY_H
#include "MMapManager.h"
+#include "UnorderedMap.h"
+#include "DetourAlloc.h"
+#include "DetourNavMesh.h"
+#include "DetourNavMeshQuery.h"
namespace MMAP
{
@@ -36,8 +40,8 @@ namespace MMAP
class MMapFactory
{
public:
- static MMapManager* CreateOrGetMMapManager();
- static void Clear();
+ static MMapManager* createOrGetMMapManager();
+ static void clear();
static bool IsPathfindingEnabled(uint32 mapId);
};
}
diff --git a/src/server/collision/Management/MMapManager.cpp b/src/server/collision/Management/MMapManager.cpp
index 6c6e39eeda2..cbb10923fe0 100644
--- a/src/server/collision/Management/MMapManager.cpp
+++ b/src/server/collision/Management/MMapManager.cpp
@@ -22,29 +22,32 @@
namespace MMAP
{
+ // ######################## MMapManager ########################
MMapManager::~MMapManager()
{
- for (MMapDataSet::iterator i = _loadedMaps.begin(); i != _loadedMaps.end(); ++i)
+ for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
delete i->second;
+
+ // by now we should not have maps loaded
+ // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
}
- bool MMapManager::LoadMap(uint32 mapId)
+ bool MMapManager::loadMapData(uint32 mapId)
{
- // Do not load a map twice.
- if (_loadedMaps.find(mapId) != _loadedMaps.end())
+ // we already have this map loaded?
+ if (loadedMMaps.find(mapId) != loadedMMaps.end())
return true;
// load and init dtNavMesh - read parameters from file
- std::string basePath = sWorld->GetDataPath();
- uint32 pathLen = basePath.length() + strlen("mmaps/%03i.mmap") + 1;
- char* fileName = new char[pathLen];
- snprintf(fileName, pathLen, (basePath + "mmaps/%03i.mmap").c_str(), mapId);
+ uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i.mmap")+1;
+ char *fileName = new char[pathLen];
+ snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i.mmap").c_str(), mapId);
FILE* file = fopen(fileName, "rb");
if (!file)
{
- TC_LOG_DEBUG("maps", "MMAP::LoadMap: Error: Could not open mmap file '%s'", fileName);
- delete[] fileName;
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
+ delete [] fileName;
return false;
}
@@ -53,75 +56,80 @@ namespace MMAP
fclose(file);
if (count != 1)
{
- TC_LOG_DEBUG("maps", "MMAP::LoadMap: Error: Could not read params from file '%s'", fileName);
- delete[] fileName;
+ TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName);
+ delete [] fileName;
return false;
}
dtNavMesh* mesh = dtAllocNavMesh();
+ ASSERT(mesh);
if (dtStatusFailed(mesh->init(&params)))
{
dtFreeNavMesh(mesh);
- TC_LOG_ERROR("maps", "MMAP::LoadMap: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
- delete[] fileName;
+ TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
+ delete [] fileName;
return false;
}
- delete[] fileName;
+ delete [] fileName;
- TC_LOG_INFO("maps", "MMAP::LoadMap: Loaded %03i.mmap", mapId);
+ TC_LOG_INFO("maps", "MMAP:loadMapData: Loaded %03i.mmap", mapId);
// store inside our map list
- MMapData* mmapData = new MMapData(mesh);
- mmapData->_loadedTiles.clear();
+ MMapData* mmap_data = new MMapData(mesh);
+ mmap_data->mmapLoadedTiles.clear();
- _loadedMaps.insert(std::pair<uint32, MMapData*>(mapId, mmapData));
+ loadedMMaps.insert(std::pair<uint32, MMapData*>(mapId, mmap_data));
return true;
}
- bool MMapManager::LoadMapTile(uint32 mapId, int32 x, int32 y)
+ uint32 MMapManager::packTileID(int32 x, int32 y)
+ {
+ return uint32(x << 16 | y);
+ }
+
+ bool MMapManager::loadMap(const std::string& /*basePath*/, uint32 mapId, int32 x, int32 y)
{
// make sure the mmap is loaded and ready to load tiles
- if (!LoadMap(mapId))
+ if (!loadMapData(mapId))
return false;
// get this mmap data
- MMapData* mmap = _loadedMaps[mapId];
+ MMapData* mmap = loadedMMaps[mapId];
ASSERT(mmap->navMesh);
- // Check if we already have this tile loaded
- uint32 pos = PackTileId(x, y);
- if (mmap->_loadedTiles.find(pos) != mmap->_loadedTiles.end())
+ // check if we already have this tile loaded
+ uint32 packedGridPos = packTileID(x, y);
+ if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end())
return false;
- std::string basePath = sWorld->GetDataPath();
- uint32 pathLen = basePath.length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1;
- char* fileName = new char[pathLen];
+ // load this tile :: mmaps/MMMXXYY.mmtile
+ uint32 pathLen = sWorld->GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile")+1;
+ char *fileName = new char[pathLen];
- snprintf(fileName, pathLen, (basePath + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
+ snprintf(fileName, pathLen, (sWorld->GetDataPath()+"mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
FILE* file = fopen(fileName, "rb");
if (!file)
{
- TC_LOG_DEBUG("maps", "MMAP::LoadMapTile: Could not open mmtile file '%s'", fileName);
- delete[] fileName;
+ TC_LOG_DEBUG("maps", "MMAP:loadMap: Could not open mmtile file '%s'", fileName);
+ delete [] fileName;
return false;
}
-
- delete[] fileName;
+ delete [] fileName;
// read header
MmapTileHeader fileHeader;
if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
{
- TC_LOG_ERROR("maps", "MMAP::LoadMapTile: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
fclose(file);
return false;
}
if (fileHeader.mmapVersion != MMAP_VERSION)
{
- TC_LOG_ERROR("maps", "MMAP::LoadMapTile: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
+ TC_LOG_ERROR("maps", "MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
fclose(file);
return false;
@@ -131,9 +139,9 @@ namespace MMAP
ASSERT(data);
size_t result = fread(data, fileHeader.size, 1, file);
- if (result != 1)
+ if (!result)
{
- TC_LOG_ERROR("maps", "MMAP::LoadMapTile: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
fclose(file);
return false;
}
@@ -146,14 +154,14 @@ namespace MMAP
// memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
{
- mmap->_loadedTiles.insert(std::pair<uint32, dtTileRef>(pos, tileRef));
- ++_loadedTiles;
- TC_LOG_INFO("maps", "MMAP::LoadMapTile: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
+ mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
+ ++loadedTiles;
+ TC_LOG_INFO("maps", "MMAP:loadMap: Loaded mmtile %03i[%02i, %02i] into %03i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
return true;
}
else
{
- TC_LOG_ERROR("maps", "MMAP::LoadMapTile: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
dtFree(data);
return false;
}
@@ -161,26 +169,28 @@ namespace MMAP
return false;
}
- bool MMapManager::UnloadMapTile(uint32 mapId, int32 x, int32 y)
+ bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
{
- // Do not attempt to remove tiles from a not-loaded map
- if (_loadedMaps.find(mapId) == _loadedMaps.end())
+ // check if we have this map loaded
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
{
- TC_LOG_DEBUG("maps", "MMAP::UnloadMapTile: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
+ // file may not exist, therefore not loaded
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
return false;
}
- MMapData* mmap = _loadedMaps[mapId];
+ MMapData* mmap = loadedMMaps[mapId];
// check if we have this tile loaded
- uint32 pos = PackTileId(x, y);
- if (mmap->_loadedTiles.find(pos) == mmap->_loadedTiles.end())
+ uint32 packedGridPos = packTileID(x, y);
+ if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end())
{
- TC_LOG_DEBUG("maps", "MMAP::UnloadMapTile: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
+ // file may not exist, therefore not loaded
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
return false;
}
- dtTileRef tileRef = mmap->_loadedTiles[pos];
+ dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos];
// unload, and mark as non loaded
if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, NULL, NULL)))
@@ -188,106 +198,107 @@ namespace MMAP
// this is technically a memory leak
// if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
// we cannot recover from this error - assert out
- TC_LOG_ERROR("maps", "MMAP::UnloadMapTile: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
ASSERT(false);
}
else
{
- mmap->_loadedTiles.erase(pos);
- --_loadedTiles;
- TC_LOG_INFO("maps", "MMAP::UnloadMapTile: Unloaded mmtile [%02i, %02i] from %03i", x, y, mapId);
+ mmap->mmapLoadedTiles.erase(packedGridPos);
+ --loadedTiles;
+ TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
return true;
}
return false;
}
- bool MMapManager::UnloadMap(uint32 mapId)
+ bool MMapManager::unloadMap(uint32 mapId)
{
- if (_loadedMaps.find(mapId) == _loadedMaps.end())
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
{
// file may not exist, therefore not loaded
- TC_LOG_DEBUG("maps", "MMAP::UnloadMap: Asked to unload not loaded navmesh map %03u", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
return false;
}
// unload all tiles from given map
- MMapData* mmap = _loadedMaps[mapId];
- for (MMapTileSet::iterator i = mmap->_loadedTiles.begin(); i != mmap->_loadedTiles.end(); ++i)
+ MMapData* mmap = loadedMMaps[mapId];
+ for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
{
uint32 x = (i->first >> 16);
uint32 y = (i->first & 0x0000FFFF);
if (dtStatusFailed(mmap->navMesh->removeTile(i->second, NULL, NULL)))
- TC_LOG_ERROR("maps", "MMAP::UnloadMap: Could not unload %03u%02u%02u.mmtile from navmesh", mapId, x, y);
+ TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
else
{
- --_loadedTiles;
- TC_LOG_INFO("maps", "MMAP::UnloadMap: Unloaded mmtile [%02u, %02u] from %03u", x, y, mapId);
+ --loadedTiles;
+ TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded mmtile %03i[%02i, %02i] from %03i", mapId, x, y, mapId);
}
}
delete mmap;
- _loadedMaps.erase(mapId);
- TC_LOG_INFO("maps", "MMAP::UnloadMap: Unloaded %03u.mmap", mapId);
+ loadedMMaps.erase(mapId);
+ TC_LOG_INFO("maps", "MMAP:unloadMap: Unloaded %03i.mmap", mapId);
return true;
}
- bool MMapManager::UnloadMapInstance(uint32 mapId, uint32 instanceId)
+ bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
{
// check if we have this map loaded
- if (_loadedMaps.find(mapId) == _loadedMaps.end())
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
{
// file may not exist, therefore not loaded
- TC_LOG_DEBUG("maps", "MMAP::UnloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
return false;
}
- MMapData* mmap = _loadedMaps[mapId];
- if (mmap->_navMeshQueries.find(instanceId) == mmap->_navMeshQueries.end())
+ MMapData* mmap = loadedMMaps[mapId];
+ if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
- TC_LOG_DEBUG("maps", "MMAP::UnloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
return false;
}
- dtNavMeshQuery* query = mmap->_navMeshQueries[instanceId];
+ dtNavMeshQuery* query = mmap->navMeshQueries[instanceId];
dtFreeNavMeshQuery(query);
- mmap->_navMeshQueries.erase(instanceId);
- TC_LOG_INFO("maps", "MMAP::UnloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
+ mmap->navMeshQueries.erase(instanceId);
+ TC_LOG_INFO("maps", "MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
return true;
}
dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
{
- if (_loadedMaps.find(mapId) == _loadedMaps.end())
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
return NULL;
- return _loadedMaps[mapId]->navMesh;
+ return loadedMMaps[mapId]->navMesh;
}
dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
{
- if (_loadedMaps.find(mapId) == _loadedMaps.end())
+ if (loadedMMaps.find(mapId) == loadedMMaps.end())
return NULL;
- MMapData* mmap = _loadedMaps[mapId];
- if (mmap->_navMeshQueries.find(instanceId) == mmap->_navMeshQueries.end())
+ MMapData* mmap = loadedMMaps[mapId];
+ if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
{
// allocate mesh query
dtNavMeshQuery* query = dtAllocNavMeshQuery();
- if (dtStatusFailed(query->init(mmap->navMesh, 2048)))
+ ASSERT(query);
+ if (dtStatusFailed(query->init(mmap->navMesh, 1024)))
{
dtFreeNavMeshQuery(query);
- TC_LOG_ERROR("maps", "MMAP::GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
+ TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
return NULL;
}
TC_LOG_INFO("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
- mmap->_navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
+ mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
}
- return mmap->_navMeshQueries[instanceId];
+ return mmap->navMeshQueries[instanceId];
}
}
diff --git a/src/server/collision/Management/MMapManager.h b/src/server/collision/Management/MMapManager.h
index 87bb4702dd2..8b0d42b83cd 100644
--- a/src/server/collision/Management/MMapManager.h
+++ b/src/server/collision/Management/MMapManager.h
@@ -36,7 +36,7 @@ namespace MMAP
MMapData(dtNavMesh* mesh) : navMesh(mesh) { }
~MMapData()
{
- for (NavMeshQuerySet::iterator i = _navMeshQueries.begin(); i != _navMeshQueries.end(); ++i)
+ for (NavMeshQuerySet::iterator i = navMeshQueries.begin(); i != navMeshQueries.end(); ++i)
dtFreeNavMeshQuery(i->second);
if (navMesh)
@@ -46,8 +46,8 @@ namespace MMAP
dtNavMesh* navMesh;
// we have to use single dtNavMeshQuery for every instance, since those are not thread safe
- NavMeshQuerySet _navMeshQueries; // instanceId to query
- MMapTileSet _loadedTiles; // maps [map grid coords] to [dtTile]
+ NavMeshQuerySet navMeshQueries; // instanceId to query
+ MMapTileSet mmapLoadedTiles; // maps [map grid coords] to [dtTile]
};
@@ -58,27 +58,26 @@ namespace MMAP
class MMapManager
{
public:
- MMapManager() : _loadedTiles(0) {}
-
+ MMapManager() : loadedTiles(0) { }
~MMapManager();
- bool LoadMapTile(uint32 mapId, int32 x, int32 y);
- bool UnloadMapTile(uint32 mapId, int32 x, int32 y);
- bool UnloadMap(uint32 mapId);
- bool UnloadMapInstance(uint32 mapId, uint32 instanceId);
+ bool loadMap(const std::string& basePath, uint32 mapId, int32 x, int32 y);
+ bool unloadMap(uint32 mapId, int32 x, int32 y);
+ bool unloadMap(uint32 mapId);
+ bool unloadMapInstance(uint32 mapId, uint32 instanceId);
// the returned [dtNavMeshQuery const*] is NOT threadsafe
dtNavMeshQuery const* GetNavMeshQuery(uint32 mapId, uint32 instanceId);
dtNavMesh const* GetNavMesh(uint32 mapId);
- uint32 GetLoadedTilesCount() const { return _loadedTiles; }
- uint32 GetLoadedMapsCount() const { return _loadedMaps.size(); }
+ uint32 getLoadedTilesCount() const { return loadedTiles; }
+ uint32 getLoadedMapsCount() const { return loadedMMaps.size(); }
private:
- bool LoadMap(uint32 mapId);
- uint32 PackTileId(int32 x, int32 y) { return uint32(x << 16 | y); }
+ bool loadMapData(uint32 mapId);
+ uint32 packTileID(int32 x, int32 y);
- MMapDataSet _loadedMaps;
- uint32 _loadedTiles;
+ MMapDataSet loadedMMaps;
+ uint32 loadedTiles;
};
}
diff --git a/src/server/game/Instances/InstanceSaveMgr.cpp b/src/server/game/Instances/InstanceSaveMgr.cpp
index c46d9002604..e37e6847bdd 100644
--- a/src/server/game/Instances/InstanceSaveMgr.cpp
+++ b/src/server/game/Instances/InstanceSaveMgr.cpp
@@ -164,11 +164,7 @@ void InstanceSaveManager::RemoveInstanceSave(uint32 InstanceId)
void InstanceSaveManager::UnloadInstanceSave(uint32 InstanceId)
{
if (InstanceSave* save = GetInstanceSave(InstanceId))
- {
save->UnloadIfEmpty();
- if (save->m_toDelete)
- delete save;
- }
}
InstanceSave::InstanceSave(uint16 MapId, uint32 InstanceId, Difficulty difficulty, time_t resetTime, bool canReset)
diff --git a/src/server/game/Instances/InstanceSaveMgr.h b/src/server/game/Instances/InstanceSaveMgr.h
index 1d753ebaa48..7a89e6488f0 100644
--- a/src/server/game/Instances/InstanceSaveMgr.h
+++ b/src/server/game/Instances/InstanceSaveMgr.h
@@ -115,16 +115,16 @@ class InstanceSave
but that would depend on a lot of things that can easily change in future */
Difficulty GetDifficulty() const { return m_difficulty; }
- typedef std::list<Player*> PlayerListType;
- typedef std::list<Group*> GroupListType;
- private:
- bool UnloadIfEmpty();
/* used to flag the InstanceSave as to be deleted, so the caller can delete it */
void SetToDelete(bool toDelete)
{
m_toDelete = toDelete;
}
+ typedef std::list<Player*> PlayerListType;
+ typedef std::list<Group*> GroupListType;
+ private:
+ bool UnloadIfEmpty();
/* the only reason the instSave-object links are kept is because
the object-instSave links need to be broken at reset time */
/// @todo: Check if maybe it's enough to just store the number of players/groups
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index 10ed0e804a7..79e63cf2035 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -66,9 +66,7 @@ Map::~Map()
if (!m_scriptSchedule.empty())
sScriptMgr->DecreaseScheduledScriptCount(m_scriptSchedule.size());
- MMAP::MMapManager* manager = MMAP::MMapFactory::CreateOrGetMMapManager();
- manager->UnloadMapInstance(GetId(), i_InstanceId); // Delete the dtNavMeshQuery
- manager->UnloadMap(GetId()); // Unload the loaded tiles and delete the dtNavMesh
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId);
}
bool Map::ExistMap(uint32 mapid, int gx, int gy)
@@ -121,16 +119,12 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy)
void Map::LoadMMap(int gx, int gy)
{
- bool mmapLoadResult = false;
- if (GetEntry()->Instanceable())
- mmapLoadResult = MMAP::MMapFactory::CreateOrGetMMapManager()->LoadMapTile(GetId(), 0, 0); // Ignore the tile entry for instances, as they only have 1 tile.
- else
- mmapLoadResult = MMAP::MMapFactory::CreateOrGetMMapManager()->LoadMapTile(GetId(), gx, gy);
+ bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap((sWorld->GetDataPath() + "mmaps").c_str(), GetId(), gx, gy);
if (mmapLoadResult)
- TC_LOG_INFO("maps", "MMAP loaded name: %s, id: %d, x: %d, y: %d", GetMapName(), GetId(), gx, gy);
+ TC_LOG_INFO("maps", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
else
- TC_LOG_INFO("maps", "Could not load MMAP name: %s, id: %d, x: %d, y: %d", GetMapName(), GetId(), gx, gy);
+ TC_LOG_INFO("maps", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy);
}
void Map::LoadVMap(int gx, int gy)
@@ -232,9 +226,9 @@ i_gridExpiry(expiry),
i_scriptLock(false)
{
m_parentMap = (_parent ? _parent : this);
- for (unsigned int idx = 0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
+ for (unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
{
- for (unsigned int j = 0; j < MAX_NUMBER_OF_GRIDS; ++j)
+ for (unsigned int j=0; j < MAX_NUMBER_OF_GRIDS; ++j)
{
//z code
GridMaps[idx][j] =NULL;
@@ -1342,7 +1336,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll)
delete GridMaps[gx][gy];
}
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(GetId(), gx, gy);
- MMAP::MMapFactory::CreateOrGetMMapManager()->UnloadMapTile(GetId(), gx, gy);
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(GetId(), gx, gy);
}
else
((MapInstanced*)m_parentMap)->RemoveGridMapReference(GridCoord(gx, gy));
diff --git a/src/server/game/Maps/MapInstanced.cpp b/src/server/game/Maps/MapInstanced.cpp
index d8f93cbe293..e914a5c3eee 100644
--- a/src/server/game/Maps/MapInstanced.cpp
+++ b/src/server/game/Maps/MapInstanced.cpp
@@ -260,7 +260,7 @@ bool MapInstanced::DestroyInstance(InstancedMaps::iterator &itr)
if (m_InstancedMaps.size() <= 1 && sWorld->getBoolConfig(CONFIG_GRID_UNLOAD))
{
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(itr->second->GetId());
- MMAP::MMapFactory::CreateOrGetMMapManager()->UnloadMap(itr->second->GetId());
+ MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(itr->second->GetId());
// in that case, unload grids of the base map, too
// so in the next map creation, (EnsureGridCreated actually) VMaps will be reloaded
Map::UnloadAll();
diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h
index 69d4cf847ac..75e190ed20d 100644
--- a/src/server/game/Miscellaneous/SharedDefines.h
+++ b/src/server/game/Miscellaneous/SharedDefines.h
@@ -4068,7 +4068,7 @@ enum PartyResult
};
const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP'
-#define MMAP_VERSION 5
+#define MMAP_VERSION 4
struct MmapTileHeader
{
diff --git a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
index e7a3c6de33c..61f3a04bc5d 100755
--- a/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/ConfusedMovementGenerator.cpp
@@ -86,6 +86,7 @@ bool ConfusedMovementGenerator<T>::DoUpdate(T* unit, uint32 diff)
unit->MovePositionToFirstCollision(pos, dest, 0.0f);
PathGenerator path(unit);
+ path.SetPathLengthLimit(30.0f);
bool result = path.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ);
if (!result || (path.GetPathType() & PATHFIND_NOPATH))
{
diff --git a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
index c351aeecd51..572d65b07c7 100644
--- a/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp
@@ -59,6 +59,7 @@ void FleeingMovementGenerator<T>::_setTargetLocation(T* owner)
}
PathGenerator path(owner);
+ path.SetPathLengthLimit(30.0f);
bool result = path.CalculatePath(x, y, z);
if (!result || (path.GetPathType() & PATHFIND_NOPATH))
{
diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp
index 9f16b6b8771..d8a300a2bab 100644
--- a/src/server/game/Movement/PathGenerator.cpp
+++ b/src/server/game/Movement/PathGenerator.cpp
@@ -27,19 +27,21 @@
#include "DetourCommon.h"
#include "DetourNavMeshQuery.h"
-float PathGenerator::MinWallDistance = 2.5f;
-
////////////////// PathGenerator //////////////////
PathGenerator::PathGenerator(const Unit* owner) :
- _type(PATHFIND_BLANK), _endPosition(G3D::Vector3::zero()),
- _sourceUnit(owner), _navMesh(NULL), _navMeshQuery(NULL)
+ _polyLength(0), _type(PATHFIND_BLANK), _useStraightPath(false),
+ _forceDestination(false), _pointPathLimit(MAX_POINT_PATH_LENGTH),
+ _endPosition(G3D::Vector3::zero()), _sourceUnit(owner), _navMesh(NULL),
+ _navMeshQuery(NULL)
{
- TC_LOG_DEBUG("maps", "PathGenerator::PathGenerator for %u \n", _sourceUnit->GetGUIDLow());
+ memset(_pathPolyRefs, 0, sizeof(_pathPolyRefs));
+
+ TC_LOG_DEBUG("maps", "++ PathGenerator::PathGenerator for %u \n", _sourceUnit->GetGUIDLow());
uint32 mapId = _sourceUnit->GetMapId();
if (MMAP::MMapFactory::IsPathfindingEnabled(mapId))
{
- MMAP::MMapManager* mmap = MMAP::MMapFactory::CreateOrGetMMapManager();
+ MMAP::MMapManager* mmap = MMAP::MMapFactory::createOrGetMMapManager();
_navMesh = mmap->GetNavMesh(mapId);
_navMeshQuery = mmap->GetNavMeshQuery(mapId, _sourceUnit->GetInstanceId());
}
@@ -49,23 +51,16 @@ PathGenerator::PathGenerator(const Unit* owner) :
PathGenerator::~PathGenerator()
{
- TC_LOG_DEBUG("maps", "PathGenerator::~PathGenerator() for %u \n", _sourceUnit->GetGUIDLow());
+ TC_LOG_DEBUG("maps", "++ PathGenerator::~PathGenerator() for %u \n", _sourceUnit->GetGUIDLow());
}
bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool forceDest)
{
- // Clear the previous path, just in case that the same PathGenerator instance is being used
- _pathPoints.clear();
-
float x, y, z;
_sourceUnit->GetPosition(x, y, z);
if (!Trinity::IsValidMapCoord(destX, destY, destZ) || !Trinity::IsValidMapCoord(x, y, z))
- {
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() called with invalid map coords, destX: %f destY: %f destZ: %f x: %f y: %f z: %f for creature %u", destX, destY, destZ, x, y, z, _sourceUnit->GetGUIDLow());
- _type = PATHFIND_NOPATH;
return false;
- }
G3D::Vector3 dest(destX, destY, destZ);
SetEndPosition(dest);
@@ -73,103 +68,463 @@ bool PathGenerator::CalculatePath(float destX, float destY, float destZ, bool fo
G3D::Vector3 start(x, y, z);
SetStartPosition(start);
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() for %u \n", _sourceUnit->GetGUIDLow());
+ _forceDestination = forceDest;
+
+ TC_LOG_DEBUG("maps", "++ PathGenerator::CalculatePath() for %u \n", _sourceUnit->GetGUIDLow());
// make sure navMesh works - we can run on map w/o mmap
// check if the start and end point have a .mmtile loaded (can we pass via not loaded tile on the way?)
- if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING))
+ if (!_navMesh || !_navMeshQuery || _sourceUnit->HasUnitState(UNIT_STATE_IGNORE_PATHFINDING) ||
+ !HaveTile(start) || !HaveTile(dest))
{
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() navmesh is not initialized for %u \n", _sourceUnit->GetGUIDLow());
+ BuildShortcut();
_type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
- _pathPoints.push_back(start);
- _pathPoints.push_back(dest);
return true;
}
UpdateFilter();
- float startPos[3];
- startPos[0] = -y;
- startPos[1] = z;
- startPos[2] = -x;
+ BuildPolyPath(start, dest);
+ return true;
+}
- float endPos[3];
- endPos[0] = -destY;
- endPos[1] = destZ;
- endPos[2] = -destX;
+dtPolyRef PathGenerator::GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* point, float* distance) const
+{
+ if (!polyPath || !polyPathSize)
+ return INVALID_POLYREF;
- float polyPickExt[3];
- polyPickExt[0] = 2.5f;
- polyPickExt[1] = 2.5f;
- polyPickExt[2] = 2.5f;
+ dtPolyRef nearestPoly = INVALID_POLYREF;
+ float minDist2d = FLT_MAX;
+ float minDist3d = 0.0f;
- //
- dtPolyRef startRef;
- dtPolyRef endRef;
+ for (uint32 i = 0; i < polyPathSize; ++i)
+ {
+ float closestPoint[VERTEX_SIZE];
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(polyPath[i], point, closestPoint)))
+ continue;
- float nearestPt[3];
+ float d = dtVdist2DSqr(point, closestPoint);
+ if (d < minDist2d)
+ {
+ minDist2d = d;
+ nearestPoly = polyPath[i];
+ minDist3d = dtVdistSqr(point, closestPoint);
+ }
- _navMeshQuery->findNearestPoly(startPos, polyPickExt, &_filter, &startRef, nearestPt);
- _navMeshQuery->findNearestPoly(endPos, polyPickExt, &_filter, &endRef, nearestPt);
+ if (minDist2d < 1.0f) // shortcut out - close enough for us
+ break;
+ }
+
+ if (distance)
+ *distance = dtSqrt(minDist3d);
+
+ return (minDist2d < 3.0f) ? nearestPoly : INVALID_POLYREF;
+}
- if (!startRef || !endRef)
+dtPolyRef PathGenerator::GetPolyByLocation(float const* point, float* distance) const
+{
+ // first we check the current path
+ // if the current path doesn't contain the current poly,
+ // we need to use the expensive navMesh.findNearestPoly
+ dtPolyRef polyRef = GetPathPolyByPosition(_pathPolyRefs, _polyLength, point, distance);
+ if (polyRef != INVALID_POLYREF)
+ return polyRef;
+
+ // we don't have it in our old path
+ // try to get it by findNearestPoly()
+ // first try with low search box
+ float extents[VERTEX_SIZE] = {3.0f, 5.0f, 3.0f}; // bounds of poly search area
+ float closestPoint[VERTEX_SIZE] = {0.0f, 0.0f, 0.0f};
+ if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
{
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() for %u no polygons found for start and end locations\n", _sourceUnit->GetGUIDLow());
- _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
- _pathPoints.push_back(start);
- _pathPoints.push_back(dest);
- return false;
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
}
- int hops;
- dtPolyRef* hopBuffer = new dtPolyRef[8192];
- dtStatus status = _navMeshQuery->findPath(startRef, endRef, startPos, endPos, &_filter, hopBuffer, &hops, 8192);
+ // still nothing ..
+ // try with bigger search box
+ // Note that the extent should not overlap more than 128 polygons in the navmesh (see dtNavMeshQuery::findNearestPoly)
+ extents[1] = 50.0f;
- if (!dtStatusSucceed(status))
+ if (dtStatusSucceed(_navMeshQuery->findNearestPoly(point, extents, &_filter, &polyRef, closestPoint)) && polyRef != INVALID_POLYREF)
{
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() for %u no path found for start and end locations\n", _sourceUnit->GetGUIDLow());
- _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
- _pathPoints.push_back(start);
- _pathPoints.push_back(dest);
- return false;
+ *distance = dtVdist(closestPoint, point);
+ return polyRef;
}
- int resultHopCount;
- float* straightPath = new float[2048 * 3];
- unsigned char* pathFlags = new unsigned char[2048];
- dtPolyRef* pathRefs = new dtPolyRef[2048];
+ return INVALID_POLYREF;
+}
+
+void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos)
+{
+ // *** getting start/end poly logic ***
+
+ float distToStartPoly, distToEndPoly;
+ float startPoint[VERTEX_SIZE] = {startPos.y, startPos.z, startPos.x};
+ float endPoint[VERTEX_SIZE] = {endPos.y, endPos.z, endPos.x};
+
+ dtPolyRef startPoly = GetPolyByLocation(startPoint, &distToStartPoly);
+ dtPolyRef endPoly = GetPolyByLocation(endPoint, &distToEndPoly);
- status = _navMeshQuery->findStraightPath(startPos, endPos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
- if (!dtStatusSucceed(status))
+ // we have a hole in our mesh
+ // make shortcut path and mark it as NOPATH ( with flying and swimming exception )
+ // its up to caller how he will use this info
+ if (startPoly == INVALID_POLYREF || endPoly == INVALID_POLYREF)
{
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() for %u no straight path found for start and end locations\n", _sourceUnit->GetGUIDLow());
- _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
- _pathPoints.push_back(start);
- _pathPoints.push_back(dest);
- return false;
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPoly == 0 || endPoly == 0)\n");
+ BuildShortcut();
+ bool path = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanFly();
+
+ bool waterPath = _sourceUnit->GetTypeId() == TYPEID_UNIT && _sourceUnit->ToCreature()->CanSwim();
+ if (waterPath)
+ {
+ // Check both start and end points, if they're both in water, then we can *safely* let the creature move
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ {
+ ZLiquidStatus status = _sourceUnit->GetBaseMap()->getLiquidStatus(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z, MAP_ALL_LIQUIDS, NULL);
+ // One of the points is not in the water, cancel movement.
+ if (status == LIQUID_MAP_NO_WATER)
+ {
+ waterPath = false;
+ break;
+ }
+ }
+ }
+
+ _type = (path || waterPath) ? PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH) : PATHFIND_NOPATH;
+ return;
}
- SmoothPath(polyPickExt, resultHopCount, straightPath); // Separate the path from the walls
+ // we may need a better number here
+ bool farFromPoly = (distToStartPoly > 7.0f || distToEndPoly > 7.0f);
+ if (farFromPoly)
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: farFromPoly distToStartPoly=%.3f distToEndPoly=%.3f\n", distToStartPoly, distToEndPoly);
- for (uint32 i = 0; i < resultHopCount; ++i)
+ bool buildShotrcut = false;
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
+ {
+ Creature* owner = (Creature*)_sourceUnit;
+
+ G3D::Vector3 const& p = (distToStartPoly > 7.0f) ? startPos : endPos;
+ if (_sourceUnit->GetBaseMap()->IsUnderWater(p.x, p.y, p.z))
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: underWater case\n");
+ if (owner->CanSwim())
+ buildShotrcut = true;
+ }
+ else
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: flying case\n");
+ if (owner->CanFly())
+ buildShotrcut = true;
+ }
+ }
+
+ if (buildShotrcut)
+ {
+ BuildShortcut();
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ return;
+ }
+ else
+ {
+ float closestPoint[VERTEX_SIZE];
+ // we may want to use closestPointOnPolyBoundary instead
+ if (dtStatusSucceed(_navMeshQuery->closestPointOnPoly(endPoly, endPoint, closestPoint)))
+ {
+ dtVcopy(endPoint, closestPoint);
+ SetActualEndPosition(G3D::Vector3(endPoint[2], endPoint[0], endPoint[1]));
+ }
+
+ _type = PATHFIND_INCOMPLETE;
+ }
+ }
+
+ // *** poly path generating logic ***
+
+ // start and end are on same polygon
+ // just need to move in straight line
+ if (startPoly == endPoly)
{
- _pathPoints.push_back(G3D::Vector3(-straightPath[i * 3 + 2], -straightPath[i * 3 + 0], straightPath[i * 3 + 1]));
- TC_LOG_DEBUG("maps", "PathGenerator::CalculatePath() for %u path point %u: (%f, %f, %f)", _sourceUnit->GetGUIDLow(), i, _pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z);
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPoly == endPoly)\n");
+
+ BuildShortcut();
+
+ _pathPolyRefs[0] = startPoly;
+ _polyLength = 1;
+
+ _type = farFromPoly ? PATHFIND_INCOMPLETE : PATHFIND_NORMAL;
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: path type %d\n", _type);
+ return;
}
- _type = PATHFIND_NORMAL;
- return true;
+ // look for startPoly/endPoly in current path
+ /// @todo we can merge it with getPathPolyByPosition() loop
+ bool startPolyFound = false;
+ bool endPolyFound = false;
+ uint32 pathStartIndex = 0;
+ uint32 pathEndIndex = 0;
+
+ if (_polyLength)
+ {
+ for (; pathStartIndex < _polyLength; ++pathStartIndex)
+ {
+ // here to carch few bugs
+ ASSERT(_pathPolyRefs[pathStartIndex] != INVALID_POLYREF);
+
+ if (_pathPolyRefs[pathStartIndex] == startPoly)
+ {
+ startPolyFound = true;
+ break;
+ }
+ }
+
+ for (pathEndIndex = _polyLength-1; pathEndIndex > pathStartIndex; --pathEndIndex)
+ if (_pathPolyRefs[pathEndIndex] == endPoly)
+ {
+ endPolyFound = true;
+ break;
+ }
+ }
+
+ if (startPolyFound && endPolyFound)
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPolyFound && endPolyFound)\n");
+
+ // we moved along the path and the target did not move out of our old poly-path
+ // our path is a simple subpath case, we have all the data we need
+ // just "cut" it out
+
+ _polyLength = pathEndIndex - pathStartIndex + 1;
+ memmove(_pathPolyRefs, _pathPolyRefs + pathStartIndex, _polyLength * sizeof(dtPolyRef));
+ }
+ else if (startPolyFound && !endPolyFound)
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (startPolyFound && !endPolyFound)\n");
+
+ // we are moving on the old path but target moved out
+ // so we have atleast part of poly-path ready
+
+ _polyLength -= pathStartIndex;
+
+ // try to adjust the suffix of the path instead of recalculating entire length
+ // at given interval the target cannot get too far from its last location
+ // thus we have less poly to cover
+ // sub-path of optimal path is optimal
+
+ // take ~80% of the original length
+ /// @todo play with the values here
+ uint32 prefixPolyLength = uint32(_polyLength * 0.8f + 0.5f);
+ memmove(_pathPolyRefs, _pathPolyRefs+pathStartIndex, prefixPolyLength * sizeof(dtPolyRef));
+
+ dtPolyRef suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+
+ // we need any point on our suffix start poly to generate poly-path, so we need last poly in prefix data
+ float suffixEndPoint[VERTEX_SIZE];
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)))
+ {
+ // we can hit offmesh connection as last poly - closestPointOnPoly() don't like that
+ // try to recover by using prev polyref
+ --prefixPolyLength;
+ suffixStartPoly = _pathPolyRefs[prefixPolyLength-1];
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPoly(suffixStartPoly, endPoint, suffixEndPoint)))
+ {
+ // suffixStartPoly is still invalid, error state
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // generate suffix
+ uint32 suffixPolyLength = 0;
+ dtStatus dtResult = _navMeshQuery->findPath(
+ suffixStartPoly, // start polygon
+ endPoly, // end polygon
+ suffixEndPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs + prefixPolyLength - 1, // [out] path
+ (int*)&suffixPolyLength,
+ MAX_PATH_LENGTH-prefixPolyLength); // max number of polygons in output path
+
+ if (!suffixPolyLength || dtStatusFailed(dtResult))
+ {
+ // this is probably an error state, but we'll leave it
+ // and hopefully recover on the next Update
+ // we still need to copy our preffix
+ TC_LOG_ERROR("maps", "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ }
+
+ TC_LOG_DEBUG("maps", "++ m_polyLength=%u prefixPolyLength=%u suffixPolyLength=%u \n", _polyLength, prefixPolyLength, suffixPolyLength);
+
+ // new path = prefix + suffix - overlap
+ _polyLength = prefixPolyLength + suffixPolyLength - 1;
+ }
+ else
+ {
+ TC_LOG_DEBUG("maps", "++ BuildPolyPath :: (!startPolyFound && !endPolyFound)\n");
+
+ // either we have no path at all -> first run
+ // or something went really wrong -> we aren't moving along the path to the target
+ // just generate new path
+
+ // free and invalidate old path data
+ Clear();
+
+ dtStatus dtResult = _navMeshQuery->findPath(
+ startPoly, // start polygon
+ endPoly, // end polygon
+ startPoint, // start position
+ endPoint, // end position
+ &_filter, // polygon search filter
+ _pathPolyRefs, // [out] path
+ (int*)&_polyLength,
+ MAX_PATH_LENGTH); // max number of polygons in output path
+
+ if (!_polyLength || dtStatusFailed(dtResult))
+ {
+ // only happens if we passed bad data to findPath(), or navmesh is messed up
+ TC_LOG_ERROR("maps", "%u's Path Build failed: 0 length path", _sourceUnit->GetGUIDLow());
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ }
+
+ // by now we know what type of path we can get
+ if (_pathPolyRefs[_polyLength - 1] == endPoly && !(_type & PATHFIND_INCOMPLETE))
+ _type = PATHFIND_NORMAL;
+ else
+ _type = PATHFIND_INCOMPLETE;
+
+ // generate the point-path out of our up-to-date poly-path
+ BuildPointPath(startPoint, endPoint);
+}
+
+void PathGenerator::BuildPointPath(const float *startPoint, const float *endPoint)
+{
+ float pathPoints[MAX_POINT_PATH_LENGTH*VERTEX_SIZE];
+ uint32 pointCount = 0;
+ dtStatus dtResult = DT_FAILURE;
+ if (_useStraightPath)
+ {
+ dtResult = _navMeshQuery->findStraightPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // lenth of current path
+ pathPoints, // [out] path corner points
+ NULL, // [out] flags
+ NULL, // [out] shortened path
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points/polygons to use
+ }
+ else
+ {
+ dtResult = FindSmoothPath(
+ startPoint, // start position
+ endPoint, // end position
+ _pathPolyRefs, // current path
+ _polyLength, // length of current path
+ pathPoints, // [out] path corner points
+ (int*)&pointCount,
+ _pointPathLimit); // maximum number of points
+ }
+
+ if (pointCount < 2 || dtStatusFailed(dtResult))
+ {
+ // only happens if pass bad data to findStraightPath or navmesh is broken
+ // single point paths can be generated here
+ /// @todo check the exact cases
+ TC_LOG_DEBUG("maps", "++ PathGenerator::BuildPointPath FAILED! path sized %d returned\n", pointCount);
+ BuildShortcut();
+ _type = PATHFIND_NOPATH;
+ return;
+ }
+ else if (pointCount == _pointPathLimit)
+ {
+ TC_LOG_DEBUG("maps", "++ PathGenerator::BuildPointPath FAILED! path sized %d returned, lower than limit set to %d\n", pointCount, _pointPathLimit);
+ BuildShortcut();
+ _type = PATHFIND_SHORT;
+ return;
+ }
+
+ _pathPoints.resize(pointCount);
+ for (uint32 i = 0; i < pointCount; ++i)
+ _pathPoints[i] = G3D::Vector3(pathPoints[i*VERTEX_SIZE+2], pathPoints[i*VERTEX_SIZE], pathPoints[i*VERTEX_SIZE+1]);
+
+ NormalizePath();
+
+ // first point is always our current location - we need the next one
+ SetActualEndPosition(_pathPoints[pointCount-1]);
+
+ // force the given destination, if needed
+ if (_forceDestination &&
+ (!(_type & PATHFIND_NORMAL) || !InRange(GetEndPosition(), GetActualEndPosition(), 1.0f, 1.0f)))
+ {
+ // we may want to keep partial subpath
+ if (Dist3DSqr(GetActualEndPosition(), GetEndPosition()) < 0.3f * Dist3DSqr(GetStartPosition(), GetEndPosition()))
+ {
+ SetActualEndPosition(GetEndPosition());
+ _pathPoints[_pathPoints.size()-1] = GetEndPosition();
+ }
+ else
+ {
+ SetActualEndPosition(GetEndPosition());
+ BuildShortcut();
+ }
+
+ _type = PathType(PATHFIND_NORMAL | PATHFIND_NOT_USING_PATH);
+ }
+
+ TC_LOG_DEBUG("maps", "++ PathGenerator::BuildPointPath path type %d size %d poly-size %d\n", _type, pointCount, _polyLength);
+}
+
+void PathGenerator::NormalizePath()
+{
+ for (uint32 i = 0; i < _pathPoints.size(); ++i)
+ _sourceUnit->UpdateAllowedPositionZ(_pathPoints[i].x, _pathPoints[i].y, _pathPoints[i].z);
+}
+
+void PathGenerator::BuildShortcut()
+{
+ TC_LOG_DEBUG("maps", "++ BuildShortcut :: making shortcut\n");
+
+ Clear();
+
+ // make two point path, our curr pos is the start, and dest is the end
+ _pathPoints.resize(2);
+
+ // set start and a default next position
+ _pathPoints[0] = GetStartPosition();
+ _pathPoints[1] = GetActualEndPosition();
+
+ NormalizePath();
+
+ _type = PATHFIND_SHORTCUT;
}
void PathGenerator::CreateFilter()
{
- uint16 includeFlags = POLY_FLAG_WALK | POLY_FLAG_SWIM;
+ uint16 includeFlags = 0;
uint16 excludeFlags = 0;
- if (_sourceUnit->GetTypeId() == TYPEID_UNIT && !_sourceUnit->ToCreature()->CanSwim())
+ if (_sourceUnit->GetTypeId() == TYPEID_UNIT)
{
- includeFlags = POLY_FLAG_WALK;
- excludeFlags = POLY_FLAG_SWIM;
+ Creature* creature = (Creature*)_sourceUnit;
+ if (creature->CanWalk())
+ includeFlags |= NAV_GROUND; // walk
+
+ // creatures don't take environmental damage
+ if (creature->CanSwim())
+ includeFlags |= (NAV_WATER | NAV_MAGMA | NAV_SLIME); // swim
+ }
+ else // assume Player
+ {
+ // perfect support not possible, just stay 'safe'
+ includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA | NAV_SLIME);
}
_filter.setIncludeFlags(includeFlags);
@@ -180,130 +535,275 @@ void PathGenerator::CreateFilter()
void PathGenerator::UpdateFilter()
{
+ // allow creatures to cheat and use different movement types if they are moved
+ // forcefully into terrain they can't normally move in
+ if (_sourceUnit->IsInWater() || _sourceUnit->IsUnderWater())
+ {
+ uint16 includedFlags = _filter.getIncludeFlags();
+ includedFlags |= GetNavTerrain(_sourceUnit->GetPositionX(),
+ _sourceUnit->GetPositionY(),
+ _sourceUnit->GetPositionZ());
+ _filter.setIncludeFlags(includedFlags);
+ }
}
-float PathGenerator::GetTriangleArea(float* verts, int nv)
+NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z)
{
- float area = 0;
- for (int i = 0; i < nv - 1; i++)
- area += verts[i * 3] * verts[i * 3 + 5] - verts[i * 3 + 3] * verts[i * 3 + 2];
- area += verts[(nv - 1) * 3] * verts[2] - verts[0] * verts[(nv - 1) * 3 + 2];
- return area * 0.5f;
-}
+ LiquidData data;
+ ZLiquidStatus liquidStatus = _sourceUnit->GetBaseMap()->getLiquidStatus(x, y, z, MAP_ALL_LIQUIDS, &data);
+ if (liquidStatus == LIQUID_MAP_NO_WATER)
+ return NAV_GROUND;
-bool PathGenerator::PointInPoly(float* pos, float* verts, int nv, float err)
-{
- // Poly area
- float area = abs(PathGenerator::GetTriangleArea(verts, nv));
-
- // Calculate each area of the triangles
- float testTri[9];
- memcpy(testTri, pos, sizeof(float) * 3);
- float area1 = 0;
- for(int i = 0; i < nv - 1; ++i)
+ switch (data.type_flags)
{
- memcpy(&testTri[3], &verts[i * 3], sizeof(float) * 3);
- memcpy(&testTri[6], &verts[i * 3 + 3], sizeof(float) * 3);
- area1 += abs(PathGenerator::GetTriangleArea(testTri, 3));
- if (area1 - err > area)
- return false;
+ case MAP_LIQUID_TYPE_WATER:
+ case MAP_LIQUID_TYPE_OCEAN:
+ return NAV_WATER;
+ case MAP_LIQUID_TYPE_MAGMA:
+ return NAV_MAGMA;
+ case MAP_LIQUID_TYPE_SLIME:
+ return NAV_SLIME;
+ default:
+ return NAV_GROUND;
}
-
- // Last one
- memcpy(&testTri[3], verts, sizeof(float) * 3);
- memcpy(&testTri[6], &verts[nv * 3 - 3] , sizeof(float) * 3);
- area1 += abs(PathGenerator::GetTriangleArea(testTri, 3));
-
- return abs(area1 - area) < err;
}
-float PathGenerator::DistanceToWall(float* polyPickExt, float* pos, float* hitPos, float* hitNormal)
+bool PathGenerator::HaveTile(const G3D::Vector3& p) const
{
- float distanceToWall = 0;
- dtPolyRef ref;
+ int tx = -1, ty = -1;
+ float point[VERTEX_SIZE] = {p.y, p.z, p.x};
- dtStatus status = _navMeshQuery->findNearestPoly(pos, polyPickExt, &_filter, &ref, 0);
+ _navMesh->calcTileLoc(point, &tx, &ty);
- if (!dtStatusSucceed(status) || ref == 0)
- return -1;
+ /// Workaround
+ /// For some reason, often the tx and ty variables wont get a valid value
+ /// Use this check to prevent getting negative tile coords and crashing on getTileAt
+ if (tx < 0 || ty < 0)
+ return false;
- const dtMeshTile* tile = 0;
- const dtPoly* poly = 0;
- if (dtStatusFailed(_navMesh->getTileAndPolyByRef(ref, &tile, &poly)))
- return -1;
+ return (_navMesh->getTileAt(tx, ty, 0) != NULL);
+}
- // Collect vertices.
- float verts[DT_VERTS_PER_POLYGON * 3];
- int nv = 0;
- for (unsigned char i = 0; i < poly->vertCount; ++i)
+uint32 PathGenerator::FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited)
+{
+ int32 furthestPath = -1;
+ int32 furthestVisited = -1;
+
+ // Find furthest common polygon.
+ for (int32 i = npath-1; i >= 0; --i)
{
- dtVcopy(&verts[nv * 3], &tile->verts[poly->verts[i] * 3]);
- nv++;
+ bool found = false;
+ for (int32 j = nvisited-1; j >= 0; --j)
+ {
+ if (path[i] == visited[j])
+ {
+ furthestPath = i;
+ furthestVisited = j;
+ found = true;
+ }
+ }
+ if (found)
+ break;
}
- bool inside = PathGenerator::PointInPoly(pos, verts, nv, 0.05f);
- if (!inside)
- return -1;
+ // If no intersection found just return current path.
+ if (furthestPath == -1 || furthestVisited == -1)
+ return npath;
+
+ // Concatenate paths.
+
+ // Adjust beginning of the buffer to include the visited.
+ uint32 req = nvisited - furthestVisited;
+ uint32 orig = uint32(furthestPath + 1) < npath ? furthestPath + 1 : npath;
+ uint32 size = npath > orig ? npath - orig : 0;
+ if (req + size > maxPath)
+ size = maxPath-req;
- if (!dtStatusSucceed(_navMeshQuery->findDistanceToWall(ref, pos, 100.0f, &_filter, &distanceToWall, hitPos, hitNormal)))
- return -1;
+ if (size)
+ memmove(path + req, path + orig, size * sizeof(dtPolyRef));
- return distanceToWall;
+ // Store visited
+ for (uint32 i = 0; i < req; ++i)
+ path[i] = visited[(nvisited - 1) - i];
+
+ return req+size;
}
-void PathGenerator::SmoothPath(float* polyPickExt, int pathLength, float*& straightPath)
+bool PathGenerator::GetSteerTarget(float const* startPos, float const* endPos,
+ float minTargetDist, dtPolyRef const* path, uint32 pathSize,
+ float* steerPos, unsigned char& steerPosFlag, dtPolyRef& steerPosRef)
{
- float hitPos[3];
- float hitNormal[3];
- float testPos[3];
- float distanceToWall = 0;
- float up[]= { 0, 1, 0 };
- float origDis = 0;
-
- for (int i = 1; i < pathLength - 1; ++i)
+ // Find steer target.
+ static const uint32 MAX_STEER_POINTS = 3;
+ float steerPath[MAX_STEER_POINTS*VERTEX_SIZE];
+ unsigned char steerPathFlags[MAX_STEER_POINTS];
+ dtPolyRef steerPathPolys[MAX_STEER_POINTS];
+ uint32 nsteerPath = 0;
+ dtStatus dtResult = _navMeshQuery->findStraightPath(startPos, endPos, path, pathSize,
+ steerPath, steerPathFlags, steerPathPolys, (int*)&nsteerPath, MAX_STEER_POINTS);
+ if (!nsteerPath || dtStatusFailed(dtResult))
+ return false;
+
+ // Find vertex far enough to steer to.
+ uint32 ns = 0;
+ while (ns < nsteerPath)
{
- dtPolyRef pt;
- float* curPoi = &straightPath[i * 3];
- distanceToWall = DistanceToWall(polyPickExt, curPoi, hitPos, hitNormal);
+ // Stop at Off-Mesh link or when point is further than slop away.
+ if ((steerPathFlags[ns] & DT_STRAIGHTPATH_OFFMESH_CONNECTION) ||
+ !InRangeYZX(&steerPath[ns*VERTEX_SIZE], startPos, minTargetDist, 1000.0f))
+ break;
+ ns++;
+ }
+ // Failed to find good point to steer to.
+ if (ns >= nsteerPath)
+ return false;
+
+ dtVcopy(steerPos, &steerPath[ns*VERTEX_SIZE]);
+ steerPos[1] = startPos[1]; // keep Z value
+ steerPosFlag = steerPathFlags[ns];
+ steerPosRef = steerPathPolys[ns];
- if (distanceToWall < PathGenerator::MinWallDistance && distanceToWall >= 0)
+ return true;
+}
+
+dtStatus PathGenerator::FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 maxSmoothPathSize)
+{
+ *smoothPathSize = 0;
+ uint32 nsmoothPath = 0;
+
+ dtPolyRef polys[MAX_PATH_LENGTH];
+ memcpy(polys, polyPath, sizeof(dtPolyRef)*polyPathSize);
+ uint32 npolys = polyPathSize;
+
+ float iterPos[VERTEX_SIZE], targetPos[VERTEX_SIZE];
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[0], startPos, iterPos)))
+ return DT_FAILURE;
+
+ if (dtStatusFailed(_navMeshQuery->closestPointOnPolyBoundary(polys[npolys-1], endPos, targetPos)))
+ return DT_FAILURE;
+
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+
+ // Move towards target a small advancement at a time until target reached or
+ // when ran out of memory to store the path.
+ while (npolys && nsmoothPath < maxSmoothPathSize)
+ {
+ // Find location to steer towards.
+ float steerPos[VERTEX_SIZE];
+ unsigned char steerPosFlag;
+ dtPolyRef steerPosRef = INVALID_POLYREF;
+
+ if (!GetSteerTarget(iterPos, targetPos, SMOOTH_PATH_SLOP, polys, npolys, steerPos, steerPosFlag, steerPosRef))
+ break;
+
+ bool endOfPath = (steerPosFlag & DT_STRAIGHTPATH_END);
+ bool offMeshConnection = (steerPosFlag & DT_STRAIGHTPATH_OFFMESH_CONNECTION);
+
+ // Find movement delta.
+ float delta[VERTEX_SIZE];
+ dtVsub(delta, steerPos, iterPos);
+ float len = dtSqrt(dtVdot(delta, delta));
+ // If the steer target is end of path or off-mesh link, do not move past the location.
+ if ((endOfPath || offMeshConnection) && len < SMOOTH_PATH_STEP_SIZE)
+ len = 1.0f;
+ else
+ len = SMOOTH_PATH_STEP_SIZE / len;
+
+ float moveTgt[VERTEX_SIZE];
+ dtVmad(moveTgt, iterPos, delta, len);
+
+ // Move
+ float result[VERTEX_SIZE];
+ const static uint32 MAX_VISIT_POLY = 16;
+ dtPolyRef visited[MAX_VISIT_POLY];
+
+ uint32 nvisited = 0;
+ _navMeshQuery->moveAlongSurface(polys[0], iterPos, moveTgt, &_filter, result, visited, (int*)&nvisited, MAX_VISIT_POLY);
+ npolys = FixupCorridor(polys, npolys, MAX_PATH_LENGTH, visited, nvisited);
+
+ _navMeshQuery->getPolyHeight(polys[0], result, &result[1]);
+ result[1] += 0.5f;
+ dtVcopy(iterPos, result);
+
+ // Handle end of path and off-mesh links when close enough.
+ if (endOfPath && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
{
- float vec[3];
- dtVsub(vec, &straightPath[i * 3 - 3], &straightPath[i * 3]);
- // If distanceToWall is 0 means the point is in the edge, so we can't get the hitpos.
- if (distanceToWall == 0)
+ // Reached end of path.
+ dtVcopy(iterPos, targetPos);
+ if (nsmoothPath < maxSmoothPathSize)
{
- // Test the left side
- dtVcross(testPos, vec, up);
- dtVadd(testPos, testPos, curPoi);
- float ft = PathGenerator::MinWallDistance / dtVdist(testPos, curPoi);
- dtVlerp(testPos, curPoi, testPos, ft);
- distanceToWall = DistanceToWall(polyPickExt, testPos, hitPos, hitNormal);
- if (abs(PathGenerator::MinWallDistance - distanceToWall) > 0.1f)
- {
- // Test the right side
- dtVcross(testPos, up, vec);
- dtVadd(testPos, testPos, curPoi);
- ft = PathGenerator::MinWallDistance / dtVdist(testPos, curPoi);
- dtVlerp(testPos, curPoi, testPos, ft);
- distanceToWall = DistanceToWall(polyPickExt, testPos, hitPos, hitNormal);
- }
-
- // If the test point is better than the orig point, replace it.
- if (abs(distanceToWall - PathGenerator::MinWallDistance) < 0.1f)
- dtVcopy(curPoi, testPos);
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
}
- else
+ break;
+ }
+ else if (offMeshConnection && InRangeYZX(iterPos, steerPos, SMOOTH_PATH_SLOP, 1.0f))
+ {
+ // Advance the path up to and over the off-mesh connection.
+ dtPolyRef prevRef = INVALID_POLYREF;
+ dtPolyRef polyRef = polys[0];
+ uint32 npos = 0;
+ while (npos < npolys && polyRef != steerPosRef)
{
- // We get the hitpos with a ray
- float ft = PathGenerator::MinWallDistance / distanceToWall;
- dtVlerp(testPos, hitPos, curPoi, ft);
- distanceToWall = DistanceToWall(polyPickExt, testPos, hitPos, hitNormal);
+ prevRef = polyRef;
+ polyRef = polys[npos];
+ npos++;
+ }
+
+ for (uint32 i = npos; i < npolys; ++i)
+ polys[i-npos] = polys[i];
- if (abs(distanceToWall - PathGenerator::MinWallDistance) < 0.1f)
- dtVcopy(curPoi, testPos);
+ npolys -= npos;
+
+ // Handle the connection.
+ float startPos[VERTEX_SIZE], endPos[VERTEX_SIZE];
+ if (dtStatusSucceed(_navMesh->getOffMeshConnectionPolyEndPoints(prevRef, polyRef, startPos, endPos)))
+ {
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], startPos);
+ nsmoothPath++;
+ }
+ // Move position at the other side of the off-mesh link.
+ dtVcopy(iterPos, endPos);
+ _navMeshQuery->getPolyHeight(polys[0], iterPos, &iterPos[1]);
+ iterPos[1] += 0.5f;
}
}
+
+ // Store results.
+ if (nsmoothPath < maxSmoothPathSize)
+ {
+ dtVcopy(&smoothPath[nsmoothPath*VERTEX_SIZE], iterPos);
+ nsmoothPath++;
+ }
}
+
+ *smoothPathSize = nsmoothPath;
+
+ // this is most likely a loop
+ return nsmoothPath < MAX_POINT_PATH_LENGTH ? DT_SUCCESS : DT_FAILURE;
+}
+
+bool PathGenerator::InRangeYZX(const float* v1, const float* v2, float r, float h) const
+{
+ const float dx = v2[0] - v1[0];
+ const float dy = v2[1] - v1[1]; // elevation
+ const float dz = v2[2] - v1[2];
+ return (dx * dx + dz * dz) < r * r && fabsf(dy) < h;
+}
+
+bool PathGenerator::InRange(G3D::Vector3 const& p1, G3D::Vector3 const& p2, float r, float h) const
+{
+ G3D::Vector3 d = p1 - p2;
+ return (d.x * d.x + d.y * d.y) < r * r && fabsf(d.z) < h;
+}
+
+float PathGenerator::Dist3DSqr(G3D::Vector3 const& p1, G3D::Vector3 const& p2) const
+{
+ return (p1 - p2).squaredLength();
}
diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h
index 075d6dabc9f..ac66b7cec57 100644
--- a/src/server/game/Movement/PathGenerator.h
+++ b/src/server/game/Movement/PathGenerator.h
@@ -26,6 +26,18 @@
class Unit;
+// 74*4.0f=296y number_of_points*interval = max_path_len
+// this is way more than actual evade range
+// I think we can safely cut those down even more
+#define MAX_PATH_LENGTH 74
+#define MAX_POINT_PATH_LENGTH 74
+
+#define SMOOTH_PATH_STEP_SIZE 4.0f
+#define SMOOTH_PATH_SLOP 0.3f
+
+#define VERTEX_SIZE 3
+#define INVALID_POLYREF 0
+
enum PathType
{
PATHFIND_BLANK = 0x00, // path not built yet
@@ -37,12 +49,6 @@ enum PathType
PATHFIND_SHORT = 0x20, // path is longer or equal to its limited path length
};
-enum PolyFlag
-{
- POLY_FLAG_WALK = 1,
- POLY_FLAG_SWIM = 2
-};
-
class PathGenerator
{
public:
@@ -53,6 +59,10 @@ class PathGenerator
// return: true if new path was calculated, false otherwise (no change needed)
bool CalculatePath(float destX, float destY, float destZ, bool forceDest = false);
+ // option setters - use optional
+ void SetUseStraightPath(bool useStraightPath) { _useStraightPath = useStraightPath; }
+ void SetPathLengthLimit(float distance) { _pointPathLimit = std::min<uint32>(uint32(distance/SMOOTH_PATH_STEP_SIZE), MAX_POINT_PATH_LENGTH); }
+
// result getters
G3D::Vector3 const& GetStartPosition() const { return _startPosition; }
G3D::Vector3 const& GetEndPosition() const { return _endPosition; }
@@ -61,13 +71,19 @@ class PathGenerator
Movement::PointsArray const& GetPath() const { return _pathPoints; }
PathType GetPathType() const { return _type; }
-
- static float MinWallDistance;
private:
+
+ dtPolyRef _pathPolyRefs[MAX_PATH_LENGTH]; // array of detour polygon references
+ uint32 _polyLength; // number of polygons in the path
+
Movement::PointsArray _pathPoints; // our actual (x,y,z) path to the target
PathType _type; // tells what kind of path this is
+ bool _useStraightPath; // type of path will be generated
+ bool _forceDestination; // when set, we will always arrive at given point
+ uint32 _pointPathLimit; // limit point path size; min(this, MAX_POINT_PATH_LENGTH)
+
G3D::Vector3 _startPosition; // {x, y, z} of current location
G3D::Vector3 _endPosition; // {x, y, z} of the destination
G3D::Vector3 _actualEndPosition; // {x, y, z} of the closest possible point to given destination
@@ -81,16 +97,37 @@ class PathGenerator
void SetStartPosition(G3D::Vector3 const& point) { _startPosition = point; }
void SetEndPosition(G3D::Vector3 const& point) { _actualEndPosition = point; _endPosition = point; }
void SetActualEndPosition(G3D::Vector3 const& point) { _actualEndPosition = point; }
+ void NormalizePath();
+
+ void Clear()
+ {
+ _polyLength = 0;
+ _pathPoints.clear();
+ }
- // Path smoothing
- void SmoothPath(float* polyPickExt, int pathLength, float*& straightPath);
- float DistanceToWall(float* polyPickExt, float* pos, float* hitPos, float* hitNormal);
- // dtPointInPolygon will return false when the point is too close to the edge, so we rewrite the test function.
- static bool PointInPoly(float* pos, float* verts, int nv, float err);
- static float GetTriangleArea(float* verts, int nv);
+ bool InRange(G3D::Vector3 const& p1, G3D::Vector3 const& p2, float r, float h) const;
+ float Dist3DSqr(G3D::Vector3 const& p1, G3D::Vector3 const& p2) const;
+ bool InRangeYZX(float const* v1, float const* v2, float r, float h) const;
+ dtPolyRef GetPathPolyByPosition(dtPolyRef const* polyPath, uint32 polyPathSize, float const* Point, float* Distance = NULL) const;
+ dtPolyRef GetPolyByLocation(float const* Point, float* Distance) const;
+ bool HaveTile(G3D::Vector3 const& p) const;
+
+ void BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 const& endPos);
+ void BuildPointPath(float const* startPoint, float const* endPoint);
+ void BuildShortcut();
+
+ NavTerrain GetNavTerrain(float x, float y, float z);
void CreateFilter();
void UpdateFilter();
+
+ // smooth path aux functions
+ uint32 FixupCorridor(dtPolyRef* path, uint32 npath, uint32 maxPath, dtPolyRef const* visited, uint32 nvisited);
+ bool GetSteerTarget(float const* startPos, float const* endPos, float minTargetDist, dtPolyRef const* path, uint32 pathSize, float* steerPos,
+ unsigned char& steerPosFlag, dtPolyRef& steerPosRef);
+ dtStatus FindSmoothPath(float const* startPos, float const* endPos,
+ dtPolyRef const* polyPath, uint32 polyPathSize,
+ float* smoothPath, int* smoothPathSize, uint32 smoothPathMaxSize);
};
#endif
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp
index 417d7be78ad..0d5ba60df65 100644
--- a/src/server/game/Spells/Spell.cpp
+++ b/src/server/game/Spells/Spell.cpp
@@ -5234,6 +5234,7 @@ SpellCastResult Spell::CheckCast(bool strict)
target->GetContactPoint(m_caster, pos.m_positionX, pos.m_positionY, pos.m_positionZ);
target->GetFirstCollisionPosition(pos, CONTACT_DISTANCE, target->GetRelativeAngle(m_caster));
+ m_preGeneratedPath.SetPathLengthLimit(m_spellInfo->GetMaxRange(true) * 1.5f);
bool result = m_preGeneratedPath.CalculatePath(pos.m_positionX, pos.m_positionY, pos.m_positionZ + target->GetObjectSize());
if (m_preGeneratedPath.GetPathType() & PATHFIND_SHORT)
return SPELL_FAILED_OUT_OF_RANGE;
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index e472e975777..ef6f2869ec5 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -152,7 +152,7 @@ World::~World()
delete command;
VMAP::VMapFactory::clear();
- MMAP::MMapFactory::Clear();
+ MMAP::MMapFactory::clear();
/// @todo free addSessQueue
}
diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp
index 81fc9f9b2b2..ba355d08d0c 100644
--- a/src/server/scripts/Commands/cs_misc.cpp
+++ b/src/server/scripts/Commands/cs_misc.cpp
@@ -186,7 +186,7 @@ public:
uint32 haveMap = Map::ExistMap(mapId, gridX, gridY) ? 1 : 0;
uint32 haveVMap = Map::ExistVMap(mapId, gridX, gridY) ? 1 : 0;
- uint32 haveMMap = (MMAP::MMapFactory::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0;
+ uint32 haveMMap = (MMAP::MMapFactory::IsPathfindingEnabled(mapId) && MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId())) ? 1 : 0;
if (haveVMap)
{
diff --git a/src/server/scripts/Commands/cs_mmaps.cpp b/src/server/scripts/Commands/cs_mmaps.cpp
index f38717ba31e..37e7177cbc6 100644
--- a/src/server/scripts/Commands/cs_mmaps.cpp
+++ b/src/server/scripts/Commands/cs_mmaps.cpp
@@ -1,19 +1,19 @@
/*
- * Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
- *
- * 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/>.
- */
+* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
+*
+* 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/>.
+*/
/**
* @file cs_mmaps.cpp
@@ -30,13 +30,11 @@
#include "PointMovementGenerator.h"
#include "PathGenerator.h"
#include "MMapFactory.h"
-#include "DetourCommon.h"
#include "Map.h"
#include "TargetedMovementGenerator.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
-#include "MMapManager.h"
class mmaps_commandscript : public CommandScript
{
@@ -48,152 +46,24 @@ public:
static ChatCommand mmapCommandTable[] =
{
{ "loadedtiles", rbac::RBAC_PERM_COMMAND_MMAP_LOADEDTILES, false, &HandleMmapLoadedTilesCommand, "", NULL },
- { "loc", rbac::RBAC_PERM_COMMAND_MMAP_LOC, false, &HandleMmapLocCommand, "", NULL },
- { "path", rbac::RBAC_PERM_COMMAND_MMAP_PATH, false, &HandleMmapPathCommand, "", NULL },
- { "stats", rbac::RBAC_PERM_COMMAND_MMAP_STATS, false, &HandleMmapStatsCommand, "", NULL },
- { "testarea", rbac::RBAC_PERM_COMMAND_MMAP_TESTAREA, false, &HandleMmapTestArea, "", NULL },
- { NULL, 0, false, NULL, "", NULL }
+ { "loc", rbac::RBAC_PERM_COMMAND_MMAP_LOC, false, &HandleMmapLocCommand, "", NULL },
+ { "path", rbac::RBAC_PERM_COMMAND_MMAP_PATH, false, &HandleMmapPathCommand, "", NULL },
+ { "stats", rbac::RBAC_PERM_COMMAND_MMAP_STATS, false, &HandleMmapStatsCommand, "", NULL },
+ { "testarea", rbac::RBAC_PERM_COMMAND_MMAP_TESTAREA, false, &HandleMmapTestArea, "", NULL },
+ { NULL, 0, false, NULL, "", NULL }
};
static ChatCommand commandTable[] =
{
- { "mmap", rbac::RBAC_PERM_COMMAND_MMAP, true, NULL, "", mmapCommandTable },
- { NULL, 0, false, NULL, "", NULL }
+ { "mmap", rbac::RBAC_PERM_COMMAND_MMAP, true, NULL, "", mmapCommandTable },
+ { NULL, 0, false, NULL, "", NULL }
};
return commandTable;
}
- static float Fix_GetXZArea(float* verts, int nv)
- {
- float area = 0;
- for(int i=0; i<nv-1; i++)
- area+=(verts[i*3]*verts[i*3+5]-verts[i*3+3]*verts[i*3+2]);
- area += (verts[(nv-1)*3]*verts[2] - verts[0]*verts[(nv-1)*3+2]);
- return area*0.5f;
- }
-
-
- //dtPointInPolygon will return false when the point is too close to the edge,so we rewite the test function.
- static bool Fix_PointIsInPoly(float* pos,float* verts,int nv,float err)
- {
- //poly area
- float area = abs(Fix_GetXZArea(verts,nv));
-
- //calculate each area of triangles
- float TestTri[9];
- memcpy(TestTri,pos,sizeof(float)*3);
- float area1 = 0;
- for(int i=0;i<nv-1;++i)
- {
- memcpy(&TestTri[3],&verts[i*3],sizeof(float)*3);
- memcpy(&TestTri[6],&verts[i*3+3],sizeof(float)*3);
- area1+= abs(Fix_GetXZArea(TestTri,3));
- if(area1-err>area)
- return false;
- }
-
- //last one
- memcpy(&TestTri[3],verts,sizeof(float)*3);
- memcpy(&TestTri[6],&verts[nv*3-3],sizeof(float)*3);
- area1+= abs(Fix_GetXZArea(TestTri,3));
-
- return abs(area1-area)<err;
- }
-
-
- static float DistanceToWall(dtNavMeshQuery* navQuery, dtNavMesh* navMesh, float* polyPickExt, dtQueryFilter& filter, float* pos,float* hitPos,float* hitNormal)
- {
- float distanceToWall=0;
- dtPolyRef ref;
- if(dtStatusSucceed(navQuery->findNearestPoly(pos, polyPickExt, &filter, &ref, 0))==false || ref ==0)
- return -1;
-
- const dtMeshTile* tile = 0;
- const dtPoly* poly = 0;
- if (dtStatusFailed(navMesh->getTileAndPolyByRef(ref, &tile, &poly)))
- return -1;
-
- // Collect vertices.
- float verts[DT_VERTS_PER_POLYGON*3];
- int nv = 0;
- for (int i = 0; i < (int)poly->vertCount; ++i)
- {
- dtVcopy(&verts[nv*3], &tile->verts[poly->verts[i]*3]);
- nv++;
- }
-
- bool inside = Fix_PointIsInPoly(pos, verts, nv,0.05f);
- if(inside == false)
- return -1;
-
- if(dtStatusSucceed(navQuery->findDistanceToWall(ref, pos, 100.0f, &filter, &distanceToWall, hitPos, hitNormal))==false)
- return -1;
-
- return distanceToWall;
- }
-
- #define MIN_WALL_DISTANCE 1.5f //set this value bigger to make the path point far way from wall
-
- //Try to fix the path,
- static void FixPath(dtNavMesh* navMesh, dtNavMeshQuery* navQuery, float* polyPickExt, dtQueryFilter& filter, int pathLength, float*& straightPath)
- {
- float hitPos[3];
- float hitNormal[3];
- float TestPos[3];
- float distanceToWall=0;
- float up[3]={0,1,0};
- float origDis = 0;
-
- for(int i=1;i<pathLength-1;++i)
- {
- dtPolyRef pt;
- float* pCurPoi=&straightPath[i*3];
- distanceToWall = DistanceToWall(navQuery, navMesh, polyPickExt, filter, pCurPoi,hitPos,hitNormal);
-
- if(distanceToWall<MIN_WALL_DISTANCE && distanceToWall>=0)
- {
- float vec[3];
- dtVsub(vec,&straightPath[i*3-3],&straightPath[i*3]);
- //distanceToWall is 0 means the point is in the edge.so we can't get the hitpos.
- if(distanceToWall == 0)
- {
- //test left side
- dtVcross(TestPos,vec,up);
- dtVadd(TestPos,TestPos,pCurPoi);
- float ft = MIN_WALL_DISTANCE/dtVdist(TestPos,pCurPoi);
- dtVlerp(TestPos,pCurPoi,TestPos,ft);
- distanceToWall = DistanceToWall(navQuery, navMesh, polyPickExt, filter,TestPos,hitPos,hitNormal);
- if(abs(MIN_WALL_DISTANCE - distanceToWall)>0.1f)
- {
- //test right side
- dtVcross(TestPos,up,vec);
- dtVadd(TestPos,TestPos,pCurPoi);
- ft = MIN_WALL_DISTANCE/dtVdist(TestPos,pCurPoi);
- dtVlerp(TestPos,pCurPoi,TestPos,ft);
- distanceToWall = DistanceToWall(navQuery, navMesh, polyPickExt, filter,TestPos,hitPos,hitNormal);
- }
-
- //if test point is better than the orig point,replace it.
- if(abs(distanceToWall-MIN_WALL_DISTANCE)<0.1f)
- dtVcopy(pCurPoi,TestPos);
- }
- else
- {
- //ok,we get the hitpos,just make a ray
- float ft = MIN_WALL_DISTANCE/distanceToWall;
- dtVlerp(TestPos,hitPos,pCurPoi,ft);
- distanceToWall = DistanceToWall(navQuery, navMesh, polyPickExt, filter, TestPos,hitPos,hitNormal);
-
- if(abs(distanceToWall-MIN_WALL_DISTANCE)<0.1f)
- dtVcopy(pCurPoi,TestPos);
- }
- }
- }
- }
-
static bool HandleMmapPathCommand(ChatHandler* handler, char const* args)
{
- if (!MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
+ if (!MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId()))
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
return true;
@@ -221,10 +91,10 @@ public:
player->GetPosition(x, y, z);
// path
- /*PathGenerator path(target);
+ PathGenerator path(target);
path.SetUseStraightPath(useStraightPath);
bool result = path.CalculatePath(x, y, z);
-
+
Movement::PointsArray const& pointPath = path.GetPath();
handler->PSendSysMessage("%s's path to %s:", target->GetName().c_str(), player->GetName().c_str());
handler->PSendSysMessage("Building: %s", useStraightPath ? "StraightPath" : "SmoothPath");
@@ -237,64 +107,13 @@ public:
handler->PSendSysMessage("StartPosition (%.3f, %.3f, %.3f)", start.x, start.y, start.z);
handler->PSendSysMessage("EndPosition (%.3f, %.3f, %.3f)", end.x, end.y, end.z);
handler->PSendSysMessage("ActualEndPosition (%.3f, %.3f, %.3f)", actualEnd.x, actualEnd.y, actualEnd.z);
- */
- float m_spos[3];
- m_spos[0] = -y;
- m_spos[1] = z;
- m_spos[2] = -x;
-
- //
- float m_epos[3];
- m_epos[0] = -target->GetPositionY();
- m_epos[1] = target->GetPositionZ();
- m_epos[2] = -target->GetPositionX();
-
- //
- dtQueryFilter m_filter;
- m_filter.setIncludeFlags(3);
- m_filter.setExcludeFlags(2);
-
- //
- float m_polyPickExt[3];
- m_polyPickExt[0] = 2.5f;
- m_polyPickExt[1] = 2.5f;
- m_polyPickExt[2] = 2.5f;
-
- //
- dtPolyRef m_startRef;
- dtPolyRef m_endRef;
-
- const dtNavMesh* navMesh = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMesh(player->GetMapId());
- const dtNavMeshQuery* navMeshQuery = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMeshQuery(player->GetMapId(), handler->GetSession()->GetPlayer()->GetInstanceId());
-
- float nearestPt[3];
-
- navMeshQuery->findNearestPoly(m_spos, m_polyPickExt, &m_filter, &m_startRef, nearestPt);
- navMeshQuery->findNearestPoly(m_epos, m_polyPickExt, &m_filter, &m_endRef, nearestPt);
-
- if ( !m_startRef || !m_endRef )
- {
- std::cerr << "Could not find any nearby poly's (" << m_startRef << "," << m_endRef << ")" << std::endl;
- return 0;
- }
-
- int hops;
- dtPolyRef* hopBuffer = new dtPolyRef[8192];
- dtStatus status = navMeshQuery->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, hopBuffer, &hops, 8192);
-
- int resultHopCount;
- float* straightPath = new float[2048*3];
- unsigned char* pathFlags = new unsigned char[2048];
- dtPolyRef* pathRefs = new dtPolyRef[2048];
-
- status = navMeshQuery->findStraightPath(m_spos, m_epos, hopBuffer, hops, straightPath, pathFlags, pathRefs, &resultHopCount, 2048);
- FixPath(const_cast<dtNavMesh*>(navMesh), const_cast<dtNavMeshQuery*>(navMeshQuery), m_polyPickExt, m_filter, resultHopCount, straightPath);
- for (uint32 i = 0; i < resultHopCount; ++i)
- player->SummonCreature(VISUAL_WAYPOINT, -straightPath[i * 3 + 2], -straightPath[i * 3 + 0], straightPath[i * 3 + 1], 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
if (!player->IsGameMaster())
handler->PSendSysMessage("Enable GM mode to see the path points.");
+ for (uint32 i = 0; i < pointPath.size(); ++i)
+ player->SummonCreature(VISUAL_WAYPOINT, pointPath[i].x, pointPath[i].y, pointPath[i].z, 0, TEMPSUMMON_TIMED_DESPAWN, 9000);
+
return true;
}
@@ -312,8 +131,8 @@ public:
handler->PSendSysMessage("gridloc [%i, %i]", gx, gy);
// calculate navmesh tile location
- dtNavMesh const* navmesh = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
- dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(handler->GetSession()->GetPlayer()->GetMapId(), player->GetInstanceId());
if (!navmesh || !navmeshquery)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
@@ -323,8 +142,8 @@ public:
float const* min = navmesh->getParams()->orig;
float x, y, z;
player->GetPosition(x, y, z);
- float location[] = {y, z, x};
- float extents[] = {3.0f, 5.0f, 3.0f};
+ float location[VERTEX_SIZE] = { y, z, x };
+ float extents[VERTEX_SIZE] = { 3.0f, 5.0f, 3.0f };
int32 tilex = int32((y - min[0]) / SIZE_OF_GRIDS);
int32 tiley = int32((x - min[2]) / SIZE_OF_GRIDS);
@@ -333,14 +152,14 @@ public:
// navmesh poly -> navmesh tile location
dtQueryFilter filter = dtQueryFilter();
- dtPolyRef polyRef = 0;
+ dtPolyRef polyRef = INVALID_POLYREF;
if (dtStatusFailed(navmeshquery->findNearestPoly(location, extents, &filter, &polyRef, NULL)))
{
handler->PSendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)");
return true;
}
- if (polyRef == 0)
+ if (polyRef == INVALID_POLYREF)
handler->PSendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)");
else
{
@@ -364,8 +183,8 @@ public:
static bool HandleMmapLoadedTilesCommand(ChatHandler* handler, char const* /*args*/)
{
uint32 mapid = handler->GetSession()->GetPlayer()->GetMapId();
- dtNavMesh const* navmesh = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMesh(mapid);
- dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::CreateOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
+ dtNavMesh const* navmesh = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMesh(mapid);
+ dtNavMeshQuery const* navmeshquery = MMAP::MMapFactory::createOrGetMMapManager()->GetNavMeshQuery(mapid, handler->GetSession()->GetPlayer()->GetInstanceId());
if (!navmesh || !navmeshquery)
{
handler->PSendSysMessage("NavMesh not loaded for current map.");
@@ -392,8 +211,8 @@ public:
handler->PSendSysMessage("mmap stats:");
handler->PSendSysMessage(" global mmap pathfinding is %sabled", MMAP::MMapFactory::IsPathfindingEnabled(mapId) ? "en" : "dis");
- MMAP::MMapManager* manager = MMAP::MMapFactory::CreateOrGetMMapManager();
- handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->GetLoadedMapsCount(), manager->GetLoadedTilesCount());
+ MMAP::MMapManager* manager = MMAP::MMapFactory::createOrGetMMapManager();
+ handler->PSendSysMessage(" %u maps loaded with %u tiles overall", manager->getLoadedMapsCount(), manager->getLoadedTilesCount());
dtNavMesh const* navmesh = manager->GetNavMesh(handler->GetSession()->GetPlayer()->GetMapId());
if (!navmesh)