OregonCore  revision 3611e8a-git
Your Favourite TBC server
MoveMap.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the OregonCore Project. See AUTHORS file for Copyright information
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the
6  * Free Software Foundation; either version 2 of the License, or (at your
7  * option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "Map.h"
19 #include "Log.h"
20 #include "World.h"
21 
22 #include "MoveMap.h"
23 #include "MoveMapSharedDefines.h"
24 
25 namespace MMAP
26 {
27 // ######################## MMapFactory ########################
28 // our global singelton copy
30 
31 // stores list of mapids which do not use pathfinding
32 std::set<uint32>* g_mmapDisabledIds = NULL;
33 
35 {
36  if (g_MMapManager == NULL)
37  g_MMapManager = new MMapManager();
38 
39  return g_MMapManager;
40 }
41 
42 void MMapFactory::preventPathfindingOnMaps(const char* ignoreMapIds)
43 {
44  if (!g_mmapDisabledIds)
45  g_mmapDisabledIds = new std::set<uint32>();
46 
47  uint32 strLenght = strlen(ignoreMapIds) + 1;
48  char* mapList = new char[strLenght];
49  memcpy(mapList, ignoreMapIds, sizeof(char)*strLenght);
50 
51  char* idstr = strtok(mapList, ",");
52  while (idstr)
53  {
54  g_mmapDisabledIds->insert(uint32(atoi(idstr)));
55  idstr = strtok(NULL, ",");
56  }
57 
58  delete[] mapList;
59 }
60 
62 {
63  return sWorld.getConfig(CONFIG_BOOL_MMAP_ENABLED)
64  && g_mmapDisabledIds->find(mapId) == g_mmapDisabledIds->end();
65 }
66 
68 {
69  if (g_mmapDisabledIds)
70  {
71  delete g_mmapDisabledIds;
72  g_mmapDisabledIds = NULL;
73  }
74 
75  if (g_MMapManager)
76  {
77  delete g_MMapManager;
78  g_MMapManager = NULL;
79  }
80 }
81 
82 // ######################## MMapManager ########################
84 {
85  for (MMapDataSet::iterator i = loadedMMaps.begin(); i != loadedMMaps.end(); ++i)
86  delete i->second;
87 
88  // by now we should not have maps loaded
89  // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
90 }
91 
92  void MMapManager::InitializeThreadUnsafe(const std::vector<uint32>& mapIds)
93  {
94  // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
95  for (const uint32& mapId : mapIds)
96  loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr));
97 
98  thread_safe_environment = false;
99  }
100 
101  MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const
102  {
103  // return the iterator if found or end() if not found/NULL
104  MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
105  if (itr != loadedMMaps.cend() && !itr->second)
106  itr = loadedMMaps.cend();
107 
108  return itr;
109  }
110 
112 {
113  // we already have this map loaded?
114  MMapDataSet::iterator itr = loadedMMaps.find(mapId);
115  if (itr != loadedMMaps.end())
116  {
117  if (itr->second)
118  return true;
119  }
120  else
121  {
122  if (thread_safe_environment)
123  itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
124  else
125  ASSERT(false && "Invalid mapId passed to MMapManager after startup in thread unsafe environment");
126  }
127 
128  // load and init dtNavMesh - read parameters from file
129  uint32 pathLen = sWorld.GetDataPath().length() + strlen("mmaps/%03i.mmap") + 1;
130  char* fileName = new char[pathLen];
131  snprintf(fileName, pathLen, (sWorld.GetDataPath() + "mmaps/%03i.mmap").c_str(), mapId);
132 
133  FILE* file = fopen(fileName, "rb");
134  if (!file)
135  {
136  sLog.outMMap("MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName);
137  delete [] fileName;
138  return false;
139  }
140 
141  dtNavMeshParams params;
142  fread(&params, sizeof(dtNavMeshParams), 1, file);
143  fclose(file);
144 
145  dtNavMesh* mesh = dtAllocNavMesh();
146  ASSERT(mesh);
147  if (dtStatusFailed(mesh->init(&params)))
148  {
149  dtFreeNavMesh(mesh);
150  sLog.outError("MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %03u from file %s", mapId, fileName);
151  delete [] fileName;
152  return false;
153  }
154 
155  delete [] fileName;
156 
157  sLog.outDetail("MMAP:loadMapData: Loaded %03i.mmap", mapId);
158 
159  // store inside our map list
160  MMapData* mmap_data = new MMapData(mesh);
161  mmap_data->mmapLoadedTiles.clear();
162 
163  itr->second = mmap_data;
164  return true;
165 }
166 
168 {
169  return uint32(x << 16 | y);
170 }
171 
173 {
174  // make sure the mmap is loaded and ready to load tiles
175  if (!loadMapData(mapId))
176  return false;
177 
178  // get this mmap data
179  MMapData* mmap = loadedMMaps[mapId];
180  ASSERT(mmap->navMesh);
181 
182  // check if we already have this tile loaded
183  uint32 packedGridPos = packTileID(x, y);
184  if (mmap->mmapLoadedTiles.find(packedGridPos) != mmap->mmapLoadedTiles.end())
185  {
186  sLog.outError("MMAP:loadMap: Asked to load already loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
187  return false;
188  }
189 
190  // load this tile :: mmaps/MMMXXYY.mmtile
191  uint32 pathLen = sWorld.GetDataPath().length() + strlen("mmaps/%03i%02i%02i.mmtile") + 1;
192  char* fileName = new char[pathLen];
193  snprintf(fileName, pathLen, (sWorld.GetDataPath() + "mmaps/%03i%02i%02i.mmtile").c_str(), mapId, x, y);
194 
195  FILE* file = fopen(fileName, "rb");
196  if (!file)
197  {
198  sLog.outMMap("MMAP:loadMap: Could not open mmtile file '%s'", fileName);
199  delete [] fileName;
200  return false;
201  }
202  delete [] fileName;
203 
204  // read header
205  MmapTileHeader fileHeader;
206  fread(&fileHeader, sizeof(MmapTileHeader), 1, file);
207 
208  if (fileHeader.mmapMagic != MMAP_MAGIC)
209  {
210  sLog.outError("MMAP:loadMap: Bad header in mmap %03u%02i%02i.mmtile", mapId, x, y);
211  fclose(file);
212  return false;
213  }
214 
215  if (fileHeader.mmapVersion != MMAP_VERSION)
216  {
217  sLog.outError("MMAP:loadMap: %03u%02i%02i.mmtile was built with generator v%i, expected v%i",
218  mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
219  fclose(file);
220  return false;
221  }
222 
223  unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);
224  ASSERT(data);
225 
226  size_t result = fread(data, fileHeader.size, 1, file);
227  if (!result)
228  {
229  sLog.outError("MMAP:loadMap: Bad header or data in mmap %03u%02i%02i.mmtile", mapId, x, y);
230  fclose(file);
231  return false;
232  }
233 
234  fclose(file);
235 
236  dtMeshHeader* header = (dtMeshHeader*)data;
237  dtTileRef tileRef = 0;
238 
239  // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
240  if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
241  {
242  mmap->mmapLoadedTiles.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
243  ++loadedTiles;
244  sLog.outDetail("MMAP:loadMap: Loaded mmtile %03i[%02i,%02i] into %03i[%02i,%02i]", mapId, x, y, mapId, header->x, header->y);
245  return true;
246  }
247  else
248  {
249  sLog.outError("MMAP:loadMap: Could not load %03u%02i%02i.mmtile into navmesh", mapId, x, y);
250  dtFree(data);
251  return false;
252  }
253 }
254 
256 {
257  // check if we have this map loaded
258  MMapDataSet::const_iterator itr = GetMMapData(mapId);
259  if (itr == loadedMMaps.end())
260  {
261  // file may not exist, therefore not loaded
262  sLog.outMMap("MMAP:unloadMap: Asked to unload not loaded navmesh map. %03u%02i%02i.mmtile", mapId, x, y);
263  return false;
264  }
265 
266  MMapData* mmap = itr->second;
267 
268  // check if we have this tile loaded
269  uint32 packedGridPos = packTileID(x, y);
270  if (mmap->mmapLoadedTiles.find(packedGridPos) == mmap->mmapLoadedTiles.end())
271  {
272  // file may not exist, therefore not loaded
273  sLog.outMMap("MMAP:unloadMap: Asked to unload not loaded navmesh tile. %03u%02i%02i.mmtile", mapId, x, y);
274  return false;
275  }
276 
277  dtTileRef tileRef = mmap->mmapLoadedTiles[packedGridPos];
278 
279  // unload, and mark as non loaded
280  if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, NULL, NULL)))
281  {
282  // this is technically a memory leak
283  // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
284  // we cannot recover from this error - assert out
285  sLog.outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
286  ASSERT(false);
287  }
288  else
289  {
290  mmap->mmapLoadedTiles.erase(packedGridPos);
291  --loadedTiles;
292  sLog.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
293  return true;
294  }
295 
296  return false;
297 }
298 
300 {
301  MMapDataSet::iterator itr = loadedMMaps.find(mapId);
302  if (itr == loadedMMaps.end() || !itr->second)
303  {
304  // file may not exist, therefore not loaded
305  sLog.outMMap("MMAP:unloadMap: Asked to unload not loaded navmesh map %03u", mapId);
306  return false;
307  }
308 
309  // unload all tiles from given map
310  MMapData* mmap = itr->second;
311  for (MMapTileSet::iterator i = mmap->mmapLoadedTiles.begin(); i != mmap->mmapLoadedTiles.end(); ++i)
312  {
313  uint32 x = (i->first >> 16);
314  uint32 y = (i->first & 0x0000FFFF);
315  if (dtStatusFailed(mmap->navMesh->removeTile(i->second, NULL, NULL)))
316  sLog.outError("MMAP:unloadMap: Could not unload %03u%02i%02i.mmtile from navmesh", mapId, x, y);
317  else
318  {
319  --loadedTiles;
320  sLog.outDetail("MMAP:unloadMap: Unloaded mmtile %03i[%02i,%02i] from %03i", mapId, x, y, mapId);
321  }
322  }
323 
324  delete mmap;
325  itr->second = nullptr;
326  sLog.outDetail("MMAP:unloadMap: Unloaded %03i.mmap", mapId);
327 
328  return true;
329 }
330 
332 {
333  // check if we have this map loaded
334  MMapDataSet::const_iterator itr = GetMMapData(mapId);
335  if (itr == loadedMMaps.end())
336  {
337  // file may not exist, therefore not loaded
338  sLog.outMMap("MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %03u", mapId);
339  return false;
340  }
341 
342  MMapData* mmap = itr->second;
343  if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
344  {
345  sLog.outMMap("MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %03u instanceId %u", mapId, instanceId);
346  return false;
347  }
348 
349  dtNavMeshQuery* query = mmap->navMeshQueries[instanceId];
350 
351  dtFreeNavMeshQuery(query);
352  mmap->navMeshQueries.erase(instanceId);
353  sLog.outDetail("MMAP:unloadMapInstance: Unloaded mapId %03u instanceId %u", mapId, instanceId);
354 
355  return true;
356 }
357 
358 dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
359 {
360  MMapDataSet::const_iterator itr = GetMMapData(mapId);
361  if (itr == loadedMMaps.end())
362  return NULL;
363 
364  return itr->second->navMesh;
365 }
366 
367 dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
368 {
369  MMapDataSet::const_iterator itr = GetMMapData(mapId);
370  if (itr == loadedMMaps.end())
371  return NULL;
372 
373  MMapData* mmap = itr->second;
374  if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
375  {
376  // allocate mesh query
377  dtNavMeshQuery* query = dtAllocNavMeshQuery();
378  ASSERT(query);
379  if (dtStatusFailed(query->init(mmap->navMesh, 1024)))
380  {
381  dtFreeNavMeshQuery(query);
382  sLog.outError("MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
383  return NULL;
384  }
385 
386  sLog.outDetail("MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
387  mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
388  }
389 
390  return mmap->navMeshQueries[instanceId];
391 }
392 }
NavMeshQuerySet navMeshQueries
Definition: MoveMap.h:61
#define MMAP_MAGIC
#define snprintf
Definition: Common.h:129
MMapManager * g_MMapManager
Definition: MoveMap.cpp:29
bool loadMapData(uint32 mapId)
Definition: MoveMap.cpp:111
MMapTileSet mmapLoadedTiles
Definition: MoveMap.h:62
static void clear()
Definition: MoveMap.cpp:67
uint32 packTileID(int32 x, int32 y)
Definition: MoveMap.cpp:167
#define sLog
Log class singleton.
Definition: Log.h:187
ACE_INT32 int32
Definition: Define.h:67
Definition: MoveMap.cpp:25
bool unloadMap(uint32 mapId, int32 x, int32 y)
Definition: MoveMap.cpp:255
MMapDataSet::const_iterator GetMMapData(uint32 mapId) const
Definition: MoveMap.cpp:101
std::set< uint32 > * g_mmapDisabledIds
Definition: MoveMap.cpp:32
bool loadMap(uint32 mapId, int32 x, int32 y)
Definition: MoveMap.cpp:172
void InitializeThreadUnsafe(const std::vector< uint32 > &mapIds)
Definition: MoveMap.cpp:92
dtNavMesh const * GetNavMesh(uint32 mapId)
Definition: MoveMap.cpp:358
dtNavMesh * navMesh
Definition: MoveMap.h:58
bool unloadMapInstance(uint32 mapId, uint32 instanceId)
Definition: MoveMap.cpp:331
static void preventPathfindingOnMaps(const char *ignoreMapIds)
Definition: MoveMap.cpp:42
#define ASSERT
Definition: Errors.h:33
dtNavMeshQuery const * GetNavMeshQuery(uint32 mapId, uint32 instanceId)
Definition: MoveMap.cpp:367
static MMapManager * createOrGetMMapManager()
Definition: MoveMap.cpp:34
#define sWorld
Definition: World.h:860
static bool IsPathfindingEnabled(uint32 mapId)
Definition: MoveMap.cpp:61
#define MMAP_VERSION
ACE_UINT32 uint32
Definition: Define.h:71