diff options
author | Vincent_Michael <Vincent_Michael@gmx.de> | 2014-01-18 01:36:12 +0100 |
---|---|---|
committer | Vincent_Michael <Vincent_Michael@gmx.de> | 2014-01-18 01:36:12 +0100 |
commit | ad8c046916262918b88917cbe4194a943ce75d16 (patch) | |
tree | 1bdf4a3995b184377229a767278771f4e533b828 /src | |
parent | 3276a786cc35f4dddcceedcab84fba5e77b78e58 (diff) |
Core/Revert: ...
Diffstat (limited to 'src')
59 files changed, 1709 insertions, 1492 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(¶ms))) { 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) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 7c181e95104..0267f17fd6c 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -11,6 +11,7 @@ add_subdirectory(map_extractor) add_subdirectory(vmap4_assembler) add_subdirectory(vmap4_extractor) + #if (WITH_MESHEXTRACTOR) # add_subdirectory(mesh_extractor) #else() diff --git a/src/tools/mesh_extractor/ADT.cpp b/src/tools/mesh_extractor/ADT.cpp index f1b06fb1c0b..a55bdd5e4bb 100644 --- a/src/tools/mesh_extractor/ADT.cpp +++ b/src/tools/mesh_extractor/ADT.cpp @@ -25,7 +25,7 @@ ADT::ADT( std::string file, int x, int y ) : ObjectData(NULL), Data(NULL), HasOb { Data = new ChunkedData(file); ObjectData = new ChunkedData(file); - if (ObjectData->_Stream) + if (ObjectData->Stream) HasObjectData = true; else ObjectData = NULL; @@ -33,11 +33,6 @@ ADT::ADT( std::string file, int x, int y ) : ObjectData(NULL), Data(NULL), HasOb ADT::~ADT() { - // Temporarily delete the underlying streams, they are guaranteed to be different - // @TODO: Remove this code once the ChunkedData destructor properly releases _Stream - delete ObjectData->_Stream; - delete Data->_Stream; - delete ObjectData; delete Data; diff --git a/src/tools/mesh_extractor/Cache.h b/src/tools/mesh_extractor/Cache.h index 37aeb9caf48..5d8c02252c9 100644 --- a/src/tools/mesh_extractor/Cache.h +++ b/src/tools/mesh_extractor/Cache.h @@ -31,18 +31,24 @@ class GenericCache public: GenericCache() {} - T const* Get(K key) + static const uint32 FlushLimit = 300; // We can't get too close to filling up all the memory, and we have to be wary of the maximum number of open streams. + + void Insert(K key, T* val) + { + ACE_GUARD(ACE_Thread_Mutex, g, mutex); + + if (_items.size() > FlushLimit) + Clear(); + _items[key] = val; + } + + T* Get(K key) { ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL); typename std::map<K, T*>::iterator itr = _items.find(key); if (itr != _items.end()) return itr->second; - else - { - T* t = new T(key); // Create the object - _items[key] = t; - return t; - } + return NULL; } void Clear() diff --git a/src/tools/mesh_extractor/Chunk.cpp b/src/tools/mesh_extractor/Chunk.cpp index b1b28494a66..e4b2f60ff99 100644 --- a/src/tools/mesh_extractor/Chunk.cpp +++ b/src/tools/mesh_extractor/Chunk.cpp @@ -25,24 +25,24 @@ int32 Chunk::FindSubChunkOffset(std::string name) if (name.size() != 4) return -1; - Stream* stream = GetStream(); + FILE* stream = GetStream(); uint32 matched = 0; - while (stream->GetPos() < stream->GetSize()) + while (uint32(ftell(stream)) < Utils::Size(stream)) { - char b = stream->Read<char>(); - if (b != name[matched]) + char b = 0; + if (fread(&b, sizeof(char), 1, stream) != 1 || b != name[matched]) matched = 0; else ++matched; if (matched == 4) - return stream->GetPos() - 4; + return ftell(stream) - 4; } return -1; } -Stream* Chunk::GetStream() +FILE* Chunk::GetStream() { - _Stream->Seek(Offset, SEEK_SET); - return _Stream; + fseek(Stream, Offset, SEEK_SET); + return Stream; } diff --git a/src/tools/mesh_extractor/Chunk.h b/src/tools/mesh_extractor/Chunk.h index 6cb6a10c8c2..87201928435 100644 --- a/src/tools/mesh_extractor/Chunk.h +++ b/src/tools/mesh_extractor/Chunk.h @@ -19,21 +19,19 @@ #define CHUNK_H #include "Define.h" #include <string> -#include "Stream.h" - class ChunkedData; class Chunk { public: - Chunk(const char* name, uint32 length, uint32 offset, Stream* stream) : Name(name), Length(length), Offset(offset), _Stream(stream) {} + Chunk(const char* name, uint32 length, uint32 offset, FILE* stream) : Name(name), Length(length), Offset(offset), Stream(stream) {} int32 FindSubChunkOffset(std::string name); - Stream* GetStream(); + FILE* GetStream(); std::string Name; uint32 Length; uint32 Offset; - Stream* _Stream; + FILE* Stream; }; #endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/ChunkedData.cpp b/src/tools/mesh_extractor/ChunkedData.cpp index 96af6f56a52..ae7827d98ea 100644 --- a/src/tools/mesh_extractor/ChunkedData.cpp +++ b/src/tools/mesh_extractor/ChunkedData.cpp @@ -21,18 +21,18 @@ #include <string> -ChunkedData::ChunkedData(Stream* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) : -_Stream(stream) +ChunkedData::ChunkedData( FILE* stream, uint32 maxLength, uint32 chunksHint /*= 300*/ ) : +Stream(stream) { - if (!_Stream) + if (!Stream) return; Load(maxLength, chunksHint); } ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ ) { - _Stream = MPQHandler->GetFile(file); - if (!_Stream) + Stream = MPQHandler->GetFile(file); + if (!Stream) return; Load(0, chunksHint); } @@ -40,30 +40,31 @@ ChunkedData::ChunkedData( const std::string& file, uint32 chunksHint /*= 300*/ ) void ChunkedData::Load( uint32 maxLength, uint32 chunksHint ) { if (!maxLength) - maxLength = _Stream->GetSize(); + maxLength = Utils::Size(Stream); Chunks.reserve(chunksHint); - uint32 baseOffset = _Stream->GetPos(); + uint32 baseOffset = ftell(Stream); uint32 calcOffset = 0; - while ((calcOffset + baseOffset) < _Stream->GetSize() && (calcOffset < maxLength)) + while ((calcOffset + baseOffset) < Utils::Size(Stream) && (calcOffset < maxLength)) { char nameBytes[5]; - _Stream->Read(nameBytes, sizeof(char) * 4); - nameBytes[4] = '\0'; + uint32 read = fread(&nameBytes, sizeof(char), 4, Stream); + nameBytes[read] = '\0'; std::string name = std::string(nameBytes); + // Utils::Reverse(nameBytes); name = std::string(name.rbegin(), name.rend()); - - uint32 length = _Stream->Read<uint32>(); + uint32 length; + if (fread(&length, sizeof(uint32), 1, Stream) != 1) + continue; calcOffset += 8; - - Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, _Stream)); + Chunks.push_back(new Chunk(name.c_str(), length, calcOffset + baseOffset, Stream)); calcOffset += length; // save an extra seek at the end - if ((calcOffset + baseOffset) < _Stream->GetSize() && calcOffset < maxLength) - _Stream->Seek(length, SEEK_CUR); + if ((calcOffset + baseOffset) < Utils::Size(Stream) && calcOffset < maxLength) + fseek(Stream, length, SEEK_CUR); } } -int ChunkedData::GetFirstIndex( const std::string& name ) const +int ChunkedData::GetFirstIndex( const std::string& name ) { for (uint32 i = 0; i < Chunks.size(); ++i) if (Chunks[i]->Name == name) @@ -85,7 +86,6 @@ ChunkedData::~ChunkedData() delete *itr; Chunks.clear(); - /* WorldModelGroup Data and SubData share the same _Stream so it's deleted twice and it crashes - if (_Stream) - delete _Stream;*/ + if (Stream) + fclose(Stream); } diff --git a/src/tools/mesh_extractor/ChunkedData.h b/src/tools/mesh_extractor/ChunkedData.h index cef6c111542..48bb61f6959 100644 --- a/src/tools/mesh_extractor/ChunkedData.h +++ b/src/tools/mesh_extractor/ChunkedData.h @@ -20,20 +20,19 @@ #include <vector> #include "Chunk.h" -#include "Stream.h" class ChunkedData { public: - ChunkedData(Stream* stream, uint32 maxLength, uint32 chunksHint = 300); + ChunkedData(FILE* stream, uint32 maxLength, uint32 chunksHint = 300); ChunkedData(const std::string &file, uint32 chunksHint = 300); ~ChunkedData(); - int GetFirstIndex(const std::string& name) const; + int GetFirstIndex(const std::string& name); Chunk* GetChunkByName(const std::string& name); void Load(uint32 maxLength, uint32 chunksHint); std::vector<Chunk*> Chunks; - Stream* _Stream; + FILE* Stream; }; #endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/Constants.h b/src/tools/mesh_extractor/Constants.h index 1961c2f386f..75e08bcf6fd 100644 --- a/src/tools/mesh_extractor/Constants.h +++ b/src/tools/mesh_extractor/Constants.h @@ -26,8 +26,6 @@ public: TRIANGLE_TYPE_UNKNOWN, TRIANGLE_TYPE_TERRAIN, TRIANGLE_TYPE_WATER, - TRIANGLE_TYPE_MAGMA, - TRIANGLE_TYPE_SLIME, TRIANGLE_TYPE_DOODAD, TRIANGLE_TYPE_WMO }; diff --git a/src/tools/mesh_extractor/ContinentBuilder.cpp b/src/tools/mesh_extractor/ContinentBuilder.cpp index aa1666fd0e3..8f6a918ef8d 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.cpp +++ b/src/tools/mesh_extractor/ContinentBuilder.cpp @@ -16,21 +16,80 @@ */ #include "ContinentBuilder.h" +#include "TileBuilder.h" #include "WDT.h" #include "Utils.h" #include "DetourNavMesh.h" #include "Cache.h" +#include "ace/Task.h" #include "Recast.h" #include "DetourCommon.h" -void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const +class BuilderThread : public ACE_Task_Base +{ +private: + int X, Y, MapId; + std::string Continent; + dtNavMeshParams Params; + ContinentBuilder* cBuilder; +public: + BuilderThread(ContinentBuilder* _cBuilder, dtNavMeshParams& params) : Params(params), cBuilder(_cBuilder), Free(true) {} + + void SetData(int x, int y, int map, const std::string& cont) + { + X = x; + Y = y; + MapId = map; + Continent = cont; + } + + int svc() + { + Free = false; + printf("[%02i,%02i] Building tile\n", X, Y); + TileBuilder builder(cBuilder, Continent, X, Y, MapId); + char buff[100]; + sprintf(buff, "mmaps/%03u%02i%02i.mmtile", MapId, Y, X); + FILE* f = fopen(buff, "r"); + if (f) // Check if file already exists. + { + printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); + fclose(f); + Free = true; + return 0; + } + uint8* nav = builder.BuildTiled(Params); + if (nav) + { + f = fopen(buff, "wb"); + if (!f) + { + printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); + return 0; + } + MmapTileHeader header; + header.size = builder.DataSize; + fwrite(&header, sizeof(MmapTileHeader), 1, f); + fwrite(nav, sizeof(unsigned char), builder.DataSize, f); + fclose(f); + } + dtFree(nav); + printf("[%02i,%02i] Tile Built!\n", X, Y); + Free = true; + return 0; + } + + bool Free; +}; + +void ContinentBuilder::getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) { // this is for elevation if (verts && vertCount) rcCalcBounds(verts, vertCount, bmin, bmax); else { - bmin[1] = -FLT_MAX; + bmin[1] = FLT_MIN; bmax[1] = FLT_MAX; } @@ -69,6 +128,8 @@ void ContinentBuilder::Build() dtNavMeshParams params; + std::vector<BuilderThread*> Threads; + if (TileMap->IsGlobalModel) { printf("Map %s ( %u ) is a WMO. Building with 1 thread.\n", Continent.c_str(), MapId); @@ -98,7 +159,6 @@ void ContinentBuilder::Build() } MmapTileHeader mheader; - Utils::InitializeMmapTileHeader(mheader); mheader.size = builder->DataSize; fwrite(&mheader, sizeof(MmapTileHeader), 1, f); fwrite(nav, sizeof(unsigned char), builder->DataSize, f); @@ -110,70 +170,44 @@ void ContinentBuilder::Build() } else { - params.maxPolys = 1024; - params.maxTiles = TileMap->TileTable.size(); + params.maxPolys = 32768; + params.maxTiles = 4096; rcVcopy(params.orig, Constants::Origin); params.tileHeight = Constants::TileSize; params.tileWidth = Constants::TileSize; fwrite(¶ms, sizeof(dtNavMeshParams), 1, mmap); fclose(mmap); - std::vector<BuilderThread*> _threads; - BuilderThreadPool* pool = NumberOfThreads > 0 ? new BuilderThreadPool() : NULL; - + for (uint32 i = 0; i < NumberOfThreads; ++i) + Threads.push_back(new BuilderThread(this, params)); printf("Map %s ( %u ) has %u tiles. Building them with %u threads\n", Continent.c_str(), MapId, uint32(TileMap->TileTable.size()), NumberOfThreads); - for (std::vector<TilePos>::iterator itr = TileMap->TileTable.begin(); itr != TileMap->TileTable.end(); ++itr) - pool->Enqueue(new TileBuildRequest(this, Continent, itr->X, itr->Y, MapId, params)); - - for (uint32 i = 0; i < NumberOfThreads; ++i) - _threads.push_back(new BuilderThread(this, pool->Queue())); - - // Free memory - for (std::vector<BuilderThread*>::iterator _th = _threads.begin(); _th != _threads.end(); ++_th) { - (*_th)->wait(); - delete *_th; + bool next = false; + while (!next) + { + for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th) + { + if ((*_th)->Free) + { + (*_th)->SetData(itr->X, itr->Y, MapId, Continent); + (*_th)->activate(); + next = true; + break; + } + } + // Wait for 20 seconds + ACE_OS::sleep(ACE_Time_Value (0, 20000)); + } } - - delete pool; } Cache->Clear(); -} -int TileBuildRequest::call() -{ - printf("[%02i,%02i] Building tile\n", X, Y); - // Build the tile and return negative on error - TileBuilder tile(_builder, _continent, X, Y, _mapId); - char buff[100]; - sprintf(buff, "mmaps/%03u%02i%02i.mmtile", _mapId, Y, X); - FILE* f = fopen(buff, "r"); - if (f) // Check if file already exists. + // Free memory + for (std::vector<BuilderThread*>::iterator _th = Threads.begin(); _th != Threads.end(); ++_th) { - printf("[%02i,%02i] Tile skipped, file already exists\n", X, Y); - fclose(f); - return 0; - } - uint8* nav = tile.BuildTiled(_params); - if (nav) - { - f = fopen(buff, "wb"); - if (!f) - { - printf("Could not create file %s. Check that you have write permissions to the destination folder and try again\n", buff); - dtFree(nav); - return -1; - } - MmapTileHeader header; - Utils::InitializeMmapTileHeader(header); - header.size = tile.DataSize; - fwrite(&header, sizeof(MmapTileHeader), 1, f); - fwrite(nav, sizeof(unsigned char), tile.DataSize, f); - fclose(f); + (*_th)->wait(); + delete *_th; } - dtFree(nav); - printf("[%02i,%02i] Tile Built!\n", X, Y); - return 0; } diff --git a/src/tools/mesh_extractor/ContinentBuilder.h b/src/tools/mesh_extractor/ContinentBuilder.h index 3dccced09c3..075265f2627 100644 --- a/src/tools/mesh_extractor/ContinentBuilder.h +++ b/src/tools/mesh_extractor/ContinentBuilder.h @@ -17,15 +17,9 @@ #ifndef CONT_BUILDER_H #define CONT_BUILDER_H - #include <string> #include "WDT.h" #include "Define.h" -#include "TileBuilder.h" - -#include <ace/Task.h> -#include <ace/Activation_Queue.h> -#include <ace/Method_Request.h> class ContinentBuilder { @@ -36,7 +30,7 @@ public: {} void Build(); - void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax) const; + void getTileBounds(uint32 tileX, uint32 tileY, float* verts, int vertCount, float* bmin, float* bmax); void CalculateTileBounds(); float bmin[3]; float bmax[3]; @@ -51,60 +45,4 @@ private: int tileYMax; }; -class TileBuildRequest : public ACE_Method_Request -{ -public: - TileBuildRequest(ContinentBuilder* builder, std::string& continent, uint32 x, uint32 y, uint32 mapId, dtNavMeshParams& params) : _mapId(mapId), _builder(builder), _continent(continent), X(x), Y(y), _params(params) { } - - virtual int call(); - -private: - uint32 _mapId; - ContinentBuilder* _builder; - std::string& _continent; - uint32 X; - uint32 Y; - dtNavMeshParams& _params; -}; - -class BuilderThreadPool -{ -public: - BuilderThreadPool() : _queue(new ACE_Activation_Queue()) {} - ~BuilderThreadPool() { _queue->queue()->close(); delete _queue; } - - void Enqueue(TileBuildRequest* request) - { - _queue->enqueue(request); - } - - ACE_Activation_Queue* Queue() { return _queue; } - -private: - ACE_Activation_Queue* _queue; -}; - -class BuilderThread : public ACE_Task_Base -{ -private: - ContinentBuilder* _builder; - ACE_Activation_Queue* _queue; -public: - BuilderThread(ContinentBuilder* builder, ACE_Activation_Queue* queue) : _builder(builder), _queue(queue) { activate(); } - - int svc() - { - /// @ Set a timeout for dequeue attempts (only used when the queue is empty) as it will never get populated after thread starts - ACE_Time_Value timeout(5); - ACE_Method_Request* request = NULL; - while ((request = _queue->dequeue(&timeout)) != NULL) - { - request->call(); - delete request; - request = NULL; - } - return 0; - } -}; - #endif diff --git a/src/tools/mesh_extractor/DBC.cpp b/src/tools/mesh_extractor/DBC.cpp index 49c136efc80..e38b9560533 100644 --- a/src/tools/mesh_extractor/DBC.cpp +++ b/src/tools/mesh_extractor/DBC.cpp @@ -19,15 +19,19 @@ #include "DBC.h" #include "Define.h" -DBC::DBC(Stream* stream) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true) +DBC::DBC( FILE* stream ) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true) { - delete[] stream->Read(4); // Read the magic "WDBC" - - RecordCount = stream->Read<int>(); + char magic[5]; + uint32 count = 0; + count += fread(&magic, sizeof(char), 4, stream); + magic[4] = '\0'; + count += fread(&RecordCount, sizeof(uint32), 1, stream); Records.reserve(RecordCount); - Fields = stream->Read<int>(); - RecordSize = stream->Read<int>(); - StringBlockSize = stream->Read<uint32>(); + count += fread(&Fields, sizeof(uint32), 1, stream); + count += fread(&RecordSize, sizeof(uint32), 1, stream); + count += fread(&StringBlockSize, sizeof(uint32), 1, stream); + if (count != 8) + printf("DBC::DBC: Failed to read some data expected 8, read %u\n", count); for (int i = 0; i < RecordCount; i++) { @@ -41,21 +45,21 @@ DBC::DBC(Stream* stream) : StringBlock(NULL), StringBlockSize(0), IsFaulty(true) IsFaulty = true; break; } - rec->Values.push_back(stream->Read<uint32>()); + uint32 tmp; + if (fread(&tmp, sizeof(uint32), 1, stream) != 1) + printf("DBC::DBC: Failed to read some data expected 1, read 0\n"); + rec->Values.push_back(tmp); size += 4; } } - StringBlock = (uint8*)stream->Read(StringBlockSize); -} -DBC::~DBC() -{ - delete[] StringBlock; - for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr) - delete *itr; + StringBlock = new uint8[StringBlockSize]; + count = fread(StringBlock, sizeof(uint8), StringBlockSize, stream); + if (count != StringBlockSize) + printf("DBC::DBC: Failed to read some data expected %u, read %u\n", StringBlockSize, count); } -std::string DBC::GetStringByOffset( int offset ) const +std::string DBC::GetStringByOffset( int offset ) { int len = 0; for (uint32 i = offset; i < StringBlockSize; i++) @@ -70,14 +74,14 @@ std::string DBC::GetStringByOffset( int offset ) const strcpy(d, (const char*)(StringBlock + offset)); d[len] = '\0'; std::string val = std::string(d); - delete[] d; + delete [] d; return val; } -Record const* DBC::GetRecordById( int id ) const +Record* DBC::GetRecordById( int id ) { // we assume Id is index 0 - for (std::vector<Record*>::const_iterator itr = Records.begin(); itr != Records.end(); ++itr) + for (std::vector<Record*>::iterator itr = Records.begin(); itr != Records.end(); ++itr) if ((*itr)->Values[0] == id) return *itr; return NULL; diff --git a/src/tools/mesh_extractor/DBC.h b/src/tools/mesh_extractor/DBC.h index 179c63ffcf2..d0951e36737 100644 --- a/src/tools/mesh_extractor/DBC.h +++ b/src/tools/mesh_extractor/DBC.h @@ -20,19 +20,17 @@ #include <vector> #include <string> #include "Define.h" -#include "Stream.h" class Record; class DBC { public: - DBC(Stream* stream); - ~DBC(); + DBC(FILE* stream); - std::string GetStringByOffset(int offset) const; + std::string GetStringByOffset(int offset); - Record const* GetRecordById(int id) const; + Record* GetRecordById(int id); std::string Name; std::vector<Record*> Records; @@ -52,18 +50,18 @@ public: DBC* Source; std::vector<int> Values; - int operator[](int index) const + int operator[](int index) { return Values[index]; } template <typename T> - T GetValue(int index) const + T GetValue(int index) { return *(T*)(&Values[index]); } - const std::string GetString(int index) const + std::string GetString(int index) { return Source->GetStringByOffset(Values[index]); } diff --git a/src/tools/mesh_extractor/DoodadHandler.cpp b/src/tools/mesh_extractor/DoodadHandler.cpp index 7e84eaa6044..d56ba4c3bdf 100644 --- a/src/tools/mesh_extractor/DoodadHandler.cpp +++ b/src/tools/mesh_extractor/DoodadHandler.cpp @@ -34,18 +34,20 @@ DoodadHandler::DoodadHandler( ADT* adt ) : ReadDoodadPaths(mmid, mmdx); } -void DoodadHandler::ProcessInternal(MapChunk* mcnk) +void DoodadHandler::ProcessInternal( MapChunk* mcnk ) { if (!IsSane()) return; uint32 refCount = mcnk->Header.DoodadRefs; - Stream* stream = mcnk->Source->GetStream(); - stream->Seek(mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET); - + FILE* stream = mcnk->Source->GetStream(); + fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET); for (uint32 i = 0; i < refCount; i++) { - int32 index = stream->Read<int32>(); + int32 index; + int32 count; + if ((count = fread(&index, sizeof(int32), 1, stream)) != 1) + printf("DoodadHandler::ProcessInternal: Failed to read some data expected 1, read %d\n", count); if (index < 0 || uint32(index) >= _definitions->size()) continue; DoodadDefinition doodad = (*_definitions)[index]; @@ -56,7 +58,12 @@ void DoodadHandler::ProcessInternal(MapChunk* mcnk) continue; std::string path = (*_paths)[doodad.MmidIndex]; - Model const* model = Cache->ModelCache.Get(path); + Model* model = Cache->ModelCache.Get(path); + if (!model) + { + model = new Model(path); + Cache->ModelCache.Insert(path, model); + } if (!model->IsCollidable) continue; @@ -66,7 +73,7 @@ void DoodadHandler::ProcessInternal(MapChunk* mcnk) InsertModelGeometry(doodad, model); } // Restore the stream position - stream->Seek(mcnk->Source->Offset, SEEK_SET); + fseek(stream, mcnk->Source->Offset, SEEK_SET); } void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk ) @@ -74,7 +81,7 @@ void DoodadHandler::ReadDoodadDefinitions( Chunk* chunk ) int32 count = chunk->Length / 36; _definitions = new std::vector<DoodadDefinition>; _definitions->reserve(count); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); for (int i = 0; i < count; i++) { DoodadDefinition def; @@ -90,24 +97,25 @@ void DoodadHandler::ReadDoodadPaths( Chunk* id, Chunk* data ) _paths->reserve(paths); for (int i = 0; i < paths; i++) { - Stream* idStream = id->GetStream(); - idStream->Seek(i * 4, SEEK_CUR); - uint32 offset = idStream->Read<uint32>(); - - Stream* dataStream = data->GetStream(); - dataStream->Seek(offset + data->Offset, SEEK_SET); - _paths->push_back(dataStream->ReadString()); + FILE* idStream = id->GetStream(); + fseek(idStream, i * 4, SEEK_CUR); + uint32 offset; + if (fread(&offset, sizeof(uint32), 1, idStream) != 1) + printf("DoodadHandler::ReadDoodadPaths: Failed to read some data expected 1, read 0\n"); + FILE* dataStream = data->GetStream(); + fseek(dataStream, offset + data->Offset, SEEK_SET); + _paths->push_back(Utils::ReadString(dataStream)); } } -void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model const* model) +void DoodadHandler::InsertModelGeometry(const DoodadDefinition& def, Model* model) { uint32 vertOffset = Vertices.size(); - for (std::vector<Vector3>::const_iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr) + for (std::vector<Vector3>::iterator itr = model->Vertices.begin(); itr != model->Vertices.end(); ++itr) Vertices.push_back(Utils::TransformDoodadVertex(def, *itr)); // Vertices have to be converted based on the information from the DoodadDefinition struct - for (std::vector<Triangle<uint16> >::const_iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr) + for (std::vector<Triangle<uint16> >::iterator itr = model->Triangles.begin(); itr != model->Triangles.end(); ++itr) Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_DOODAD, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset)); } diff --git a/src/tools/mesh_extractor/DoodadHandler.h b/src/tools/mesh_extractor/DoodadHandler.h index 00bb3edb7b0..3e179f63539 100644 --- a/src/tools/mesh_extractor/DoodadHandler.h +++ b/src/tools/mesh_extractor/DoodadHandler.h @@ -21,7 +21,6 @@ #include "Utils.h" #include "Chunk.h" #include "Model.h" -#include "Stream.h" #include <set> #include <vector> @@ -40,14 +39,18 @@ public: return Vector3(vec.z, vec.x, vec.y); } - void Read(Stream* stream) + void Read(FILE* stream) { - MmidIndex = stream->Read<uint32>(); - UniqueId = stream->Read<uint32>(); - Position = Vector3::Read(stream); + int count = 0; + + count += fread(&MmidIndex, sizeof(uint32), 1, stream); + count += fread(&UniqueId, sizeof(uint32), 1, stream); + Position = (Vector3::Read(stream)); Rotation = Vector3::Read(stream); - DecimalScale = stream->Read<uint16>(); - Flags = stream->Read<uint16>(); + count += fread(&DecimalScale, sizeof(uint16), 1, stream); + count += fread(&Flags, sizeof(uint16), 1, stream); + if (count != 4) + printf("DoodadDefinition::Read: Failed to read some data expected 4, read %d\n", count); } }; @@ -59,7 +62,7 @@ public: std::vector<Vector3> Vertices; std::vector<Triangle<uint32> > Triangles; - bool IsSane() const { return _definitions && _paths; } + bool IsSane() { return _definitions && _paths; } protected: @@ -68,7 +71,7 @@ protected: private: void ReadDoodadDefinitions(Chunk* chunk); void ReadDoodadPaths(Chunk* id, Chunk* data); - void InsertModelGeometry(const DoodadDefinition& def, Model const* model); + void InsertModelGeometry(const DoodadDefinition& def, Model* model); std::set<uint32> _drawn; std::vector<DoodadDefinition>* _definitions; std::vector<std::string>* _paths; diff --git a/src/tools/mesh_extractor/Geometry.cpp b/src/tools/mesh_extractor/Geometry.cpp index d95c07bc89b..e81dd8a7660 100644 --- a/src/tools/mesh_extractor/Geometry.cpp +++ b/src/tools/mesh_extractor/Geometry.cpp @@ -20,7 +20,6 @@ #include "ADT.h" #include "WorldModelHandler.h" #include "DoodadHandler.h" -#include "LiquidHandler.h" #include <limits.h> Geometry::Geometry() : Transform(false) @@ -35,7 +34,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max ) max = new float[3]; for (int i = 0; i < 3; ++i) { - max[i] = -FLT_MAX; + max[i] = std::numeric_limits<float>::lowest(); min[i] = std::numeric_limits<float>::max(); } @@ -61,7 +60,7 @@ void Geometry::CalculateBoundingBox( float*& min, float*& max ) void Geometry::CalculateMinMaxHeight( float& min, float& max ) { min = std::numeric_limits<float>::max(); - max = -FLT_MAX; + max = std::numeric_limits<float>::lowest(); for (std::vector<Vector3>::iterator itr = Vertices.begin(); itr != Vertices.end(); ++itr) { @@ -92,12 +91,12 @@ void Geometry::AddData( std::vector<Vector3>& verts, std::vector<Triangle<uint32 Triangles.push_back(Triangle<uint32>(itr->Type, itr->V0 + vertOffset, itr->V1 + vertOffset, itr->V2 + vertOffset)); } -void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas ) const +void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas ) { verts = new float[Vertices.size() * 3]; for (uint32 i = 0; i < Vertices.size(); ++i) { - const Vector3& vert = Vertices[i]; + Vector3& vert = Vertices[i]; verts[(i * 3) + 0] = vert.x; verts[(i * 3) + 1] = vert.y; verts[(i * 3) + 2] = vert.z; @@ -106,7 +105,7 @@ void Geometry::GetRawData( float*& verts, int*& tris, uint8*& areas ) const tris = new int[Triangles.size() * 3]; for (uint32 i = 0; i < Triangles.size(); ++i) { - const Triangle<uint32>& tri = Triangles[i]; + Triangle<uint32>& tri = Triangles[i]; tris[(i * 3) + 0] = (int)tri.V0; tris[(i * 3) + 1] = (int)tri.V1; tris[(i * 3) + 2] = (int)tri.V2; @@ -143,8 +142,5 @@ void Geometry::AddAdt( ADT* adt ) if (!adt->_WorldModelHandler->Triangles.empty()) AddData(adt->_WorldModelHandler->Vertices, adt->_WorldModelHandler->Triangles); - - if (!adt->_LiquidHandler->Triangles.empty()) - AddData(adt->_LiquidHandler->Vertices, adt->_LiquidHandler->Triangles); } diff --git a/src/tools/mesh_extractor/Geometry.h b/src/tools/mesh_extractor/Geometry.h index d7a664068c6..d54cdbde5dd 100644 --- a/src/tools/mesh_extractor/Geometry.h +++ b/src/tools/mesh_extractor/Geometry.h @@ -31,7 +31,7 @@ public: void CalculateMinMaxHeight(float& min, float& max); void AddData(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris); void AddAdt(ADT* adt); - void GetRawData(float*& verts, int*& tris, uint8*& areas) const; + void GetRawData(float*& verts, int*& tris, uint8*& areas); std::vector<Vector3> Vertices; std::vector<Triangle<uint32> > Triangles; diff --git a/src/tools/mesh_extractor/LiquidHandler.cpp b/src/tools/mesh_extractor/LiquidHandler.cpp index 177b94924d0..0a76dbfb54c 100644 --- a/src/tools/mesh_extractor/LiquidHandler.cpp +++ b/src/tools/mesh_extractor/LiquidHandler.cpp @@ -17,20 +17,10 @@ #include "LiquidHandler.h" #include "Utils.h" -#include "DBC.h" -#include "MPQManager.h" LiquidHandler::LiquidHandler( ADT* adt ) : Source(adt) { HandleNewLiquid(); - HandleOldLiquid(); -} - -LiquidHandler::~LiquidHandler() -{ - for (std::vector<MCNKLiquidData*>::iterator itr = MCNKData.begin(); itr != MCNKData.end(); ++itr) - delete *itr; - MCNKData.clear(); } void LiquidHandler::HandleNewLiquid() @@ -42,7 +32,7 @@ void LiquidHandler::HandleNewLiquid() Vertices.reserve(1000); Triangles.reserve(1000); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); H2OHeader header[256]; MCNKData.reserve(256); for (int i = 0; i < 256; i++) @@ -54,44 +44,40 @@ void LiquidHandler::HandleNewLiquid() if (h.LayerCount == 0) { // Need to fill in missing data with dummies. - MCNKData.push_back(new MCNKLiquidData(NULL, H2ORenderMask())); + MCNKData.push_back(MCNKLiquidData(NULL, H2ORenderMask())); continue; } - stream->Seek(chunk->Offset + h.OffsetInformation, SEEK_SET); + fseek(stream, chunk->Offset + h.OffsetInformation, SEEK_SET); H2OInformation information = H2OInformation::Read(stream); - // Load the LiquidTypes DBC - DBC const* liquidTypes = MPQHandler->GetDBC("LiquidTypes"); - Record const* liquid = liquidTypes->GetRecordById(information.LiquidType); - ASSERT(liquid); - - // This pointer will be passed to the MCNKLiquidData constructor, from that point on, it is the job of MCNKLiquidData's destructor to release it. float** heights = new float*[9]; for (int j = 0; j < 9; ++j) { heights[j] = new float[9]; memset(heights[j], 0, sizeof(float) * 9); } - + H2ORenderMask renderMask; - if (liquid->GetValue<uint32>(3) != 1) // Read the liquid type and skip Ocean, Slow Ocean and Fast Ocean + if (information.LiquidType != 2) { - stream->Seek(chunk->Offset + h.OffsetRender, SEEK_SET); + fseek(stream, chunk->Offset + h.OffsetRender, SEEK_SET); renderMask = H2ORenderMask::Read(stream); if ((Utils::IsAllZero(renderMask.Mask, 8) || (information.Width == 8 && information.Height == 8)) && information.OffsetMask2) { - stream->Seek(chunk->Offset + information.OffsetMask2, SEEK_SET); + fseek(stream, chunk->Offset + information.OffsetMask2, SEEK_SET); uint32 size = ceil(information.Width * information.Height / 8.0f); - uint8* altMask = (uint8*)stream->Read(size); - for (uint32 mi = 0; mi < size; mi++) - renderMask.Mask[mi + information.OffsetY] |= altMask[mi]; + uint8* altMask = new uint8[size]; + if (fread(altMask, sizeof(uint8), size, stream) == size) + for (uint32 mi = 0; mi < size; mi++) + renderMask.Mask[mi + information.OffsetY] |= altMask[mi]; delete[] altMask; } - stream->Seek(chunk->Offset + information.OffsetHeightmap, SEEK_SET); + fseek(stream, chunk->Offset + information.OffsetHeightmap, SEEK_SET); for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++) for (int x = information.OffsetX; x < (information.OffsetX + information.Width); x++) - heights[x][y] = stream->Read<float>(); + if (fread(&heights[x][y], sizeof(float), 1, stream) != 1) + return; } else { @@ -104,7 +90,7 @@ void LiquidHandler::HandleNewLiquid() heights[x][y] = information.HeightLevel1; } - MCNKData.push_back(new MCNKLiquidData(heights, renderMask)); + MCNKData.push_back(MCNKLiquidData(heights, renderMask)); for (int y = information.OffsetY; y < (information.OffsetY + information.Height); y++) { @@ -124,37 +110,10 @@ void LiquidHandler::HandleNewLiquid() Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y, location.z)); Vertices.push_back(Vector3(location.x, location.y - Constants::UnitSize, location.z)); Vertices.push_back(Vector3(location.x - Constants::UnitSize, location.y - Constants::UnitSize, location.z)); - - // Define the liquid type - Constants::TriangleType type = Constants::TRIANGLE_TYPE_UNKNOWN; - switch (liquid->GetValue<uint32>(3)) - { - case 0: // Water - case 1: // Ocean - type = Constants::TRIANGLE_TYPE_WATER; - break; - case 2: // Magma - type = Constants::TRIANGLE_TYPE_MAGMA; - break; - case 3: // Slime - type = Constants::TRIANGLE_TYPE_SLIME; - break; - } - Triangles.push_back(Triangle<uint32>(type, vertOffset, vertOffset+2, vertOffset + 1)); - Triangles.push_back(Triangle<uint32>(type, vertOffset + 2, vertOffset + 3, vertOffset + 1)); + Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset, vertOffset+2, vertOffset + 1)); + Triangles.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WATER, vertOffset + 2, vertOffset + 3, vertOffset + 1)); } } } } - -void LiquidHandler::HandleOldLiquid() -{ - for (uint32 i = 0; i < 256; ++i) - { - MapChunk* mapChunk = Source->MapChunks[i]; - if (!mapChunk->Header.OffsetMCLQ || mapChunk->Header.SizeMCLQ <= 8) - continue; - printf("Found old liquid"); - } -} diff --git a/src/tools/mesh_extractor/LiquidHandler.h b/src/tools/mesh_extractor/LiquidHandler.h index 7001e849097..424dbde7e63 100644 --- a/src/tools/mesh_extractor/LiquidHandler.h +++ b/src/tools/mesh_extractor/LiquidHandler.h @@ -27,14 +27,12 @@ class LiquidHandler { public: LiquidHandler(ADT* adt); - ~LiquidHandler(); ADT* Source; std::vector<Vector3> Vertices; std::vector<Triangle<uint32> > Triangles; - std::vector<MCNKLiquidData*> MCNKData; + std::vector<MCNKLiquidData> MCNKData; private: void HandleNewLiquid(); - void HandleOldLiquid(); }; #endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/MPQ.cpp b/src/tools/mesh_extractor/MPQ.cpp index 5551b0a9d47..b75a5bbdd85 100644 --- a/src/tools/mesh_extractor/MPQ.cpp +++ b/src/tools/mesh_extractor/MPQ.cpp @@ -17,7 +17,6 @@ #include "MPQ.h" #include "MPQManager.h" -#include "Stream.h" #include <deque> #include <cstdio> @@ -126,8 +125,15 @@ void MPQFile::close() eof = true; } -Stream* MPQFile::GetFileStream() +FILE* MPQFile::GetFileStream() { - Stream* stream = new Stream(buffer, size); - return stream; + FILE* file = tmpfile(); + if (!file) + { + printf("Could not create temporary file. Please run as Administrator or root\n"); + exit(1); + } + fwrite(buffer, sizeof(char), size, file); + fseek(file, 0, SEEK_SET); + return file; } diff --git a/src/tools/mesh_extractor/MPQ.h b/src/tools/mesh_extractor/MPQ.h index 68c678df616..7eb048480b9 100644 --- a/src/tools/mesh_extractor/MPQ.h +++ b/src/tools/mesh_extractor/MPQ.h @@ -20,7 +20,6 @@ #include "libmpq/mpq.h" #include "Define.h" -#include "Stream.h" #include <string> #include <ctype.h> #include <vector> @@ -31,7 +30,7 @@ class MPQArchive { public: - mpq_archive_s* mpq_a; + mpq_archive_s *mpq_a; std::vector<std::string> Files; @@ -71,8 +70,8 @@ class MPQFile { //MPQHANDLE handle; bool eof; - char* buffer; - libmpq__off_t pointer, size; + char *buffer; + libmpq__off_t pointer,size; // disable copying MPQFile(const MPQFile& /*f*/) {} @@ -82,18 +81,18 @@ public: MPQFile(const char* filename); // filenames are not case sensitive ~MPQFile() { close(); } size_t Read(void* dest, size_t bytes); - Stream* GetFileStream(); - size_t getSize() const { return size; } - size_t getPos() const { return pointer; } + FILE* GetFileStream(); + size_t getSize() { return size; } + size_t getPos() { return pointer; } char* getBuffer() { return buffer; } char* getPointer() { return buffer + pointer; } - bool isEof() const { return eof; } + bool isEof() { return eof; } void seek(int offset); void seekRelative(int offset); void close(); }; -inline void flipcc(char* fcc) +inline void flipcc(char *fcc) { char t; t=fcc[0]; diff --git a/src/tools/mesh_extractor/MPQManager.cpp b/src/tools/mesh_extractor/MPQManager.cpp index 563b31d724e..5f6e4a331ac 100644 --- a/src/tools/mesh_extractor/MPQManager.cpp +++ b/src/tools/mesh_extractor/MPQManager.cpp @@ -19,7 +19,6 @@ #include "MPQ.h" #include "DBC.h" #include "Utils.h" -#include "Stream.h" #include <ace/Guard_T.h> char const* MPQManager::Files[] = { @@ -32,12 +31,6 @@ char const* MPQManager::Files[] = { "patch-3.MPQ" }; -char const* MPQManager::LocalePatchFiles[] = { - "Data/%s/patch-%s.MPQ", - "Data/%s/patch-%s-2.MPQ", - "Data/%s/patch-%s-3.MPQ" -}; - char const* MPQManager::Languages[] = { "enGB", "enUS", "deDE", "esES", "frFR", "koKR", "zhCN", "zhTW", "enCN", "enTW", "esMX", "ruRU" }; void MPQManager::Initialize() @@ -55,7 +48,9 @@ void MPQManager::Initialize() void MPQManager::InitializeDBC() { BaseLocale = -1; + std::string fileName; uint32 size = sizeof(Languages) / sizeof(char*); + MPQArchive* _baseLocale = NULL; for (uint32 i = 0; i < size; ++i) { std::string _fileName = "Data/" + std::string(Languages[i]) + "/locale-" + std::string(Languages[i]) + ".MPQ"; @@ -63,34 +58,20 @@ void MPQManager::InitializeDBC() if (file) { if (BaseLocale == -1) - BaseLocale = i; - - // Load the base locale file - MPQArchive* arch = new MPQArchive(_fileName.c_str()); - LocaleFiles[i].push_front(arch); - - Archives.push_front(arch); // For lookup in GetFile - - // Load the locale patches - for (uint32 j = 0; j < sizeof(LocalePatchFiles) / sizeof(char*); ++j) { - char patchName[100]; - sprintf(patchName, LocalePatchFiles[j], Languages[i], Languages[i]); - FILE* patch = fopen(patchName, "rb"); - if (file) - { - MPQArchive* archP = new MPQArchive(patchName); - LocaleFiles[i].push_front(archP); - Archives.push_front(archP); // For lookup in GetFile - fclose(patch); - } + BaseLocale = i; + _baseLocale = new MPQArchive(_fileName.c_str()); + fileName = _fileName; + LocaleFiles[i] = _baseLocale; } + else + LocaleFiles[i] = new MPQArchive(_fileName.c_str()); AvailableLocales.insert(i); printf("Detected locale: %s\n", Languages[i]); } } - + Archives.push_front(_baseLocale); if (BaseLocale == -1) { printf("No locale data detected. Please make sure that the executable is in the same folder as your WoW installation.\n"); @@ -100,7 +81,7 @@ void MPQManager::InitializeDBC() printf("Using default locale: %s\n", Languages[BaseLocale]); } -Stream* MPQManager::GetFile(const std::string& path ) +FILE* MPQManager::GetFile(const std::string& path ) { ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL); MPQFile file(path.c_str()); @@ -109,54 +90,13 @@ Stream* MPQManager::GetFile(const std::string& path ) return file.GetFileStream(); } -DBC const* MPQManager::GetDBC(const std::string& name ) +DBC* MPQManager::GetDBC(const std::string& name ) { - std::map<std::string, DBC*>::const_iterator itr = LoadedDBCs.find(name); - if (itr != LoadedDBCs.end()) - return itr->second; - std::string path = "DBFilesClient\\" + name + ".dbc"; - DBC* dbc = new DBC(GetFile(path)); - - LoadedDBCs[name] = dbc; - - return dbc; + return new DBC(GetFile(path)); } -Stream* MPQManager::GetFileFromLocale( const std::string& path, uint32 locale ) -{ - ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL); - std::deque<MPQArchive*> files = LocaleFiles[locale]; - Stream* ret = NULL; - for (std::deque<MPQArchive*>::iterator itr = files.begin(); itr != files.end(); ++itr) - { - mpq_archive* mpq_a = (*itr)->mpq_a; - - uint32_t filenum; - if(libmpq__file_number(mpq_a, path.c_str(), &filenum)) - continue; - libmpq__off_t transferred; - libmpq__off_t size = 0; - libmpq__file_unpacked_size(mpq_a, filenum, &size); - - // HACK: in patch.mpq some files don't want to open and give 1 for filesize - if (size <= 1) - continue; - - char* buffer = new char[size]; - - //libmpq_file_getdata - libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred); - - ret = new Stream(buffer, size); - - delete[] buffer; - break; - } - return ret; -} - -Stream* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file ) +FILE* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file ) { ACE_GUARD_RETURN(ACE_Thread_Mutex, g, mutex, NULL); mpq_archive* mpq_a = file->mpq_a; @@ -179,7 +119,14 @@ Stream* MPQManager::GetFileFrom(const std::string& path, MPQArchive* file ) libmpq__file_read(mpq_a, filenum, (unsigned char*)buffer, size, &transferred); // Pack the return into a FILE stream - Stream* ret = new Stream((char*)buffer, size); + FILE* ret = tmpfile(); + if (!ret) + { + printf("Could not create temporary file. Please run as Administrator or root\n"); + exit(1); + } + fwrite(buffer, sizeof(uint8), size, ret); + fseek(ret, 0, SEEK_SET); delete[] buffer; return ret; } diff --git a/src/tools/mesh_extractor/MPQManager.h b/src/tools/mesh_extractor/MPQManager.h index 43aba352dd3..588052bb844 100644 --- a/src/tools/mesh_extractor/MPQManager.h +++ b/src/tools/mesh_extractor/MPQManager.h @@ -19,7 +19,6 @@ #define MPQ_MANAGER_H #include "MPQ.h" -#include "Stream.h" #include <ace/Synch.h> #include <set> #include <map> @@ -32,26 +31,22 @@ public: ~MPQManager() {} void Initialize(); - Stream* GetFile(const std::string& path); - Stream* GetFileFrom(const std::string& path, MPQArchive* file); - Stream* GetFileFromLocale(const std::string& path, uint32 locale); - - DBC const* GetDBC(const std::string& name); + FILE* GetFile(const std::string& path); + FILE* GetFileFrom(const std::string& path, MPQArchive* file); + DBC* GetDBC(const std::string& name); std::vector<std::string> GetAllFiles(std::string extension); std::deque<MPQArchive*> Archives; int32 BaseLocale; std::set<uint32> AvailableLocales; - std::map<uint32, std::deque<MPQArchive*> > LocaleFiles; + std::map<uint32, MPQArchive*> LocaleFiles; static char const* Files[]; - static char const* LocalePatchFiles[]; static char const* Languages[]; protected: void InitializeDBC(); private: ACE_Thread_Mutex mutex; - std::map<std::string, DBC*> LoadedDBCs; }; extern MPQManager* MPQHandler; diff --git a/src/tools/mesh_extractor/MapChunk.cpp b/src/tools/mesh_extractor/MapChunk.cpp index 3a9738c92b1..76280dcc973 100644 --- a/src/tools/mesh_extractor/MapChunk.cpp +++ b/src/tools/mesh_extractor/MapChunk.cpp @@ -21,9 +21,9 @@ MapChunk::MapChunk( ADT* _adt, Chunk* chunk ) : Adt(_adt), Source(chunk) { - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); Header.Read(stream); - stream->Seek(chunk->Offset, SEEK_SET); + fseek(stream, chunk->Offset, SEEK_SET); Index = Header.IndexX + Header.IndexY * 16; GenerateVertices(stream); } @@ -47,12 +47,12 @@ void MapChunk::GenerateTriangles() Constants::TriangleType triangleType = Constants::TRIANGLE_TYPE_TERRAIN; if (Adt->_LiquidHandler && !Adt->_LiquidHandler->MCNKData.empty()) { - MCNKLiquidData* data = Adt->_LiquidHandler->MCNKData[Index]; + MCNKLiquidData& data = Adt->_LiquidHandler->MCNKData[Index]; float maxHeight = std::max( std::max( std::max(std::max(Vertices[topLeft].z, Vertices[topRight].z), Vertices[bottomLeft].z), Vertices[bottomRight].z), Vertices[center].z); - if (data->IsWater(x, y, maxHeight)) + if (data.IsWater(x, y, maxHeight)) triangleType = Constants::TRIANGLE_TYPE_WATER; } @@ -64,9 +64,9 @@ void MapChunk::GenerateTriangles() } } -void MapChunk::GenerateVertices(Stream* stream) +void MapChunk::GenerateVertices( FILE* stream ) { - stream->Seek(Header.OffsetMCVT, SEEK_CUR); + fseek(stream, Header.OffsetMCVT, SEEK_CUR); Vertices.reserve(125); for (int j = 0; j < 17; j++) @@ -74,7 +74,9 @@ void MapChunk::GenerateVertices(Stream* stream) int values = j % 2 ? 8 : 9; for (int i = 0; i < values; i++) { - float tmp = stream->Read<float>(); + float tmp; + if (fread(&tmp, sizeof(float), 1, stream) != 1) + printf("MapChunk::GenerateVertices: Failed to read some data expected 1, read 0\n"); Vector3 vert(Header.Position.x - (j * (Constants::UnitSize * 0.5f)), Header.Position.y - (i * Constants::UnitSize), Header.Position.z + tmp); if (values == 8) vert.y -= Constants::UnitSize * 0.5f; @@ -82,7 +84,7 @@ void MapChunk::GenerateVertices(Stream* stream) } } // Restore stream position. - stream->Seek(Source->Offset, SEEK_SET); + fseek(stream, Source->Offset, SEEK_SET); } bool MapChunk::HasHole( uint32 map, int x, int y ) diff --git a/src/tools/mesh_extractor/MapChunk.h b/src/tools/mesh_extractor/MapChunk.h index a32a6ce20a7..97adc790e94 100644 --- a/src/tools/mesh_extractor/MapChunk.h +++ b/src/tools/mesh_extractor/MapChunk.h @@ -29,7 +29,7 @@ public: MapChunk(ADT* _adt, Chunk* chunk); void GenerateTriangles(); - void GenerateVertices(Stream* stream); + void GenerateVertices(FILE* stream); static bool HasHole(uint32 map, int x, int y); ADT* Adt; Chunk* Source; diff --git a/src/tools/mesh_extractor/MeshExtractor.cpp b/src/tools/mesh_extractor/MeshExtractor.cpp index 00121509a8a..df1393f7e6b 100644 --- a/src/tools/mesh_extractor/MeshExtractor.cpp +++ b/src/tools/mesh_extractor/MeshExtractor.cpp @@ -34,41 +34,16 @@ MPQManager* MPQHandler; CacheClass* Cache; -bool IgnoreMap(uint32 id) -{ - switch (id) - { - case 13: // test.wdt - case 25: // ScottTest.wdt - case 29: // Test.wdt - case 42: // Colin.wdt - case 169: // EmeraldDream.wdt (unused, and very large) - case 451: // development.wdt - case 573: // ExteriorTest.wdt - case 597: // CraigTest.wdt - case 605: // development_nonweighted.wdt - case 606: // QA_DVD.wdt - return true; - default: - break; - } - - return false; -} - void ExtractMMaps(std::set<uint32>& mapIds, uint32 threads) { - std::string basePath = "mmaps/"; - Utils::CreateDir(basePath); - - DBC const* dbc = MPQHandler->GetDBC("Map"); - printf("Map.dbc contains " SIZEFMTD " rows.\n", dbc->Records.size()); - for (std::vector<Record*>::const_iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr) + DBC* dbc = MPQHandler->GetDBC("Map"); + printf("Map.dbc contains %u rows.\n", dbc->Records.size()); + for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr) { uint32 mapId = (*itr)->Values[0]; - // Skip this map if a list of specific maps was provided and this one is not contained in it, or if the map is in the ignore list. - if ((!mapIds.empty() && mapIds.find(mapId) == mapIds.end()) || IgnoreMap(mapId)) + // Skip this map if a list of specific maps was provided and this one is not contained in it. + if (!mapIds.empty() && mapIds.find(mapId) == mapIds.end()) { if (Constants::Debug) printf("Map %u will not be built.\n", mapId); @@ -100,12 +75,9 @@ void ExtractDBCs() // Populate list of DBC files // We get the DBC names by going over the (guaranteed to exist) default locale files // Then we look in other locale files in case that they are available. - for (std::map<uint32, std::deque<MPQArchive*> >::iterator itr = MPQHandler->LocaleFiles.begin(); itr != MPQHandler->LocaleFiles.end(); ++itr) - for (std::deque<MPQArchive*>::iterator itr2 = itr->second.begin(); itr2 != itr->second.end(); ++itr2) - for (std::vector<std::string>::iterator itr3 = (*itr2)->Files.begin(); itr3 != (*itr2)->Files.end(); ++itr3) - if (itr3->rfind(".dbc") == itr3->length() - extLen) // Check if the extension is ".dbc" - if (DBCFiles.find(*itr3) == DBCFiles.end()) - DBCFiles.insert(*itr3); + for (std::vector<std::string>::iterator itr = MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.begin(); itr != MPQHandler->LocaleFiles[MPQHandler->BaseLocale]->Files.end(); ++itr) + if (itr->rfind(".dbc") == itr->length() - extLen) // Check if the extension is ".dbc" + DBCFiles.insert(*itr); const size_t folderLen = strlen("DBFilesClient\\"); // Iterate over all available locales @@ -121,10 +93,10 @@ void ExtractDBCs() std::string component = "component.wow-" + std::string(MPQManager::Languages[*itr]) + ".txt"; // Extract the component file - Utils::SaveToDisk(MPQHandler->GetFileFromLocale(component, *itr), path + component); + Utils::SaveToDisk(MPQHandler->GetFileFrom(component, MPQHandler->LocaleFiles[*itr]), path + component); // Extract the DBC files for the given locale for (std::set<std::string>::iterator itr2 = DBCFiles.begin(); itr2 != DBCFiles.end(); ++itr2) - Utils::SaveToDisk(MPQHandler->GetFileFromLocale(*itr2, *itr), path + (itr2->c_str() + folderLen)); + Utils::SaveToDisk(MPQHandler->GetFileFrom(*itr2, MPQHandler->LocaleFiles[*itr]), path + (itr2->c_str() + folderLen)); } printf("DBC extraction finished!\n"); } @@ -146,8 +118,8 @@ void ExtractGameobjectModels() return; } - DBC const* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo"); - for (std::vector<Record*>::const_iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr) + DBC* dbc = MPQHandler->GetDBC("GameObjectDisplayInfo"); + for (std::vector<Record*>::iterator itr = dbc->Records.begin(); itr != dbc->Records.end(); ++itr) { std::string path = (*itr)->GetString(1); std::string fileName = Utils::GetPlainName(path.c_str()); @@ -253,9 +225,8 @@ void ExtractGameobjectModels() fwrite(&model.Header.WmoId, sizeof(uint32), 1, output); const char grp[] = { 'G' , 'R' , 'P', ' ' }; - for (std::vector<WorldModelGroup*>::iterator groupItr = model.Groups.begin(); groupItr != model.Groups.end(); ++groupItr) + for (std::vector<WorldModelGroup>::iterator itr2 = model.Groups.begin(); itr2 != model.Groups.end(); ++itr2) { - WorldModelGroup* itr2 = *groupItr; const WMOGroupHeader& header = itr2->Header; fwrite(&header.Flags, sizeof(uint32), 1, output); fwrite(&header.WmoId, sizeof(uint32), 1, output); @@ -392,6 +363,7 @@ void LoadTile(dtNavMesh*& navMesh, const char* tile) int main(int argc, char* argv[]) { + _setmaxstdio(2048); uint32 threads = 4, extractFlags = 0; std::set<uint32> mapIds; @@ -423,8 +395,13 @@ int main(int argc, char* argv[]) if (extractFlags & Constants::EXTRACT_FLAG_TEST) { +<<<<<<< .mine float start[] = { -45.4745407f, -29.5000954f, -21.4456501f }; float end[] = { -107.686218f, -32.3544769f, -30.3459435f }; +======= + float start[] = { 16226.200195f, 16257.000000f, 13.202200f }; + float end[] = { 16245.725586f, 16382.465820f, 47.384956f }; +>>>>>>> .theirs // float m_spos[3]; @@ -453,7 +430,7 @@ int main(int argc, char* argv[]) dtPolyRef m_startRef; dtPolyRef m_endRef; - FILE* mmap = fopen("mmaps/631.mmap", "rb"); + FILE* mmap = fopen("mmaps/001.mmap", "rb"); dtNavMeshParams params; int count = fread(¶ms, sizeof(dtNavMeshParams), 1, mmap); fclose(mmap); @@ -472,7 +449,7 @@ int main(int argc, char* argv[]) for (int j = 0; j <= 32; ++j) { char buff[100]; - sprintf(buff, "mmaps/631%02i%02i.mmtile", i, j); + sprintf(buff, "mmaps/001%02i%02i.mmtile", i, j); LoadTile(navMesh, buff); } } @@ -490,6 +467,7 @@ int main(int argc, char* argv[]) return 0; } +<<<<<<< .mine dtStatus status; status = navMeshQuery->initSlicedFindPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter); while (status != DT_SUCCESS) @@ -500,12 +478,46 @@ int main(int argc, char* argv[]) int resultHopCount = 0; float* straightPath = new float[2048 * 3]; unsigned char* pathFlags = new unsigned char[2048]; +======= + int hops; + + + + + + + + + +>>>>>>> .theirs dtPolyRef* hopBuffer = new dtPolyRef[8192]; +<<<<<<< .mine navMeshQuery->finalizeSlicedFindPath(pathRefs, &pcount, 200); + + + + + + +======= + 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); +>>>>>>> .theirs std::vector<Vector3> FinalPath; +<<<<<<< .mine for (int i = 0; i < pcount; ++i) +======= + FinalPath.reserve(resultHopCount); + for (uint32 i = 0; i < resultHopCount; ++i) +>>>>>>> .theirs { navMeshQuery->findStraightPath(m_spos, m_epos, &pathRefs[i], 1, straightPath, pathFlags, @@ -514,14 +526,6 @@ int main(int argc, char* argv[]) FinalPath.push_back(finalV); printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z); } - /* - FinalPath.reserve(resultHopCount); - for (int i = 0; i < resultHopCount; ++i) - { - Vector3 finalV = Utils::ToWoWCoords(Vector3(straightPath[i * 3 + 0], straightPath[i * 3 + 1], straightPath[i * 3 + 2])); - FinalPath.push_back(finalV); - printf("Point %f %f %f\n", finalV.x, finalV.y, finalV.z); - }*/ } return 0; diff --git a/src/tools/mesh_extractor/Model.cpp b/src/tools/mesh_extractor/Model.cpp index 6e735ec7440..48c60d9d644 100644 --- a/src/tools/mesh_extractor/Model.cpp +++ b/src/tools/mesh_extractor/Model.cpp @@ -19,15 +19,15 @@ #include "MPQManager.h" #include "Utils.h" -Model::Model(std::string path) : IsCollidable(false), IsBad(false) +Model::Model( std::string path ) : IsCollidable(false), IsBad(false) { - _Stream = MPQHandler->GetFile(Utils::FixModelPath(path)); - if (!_Stream) + Stream = MPQHandler->GetFile(Utils::FixModelPath(path)); + if (!Stream) { IsBad = true; return; } - Header.Read(_Stream); + Header.Read(Stream); if (Header.OffsetBoundingNormals > 0 && Header.OffsetBoundingVertices > 0 && Header.OffsetBoundingTriangles > 0 && Header.BoundingRadius > 0.0f) { @@ -40,17 +40,17 @@ Model::Model(std::string path) : IsCollidable(false), IsBad(false) Model::~Model() { - if (_Stream) - delete _Stream; + if (Stream) + fclose(Stream); } void Model::ReadVertices() { - _Stream->Seek(Header.OffsetBoundingVertices, SEEK_SET); + fseek(Stream, Header.OffsetBoundingVertices, SEEK_SET); Vertices.reserve(Header.CountBoundingVertices); for (uint32 i = 0; i < Header.CountBoundingVertices; ++i) { - Vertices.push_back(Vector3::Read(_Stream)); + Vertices.push_back(Vector3::Read(Stream)); if (Constants::ToWoWCoords) Vertices[i] = Utils::ToWoWCoords(Vertices[i]); } @@ -58,24 +58,27 @@ void Model::ReadVertices() void Model::ReadBoundingTriangles() { - _Stream->Seek(Header.OffsetBoundingTriangles, SEEK_SET); + fseek(Stream, Header.OffsetBoundingTriangles, SEEK_SET); Triangles.reserve(Header.CountBoundingTriangles / 3); for (uint32 i = 0; i < Header.CountBoundingTriangles / 3; i++) { Triangle<uint16> tri; tri.Type = Constants::TRIANGLE_TYPE_DOODAD; - tri.V0 = _Stream->Read<uint16>(); - tri.V1 = _Stream->Read<uint16>(); - tri.V2 = _Stream->Read<uint16>(); + int count = 0; + count += fread(&tri.V0, sizeof(uint16), 1, Stream); + count += fread(&tri.V1, sizeof(uint16), 1, Stream); + count += fread(&tri.V2, sizeof(uint16), 1, Stream); + if (count != 3) + printf("Model::ReadBoundingTriangles: Error reading data, expected 3, read %d\n", count); Triangles.push_back(tri); } } void Model::ReadBoundingNormals() { - _Stream->Seek(Header.OffsetBoundingNormals, SEEK_SET); + fseek(Stream, Header.OffsetBoundingNormals, SEEK_SET); Normals.reserve(Header.CountBoundingNormals); for (uint32 i = 0; i < Header.CountBoundingNormals; i++) - Normals.push_back(Vector3::Read(_Stream)); + Normals.push_back(Vector3::Read(Stream)); } diff --git a/src/tools/mesh_extractor/Model.h b/src/tools/mesh_extractor/Model.h index 1169421cdf1..8f43b2963ea 100644 --- a/src/tools/mesh_extractor/Model.h +++ b/src/tools/mesh_extractor/Model.h @@ -19,7 +19,6 @@ #define MODEL_H #include <vector> #include "Utils.h" -#include "Stream.h" class Model { @@ -35,7 +34,7 @@ public: std::vector<Vector3> Normals; std::vector<Triangle<uint16> > Triangles; bool IsCollidable; - Stream* _Stream; + FILE* Stream; bool IsBad; }; #endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/ObjectDataHandler.h b/src/tools/mesh_extractor/ObjectDataHandler.h index 423d8704a00..dc57301563a 100644 --- a/src/tools/mesh_extractor/ObjectDataHandler.h +++ b/src/tools/mesh_extractor/ObjectDataHandler.h @@ -24,7 +24,6 @@ class ObjectDataHandler { public: ObjectDataHandler(ADT* _adt) : Source(_adt) {} - virtual ~ObjectDataHandler() {} void ProcessMapChunk(MapChunk* chunk); virtual void ProcessInternal(MapChunk* data) = 0; diff --git a/src/tools/mesh_extractor/Stream.cpp b/src/tools/mesh_extractor/Stream.cpp deleted file mode 100644 index f775d97d114..00000000000 --- a/src/tools/mesh_extractor/Stream.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "Stream.h" -#include <iostream> - -Stream::Stream(char* buffer, uint32 size) : _size(size), _position(0) -{ - _buffer = new char[size]; - memcpy(_buffer, buffer, size); // Initialize the buffer -} - -Stream::~Stream() -{ - delete[] _buffer; -} - -char* Stream::Read(uint32 size) -{ - char* buff = new char[size]; - memcpy(buff, &_buffer[_position], size); - _position += size; - return buff; -} - -void Stream::Seek(uint32 position, uint32 type) -{ - switch (type) - { - case SEEK_SET: - _position = position; - break; - case SEEK_CUR: - _position += position; - break; - } -} - -std::string Stream::ReadString() -{ - std::string str; - while (true) - { - char b = Read<char>(); - if (b == 0) - break; - str.push_back(b); - } - return str; -}
\ No newline at end of file diff --git a/src/tools/mesh_extractor/Stream.h b/src/tools/mesh_extractor/Stream.h deleted file mode 100644 index 647ff9d5357..00000000000 --- a/src/tools/mesh_extractor/Stream.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef STREAM_H -#define STREAM_H - -#include "Define.h" -#include <iostream> - -class Stream -{ -public: - Stream(char* buffer, uint32 size); - ~Stream(); - - template<typename T> - T Read() - { - T ret = *((T*)(&_buffer[_position])); - _position += sizeof(T); - return ret; - } - - template<typename T> - void Read(T* dest, uint32 size) - { - memcpy(dest, &_buffer[_position], size); - _position += size; - } - - template<typename T> - void Skip() - { - _position += sizeof(T); - } - - char* Read(uint32 size); - std::string ReadString(); - - void Reset() - { - _position = 0; - } - - void Seek(uint32 position, uint32 type); - - uint32 GetSize() const - { - return _size; - } - - uint32 GetPos() const - { - return _position; - } - -private: - char* _buffer; - uint32 _size; - uint32 _position; -}; -#endif
\ No newline at end of file diff --git a/src/tools/mesh_extractor/TileBuilder.cpp b/src/tools/mesh_extractor/TileBuilder.cpp index 0ec35c5a04f..a9774abe6ce 100644 --- a/src/tools/mesh_extractor/TileBuilder.cpp +++ b/src/tools/mesh_extractor/TileBuilder.cpp @@ -43,8 +43,8 @@ TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, Config.detailSampleDist = 3.0f; Config.detailSampleMaxError = 1.25f; Config.walkableClimb = 1.0f / Config.ch; - Config.walkableHeight = 2.1; - Config.walkableRadius = 0.6f; + Config.walkableHeight = 2.1 / Config.ch; + Config.walkableRadius = 0.6f / Config.cs; Config.maxEdgeLen = Config.walkableRadius * 8; Config.borderSize = Config.walkableRadius + 8; Config.tileSize = 1800; @@ -59,19 +59,19 @@ TileBuilder::TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, InstanceConfig.mergeRegionArea = 100; InstanceConfig.walkableSlopeAngle = 50.0f; InstanceConfig.detailSampleDist = 3.0f; - InstanceConfig.detailSampleMaxError = 1.25f; + InstanceConfig.detailSampleMaxError = 1.5f; InstanceConfig.walkableClimb = 1.0f / InstanceConfig.ch; - InstanceConfig.walkableHeight = 2.1f; - InstanceConfig.walkableRadius = 0.6f; + InstanceConfig.walkableHeight = 2.1f / InstanceConfig.ch; + InstanceConfig.walkableRadius = 0.6f / InstanceConfig.cs; InstanceConfig.maxEdgeLen = 8 * InstanceConfig.walkableRadius; InstanceConfig.maxVertsPerPoly = 6; - InstanceConfig.maxSimplificationError = 1.3f; + InstanceConfig.maxSimplificationError = 1.25f; InstanceConfig.borderSize = 0; Context = new rcContext; } -void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ ) const +void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshParams& /*navMeshParams*/ ) { bmin = new float[3]; bmax = new float[3]; @@ -81,7 +81,7 @@ void TileBuilder::CalculateTileBounds( float*& bmin, float*& bmax, dtNavMeshPara bmax[2] = Constants::Origin[2] /*navMeshParams.orig[2]*/ + (Constants::TileSize * (Y + 1)); } -void TileBuilder::AddGeometry(WorldModelRoot const* root, const WorldModelDefinition& def) +void TileBuilder::AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def) { _Geometry = new Geometry(); _Geometry->Transform = true; @@ -91,7 +91,7 @@ void TileBuilder::AddGeometry(WorldModelRoot const* root, const WorldModelDefini OutputDebugVertices(); } -uint8* TileBuilder::BuildInstance( dtNavMeshParams& /*navMeshParams*/ ) +uint8* TileBuilder::BuildInstance( dtNavMeshParams& navMeshParams ) { float* bmin = NULL, *bmax = NULL; @@ -183,11 +183,11 @@ uint8* TileBuilder::BuildInstance( dtNavMeshParams& /*navMeshParams*/ ) rcFreeHeightField(hf); rcFreeCompactHeightfield(chf); rcFreeContourSet(contours); - delete[] vertices; - delete[] triangles; - delete[] areas; - delete[] bmin; - delete[] bmax; + delete vertices; + delete triangles; + delete areas; + delete bmin; + delete bmax; if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount) { @@ -226,7 +226,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams) adt->Read(); _Geometry->AddAdt(adt); delete adt; - + if (_Geometry->Vertices.empty() && _Geometry->Triangles.empty()) return NULL; @@ -246,7 +246,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams) ADT* _adt = new ADT(Utils::GetAdtPath(World, tx, ty), tx, ty); // If this condition is met, it means that this WDT does not contain the ADT - if (!_adt->Data->_Stream) + if (!_adt->Data->Stream) { delete _adt; continue; @@ -352,11 +352,12 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams) rcFreeHeightField(hf); rcFreeCompactHeightfield(chf); rcFreeContourSet(contours); - delete[] vertices; - delete[] triangles; - delete[] areas; - delete[] bmin; - delete[] bmax; + + delete vertices; + delete triangles; + delete areas; + delete bmin; + delete bmax; if (!params.polyCount || !params.polys || Constants::TilesPerMap * Constants::TilesPerMap == params.polyCount) { @@ -387,7 +388,7 @@ uint8* TileBuilder::BuildTiled(dtNavMeshParams& navMeshParams) return NULL; } -void TileBuilder::OutputDebugVertices() const +void TileBuilder::OutputDebugVertices() { if (Constants::Debug) { diff --git a/src/tools/mesh_extractor/TileBuilder.h b/src/tools/mesh_extractor/TileBuilder.h index ba8b9539649..b88966190b0 100644 --- a/src/tools/mesh_extractor/TileBuilder.h +++ b/src/tools/mesh_extractor/TileBuilder.h @@ -32,11 +32,11 @@ public: TileBuilder(ContinentBuilder* _cBuilder, std::string world, int x, int y, uint32 mapId); ~TileBuilder(); - void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams) const; + void CalculateTileBounds(float*& bmin, float*& bmax, dtNavMeshParams& navMeshParams); uint8* BuildTiled(dtNavMeshParams& navMeshParams); uint8* BuildInstance(dtNavMeshParams& navMeshParams); - void AddGeometry(WorldModelRoot const* root, const WorldModelDefinition& def); - void OutputDebugVertices() const; + void AddGeometry(WorldModelRoot* root, const WorldModelDefinition& def); + void OutputDebugVertices(); std::string World; int X; int Y; diff --git a/src/tools/mesh_extractor/Utils.cpp b/src/tools/mesh_extractor/Utils.cpp index 42df1107bc0..704acf967ee 100644 --- a/src/tools/mesh_extractor/Utils.cpp +++ b/src/tools/mesh_extractor/Utils.cpp @@ -18,7 +18,6 @@ #include "Utils.h" #include "WorldModelHandler.h" #include "Constants.h" -#include "Stream.h" #include <cstring> #include "G3D/Matrix4.h" #include "G3D/Quat.h" @@ -54,9 +53,40 @@ void Utils::CreateDir( const std::string& Path ) #endif } -void Utils::Reverse(std::string& str) +void Utils::Reverse(char word[]) { - std::reverse(str.begin(), str.end()); + int len = strlen(word); + for (int i = 0;i < len / 2; i++) + { + word[i] ^= word[len-i-1]; + word[len-i-1] ^= word[i]; + word[i] ^= word[len-i-1]; + } +} + +std::string Utils::ReadString( FILE* file ) +{ + std::string ret; + while (true) + { + char b; + if (fread(&b, sizeof(char), 1, file) != 1 || b == 0) + break; + ret.push_back(b); + } + return ret; +} + +uint32 Utils::Size( FILE* file ) +{ + // store the old position + uint32 offset = ftell(file); + // Get file size + fseek(file, 0, SEEK_END); + uint32 size = ftell(file); + // reset back to the old position + fseek(file, offset, SEEK_SET); + return size; } Vector3 Utils::ToRecast(const Vector3& val ) @@ -74,7 +104,7 @@ std::string Utils::FixModelPath(const std::string& path ) return Utils::GetPathBase(path) + ".M2"; } -Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3 vec, bool translate) +Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate) { // Sources of information: /// http://www.pxr.dk/wowdev/wiki/index.php?title=ADT/v18&oldid=3715 @@ -92,7 +122,7 @@ Vector3 Utils::TransformDoodadVertex(const IDefinition& def, Vector3 vec, bool t return ret; } -Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& /*root*/, const Vector3& vec, bool translate) +Vector3 Utils::TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate ) { G3D::Quat quat = G3D::Quat(-inst.QuatY, inst.QuatZ, -inst.QuatX, inst.QuatW); @@ -123,9 +153,12 @@ std::string Utils::GetPathBase(const std::string& path ) return path; } -Vector3 Vector3::Read(Stream* file) +Vector3 Vector3::Read( FILE* file ) { - return file->Read<Vector3>(); + Vector3 ret; + if (fread(&ret, sizeof(Vector3), 1, file) != 1) + printf("Vector3::Read: Failed to read some data expected 1, read 0\n"); + return ret; } Vector3 Utils::GetLiquidVert(const IDefinition& def, Vector3 basePosition, float height, int x, int y, bool translate) @@ -151,36 +184,41 @@ std::string Utils::Replace( std::string str, const std::string& oldStr, const st return str; } -void Utils::SaveToDisk(Stream* stream, const std::string& path) +void Utils::SaveToDisk( FILE* stream, const std::string& path ) { FILE* disk = fopen(path.c_str(), "wb"); if (!disk) { printf("SaveToDisk: Could not save file %s to disk, please verify that you have write permissions on that directory\n", path.c_str()); - delete stream; + fclose(stream); return; } - uint32 size = stream->GetSize(); - stream->Reset(); // Reset the stream just in case - + uint32 size = Utils::Size(stream); + uint8* data = new uint8[size]; // Read the data to an array - char* data = stream->Read(size); - + size_t read = fread(data, size, 1, stream); + if (read != 1) + { + printf("SaveToDisk: Error reading from Stream while trying to save file %s to disk.\n", path.c_str()); + fclose(disk); + fclose(stream); + return; + } + // And write it in the file size_t wrote = fwrite(data, size, 1, disk); if (wrote != 1) { printf("SaveToDisk: Error writing to the file while trying to save %s to disk.\n", path.c_str()); - delete[] data; - delete stream; + fclose(stream); fclose(disk); return; } // Close the filestream fclose(disk); - delete stream; + fclose(stream); // Free the used memory delete[] data; @@ -201,193 +239,249 @@ std::string Utils::GetExtension( std::string path ) return extension; } -void MapChunkHeader::Read(Stream* stream) -{ - Flags = stream->Read<uint32>(); - IndexX = stream->Read<uint32>(); - IndexY = stream->Read<uint32>(); - Layers = stream->Read<uint32>(); - DoodadRefs = stream->Read<uint32>(); - OffsetMCVT = stream->Read<uint32>(); - OffsetMCNR = stream->Read<uint32>(); - OffsetMCLY = stream->Read<uint32>(); - OffsetMCRF = stream->Read<uint32>(); - OffsetMCAL = stream->Read<uint32>(); - SizeMCAL = stream->Read<uint32>(); - OffsetMCSH = stream->Read<uint32>(); - SizeMCSH = stream->Read<uint32>(); - AreaId = stream->Read<uint32>(); - MapObjectRefs = stream->Read<uint32>(); - Holes = stream->Read<uint32>(); - stream->Read(LowQualityTextureMap, sizeof(uint32) * 4); - PredTex = stream->Read<uint32>(); - NumberEffectDoodad = stream->Read<uint32>(); - OffsetMCSE = stream->Read<uint32>(); - SoundEmitters = stream->Read<uint32>(); - OffsetMCLQ = stream->Read<uint32>(); - SizeMCLQ = stream->Read<uint32>(); +void MapChunkHeader::Read(FILE* stream) +{ + int count = 0; + + count += fread(&Flags, sizeof(uint32), 1, stream); + count += fread(&IndexX, sizeof(uint32), 1, stream); + count += fread(&IndexY, sizeof(uint32), 1, stream); + count += fread(&Layers, sizeof(uint32), 1, stream); + count += fread(&DoodadRefs, sizeof(uint32), 1, stream); + count += fread(&OffsetMCVT, sizeof(uint32), 1, stream); + count += fread(&OffsetMCNR, sizeof(uint32), 1, stream); + count += fread(&OffsetMCLY, sizeof(uint32), 1, stream); + count += fread(&OffsetMCRF, sizeof(uint32), 1, stream); + count += fread(&OffsetMCAL, sizeof(uint32), 1, stream); + count += fread(&SizeMCAL, sizeof(uint32), 1, stream); + count += fread(&OffsetMCSH, sizeof(uint32), 1, stream); + count += fread(&SizeMCSH, sizeof(uint32), 1, stream); + count += fread(&AreaId, sizeof(uint32), 1, stream); + count += fread(&MapObjectRefs, sizeof(uint32), 1, stream); + count += fread(&Holes, sizeof(uint32), 1, stream); + LowQualityTextureMap = new uint32[4]; + count += fread(LowQualityTextureMap, sizeof(uint32), 4, stream); + count += fread(&PredTex, sizeof(uint32), 1, stream); + count += fread(&NumberEffectDoodad, sizeof(uint32), 1, stream); + count += fread(&OffsetMCSE, sizeof(uint32), 1, stream); + count += fread(&SoundEmitters, sizeof(uint32), 1, stream); + count += fread(&OffsetMCLQ, sizeof(uint32), 1, stream); + count += fread(&SizeMCLQ, sizeof(uint32), 1, stream); Position = Vector3::Read(stream); - OffsetMCCV = stream->Read<uint32>(); + count += fread(&OffsetMCCV, sizeof(uint32), 1, stream); + + if (count != 27) + printf("MapChunkHeader::Read: Failed to read some data expected 27, read %d\n", count); } -void MHDR::Read(Stream* stream) +void MHDR::Read(FILE* stream) { - Flags = stream->Read<uint32>(); - OffsetMCIN = stream->Read<uint32>(); - OffsetMTEX = stream->Read<uint32>(); - OffsetMMDX = stream->Read<uint32>(); - OffsetMMID = stream->Read<uint32>(); - OffsetMWMO = stream->Read<uint32>(); - OffsetMWID = stream->Read<uint32>(); - OffsetMDDF = stream->Read<uint32>(); - OffsetMODF = stream->Read<uint32>(); - OffsetMFBO = stream->Read<uint32>(); - OffsetMH2O = stream->Read<uint32>(); - OffsetMTFX = stream->Read<uint32>(); + int count = 0; + + count += fread(&Flags, sizeof(uint32), 1, stream); + count += fread(&OffsetMCIN, sizeof(uint32), 1, stream); + count += fread(&OffsetMTEX, sizeof(uint32), 1, stream); + count += fread(&OffsetMMDX, sizeof(uint32), 1, stream); + count += fread(&OffsetMMID, sizeof(uint32), 1, stream); + count += fread(&OffsetMWMO, sizeof(uint32), 1, stream); + count += fread(&OffsetMWID, sizeof(uint32), 1, stream); + count += fread(&OffsetMDDF, sizeof(uint32), 1, stream); + count += fread(&OffsetMODF, sizeof(uint32), 1, stream); + count += fread(&OffsetMFBO, sizeof(uint32), 1, stream); + count += fread(&OffsetMH2O, sizeof(uint32), 1, stream); + count += fread(&OffsetMTFX, sizeof(uint32), 1, stream); + + if (count != 12) + printf("MHDR::Read: Failed to read some data expected 12, read %d\n", count); } -void ModelHeader::Read(Stream* stream) +void ModelHeader::Read(FILE* stream) { - stream->Read(Magic, 4); + int count = 0; + + count += fread(&Magic, sizeof(char), 4, stream); Magic[4] = '\0'; // null-terminate it. - Version = stream->Read<uint32>(); - LengthModelName = stream->Read<uint32>(); - OffsetName = stream->Read<uint32>(); - ModelFlags = stream->Read<uint32>(); - CountGlobalSequences = stream->Read<uint32>(); - OffsetGlobalSequences = stream->Read<uint32>(); - CountAnimations = stream->Read<uint32>(); - OffsetAnimations = stream->Read<uint32>(); - CountAnimationLookup = stream->Read<uint32>(); - OffsetAnimationLookup = stream->Read<uint32>(); - CountBones = stream->Read<uint32>(); - OffsetBones = stream->Read<uint32>(); - CountKeyBoneLookup = stream->Read<uint32>(); - OffsetKeyBoneLookup = stream->Read<uint32>(); - CountVertices = stream->Read<uint32>(); - OffsetVertices = stream->Read<uint32>(); - CountViews = stream->Read<uint32>(); - CountColors = stream->Read<uint32>(); - OffsetColors = stream->Read<uint32>(); - CountTextures = stream->Read<uint32>(); - OffsetTextures = stream->Read<uint32>(); - CountTransparency = stream->Read<uint32>(); - OffsetTransparency = stream->Read<uint32>(); - CountUvAnimation = stream->Read<uint32>(); - OffsetUvAnimation = stream->Read<uint32>(); - CountTexReplace = stream->Read<uint32>(); - OffsetTexReplace = stream->Read<uint32>(); - CountRenderFlags = stream->Read<uint32>(); - OffsetRenderFlags = stream->Read<uint32>(); - CountBoneLookup = stream->Read<uint32>(); - OffsetBoneLookup = stream->Read<uint32>(); - CountTexLookup = stream->Read<uint32>(); - OffsetTexLookup = stream->Read<uint32>(); - CountTexUnits = stream->Read<uint32>(); - OffsetTexUnits = stream->Read<uint32>(); - CountTransLookup = stream->Read<uint32>(); - OffsetTransLookup = stream->Read<uint32>(); - CountUvAnimLookup = stream->Read<uint32>(); - OffsetUvAnimLookup = stream->Read<uint32>(); + count += fread(&Version, sizeof(uint32), 1, stream); + count += fread(&LengthModelName, sizeof(uint32), 1, stream); + count += fread(&OffsetName, sizeof(uint32), 1, stream); + count += fread(&ModelFlags, sizeof(uint32), 1, stream); + count += fread(&CountGlobalSequences, sizeof(uint32), 1, stream); + count += fread(&OffsetGlobalSequences, sizeof(uint32), 1, stream); + count += fread(&CountAnimations, sizeof(uint32), 1, stream); + count += fread(&OffsetAnimations, sizeof(uint32), 1, stream); + count += fread(&CountAnimationLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetAnimationLookup, sizeof(uint32), 1, stream); + count += fread(&CountBones, sizeof(uint32), 1, stream); + count += fread(&OffsetBones, sizeof(uint32), 1, stream); + count += fread(&CountKeyBoneLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetKeyBoneLookup, sizeof(uint32), 1, stream); + count += fread(&CountVertices, sizeof(uint32), 1, stream); + count += fread(&OffsetVertices, sizeof(uint32), 1, stream); + count += fread(&CountViews, sizeof(uint32), 1, stream); + count += fread(&CountColors, sizeof(uint32), 1, stream); + count += fread(&OffsetColors, sizeof(uint32), 1, stream); + count += fread(&CountTextures, sizeof(uint32), 1, stream); + count += fread(&OffsetTextures, sizeof(uint32), 1, stream); + count += fread(&CountTransparency, sizeof(uint32), 1, stream); + count += fread(&OffsetTransparency, sizeof(uint32), 1, stream); + count += fread(&CountUvAnimation, sizeof(uint32), 1, stream); + count += fread(&OffsetUvAnimation, sizeof(uint32), 1, stream); + count += fread(&CountTexReplace, sizeof(uint32), 1, stream); + count += fread(&OffsetTexReplace, sizeof(uint32), 1, stream); + count += fread(&CountRenderFlags, sizeof(uint32), 1, stream); + count += fread(&OffsetRenderFlags, sizeof(uint32), 1, stream); + count += fread(&CountBoneLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetBoneLookup, sizeof(uint32), 1, stream); + count += fread(&CountTexLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetTexLookup, sizeof(uint32), 1, stream); + count += fread(&CountTexUnits, sizeof(uint32), 1, stream); + count += fread(&OffsetTexUnits, sizeof(uint32), 1, stream); + count += fread(&CountTransLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetTransLookup, sizeof(uint32), 1, stream); + count += fread(&CountUvAnimLookup, sizeof(uint32), 1, stream); + count += fread(&OffsetUvAnimLookup, sizeof(uint32), 1, stream); VertexBox[0] = Vector3::Read(stream); VertexBox[1] = Vector3::Read(stream); - VertexRadius = stream->Read<float>(); + count += fread(&VertexRadius, sizeof(float), 1, stream); BoundingBox[0] = Vector3::Read(stream); BoundingBox[1] = Vector3::Read(stream); - BoundingRadius = stream->Read<float>(); - CountBoundingTriangles = stream->Read<uint32>(); - OffsetBoundingTriangles = stream->Read<uint32>(); - CountBoundingVertices = stream->Read<uint32>(); - OffsetBoundingVertices = stream->Read<uint32>(); - CountBoundingNormals = stream->Read<uint32>(); - OffsetBoundingNormals = stream->Read<uint32>(); -} - -void WorldModelHeader::Read(Stream* stream) -{ - CountMaterials = stream->Read<uint32>(); - CountGroups = stream->Read<uint32>(); - CountPortals = stream->Read<uint32>(); - CountLights = stream->Read<uint32>(); - CountModels = stream->Read<uint32>(); - CountDoodads = stream->Read<uint32>(); - CountSets = stream->Read<uint32>(); - AmbientColorUnk = stream->Read<uint32>(); - WmoId = stream->Read<uint32>(); - BoundingBox[0] = Vector3::Read(stream); - BoundingBox[1] = Vector3::Read(stream); - LiquidTypeRelated = stream->Read<uint32>(); + count += fread(&BoundingRadius, sizeof(float), 1, stream); + count += fread(&CountBoundingTriangles, sizeof(uint32), 1, stream); + count += fread(&OffsetBoundingTriangles, sizeof(uint32), 1, stream); + count += fread(&CountBoundingVertices, sizeof(uint32), 1, stream); + count += fread(&OffsetBoundingVertices, sizeof(uint32), 1, stream); + count += fread(&CountBoundingNormals, sizeof(uint32), 1, stream); + count += fread(&OffsetBoundingNormals, sizeof(uint32), 1, stream); + + if (count != 51) + printf("ModelHeader::Read: Failed to read some data expected 51, read %d\n", count); + } -DoodadInstance DoodadInstance::Read(Stream* stream) +WorldModelHeader WorldModelHeader::Read(FILE* stream) +{ + WorldModelHeader ret; + int count = 0; + + count += fread(&ret.CountMaterials, sizeof(uint32), 1, stream); + count += fread(&ret.CountGroups, sizeof(uint32), 1, stream); + count += fread(&ret.CountPortals, sizeof(uint32), 1, stream); + count += fread(&ret.CountLights, sizeof(uint32), 1, stream); + count += fread(&ret.CountModels, sizeof(uint32), 1, stream); + count += fread(&ret.CountDoodads, sizeof(uint32), 1, stream); + count += fread(&ret.CountSets, sizeof(uint32), 1, stream); + count += fread(&ret.AmbientColorUnk, sizeof(uint32), 1, stream); + count += fread(&ret.WmoId, sizeof(uint32), 1, stream); + ret.BoundingBox[0] = Vector3::Read(stream); + ret.BoundingBox[1] = Vector3::Read(stream); + count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream); + + if (count != 10) + printf("WorldModelHeader::Read: Failed to read some data expected 10, read %d\n", count); + + return ret; +} + +DoodadInstance DoodadInstance::Read(FILE* stream) { DoodadInstance ret; + int count = 0; - ret.FileOffset = stream->Read<uint32>(); + count += fread(&ret.FileOffset, sizeof(uint32), 1, stream); ret.Position = Vector3::Read(stream); - ret.QuatW = stream->Read<float>(); - ret.QuatX = stream->Read<float>(); - ret.QuatY = stream->Read<float>(); - ret.QuatZ = stream->Read<float>(); - ret.Scale = stream->Read<float>(); - ret.LightColor = stream->Read<uint32>(); + count += fread(&ret.QuatW, sizeof(float), 1, stream); + count += fread(&ret.QuatX, sizeof(float), 1, stream); + count += fread(&ret.QuatY, sizeof(float), 1, stream); + count += fread(&ret.QuatZ, sizeof(float), 1, stream); + count += fread(&ret.Scale, sizeof(float), 1, stream); + count += fread(&ret.LightColor, sizeof(uint32), 1, stream); + + if (count != 7) + printf("DoodadInstance::Read: Failed to read some data expected 7, read %d\n", count); + return ret; } -DoodadSet DoodadSet::Read(Stream* stream) +DoodadSet DoodadSet::Read(FILE* stream) { DoodadSet ret; - char* name = stream->Read(20); - ret.Name = std::string(name, 20); - delete[] name; - ret.FirstInstanceIndex = stream->Read<uint32>(); - ret.CountInstances = stream->Read<uint32>(); - ret.UnknownZero = stream->Read<uint32>(); - + char name[21]; + int count = 0; + + count += fread(&name, sizeof(char), 20, stream); + name[20] = '\0'; + ret.Name = name; + count += fread(&ret.FirstInstanceIndex, sizeof(uint32), 1, stream); + count += fread(&ret.CountInstances, sizeof(uint32), 1, stream); + count += fread(&ret.UnknownZero, sizeof(uint32), 1, stream); + + if (count != 23) + printf("DoodadSet::Read: Failed to read some data expected 23, read %d\n", count); + return ret; } -void LiquidHeader::Read(Stream* stream) +LiquidHeader LiquidHeader::Read(FILE* stream) { - CountXVertices = stream->Read<uint32>(); - CountYVertices = stream->Read<uint32>(); - Width = stream->Read<uint32>(); - Height = stream->Read<uint32>(); - BaseLocation = Vector3::Read(stream); - MaterialId = stream->Read<uint16>(); + LiquidHeader ret; + int count = 0; + count += fread(&ret.CountXVertices, sizeof(uint32), 1, stream); + count += fread(&ret.CountYVertices, sizeof(uint32), 1, stream); + count += fread(&ret.Width, sizeof(uint32), 1, stream); + count += fread(&ret.Height, sizeof(uint32), 1, stream); + ret.BaseLocation = Vector3::Read(stream); + count += fread(&ret.MaterialId, sizeof(uint16), 1, stream); + + if (count != 5) + printf("LiquidHeader::Read: Failed to read some data expected 5, read %d\n", count); + + return ret; } -void LiquidData::Read(Stream* stream, LiquidHeader& header) +LiquidData LiquidData::Read(FILE* stream, LiquidHeader& header) { - CountXVertices = header.CountXVertices; - Width = header.Width; - - HeightMap = new float*[header.CountXVertices]; + LiquidData ret; + ret.HeightMap = new float*[header.CountXVertices]; for (uint32 i = 0; i < header.CountXVertices; ++i) - HeightMap[i] = new float[header.CountYVertices]; + ret.HeightMap[i] = new float[header.CountYVertices]; - RenderFlags = new uint8*[header.Width]; + ret.RenderFlags = new uint8*[header.Width]; for (uint32 i = 0; i < header.Width; ++i) - RenderFlags[i] = new uint8[header.Height]; + ret.RenderFlags[i] = new uint8[header.Height]; for (uint32 y = 0; y < header.CountYVertices; y++) { for (uint32 x = 0; x < header.CountXVertices; x++) { - stream->Skip<uint32>(); - HeightMap[x][y] = stream->Read<float>(); + uint32 discard; + float tmp; + if (fread(&discard, sizeof(uint32), 1, stream) == 1 && + fread(&tmp, sizeof(float), 1, stream) == 1) + { + ret.HeightMap[x][y] = tmp; + } } } for (uint32 y = 0; y < header.Height; y++) + { for (uint32 x = 0; x < header.Width; x++) - RenderFlags[x][y] = stream->Read<uint8>(); + { + uint8 tmp = 0; + if (fread(&tmp, sizeof(uint8), 1, stream) == 1) + ret.RenderFlags[x][y] = tmp; + } + } + + return ret; } -H2ORenderMask H2ORenderMask::Read(Stream* stream) +H2ORenderMask H2ORenderMask::Read(FILE* stream) { H2ORenderMask ret; - stream->Read(ret.Mask, sizeof(uint8) * 8); + int32 count; + if ((count = fread(&ret.Mask, sizeof(uint8), 8, stream)) != 8) + printf("H2OHeader::Read: Failed to read some data expected 8, read %d\n", count); return ret; } @@ -403,42 +497,38 @@ bool MCNKLiquidData::IsWater(int x, int y, float height) return false; } -MCNKLiquidData::~MCNKLiquidData() +H2OHeader H2OHeader::Read(FILE* stream) { - if (!Heights) - return; + H2OHeader ret; + int count = 0; + count += fread(&ret.OffsetInformation, sizeof(uint32), 1, stream); + count += fread(&ret.LayerCount, sizeof(uint32), 1, stream); + count += fread(&ret.OffsetRender, sizeof(uint32), 1, stream); - for (uint32 i = 0; i < 9; ++i) - delete[] Heights[i]; - delete[] Heights; - Heights = NULL; -} + if (count != 3) + printf("H2OHeader::Read: Failed to read some data expected 3, read %d\n", count); -H2OHeader H2OHeader::Read(Stream* stream) -{ - H2OHeader ret; - - ret.OffsetInformation = stream->Read<uint32>(); - ret.LayerCount = stream->Read<uint32>(); - ret.OffsetRender = stream->Read<uint32>(); - return ret; } -H2OInformation H2OInformation::Read(Stream* stream) +H2OInformation H2OInformation::Read(FILE* stream) { H2OInformation ret; - ret.LiquidType = stream->Read<uint16>(); - ret.Flags = stream->Read<uint16>(); - ret.HeightLevel1 = stream->Read<float>(); - ret.HeightLevel2 = stream->Read<float>(); - ret.OffsetX = stream->Read<uint8>(); - ret.OffsetY = stream->Read<uint8>(); - ret.Width = stream->Read<uint8>(); - ret.Height = stream->Read<uint8>(); - ret.OffsetMask2 = stream->Read<uint32>(); - ret.OffsetHeightmap = stream->Read<uint32>(); - + int count = 0; + count += fread(&ret.LiquidType, sizeof(uint16), 1, stream); + count += fread(&ret.Flags, sizeof(uint16), 1, stream); + count += fread(&ret.HeightLevel1, sizeof(float), 1, stream); + count += fread(&ret.HeightLevel2, sizeof(float), 1, stream); + count += fread(&ret.OffsetX, sizeof(uint8), 1, stream); + count += fread(&ret.OffsetY, sizeof(uint8), 1, stream); + count += fread(&ret.Width, sizeof(uint8), 1, stream); + count += fread(&ret.Height, sizeof(uint8), 1, stream); + count += fread(&ret.OffsetMask2, sizeof(uint32), 1, stream); + count += fread(&ret.OffsetHeightmap, sizeof(uint32), 1, stream); + + if (count != 10) + printf("H2OInformation::Read: Failed to read some data expected 10, read %d\n", count); + return ret; } @@ -451,30 +541,24 @@ char* Utils::GetPlainName(const char* FileName) return (char*)FileName; } -WMOGroupHeader WMOGroupHeader::Read(Stream* stream) +WMOGroupHeader WMOGroupHeader::Read( FILE* stream ) { WMOGroupHeader ret; - ret.OffsetGroupName = stream->Read<uint32>(); - ret.OffsetDescriptiveName = stream->Read<uint32>(); - ret.Flags = stream->Read<uint32>(); + int count = 0; + count += fread(&ret.OffsetGroupName, sizeof(uint32), 1, stream); + count += fread(&ret.OffsetDescriptiveName, sizeof(uint32), 1, stream); + count += fread(&ret.Flags, sizeof(uint32), 1, stream); ret.BoundingBox[0] = Vector3::Read(stream); ret.BoundingBox[1] = Vector3::Read(stream); - ret.OffsetPortals = stream->Read<uint32>(); - ret.CountPortals = stream->Read<uint32>(); - stream->Read(ret.CountBatches, sizeof(uint16) * 4); - stream->Read(ret.Fogs, sizeof(uint8) * 4); - ret.LiquidTypeRelated = stream->Read<uint32>(); - ret.WmoId = stream->Read<uint32>(); - - return ret; -} + count += fread(&ret.OffsetPortals, sizeof(uint32), 1, stream); + count += fread(&ret.CountPortals, sizeof(uint32), 1, stream); + count += fread(&ret.CountBatches, sizeof(uint16), 4, stream); + count += fread(&ret.Fogs, sizeof(uint8), 4, stream); + count += fread(&ret.LiquidTypeRelated, sizeof(uint32), 1, stream); + count += fread(&ret.WmoId, sizeof(uint32), 1, stream); -void Utils::InitializeMmapTileHeader(MmapTileHeader& header) -{ - memset(&header, 0, sizeof(MmapTileHeader)); - header.mmapMagic = MMAP_MAGIC; - header.dtVersion = DT_NAVMESH_VERSION; - header.mmapVersion = MMAP_VERSION; - header.size = 0; - header.usesLiquids = true; + if (count != 15) + printf("WMOGroupHeader::Read: Failed to read some data expected 15, read %d\n", count); + + return ret; } diff --git a/src/tools/mesh_extractor/Utils.h b/src/tools/mesh_extractor/Utils.h index f93bc6e6be6..267a32c27cd 100644 --- a/src/tools/mesh_extractor/Utils.h +++ b/src/tools/mesh_extractor/Utils.h @@ -27,8 +27,6 @@ #include "Define.h" #include "Constants.h" -#include "Stream.h" - #include <ace/Stack_Trace.h> struct WorldModelDefinition; @@ -61,7 +59,7 @@ struct Vector3 return Vector3(x * s, y * s, z * s); } - static Vector3 Read(Stream* file); + static Vector3 Read(FILE* file); }; struct TilePos @@ -102,7 +100,7 @@ public: uint32 AreaId; uint32 MapObjectRefs; uint32 Holes; - uint32 LowQualityTextureMap[4]; + uint32* LowQualityTextureMap; uint32 PredTex; uint32 NumberEffectDoodad; uint32 OffsetMCSE; @@ -112,7 +110,7 @@ public: Vector3 Position; uint32 OffsetMCCV; - void Read(Stream* stream); + void Read(FILE* stream); }; class MHDR @@ -132,7 +130,7 @@ public: uint32 OffsetMH2O; uint32 OffsetMTFX; - void Read(Stream* stream); + void Read(FILE* stream); }; class ModelHeader @@ -189,7 +187,7 @@ public: uint32 CountBoundingNormals; uint32 OffsetBoundingNormals; - void Read(Stream* stream); + void Read(FILE* stream); }; class WorldModelHeader @@ -208,7 +206,7 @@ public: Vector3 BoundingBox[2]; uint32 LiquidTypeRelated; - void Read(Stream* stream); + static WorldModelHeader Read(FILE* stream); }; class DoodadInstance @@ -225,7 +223,7 @@ public: float Scale; uint32 LightColor; - static DoodadInstance Read(Stream* stream); + static DoodadInstance Read(FILE* stream); }; class DoodadSet @@ -237,13 +235,13 @@ public: uint32 CountInstances; uint32 UnknownZero; - static DoodadSet Read(Stream* stream); + static DoodadSet Read(FILE* stream); }; class LiquidHeader { public: - LiquidHeader() : CountXVertices(0), CountYVertices(0), Width(0), Height(0), BaseLocation(0,0,0), MaterialId(0) {} + LiquidHeader() {} uint32 CountXVertices; uint32 CountYVertices; uint32 Width; @@ -251,36 +249,22 @@ public: Vector3 BaseLocation; uint16 MaterialId; - void Read(Stream* stream); + static LiquidHeader Read(FILE* stream); }; class LiquidData { public: - LiquidData() : HeightMap(NULL), RenderFlags(NULL), CountXVertices(0), Width(0) {} - - ~LiquidData() - { - for (uint32 i = 0; i < CountXVertices; ++i) - delete[] HeightMap[i]; - delete[] HeightMap; - - for (uint32 i = 0; i < Width; ++i) - delete[] RenderFlags[i]; - delete[] RenderFlags; - } - + LiquidData() {} float** HeightMap; uint8** RenderFlags; - uint32 CountXVertices; - uint32 Width; - bool ShouldRender(int x, int y) const + bool ShouldRender(int x, int y) { return RenderFlags[x][y] != 0x0F; } - void Read(Stream* stream, LiquidHeader& header); + static LiquidData Read(FILE* stream, LiquidHeader& header); }; class H2ORenderMask @@ -294,15 +278,14 @@ public: return (Mask[y] >> x & 1) != 0; } - static H2ORenderMask Read(Stream* stream); + static H2ORenderMask Read(FILE* stream); }; class MCNKLiquidData { public: - MCNKLiquidData() : Heights(NULL) {} + MCNKLiquidData() {} MCNKLiquidData(float** heights, H2ORenderMask mask) : Heights(heights), Mask(mask) {} - ~MCNKLiquidData(); float** Heights; H2ORenderMask Mask; @@ -318,7 +301,7 @@ public: uint32 LayerCount; uint32 OffsetRender; - static H2OHeader Read(Stream* stream); + static H2OHeader Read(FILE* stream); }; class H2OInformation @@ -336,7 +319,7 @@ public: uint32 OffsetMask2; uint32 OffsetHeightmap; - static H2OInformation Read(Stream* stream); + static H2OInformation Read(FILE* stream); }; class WMOGroupHeader @@ -355,7 +338,7 @@ public: uint32 LiquidTypeRelated; uint32 WmoId; - static WMOGroupHeader Read(Stream* stream); + static WMOGroupHeader Read(FILE* stream); }; // Dummy class to act as an interface. @@ -368,7 +351,7 @@ public: }; #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 5 +#define MMAP_VERSION 3 struct MmapTileHeader { @@ -376,13 +359,18 @@ struct MmapTileHeader uint32 dtVersion; uint32 mmapVersion; uint32 size; - bool usesLiquids : 1; + bool usesLiquids; + + MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION), + mmapVersion(MMAP_VERSION), size(0), usesLiquids(true) {} }; class Utils { public: - static void Reverse(std::string& str); + static void Reverse(char word[]); + static std::string ReadString(FILE* file); + static uint32 Size(FILE* file); static Vector3 ToRecast(const Vector3& val ); static std::string GetAdtPath(const std::string& world, int x, int y); static std::string FixModelPath(const std::string& path); @@ -406,15 +394,14 @@ public: return false; return true; } - static std::string Replace(std::string str, const std::string& oldStr, const std::string& newStr); - static void CreateDir(const std::string& Path); - static void SaveToDisk(Stream* stream, const std::string& path); - static Vector3 ToWoWCoords(const Vector3& vec); - static std::string GetExtension( std::string path); + static std::string Replace( std::string str, const std::string& oldStr, const std::string& newStr ); + static void CreateDir( const std::string& Path ); + static void SaveToDisk(FILE* stream, const std::string& path); + static Vector3 ToWoWCoords(const Vector3& vec ); + static std::string GetExtension( std::string path ); static char* GetPlainName(const char* FileName); - static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3 vec, bool translate = true); - static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false); - static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, const Vector3& vec, bool translate = true); - static void InitializeMmapTileHeader(MmapTileHeader& header); + static Vector3 TransformDoodadVertex(const IDefinition& def, Vector3& vec, bool translate = true); + static Vector3 VectorTransform(const Vector3& vec, const G3D::Matrix4& matrix, bool normal = false ); + static Vector3 TransformWmoDoodad(const DoodadInstance& inst, const WorldModelDefinition& root, Vector3& vec, bool translate = true ); }; #endif diff --git a/src/tools/mesh_extractor/WDT.cpp b/src/tools/mesh_extractor/WDT.cpp index 42461f4f247..593127e0d34 100644 --- a/src/tools/mesh_extractor/WDT.cpp +++ b/src/tools/mesh_extractor/WDT.cpp @@ -20,7 +20,6 @@ #include "ChunkedData.h" #include "Utils.h" #include "WorldModelHandler.h" -#include "Cache.h" WDT::WDT(std::string file) : IsGlobalModel(false), IsValid(false), Model(NULL) { @@ -38,8 +37,8 @@ void WDT::ReadGlobalModel() IsGlobalModel = true; ModelDefinition = WorldModelDefinition::Read(defChunk->GetStream()); - ModelFile = fileChunk->GetStream()->ReadString(); - Model = Cache->WorldModelCache.Get(ModelFile); + ModelFile = Utils::ReadString(fileChunk->GetStream()); + Model = new WorldModelRoot(ModelFile); } void WDT::ReadTileTable() @@ -48,14 +47,20 @@ void WDT::ReadTileTable() if (!chunk) return; IsValid = true; - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); for (int y = 0; y < 64; ++y) { for (int x = 0; x < 64; ++x) { const uint32 hasTileFlag = 0x1; - uint32 flags = stream->Read<uint32>(); - stream->Skip<uint32>(); + uint32 flags; + uint32 discard; + int count = 0; + count += fread(&flags, sizeof(uint32), 1, stream); + count += fread(&discard, sizeof(uint32), 1, stream); + + if (count != 2) + printf("WDT::ReadTileTable: Failed to read some data expected 2, read %d\n", count); if (flags & hasTileFlag) TileTable.push_back(TilePos(x, y)); @@ -64,9 +69,9 @@ void WDT::ReadTileTable() } } -bool WDT::HasTile( int x, int y ) const +bool WDT::HasTile( int x, int y ) { - for (std::vector<TilePos>::const_iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr) + for (std::vector<TilePos>::iterator itr = TileTable.begin(); itr != TileTable.end(); ++itr) if (itr->X == x && itr->Y == y) return true; return false; diff --git a/src/tools/mesh_extractor/WDT.h b/src/tools/mesh_extractor/WDT.h index 8943471ca86..55a1a9861ff 100644 --- a/src/tools/mesh_extractor/WDT.h +++ b/src/tools/mesh_extractor/WDT.h @@ -36,8 +36,8 @@ public: bool IsValid; std::string ModelFile; WorldModelDefinition ModelDefinition; - WorldModelRoot const* Model; - bool HasTile(int x, int y) const; + WorldModelRoot* Model; + bool HasTile(int x, int y); private: void ReadGlobalModel(); void ReadTileTable(); diff --git a/src/tools/mesh_extractor/WorldModelGroup.cpp b/src/tools/mesh_extractor/WorldModelGroup.cpp index 530b78e2792..9d32a096592 100644 --- a/src/tools/mesh_extractor/WorldModelGroup.cpp +++ b/src/tools/mesh_extractor/WorldModelGroup.cpp @@ -20,37 +20,14 @@ #include "Chunk.h" #include "Utils.h" -WorldModelGroup::WorldModelGroup(std::string path, int groupIndex) : SubData(NULL), GroupIndex(groupIndex), MOBA(NULL), MOBALength(0), HasLiquidData(false), IsBad(false) +WorldModelGroup::WorldModelGroup( std::string path, int groupIndex ) : GroupIndex(groupIndex), MOBA(NULL), IsBad(false), HasLiquidData(false) { Data = new ChunkedData(path); - if (!Data->_Stream) + if (!Data->Stream) { IsBad = true; return; } - Load(path); -} - -WorldModelGroup::WorldModelGroup(Stream* stream, std::string path, int groupIndex) : SubData(NULL), GroupIndex(groupIndex), MOBA(NULL), MOBALength(0), HasLiquidData(false), IsBad(false) -{ - Data = new ChunkedData(stream, stream->GetSize()); - Load(path); -} - -WorldModelGroup::~WorldModelGroup() -{ - // Temporarily delete the underlying stream, it is the same pointer for both Data and SubData. - // @TODO: Remove this code once the ChunkedData destructor properly releases _Stream - delete Data->_Stream; - - delete Data; - delete SubData; - delete[] MOBA; - -} - -void WorldModelGroup::Load(std::string& path) -{ Chunk* mainChunk = Data->GetChunkByName("MOGP"); int32 firstSub = mainChunk->FindSubChunkOffset("MOPY"); if (firstSub == -1) @@ -58,8 +35,8 @@ void WorldModelGroup::Load(std::string& path) Name = Utils::GetPlainName(path.c_str()); - Stream* stream = mainChunk->GetStream(); - stream->Seek(firstSub, SEEK_SET); + FILE* stream = mainChunk->GetStream(); + fseek(stream, firstSub, SEEK_SET); SubData = new ChunkedData(stream, mainChunk->Length - firstSub); ReadHeader(); @@ -80,7 +57,7 @@ void WorldModelGroup::ReadNormals() uint32 normalCount = chunk->Length / 12; ASSERT(normalCount == Vertices.size() && "normalCount is different than the Vertices count"); Normals.reserve(normalCount); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); for (uint32 i = 0; i < normalCount; i++) Normals.push_back(Vector3::Read(stream)); } @@ -92,9 +69,9 @@ void WorldModelGroup::ReadLiquid() return; HasLiquidData = true; - Stream* stream = chunk->GetStream(); - LiquidDataHeader.Read(stream); - LiquidDataGeometry.Read(stream, LiquidDataHeader); + FILE* stream = chunk->GetStream(); + LiquidDataHeader = LiquidHeader::Read(stream); + LiquidDataGeometry = LiquidData::Read(stream, LiquidDataHeader); } void WorldModelGroup::ReadVertices() @@ -105,7 +82,7 @@ void WorldModelGroup::ReadVertices() uint32 verticeCount = chunk->Length / 12; Vertices.reserve(verticeCount); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); for (uint32 i = 0; i < verticeCount; i++) Vertices.push_back(Vector3::Read(stream)); } @@ -118,13 +95,19 @@ void WorldModelGroup::ReadTriangles() uint32 triangleCount = chunk->Length / 6; ASSERT(triangleCount == TriangleFlags.size() && "triangleCount != TriangleFlags.size()"); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); Triangles.reserve(triangleCount); for (uint32 i = 0; i < triangleCount; i++) { - uint16 v0 = stream->Read<uint16>(); - uint16 v1 = stream->Read<uint16>(); - uint16 v2 = stream->Read<uint16>(); + uint16 v0; + uint16 v1; + uint16 v2; + int count = 0; + count += fread(&v0, sizeof(uint16), 1, stream); + count += fread(&v1, sizeof(uint16), 1, stream); + count += fread(&v2, sizeof(uint16), 1, stream); + if (count != 3) + printf("WorldModelGroup::ReadMaterials: Error reading data, expected 3, read %d\n", count); Triangles.push_back(Triangle<uint16>(Constants::TRIANGLE_TYPE_WMO, v0, v1, v2)); } @@ -136,15 +119,20 @@ void WorldModelGroup::ReadMaterials() if (!chunk) return; - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); uint32 triangleCount = chunk->Length / 2; TriangleFlags.reserve(triangleCount); TriangleMaterials.reserve(triangleCount); for (uint32 i = 0; i < triangleCount; i++) { - TriangleFlags.push_back(stream->Read<uint8>()); + uint8 tmp; + if (fread(&tmp, sizeof(uint8), 1, stream) != 1) + printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n"); + TriangleFlags.push_back(tmp); // Read again for material. - TriangleMaterials.push_back(stream->Read<uint8>()); + if (fread(&tmp, sizeof(uint8), 1, stream) != 1) + printf("WorldModelGroup::ReadMaterials: Error reading data, expected 1, read 0\n"); + TriangleMaterials.push_back(tmp); } } @@ -154,7 +142,7 @@ void WorldModelGroup::ReadHeader() if (!chunk) return; - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); Header = WMOGroupHeader::Read(stream); } @@ -166,5 +154,7 @@ void WorldModelGroup::ReadBatches() MOBALength = chunk->Length / 2; MOBA = new uint16[MOBALength]; - chunk->GetStream()->Read(MOBA, sizeof(uint16) * MOBALength); + uint32 count = (uint32)fread(MOBA, sizeof(uint16), MOBALength, chunk->GetStream()); + if (count != MOBALength) + printf("WorldModelGroup::ReadBatches: Error reading data, expected %u, read %u\n", MOBALength, count); } diff --git a/src/tools/mesh_extractor/WorldModelGroup.h b/src/tools/mesh_extractor/WorldModelGroup.h index 54056f9d37e..cf98dc8768a 100644 --- a/src/tools/mesh_extractor/WorldModelGroup.h +++ b/src/tools/mesh_extractor/WorldModelGroup.h @@ -24,10 +24,6 @@ class WorldModelGroup { public: WorldModelGroup(std::string path, int groupIndex); - WorldModelGroup(Stream* stream, std::string path, int groupIndex); - ~WorldModelGroup(); - void Load(std::string& path); - ChunkedData* Data; ChunkedData* SubData; int GroupIndex; diff --git a/src/tools/mesh_extractor/WorldModelHandler.cpp b/src/tools/mesh_extractor/WorldModelHandler.cpp index a0de6ec1172..fa816627435 100644 --- a/src/tools/mesh_extractor/WorldModelHandler.cpp +++ b/src/tools/mesh_extractor/WorldModelHandler.cpp @@ -21,24 +21,27 @@ #include "Cache.h" #include "Model.h" #include "Define.h" -#include "Stream.h" #include "G3D/Matrix4.h" #include "G3D/Quat.h" #include <cstdio> -WorldModelDefinition WorldModelDefinition::Read(Stream* file) +WorldModelDefinition WorldModelDefinition::Read( FILE* file ) { WorldModelDefinition ret; - ret.MwidIndex = file->Read<uint32>(); - ret.UniqueId = file->Read<uint32>(); + int count = 0; + count += fread(&ret.MwidIndex, sizeof(uint32), 1, file); + count += fread(&ret.UniqueId, sizeof(uint32), 1, file); ret.Position = Vector3::Read(file); ret.Rotation = Vector3::Read(file); ret.UpperExtents = Vector3::Read(file); ret.LowerExtents = Vector3::Read(file); - ret.Flags = file->Read<uint16>(); - ret.DoodadSet = file->Read<uint16>(); - file->Read<uint32>(); // Discarded - + count += fread(&ret.Flags, sizeof(uint16), 1, file); + count += fread(&ret.DoodadSet, sizeof(uint16), 1, file); + uint32 discard; + count += fread(&discard, sizeof(uint32), 1, file); + + if (count != 5) + printf("WorldModelDefinition::Read: Error reading data, expected 5, read %d\n", count); return ret; } @@ -55,12 +58,14 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk ) return; uint32 refCount = mcnk->Header.MapObjectRefs; - Stream* stream = mcnk->Source->GetStream(); - stream->Seek(mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET); + FILE* stream = mcnk->Source->GetStream(); + fseek(stream, mcnk->Source->Offset + mcnk->Header.OffsetMCRF, SEEK_SET); // Start looping at the last Doodad Ref index for (uint32 i = mcnk->Header.DoodadRefs; i < refCount; i++) { - int32 index = stream->Read<int32>(); + int32 index; + if (fread(&index, sizeof(int32), 1, stream) != 1) + printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n"); if (index < 0 || uint32(index) >= _definitions->size()) continue; @@ -75,7 +80,12 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk ) continue; std::string path = (*_paths)[wmo.MwidIndex]; - WorldModelRoot const* model = Cache->WorldModelCache.Get(path); + WorldModelRoot* model = Cache->WorldModelCache.Get(path); + if (!model) + { + model = new WorldModelRoot(path); + Cache->WorldModelCache.Insert(path, model); + } Vertices.reserve(1000); Triangles.reserve(1000); @@ -83,16 +93,15 @@ void WorldModelHandler::ProcessInternal( MapChunk* mcnk ) InsertModelGeometry(Vertices, Triangles, wmo, model); } // Restore the stream position - stream->Seek(mcnk->Source->Offset, SEEK_SET); + fseek(stream, mcnk->Source->Offset, SEEK_SET); } -void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot const* root, bool translate ) +void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate ) { - for (std::vector<WorldModelGroup*>::const_iterator groupItr = root->Groups.begin(); groupItr != root->Groups.end(); ++groupItr) + for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group) { - WorldModelGroup const* group = *groupItr; uint32 vertOffset = verts.size(); - for (std::vector<Vector3>::const_iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2) + for (std::vector<Vector3>::iterator itr2 = group->Vertices.begin(); itr2 != group->Vertices.end(); ++itr2) { Vector3 v = Utils::TransformDoodadVertex(def, *itr2, translate); // If translate is false, then we were called directly from the TileBuilder to add data to it's _Geometry member, hence, we have to manually convert the vertices to Recast format. @@ -104,7 +113,6 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v // only include colliding tris if ((group->TriangleFlags[i] & 0x04) != 0 || group->TriangleMaterials[i] == 0xFF) continue; - Triangle<uint16> tri = group->Triangles[i]; tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, tri.V0 + vertOffset, tri.V1 + vertOffset, tri.V2 + vertOffset)); } @@ -124,33 +132,38 @@ void WorldModelHandler::InsertModelGeometry( std::vector<Vector3>& verts, std::v for (std::vector<DoodadInstance>::iterator instance = instances.begin(); instance != instances.end(); ++instance) { - Model const* model = Cache->ModelCache.Get(instance->File); + Model* model = Cache->ModelCache.Get(instance->File); + if (!model) + { + model = new Model(instance->File); + Cache->ModelCache.Insert(instance->File, model); + } if (!model->IsCollidable) continue; int vertOffset = verts.size(); - for (std::vector<Vector3>::const_iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2) + for (std::vector<Vector3>::iterator itr2 = model->Vertices.begin(); itr2 != model->Vertices.end(); ++itr2) { Vector3 v = Utils::TransformDoodadVertex(def, Utils::TransformWmoDoodad(*instance, def, *itr2, false), translate); verts.push_back(translate ? v : Utils::ToRecast(v)); } - for (std::vector<Triangle<uint16> >::const_iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2) + for (std::vector<Triangle<uint16> >::iterator itr2 = model->Triangles.begin(); itr2 != model->Triangles.end(); ++itr2) tris.push_back(Triangle<uint32>(Constants::TRIANGLE_TYPE_WMO, itr2->V0 + vertOffset, itr2->V1 + vertOffset, itr2->V2 + vertOffset)); } - for (std::vector<WorldModelGroup*>::const_iterator groupItr = root->Groups.begin(); groupItr != root->Groups.end(); ++groupItr) + for (std::vector<WorldModelGroup>::iterator group = root->Groups.begin(); group != root->Groups.end(); ++group) { - WorldModelGroup const* group = *groupItr; if (!group->HasLiquidData) continue; const LiquidHeader& liquidHeader = group->LiquidDataHeader; - const LiquidData& liquidDataGeometry = group->LiquidDataGeometry; + LiquidData& liquidDataGeometry = group->LiquidDataGeometry; for (uint32 y = 0; y < liquidHeader.Height; y++) { for (uint32 x = 0; x < liquidHeader.Width; x++) { + if (!liquidDataGeometry.ShouldRender(x, y)) continue; @@ -189,7 +202,7 @@ void WorldModelHandler::ReadDefinitions() uint32 definitionCount = chunk->Length / definitionSize; _definitions = new std::vector<WorldModelDefinition>; _definitions->reserve(definitionCount); - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); for (uint32 i = 0; i < definitionCount; i++) _definitions->push_back(WorldModelDefinition::Read(stream)); } @@ -206,13 +219,14 @@ void WorldModelHandler::ReadModelPaths() _paths->reserve(paths); for (uint32 i = 0; i < paths; i++) { - Stream* stream = mwid->GetStream(); - stream->Seek(i * 4, SEEK_CUR); - uint32 offset = stream->Read<uint32>(); - - Stream* dataStream = mwmo->GetStream(); - dataStream->Seek(offset + mwmo->Offset, SEEK_SET); - _paths->push_back(dataStream->ReadString()); + FILE* stream = mwid->GetStream(); + fseek(stream, i * 4, SEEK_CUR); + uint32 offset; + if (fread(&offset, sizeof(uint32), 1, stream) != 1) + printf("WorldModelDefinition::Read: Error reading data, expected 1, read 0\n"); + FILE* dataStream = mwmo->GetStream(); + fseek(dataStream, offset + mwmo->Offset, SEEK_SET); + _paths->push_back(Utils::ReadString(dataStream)); } } diff --git a/src/tools/mesh_extractor/WorldModelHandler.h b/src/tools/mesh_extractor/WorldModelHandler.h index ac7b7431c1e..972dda0f5d8 100644 --- a/src/tools/mesh_extractor/WorldModelHandler.h +++ b/src/tools/mesh_extractor/WorldModelHandler.h @@ -39,7 +39,7 @@ public: uint16 Flags; uint16 DoodadSet; - static WorldModelDefinition Read(Stream* file); + static WorldModelDefinition Read(FILE* file); }; class WorldModelHandler : public ObjectDataHandler @@ -50,8 +50,8 @@ public: std::vector<Vector3> Vertices; std::vector<Triangle<uint32> > Triangles; - bool IsSane() const { return _definitions && _paths; } - static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot const* root, bool translate = true); + bool IsSane() { return _definitions && _paths; } + static void InsertModelGeometry(std::vector<Vector3>& verts, std::vector<Triangle<uint32> >& tris, const WorldModelDefinition& def, WorldModelRoot* root, bool translate = true); protected: void ProcessInternal(MapChunk* data); private: diff --git a/src/tools/mesh_extractor/WorldModelRoot.cpp b/src/tools/mesh_extractor/WorldModelRoot.cpp index ffc7d7c8484..d9bc4e550b3 100644 --- a/src/tools/mesh_extractor/WorldModelRoot.cpp +++ b/src/tools/mesh_extractor/WorldModelRoot.cpp @@ -18,7 +18,6 @@ #include "WorldModelRoot.h" #include "ChunkedData.h" #include "Utils.h" -#include "MPQManager.h" WorldModelRoot::WorldModelRoot( std::string path ) { @@ -33,10 +32,6 @@ WorldModelRoot::WorldModelRoot( std::string path ) WorldModelRoot::~WorldModelRoot() { delete Data; - for (std::vector<WorldModelGroup*>::iterator group = Groups.begin(); group != Groups.end(); ++group) - delete *group; - - Groups.clear(); } void WorldModelRoot::ReadGroups() @@ -47,10 +42,9 @@ void WorldModelRoot::ReadGroups() { char name[200]; sprintf(name, "%s_%03u.wmo", pathBase.c_str(), i); - Stream* stream = MPQHandler->GetFile(name); - if (!stream) - continue; - Groups.push_back(new WorldModelGroup(stream, name, i)); + WorldModelGroup group(name, i); + if (!group.IsBad) + Groups.push_back(group); } } @@ -60,7 +54,7 @@ void WorldModelRoot::ReadDoodadSets() if (!chunk) return; - Stream* stream = chunk->GetStream(); + FILE* stream = chunk->GetStream(); ASSERT(chunk->Length / 32 == Header.CountSets && "chunk.Length / 32 == Header.CountSets"); DoodadSets.reserve(Header.CountSets); for (uint32 i = 0; i < Header.CountSets; i++) @@ -79,14 +73,14 @@ void WorldModelRoot::ReadDoodadInstances() DoodadInstances.reserve(countInstances); for (uint32 i = 0; i < countInstances; i++) { - Stream* stream = chunk->GetStream(); - stream->Seek(instanceSize * i, SEEK_CUR); + FILE* stream = chunk->GetStream(); + fseek(stream, instanceSize * i, SEEK_CUR); DoodadInstance instance = DoodadInstance::Read(stream); - Stream* nameStream = nameChunk->GetStream(); + FILE* nameStream = nameChunk->GetStream(); if (instance.FileOffset >= nameChunk->Length) continue; - nameStream->Seek(instance.FileOffset, SEEK_CUR); - instance.File = nameStream->ReadString(); + fseek(nameStream, instance.FileOffset, SEEK_CUR); + instance.File = Utils::ReadString(nameStream); DoodadInstances.push_back(instance); } } @@ -97,6 +91,6 @@ void WorldModelRoot::ReadHeader() if (!chunk) return; - Stream* stream = chunk->GetStream(); - Header.Read(stream); + FILE* stream = chunk->GetStream(); + Header = WorldModelHeader::Read(stream); } diff --git a/src/tools/mesh_extractor/WorldModelRoot.h b/src/tools/mesh_extractor/WorldModelRoot.h index 89ebb681f17..7fbc04d2b6d 100644 --- a/src/tools/mesh_extractor/WorldModelRoot.h +++ b/src/tools/mesh_extractor/WorldModelRoot.h @@ -34,7 +34,7 @@ public: WorldModelHeader Header; std::vector<DoodadInstance> DoodadInstances; std::vector<DoodadSet> DoodadSets; - std::vector<WorldModelGroup*> Groups; + std::vector<WorldModelGroup> Groups; private: void ReadGroups(); void ReadDoodadSets(); |