From fbcb423f603db13f2e39e7c360d6cdabc2445f14 Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Tue, 24 Apr 2018 18:45:23 +0200 Subject: [PATCH] Tools: merged Master tools updates --- dep/fmt/fmt/printf.h | 3 + src/common/Collision/Maps/MapDefines.h | 28 +- src/common/Collision/Maps/TileAssembler.cpp | 57 +++- src/common/Collision/Maps/TileAssembler.h | 4 - .../Collision/Models/GameObjectModel.cpp | 23 +- src/common/Collision/Models/GameObjectModel.h | 17 +- src/common/Collision/Models/WorldModel.cpp | 56 +++- src/common/Collision/VMapDefinitions.h | 4 +- src/server/game/Maps/Map.cpp | 50 ++- src/server/game/Maps/Map.h | 7 +- src/server/game/Movement/PathGenerator.cpp | 9 +- src/server/game/Movement/PathGenerator.h | 2 +- src/tools/mmaps_generator/MapBuilder.cpp | 50 ++- src/tools/mmaps_generator/PathCommon.h | 14 - src/tools/mmaps_generator/PathGenerator.cpp | 70 +++-- src/tools/mmaps_generator/TerrainBuilder.cpp | 29 +- src/tools/vmap4_extractor/adtfile.cpp | 79 +++-- src/tools/vmap4_extractor/adtfile.h | 109 ++----- .../vmap4_extractor/gameobject_extract.cpp | 21 +- src/tools/vmap4_extractor/model.cpp | 193 ++++++++---- src/tools/vmap4_extractor/model.h | 20 +- src/tools/vmap4_extractor/vec3d.h | 11 + src/tools/vmap4_extractor/vmapexport.cpp | 44 +-- src/tools/vmap4_extractor/vmapexport.h | 8 +- src/tools/vmap4_extractor/wdtfile.cpp | 24 +- src/tools/vmap4_extractor/wmo.cpp | 289 +++++++++--------- src/tools/vmap4_extractor/wmo.h | 73 +++-- 27 files changed, 723 insertions(+), 571 deletions(-) diff --git a/dep/fmt/fmt/printf.h b/dep/fmt/fmt/printf.h index 46205a78eee..8867e75772b 100644 --- a/dep/fmt/fmt/printf.h +++ b/dep/fmt/fmt/printf.h @@ -15,6 +15,9 @@ #include "ostream.h" +#undef min +#undef max + namespace fmt { namespace internal { diff --git a/src/common/Collision/Maps/MapDefines.h b/src/common/Collision/Maps/MapDefines.h index 39088ef0dff..decbe75caee 100644 --- a/src/common/Collision/Maps/MapDefines.h +++ b/src/common/Collision/Maps/MapDefines.h @@ -5,7 +5,7 @@ #include "DetourNavMesh.h" const uint32 MMAP_MAGIC = 0x4d4d4150; // 'MMAP' -#define MMAP_VERSION 7 +#define MMAP_VERSION 8 struct MmapTileHeader { @@ -29,18 +29,22 @@ static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) + sizeof(MmapTileHeader::usesLiquids) + sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields"); -enum NavTerrain +enum NavArea { - NAV_EMPTY = 0x00, - NAV_GROUND = 0x01, - NAV_MAGMA = 0x02, - NAV_SLIME = 0x04, - NAV_WATER = 0x08, - NAV_UNUSED1 = 0x10, - NAV_UNUSED2 = 0x20, - NAV_UNUSED3 = 0x40, - NAV_UNUSED4 = 0x80 - // we only have 8 bits + NAV_AREA_EMPTY = 0, + // areas 1-60 will be used for destructible areas (currently skipped in vmaps, WMO with flag 1) + // ground is the highest value to make recast choose ground over water when merging surfaces very close to each other (shallow water would be walkable) + NAV_AREA_GROUND = 63, + NAV_AREA_WATER = 62, + NAV_AREA_MAGMA_SLIME = 61 // don't need to differentiate between them +}; + +enum NavTerrainFlag +{ + NAV_EMPTY = 0x00, + NAV_GROUND = 1 << (63 - NAV_AREA_GROUND), + NAV_WATER = 1 << (63 - NAV_AREA_WATER), + NAV_MAGMA_SLIME = 1 << (63 - NAV_AREA_MAGMA_SLIME) }; #endif /* _MAPDEFINES_H */ diff --git a/src/common/Collision/Maps/TileAssembler.cpp b/src/common/Collision/Maps/TileAssembler.cpp index 2714c8907aa..1b5cc88f200 100644 --- a/src/common/Collision/Maps/TileAssembler.cpp +++ b/src/common/Collision/Maps/TileAssembler.cpp @@ -54,7 +54,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) { boost::filesystem::create_directory(iDestDir); //init(); @@ -225,7 +225,7 @@ namespace VMAP ModelSpawn spawn; while (!feof(dirf)) { - // read mapID, tileX, tileY, Flags, adtID, ID, Pos, Rot, Scale, Bound_lo, Bound_hi, name + // 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; @@ -241,8 +241,10 @@ namespace VMAP printf("spawning Map %u\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), TileSpawn{ spawn.ID, spawn.flags })); } bool success = (ferror(dirf) == 0); @@ -298,14 +300,16 @@ namespace VMAP return true; } +#pragma pack(push, 1) struct WMOLiquidHeader { int xverts, yverts, xtiles, ytiles; float pos_x; float pos_y; float pos_z; - short type; + short material; }; +#pragma pack(pop) //================================================================= bool TileAssembler::convertRawFile(const std::string& pModelFilename) { @@ -349,6 +353,13 @@ 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) + { + fclose(model_list); + return; + } + FILE* model_list_copy = fopen((iDestDir + "/" + GAMEOBJECT_MODELS).c_str(), "wb"); if (!model_list_copy) { @@ -356,7 +367,10 @@ namespace VMAP return; } + fwrite(VMAP::VMAP_MAGIC, 1, 8, model_list_copy); + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (true) { @@ -364,7 +378,8 @@ namespace VMAP if (feof(model_list)) // EOF flag is only set after failed reading attempt break; - if (fread(&name_length, sizeof(uint32), 1, model_list) != 1 + 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) { @@ -409,6 +424,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); @@ -493,25 +509,34 @@ namespace VMAP delete[] vectorarray; } // ----- liquid - liquid = 0; - if (liquidflags& 1) + liquid = nullptr; + if (liquidflags & 3) { - WMOLiquidHeader hlq; READ_OR_RETURN(&blockId, 4); CMP_OR_RETURN(blockId, "LIQU"); READ_OR_RETURN(&blocksize, sizeof(int)); - READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader)); - liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), hlq.type); - uint32 size = hlq.xverts*hlq.yverts; - READ_OR_RETURN(liquid->GetHeightStorage(), size*sizeof(float)); - size = hlq.xtiles*hlq.ytiles; - READ_OR_RETURN(liquid->GetFlagsStorage(), size); + uint32 liquidType; + READ_OR_RETURN(&liquidType, sizeof(uint32)); + if (liquidflags & 1) + { + WMOLiquidHeader hlq; + READ_OR_RETURN(&hlq, sizeof(WMOLiquidHeader)); + liquid = new WmoLiquid(hlq.xtiles, hlq.ytiles, Vector3(hlq.pos_x, hlq.pos_y, hlq.pos_z), liquidType); + uint32 size = hlq.xverts * hlq.yverts; + READ_OR_RETURN(liquid->GetHeightStorage(), size * sizeof(float)); + size = hlq.xtiles * hlq.ytiles; + READ_OR_RETURN(liquid->GetFlagsStorage(), size); + } + else + { + liquid = new WmoLiquid(0, 0, Vector3::zero(), liquidType); + liquid->GetHeightStorage()[0] = bounds.high().z; + } } return true; } - GroupModel_Raw::~GroupModel_Raw() { delete liquid; diff --git a/src/common/Collision/Maps/TileAssembler.h b/src/common/Collision/Maps/TileAssembler.h index a79784c9451..ffb21a2ab6c 100644 --- a/src/common/Collision/Maps/TileAssembler.h +++ b/src/common/Collision/Maps/TileAssembler.h @@ -101,9 +101,7 @@ namespace VMAP private: std::string iDestDir; std::string iSrcDir; - bool (*iFilterMethod)(char *pName); G3D::Table iUniqueNameIds; - unsigned int iCurrentUniqueNameId; MapData mapData; std::set spawnedModelFiles; @@ -117,8 +115,6 @@ namespace VMAP 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); }; } // VMAP diff --git a/src/common/Collision/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index 1c5f7ada0b6..fb113172d7e 100644 --- a/src/common/Collision/Models/GameObjectModel.cpp +++ b/src/common/Collision/Models/GameObjectModel.cpp @@ -30,11 +30,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; @@ -53,7 +54,17 @@ void LoadGameObjectModelList(std::string const& dataPath) return; } + char magic[8]; + if (fread(magic, 1, 8, model_list_file) != 8 + || memcmp(magic, VMAP::VMAP_MAGIC, 8) != 0) + { + TC_LOG_ERROR("misc", "File '%s' has wrong header, expected %s.", VMAP::GAMEOBJECT_MODELS, VMAP::VMAP_MAGIC); + fclose(model_list_file); + return; + } + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (true) { @@ -62,7 +73,8 @@ void LoadGameObjectModelList(std::string const& dataPath) 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 + 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 @@ -78,10 +90,7 @@ void LoadGameObjectModelList(std::string const& dataPath) continue; } - model_list.insert - ( - ModelList::value_type(displayId, GameobjectModelData(std::string(buff, name_length), AABox(v1, v2))) - ); + 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/Models/GameObjectModel.h b/src/common/Collision/Models/GameObjectModel.h index a8dd8547750..3dec7fdfa1c 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -40,14 +40,15 @@ struct GameObjectDisplayInfoEntry; class TC_COMMON_API GameObjectModelOwnerBase { public: - virtual bool IsSpawned() const { return false; } - virtual uint32 GetDisplayId() const { return 0; } - virtual bool IsInPhase(PhaseShift const& /*phaseShift*/) const { return false; } - virtual G3D::Vector3 GetPosition() const { return G3D::Vector3::zero(); } - virtual float GetOrientation() const { return 0.0f; } - virtual float GetScale() const { return 1.0f; } - virtual void DebugVisualizeCorner(G3D::Vector3 const& /*corner*/) const { } - virtual ~GameObjectModelOwnerBase() { } + virtual ~GameObjectModelOwnerBase() = default; + + virtual bool IsSpawned() const = 0; + virtual uint32 GetDisplayId() const = 0; + virtual bool IsInPhase(PhaseShift const& /*phaseShift*/) const = 0; + virtual G3D::Vector3 GetPosition() const = 0; + virtual float GetOrientation() const = 0; + virtual float GetScale() const = 0; + virtual void DebugVisualizeCorner(G3D::Vector3 const& /*corner*/) const = 0; }; class TC_COMMON_API GameObjectModel /*, public Intersectable*/ diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index 58c47c1d630..465fda2f0ce 100644 --- a/src/common/Collision/Models/WorldModel.cpp +++ b/src/common/Collision/Models/WorldModel.cpp @@ -105,8 +105,16 @@ namespace VMAP WmoLiquid::WmoLiquid(uint32 width, uint32 height, const Vector3 &corner, uint32 type): iTilesX(width), iTilesY(height), iCorner(corner), iType(type) { - iHeight = new float[(width+1)*(height+1)]; - iFlags = new uint8[width*height]; + if (width && height) + { + iHeight = new float[(width + 1) * (height + 1)]; + iFlags = new uint8[width * height]; + } + else + { + iHeight = new float[1]; + iFlags = nullptr; + } } WmoLiquid::WmoLiquid(const WmoLiquid &other): iHeight(nullptr), iFlags(nullptr) @@ -149,6 +157,13 @@ namespace VMAP bool WmoLiquid::GetLiquidHeight(const Vector3 &pos, float &liqHeight) const { + // simple case + if (!iFlags) + { + liqHeight = iHeight[0]; + return true; + } + float tx_f = (pos.x - iCorner.x)/LIQUID_TILE_SIZE; uint32 tx = uint32(tx_f); if (tx_f < 0.0f || tx >= iTilesX) @@ -200,8 +215,8 @@ namespace VMAP { return 2 * sizeof(uint32) + sizeof(Vector3) + - (iTilesX + 1)*(iTilesY + 1) * sizeof(float) + - iTilesX * iTilesY; + sizeof(uint32) + + (iFlags ? ((iTilesX + 1) * (iTilesY + 1) * sizeof(float) + iTilesX * iTilesY) : sizeof(float)); } bool WmoLiquid::writeToFile(FILE* wf) @@ -212,12 +227,17 @@ namespace VMAP fwrite(&iCorner, sizeof(Vector3), 1, wf) == 1 && fwrite(&iType, sizeof(uint32), 1, wf) == 1) { - uint32 size = (iTilesX + 1) * (iTilesY + 1); - if (fwrite(iHeight, sizeof(float), size, wf) == size) + if (iTilesX && iTilesY) { - size = iTilesX*iTilesY; - result = fwrite(iFlags, sizeof(uint8), size, wf) == size; + uint32 size = (iTilesX + 1) * (iTilesY + 1); + if (fwrite(iHeight, sizeof(float), size, wf) == size) + { + size = iTilesX * iTilesY; + result = fwrite(iFlags, sizeof(uint8), size, wf) == size; + } } + else + result = fwrite(iHeight, sizeof(float), 1, wf) == 1; } return result; @@ -233,13 +253,21 @@ namespace VMAP fread(&liquid->iCorner, sizeof(Vector3), 1, rf) == 1 && fread(&liquid->iType, sizeof(uint32), 1, rf) == 1) { - uint32 size = (liquid->iTilesX + 1) * (liquid->iTilesY + 1); - liquid->iHeight = new float[size]; - if (fread(liquid->iHeight, sizeof(float), size, rf) == size) + if (liquid->iTilesX && liquid->iTilesY) { - size = liquid->iTilesX * liquid->iTilesY; - liquid->iFlags = new uint8[size]; - result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size; + uint32 size = (liquid->iTilesX + 1) * (liquid->iTilesY + 1); + liquid->iHeight = new float[size]; + if (fread(liquid->iHeight, sizeof(float), size, rf) == size) + { + size = liquid->iTilesX * liquid->iTilesY; + liquid->iFlags = new uint8[size]; + result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size; + } + } + else + { + liquid->iHeight = new float[1]; + result = fread(liquid->iHeight, sizeof(float), 1, rf) == 1; } } diff --git a/src/common/Collision/VMapDefinitions.h b/src/common/Collision/VMapDefinitions.h index 5410eb2130c..c8f3f2fdbe3 100644 --- a/src/common/Collision/VMapDefinitions.h +++ b/src/common/Collision/VMapDefinitions.h @@ -25,8 +25,8 @@ namespace VMAP { - const char VMAP_MAGIC[] = "VMAP_4.5"; - const char RAW_VMAP_MAGIC[] = "VMAP045"; // used in extracted vmap files with raw data + const char VMAP_MAGIC[] = "VMAP_4.6"; + const char RAW_VMAP_MAGIC[] = "VMAP046"; // 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/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 4f9a9d38261..f4d9d044b6d 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1741,7 +1741,8 @@ GridMap::GridMap() m_V9 = nullptr; m_V8 = nullptr; // Liquid data - _liquidType = 0; + _liquidGlobalEntry = 0; + _liquidGlobalFlags = 0; _liquidOffX = 0; _liquidOffY = 0; _liquidWidth = 0; @@ -1901,7 +1902,8 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/) if (fread(&header, sizeof(header), 1, in) != 1 || header.fourcc != MapLiquidMagic.asUInt) return false; - _liquidType = header.liquidType; + _liquidGlobalEntry = header.liquidType; + _liquidGlobalFlags = header.liquidFlags; _liquidOffX = header.offsetX; _liquidOffY = header.offsetY; _liquidWidth = header.width; @@ -2196,7 +2198,7 @@ uint8 GridMap::getTerrainType(float x, float y) const inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) { // Check water type (if no water return) - if (!_liquidType && !_liquidFlags) + if (!_liquidGlobalFlags && !_liquidFlags) return LIQUID_MAP_NO_WATER; // Get cell @@ -2208,37 +2210,33 @@ inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 R // Check water type in cell int idx=(x_int>>3)*16 + (y_int>>3); - uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidType; - uint32 entry = 0; - if (_liquidEntry) + uint8 type = _liquidFlags ? _liquidFlags[idx] : _liquidGlobalFlags; + uint32 entry = _liquidEntry ? _liquidEntry[idx] : _liquidGlobalEntry; + if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry)) { - if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(_liquidEntry[idx])) + type &= MAP_LIQUID_TYPE_DARK_WATER; + uint32 liqTypeIdx = liquidEntry->Type; + if (entry < 21) { - entry = liquidEntry->Id; - type &= MAP_LIQUID_TYPE_DARK_WATER; - uint32 liqTypeIdx = liquidEntry->Type; - if (entry < 21) + if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) { - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) + uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; + if (!overrideLiquid && area->zone) { - uint32 overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; - if (!overrideLiquid && area->zone) - { - area = sAreaTableStore.LookupEntry(area->zone); - if (area) - overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; - } + area = sAreaTableStore.LookupEntry(area->zone); + if (area) + overrideLiquid = area->LiquidTypeOverride[liquidEntry->Type]; + } - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - entry = overrideLiquid; - liqTypeIdx = liq->Type; - } + if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) + { + entry = overrideLiquid; + liqTypeIdx = liq->Type; } } - - type |= 1 << liqTypeIdx; } + + type |= 1 << liqTypeIdx; } if (type == 0) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 31ee265d845..8d8beb07112 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -123,7 +123,8 @@ struct map_heightHeader struct map_liquidHeader { uint32 fourcc; - uint16 flags; + uint8 flags; + uint8 liquidFlags; uint16 liquidType; uint8 offsetX; uint8 offsetY; @@ -150,7 +151,6 @@ enum ZLiquidStatus : uint32 #define MAP_ALL_LIQUIDS (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME) #define MAP_LIQUID_TYPE_DARK_WATER 0x10 -#define MAP_LIQUID_TYPE_WMO_WATER 0x20 struct LiquidData { @@ -186,7 +186,8 @@ class TC_GAME_API GridMap uint8* _liquidFlags; float* _liquidMap; uint16 _gridArea; - uint16 _liquidType; + uint16 _liquidGlobalEntry; + uint8 _liquidGlobalFlags; uint8 _liquidOffX; uint8 _liquidOffY; uint8 _liquidWidth; diff --git a/src/server/game/Movement/PathGenerator.cpp b/src/server/game/Movement/PathGenerator.cpp index 52637c34bf3..8b2299fe62f 100644 --- a/src/server/game/Movement/PathGenerator.cpp +++ b/src/server/game/Movement/PathGenerator.cpp @@ -617,12 +617,12 @@ void PathGenerator::CreateFilter() // creatures don't take environmental damage if (creature->CanSwim()) - includeFlags |= (NAV_WATER | NAV_MAGMA | NAV_SLIME); // swim + includeFlags |= (NAV_WATER | NAV_MAGMA_SLIME); // swim } else // assume Player { // perfect support not possible, just stay 'safe' - includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA | NAV_SLIME); + includeFlags |= (NAV_GROUND | NAV_WATER | NAV_MAGMA_SLIME); } _filter.setIncludeFlags(includeFlags); @@ -646,7 +646,7 @@ void PathGenerator::UpdateFilter() } } -NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) +NavTerrainFlag PathGenerator::GetNavTerrain(float x, float y, float z) { LiquidData data; ZLiquidStatus liquidStatus = _sourceUnit->GetBaseMap()->GetLiquidStatus(_sourceUnit->GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &data); @@ -660,9 +660,8 @@ NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) case MAP_LIQUID_TYPE_OCEAN: return NAV_WATER; case MAP_LIQUID_TYPE_MAGMA: - return NAV_MAGMA; case MAP_LIQUID_TYPE_SLIME: - return NAV_SLIME; + return NAV_MAGMA_SLIME;; default: return NAV_GROUND; } diff --git a/src/server/game/Movement/PathGenerator.h b/src/server/game/Movement/PathGenerator.h index 3575ef7597a..8419095f2a4 100644 --- a/src/server/game/Movement/PathGenerator.h +++ b/src/server/game/Movement/PathGenerator.h @@ -122,7 +122,7 @@ class TC_GAME_API PathGenerator void BuildPointPath(float const* startPoint, float const* endPoint); void BuildShortcut(); - NavTerrain GetNavTerrain(float x, float y, float z); + NavTerrainFlag GetNavTerrain(float x, float y, float z); void CreateFilter(); void UpdateFilter(); diff --git a/src/tools/mmaps_generator/MapBuilder.cpp b/src/tools/mmaps_generator/MapBuilder.cpp index 5cc935d6944..accc4957486 100644 --- a/src/tools/mmaps_generator/MapBuilder.cpp +++ b/src/tools/mmaps_generator/MapBuilder.cpp @@ -16,42 +16,19 @@ * with this program. If not, see . */ -#include "PathCommon.h" #include "MapBuilder.h" +#include "MapDefines.h" #include "MapTree.h" -#include "DetourNavMeshBuilder.h" -#include "DetourNavMesh.h" +#include "ModelInstance.h" +#include "PathCommon.h" #include "IntermediateValues.h" #include "StringFormat.h" #include "VMapFactory.h" #include "VMapManager2.h" - -#include - -#define MMAP_MAGIC 0x4d4d4150 // 'MMAP' -#define MMAP_VERSION 7 - -struct MmapTileHeader -{ - uint32 mmapMagic; - uint32 dtVersion; - uint32 mmapVersion; - uint32 size; - char usesLiquids; - char padding[3]; - - MmapTileHeader() : mmapMagic(MMAP_MAGIC), dtVersion(DT_NAVMESH_VERSION), - mmapVersion(MMAP_VERSION), size(0), usesLiquids(true), padding() {} -}; - -// All padding fields must be handled and initialized to ensure mmaps_generator will produce binary-identical *.mmtile files -static_assert(sizeof(MmapTileHeader) == 20, "MmapTileHeader size is not correct, adjust the padding field size"); -static_assert(sizeof(MmapTileHeader) == (sizeof(MmapTileHeader::mmapMagic) + - sizeof(MmapTileHeader::dtVersion) + - sizeof(MmapTileHeader::mmapVersion) + - sizeof(MmapTileHeader::size) + - sizeof(MmapTileHeader::usesLiquids) + - sizeof(MmapTileHeader::padding)), "MmapTileHeader has uninitialized padding fields"); +#include +#include +#include +#include namespace MMAP { @@ -645,7 +622,7 @@ namespace MMAP // mark all walkable tiles, both liquids and solids unsigned char* triFlags = new unsigned char[tTriCount]; - memset(triFlags, NAV_GROUND, tTriCount*sizeof(unsigned char)); + memset(triFlags, NAV_AREA_GROUND, tTriCount*sizeof(unsigned char)); rcClearUnwalkableTriangles(m_rcContext, tileCfg.walkableSlopeAngle, tVerts, tVertCount, tTris, tTriCount, triFlags); rcRasterizeTriangles(m_rcContext, tVerts, tVertCount, tTris, triFlags, tTriCount, *tile.solid, config.walkableClimb); delete[] triFlags; @@ -751,8 +728,15 @@ namespace MMAP // set polygons as walkable // TODO: special flags for DYNAMIC polygons, ie surfaces that can be turned on and off for (int i = 0; i < iv.polyMesh->npolys; ++i) - if (iv.polyMesh->areas[i] & RC_WALKABLE_AREA) - iv.polyMesh->flags[i] = iv.polyMesh->areas[i]; + { + if (uint8 area = iv.polyMesh->areas[i] & RC_WALKABLE_AREA) + { + if (area >= NAV_AREA_MAGMA_SLIME) + iv.polyMesh->flags[i] = 1 << (63 - area); + else + iv.polyMesh->flags[i] = NAV_GROUND; // TODO: these will be dynamic in future + } + } // setup mesh parameters dtNavMeshCreateParams params; diff --git a/src/tools/mmaps_generator/PathCommon.h b/src/tools/mmaps_generator/PathCommon.h index 7129ac1080d..603a98088d8 100644 --- a/src/tools/mmaps_generator/PathCommon.h +++ b/src/tools/mmaps_generator/PathCommon.h @@ -32,20 +32,6 @@ #include #endif -enum NavTerrain -{ - NAV_EMPTY = 0x00, - NAV_GROUND = 0x01, - NAV_MAGMA = 0x02, - NAV_SLIME = 0x04, - NAV_WATER = 0x08, - NAV_UNUSED1 = 0x10, - NAV_UNUSED2 = 0x20, - NAV_UNUSED3 = 0x40, - NAV_UNUSED4 = 0x80 - // we only have 8 bits -}; - namespace MMAP { inline bool matchWildcardFilter(char const* filter, char const* str) diff --git a/src/tools/mmaps_generator/PathGenerator.cpp b/src/tools/mmaps_generator/PathGenerator.cpp index a3503ad08ce..4eda83319d0 100644 --- a/src/tools/mmaps_generator/PathGenerator.cpp +++ b/src/tools/mmaps_generator/PathGenerator.cpp @@ -28,6 +28,11 @@ using namespace MMAP; +namespace +{ + std::unordered_map _liquidTypes; +} + bool checkDirectories(bool debugOutput) { std::vector dirFiles; @@ -258,6 +263,49 @@ int finish(char const* message, int returnValue) return returnValue; } +std::unordered_map LoadLiquid() +{ + bool silent = false; + + DBCFileLoader* liquidDbc = new DBCFileLoader(); + std::unordered_map liquidData; + std::string liquidTypeSource = (boost::filesystem::path("dbc") / "LiquidType.dbc").string(); + char const* liquidTypeFmt = "nxxixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + + if (liquidDbc->Load(liquidTypeSource.c_str(), liquidTypeFmt)) + { + for (uint32 x = 0; x < liquidDbc->GetNumRows(); ++x) + { + DBCFileLoader::Record record = liquidDbc->getRecord(x); + liquidData[record.getUInt(0)] = record.getUInt(3); + } + } + + return liquidData; +} + +std::unordered_map> LoadMap() +{ + DBCFileLoader* mapDbc = new DBCFileLoader; + std::unordered_map> mapData; + std::string mapSource = (boost::filesystem::path("dbc") / "Map.dbc").string(); + char const* mapFmt = "nxxxxxxxxxxxxxxxxxxi"; + + if (mapDbc->Load(mapSource.c_str(), mapFmt)) + { + for (uint32 x = 0; x < mapDbc->GetNumRows(); ++x) + { + DBCFileLoader::Record record = mapDbc->getRecord(x); + mapData.emplace(std::piecewise_construct, std::forward_as_tuple(record.getUInt(0)), std::forward_as_tuple()); + int16 parentMapId = int16(record.getUInt(19)); + if (parentMapId != -1) + mapData[parentMapId].push_back(record.getUInt(0)); + } + } + + return mapData; +} + int main(int argc, char** argv) { Trinity::Banner::Show("MMAP generator", [](char const* text) { printf("%s\n", text); }, nullptr); @@ -300,28 +348,6 @@ int main(int argc, char** argv) if (!checkDirectories(debugOutput)) return silent ? -3 : finish("Press ENTER to close...", -3); - std::string mapPath = (boost::filesystem::path("dbc") / "Map.dbc").string(); - - std::unordered_map> mapData; - { - DBCFileLoader* loader = new DBCFileLoader(); - char const* mapFmt = "nxxxxxxxxxxxxxxxxxxi"; - if (!loader->Load(mapPath.c_str(), mapFmt)) - { - delete loader; - return silent ? -4 : finish("Failed to load Map.dbc", -4); - } - for (uint32 x = 0; x < loader->GetNumRows(); ++x) - { - mapData.emplace(std::piecewise_construct, std::forward_as_tuple(loader->getRecord(x).getUInt(0)), std::forward_as_tuple()); - int16 parentMapId = int16(loader->getRecord(x).getUInt(19)); - if (parentMapId != -1) - mapData[parentMapId].push_back(loader->getRecord(x).getUInt(0)); - } - - static_cast(VMAP::VMapFactory::createOrGetVMapManager())->InitializeThreadUnsafe(mapData); - } - MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds, debugOutput, bigBaseUnit, mapnum, offMeshInputPath); diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 9bca0dc04dd..b6e3f1cdcac 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -18,6 +18,7 @@ #include "TerrainBuilder.h" #include "MapBuilder.h" +#include "MapDefines.h" #include "MapTree.h" #include "ModelInstance.h" #include "VMapFactory.h" @@ -426,11 +427,9 @@ namespace MMAP useLiquid = false; } else if ((liquidType & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0) - liquidType = NAV_WATER; - else if (liquidType & MAP_LIQUID_TYPE_MAGMA) - liquidType = NAV_MAGMA; - else if (liquidType & MAP_LIQUID_TYPE_SLIME) - liquidType = NAV_SLIME; + liquidType = NAV_AREA_WATER; + else if ((liquidType & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0) + liquidType = NAV_AREA_MAGMA_SLIME; else useLiquid = false; } @@ -721,22 +720,14 @@ namespace MMAP vertsY = tilesY + 1; uint8* flags = liquid->GetFlagsStorage(); float* data = liquid->GetHeightStorage(); - uint8 type = NAV_EMPTY; + uint8 type = NAV_AREA_EMPTY; // convert liquid type to NavTerrain - switch (liquid->GetType() & 3) - { - case 0: - case 1: - type = NAV_WATER; - break; - case 2: - type = NAV_MAGMA; - break; - case 3: - type = NAV_SLIME; - break; - } + uint32 liquidFlags = vmapManager->GetLiquidFlagsPtr(liquid->GetType()); + if ((liquidFlags & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)) != 0) + type = NAV_AREA_WATER; + else if ((liquidFlags & (MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) != 0) + type = NAV_AREA_MAGMA_SLIME; // indexing is weird... // after a lot of trial and error, this is what works: diff --git a/src/tools/vmap4_extractor/adtfile.cpp b/src/tools/vmap4_extractor/adtfile.cpp index e01e79a9e49..2ed6cc41431 100644 --- a/src/tools/vmap4_extractor/adtfile.cpp +++ b/src/tools/vmap4_extractor/adtfile.cpp @@ -18,13 +18,10 @@ #include "vmapexport.h" #include "adtfile.h" - +#include "StringFormat.h" #include #include - -#ifdef WIN32 -#define snprintf _snprintf -#endif +#include "Errors.h" char const* GetPlainName(char const* FileName) { @@ -63,11 +60,12 @@ void FixNameCase(char* name, size_t len) void FixNameSpaces(char* name, size_t len) { - for (size_t i=0; i(); - 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")) { @@ -143,7 +141,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa if (size) { char* buf = new char[size]; - ADT.read(buf, size); + _file.read(buf, size); char* p = buf; int t = 0; ModelInstanceNames = new std::string[size]; @@ -169,7 +167,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa if (size) { char* buf = new char[size]; - ADT.read(buf, size); + _file.read(buf, size); char* p = buf; int q = 0; WmoInstanceNames = new std::string[size]; @@ -187,17 +185,27 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMa } } //====================== - else if (!strcmp(fourcc,"MDDF")) + else if (!strcmp(fourcc, "MDDF")) { if (size) { - nMDX = (int)size / 36; - for (int i=0; i* dirfileCache; public: ADTFile(char* filename, bool cache); ~ADTFile(); - int nWMO; - int nMDX; std::string* WmoInstanceNames; std::string* ModelInstanceNames; bool init(uint32 map_num, uint32 tileX, uint32 tileY, uint32 originalMapId); diff --git a/src/tools/vmap4_extractor/gameobject_extract.cpp b/src/tools/vmap4_extractor/gameobject_extract.cpp index 1af3e51a452..889fc9ff0b5 100644 --- a/src/tools/vmap4_extractor/gameobject_extract.cpp +++ b/src/tools/vmap4_extractor/gameobject_extract.cpp @@ -20,13 +20,17 @@ #include "dbcfile.h" #include "adtfile.h" #include "vmapexport.h" - +#include "VMapDefinitions.h" #include #include bool ExtractSingleModel(std::string& fname) { - if (fname.substr(fname.length() - 4, 4) == ".mdx") + if (fname.length() < 4) + return false; + + std::string extension = fname.substr(fname.length() - 4, 4); + if (extension == ".mdx" || extension == ".MDX" || extension == ".mdl" || extension == ".MDL") { fname.erase(fname.length() - 2, 2); fname.append("2"); @@ -76,6 +80,8 @@ void ExtractGameobjectModels() return; } + fwrite(VMAP::RAW_VMAP_MAGIC, 1, 8, model_list); + for (DBCFile::Iterator it = dbc.begin(); it != dbc.end(); ++it) { path = it->getString(1); @@ -91,12 +97,14 @@ void ExtractGameobjectModels() if (!ch_ext) continue; - strToLower(ch_ext); - bool result = false; - if (!strcmp(ch_ext, ".wmo")) + uint8 isWmo = 0; + if (!strcmp(ch_ext, ".WMO") && !strcmp(ch_ext, ".wmo")) + { + isWmo = 1; result = ExtractSingleWmo(path); - else if (!strcmp(ch_ext, ".mdl")) // TODO: extract .mdl files, if needed + } + else if (!strcmp(ch_ext, ".MDL") && !strcmp(ch_ext, ".mdl")) // TODO: extract .mdl files, if needed continue; else //if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2")) result = ExtractSingleModel(path); @@ -106,6 +114,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 d797a28a61f..15e10fcd0cf 100644 --- a/src/tools/vmap4_extractor/model.cpp +++ b/src/tools/vmap4_extractor/model.cpp @@ -17,13 +17,16 @@ */ #include "vmapexport.h" +#include "Errors.h" #include "model.h" #include "wmo.h" #include "adtfile.h" #include "mpqfile.h" -#include +#include "VMapDefinitions.h" +#include #include #include +#include extern HANDLE WorldMpq; @@ -79,7 +82,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; @@ -135,39 +138,23 @@ bool Model::ConvertToVMAPModel(const char * outfilename) } -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, uint32 originalMapId, + FILE* pDirfile, std::vector* dirfileCache) { - return Vec3D(v.x, v.z, v.y); -} - -ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache) - : id(0), scale(0), flags(0) -{ - 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; + float sc = doodadDef.Scale / 1024.0f; char tempname[512]; 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; @@ -177,22 +164,25 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID if (count != 1 || nVertices == 0) return; - uint16 adtId = 0;// not used for models + Vec3D position = fixCoords(doodadDef.Position); + + uint16 nameSet = 0;// not used for models + uint32 uniqueId = GenerateUniqueObjectId(doodadDef.UniqueId, 0); uint32 flags = MOD_M2; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; if (mapID != originalMapId) flags |= MOD_PARENT_SPAWN; - //write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name + //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(&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); @@ -204,41 +194,134 @@ ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID ADTOutputCache& cacheModelData = dirfileCache->back(); cacheModelData.Flags = flags & ~MOD_PARENT_SPAWN; cacheModelData.Data.resize( - sizeof(uint16) + // adtId - sizeof(uint32) + // id - sizeof(float) * 3 + // pos - sizeof(float) * 3 + // rot + sizeof(uint16) + // nameSet + sizeof(uint32) + // uniqueId + sizeof(Vec3D) + // position + sizeof(Vec3D) + // doodadDef.Rotation sizeof(float) + // sc sizeof(uint32) + // nlen nlen); // ModelInstName uint8* cacheData = cacheModelData.Data.data(); -#define CACHE_WRITE(value, size, count, dest) memcpy(dest, value, size * count); dest += size * count; +#define CACHE_WRITE(value, size, cnt, dest) memcpy(dest, value, size * cnt); dest += size * cnt; - CACHE_WRITE(&adtId, sizeof(uint16), 1, cacheData); - CACHE_WRITE(&id, sizeof(uint32), 1, cacheData); - CACHE_WRITE(&pos, sizeof(float), 3, cacheData); - CACHE_WRITE(&rot, sizeof(float), 3, cacheData); + CACHE_WRITE(&nameSet, sizeof(uint16), 1, cacheData); + CACHE_WRITE(&uniqueId, sizeof(uint32), 1, cacheData); + CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData); + CACHE_WRITE(&doodadDef.Rotation, sizeof(Vec3D), 1, cacheData); CACHE_WRITE(&sc, sizeof(float), 1, cacheData); CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData); CACHE_WRITE(ModelInstName, sizeof(char), nlen, cacheData); + } +} + +void Doodad::ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, + FILE* pDirfile, std::vector* dirfileCache) +{ + 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); + FixNameCase(ModelInstName, nlen); + FixNameSpaces(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[512]; + 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; + if (mapID != originalMapId) + tcflags |= MOD_PARENT_SPAWN; + + //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); + + if (dirfileCache) + { + dirfileCache->emplace_back(); + ADTOutputCache& cacheModelData = dirfileCache->back(); + cacheModelData.Flags = tcflags & ~MOD_PARENT_SPAWN; + cacheModelData.Data.resize( + sizeof(uint16) + // nameSet + sizeof(uint32) + // uniqueId + sizeof(Vec3D) + // position + sizeof(Vec3D) + // rotation + sizeof(float) + // doodad.Scale + sizeof(uint32) + // nlen + nlen); // ModelInstName + + uint8* cacheData = cacheModelData.Data.data(); + CACHE_WRITE(&nameSet, sizeof(uint16), 1, cacheData); + CACHE_WRITE(&uniqueId, sizeof(uint32), 1, cacheData); + CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData); + CACHE_WRITE(&rotation, sizeof(Vec3D), 1, cacheData); + CACHE_WRITE(&doodad.Scale, sizeof(float), 1, cacheData); + CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData); + CACHE_WRITE(ModelInstName, sizeof(char), nlen, cacheData); + } + } +} #undef CACHE_WRITE - } - - /* 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 - ); */ -} diff --git a/src/tools/vmap4_extractor/model.h b/src/tools/vmap4_extractor/model.h index 8376a50e036..eb4c35cb096 100644 --- a/src/tools/vmap4_extractor/model.h +++ b/src/tools/vmap4_extractor/model.h @@ -25,8 +25,10 @@ class MPQFile; struct ADTOutputCache; +struct WMODoodadData; +namespace ADT { struct MDDF; struct MODF; } -Vec3D fixCoordSystem(Vec3D v); +Vec3D fixCoordSystem(Vec3D const& v); class Model { @@ -51,17 +53,13 @@ public: ~Model() { _unload(); } }; -class ModelInstance +namespace Doodad { -public: - uint32 id; - Vec3D pos, rot; - uint16 scale, flags; - float sc; + void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, + FILE* pDirfile, std::vector* dirfileCache); - ModelInstance() : id(0), scale(0), flags(0), sc(0.0f) {} - ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache); - -}; + void ExtractSet(WMODoodadData const& doodadData, ADT::MODF const& wmo, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, + FILE* pDirfile, std::vector* dirfileCache); +} #endif diff --git a/src/tools/vmap4_extractor/vec3d.h b/src/tools/vmap4_extractor/vec3d.h index 0fa5f328e58..ae64bdad615 100644 --- a/src/tools/vmap4_extractor/vec3d.h +++ b/src/tools/vmap4_extractor/vec3d.h @@ -137,6 +137,12 @@ public: } }; +class AaBox3D +{ +public: + Vec3D min; + Vec3D max; +}; class Vec2D { @@ -245,4 +251,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 68398bdc77b..ef83a0f3390 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -127,12 +127,11 @@ std::unordered_map LiquidTypes; char output_path[128]="."; char input_path[1024]="."; bool preciseVectorData = false; +std::unordered_map WmoDoodads; // Constants -//static const char * szWorkDirMaps = ".\\Maps"; char const* szWorkDirWmo = "./Buildings"; -char const* szRawVMAPMagic = "VMAP045"; bool LoadLocaleMPQFile(int locale) { @@ -247,7 +246,12 @@ void LoadCommonMPQFiles(uint32 build) printf("\n"); } +std::map, uint32> uniqueObjectIds; +uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId) +{ + return uniqueObjectIds.emplace(std::make_pair(clientId, clientDoodadId), uniqueObjectIds.size() + 1).first->second; +} // Local testing functions bool FileExists(char const* file) @@ -260,15 +264,6 @@ bool FileExists(char const* file) return false; } -void strToLower(char* str) -{ - while(*str) - { - *str=tolower(*str); - ++str; - } -} - // copied from contrib/extractor/System.cpp void ReadLiquidMaterialTable() { @@ -360,11 +355,13 @@ bool ExtractWmo() 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]); + FixNameCase(plain_name, strlen(plain_name)); + FixNameSpaces(plain_name, strlen(plain_name)); sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name); - FixNameCase(szLocalFile,strlen(szLocalFile)); if (FileExists(szLocalFile)) return true; @@ -388,8 +385,8 @@ bool ExtractSingleWmo(std::string& fname) return true; bool file_ok = true; - std::cout << "Extracting " << fname << std::endl; - WMORoot froot(fname); + std::cout << "Extracting " << originalName << std::endl; + WMORoot froot(originalName); if (!froot.open()) { printf("Couldn't open RootWmo!!!\n"); @@ -402,6 +399,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) @@ -417,14 +416,25 @@ bool ExtractSingleWmo(std::string& fname) std::string s = groupFileName; WMOGroup fgroup(s); - if (!fgroup.open()) + if (!fgroup.open(&froot)) { printf("Could not open all Group file for: %s\n", plain_name); file_ok = false; break; } - Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData); + Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, 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); + } } } diff --git a/src/tools/vmap4_extractor/vmapexport.h b/src/tools/vmap4_extractor/vmapexport.h index c798fb496ba..3be4bbe4a98 100644 --- a/src/tools/vmap4_extractor/vmapexport.h +++ b/src/tools/vmap4_extractor/vmapexport.h @@ -19,7 +19,11 @@ #ifndef VMAPEXPORT_H #define VMAPEXPORT_H +#include "Define.h" #include +#include + +struct WMODoodadData; enum ModelFlags { @@ -30,10 +34,10 @@ enum ModelFlags }; extern const char * szWorkDirWmo; -extern const char * szRawVMAPMagic; // vmap magic string for extracted raw vmap data +extern std::unordered_map WmoDoodads; +uint32 GenerateUniqueObjectId(uint32 clientId, uint16 clientDoodadId); bool FileExists(const char * file); -void strToLower(char* str); bool ExtractSingleWmo(std::string& fname); bool ExtractSingleModel(std::string& fname); diff --git a/src/tools/vmap4_extractor/wdtfile.cpp b/src/tools/vmap4_extractor/wdtfile.cpp index 86e4bcef46d..1e5f0044ba1 100644 --- a/src/tools/vmap4_extractor/wdtfile.cpp +++ b/src/tools/vmap4_extractor/wdtfile.cpp @@ -19,7 +19,7 @@ #include "vmapexport.h" #include "wdtfile.h" #include "adtfile.h" - +#include "StringFormat.h" #include char * wdtGetPlainName(char * FileName) @@ -104,13 +104,23 @@ bool WDTFile::init(uint32 mapId) // global wmo instance data if (size) { - int32 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; - _file.read(&id, 4); - WMOInstance inst(_file, _wmoNames[id].c_str(), mapId, 65, 65, mapId, dirfile, nullptr); + ADT::MODF mapObjDef; + _file.read(&mapObjDef, sizeof(ADT::MODF)); + if (!(mapObjDef.Flags & 0x8)) + { + MapObject::Extract(mapObjDef, _wmoNames[mapObjDef.Id].c_str(), mapId, 65, 65, mapId, dirfile, nullptr); + Doodad::ExtractSet(WmoDoodads[_wmoNames[mapObjDef.Id]], mapObjDef, mapId, 65, 65, mapId, dirfile, nullptr); + } + else + { + std::string fileName = Trinity::StringFormat("FILE%08X.xxx", mapObjDef.Id); + ExtractSingleWmo(fileName); + MapObject::Extract(mapObjDef, fileName.c_str(), mapId, 65, 65, mapId, dirfile, nullptr); + Doodad::ExtractSet(WmoDoodads[fileName], mapObjDef, mapId, 65, 65, mapId, dirfile, nullptr); + } } } } diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp index 74bb69b5117..ba44d14a650 100644 --- a/src/tools/vmap4_extractor/wmo.cpp +++ b/src/tools/vmap4_extractor/wmo.cpp @@ -17,20 +17,19 @@ */ #include "vmapexport.h" -#include "wmo.h" #include "adtfile.h" +#include "mpqfile.h" #include "vec3d.h" - +#include "VMapDefinitions.h" +#include "wmo.h" +#include +#include #include #include -#include -#undef min -#undef max -#include "mpqfile.h" extern uint16 *LiqType; -WMORoot::WMORoot(std::string &filename) +WMORoot::WMORoot(std::string const& filename) : filename(filename), col(0), nTextures(0), nGroups(0), nP(0), nLights(0), nModels(0), nDoodads(0), nDoodadSets(0), RootWMOID(0), liquidType(0) { @@ -78,6 +77,37 @@ bool WMORoot::open() 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); + FixNameCase(s, strlen(s)); + FixNameSpaces(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")) { @@ -94,15 +124,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")) { } @@ -129,7 +150,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); @@ -141,14 +162,14 @@ WMOGroup::WMOGroup(const std::string &filename) : filename(filename), MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0), hlq(0), LiquEx(0), LiquBytes(0), groupName(0), descGroupName(0), mogpFlags(0), moprIdx(0), moprNItems(0), nBatchA(0), nBatchB(0), nBatchC(0), fogIdx(0), - liquidType(0), groupWMOID(0), mopy_size(0), moba_size(0), LiquEx_size(0), + groupLiquid(0), groupWMOID(0), mopy_size(0), moba_size(0), LiquEx_size(0), nVertices(0), nTriangles(0), liquflags(0) { memset(bbcorn1, 0, sizeof(bbcorn1)); memset(bbcorn2, 0, sizeof(bbcorn2)); } -bool WMOGroup::open() +bool WMOGroup::open(WMORoot* rootWMO) { MPQFile f(WorldMpq, filename.c_str()); if (f.isEof ()) @@ -170,7 +191,7 @@ bool WMOGroup::open() fourcc[4] = 0; size_t nextpos = f.getPos() + size; - if (!strcmp(fourcc,"MOGP"))//header + if (!strcmp(fourcc,"MOGP")) //header { f.read(&groupName, 4); f.read(&descGroupName, 4); @@ -183,8 +204,19 @@ bool WMOGroup::open() f.read(&nBatchB, 2); f.read(&nBatchC, 4); f.read(&fogIdx, 4); - f.read(&liquidType, 4); - f.read(&groupWMOID,4); + f.read(&groupLiquid, 4); + f.read(&groupWMOID, 4); + + // according to WoW.Dev Wiki: + if (rootWMO->liquidType & 4) + groupLiquid = GetLiquidTypeId(groupLiquid); + else if (groupLiquid == 15) + groupLiquid = 0; + else + groupLiquid = GetLiquidTypeId(groupLiquid + 1); + + if (groupLiquid) + liquflags |= 2; } else if (!strcmp(fourcc,"MOPY")) @@ -217,11 +249,16 @@ bool WMOGroup::open() moba_size = size/2; f.read(MOBA, size); } + 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); @@ -229,6 +266,19 @@ bool WMOGroup::open() LiquBytes = new char[nLiquBytes]; f.read(LiquBytes, nLiquBytes); + // Determine legacy liquid type + if (!groupLiquid) + { + for (int i = 0; i < hlq->xtiles * hlq->ytiles; ++i) + { + if ((LiquBytes[i] & 0xF) != 15) + { + groupLiquid = GetLiquidTypeId((LiquBytes[i] & 0xF) + 1); + break; + } + } + } + /* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app); llog << filename; llog << "\nbbox: " << bbcorn1[0] << ", " << bbcorn1[1] << ", " << bbcorn1[2] << " | " << bbcorn2[0] << ", " << bbcorn2[1] << ", " << bbcorn2[2]; @@ -242,7 +292,7 @@ bool WMOGroup::open() return true; } -int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool preciseVectorData) +int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, bool preciseVectorData) { fwrite(&mogpFlags,sizeof(uint32),1,output); fwrite(&groupWMOID,sizeof(uint32),1,output); @@ -401,78 +451,54 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool precise } //------LIQU------------------------ - if (LiquEx_size != 0) + if (liquflags & 3) { - int LIQU_h[] = {0x5551494C, static_cast(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles*hlq->ytiles};// "LIQU" + int LIQU_totalSize = sizeof(uint32); + if (liquflags & 1) + { + LIQU_totalSize += sizeof(WMOLiquidHeader); + LIQU_totalSize += LiquEx_size / sizeof(WMOLiquidVert) * sizeof(float); + LIQU_totalSize += hlq->xtiles * hlq->ytiles; + } + int LIQU_h[] = { 0x5551494C, LIQU_totalSize };// "LIQU" fwrite(LIQU_h, 4, 2, output); - // according to WoW.Dev Wiki: - uint32 liquidEntry; - if (rootWMO->liquidType & 4) - liquidEntry = liquidType; - else if (liquidType == 15) - liquidEntry = 0; - else - liquidEntry = liquidType + 1; - - if (!liquidEntry) - { - int v1; // edx@1 - int v2; // eax@1 - - v1 = hlq->xtiles * hlq->ytiles; - v2 = 0; - if (v1 > 0) - { - while ((LiquBytes[v2] & 0xF) == 15) - { - ++v2; - if (v2 >= v1) - break; - } - - if (v2 < v1 && (LiquBytes[v2] & 0xF) != 15) - liquidEntry = (LiquBytes[v2] & 0xF) + 1; - } - } - - if (liquidEntry && liquidEntry < 21) - { - switch ((liquidEntry - 1) & 3) - { - case 0: - liquidEntry = ((mogpFlags & 0x80000) != 0) + 13; - break; - case 1: - liquidEntry = 14; - break; - case 2: - liquidEntry = 19; - break; - case 3: - liquidEntry = 20; - break; - } - } - - hlq->type = liquidEntry; - /* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app); llog << filename; - llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n"; + llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->flags << " group:" << flags << ")\n"; llog.close(); */ - fwrite(hlq, sizeof(WMOLiquidHeader), 1, output); - // only need height values, the other values are unknown anyway - for (uint32 i = 0; ixtiles*hlq->ytiles, output); + fwrite(&groupLiquid, sizeof(uint32), 1, output); + if (liquflags & 1) + { + fwrite(hlq, sizeof(WMOLiquidHeader), 1, output); + // only need height values, the other values are unknown anyway + for (uint32 i = 0; i < LiquEx_size / sizeof(WMOLiquidVert); ++i) + fwrite(&LiquEx[i].height, sizeof(float), 1, output); + // todo: compress to bit field + fwrite(LiquBytes, 1, hlq->xtiles * hlq->ytiles, output); + } } return nColTriangles; } +uint32 WMOGroup::GetLiquidTypeId(uint32 liquidTypeId) +{ + if (liquidTypeId < 21 && liquidTypeId) + { + switch (((static_cast(liquidTypeId) - 1) & 3)) + { + case 0: return ((mogpFlags & 0x80000) != 0) + 13; + case 1: return 14; + case 2: return 19; + case 3: return 20; + default: break; + } + } + return liquidTypeId; +} + WMOGroup::~WMOGroup() { delete [] MOPY; @@ -484,33 +510,11 @@ WMOGroup::~WMOGroup() delete [] LiquBytes; } -WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache) - : currx(0), curry(0), wmo(nullptr), doodadset(0), pos(), indx(0), id(0) +void MapObject::Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache) { - 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]); // bounding box corners - f.read(ff,12); - pos3 = Vec3D(ff[0],ff[1],ff[2]); // bounding box corners - - uint16 fflags; - f.read(&fflags, 2); - - uint16 doodadSet; - f.read(&doodadSet, 2); - - 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 ((fflags & 0x01) != 0) + if ((mapObjDef.Flags & 0x1) != 0) return; //-----------add_in _dir_file---------------- @@ -534,37 +538,40 @@ WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint if (count != 1 || nVertices == 0) return; - float x,z; - x = pos.x; - z = pos.z; - if (x==0 && z == 0) + Vec3D position = mapObjDef.Position; + + float x, 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; if (mapID != originalMapId) flags |= MOD_PARENT_SPAWN; - //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); @@ -575,41 +582,27 @@ WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint ADTOutputCache& cacheModelData = dirfileCache->back(); cacheModelData.Flags = flags & ~MOD_PARENT_SPAWN; cacheModelData.Data.resize( - sizeof(uint16) + // adtId - sizeof(uint32) + // id - sizeof(float) * 3 + // pos - sizeof(float) * 3 + // rot + sizeof(uint16) + // mapObjDef.NameSet + sizeof(uint32) + // uniqueId + sizeof(Vec3D) + // position + sizeof(Vec3D) + // mapObjDef.Rotation sizeof(float) + // scale - sizeof(float) * 3 + // pos2 - sizeof(float) * 3 + // pos3 + sizeof(AaBox3D) + // bounds sizeof(uint32) + // nlen nlen); // WmoInstName uint8* cacheData = cacheModelData.Data.data(); #define CACHE_WRITE(value, size, count, dest) memcpy(dest, value, size * count); dest += size * count; - CACHE_WRITE(&adtId, sizeof(uint16), 1, cacheData); - CACHE_WRITE(&id, sizeof(uint32), 1, cacheData); - CACHE_WRITE(&pos, sizeof(float), 3, cacheData); - CACHE_WRITE(&rot, sizeof(float), 3, cacheData); + CACHE_WRITE(&mapObjDef.NameSet, sizeof(uint16), 1, cacheData); + CACHE_WRITE(&uniqueId, sizeof(uint32), 1, cacheData); + CACHE_WRITE(&position, sizeof(Vec3D), 1, cacheData); + CACHE_WRITE(&mapObjDef.Rotation, sizeof(Vec3D), 1, cacheData); CACHE_WRITE(&scale, sizeof(float), 1, cacheData); - CACHE_WRITE(&pos2, sizeof(float), 3, cacheData); - CACHE_WRITE(&pos3, sizeof(float), 3, cacheData); + CACHE_WRITE(&bounds, sizeof(AaBox3D), 1, cacheData); CACHE_WRITE(&nlen, sizeof(uint32), 1, cacheData); CACHE_WRITE(WmoInstName, sizeof(char), nlen, cacheData); #undef CACHE_WRITE } - - /* 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 d85b2fd2af7..d54422209f0 100644 --- a/src/tools/vmap4_extractor/wmo.h +++ b/src/tools/vmap4_extractor/wmo.h @@ -18,11 +18,10 @@ #ifndef WMO_H #define WMO_H -#define TILESIZE (533.33333f) -#define CHUNKSIZE ((TILESIZE) / 16.0f) #include -#include +#include +#include #include "vec3d.h" #include "mpqfile.h" @@ -43,10 +42,40 @@ class WMOInstance; class WMOManager; class MPQFile; struct ADTOutputCache; +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: @@ -57,23 +86,25 @@ public: 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; float pos_x; float pos_y; float pos_z; - short type; + short material; }; -#pragma pack(push, 1) - struct WMOLiquidVert { uint16 unk1; @@ -107,7 +138,7 @@ public: uint16 moprNItems; uint16 nBatchA; uint16 nBatchB; - uint32 nBatchC, fogIdx, liquidType, groupWMOID; + uint32 nBatchC, fogIdx, groupLiquid, groupWMOID; int mopy_size, moba_size; int LiquEx_size; @@ -115,29 +146,19 @@ public: int nTriangles; // number when loaded uint32 liquflags; + std::vector DoodadReferences; + WMOGroup(std::string const& filename); ~WMOGroup(); - bool open(); - int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData); + bool open(WMORoot* rootWMO); + int ConvertToVMAPGroupWmo(FILE* output, bool preciseVectorData); + uint32 GetLiquidTypeId(uint32 liquidTypeId); }; -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; - - WMOInstance(MPQFile&f , char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache); - - static void reset(); -}; + void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, uint32 originalMapId, FILE* pDirfile, std::vector* dirfileCache); +} #endif