Updated Copyright year to 2013
[getmangos.git] / src / game / MoveMap.cpp
blob29ba537413fb54c7b7fd5a06e9f2ff0ecf96089e
1 /*
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
19 #include "GridMap.h"
20 #include "Log.h"
21 #include "World.h"
23 #include "MoveMap.h"
24 #include "MoveMapSharedDefines.h"
26 namespace MMAP
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();
40 return g_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, ",");
53 while (idstr)
55 g_mmapDisabledIds->insert(uint32(atoi(idstr)));
56 idstr = strtok(NULL, ",");
59 delete[] mapList;
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;
71 delete g_MMapManager;
73 g_mmapDisabledIds = NULL;
74 g_MMapManager = NULL;
77 // ######################## MMapManager ########################
78 MMapManager::~MMapManager()
80 for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
81 delete i->second;
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())
91 return true;
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");
99 if (!file)
101 sLog.outDebug("MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
102 delete[] fileName;
103 return false;
106 dtNavMeshParams params;
107 fread(&params, sizeof(dtNavMeshParams), 1, file);
108 fclose(file);
110 dtNavMesh* mesh = dtAllocNavMesh();
111 MANGOS_ASSERT(mesh);
112 if (DT_SUCCESS != mesh->init(&params))
114 dtFreeNavMesh(mesh);
115 sLog.outError("MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
116 delete[] fileName;
117 return false;
120 delete[] 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));
129 return true;
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))
141 return false;
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);
152 return false;
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");
161 if (!file)
163 sLog.outDebug("MMAP:loadMap: Could not open mmtile file '%s'", fileName);
164 delete[] fileName;
165 return false;
167 delete[] fileName;
169 // read header
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);
176 return false;
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);
183 return false;
186 unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);
187 MANGOS_ASSERT(data);
189 size_t result = fread(data, fileHeader.size, 1, file);
190 if (!result)
192 sLog.outError("MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
193 fclose(file);
194 return false;
197 fclose(file);
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);
206 dtFree(data);
207 return false;
210 mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
211 ++loadedTiles;
212 sLog.outDetail("MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
213 return true;
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);
223 return false;
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);
234 return false;
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);
248 else
250 mmap->mmapLoadedTiles.erase(packedGridPos);
251 --loadedTiles;
252 sLog.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
253 return true;
256 return false;
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);
265 return false;
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);
276 else
278 --loadedTiles;
279 sLog.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
283 delete mmap;
284 loadedMMaps.erase(mapId);
285 sLog.outDetail("MMAP:unloadMap: Unloaded %03i.mmap", mapId);
287 return true;
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);
297 return false;
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);
304 return false;
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);
313 return true;
316 dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
318 if (loadedMMaps.find(mapId) == loadedMMaps.end())
319 return NULL;
321 return loadedMMaps[mapId]->navMesh;
324 dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
326 if (loadedMMaps.find(mapId) == loadedMMaps.end())
327 return NULL;
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);
339 return NULL;
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];