aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/tools/map_extractor/System.cpp218
-rw-r--r--src/tools/map_extractor/loadlib.cpp27
-rw-r--r--src/tools/map_extractor/loadlib/loadlib.h1
-rw-r--r--src/tools/map_extractor/wdt.h42
-rw-r--r--src/tools/vmap4_extractor/adtfile.cpp17
-rw-r--r--src/tools/vmap4_extractor/adtfile.h4
-rw-r--r--src/tools/vmap4_extractor/cascfile.cpp31
-rw-r--r--src/tools/vmap4_extractor/cascfile.h3
-rw-r--r--src/tools/vmap4_extractor/gameobject_extract.cpp3
-rw-r--r--src/tools/vmap4_extractor/model.cpp8
-rw-r--r--src/tools/vmap4_extractor/vmapexport.cpp60
-rw-r--r--src/tools/vmap4_extractor/wdtfile.cpp37
-rw-r--r--src/tools/vmap4_extractor/wdtfile.h46
-rw-r--r--src/tools/vmap4_extractor/wmo.cpp24
-rw-r--r--src/tools/vmap4_extractor/wmo.h1
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;
};