diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/Collision/Management/IVMapManager.h | 3 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.cpp | 20 | ||||
-rw-r--r-- | src/common/Collision/Management/VMapManager2.h | 2 | ||||
-rw-r--r-- | src/common/Collision/Maps/MapTree.cpp | 72 | ||||
-rw-r--r-- | src/common/Collision/Maps/MapTree.h | 7 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 4 | ||||
-rw-r--r-- | src/tools/mmaps_generator/PathGenerator.cpp | 2 | ||||
-rw-r--r-- | src/tools/mmaps_generator/TerrainBuilder.cpp | 4 | ||||
-rw-r--r-- | src/tools/vmap4_assembler/TileAssembler.cpp | 23 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/vmapexport.cpp | 4 |
10 files changed, 82 insertions, 59 deletions
diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index 3d760082e28..e779878b8e0 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -43,7 +43,8 @@ namespace VMAP { Success, FileNotFound, - VersionMismatch + VersionMismatch, + ReadFromFileFailed }; #define VMAP_INVALID_HEIGHT -100000.0f // for check diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp index 88494d0a0c7..ed4e5535250 100644 --- a/src/common/Collision/Management/VMapManager2.cpp +++ b/src/common/Collision/Management/VMapManager2.cpp @@ -104,14 +104,21 @@ namespace VMAP int result = VMAP_LOAD_RESULT_IGNORED; if (isMapLoadingEnabled()) { - if (loadSingleMap(mapId, basePath, x, y)) + LoadResult parentLoadResult = loadSingleMap(mapId, basePath, x, y); + if (parentLoadResult == LoadResult::Success || parentLoadResult == LoadResult::FileNotFound) { - result = VMAP_LOAD_RESULT_OK; + if (parentLoadResult == LoadResult::Success) + result = VMAP_LOAD_RESULT_OK; + // else VMAP_LOAD_RESULT_IGNORED + auto childMaps = iChildMapData.find(mapId); if (childMaps != iChildMapData.end()) for (uint32 childMapId : childMaps->second) - if (!loadSingleMap(childMapId, basePath, x, y)) + { + LoadResult childLoadResult = loadSingleMap(childMapId, basePath, x, y); + if (childLoadResult != LoadResult::Success && childLoadResult != LoadResult::FileNotFound) result = VMAP_LOAD_RESULT_ERROR; + } } else result = VMAP_LOAD_RESULT_ERROR; @@ -121,7 +128,7 @@ namespace VMAP } // load one tile (internal use only) - bool VMapManager2::loadSingleMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY) + LoadResult VMapManager2::loadSingleMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY) { auto instanceTree = iInstanceMapTrees.find(mapId); if (instanceTree == iInstanceMapTrees.end()) @@ -137,10 +144,11 @@ namespace VMAP { std::string mapFileName = getMapFileName(mapId); StaticMapTree* newTree = new StaticMapTree(mapId, basePath); - if (!newTree->InitMap(mapFileName)) + LoadResult treeInitResult = newTree->InitMap(mapFileName); + if (treeInitResult != LoadResult::Success) { delete newTree; - return false; + return treeInitResult; } instanceTree->second = newTree; } diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index 76253faded4..024c1619a2f 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -102,7 +102,7 @@ namespace VMAP void InitializeThreadUnsafe(std::unordered_map<uint32, std::vector<uint32>> const& mapData); int loadMap(char const* pBasePath, unsigned int mapId, int x, int y) override; - bool loadSingleMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY); + LoadResult loadSingleMap(uint32 mapId, const std::string& basePath, uint32 tileX, uint32 tileY); void unloadMap(unsigned int mapId, int x, int y) override; void unloadSingleMap(uint32 mapId, int x, int y); diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index 04f914fb4f1..7249a0cf1a2 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -240,6 +240,7 @@ namespace VMAP TileFileOpenResult result; result.Name = basePath + getTileFileName(mapID, tileX, tileY); result.File = fopen(result.Name.c_str(), "rb"); + result.UsedMapId = mapID; if (!result.File) { int32 parentMapId = vm->getParentMapId(mapID); @@ -247,6 +248,7 @@ namespace VMAP { result.Name = basePath + getTileFileName(parentMapId, tileX, tileY); result.File = fopen(result.Name.c_str(), "rb"); + result.UsedMapId = parentMapId; if (result.File) break; @@ -302,44 +304,47 @@ namespace VMAP //========================================================= - bool StaticMapTree::InitMap(std::string const& fname) + LoadResult StaticMapTree::InitMap(std::string const& fname) { TC_LOG_DEBUG("maps", "StaticMapTree::InitMap() : initializing StaticMapTree '%s'", fname.c_str()); - bool success = false; std::string fullname = iBasePath + fname; FILE* rf = fopen(fullname.c_str(), "rb"); if (!rf) - return false; + return LoadResult::FileNotFound; + LoadResult result = LoadResult::Success; char chunk[8]; - if (readChunk(rf, chunk, VMAP_MAGIC, 8) && + if (!readChunk(rf, chunk, VMAP_MAGIC, 8)) + result = LoadResult::VersionMismatch; + + if (result == LoadResult::Success && readChunk(rf, chunk, "NODE", 4) && iTree.readFromFile(rf)) { iNTreeValues = iTree.primCount(); iTreeValues = new ModelInstance[iNTreeValues]; - success = true; + result = LoadResult::Success; } - if (success) + if (result == LoadResult::Success) { - success = readChunk(rf, chunk, "SIDX", 4); + result = readChunk(rf, chunk, "SIDX", 4) ? LoadResult::Success : LoadResult::ReadFromFileFailed; uint32 spawnIndicesSize = 0; uint32 spawnId; - uint32 spawnIndex; - if (success && fread(&spawnIndicesSize, sizeof(uint32), 1, rf) != 1) success = false; - for (uint32 i = 0; i < spawnIndicesSize && success; ++i) + if (result == LoadResult::Success && fread(&spawnIndicesSize, sizeof(uint32), 1, rf) != 1) + result = LoadResult::ReadFromFileFailed; + for (uint32 i = 0; i < spawnIndicesSize && result == LoadResult::Success; ++i) { - if (fread(&spawnId, sizeof(uint32), 1, rf) == 1 && fread(&spawnIndex, sizeof(uint32), 1, rf) == 1) - iSpawnIndices[spawnId] = spawnIndex; + if (fread(&spawnId, sizeof(uint32), 1, rf) == 1) + iSpawnIndices[spawnId] = i; else - success = false; + result = LoadResult::ReadFromFileFailed; } } fclose(rf); - return success; + return result; } //========================================================= @@ -358,31 +363,31 @@ namespace VMAP //========================================================= - bool StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm) + LoadResult StaticMapTree::LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm) { if (!iTreeValues) { TC_LOG_ERROR("misc", "StaticMapTree::LoadMapTile() : tree has not been initialized [%u, %u]", tileX, tileY); - return false; + return LoadResult::ReadFromFileFailed; } - bool result = true; + LoadResult result = LoadResult::FileNotFound; TileFileOpenResult fileResult = OpenMapTileFile(iBasePath, iMapID, tileX, tileY, vm); if (fileResult.File) { char chunk[8]; + result = LoadResult::Success; if (!readChunk(fileResult.File, chunk, VMAP_MAGIC, 8)) - result = false; + result = LoadResult::VersionMismatch; uint32 numSpawns = 0; - if (result && fread(&numSpawns, sizeof(uint32), 1, fileResult.File) != 1) - result = false; - for (uint32 i = 0; i < numSpawns && result; ++i) + if (result == LoadResult::Success && fread(&numSpawns, sizeof(uint32), 1, fileResult.File) != 1) + result = LoadResult::ReadFromFileFailed; + for (uint32 i = 0; i < numSpawns && result == LoadResult::Success; ++i) { // read model spawns ModelSpawn spawn; - result = ModelSpawn::readFromFile(fileResult.File, spawn); - if (result) + if (ModelSpawn::readFromFile(fileResult.File, spawn)) { // acquire model instance WorldModel* model = vm->acquireModelInstance(iBasePath, spawn.name, spawn.flags); @@ -416,8 +421,19 @@ namespace VMAP #endif } } - else - result = false; + else if (int32(iMapID) == fileResult.UsedMapId) + { + // unknown parent spawn might appear in because it overlaps multiple tiles + // in case the original tile is swapped but its neighbour is now (adding this spawn) + // we want to not mark it as loading error and just skip that model + TC_LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : invalid tree element (spawn %u) referenced in tile %s by map %u", spawn.ID, fileResult.Name.c_str(), iMapID); + result = LoadResult::ReadFromFileFailed; + } + } + else + { + TC_LOG_ERROR("maps", "StaticMapTree::LoadMapTile() : cannot read model from file (spawn index %u) referenced in tile %s by map %u", i, fileResult.Name.c_str(), iMapID); + result = LoadResult::ReadFromFileFailed; } } iLoadedTiles[packTileID(tileX, tileY)] = true; @@ -465,9 +481,7 @@ namespace VMAP // update tree auto spawnIndex = iSpawnIndices.find(spawn.ID); - if (spawnIndex == iSpawnIndices.end()) - result = false; - else + if (spawnIndex != iSpawnIndices.end()) { uint32 referencedNode = spawnIndex->second; if (!iLoadedSpawns.count(referencedNode)) @@ -478,6 +492,8 @@ namespace VMAP iLoadedSpawns.erase(referencedNode); } } + else if (int32(iMapID) == fileResult.UsedMapId) // logic documented in StaticMapTree::LoadMapTile + result = false; } } fclose(fileResult.File); diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index d2012ea7a30..8b96164bd7c 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -61,8 +61,9 @@ namespace VMAP struct TileFileOpenResult { - FILE* File; std::string Name; + FILE* File; + int32 UsedMapId; }; private: @@ -84,9 +85,9 @@ namespace VMAP bool getAreaInfo(G3D::Vector3 &pos, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const; bool GetLocationInfo(const G3D::Vector3 &pos, LocationInfo &info) const; - bool InitMap(std::string const& fname); + LoadResult InitMap(std::string const& fname); void UnloadMap(VMapManager2* vm); - bool LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm); + LoadResult LoadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm); void UnloadMapTile(uint32 tileX, uint32 tileY, VMapManager2* vm); uint32 numLoadedTiles() const { return uint32(iLoadedTiles.size()); } void getModelInstances(ModelInstance* &models, uint32 &count); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index bd844ac6329..e0fb4370fea 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -190,6 +190,10 @@ bool Map::ExistVMap(uint32 mapid, int gx, int gy) TC_LOG_ERROR("maps", "VMap file '%s' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name).c_str()); TC_LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module."); return false; + case VMAP::LoadResult::ReadFromFileFailed: + TC_LOG_ERROR("maps", "VMap file '%s' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name).c_str()); + TC_LOG_ERROR("maps", "This is because VMAP files are corrupted, please re-extract the maps with the tools compiled with this module."); + return false; } } } diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp index 0873885d114..2589ae9c875 100644 --- a/src/tools/mmaps_generator/PathGenerator.cpp +++ b/src/tools/mmaps_generator/PathGenerator.cpp @@ -319,6 +319,8 @@ std::unordered_map<uint32, std::vector<uint32>> LoadMap(std::string const& local mapData.emplace(std::piecewise_construct, std::forward_as_tuple(record.GetId()), std::forward_as_tuple()); int16 parentMapId = int16(record.GetUInt16("ParentMapID")); + if (parentMapId < 0) + parentMapId = int16(record.GetUInt16("CosmeticParentMapID")); if (parentMapId != -1) mapData[parentMapId].push_back(record.GetId()); } diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index fda251e8402..a5c77fefe31 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -638,12 +638,12 @@ namespace MMAP bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData) { VMapManager2* vmapManager = static_cast<VMapManager2*>(VMapFactory::createOrGetVMapManager()); - int result = vmapManager->loadSingleMap(mapID, "vmaps", tileX, tileY); + LoadResult result = vmapManager->loadSingleMap(mapID, "vmaps", tileX, tileY); bool retval = false; do { - if (result == VMAP_LOAD_RESULT_ERROR) + if (result != LoadResult::Success) break; InstanceTreeMap instanceTrees; diff --git a/src/tools/vmap4_assembler/TileAssembler.cpp b/src/tools/vmap4_assembler/TileAssembler.cpp index a29cb3a516d..ed9406eca96 100644 --- a/src/tools/vmap4_assembler/TileAssembler.cpp +++ b/src/tools/vmap4_assembler/TileAssembler.cpp @@ -76,7 +76,7 @@ namespace VMAP printf("Calculating model bounds for map %u...\n", data.MapId); for (auto entry = data.UniqueEntries.begin(); entry != data.UniqueEntries.end(); ++entry) { - // M2 models don't have a bound set in WDT/ADT placement data, i still think they're not used for LoS at all on retail + // M2 models don't have a bound set in WDT/ADT placement data, they're not used for LoS but are needed for pathfinding if (entry->second.flags & MOD_M2) if (!calculateTransformedBound(entry->second)) continue; @@ -133,7 +133,6 @@ namespace VMAP for (uint32 i = 0; i < mapSpawnsSize; ++i) { if (success && fwrite(&mapSpawns[i]->ID, sizeof(uint32), 1, mapfile) != 1) success = false; - if (success && fwrite(&i, sizeof(uint32), 1, mapfile) != 1) success = false; } fclose(mapfile); @@ -292,7 +291,7 @@ namespace VMAP for (uint32 g = 0; g < groups; ++g) { GroupModel_Raw& raw_group = raw_model.groupsArray[g]; - groupsArray.push_back(GroupModel(raw_group.mogpflags, raw_group.GroupWMOID, raw_group.bounds )); + groupsArray.push_back(GroupModel(raw_group.mogpflags, raw_group.GroupWMOID, raw_group.bounds)); groupsArray.back().setMeshData(raw_group.vertexArray, raw_group.triangles); groupsArray.back().setLiquidData(raw_group.liquid); } @@ -353,21 +352,9 @@ namespace VMAP spawnedModelFiles.insert(model_name); AABox bounds; - bool boundEmpty = true; - for (uint32 g = 0; g < raw_model.groupsArray.size(); ++g) - { - std::vector<Vector3>& vertices = raw_model.groupsArray[g].vertexArray; - - uint32 nvectors = vertices.size(); - for (uint32 i = 0; i < nvectors; ++i) - { - Vector3& v = vertices[i]; - if (boundEmpty) - bounds = AABox(v, v), boundEmpty = false; - else - bounds.merge(v); - } - } + for (GroupModel_Raw const& groupModel : raw_model.groupsArray) + for (G3D::Vector3 const& vertice : groupModel.vertexArray) + bounds.merge(vertice); if (bounds.isEmpty()) { diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index d3407beb895..4b7239bf53e 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -502,6 +502,10 @@ int main(int argc, char ** argv) map.ParentMapID = int16(record.GetUInt16("ParentMapID")); map.Name = record.GetString("MapName"); map.Directory = record.GetString("Directory"); + + if (map.ParentMapID < 0) + map.ParentMapID = int16(record.GetUInt16("CosmeticParentMapID")); + if (map.ParentMapID >= 0) maps_that_are_parents.insert(map.ParentMapID); |