Legends-of-Azeroth-Pandaria-5.4.8

Форк
0
337 строк · 12.3 Кб
1
/*
2
* This file is part of the Pandaria 5.4.8 Project. See THANKS 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 "MMapManager.h"
19
#include "Errors.h"
20
#include "Log.h"
21
#include "Config.h"
22
#include "MapDefines.h"
23

24
namespace MMAP
25
{
26
    constexpr char MAP_FILE_NAME_FORMAT[] = "%s/mmaps/%04i.mmap";
27
    constexpr char TILE_FILE_NAME_FORMAT[] = "%s/mmaps/%04i_%02i_%02i.mmtile";
28

29
    // ######################## MMapManager ########################
30
    MMapManager::~MMapManager()
31
    {
32
        for (std::pair<uint32 const, MMapData*>& loadedMMap : loadedMMaps)
33
            delete loadedMMap.second;
34

35
        // by now we should not have maps loaded
36
        // if we had, tiles in MMapData->mmapLoadedTiles, their actual data is lost!
37
    }
38

39
    void MMapManager::InitializeThreadUnsafe(const std::vector<uint32>& mapIds)
40
    {
41
        // the caller must pass the list of all mapIds that will be used in the VMapManager2 lifetime
42
        for (uint32 const& mapId : mapIds)
43
            loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr));
44

45
        thread_safe_environment = false;
46
    }
47

48
    MMapDataSet::const_iterator MMapManager::GetMMapData(uint32 mapId) const
49
    {
50
        // return the iterator if found or end() if not found/NULL
51
        MMapDataSet::const_iterator itr = loadedMMaps.find(mapId);
52
        if (itr != loadedMMaps.cend() && !itr->second)
53
            itr = loadedMMaps.cend();
54

55
        return itr;
56
    }
57

58
    bool MMapManager::loadMapData(uint32 mapId)
59
    {
60
        // we already have this map loaded?
61
        MMapDataSet::iterator itr = loadedMMaps.find(mapId);
62
        if (itr != loadedMMaps.end())
63
        {
64
            if (itr->second)
65
                return true;
66
        }
67
        else
68
        {
69
            if (thread_safe_environment)
70
                itr = loadedMMaps.insert(MMapDataSet::value_type(mapId, nullptr)).first;
71
            else
72
                ABORT_MSG("Invalid mapId %u passed to MMapManager after startup in thread unsafe environment", mapId);
73
        }
74

75
        // load and init dtNavMesh - read parameters from file
76
        std::string fileName = Trinity::StringFormat(MAP_FILE_NAME_FORMAT, sConfigMgr->GetStringDefault("DataDir", ".").c_str(), mapId);
77
        FILE* file = fopen(fileName.c_str(), "rb");
78
        if (!file)
79
        {
80
            TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not open mmap file '%s'", fileName.c_str());
81
            return false;
82
        }
83

84
        dtNavMeshParams params;
85
        uint32 count = uint32(fread(&params, sizeof(dtNavMeshParams), 1, file));
86
        fclose(file);
87
        if (count != 1)
88
        {
89
            TC_LOG_DEBUG("maps", "MMAP:loadMapData: Error: Could not read params from file '%s'", fileName.c_str());
90
            return false;
91
        }
92

93
        dtNavMesh* mesh = dtAllocNavMesh();
94
        ASSERT(mesh);
95
        if (dtStatusFailed(mesh->init(&params)))
96
        {
97
            dtFreeNavMesh(mesh);
98
            TC_LOG_ERROR("maps", "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap %04u from file %s", mapId, fileName.c_str());
99
            return false;
100
        }
101

102
        TC_LOG_DEBUG("maps", "MMAP:loadMapData: Loaded %04i.mmap", mapId);
103

104
        // store inside our map list
105
        MMapData* mmap_data = new MMapData(mesh);
106

107
        itr->second = mmap_data;
108
        return true;
109
    }
110

111
    uint32 MMapManager::packTileID(int32 x, int32 y)
112
    {
113
        return uint32(x << 16 | y);
114
    }
115

116
    bool MMapManager::loadMap(uint32 mapId, int32 x, int32 y)
117
    {
118
        // make sure the mmap is loaded and ready to load tiles
119
        if (!loadMapData(mapId))
120
            return false;
121

122
        // get this mmap data
123
        MMapData* mmap = loadedMMaps[mapId];
124
        ASSERT(mmap->navMesh);
125

126
        // check if we already have this tile loaded
127
        uint32 packedGridPos = packTileID(x, y);
128
        if (mmap->loadedTileRefs.find(packedGridPos) != mmap->loadedTileRefs.end())
129
            return false;
130

131
        // load this tile :: mmaps/MMMXXYY.mmtile
132
        std::string fileName = Trinity::StringFormat(TILE_FILE_NAME_FORMAT, sConfigMgr->GetStringDefault("DataDir", ".").c_str(), mapId, x, y);
133
        FILE* file = fopen(fileName.c_str(), "rb");
134
        if (!file)
135
        {
136
            TC_LOG_ERROR("maps", "MMAP:loadMap: Could not open mmtile file '%s'", fileName.c_str());
137
            return false;
138
        }
139

140
        // read header
141
        MmapTileHeader fileHeader;
142
        if (fread(&fileHeader, sizeof(MmapTileHeader), 1, file) != 1 || fileHeader.mmapMagic != MMAP_MAGIC)
143
        {
144
            TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header in mmap %04u_%02i_%02i.mmtile", mapId, x, y);
145
            fclose(file);
146
            return false;
147
        }
148

149
        if (fileHeader.mmapVersion != MMAP_VERSION)
150
        {
151
            TC_LOG_ERROR("maps", "MMAP:loadMap: %04u_%02i_%02i.mmtile was built with generator v%i, expected v%i",
152
                mapId, x, y, fileHeader.mmapVersion, MMAP_VERSION);
153
            fclose(file);
154
            return false;
155
        }
156

157
        long pos = ftell(file);
158
        fseek(file, 0, SEEK_END);
159
        if (pos < 0 || static_cast<int32>(fileHeader.size) > ftell(file) - pos)
160
        {
161
            TC_LOG_ERROR("maps", "MMAP:loadMap: %04u_%02i_%02i.mmtile has corrupted data size", mapId, x, y);
162
            fclose(file);
163
            return false;
164
        }
165

166
        fseek(file, pos, SEEK_SET);
167

168
        unsigned char* data = (unsigned char*)dtAlloc(fileHeader.size, DT_ALLOC_PERM);
169
        ASSERT(data);
170

171
        size_t result = fread(data, fileHeader.size, 1, file);
172
        if (!result)
173
        {
174
            TC_LOG_ERROR("maps", "MMAP:loadMap: Bad header or data in mmap %04u_%02i_%02i.mmtile", mapId, x, y);
175
            fclose(file);
176
            return false;
177
        }
178

179
        fclose(file);
180

181
        dtMeshHeader* header = (dtMeshHeader*)data;
182
        dtTileRef tileRef = 0;
183

184
        // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed
185
        if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef)))
186
        {
187
            mmap->loadedTileRefs.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef));
188
            ++loadedTiles;
189
            TC_LOG_DEBUG("maps", "MMAP:loadMap: Loaded mmtile %04i[%02i, %02i] into %04i[%02i, %02i]", mapId, x, y, mapId, header->x, header->y);
190
            return true;
191
        }
192
        else
193
        {
194
            TC_LOG_ERROR("maps", "MMAP:loadMap: Could not load %04u_%02i_%02i.mmtile into navmesh", mapId, x, y);
195
            dtFree(data);
196
            return false;
197
        }
198
    }
199

200
    bool MMapManager::unloadMap(uint32 mapId, int32 x, int32 y)
201
    {
202
        // check if we have this map loaded
203
        MMapDataSet::const_iterator itr = GetMMapData(mapId);
204
        if (itr == loadedMMaps.end())
205
        {
206
            // file may not exist, therefore not loaded
207
            TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map. %04u_%02i_%02i.mmtile", mapId, x, y);
208
            return false;
209
        }
210

211
        MMapData* mmap = itr->second;
212

213
        // check if we have this tile loaded
214
        uint32 packedGridPos = packTileID(x, y);
215
        if (mmap->loadedTileRefs.find(packedGridPos) == mmap->loadedTileRefs.end())
216
        {
217
            // file may not exist, therefore not loaded
218
            TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh tile. %04u_%02i_%02i.mmtile", mapId, x, y);
219
            return false;
220
        }
221

222
        dtTileRef tileRef = mmap->loadedTileRefs[packedGridPos];
223

224
        // unload, and mark as non loaded
225
        if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, nullptr, nullptr)))
226
        {
227
            // this is technically a memory leak
228
            // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used
229
            // we cannot recover from this error - assert out
230
            TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %04u_%02i_%02i.mmtile from navmesh", mapId, x, y);
231
            ABORT();
232
        }
233
        else
234
        {
235
            mmap->loadedTileRefs.erase(packedGridPos);
236
            --loadedTiles;
237
            TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %04i[%02i, %02i] from %04i", mapId, x, y, mapId);
238
            return true;
239
        }
240

241
        return false;
242
    }
243

244
    bool MMapManager::unloadMap(uint32 mapId)
245
    {
246
        MMapDataSet::iterator itr = loadedMMaps.find(mapId);
247
        if (itr == loadedMMaps.end() || !itr->second)
248
        {
249
            // file may not exist, therefore not loaded
250
            TC_LOG_DEBUG("maps", "MMAP:unloadMap: Asked to unload not loaded navmesh map %04u", mapId);
251
            return false;
252
        }
253

254
        // unload all tiles from given map
255
        MMapData* mmap = itr->second;
256
        for (MMapTileSet::iterator i = mmap->loadedTileRefs.begin(); i != mmap->loadedTileRefs.end(); ++i)
257
        {
258
            uint32 x = (i->first >> 16);
259
            uint32 y = (i->first & 0x0000FFFF);
260
            if (dtStatusFailed(mmap->navMesh->removeTile(i->second, nullptr, nullptr)))
261
                TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %04u_%02i_%02i.mmtile from navmesh", mapId, x, y);
262
            else
263
            {
264
                --loadedTiles;
265
                TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %04u[%02i, %02i] from %04u", mapId, x, y, mapId);
266
            }
267
        }
268

269
        delete mmap;
270
        itr->second = nullptr;
271
        TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded %04i.mmap", mapId);
272

273
        return true;
274
    }
275

276
    bool MMapManager::unloadMapInstance(uint32 mapId, uint32 instanceId)
277
    {
278
        // check if we have this map loaded
279
        MMapDataSet::const_iterator itr = GetMMapData(mapId);
280
        if (itr == loadedMMaps.end())
281
        {
282
            // file may not exist, therefore not loaded
283
            TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded navmesh map %04u", mapId);
284
            return false;
285
        }
286

287
        MMapData* mmap = itr->second;
288
        if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
289
        {
290
            TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Asked to unload not loaded dtNavMeshQuery mapId %04u instanceId %u", mapId, instanceId);
291
            return false;
292
        }
293

294
        dtNavMeshQuery* query = mmap->navMeshQueries[instanceId];
295

296
        dtFreeNavMeshQuery(query);
297
        mmap->navMeshQueries.erase(instanceId);
298
        TC_LOG_DEBUG("maps", "MMAP:unloadMapInstance: Unloaded mapId %04u instanceId %u", mapId, instanceId);
299

300
        return true;
301
    }
302

303
    dtNavMesh const* MMapManager::GetNavMesh(uint32 mapId)
304
    {
305
        MMapDataSet::const_iterator itr = GetMMapData(mapId);
306
        if (itr == loadedMMaps.end())
307
            return nullptr;
308

309
        return itr->second->navMesh;
310
    }
311

312
    dtNavMeshQuery const* MMapManager::GetNavMeshQuery(uint32 mapId, uint32 instanceId)
313
    {
314
        MMapDataSet::const_iterator itr = GetMMapData(mapId);
315
        if (itr == loadedMMaps.end())
316
            return nullptr;
317

318
        MMapData* mmap = itr->second;
319
        if (mmap->navMeshQueries.find(instanceId) == mmap->navMeshQueries.end())
320
        {
321
            // allocate mesh query
322
            dtNavMeshQuery* query = dtAllocNavMeshQuery();
323
            ASSERT(query);
324
            if (dtStatusFailed(query->init(mmap->navMesh, 1024)))
325
            {
326
                dtFreeNavMeshQuery(query);
327
                TC_LOG_ERROR("maps", "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId %04u instanceId %u", mapId, instanceId);
328
                return nullptr;
329
            }
330

331
            TC_LOG_DEBUG("maps", "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId %03u instanceId %u", mapId, instanceId);
332
            mmap->navMeshQueries.insert(std::pair<uint32, dtNavMeshQuery*>(instanceId, query));
333
        }
334

335
        return mmap->navMeshQueries[instanceId];
336
    }
337
}
338

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.