2 * Copyright (C) 2005-2013 MaNGOS <http://getmangos.com/>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "MoveMapSharedDefines.h"
28 // ######################## MMapFactory ########################
29 // our global singelton copy
30 MMapManager
* g_MMapManager
= NULL
;
32 // stores list of mapids which do not use pathfinding
33 std::set
<uint32
>* g_mmapDisabledIds
= NULL
;
35 MMapManager
* MMapFactory::createOrGetMMapManager()
37 if (g_MMapManager
== NULL
)
38 g_MMapManager
= new MMapManager();
43 void MMapFactory::preventPathfindingOnMaps(const char* ignoreMapIds
)
45 if (!g_mmapDisabledIds
)
46 g_mmapDisabledIds
= new std::set
<uint32
>();
48 uint32 strLenght
= strlen(ignoreMapIds
) + 1;
49 char* mapList
= new char[strLenght
];
50 memcpy(mapList
, ignoreMapIds
, sizeof(char)*strLenght
);
52 char* idstr
= strtok(mapList
, ",");
55 g_mmapDisabledIds
->insert(uint32(atoi(idstr
)));
56 idstr
= strtok(NULL
, ",");
62 bool MMapFactory::IsPathfindingEnabled(uint32 mapId
)
64 return sWorld
.getConfig(CONFIG_BOOL_MMAP_ENABLED
)
65 && g_mmapDisabledIds
->find(mapId
) == g_mmapDisabledIds
->end();
68 void MMapFactory::clear()
70 delete g_mmapDisabledIds
;
73 g_mmapDisabledIds
= NULL
;
77 // ######################## MMapManager ########################
78 MMapManager::~MMapManager()
80 for (MMapDataSet::iterator i
= loadedMMaps
.begin(); i
!= loadedMMaps
.end(); ++i
)
83 // by now we should not have maps loaded
84 // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
87 bool MMapManager::loadMapData(uint32 mapId
)
89 // we already have this map loaded?
90 if (loadedMMaps
.find(mapId
) != loadedMMaps
.end())
93 // load and init dtNavMesh - read parameters from file
94 uint32 pathLen
= sWorld
.GetDataPath().length() + strlen("mmaps/%03i.mmap") + 1;
95 char* fileName
= new char[pathLen
];
96 snprintf(fileName
, pathLen
, (sWorld
.GetDataPath() + "mmaps/%03i.mmap").c_str(), mapId
);
98 FILE* file
= fopen(fileName
, "rb");
101 sLog
.outDebug("MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName
);
106 dtNavMeshParams params
;
107 fread(¶ms
, sizeof(dtNavMeshParams
), 1, file
);
110 dtNavMesh
* mesh
= dtAllocNavMesh();
112 if (DT_SUCCESS
!= mesh
->init(¶ms
))
115 sLog
.outError("MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId
, fileName
);
122 sLog
.outDetail("MMAP:loadMapData: Loaded %03i.mmap", mapId
);
124 // store inside our map list
125 MMapData
* mmap_data
= new MMapData(mesh
);
126 mmap_data
->mmapLoadedTiles
.clear();
128 loadedMMaps
.insert(std::pair
<uint32
, MMapData
*>(mapId
, mmap_data
));
132 uint32
MMapManager::packTileID(int32 x
, int32 y
)
134 return uint32(x
<< 16 | y
);
137 bool MMapManager::loadMap(uint32 mapId
, int32 x
, int32 y
)
139 // make sure the mmap is loaded and ready to load tiles
140 if (!loadMapData(mapId
))
143 // get this mmap data
144 MMapData
* mmap
= loadedMMaps
[mapId
];
145 MANGOS_ASSERT(mmap
->navMesh
);
147 // check if we already have this tile loaded
148 uint32 packedGridPos
= packTileID(x
, y
);
149 if (mmap
->mmapLoadedTiles
.find(packedGridPos
) != mmap
->mmapLoadedTiles
.end())
151 sLog
.outError("MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId
, x
, y
);
155 // load this tile :: mmaps/MMMXXYY.mmtile
156 uint32 pathLen
= sWorld
.GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1;
157 char* fileName
= new char[pathLen
];
158 snprintf(fileName
, pathLen
, (sWorld
.GetDataPath() + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId
, x
, y
);
160 FILE* file
= fopen(fileName
, "rb");
163 sLog
.outDebug("MMAP:loadMap: Could not open mmtile file '%s'", fileName
);
170 MmapTileHeader fileHeader
;
171 fread(&fileHeader
, sizeof(MmapTileHeader
), 1, file
);
173 if (fileHeader
.mmapMagic
!= MMAP_MAGIC
)
175 sLog
.outError("MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId
, x
, y
);
179 if (fileHeader
.mmapVersion
!= MMAP_VERSION
)
181 sLog
.outError("MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
182 mapId
, x
, y
, fileHeader
.mmapVersion
, MMAP_VERSION
);
186 unsigned char* data
= (unsigned char*)dtAlloc(fileHeader
.size
, DT_ALLOC_PERM
);
189 size_t result
= fread(data
, fileHeader
.size
, 1, file
);
192 sLog
.outError("MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId
, x
, y
);
199 dtMeshHeader
* header
= (dtMeshHeader
*)data
;
200 dtTileRef tileRef
= 0;
202 // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
203 if (mmap
->navMesh
->addTile(data
, fileHeader
.size
, DT_TILE_FREE_DATA
, 0, &tileRef
) != DT_SUCCESS
)
205 sLog
.outError("MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId
, x
, y
);
210 mmap
->mmapLoadedTiles
.insert(std::pair
<uint32
, dtTileRef
>(packedGridPos
, tileRef
));
212 sLog
.outDetail("MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId
, x
, y
, mapId
, header
->x
, header
->y
);
216 bool MMapManager::unloadMap(uint32 mapId
, int32 x
, int32 y
)
218 // check if we have this map loaded
219 if (loadedMMaps
.find(mapId
) == loadedMMaps
.end())
221 // file may not exist, therefore not loaded
222 sLog
.outDebug("MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId
, x
, y
);
226 MMapData
* mmap
= loadedMMaps
[mapId
];
228 // check if we have this tile loaded
229 uint32 packedGridPos
= packTileID(x
, y
);
230 if (mmap
->mmapLoadedTiles
.find(packedGridPos
) == mmap
->mmapLoadedTiles
.end())
232 // file may not exist, therefore not loaded
233 sLog
.outDebug("MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId
, x
, y
);
237 dtTileRef tileRef
= mmap
->mmapLoadedTiles
[packedGridPos
];
239 // unload, and mark as non loaded
240 if (DT_SUCCESS
!= mmap
->navMesh
->removeTile(tileRef
, NULL
, NULL
))
242 // this is technically a memory leak
243 // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
244 // we cannot recover from this error - assert out
245 sLog
.outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId
, x
, y
);
246 MANGOS_ASSERT(false);
250 mmap
->mmapLoadedTiles
.erase(packedGridPos
);
252 sLog
.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId
, x
, y
, mapId
);
259 bool MMapManager::unloadMap(uint32 mapId
)
261 if (loadedMMaps
.find(mapId
) == loadedMMaps
.end())
263 // file may not exist, therefore not loaded
264 sLog
.outDebug("MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId
);
268 // unload all tiles from given map
269 MMapData
* mmap
= loadedMMaps
[mapId
];
270 for (MMapTileSet::iterator i
= mmap
->mmapLoadedTiles
.begin(); i
!= mmap
->mmapLoadedTiles
.end(); ++i
)
272 uint32 x
= (i
->first
>> 16);
273 uint32 y
= (i
->first
& 0x0000FFFF);
274 if (DT_SUCCESS
!= mmap
->navMesh
->removeTile(i
->second
, NULL
, NULL
))
275 sLog
.outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId
, x
, y
);
279 sLog
.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId
, x
, y
, mapId
);
284 loadedMMaps
.erase(mapId
);
285 sLog
.outDetail("MMAP:unloadMap: Unloaded %03i.mmap", mapId
);
290 bool MMapManager::unloadMapInstance(uint32 mapId
, uint32 instanceId
)
292 // check if we have this map loaded
293 if (loadedMMaps
.find(mapId
) == loadedMMaps
.end())
295 // file may not exist, therefore not loaded
296 sLog
.outDebug("MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId
);
300 MMapData
* mmap
= loadedMMaps
[mapId
];
301 if (mmap
->navMeshQueries
.find(instanceId
) == mmap
->navMeshQueries
.end())
303 sLog
.outDebug("MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId
, instanceId
);
307 dtNavMeshQuery
* query
= mmap
->navMeshQueries
[instanceId
];
309 dtFreeNavMeshQuery(query
);
310 mmap
->navMeshQueries
.erase(instanceId
);
311 sLog
.outDetail("MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId
, instanceId
);
316 dtNavMesh
const* MMapManager::GetNavMesh(uint32 mapId
)
318 if (loadedMMaps
.find(mapId
) == loadedMMaps
.end())
321 return loadedMMaps
[mapId
]->navMesh
;
324 dtNavMeshQuery
const* MMapManager::GetNavMeshQuery(uint32 mapId
, uint32 instanceId
)
326 if (loadedMMaps
.find(mapId
) == loadedMMaps
.end())
329 MMapData
* mmap
= loadedMMaps
[mapId
];
330 if (mmap
->navMeshQueries
.find(instanceId
) == mmap
->navMeshQueries
.end())
332 // allocate mesh query
333 dtNavMeshQuery
* query
= dtAllocNavMeshQuery();
334 MANGOS_ASSERT(query
);
335 if (DT_SUCCESS
!= query
->init(mmap
->navMesh
, 1024))
337 dtFreeNavMeshQuery(query
);
338 sLog
.outError("MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId
, instanceId
);
342 sLog
.outDetail("MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId
, instanceId
);
343 mmap
->navMeshQueries
.insert(std::pair
<uint32
, dtNavMeshQuery
*>(instanceId
, query
));
346 return mmap
->navMeshQueries
[instanceId
];