diff --git a/src/common/Collision/Maps/TileAssembler.cpp b/src/common/Collision/Maps/TileAssembler.cpp index 05c8d0c92..dd4f2621e 100644 --- a/src/common/Collision/Maps/TileAssembler.cpp +++ b/src/common/Collision/Maps/TileAssembler.cpp @@ -41,7 +41,7 @@ namespace VMAP //================================================================= TileAssembler::TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName) - : iDestDir(pDestDirName), iSrcDir(pSrcDirName), iFilterMethod(nullptr), iCurrentUniqueNameId(0) + : iDestDir(pDestDirName), iSrcDir(pSrcDirName) { //mkdir(iDestDir); //init(); @@ -209,9 +209,8 @@ namespace VMAP ModelSpawn spawn; while (!feof(dirf)) { - check = 0; - // read mapID, tileX, tileY, Flags, adtID, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name - check += fread(&mapID, sizeof(uint32), 1, dirf); + // read mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name + check = fread(&mapID, sizeof(uint32), 1, dirf); if (check == 0) // EoF... break; check += fread(&tileX, sizeof(uint32), 1, dirf); @@ -226,8 +225,10 @@ namespace VMAP printf("spawning Map %d\n", mapID); mapData[mapID] = current = new MapSpawns(); } - else current = (*map_iter).second; - current->UniqueEntries.insert(pair(spawn.ID, spawn)); + else + current = map_iter->second; + + current->UniqueEntries.emplace(spawn.ID, spawn); current->TileEntries.insert(pair(StaticMapTree::packTileID(tileX, tileY), spawn.ID)); } bool success = (ferror(dirf) == 0); @@ -283,6 +284,7 @@ namespace VMAP return true; } +#pragma pack(push, 1) struct WMOLiquidHeader { int xverts, yverts, xtiles, ytiles; @@ -291,6 +293,7 @@ namespace VMAP float pos_z; short type; }; +#pragma pack(pop) //================================================================= bool TileAssembler::convertRawFile(const std::string& pModelFilename) { @@ -334,6 +337,10 @@ namespace VMAP if (!model_list) return; + char ident[8]; + if (fread(ident, 1, 8, model_list) != 8 || memcmp(ident, VMAP::RAW_VMAP_MAGIC, 8) != 0) + return; + FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb"); if (!model_list_copy) { @@ -341,14 +348,21 @@ namespace VMAP return; } + fwrite(VMAP::VMAP_MAGIC, 1, 8, model_list_copy); + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (!feof(model_list)) { - if (fread(&displayId, sizeof(uint32), 1, model_list) != 1 - || fread(&name_length, sizeof(uint32), 1, model_list) != 1 - || name_length >= sizeof(buff) - || fread(&buff, sizeof(char), name_length, model_list) != name_length) + if (fread(&displayId, sizeof(uint32), 1, model_list) != 1) + if (feof(model_list)) // EOF flag is only set after failed reading attempt + break; + + if (fread(&isWmo, sizeof(uint8), 1, model_list) != 1 + || fread(&name_length, sizeof(uint32), 1, model_list) != 1 + || name_length >= sizeof(buff) + || fread(&buff, sizeof(char), name_length, model_list) != name_length) { std::cout << "\nFile 'temp_gameobject_models' seems to be corrupted" << std::endl; break; @@ -379,6 +393,7 @@ namespace VMAP } fwrite(&displayId, sizeof(uint32), 1, model_list_copy); + fwrite(&isWmo, sizeof(uint8), 1, model_list_copy); fwrite(&name_length, sizeof(uint32), 1, model_list_copy); fwrite(&buff, sizeof(char), name_length, model_list_copy); fwrite(&bounds.low(), sizeof(Vector3), 1, model_list_copy); diff --git a/src/common/Collision/Maps/TileAssembler.h b/src/common/Collision/Maps/TileAssembler.h index bc54fb7e1..462545ede 100644 --- a/src/common/Collision/Maps/TileAssembler.h +++ b/src/common/Collision/Maps/TileAssembler.h @@ -80,27 +80,23 @@ namespace VMAP class TileAssembler { - private: - std::string iDestDir; - std::string iSrcDir; - bool (*iFilterMethod)(char* pName); - G3D::Table iUniqueNameIds; - unsigned int iCurrentUniqueNameId; - MapData mapData; - std::set spawnedModelFiles; + private: + std::string iDestDir; + std::string iSrcDir; + G3D::Table iUniqueNameIds; + MapData mapData; + std::set spawnedModelFiles; - public: - TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName); - virtual ~TileAssembler(); + public: + TileAssembler(const std::string& pSrcDirName, const std::string& pDestDirName); + virtual ~TileAssembler(); - bool convertWorld2(); - bool readMapSpawns(); - bool calculateTransformedBound(ModelSpawn& spawn); - void exportGameobjectModels(); + bool convertWorld2(); + bool readMapSpawns(); + bool calculateTransformedBound(ModelSpawn &spawn); + void exportGameobjectModels(); - bool convertRawFile(const std::string& pModelFilename); - void setModelNameFilterMethod(bool (*pFilterMethod)(char* pName)) { iFilterMethod = pFilterMethod; } - std::string getDirEntryNameFromModName(unsigned int pMapId, const std::string& pModPosName); + bool convertRawFile(const std::string& pModelFilename); }; } // VMAP diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index c948b1251..84abe1073 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -24,11 +24,12 @@ using G3D::AABox; struct GameobjectModelData { - GameobjectModelData(const std::string& name_, const AABox& box) : - bound(box), name(name_) {} + GameobjectModelData(char const* name_, uint32 nameLength, Vector3 const& lowBound, Vector3 const& highBound, bool isWmo_) : + bound(lowBound, highBound), name(name_, nameLength), isWmo(isWmo_) { } AABox bound; std::string name; + bool isWmo; }; typedef std::unordered_map ModelList; @@ -47,7 +48,15 @@ void LoadGameObjectModelList() return; } + char magic[8]; + if (fread(magic, 1, 8, model_list_file) != 8 || memcmp(magic, VMAP::VMAP_MAGIC, 8) != 0) + { + sLog->outError("File '%s' has wrong header, expected %s.", VMAP::GAMEOBJECT_MODELS, VMAP::VMAP_MAGIC); + return; + } + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (true) { @@ -56,20 +65,25 @@ void LoadGameObjectModelList() if (feof(model_list_file)) // EOF flag is only set after failed reading attempt break; - if (fread(&name_length, sizeof(uint32), 1, model_list_file) != 1 - || name_length >= sizeof(buff) - || fread(&buff, sizeof(char), name_length, model_list_file) != name_length - || fread(&v1, sizeof(Vector3), 1, model_list_file) != 1 - || fread(&v2, sizeof(Vector3), 1, model_list_file) != 1) + if (fread(&isWmo, sizeof(uint8), 1, model_list_file) != 1 + || fread(&name_length, sizeof(uint32), 1, model_list_file) != 1 + || name_length >= sizeof(buff) + || fread(&buff, sizeof(char), name_length, model_list_file) != name_length + || fread(&v1, sizeof(Vector3), 1, model_list_file) != 1 + || fread(&v2, sizeof(Vector3), 1, model_list_file) != 1) { sLog->outError("File '%s' seems to be corrupted!", VMAP::GAMEOBJECT_MODELS); break; } - model_list.insert - ( - ModelList::value_type( displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2)) ) - ); + if (v1.isNaN() || v2.isNaN()) + { + sLog->outError("File '%s' Model '%s' has invalid v1%s v2%s values!", + VMAP::GAMEOBJECT_MODELS, std::string(buff, name_length).c_str(), v1.toString().c_str(), v2.toString().c_str()); + continue; + } + + model_list.emplace(std::piecewise_construct, std::forward_as_tuple(displayId), std::forward_as_tuple(&buff[0], name_length, v1, v2, isWmo != 0)); } fclose(model_list_file); diff --git a/src/common/Collision/VMapDefinitions.h b/src/common/Collision/VMapDefinitions.h index 6f85509c4..a33e0b405 100644 --- a/src/common/Collision/VMapDefinitions.h +++ b/src/common/Collision/VMapDefinitions.h @@ -12,8 +12,8 @@ namespace VMAP { - const char VMAP_MAGIC[] = "VMAP_4.4"; - const char RAW_VMAP_MAGIC[] = "VMAP044"; // used in extracted vmap files with raw data + const char VMAP_MAGIC[] = "VMAP_4.5"; + const char RAW_VMAP_MAGIC[] = "VMAP045"; // used in extracted vmap files with raw data const char GAMEOBJECT_MODELS[] = "GameObjectModels.dtree"; // defined in TileAssembler.cpp currently... diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index 63f15c885..1ad0a2cf1 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -3568,7 +3568,7 @@ enum PartyResult }; #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 10 +#define MMAP_VERSION 11 struct MmapTileHeader { diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 695fd7a29..389ad6a1d 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -387,6 +387,7 @@ uint16 liquid_entry[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; float liquid_height[ADT_GRID_SIZE + 1][ADT_GRID_SIZE + 1]; +uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; int16 flight_box_max[3][3]; int16 flight_box_min[3][3]; @@ -409,6 +410,8 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int memset(liquid_flags, 0, sizeof(liquid_flags)); memset(liquid_entry, 0, sizeof(liquid_entry)); + memset(holes, 0, sizeof(holes)); + // Prepare map header map_fileheader map; map.mapMagic = *reinterpret_cast(MAP_MAGIC); @@ -861,15 +864,6 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int map.liquidMapSize += sizeof(float) * liquidHeader.width * liquidHeader.height; } - // map hole info - uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; - - if (map.liquidMapOffset) - map.holesOffset = map.liquidMapOffset + map.liquidMapSize; - else - map.holesOffset = map.heightMapOffset + map.heightMapSize; - - memset(holes, 0, sizeof(holes)); bool hasHoles = false; for (int i = 0; i < ADT_CELLS_PER_GRID; ++i) @@ -886,9 +880,19 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } if (hasHoles) + { + if (map.liquidMapOffset) + map.holesOffset = map.liquidMapOffset + map.liquidMapSize; + else + map.holesOffset = map.heightMapOffset + map.heightMapSize; + map.holesSize = sizeof(holes); + } else + { + map.holesOffset = 0; map.holesSize = 0; + } // Ok all data prepared - store it FILE* output = fopen(outputPath.c_str(), "wb"); diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 5f205851c..866b63c96 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -21,7 +21,7 @@ namespace DisableMgr } #define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 10 +#define MMAP_VERSION 11 struct MmapTileHeader { diff --git a/src/tools/vmap4_extractor/CMakeLists.txt b/src/tools/vmap4_extractor/CMakeLists.txt index 4dc52004f..735973707 100644 --- a/src/tools/vmap4_extractor/CMakeLists.txt +++ b/src/tools/vmap4_extractor/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(vmap4extractor ${PRIVATE_SOURCES}) target_link_libraries(vmap4extractor PUBLIC + g3dlib mpq) # Group sources diff --git a/src/tools/vmap4_extractor/adtfile.cpp b/src/tools/vmap4_extractor/adtfile.cpp index 6f5b37825..43b54038f 100644 --- a/src/tools/vmap4_extractor/adtfile.cpp +++ b/src/tools/vmap4_extractor/adtfile.cpp @@ -6,7 +6,6 @@ #include "vmapexport.h" #include "adtfile.h" - #include #include @@ -34,6 +33,9 @@ char* GetPlainName(char* FileName) void fixnamen(char* name, size_t len) { + if (len < 3) + return; + for (size_t i = 0; i < len - 3; i++) { if (i > 0 && name[i] >= 'A' && name[i] <= 'Z' && isalpha(name[i - 1])) @@ -41,6 +43,7 @@ void fixnamen(char* name, size_t len) else if ((i == 0 || !isalpha(name[i - 1])) && name[i] >= 'a' && name[i] <= 'z') name[i] &= ~0x20; } + //extension in lowercase for (size_t i = len - 3; i < len; i++) name[i] |= 0x20; @@ -48,11 +51,12 @@ void fixnamen(char* name, size_t len) void fixname2(char* name, size_t len) { + if (len < 3) + return; + for (size_t i = 0; i < len - 3; i++) - { if (name[i] == ' ') name[i] = '_'; - } } char* GetExtension(char* FileName) @@ -62,33 +66,17 @@ char* GetExtension(char* FileName) return nullptr; } -ADTFile::ADTFile(char* filename): ADT(filename), nWMO(0), nMDX(0), WmoInstansName(nullptr), ModelInstansName(nullptr) +ADTFile::ADTFile(char* filename): _file(filename) { Adtfilename.append(filename); } bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) { - if (ADT.isEof ()) + if (_file.isEof()) return false; uint32 size; - - string xMap; - string yMap; - - Adtfilename.erase(Adtfilename.find(".adt"), 4); - string TempMapNumber; - TempMapNumber = Adtfilename.substr(Adtfilename.length() - 6, 6); - xMap = TempMapNumber.substr(TempMapNumber.find("_") + 1, (TempMapNumber.find_last_of("_") - 1) - (TempMapNumber.find("_"))); - yMap = TempMapNumber.substr(TempMapNumber.find_last_of("_") + 1, (TempMapNumber.length()) - (TempMapNumber.find_last_of("_"))); - Adtfilename.erase((Adtfilename.length() - xMap.length() - yMap.length() - 2), (xMap.length() + yMap.length() + 2)); - //string AdtMapNumber = xMap + ' ' + yMap + ' ' + GetPlainName((char*)Adtfilename.c_str()); - //printf("Processing map %s...\n", AdtMapNumber.c_str()); - //printf("MapNumber = %s\n", TempMapNumber.c_str()); - //printf("xMap = %s\n", xMap.c_str()); - //printf("yMap = %s\n", yMap.c_str()); - std::string dirname = std::string(szWorkDirWmo) + "/dir_bin"; FILE* dirfile; dirfile = fopen(dirname.c_str(), "ab"); @@ -98,15 +86,15 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) return false; } - while (!ADT.isEof()) + while (!_file.isEof()) { char fourcc[5]; - ADT.read(&fourcc, 4); - ADT.read(&size, 4); + _file.read(&fourcc, 4); + _file.read(&size, 4); flipcc(fourcc); fourcc[4] = 0; - size_t nextpos = ADT.getPos() + size; + size_t nextpos = _file.getPos() + size; if (!strcmp(fourcc, "MCIN")) { @@ -119,17 +107,15 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) if (size) { char* buf = new char[size]; - ADT.read(buf, size); + _file.read(buf, size); char* p = buf; - int t = 0; - ModelInstansName = new string[size]; while (p < buf + size) { fixnamen(p, strlen(p)); char* s = GetPlainName(p); fixname2(s, strlen(s)); - ModelInstansName[t++] = s; + ModelInstanceNames.emplace_back(s); string path(p); ExtractSingleModel(path); @@ -144,17 +130,20 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) if (size) { char* buf = new char[size]; - ADT.read(buf, size); + _file.read(buf, size); char* p = buf; - int q = 0; - WmoInstansName = new string[size]; while (p < buf + size) { + std::string path(p); + char* s = GetPlainName(p); fixnamen(s, strlen(s)); fixname2(s, strlen(s)); + WmoInstanceNames.emplace_back(s); + + ExtractSingleWmo(path); + p += strlen(p) + 1; - WmoInstansName[q++] = s; } delete[] buf; } @@ -164,39 +153,38 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) { if (size) { - nMDX = (int)size / 36; - for (int i = 0; i < nMDX; ++i) + uint32 doodadCount = size / sizeof(ADT::MDDF); + for (uint32 i = 0; i < doodadCount; ++i) { - uint32 id; - ADT.read(&id, 4); - ModelInstance inst(ADT, ModelInstansName[id].c_str(), map_num, tileX, tileY, dirfile); + ADT::MDDF doodadDef; + _file.read(&doodadDef, sizeof(ADT::MDDF)); + Doodad::Extract(doodadDef, ModelInstanceNames[doodadDef.Id].c_str(), map_num, tileX, tileY, dirfile); } - delete[] ModelInstansName; } } else if (!strcmp(fourcc, "MODF")) { if (size) { - nWMO = (int)size / 64; - for (int i = 0; i < nWMO; ++i) + uint32 mapObjectCount = size / sizeof(ADT::MODF); + for (uint32 i = 0; i < mapObjectCount; ++i) { - uint32 id; - ADT.read(&id, 4); - WMOInstance inst(ADT, WmoInstansName[id].c_str(), map_num, tileX, tileY, dirfile); + ADT::MODF mapObjDef; + _file.read(&mapObjDef, sizeof(ADT::MODF)); + MapObject::Extract(mapObjDef, WmoInstanceNames[mapObjDef.Id].c_str(), map_num, tileX, tileY, dirfile); + Doodad::ExtractSet(WmoDoodads[WmoInstanceNames[mapObjDef.Id]], mapObjDef, map_num, tileX, tileY, dirfile); } - delete[] WmoInstansName; } } //====================== - ADT.seek(nextpos); + _file.seek(nextpos); } - ADT.close(); + _file.close(); fclose(dirfile); return true; } ADTFile::~ADTFile() { - ADT.close(); + _file.close(); } diff --git a/src/tools/vmap4_extractor/adtfile.h b/src/tools/vmap4_extractor/adtfile.h index ebb171159..6c32fa33a 100644 --- a/src/tools/vmap4_extractor/adtfile.h +++ b/src/tools/vmap4_extractor/adtfile.h @@ -94,20 +94,45 @@ struct MapChunkHeader uint32 effectId; }; +#pragma pack(push, 1) + +namespace ADT +{ + struct MDDF + { + uint32 Id; + uint32 UniqueId; + Vec3D Position; + Vec3D Rotation; + uint16 Scale; + uint16 Flags; + }; + + struct MODF + { + uint32 Id; + uint32 UniqueId; + Vec3D Position; + Vec3D Rotation; + AaBox3D Bounds; + uint16 Flags; + uint16 DoodadSet; // can be larger than number of doodad sets in WMO + uint16 NameSet; + uint16 Scale; + }; +} +#pragma pack(pop) + class ADTFile { private: - //size_t mcnk_offsets[256], mcnk_sizes[256]; - MPQFile ADT; - //mcell Mcell; - string Adtfilename; + MPQFile _file; + std::string Adtfilename; public: ADTFile(char* filename); ~ADTFile(); - int nWMO; - int nMDX; - string* WmoInstansName; - string* ModelInstansName; + std::vector WmoInstanceNames; + std::vector ModelInstanceNames; bool init(uint32 map_num, uint32 tileX, uint32 tileY); //void LoadMapChunks(); diff --git a/src/tools/vmap4_extractor/gameobject_extract.cpp b/src/tools/vmap4_extractor/gameobject_extract.cpp index 0baed72c1..c773b9a05 100644 --- a/src/tools/vmap4_extractor/gameobject_extract.cpp +++ b/src/tools/vmap4_extractor/gameobject_extract.cpp @@ -8,17 +8,16 @@ #include "dbcfile.h" #include "adtfile.h" #include "vmapexport.h" - #include #include bool ExtractSingleModel(std::string& fname) { - char* name = GetPlainName((char*)fname.c_str()); - char* ext = GetExtension(name); + if (fname.length() < 4) + return false; - // < 3.1.0 ADT MMDX section store filename.mdx filenames for corresponded .m2 file - if (!strcmp(ext, ".mdx")) + std::string extension = fname.substr(fname.length() - 4, 4); + if (extension == ".mdx" || extension == ".MDX" || extension == ".mdl" || extension == ".MDL") { // replace .mdx -> .m2 fname.erase(fname.length() - 2, 2); @@ -27,6 +26,12 @@ bool ExtractSingleModel(std::string& fname) // >= 3.1.0 ADT MMDX section store filename.m2 filenames for corresponded .m2 file // nothing do + std::string originalName = fname; + + char* name = GetPlainName((char*)fname.c_str()); + fixnamen(name, strlen(name)); + fixname2(name, strlen(name)); + std::string output(szWorkDirWmo); output += "/"; output += name; @@ -34,7 +39,7 @@ bool ExtractSingleModel(std::string& fname) if (FileExists(output.c_str())) return true; - Model mdl(fname); + Model mdl(originalName); if (!mdl.open()) return false; @@ -63,6 +68,8 @@ void ExtractGameobjectModels() return; } + fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, model_list); + for (const auto & it : dbc) { path = it.getString(1); @@ -81,8 +88,10 @@ void ExtractGameobjectModels() strToLower(ch_ext); bool result = false; + uint8 isWmo = 0; if (!strcmp(ch_ext, ".wmo")) { + isWmo = 1; result = ExtractSingleWmo(path); } else if (!strcmp(ch_ext, ".mdl")) @@ -100,6 +109,7 @@ void ExtractGameobjectModels() uint32 displayId = it.getUInt(0); uint32 path_length = strlen(name); fwrite(&displayId, sizeof(uint32), 1, model_list); + fwrite(&isWmo, sizeof(uint8), 1, model_list); fwrite(&path_length, sizeof(uint32), 1, model_list); fwrite(name, sizeof(char), path_length, model_list); } diff --git a/src/tools/vmap4_extractor/model.cpp b/src/tools/vmap4_extractor/model.cpp index 43a13dca2..ce92d0d2f 100644 --- a/src/tools/vmap4_extractor/model.cpp +++ b/src/tools/vmap4_extractor/model.cpp @@ -7,14 +7,16 @@ #include "vmapexport.h" #include "model.h" #include "wmo.h" -#include "mpq_libmpq04.h" +#include "adtfile.h" #include +#include "mpq_libmpq04.h" +#include #include #include +#include -Model::Model(std::string& filename) : filename(filename), vertices(nullptr), indices(nullptr) +Model::Model(std::string& filename) : filename(filename), header(), vertices(nullptr), indices(nullptr) { - memset(&header, 0, sizeof(header)); } bool Model::open() @@ -64,7 +66,7 @@ bool Model::ConvertToVMAPModel(const char* outfilename) printf("Can't create the output file '%s'\n", outfilename); return false; } - fwrite(szRawVMAPMagic, 8, 1, output); + fwrite(VMAP::RAW_VMAP_MAGIC, 8, 1, output); uint32 nVertices = header.nBoundingVertices; fwrite(&nVertices, sizeof(int), 1, output); uint32 nofgroups = 1; @@ -118,38 +120,20 @@ bool Model::ConvertToVMAPModel(const char* outfilename) return true; } -Vec3D fixCoordSystem(Vec3D v) + +Vec3D fixCoordSystem(Vec3D const& v) { return Vec3D(v.x, v.z, -v.y); } -Vec3D fixCoordSystem2(Vec3D v) +void Doodad::Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) { - return Vec3D(v.x, v.z, v.y); -} - -ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) -{ - float ff[3]; - f.read(&id, 4); - f.read(ff, 12); - pos = fixCoords(Vec3D(ff[0], ff[1], ff[2])); - f.read(ff, 12); - rot = Vec3D(ff[0], ff[1], ff[2]); - f.read(&scale, 2); - f.read(&flags, 2); - // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? - sc = scale / 1024.0f; - - char tempname[512]; + char tempname[1036]; sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName); FILE* input = fopen(tempname, "r+b"); if (!input) - { - //printf("ModelInstance::ModelInstance couldn't open %s\n", tempname); return; - } fseek(input, 8, SEEK_SET); // get the correct no of vertices int nVertices; @@ -159,37 +143,111 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID if (count != 1 || nVertices == 0) return; - uint16 adtId = 0;// not used for models - uint32 flags = MOD_M2; - if (tileX == 65 && tileY == 65) - flags |= MOD_WORLDSPAWN; + // scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float? + float sc = doodadDef.Scale / 1024.0f; - //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name + Vec3D position = fixCoords(doodadDef.Position); + + uint16 nameSet = 0;// not used for models + uint32 uniqueId = GenerateUniqueObjectId(doodadDef.UniqueId, 0); + uint32 tcflags = MOD_M2; + if (tileX == 65 && tileY == 65) + tcflags |= MOD_WORLDSPAWN; + + //write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); - fwrite(&flags, sizeof(uint32), 1, pDirfile); - fwrite(&adtId, sizeof(uint16), 1, pDirfile); - fwrite(&id, sizeof(uint32), 1, pDirfile); - fwrite(&pos, sizeof(float), 3, pDirfile); - fwrite(&rot, sizeof(float), 3, pDirfile); + fwrite(&tcflags, sizeof(uint32), 1, pDirfile); + fwrite(&nameSet, sizeof(uint16), 1, pDirfile); + fwrite(&uniqueId, sizeof(uint32), 1, pDirfile); + fwrite(&position, sizeof(Vec3D), 1, pDirfile); + fwrite(&doodadDef.Rotation, sizeof(Vec3D), 1, pDirfile); fwrite(&sc, sizeof(float), 1, pDirfile); uint32 nlen = strlen(ModelInstName); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(ModelInstName, sizeof(char), nlen, pDirfile); - - /* int realx1 = (int) ((float) pos.x / 533.333333f); - int realy1 = (int) ((float) pos.z / 533.333333f); - int realx2 = (int) ((float) pos.x / 533.333333f); - int realy2 = (int) ((float) pos.z / 533.333333f); - fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n", - MapName, - ModelInstName, - (float) pos.x, (float) pos.y, (float) pos.z, - (float) rot.x, (float) rot.y, (float) rot.z, - sc, - nVertices, - realx1, realy1, - realx2, realy2 - ); */ } + +void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) +{ + if (wmo.DoodadSet >= doodadData.Sets.size()) + return; + + G3D::Vector3 wmoPosition(wmo.Position.z, wmo.Position.x, wmo.Position.y); + G3D::Matrix3 wmoRotation = G3D::Matrix3::fromEulerAnglesZYX(G3D::toRadians(wmo.Rotation.y), G3D::toRadians(wmo.Rotation.x), G3D::toRadians(wmo.Rotation.z)); + + uint16 doodadId = 0; + WMO::MODS const& doodadSetData = doodadData.Sets[wmo.DoodadSet]; + for (uint16 doodadIndex : doodadData.References) + { + if (doodadIndex < doodadSetData.StartIndex || + doodadIndex >= doodadSetData.StartIndex + doodadSetData.Count) + continue; + + WMO::MODD const& doodad = doodadData.Spawns[doodadIndex]; + + char ModelInstName[1024]; + sprintf(ModelInstName, "%s", GetPlainName(&doodadData.Paths[doodad.NameIndex])); + uint32 nlen = strlen(ModelInstName); + fixnamen(ModelInstName, nlen); + fixname2(ModelInstName, nlen); + if (nlen > 3) + { + char const* extension = &ModelInstName[nlen - 4]; + if (!strcmp(extension, ".mdx") || !strcmp(extension, ".mdl")) + { + ModelInstName[nlen - 2] = '2'; + ModelInstName[nlen - 1] = '\0'; + } + } + + char tempname[1036]; + sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName); + FILE* input = fopen(tempname, "r+b"); + if (!input) + continue; + + fseek(input, 8, SEEK_SET); // get the correct no of vertices + int nVertices; + int count = fread(&nVertices, sizeof(int), 1, input); + fclose(input); + + if (count != 1 || nVertices == 0) + continue; + + assert(doodadId < std::numeric_limits::max()); + ++doodadId; + + G3D::Vector3 position = wmoPosition + (wmoRotation * G3D::Vector3(doodad.Position.x, doodad.Position.y, doodad.Position.z)); + + Vec3D rotation; + (G3D::Quat(doodad.Rotation.X, doodad.Rotation.Y, doodad.Rotation.Z, doodad.Rotation.W) + .toRotationMatrix() * wmoRotation) + .toEulerAnglesXYZ(rotation.z, rotation.x, rotation.y); + + rotation.z = G3D::toDegrees(rotation.z); + rotation.x = G3D::toDegrees(rotation.x); + rotation.y = G3D::toDegrees(rotation.y); + + uint16 nameSet = 0; // not used for models + uint32 uniqueId = GenerateUniqueObjectId(wmo.UniqueId, doodadId); + uint32 tcflags = MOD_M2; + if (tileX == 65 && tileY == 65) + tcflags |= MOD_WORLDSPAWN; + + //write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, name + fwrite(&mapID, sizeof(uint32), 1, pDirfile); + fwrite(&tileX, sizeof(uint32), 1, pDirfile); + fwrite(&tileY, sizeof(uint32), 1, pDirfile); + fwrite(&tcflags, sizeof(uint32), 1, pDirfile); + fwrite(&nameSet, sizeof(uint16), 1, pDirfile); + fwrite(&uniqueId, sizeof(uint32), 1, pDirfile); + fwrite(&position, sizeof(Vec3D), 1, pDirfile); + fwrite(&rotation, sizeof(Vec3D), 1, pDirfile); + fwrite(&doodad.Scale, sizeof(float), 1, pDirfile); + fwrite(&nlen, sizeof(uint32), 1, pDirfile); + fwrite(ModelInstName, sizeof(char), nlen, pDirfile); + } +} + diff --git a/src/tools/vmap4_extractor/model.h b/src/tools/vmap4_extractor/model.h index 008fce4c0..ad43b7357 100644 --- a/src/tools/vmap4_extractor/model.h +++ b/src/tools/vmap4_extractor/model.h @@ -13,8 +13,10 @@ #include class MPQFile; +struct WMODoodadData; +namespace ADT { struct MDDF; struct MODF; } -Vec3D fixCoordSystem(Vec3D v); +Vec3D fixCoordSystem(Vec3D const& v); class Model { @@ -39,16 +41,11 @@ public: ~Model() { _unload(); } }; -class ModelInstance +namespace Doodad { -public: - uint32 id{0}; - Vec3D pos, rot; - uint16 scale{0}, flags{0}; - float sc{0.0f}; + void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); - ModelInstance() {} - ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); -}; + void ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); +} #endif diff --git a/src/tools/vmap4_extractor/vec3d.h b/src/tools/vmap4_extractor/vec3d.h index d882e1855..d34c4e61f 100644 --- a/src/tools/vmap4_extractor/vec3d.h +++ b/src/tools/vmap4_extractor/vec3d.h @@ -126,6 +126,13 @@ public: } }; +class AaBox3D +{ +public: + Vec3D min; + Vec3D max; +}; + class Vec2D { public: @@ -233,4 +240,9 @@ inline void rotate(float x0, float y0, float* x, float* y, float angle) *y = xa * sinf(angle) + ya * cosf(angle) + y0; } +struct Quaternion +{ + float X, Y, Z, W; +}; + #endif diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index 679f0b624..f04455078 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -51,19 +52,24 @@ typedef struct unsigned int id; } map_id; -map_id* map_ids; -uint16* LiqType = nullptr; +std::vector map_ids; uint32 map_count; char output_path[128] = "."; char input_path[1024] = "."; bool hasInputPathParam = false; bool preciseVectorData = false; +std::unordered_map WmoDoodads; // Constants -//static const char * szWorkDirMaps = ".\\Maps"; -const char* szWorkDirWmo = "./Buildings"; -const char* szRawVMAPMagic = "VMAP044"; +char const* szWorkDirWmo = "./Buildings"; + +std::map, uint32> uniqueObjectIds; + +uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId) +{ + return uniqueObjectIds.emplace(std::make_pair(clientId, clientDoodadId), uint32(uniqueObjectIds.size() + 1)).first->second; +} // Local testing functions @@ -86,60 +92,16 @@ void strToLower(char* str) } } -// copied from contrib/extractor/System.cpp -void ReadLiquidTypeTableDBC() -{ - printf("Read LiquidType.dbc file..."); - DBCFile dbc("DBFilesClient\\LiquidType.dbc"); - if (!dbc.open()) - { - printf("Fatal error: Invalid LiquidType.dbc file format!\n"); - exit(1); - } - - size_t LiqType_count = dbc.getRecordCount(); - size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0); - LiqType = new uint16[LiqType_maxid + 1]; - memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16)); - - for (uint32 x = 0; x < LiqType_count; ++x) - LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); - - printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count); -} - -bool ExtractWmo() -{ - bool success = true; - - //const char* ParsArchiveNames[] = {"patch-2.MPQ", "patch.MPQ", "common.MPQ", "expansion.MPQ"}; - - for (ArchiveSet::const_iterator ar_itr = gOpenArchives.begin(); ar_itr != gOpenArchives.end() && success; ++ar_itr) - { - vector filelist; - - (*ar_itr)->GetFileListTo(filelist); - for (vector::iterator fname = filelist.begin(); fname != filelist.end() && success; ++fname) - { - if (fname->find(".wmo") != string::npos) - success = ExtractSingleWmo(*fname); - } - } - - if (success) - printf("\nExtract wmo complete (No (fatal) errors)\n"); - - return success; -} - bool ExtractSingleWmo(std::string& fname) { // Copy files from archive + std::string originalName = fname; char szLocalFile[1024]; - const char* plain_name = GetPlainName(fname.c_str()); + char* plain_name = GetPlainName(&fname[0]); + fixnamen(plain_name, strlen(plain_name)); + fixname2(plain_name, strlen(plain_name)); sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name); - fixnamen(szLocalFile, strlen(szLocalFile)); if (FileExists(szLocalFile)) return true; @@ -162,12 +124,12 @@ bool ExtractSingleWmo(std::string& fname) return true; bool file_ok = true; - std::cout << "Extracting " << fname << std::endl; - WMORoot froot(fname); + printf("Extracting %s\n", originalName.c_str()); + WMORoot froot(originalName); if (!froot.open()) { printf("Couldn't open RootWmo!!!\n"); - return true; + return false; } FILE* output = fopen(szLocalFile, "wb"); if (!output) @@ -176,6 +138,8 @@ bool ExtractSingleWmo(std::string& fname) return false; } froot.ConvertToVMAPRootWmo(output); + WMODoodadData& doodads = WmoDoodads[plain_name]; + std::swap(doodads, froot.DoodadData); int Wmo_nVertices = 0; //printf("root has %d groups\n", froot->nGroups); if (froot.nGroups != 0) @@ -204,6 +168,17 @@ bool ExtractSingleWmo(std::string& fname) } Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData); + for (uint16 groupReference : fgroup.DoodadReferences) + { + if (groupReference >= doodads.Spawns.size()) + continue; + + uint32 doodadNameIndex = doodads.Spawns[groupReference].NameIndex; + if (froot.ValidDoodadNames.find(doodadNameIndex) == froot.ValidDoodadNames.end()) + continue; + + doodads.References.insert(groupReference); + } } } @@ -221,13 +196,11 @@ void ParsMapFiles() { char fn[512]; //char id_filename[64]; - char id[10]; for (unsigned int i = 0; i < map_count; ++i) { - sprintf(id, "%03u", map_ids[i].id); - snprintf(fn, sizeof(fn), R"(World\Maps\%s\%s.wdt)", map_ids[i].name, map_ids[i].name); - WDTFile WDT(fn, map_ids[i].name); - if (WDT.init(id, map_ids[i].id)) + sprintf(fn,"World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name); + WDTFile WDT(fn,map_ids[i].name); + if (WDT.init(map_ids[i].id)) { printf("Processing Map %u\n[", map_ids[i].id); for (int x = 0; x < 64; ++x) @@ -490,11 +463,6 @@ int main(int argc, char** argv) printf("FATAL ERROR: None MPQ archive found by path '%s'. Use -d option with proper path.\n", input_path); return 1; } - ReadLiquidTypeTableDBC(); - - // extract data - if (success) - success = ExtractWmo(); //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx //map.dbc @@ -507,18 +475,28 @@ int main(int argc, char** argv) printf("FATAL ERROR: Map.dbc not found in data file.\n"); return 1; } - map_count = dbc->getRecordCount (); - map_ids = new map_id[map_count]; + map_count = dbc->getRecordCount(); + map_ids.resize(map_count); for (unsigned int x = 0; x < map_count; ++x) { - map_ids[x].id = dbc->getRecord (x).getUInt(0); - strcpy(map_ids[x].name, dbc->getRecord(x).getString(1)); + map_ids[x].id = dbc->getRecord(x).getUInt(0); + + char const* map_name = dbc->getRecord(x).getString(1); + size_t max_map_name_length = sizeof(map_ids[x].name); + if (strlen(map_name) >= max_map_name_length) + { + delete dbc; + printf("FATAL ERROR: Map name too long.\n"); + return 1; + } + + strncpy(map_ids[x].name, map_name, max_map_name_length); + map_ids[x].name[max_map_name_length - 1] = '\0'; printf("Map - %s\n", map_ids[x].name); } delete dbc; ParsMapFiles(); - delete [] map_ids; //nError = ERROR_SUCCESS; // Extract models, listed in DameObjectDisplayInfo.dbc ExtractGameobjectModels(); @@ -532,6 +510,5 @@ int main(int argc, char** argv) } printf("Extract %s. Work complete. No errors.\n", versionString); - delete [] LiqType; return 0; } diff --git a/src/tools/vmap4_extractor/vmapexport.h b/src/tools/vmap4_extractor/vmapexport.h index 024e8c224..fa901b662 100644 --- a/src/tools/vmap4_extractor/vmapexport.h +++ b/src/tools/vmap4_extractor/vmapexport.h @@ -7,7 +7,15 @@ #ifndef VMAPEXPORT_H #define VMAPEXPORT_H +#include "loadlib/loadlib.h" #include +#include + +namespace VMAP +{ + const char VMAP_MAGIC[] = "VMAP_4.5"; + const char RAW_VMAP_MAGIC[] = "VMAP045"; // used in extracted vmap files with raw data +} enum ModelFlags { @@ -16,8 +24,12 @@ enum ModelFlags MOD_HAS_BOUND = 1 << 2 }; -extern const char* szWorkDirWmo; -extern const char* szRawVMAPMagic; // vmap magic string for extracted raw vmap data +struct WMODoodadData; + +extern const char * szWorkDirWmo; +extern std::unordered_map WmoDoodads; + +uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId); bool FileExists(const char* file); void strToLower(char* str); diff --git a/src/tools/vmap4_extractor/wdtfile.cpp b/src/tools/vmap4_extractor/wdtfile.cpp index b344b8d2e..4c7feaac1 100644 --- a/src/tools/vmap4_extractor/wdtfile.cpp +++ b/src/tools/vmap4_extractor/wdtfile.cpp @@ -7,6 +7,7 @@ #include "vmapexport.h" #include "wdtfile.h" #include "adtfile.h" + #include char* wdtGetPlainName(char* FileName) @@ -18,14 +19,14 @@ char* wdtGetPlainName(char* FileName) return FileName; } -WDTFile::WDTFile(char* file_name, char* file_name1) : WDT(file_name), gWmoInstansName(nullptr), gnWMO(0) +WDTFile::WDTFile(char* file_name, char* file_name1) : _file(file_name) { filename.append(file_name1, strlen(file_name1)); } -bool WDTFile::init(char* /*map_id*/, unsigned int mapID) +bool WDTFile::init(uint32 mapId) { - if (WDT.isEof()) + if (_file.isEof()) { //printf("Can't find WDT file.\n"); return false; @@ -43,15 +44,15 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID) return false; } - while (!WDT.isEof()) + while (!_file.isEof()) { - WDT.read(fourcc, 4); - WDT.read(&size, 4); + _file.read(fourcc, 4); + _file.read(&size, 4); flipcc(fourcc); fourcc[4] = 0; - size_t nextpos = WDT.getPos() + size; + size_t nextpos = _file.getPos() + size; if (!strcmp(fourcc, "MAIN")) { @@ -62,16 +63,19 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID) if (size) { char* buf = new char[size]; - WDT.read(buf, size); + _file.read(buf, size); char* p = buf; - int q = 0; - gWmoInstansName = new string[size]; while (p < buf + size) { + std::string path(p); + char* s = wdtGetPlainName(p); fixnamen(s, strlen(s)); + fixname2(s, strlen(s)); p = p + strlen(p) + 1; - gWmoInstansName[q++] = s; + _wmoNames.push_back(s); + + ExtractSingleWmo(path); } delete[] buf; } @@ -81,29 +85,27 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID) // global wmo instance data if (size) { - gnWMO = (int)size / 64; - - for (int i = 0; i < gnWMO; ++i) + uint32 mapObjectCount = size / sizeof(ADT::MODF); + for (uint32 i = 0; i < mapObjectCount; ++i) { - int id; - WDT.read(&id, 4); - WMOInstance inst(WDT, gWmoInstansName[id].c_str(), mapID, 65, 65, dirfile); + ADT::MODF mapObjDef; + _file.read(&mapObjDef, sizeof(ADT::MODF)); + MapObject::Extract(mapObjDef, _wmoNames[mapObjDef.Id].c_str(), mapId, 65, 65, dirfile); + Doodad::ExtractSet(WmoDoodads[_wmoNames[mapObjDef.Id]], mapObjDef, mapId, 65, 65, dirfile); } - - delete[] gWmoInstansName; } } - WDT.seek((int)nextpos); + _file.seek((int)nextpos); } - WDT.close(); + _file.close(); fclose(dirfile); return true; } WDTFile::~WDTFile() { - WDT.close(); + _file.close(); } ADTFile* WDTFile::GetMap(int x, int z) diff --git a/src/tools/vmap4_extractor/wdtfile.h b/src/tools/vmap4_extractor/wdtfile.h index da80082d7..f87a64000 100644 --- a/src/tools/vmap4_extractor/wdtfile.h +++ b/src/tools/vmap4_extractor/wdtfile.h @@ -16,18 +16,18 @@ class ADTFile; class WDTFile { -private: - MPQFile WDT; - string filename; public: WDTFile(char* file_name, char* file_name1); - ~WDTFile(); - bool init(char* map_id, unsigned int mapID); - - string* gWmoInstansName; - int gnWMO; + ~WDTFile(void); + bool init(uint32 mapId); ADTFile* GetMap(int x, int z); + + std::vector _wmoNames; + +private: + MPQFile _file; + std::string filename; }; #endif diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp index 34d38916a..82bde3ae8 100644 --- a/src/tools/vmap4_extractor/wmo.cpp +++ b/src/tools/vmap4_extractor/wmo.cpp @@ -4,6 +4,7 @@ * Copyright (C) 2005-2009 MaNGOS */ +#include "adtfile.h" #include "wmo.h" #include "vec3d.h" #include "vmapexport.h" @@ -17,12 +18,9 @@ #undef max #include "mpq_libmpq04.h" -using namespace std; -extern uint16* LiqType; - -WMORoot::WMORoot(std::string& filename) - : filename(filename), col(0), nTextures(0), nGroups(0), nP(0), nLights(0), - nModels(0), nDoodads(0), nDoodadSets(0), RootWMOID(0), liquidType(0) +WMORoot::WMORoot(std::string const& filename) + : filename(filename), color(0), nTextures(0), nGroups(0), nPortals(0), nLights(0), + nDoodadNames(0), nDoodadDefs(0), nDoodadSets(0), RootWMOID(0), liquidType(0) { memset(bbcorn1, 0, sizeof(bbcorn1)); memset(bbcorn2, 0, sizeof(bbcorn2)); @@ -54,17 +52,47 @@ bool WMORoot::open() { f.read(&nTextures, 4); f.read(&nGroups, 4); - f.read(&nP, 4); + f.read(&nPortals, 4); f.read(&nLights, 4); - f.read(&nModels, 4); - f.read(&nDoodads, 4); + f.read(&nDoodadNames, 4); + f.read(&nDoodadDefs, 4); f.read(&nDoodadSets, 4); - f.read(&col, 4); + f.read(&color, 4); f.read(&RootWMOID, 4); f.read(bbcorn1, 12); f.read(bbcorn2, 12); f.read(&liquidType, 4); - break; + } + else if (!strcmp(fourcc, "MODS")) + { + DoodadData.Sets.resize(size / sizeof(WMO::MODS)); + f.read(DoodadData.Sets.data(), size); + } + else if (!strcmp(fourcc,"MODN")) + { + char* ptr = f.getPointer(); + char* end = ptr + size; + DoodadData.Paths = std::make_unique(size); + memcpy(DoodadData.Paths.get(), ptr, size); + while (ptr < end) + { + std::string path = ptr; + + char* s = GetPlainName(ptr); + fixnamen(s, strlen(s)); + fixname2(s, strlen(s)); + + uint32 doodadNameIndex = ptr - f.getPointer(); + ptr += path.length() + 1; + + if (ExtractSingleModel(path)) + ValidDoodadNames.insert(doodadNameIndex); + } + } + else if (!strcmp(fourcc,"MODD")) + { + DoodadData.Spawns.resize(size / sizeof(WMO::MODD)); + f.read(DoodadData.Spawns.data(), size); } /* else if (!strcmp(fourcc,"MOTX")) @@ -82,15 +110,6 @@ bool WMORoot::open() else if (!strcmp(fourcc,"MOLT")) { } - else if (!strcmp(fourcc,"MODN")) - { - } - else if (!strcmp(fourcc,"MODS")) - { - } - else if (!strcmp(fourcc,"MODD")) - { - } else if (!strcmp(fourcc,"MOSB")) { } @@ -117,7 +136,7 @@ bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile) { //printf("Convert RootWmo...\n"); - fwrite(szRawVMAPMagic, 1, 8, pOutfile); + fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, pOutfile); unsigned int nVectors = 0; fwrite(&nVectors, sizeof(nVectors), 1, pOutfile); // will be filled later fwrite(&nGroups, 4, 1, pOutfile); @@ -125,7 +144,7 @@ bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile) return true; } -WMOGroup::WMOGroup(std::string filename) : +WMOGroup::WMOGroup(std::string const& filename) : filename(std::move(filename)), MOPY(nullptr), MOVI(nullptr), MoviEx(nullptr), MOVT(nullptr), MOBA(nullptr), MobaEx(nullptr), hlq(nullptr), LiquEx(nullptr), LiquBytes(nullptr), groupName(0), descGroupName(0), mogpFlags(0), moprIdx(0), moprNItems(0), nBatchA(0), nBatchB(0), nBatchC(0), fogIdx(0), @@ -206,11 +225,16 @@ bool WMOGroup::open() moba_size = size / 2; f.read(MOBA, size); } - else if (!strcmp(fourcc, "MLIQ")) + else if (!strcmp(fourcc,"MODR")) + { + DoodadReferences.resize(size / sizeof(uint16)); + f.read(DoodadReferences.data(), size); + } + else if (!strcmp(fourcc,"MLIQ")) { liquflags |= 1; hlq = new WMOLiquidHeader(); - f.read(hlq, 0x1E); + f.read(hlq, sizeof(WMOLiquidHeader)); LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts; LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts]; f.read(LiquEx, LiquEx_size); @@ -391,7 +415,7 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool precise //------LIQU------------------------ if (LiquEx_size != 0) { - int LIQU_h[] = {0x5551494C, static_cast(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles* hlq->ytiles}; // "LIQU" + int LIQU_h[] = { 0x5551494C, static_cast(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles * hlq->ytiles }; // "LIQU" fwrite(LIQU_h, 4, 2, output); // according to WoW.Dev Wiki: @@ -472,28 +496,16 @@ WMOGroup::~WMOGroup() delete [] LiquBytes; } -WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) - : currx(0), curry(0), wmo(nullptr), doodadset(0), pos(), indx(0), id(0), d2(0), d3(0) +void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile) { - float ff[3]; - f.read(&id, 4); - f.read(ff, 12); - pos = Vec3D(ff[0], ff[1], ff[2]); - f.read(ff, 12); - rot = Vec3D(ff[0], ff[1], ff[2]); - f.read(ff, 12); - pos2 = Vec3D(ff[0], ff[1], ff[2]); - f.read(ff, 12); - pos3 = Vec3D(ff[0], ff[1], ff[2]); - f.read(&d2, 4); - - uint16 trash, adtId; - f.read(&adtId, 2); - f.read(&trash, 2); + // destructible wmo, do not dump. we can handle the vmap for these + // in dynamic tree (gameobject vmaps) + if ((mapObjDef.Flags & 0x1) != 0) + return; //-----------add_in _dir_file---------------- - char tempname[512]; + char tempname[1036]; sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName); FILE* input; input = fopen(tempname, "r+b"); @@ -512,46 +524,39 @@ WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint if (count != 1 || nVertices == 0) return; + Vec3D position = mapObjDef.Position; + float x, z; - x = pos.x; - z = pos.z; + x = position.x; + z = position.z; if (x == 0 && z == 0) { - pos.x = 533.33333f * 32; - pos.z = 533.33333f * 32; + position.x = 533.33333f * 32; + position.z = 533.33333f * 32; } - pos = fixCoords(pos); - pos2 = fixCoords(pos2); - pos3 = fixCoords(pos3); + position = fixCoords(position); + AaBox3D bounds; + bounds.min = fixCoords(mapObjDef.Bounds.min); + bounds.max = fixCoords(mapObjDef.Bounds.max); float scale = 1.0f; + uint32 uniqueId = GenerateUniqueObjectId(mapObjDef.UniqueId, 0); uint32 flags = MOD_HAS_BOUND; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; - //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name + //write mapID, tileX, tileY, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name fwrite(&mapID, sizeof(uint32), 1, pDirfile); fwrite(&tileX, sizeof(uint32), 1, pDirfile); fwrite(&tileY, sizeof(uint32), 1, pDirfile); fwrite(&flags, sizeof(uint32), 1, pDirfile); - fwrite(&adtId, sizeof(uint16), 1, pDirfile); - fwrite(&id, sizeof(uint32), 1, pDirfile); - fwrite(&pos, sizeof(float), 3, pDirfile); - fwrite(&rot, sizeof(float), 3, pDirfile); + fwrite(&mapObjDef.NameSet, sizeof(uint16), 1, pDirfile); + fwrite(&uniqueId, sizeof(uint32), 1, pDirfile); + fwrite(&position, sizeof(Vec3D), 1, pDirfile); + fwrite(&mapObjDef.Rotation, sizeof(Vec3D), 1, pDirfile); fwrite(&scale, sizeof(float), 1, pDirfile); - fwrite(&pos2, sizeof(float), 3, pDirfile); - fwrite(&pos3, sizeof(float), 3, pDirfile); + fwrite(&bounds, sizeof(AaBox3D), 1, pDirfile); uint32 nlen = strlen(WmoInstName); fwrite(&nlen, sizeof(uint32), 1, pDirfile); fwrite(WmoInstName, sizeof(char), nlen, pDirfile); - /* fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f 1.0 %d %d %d,%d %d\n", - MapName, - WmoInstName, - (float) x, (float) pos.y, (float) z, - (float) rot.x, (float) rot.y, (float) rot.z, - nVertices, - realx1, realy1, - realx2, realy2 - ); */ - // fclose(dirfile); } diff --git a/src/tools/vmap4_extractor/wmo.h b/src/tools/vmap4_extractor/wmo.h index a19b104de..186be4ae6 100644 --- a/src/tools/vmap4_extractor/wmo.h +++ b/src/tools/vmap4_extractor/wmo.h @@ -6,14 +6,18 @@ #ifndef WMO_H #define WMO_H -#define TILESIZE (533.33333f) -#define CHUNKSIZE ((TILESIZE) / 16.0f) +#include #include -#include +#include +#include + #include "vec3d.h" #include "loadlib/loadlib.h" +#define TILESIZE (533.33333f) +#define CHUNKSIZE ((TILESIZE) / 16.0f) + // MOPY flags enum MopyFlags { @@ -30,26 +34,60 @@ enum MopyFlags class WMOInstance; class WMOManager; class MPQFile; +namespace ADT { struct MODF; } + +namespace WMO +{ + struct MODS + { + char Name[20]; + uint32 StartIndex; // index of first doodad instance in this set + uint32 Count; // number of doodad instances in this set + char _pad[4]; + }; + + struct MODD + { + uint32 NameIndex : 24; + Vec3D Position; + Quaternion Rotation; + float Scale; + uint32 Color; + }; +} /* for whatever reason a certain company just can't stick to one coordinate system... */ static inline Vec3D fixCoords(const Vec3D& v) { return Vec3D(v.z, v.x, v.y); } +struct WMODoodadData +{ + std::vector Sets; + std::unique_ptr Paths; + std::vector Spawns; + std::unordered_set References; +}; + class WMORoot { private: std::string filename; public: - unsigned int col; - uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType; + unsigned int color; + uint32 nTextures, nGroups, nPortals, nLights, nDoodadNames, nDoodadDefs, nDoodadSets, RootWMOID, liquidType; float bbcorn1[3]; float bbcorn2[3]; - WMORoot(std::string& filename); + WMODoodadData DoodadData; + std::unordered_set ValidDoodadNames; + + WMORoot(std::string const& filename); bool open(); bool ConvertToVMAPRootWmo(FILE* output); }; +#pragma pack(push, 1) + struct WMOLiquidHeader { int xverts, yverts, xtiles, ytiles; @@ -66,6 +104,8 @@ struct WMOLiquidVert float height; }; +#pragma pack(pop) + class WMOGroup { private: @@ -98,29 +138,18 @@ public: int nTriangles; // number when loaded uint32 liquflags; - WMOGroup(std::string filename); + std::vector DoodadReferences; + + WMOGroup(std::string const& filename); ~WMOGroup(); bool open(); int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData); }; -class WMOInstance +namespace MapObject { - static std::set ids; -public: - std::string MapName; - int currx; - int curry; - WMOGroup* wmo; - int doodadset; - Vec3D pos; - Vec3D pos2, pos3, rot; - uint32 indx, id, d2, d3; - - WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); - - static void reset(); -}; + void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); +} #endif