diff options
author | Shauren <shauren.trinity@gmail.com> | 2019-06-08 16:54:52 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2019-06-08 17:10:10 +0200 |
commit | 25819ea926e3ebe026f3e17de66926551e18b2e9 (patch) | |
tree | 76d6318d3be20ce8fa7b01313c50edf7c89cdab3 /src | |
parent | e7bce901da9e442c039d780fc852cccbf90f35ae (diff) |
Tools/Extractors: Use FileDataID whenever possible
Diffstat (limited to 'src')
-rw-r--r-- | src/tools/map_extractor/System.cpp | 218 | ||||
-rw-r--r-- | src/tools/map_extractor/loadlib.cpp | 27 | ||||
-rw-r--r-- | src/tools/map_extractor/loadlib/loadlib.h | 1 | ||||
-rw-r--r-- | src/tools/map_extractor/wdt.h | 42 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/adtfile.cpp | 17 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/adtfile.h | 4 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/cascfile.cpp | 31 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/cascfile.h | 3 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/gameobject_extract.cpp | 3 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/model.cpp | 8 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/vmapexport.cpp | 60 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/wdtfile.cpp | 37 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/wdtfile.h | 46 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/wmo.cpp | 24 | ||||
-rw-r--r-- | src/tools/vmap4_extractor/wmo.h | 1 |
15 files changed, 369 insertions, 153 deletions
diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 9dc017cd1da..dcbbc0547d0 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -39,33 +39,35 @@ CASC::StorageHandle CascStorage; -typedef struct +struct MapEntry { - char name[64]; - uint32 id; -} map_id; + uint32 Id = 0; + int32 WdtFileDataId = 0; + std::string Name; + std::string Directory; +}; struct LiquidMaterialEntry { - int8 LVF; + int8 LVF = 0; }; struct LiquidObjectEntry { - int16 LiquidTypeID; + int16 LiquidTypeID = 0; }; struct LiquidTypeEntry { - uint8 SoundBank; - uint8 MaterialID; + uint8 SoundBank = 0; + uint8 MaterialID = 0; }; -std::vector<map_id> map_ids; +std::vector<MapEntry> map_ids; std::unordered_map<uint32, LiquidMaterialEntry> LiquidMaterials; std::unordered_map<uint32, LiquidObjectEntry> LiquidObjects; std::unordered_map<uint32, LiquidTypeEntry> LiquidTypes; -std::set<std::string> CameraFileNames; +std::set<uint32> CameraFileDataIds; boost::filesystem::path input_path; boost::filesystem::path output_path; @@ -233,19 +235,14 @@ void ReadMapDBC() for (uint32 x = 0; x < db2.GetRecordCount(); ++x) { DB2Record record = db2.GetRecord(x); - map_ids[x].id = record.GetId(); - - const char* map_name = record.GetString("Directory"); - size_t max_map_name_length = sizeof(map_ids[x].name); - if (strlen(map_name) >= max_map_name_length) - { - printf("Fatal error: Map name too long!\n"); - exit(1); - } + if (!record) + continue; - strncpy(map_ids[x].name, map_name, max_map_name_length); - map_ids[x].name[max_map_name_length - 1] = '\0'; - idToIndex[map_ids[x].id] = x; + map_ids[x].Id = record.GetId(); + map_ids[x].WdtFileDataId = record.GetInt32("WdtFileDataID"); + map_ids[x].Name = record.GetString("MapName"); + map_ids[x].Directory = record.GetString("Directory"); + idToIndex[map_ids[x].Id] = x; } for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x) @@ -254,9 +251,11 @@ void ReadMapDBC() auto itr = idToIndex.find(copy.SourceRowId); if (itr != idToIndex.end()) { - map_id id; - id.id = copy.NewRowId; - strcpy(id.name, map_ids[itr->second].name); + MapEntry id; + id.Id = copy.NewRowId; + id.WdtFileDataId = map_ids[itr->second].WdtFileDataId; + id.Name = map_ids[itr->second].Name; + id.Directory = map_ids[itr->second].Directory; map_ids.push_back(id); } } @@ -363,9 +362,15 @@ bool ReadCinematicCameraDBC() // get camera file list from DB2 for (size_t i = 0; i < db2.GetRecordCount(); ++i) - CameraFileNames.insert(Trinity::StringFormat("FILE%08X.xxx", db2.GetRecord(i).GetUInt32("FileDataID"))); + { + DB2Record record = db2.GetRecord(i); + if (!record) + continue; - printf("Done! (" SZFMTD " CinematicCameras loaded)\n", CameraFileNames.size()); + CameraFileDataIds.insert(record.GetUInt32("FileDataID")); + } + + printf("Done! (" SZFMTD " CinematicCameras loaded)\n", CameraFileDataIds.size()); return true; } @@ -503,13 +508,8 @@ bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8]) return *((uint64*)hiResHoles) != 0; } -bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build, bool ignoreDeepWater) +bool ConvertADT(ChunkedFile& adt, std::string const& mapName, std::string const& outputPath, int gx, int gy, uint32 build, bool ignoreDeepWater) { - ChunkedFile adt; - - if (!adt.loadFile(CascStorage, inputPath)) - return false; - // Prepare map header map_fileheader map; map.mapMagic = *reinterpret_cast<uint32 const*>(MAP_MAGIC); @@ -710,7 +710,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break; case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break; default: - printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->LiquidType, inputPath.c_str(), i, j); + printf("\nCan't find Liquid type %u for map %s [%u,%u]\nchunk %d,%d\n", h->LiquidType, mapName.c_str(), gx, gy, i, j); break; } @@ -1049,6 +1049,26 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int return true; } +bool ConvertADT(std::string const& fileName, std::string const& mapName, std::string const& outputPath, int gx, int gy, uint32 build, bool ignoreDeepWater) +{ + ChunkedFile adt; + + if (!adt.loadFile(CascStorage, fileName)) + return false; + + return ConvertADT(adt, mapName, outputPath, gx, gy, build, ignoreDeepWater); +} + +bool ConvertADT(uint32 fileDataId, std::string const& mapName, std::string const& outputPath, int gx, int gy, uint32 build, bool ignoreDeepWater) +{ + ChunkedFile adt; + + if (!adt.loadFile(CascStorage, fileDataId, Trinity::StringFormat("Map %s grid [%u,%u]", mapName.c_str(), gx, gy))) + return false; + + return ConvertADT(adt, mapName, outputPath, gx, gy, build, ignoreDeepWater); +} + bool IsDeepWaterIgnored(uint32 mapId, uint32 x, uint32 y) { if (mapId == 0) @@ -1078,7 +1098,6 @@ bool IsDeepWaterIgnored(uint32 mapId, uint32 x, uint32 y) void ExtractMaps(uint32 build) { - std::string storagePath; std::string outputFileName; printf("Extracting maps...\n"); @@ -1094,25 +1113,33 @@ void ExtractMaps(uint32 build) printf("Convert map files\n"); for (std::size_t z = 0; z < map_ids.size(); ++z) { - printf("Extract %s (" SZFMTD "/" SZFMTD ") \n", map_ids[z].name, z+1, map_ids.size()); + printf("Extract %s (" SZFMTD "/" SZFMTD ") \n", map_ids[z].Name.c_str(), z + 1, map_ids.size()); // Loadup map grid data - storagePath = Trinity::StringFormat("World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name); ChunkedFile wdt; - if (!wdt.loadFile(CascStorage, storagePath, false)) + if (!wdt.loadFile(CascStorage, map_ids[z].WdtFileDataId, Trinity::StringFormat("WDT for map %u", map_ids[z].Id), false)) continue; - FileChunk* chunk = wdt.GetChunk("MAIN"); + FileChunk* mphd = wdt.GetChunk("MPHD"); + FileChunk* main = wdt.GetChunk("MAIN"); + FileChunk* maid = wdt.GetChunk("MAID"); for (uint32 y = 0; y < WDT_MAP_SIZE; ++y) { for (uint32 x = 0; x < WDT_MAP_SIZE; ++x) { - if (!(chunk->As<wdt_MAIN>()->adt_list[y][x].flag & 0x1)) + if (!(main->As<wdt_MAIN>()->adt_list[y][x].flag & 0x1)) continue; - storagePath = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y); - outputFileName = Trinity::StringFormat("%s/maps/%04u_%02u_%02u.map", output_path.string().c_str(), map_ids[z].id, y, x); - bool ignoreDeepWater = IsDeepWaterIgnored(map_ids[z].id, y, x); - ConvertADT(storagePath, outputFileName, y, x, build, ignoreDeepWater); + outputFileName = Trinity::StringFormat("%s/maps/%04u_%02u_%02u.map", output_path.string().c_str(), map_ids[z].Id, y, x); + bool ignoreDeepWater = IsDeepWaterIgnored(map_ids[z].Id, y, x); + if (mphd && mphd->As<wdt_MPHD>()->flags & 0x200) + { + ConvertADT(maid->As<wdt_MAID>()->adt_files[y][x].rootADT, map_ids[z].Name, outputFileName, y, x, build, ignoreDeepWater); + } + else + { + std::string storagePath = Trinity::StringFormat("World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].Directory.c_str(), map_ids[z].Directory.c_str(), x, y); + ConvertADT(storagePath, map_ids[z].Name, outputFileName, y, x, build, ignoreDeepWater); + } } // draw progress bar @@ -1309,18 +1336,18 @@ void ExtractCameraFiles() // extract M2s uint32 count = 0; - for (std::string const& cameraFileName : CameraFileNames) + for (uint32 cameraFileDataId : CameraFileDataIds) { - if (CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, cameraFileName.c_str(), CASC_LOCALE_NONE)) + if (CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, cameraFileDataId, CASC_LOCALE_NONE)) { - boost::filesystem::path filePath = outputPath / GetCascFilenamePart(cameraFileName.c_str()); + boost::filesystem::path filePath = outputPath / Trinity::StringFormat("FILE%08X.xxx", cameraFileDataId); if (!boost::filesystem::exists(filePath)) if (ExtractFile(dbcFile, filePath.string())) ++count; } else - printf("Unable to open file %s in the archive: %s\n", cameraFileName.c_str(), CASC::HumanReadableCASCError(GetLastError())); + printf("Unable to open file %u in the archive: %s\n", cameraFileDataId, CASC::HumanReadableCASCError(GetLastError())); } printf("Extracted %u camera files\n", count); @@ -1336,68 +1363,63 @@ void ExtractGameTables() printf("output path %s\n", outputPath.string().c_str()); - char const* GameTables[] = + DB2FileInfo GameTables[] = { - "GameTables\\ArmorMitigationByLvl.txt", - "GameTables\\ArtifactKnowledgeMultiplier.txt", - "GameTables\\ArtifactLevelXP.txt", - "GameTables\\AzeriteBaseExperiencePerLevel.txt", - "GameTables\\AzeriteKnowledgeMultiplier.txt", - "GameTables\\AzeriteLevelToItemLevel.txt", - "GameTables\\BarberShopCostBase.txt", - "GameTables\\BaseMp.txt", - "GameTables\\BattlePetTypeDamageMod.txt", - "GameTables\\BattlePetXP.txt", - "GameTables\\ChallengeModeDamage.txt", - "GameTables\\ChallengeModeHealth.txt", - "GameTables\\CombatRatings.txt", - "GameTables\\CombatRatingsMultByILvl.txt", - "GameTables\\HonorLevel.txt", - "GameTables\\HpPerSta.txt", - "GameTables\\ItemLevelByLevel.txt", - "GameTables\\ItemLevelSquish.txt", - "GameTables\\ItemSocketCostPerLevel.txt", - "GameTables\\NpcDamageByClass.txt", - "GameTables\\NpcDamageByClassExp1.txt", - "GameTables\\NpcDamageByClassExp2.txt", - "GameTables\\NpcDamageByClassExp3.txt", - "GameTables\\NpcDamageByClassExp4.txt", - "GameTables\\NpcDamageByClassExp5.txt", - "GameTables\\NpcDamageByClassExp6.txt", - "GameTables\\NpcDamageByClassExp7.txt", - "GameTables\\NPCManaCostScaler.txt", - "GameTables\\NpcTotalHp.txt", - "GameTables\\NpcTotalHpExp1.txt", - "GameTables\\NpcTotalHpExp2.txt", - "GameTables\\NpcTotalHpExp3.txt", - "GameTables\\NpcTotalHpExp4.txt", - "GameTables\\NpcTotalHpExp5.txt", - "GameTables\\NpcTotalHpExp6.txt", - "GameTables\\NpcTotalHpExp7.txt", - "GameTables\\SandboxScaling.txt", - "GameTables\\SpellScaling.txt", - "GameTables\\StaminaMultByILvl.txt", - "GameTables\\xp.txt", - nullptr + { 1385707, "ArmorMitigationByLvl.txt" }, + { 1582086, "ArtifactKnowledgeMultiplier.txt" }, + { 1391662, "ArtifactLevelXP.txt" }, + { 1892815, "AzeriteBaseExperiencePerLevel.txt" }, + { 1892816, "AzeriteKnowledgeMultiplier.txt" }, + { 1859377, "AzeriteLevelToItemLevel.txt" }, + { 1391663, "BarberShopCostBase.txt" }, + { 1391664, "BaseMp.txt" }, + { 1391665, "BattlePetTypeDamageMod.txt" }, + { 1391666, "BattlePetXP.txt" }, + { 1391667, "ChallengeModeDamage.txt" }, + { 1391668, "ChallengeModeHealth.txt" }, + { 1391669, "CombatRatings.txt" }, + { 1391670, "CombatRatingsMultByILvl.txt" }, + { 1391671, "HonorLevel.txt" }, + { 1391642, "HpPerSta.txt" }, + { 2012881, "ItemLevelByLevel.txt" }, + { 1726830, "ItemLevelSquish.txt" }, + { 1391643, "ItemSocketCostPerLevel.txt" }, + { 1391644, "NpcDamageByClass.txt" }, + { 1391645, "NpcDamageByClassExp1.txt" }, + { 1391646, "NpcDamageByClassExp2.txt" }, + { 1391647, "NpcDamageByClassExp3.txt" }, + { 1391648, "NpcDamageByClassExp4.txt" }, + { 1391649, "NpcDamageByClassExp5.txt" }, + { 1391650, "NpcDamageByClassExp6.txt" }, + { 1536195, "NpcDamageByClassExp7.txt" }, + { 1391651, "NPCManaCostScaler.txt" }, + { 1391652, "NpcTotalHp.txt" }, + { 1391653, "NpcTotalHpExp1.txt" }, + { 1391654, "NpcTotalHpExp2.txt" }, + { 1391655, "NpcTotalHpExp3.txt" }, + { 1391656, "NpcTotalHpExp4.txt" }, + { 1391657, "NpcTotalHpExp5.txt" }, + { 1391658, "NpcTotalHpExp6.txt" }, + { 1536196, "NpcTotalHpExp7.txt" }, + { 1391659, "SandboxScaling.txt" }, + { 1391660, "SpellScaling.txt" }, + { 1980632, "StaminaMultByILvl.txt" }, + { 1391661, "xp.txt" }, }; - uint32 index = 0; uint32 count = 0; - char const* fileName = GameTables[index]; - while (fileName) + for (DB2FileInfo const& gt : GameTables) { - if (CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, fileName, CASC_LOCALE_NONE)) + if (CASC::FileHandle dbcFile = CASC::OpenFile(CascStorage, gt.FileDataId, CASC_LOCALE_NONE)) { - boost::filesystem::path filePath = outputPath / GetCascFilenamePart(fileName); + boost::filesystem::path filePath = outputPath / gt.Name; if (!boost::filesystem::exists(filePath)) if (ExtractFile(dbcFile, filePath.string())) ++count; } else - printf("Unable to open file %s in the archive: %s\n", fileName, CASC::HumanReadableCASCError(GetLastError())); - - fileName = GameTables[++index]; + printf("Unable to open file %s in the archive: %s\n", gt.Name, CASC::HumanReadableCASCError(GetLastError())); } printf("Extracted %u files\n\n", count); diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp index 5bb72643a94..86ddd2f5ba8 100644 --- a/src/tools/map_extractor/loadlib.cpp +++ b/src/tools/map_extractor/loadlib.cpp @@ -61,6 +61,33 @@ bool ChunkedFile::loadFile(CASC::StorageHandle const& mpq, std::string const& fi return false; } +bool ChunkedFile::loadFile(CASC::StorageHandle const& mpq, uint32 fileDataId, std::string const& description, bool log) +{ + free(); + CASC::FileHandle file = CASC::OpenFile(mpq, fileDataId, CASC_LOCALE_ALL, log); + if (!file) + return false; + + DWORD fileSize = CASC::GetFileSize(file, nullptr); + if (fileSize == CASC_INVALID_SIZE) + return false; + + data_size = fileSize; + data = new uint8[data_size]; + DWORD bytesRead = 0; + if (!CASC::ReadFile(file, data, data_size, &bytesRead) || bytesRead != data_size) + return false; + + parseChunks(); + if (prepareLoadedData()) + return true; + + printf("Error loading %s\n", description.c_str()); + free(); + + return false; +} + bool ChunkedFile::prepareLoadedData() { FileChunk* chunk = GetChunk("MVER"); diff --git a/src/tools/map_extractor/loadlib/loadlib.h b/src/tools/map_extractor/loadlib/loadlib.h index 5adfeb20a12..d2beacf46d5 100644 --- a/src/tools/map_extractor/loadlib/loadlib.h +++ b/src/tools/map_extractor/loadlib/loadlib.h @@ -83,6 +83,7 @@ public: virtual ~ChunkedFile(); bool prepareLoadedData(); bool loadFile(CASC::StorageHandle const& mpq, std::string const& fileName, bool log = true); + bool loadFile(CASC::StorageHandle const& mpq, uint32 fileDataId, std::string const& description, bool log = true); void free(); void parseChunks(); diff --git a/src/tools/map_extractor/wdt.h b/src/tools/map_extractor/wdt.h index 5c43be05628..677c5c86c42 100644 --- a/src/tools/map_extractor/wdt.h +++ b/src/tools/map_extractor/wdt.h @@ -27,6 +27,25 @@ #pragma pack(push, 1) +class wdt_MPHD +{ + union + { + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + + uint32 flags; + uint32 lgtFileDataID; + uint32 occFileDataID; + uint32 fogsFileDataID; + uint32 mpvFileDataID; + uint32 texFileDataID; + uint32 wdlFileDataID; + uint32 pd4FileDataID; +}; class wdt_MAIN { @@ -45,6 +64,29 @@ public: } adt_list[64][64]; }; +class wdt_MAID +{ + union + { + uint32 fcc; + char fcc_txt[4]; + }; +public: + uint32 size; + + struct + { + uint32 rootADT; // FileDataID of mapname_xx_yy.adt + uint32 obj0ADT; // FileDataID of mapname_xx_yy_obj0.adt + uint32 obj1ADT; // FileDataID of mapname_xx_yy_obj1.adt + uint32 tex0ADT; // FileDataID of mapname_xx_yy_tex0.adt + uint32 lodADT; // FileDataID of mapname_xx_yy_lod.adt + uint32 mapTexture; // FileDataID of mapname_xx_yy.blp + uint32 mapTextureN; // FileDataID of mapname_xx_yy_n.blp + uint32 minimapTexture; // FileDataID of mapxx_yy.blp + } adt_files[64][64]; +}; + #pragma pack(pop) #endif diff --git a/src/tools/vmap4_extractor/adtfile.cpp b/src/tools/vmap4_extractor/adtfile.cpp index abd8ba5413f..43dddb8a414 100644 --- a/src/tools/vmap4_extractor/adtfile.cpp +++ b/src/tools/vmap4_extractor/adtfile.cpp @@ -77,9 +77,14 @@ char* GetExtension(char* FileName) extern CASC::StorageHandle CascStorage; -ADTFile::ADTFile(char* filename, bool cache) : _file(CascStorage, filename, false) +ADTFile::ADTFile(std::string const& filename, bool cache) : _file(CascStorage, filename.c_str(), false) +{ + cacheable = cache; + dirfileCache = nullptr; +} + +ADTFile::ADTFile(uint32 fileDataId, std::string const& description, bool cache) : _file(CascStorage, fileDataId, description, false) { - Adtfilename.append(filename); cacheable = cache; dirfileCache = nullptr; } @@ -114,13 +119,7 @@ bool ADTFile::init(uint32 map_num, uint32 originalMapId) size_t nextpos = _file.getPos() + size; - if (!strcmp(fourcc,"MCIN")) - { - } - else if (!strcmp(fourcc,"MTEX")) - { - } - else if (!strcmp(fourcc,"MMDX")) + if (!strcmp(fourcc,"MMDX")) { if (size) { diff --git a/src/tools/vmap4_extractor/adtfile.h b/src/tools/vmap4_extractor/adtfile.h index 0dddb5b0f4b..053800490f4 100644 --- a/src/tools/vmap4_extractor/adtfile.h +++ b/src/tools/vmap4_extractor/adtfile.h @@ -61,11 +61,11 @@ class ADTFile { private: CASCFile _file; - std::string Adtfilename; bool cacheable; std::vector<ADTOutputCache>* dirfileCache; public: - ADTFile(char* filename, bool cache); + ADTFile(std::string const& filename, bool cache); + ADTFile(uint32 fileDataId, std::string const& description, bool cache); ~ADTFile(); std::vector<std::string> WmoInstanceNames; std::vector<std::string> ModelInstanceNames; diff --git a/src/tools/vmap4_extractor/cascfile.cpp b/src/tools/vmap4_extractor/cascfile.cpp index f05db213c19..1702ddb5230 100644 --- a/src/tools/vmap4_extractor/cascfile.cpp +++ b/src/tools/vmap4_extractor/cascfile.cpp @@ -21,7 +21,7 @@ CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool warnNoExist /*= true*/) : eof(false), - buffer(0), + buffer(nullptr), pointer(0), size(0) { @@ -34,18 +34,41 @@ CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool w return; } + init(file, filename); +} + +CASCFile::CASCFile(CASC::StorageHandle const& casc, uint32 fileDataId, std::string const& description, bool warnNoExist /*= true*/) : + eof(false), + buffer(nullptr), + pointer(0), + size(0) +{ + CASC::FileHandle file = CASC::OpenFile(casc, fileDataId, CASC_LOCALE_ALL, false); + if (!file) + { + if (warnNoExist || GetLastError() != ERROR_FILE_NOT_FOUND) + fprintf(stderr, "Can't open %s: %s\n", description.c_str(), CASC::HumanReadableCASCError(GetLastError())); + eof = true; + return; + } + + init(file, description.c_str()); +} + +void CASCFile::init(CASC::FileHandle const& file, const char* description) +{ DWORD fileSizeHigh = 0; DWORD fileSize = CASC::GetFileSize(file, &fileSizeHigh); if (fileSize == CASC_INVALID_SIZE) { - fprintf(stderr, "Can't open %s, failed to get size: %s!\n", filename, CASC::HumanReadableCASCError(GetLastError())); + fprintf(stderr, "Can't open %s, failed to get size: %s!\n", description, CASC::HumanReadableCASCError(GetLastError())); eof = true; return; } if (fileSizeHigh) { - fprintf(stderr, "Can't open %s, file larger than 2GB", filename); + fprintf(stderr, "Can't open %s, file larger than 2GB", description); eof = true; return; } @@ -56,7 +79,7 @@ CASCFile::CASCFile(CASC::StorageHandle const& casc, const char* filename, bool w buffer = new char[size]; if (!CASC::ReadFile(file, buffer, size, &read) || size != read) { - fprintf(stderr, "Can't read %s, size=%u read=%u: %s\n", filename, uint32(size), uint32(read), CASC::HumanReadableCASCError(GetLastError())); + fprintf(stderr, "Can't read %s, size=%u read=%u: %s\n", description, uint32(size), uint32(read), CASC::HumanReadableCASCError(GetLastError())); eof = true; return; } diff --git a/src/tools/vmap4_extractor/cascfile.h b/src/tools/vmap4_extractor/cascfile.h index de1baa3a5d4..5ebb0bb5bfb 100644 --- a/src/tools/vmap4_extractor/cascfile.h +++ b/src/tools/vmap4_extractor/cascfile.h @@ -25,6 +25,7 @@ #include "Define.h" #include "CascHandles.h" +#include <string> #include <utility> class CASCFile @@ -39,7 +40,9 @@ class CASCFile public: CASCFile(CASC::StorageHandle const& casc, const char* filename, bool warnNoExist = true); // filenames are not case sensitive + CASCFile(CASC::StorageHandle const& casc, uint32 fileDataId, std::string const& description, bool warnNoExist = true); ~CASCFile() { close(); } + void init(CASC::FileHandle const& file, const char* description); size_t read(void* dest, size_t bytes); size_t getSize() { return size; } size_t getPos() { return pointer; } diff --git a/src/tools/vmap4_extractor/gameobject_extract.cpp b/src/tools/vmap4_extractor/gameobject_extract.cpp index bf9cf73e678..85dd992e6f1 100644 --- a/src/tools/vmap4_extractor/gameobject_extract.cpp +++ b/src/tools/vmap4_extractor/gameobject_extract.cpp @@ -43,7 +43,8 @@ bool ExtractSingleModel(std::string& fname) std::string originalName = fname; char* name = GetPlainName((char*)fname.c_str()); - FixNameCase(name, strlen(name)); + if (fname.substr(0, 4) != "FILE") + FixNameCase(name, strlen(name)); FixNameSpaces(name, strlen(name)); std::string output(szWorkDirWmo); diff --git a/src/tools/vmap4_extractor/model.cpp b/src/tools/vmap4_extractor/model.cpp index 2b01d4e1225..aeaebe28833 100644 --- a/src/tools/vmap4_extractor/model.cpp +++ b/src/tools/vmap4_extractor/model.cpp @@ -243,7 +243,13 @@ void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, b WMO::MODD const& doodad = doodadData.Spawns[doodadIndex]; char ModelInstName[1024]; - sprintf(ModelInstName, "%s", GetPlainName(&doodadData.Paths[doodad.NameIndex])); + if (doodadData.Paths) + sprintf(ModelInstName, "%s", GetPlainName(&doodadData.Paths[doodad.NameIndex])); + else if (doodadData.FileDataIds) + sprintf(ModelInstName, "FILE%08X.xxx", doodadData.FileDataIds[doodad.NameIndex]); + else + ASSERT(false); + uint32 nlen = strlen(ModelInstName); FixNameCase(ModelInstName, nlen); FixNameSpaces(ModelInstName, nlen); diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index babdb7a99c0..25b42e8ed07 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -55,13 +55,15 @@ CASC::StorageHandle CascStorage; -struct map_info +struct MapEntry { - char name[64]; - int32 parent_id; + int32 WdtFileDataId = 0; + int16 ParentMapID = 0; + std::string Name; + std::string Directory; }; -std::map<uint32, map_info> map_ids; +std::map<uint32, MapEntry> map_ids; std::unordered_set<uint32> maps_that_are_parents; boost::filesystem::path input_path; bool preciseVectorData = false; @@ -166,7 +168,8 @@ bool ExtractSingleWmo(std::string& fname) char szLocalFile[1024]; char* plain_name = GetPlainName(&fname[0]); - FixNameCase(plain_name, strlen(plain_name)); + if (fname.substr(0, 4) != "FILE") + FixNameCase(plain_name, strlen(plain_name)); FixNameSpaces(plain_name, strlen(plain_name)); sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name); @@ -192,7 +195,6 @@ bool ExtractSingleWmo(std::string& fname) return true; bool file_ok = true; - printf("Extracting %s\n", originalName.c_str()); WMORoot froot(originalName); if (!froot.open()) { @@ -253,10 +255,13 @@ void ParsMapFiles() auto itr = wdts.find(mapId); if (itr == wdts.end()) { - char fn[512]; - char* name = map_ids[mapId].name; - sprintf(fn, "World\\Maps\\%s\\%s.wdt", name, name); - itr = wdts.emplace(std::piecewise_construct, std::forward_as_tuple(mapId), std::forward_as_tuple(fn, name, maps_that_are_parents.count(mapId) > 0)).first; + uint32 fileDataId = map_ids[mapId].WdtFileDataId; + if (!fileDataId) + return nullptr; + + std::string description = Trinity::StringFormat("WDT for map %u - %s (FileDataID %u)", mapId, map_ids[mapId].Name.c_str(), fileDataId); + std::string directory = map_ids[mapId].Directory; + itr = wdts.emplace(std::piecewise_construct, std::forward_as_tuple(mapId), std::forward_as_tuple(fileDataId, description, std::move(directory), maps_that_are_parents.count(mapId) > 0)).first; if (!itr->second.init(mapId)) { wdts.erase(itr); @@ -271,7 +276,7 @@ void ParsMapFiles() { if (WDTFile* WDT = getWDT(itr->first)) { - WDTFile* parentWDT = itr->second.parent_id >= 0 ? getWDT(itr->second.parent_id) : nullptr; + WDTFile* parentWDT = itr->second.ParentMapID >= 0 ? getWDT(itr->second.ParentMapID) : nullptr; printf("Processing Map %u\n[", itr->first); for (int32 x = 0; x < 64; ++x) { @@ -287,7 +292,7 @@ void ParsMapFiles() { if (ADTFile* ADT = parentWDT->GetMap(x, y)) { - ADT->init(itr->first, itr->second.parent_id); + ADT->init(itr->first, itr->second.ParentMapID); parentWDT->FreeADT(ADT); } } @@ -479,21 +484,16 @@ int main(int argc, char ** argv) for (uint32 x = 0; x < db2.GetRecordCount(); ++x) { DB2Record record = db2.GetRecord(x); - map_info& m = map_ids[record.GetId()]; - - const char* map_name = record.GetString("Directory"); - size_t max_map_name_length = sizeof(m.name); - if (strlen(map_name) >= max_map_name_length) - { - printf("Fatal error: Map name too long!\n"); - exit(1); - } + if (!record) + continue; - strncpy(m.name, map_name, max_map_name_length); - m.name[max_map_name_length - 1] = '\0'; - m.parent_id = int16(record.GetUInt16("ParentMapID")); - if (m.parent_id >= 0) - maps_that_are_parents.insert(m.parent_id); + MapEntry& m = map_ids[record.GetId()]; + m.WdtFileDataId = record.GetInt32("WdtFileDataID"); + m.ParentMapID = int16(record.GetUInt16("ParentMapID")); + m.Name = record.GetString("MapName"); + m.Directory = record.GetString("Directory"); + if (m.ParentMapID >= 0) + maps_that_are_parents.insert(m.ParentMapID); } for (uint32 x = 0; x < db2.GetRecordCopyCount(); ++x) @@ -502,9 +502,11 @@ int main(int argc, char ** argv) auto itr = map_ids.find(copy.SourceRowId); if (itr != map_ids.end()) { - map_info& id = map_ids[copy.NewRowId]; - strcpy(id.name, itr->second.name); - id.parent_id = itr->second.parent_id; + MapEntry& id = map_ids[copy.NewRowId]; + id.WdtFileDataId = itr->second.WdtFileDataId; + id.ParentMapID = itr->second.ParentMapID; + id.Name = itr->second.Name; + id.Directory = itr->second.Directory; } } diff --git a/src/tools/vmap4_extractor/wdtfile.cpp b/src/tools/vmap4_extractor/wdtfile.cpp index acbc1e5c6f0..e757dd9a398 100644 --- a/src/tools/vmap4_extractor/wdtfile.cpp +++ b/src/tools/vmap4_extractor/wdtfile.cpp @@ -20,6 +20,7 @@ #include "wdtfile.h" #include "adtfile.h" #include "Common.h" +#include "Errors.h" #include "StringFormat.h" #include <cstdio> @@ -34,9 +35,11 @@ char * wdtGetPlainName(char * FileName) extern CASC::StorageHandle CascStorage; -WDTFile::WDTFile(char const* storagePath, std::string mapName, bool cache) - : _file(CascStorage, storagePath), _mapName(std::move(mapName)) +WDTFile::WDTFile(uint32 fileDataId, std::string const& description, std::string mapName, bool cache) + : _file(CascStorage, fileDataId, description), _mapName(std::move(mapName)) { + memset(&_header, 0, sizeof(WDT::MPHD)); + memset(&_adtInfo, 0, sizeof(WDT::MAIN)); if (cache) { _adtCache = Trinity::make_unique<ADTCache>(); @@ -74,10 +77,23 @@ bool WDTFile::init(uint32 mapId) size_t nextpos = _file.getPos() + size; - if (!strcmp(fourcc,"MAIN")) + if (!strcmp(fourcc, "MPHD")) { + ASSERT(size == sizeof(WDT::MPHD)); + _file.read(&_header, sizeof(WDT::MPHD)); } - if (!strcmp(fourcc,"MWMO")) + else if (!strcmp(fourcc,"MAIN")) + { + ASSERT(size == sizeof(WDT::MAIN)); + _file.read(&_adtInfo, sizeof(WDT::MAIN)); + } + else if (!strcmp(fourcc, "MAID")) + { + ASSERT(size == sizeof(WDT::MAID)); + _adtFileDataIds = Trinity::make_unique<WDT::MAID>(); + _file.read(_adtFileDataIds.get(), sizeof(WDT::MAID)); + } + else if (!strcmp(fourcc,"MWMO")) { // global map objects if (size) @@ -141,12 +157,19 @@ ADTFile* WDTFile::GetMap(int32 x, int32 y) if (_adtCache && _adtCache->file[x][y]) return _adtCache->file[x][y].get(); - char name[512]; + if (!(_adtInfo.Data[x][y].Flag & 1)) + return nullptr; + + ADTFile* adt; + std::string name = Trinity::StringFormat("World\\Maps\\%s\\%s_%d_%d_obj0.adt", _mapName.c_str(), _mapName.c_str(), x, y); + if (_header.Flags & 0x200) + adt = new ADTFile(_adtFileDataIds->Data[x][y].Obj0ADT, name, _adtCache != nullptr); + else + adt = new ADTFile(name, _adtCache != nullptr); - sprintf(name, "World\\Maps\\%s\\%s_%d_%d_obj0.adt", _mapName.c_str(), _mapName.c_str(), x, y); - ADTFile* adt = new ADTFile(name, _adtCache != nullptr); if (_adtCache) _adtCache->file[x][y].reset(adt); + return adt; } diff --git a/src/tools/vmap4_extractor/wdtfile.h b/src/tools/vmap4_extractor/wdtfile.h index 785f046ad7b..cf3e30a7eab 100644 --- a/src/tools/vmap4_extractor/wdtfile.h +++ b/src/tools/vmap4_extractor/wdtfile.h @@ -27,10 +27,51 @@ class ADTFile; +#pragma pack(push, 1) +namespace WDT +{ + struct MPHD + { + uint32 Flags; + uint32 LgtFileDataID; + uint32 OccFileDataID; + uint32 FogsFileDataID; + uint32 MpvFileDataID; + uint32 TexFileDataID; + uint32 WdlFileDataID; + uint32 Pd4FileDataID; + }; + + struct MAIN + { + struct SMAreaInfo + { + uint32 Flag; + uint32 AsyncId; + } Data[64][64]; + }; + + struct MAID + { + struct SMAreaFileIDs + { + uint32 RootADT; // FileDataID of mapname_xx_yy.adt + uint32 Obj0ADT; // FileDataID of mapname_xx_yy_obj0.adt + uint32 Obj1ADT; // FileDataID of mapname_xx_yy_obj1.adt + uint32 Tex0ADT; // FileDataID of mapname_xx_yy_tex0.adt + uint32 LodADT; // FileDataID of mapname_xx_yy_lod.adt + uint32 MapTexture; // FileDataID of mapname_xx_yy.blp + uint32 MapTextureN; // FileDataID of mapname_xx_yy_n.blp + uint32 MinimapTexture; // FileDataID of mapxx_yy.blp + } Data[64][64]; + }; +} +#pragma pack(pop) + class WDTFile { public: - WDTFile(char const* storagePath, std::string mapName, bool cache); + WDTFile(uint32 fileDataId, std::string const& description, std::string mapName, bool cache); ~WDTFile(); bool init(uint32 mapId); @@ -38,6 +79,9 @@ public: void FreeADT(ADTFile* adt); private: CASCFile _file; + WDT::MPHD _header; + WDT::MAIN _adtInfo; + std::unique_ptr<WDT::MAID> _adtFileDataIds; std::string _mapName; std::vector<std::string> _wmoNames; struct ADTCache diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp index 749e14d1d05..56e3fa6faec 100644 --- a/src/tools/vmap4_extractor/wmo.cpp +++ b/src/tools/vmap4_extractor/wmo.cpp @@ -19,6 +19,8 @@ #include "vmapexport.h" #include "adtfile.h" #include "cascfile.h" +#include "Errors.h" +#include "StringFormat.h" #include "vec3d.h" #include "VMapDefinitions.h" #include "wmo.h" @@ -26,7 +28,6 @@ #include <map> #include <cstdio> #include <cstdlib> -#include "Errors.h" WMORoot::WMORoot(std::string const& filename) : filename(filename), color(0), nTextures(0), nGroups(0), nPortals(0), nLights(0), @@ -83,6 +84,8 @@ bool WMORoot::open() } else if (!strcmp(fourcc,"MODN")) { + ASSERT(!DoodadData.FileDataIds); + char* ptr = f.getPointer(); char* end = ptr + size; DoodadData.Paths = std::make_unique<char[]>(size); @@ -102,6 +105,25 @@ bool WMORoot::open() ValidDoodadNames.insert(doodadNameIndex); } } + else if (!strcmp(fourcc, "MODI")) + { + ASSERT(!DoodadData.Paths); + + char* ptr = f.getPointer(); + char* end = ptr + size; + uint32 fileDataIdCount = size / sizeof(uint32); + DoodadData.FileDataIds = std::make_unique<uint32[]>(fileDataIdCount); + memcpy(DoodadData.FileDataIds.get(), ptr, size); + for (uint32 i = 0; i < fileDataIdCount; ++i) + { + if (!DoodadData.FileDataIds[i]) + continue; + + std::string path = Trinity::StringFormat("FILE%08X.xxx", DoodadData.FileDataIds[i]); + if (ExtractSingleModel(path)) + ValidDoodadNames.insert(i); + } + } else if (!strcmp(fourcc,"MODD")) { DoodadData.Spawns.resize(size / sizeof(WMO::MODD)); diff --git a/src/tools/vmap4_extractor/wmo.h b/src/tools/vmap4_extractor/wmo.h index fd9e8f589b4..7505fc4f077 100644 --- a/src/tools/vmap4_extractor/wmo.h +++ b/src/tools/vmap4_extractor/wmo.h @@ -71,6 +71,7 @@ struct WMODoodadData { std::vector<WMO::MODS> Sets; std::unique_ptr<char[]> Paths; + std::unique_ptr<uint32[]> FileDataIds; std::vector<WMO::MODD> Spawns; std::unordered_set<uint16> References; }; |