diff options
22 files changed, 443 insertions, 491 deletions
diff --git a/src/common/Collision/Maps/TileAssembler.cpp b/src/common/Collision/Maps/TileAssembler.cpp index 6c102af97bc..37dc0ee55a4 100644 --- a/src/common/Collision/Maps/TileAssembler.cpp +++ b/src/common/Collision/Maps/TileAssembler.cpp @@ -220,7 +220,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; @@ -296,14 +296,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) { @@ -347,6 +349,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) { @@ -354,7 +360,10 @@ namespace VMAP return; } + fwrite(VMAP::VMAP_MAGIC, 1, 8, model_list_copy); + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (true) { @@ -362,7 +371,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) { @@ -407,6 +417,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); @@ -491,25 +502,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/Models/GameObjectModel.cpp b/src/common/Collision/Models/GameObjectModel.cpp index 3165ee0b8f0..ffe0636176b 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(std::string const& name_, AABox const& 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<uint32, GameobjectModelData> ModelList; @@ -53,7 +54,16 @@ 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); + return; + } + uint32 name_length, displayId; + uint8 isWmo; char buff[500]; while (true) { @@ -62,7 +72,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 +89,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 325c5bcf64d..b83d855866a 100644 --- a/src/common/Collision/Models/GameObjectModel.h +++ b/src/common/Collision/Models/GameObjectModel.h @@ -39,13 +39,13 @@ struct GameObjectDisplayInfoEntry; class TC_COMMON_API GameObjectModelOwnerBase { public: - virtual bool IsSpawned() const { return false; } - virtual uint32 GetDisplayId() const { return 0; } - virtual uint32 GetPhaseMask() const { return 0; } - 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 bool IsSpawned() const = 0; + virtual uint32 GetDisplayId() const = 0; + virtual uint32 GetPhaseMask() 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; virtual ~GameObjectModelOwnerBase() { } }; diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index edae970f0c5..897f29d4f61 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, Vector3 const& 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(WmoLiquid const& other): iHeight(nullptr), iFlags(nullptr) @@ -149,6 +157,13 @@ namespace VMAP bool WmoLiquid::GetLiquidHeight(Vector3 const& 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) + { + 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 { - size = liquid->iTilesX * liquid->iTilesY; - liquid->iFlags = new uint8[size]; - result = fread(liquid->iFlags, sizeof(uint8), size, rf) == size; + 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 b1a5d6410e3..c7efe3c3e79 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.4"; - const char RAW_VMAP_MAGIC[] = "VMAP044"; // used in extracted vmap files with raw data + const char VMAP_MAGIC[] = "VMAP_4.7"; + const char RAW_VMAP_MAGIC[] = "VMAP047"; // 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 34f1b673d2d..f96ed6105e5 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -48,7 +48,7 @@ #include <vector> u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','8'} }; +u_map_magic MapVersionMagic = { {'v','1','.','9'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1754,7 +1754,8 @@ GridMap::GridMap() _maxHeight = nullptr; _minHeight = nullptr; // Liquid data - _liquidType = 0; + _liquidGlobalEntry = 0; + _liquidGlobalFlags = 0; _liquidOffX = 0; _liquidOffY = 0; _liquidWidth = 0; @@ -1933,7 +1934,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; @@ -2311,7 +2313,7 @@ float GridMap::getLiquidLevel(float x, float y) const inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data, float collisionHeight) { // Check water type (if no water return) - if (!_liquidType && !_liquidFlags) + if (!_liquidGlobalFlags && !_liquidFlags) return LIQUID_MAP_NO_WATER; // Get cell @@ -2323,37 +2325,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 66a588bdf00..cf02dfbcbf0 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -126,7 +126,8 @@ struct map_heightHeader struct map_liquidHeader { uint32 fourcc; - uint16 flags; + uint8 flags; + uint8 liquidFlags; uint16 liquidType; uint8 offsetX; uint8 offsetY; @@ -156,7 +157,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 { @@ -214,7 +214,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/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index e3ec5741b8d..eccefe624c7 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -261,7 +261,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.8"; +static char const* MAP_VERSION_MAGIC = "v1.9"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -310,8 +310,6 @@ struct map_heightHeader #define MAP_LIQUID_TYPE_SLIME 0x08 #define MAP_LIQUID_TYPE_DARK_WATER 0x10 -#define MAP_LIQUID_TYPE_WMO_WATER 0x20 - #define MAP_LIQUID_NO_TYPE 0x0001 #define MAP_LIQUID_NO_HEIGHT 0x0002 @@ -319,7 +317,8 @@ struct map_heightHeader struct map_liquidHeader { uint32 fourcc; - uint16 flags; + uint8 flags; + uint8 liquidFlags; uint16 liquidType; uint8 offsetX; uint8 offsetY; @@ -351,6 +350,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]; @@ -373,6 +373,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<uint32 const*>(MAP_MAGIC); @@ -730,13 +732,14 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int //============================================ // Pack liquid data //============================================ - uint8 type = liquid_flags[0][0]; + uint16 firstLiquidType = liquid_entry[0][0]; + uint8 firstLiquidFlag = liquid_flags[0][0]; bool fullType = false; for (int y=0;y<ADT_CELLS_PER_GRID;y++) { for(int x=0;x<ADT_CELLS_PER_GRID;x++) { - if (liquid_flags[y][x]!=type) + if (liquid_entry[y][x] != firstLiquidType || liquid_flags[y][x] != firstLiquidFlag) { fullType = true; y = ADT_CELLS_PER_GRID; @@ -748,7 +751,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int map_liquidHeader liquidHeader; // no water data (if all grid have 0 liquid type) - if (type == 0 && !fullType) + if (firstLiquidFlag == 0 && !fullType) { // No liquid data map.liquidMapOffset = 0; @@ -800,7 +803,10 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int liquidHeader.flags |= MAP_LIQUID_NO_TYPE; if (liquidHeader.flags & MAP_LIQUID_NO_TYPE) - liquidHeader.liquidType = type; + { + liquidHeader.liquidFlags = firstLiquidFlag; + liquidHeader.liquidType = firstLiquidType; + } else map.liquidMapSize += sizeof(liquid_entry) + sizeof(liquid_flags); @@ -808,15 +814,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) @@ -833,9 +830,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 diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index fc8fa1c39a8..46469516b89 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -244,6 +244,14 @@ public: return { 0, 0 }; } + uint16 GetLiquidType(adt_liquid_instance const* h) const + { + if (h->LiquidVertexFormat == LiquidVertexFormatType::Depth) + return 2; + + return h->LiquidType; + } + float GetLiquidHeight(adt_liquid_instance const* h, int32 pos) const { if (!h->OffsetVertexData) diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 016fd8b9d1c..38b3c3ca447 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -61,7 +61,8 @@ struct map_heightHeader struct map_liquidHeader { uint32 fourcc; - uint16 flags; + uint8 flags; + uint8 liquidFlags; uint16 liquidType; uint8 offsetX; uint8 offsetY; @@ -76,12 +77,10 @@ struct map_liquidHeader #define MAP_LIQUID_TYPE_MAGMA 0x04 #define MAP_LIQUID_TYPE_SLIME 0x08 #define MAP_LIQUID_TYPE_DARK_WATER 0x10 -#define MAP_LIQUID_TYPE_WMO_WATER 0x20 namespace MMAP { - - char const* MAP_VERSION_MAGIC = "v1.8"; + char const* MAP_VERSION_MAGIC = "v1.9"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } @@ -171,8 +170,10 @@ namespace MMAP // data used later uint16 holes[16][16]; memset(holes, 0, sizeof(holes)); - uint8 liquid_type[16][16]; - memset(liquid_type, 0, sizeof(liquid_type)); + uint16 liquid_entry[16][16]; + memset(liquid_entry, 0, sizeof(liquid_entry)); + uint8 liquid_flags[16][16]; + memset(liquid_flags, 0, sizeof(liquid_flags)); G3D::Array<int> ltriangles; G3D::Array<int> ttriangles; @@ -280,79 +281,90 @@ namespace MMAP if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1) printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n"); - float* liquid_map = nullptr; if (!(lheader.flags & MAP_LIQUID_NO_TYPE)) - if (fread(liquid_type, sizeof(liquid_type), 1, mapFile) != 1) + { + if (fread(liquid_entry, sizeof(liquid_entry), 1, mapFile) != 1) printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n"); + if (fread(liquid_flags, sizeof(liquid_flags), 1, mapFile) != 1) + printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n"); + } + else + { + std::fill_n(&liquid_entry[0][0], 16 * 16, lheader.liquidType); + std::fill_n(&liquid_flags[0][0], 16 * 16, lheader.liquidFlags); + } if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT)) { uint32 toRead = lheader.width * lheader.height; liquid_map = new float [toRead]; if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead) + { printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n"); + delete[] liquid_map; + liquid_map = nullptr; + } } - if (liquid_map) - { - int count = meshData.liquidVerts.size() / 3; - float xoffset = (float(tileX)-32)*GRID_SIZE; - float yoffset = (float(tileY)-32)*GRID_SIZE; + int count = meshData.liquidVerts.size() / 3; + float xoffset = (float(tileX)-32)*GRID_SIZE; + float yoffset = (float(tileY)-32)*GRID_SIZE; - float coord[3]; - int row, col; + float coord[3]; + int row, col; - // generate coordinates - if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT)) + // generate coordinates + if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT)) + { + int j = 0; + for (int i = 0; i < V9_SIZE_SQ; ++i) { - int j = 0; - for (int i = 0; i < V9_SIZE_SQ; ++i) - { - row = i / V9_SIZE; - col = i % V9_SIZE; - - if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height || - col < lheader.offsetX || col >= lheader.offsetX + lheader.width) - { - // dummy vert using invalid height - meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1); - continue; - } + row = i / V9_SIZE; + col = i % V9_SIZE; - getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map); - meshData.liquidVerts.append(coord[0]); - meshData.liquidVerts.append(coord[2]); - meshData.liquidVerts.append(coord[1]); - j++; + if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height || + col < lheader.offsetX || col >= lheader.offsetX + lheader.width) + { + // dummy vert using invalid height + meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1); + continue; } + + getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map); + meshData.liquidVerts.append(coord[0]); + meshData.liquidVerts.append(coord[2]); + meshData.liquidVerts.append(coord[1]); + j++; } - else + } + else + { + for (int i = 0; i < V9_SIZE_SQ; ++i) { - for (int i = 0; i < V9_SIZE_SQ; ++i) - { - row = i / V9_SIZE; - col = i % V9_SIZE; - meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1); - } + row = i / V9_SIZE; + col = i % V9_SIZE; + meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1); } + } - delete [] liquid_map; + delete[] liquid_map; - int indices[] = { 0, 0, 0 }; - int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP; - getLoopVars(portion, loopStart, loopEnd, loopInc); + int indices[] = { 0, 0, 0 }; + int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP; + getLoopVars(portion, loopStart, loopEnd, loopInc); - // generate triangles - for (int i = loopStart; i < loopEnd; i+=loopInc) - for (int j = TOP; j <= BOTTOM; j+= triInc) - { - getHeightTriangle(i, Spot(j), indices, true); - ltriangles.append(indices[2] + count); - ltriangles.append(indices[1] + count); - ltriangles.append(indices[0] + count); - } + // generate triangles + for (int i = loopStart; i < loopEnd; i += loopInc) + { + for (int j = TOP; j <= BOTTOM; j += triInc) + { + getHeightTriangle(i, Spot(j), indices, true); + ltriangles.append(indices[2] + count); + ltriangles.append(indices[1] + count); + ltriangles.append(indices[0] + count); + } } } @@ -390,38 +402,31 @@ namespace MMAP useTerrain = true; useLiquid = true; uint8 liquidType = MAP_LIQUID_TYPE_NO_WATER; - // FIXME: "warning: the address of ‘liquid_type’ will always evaluate as ‘true’" + // FIXME: "warning: the address of ‘liquid_type’ will always evaluate as ‘true’" // if there is no liquid, don't use liquid if (!meshData.liquidVerts.size() || !ltriangles.size()) useLiquid = false; else { - liquidType = getLiquidType(i, liquid_type); - switch (liquidType) + liquidType = getLiquidType(i, liquid_flags); + if (liquidType & MAP_LIQUID_TYPE_DARK_WATER) { - default: - useLiquid = false; - break; - case MAP_LIQUID_TYPE_WATER: - case MAP_LIQUID_TYPE_OCEAN: - // merge different types of water - liquidType = NAV_WATER; - break; - case MAP_LIQUID_TYPE_MAGMA: - liquidType = NAV_MAGMA; - break; - case MAP_LIQUID_TYPE_SLIME: - liquidType = NAV_SLIME; - break; - case MAP_LIQUID_TYPE_DARK_WATER: - // players should not be here, so logically neither should creatures - useTerrain = false; - useLiquid = false; - break; + // players should not be here, so logically neither should creatures + useTerrain = false; + 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; + else + useLiquid = false; } + // if there is no terrain, don't use terrain if (!ttriangles.size()) useTerrain = false; @@ -697,7 +702,7 @@ namespace MMAP copyIndices(tempTriangles, meshData.solidTris, offset, isM2); // now handle liquid data - if (liquid) + if (liquid && liquid->GetFlagsStorage()) { std::vector<G3D::Vector3> liqVerts; std::vector<int> liqTris; diff --git a/src/tools/vmap4_extractor/adtfile.cpp b/src/tools/vmap4_extractor/adtfile.cpp index 5b07c5b683c..588cfb5dc78 100644 --- a/src/tools/vmap4_extractor/adtfile.cpp +++ b/src/tools/vmap4_extractor/adtfile.cpp @@ -18,7 +18,7 @@ #include "vmapexport.h" #include "adtfile.h" - +#include "StringFormat.h" #include <algorithm> #include <cstdio> @@ -74,14 +74,14 @@ char* GetExtension(char* FileName) return nullptr; } -ADTFile::ADTFile(char* filename): ADT(filename), nWMO(0), nMDX(0) +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; @@ -94,15 +94,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")) { @@ -115,7 +115,7 @@ 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; while (p < buf + size) { @@ -123,7 +123,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) char* s = GetPlainName(p); fixname2(s, strlen(s)); - ModelInstansName.push_back(s); + ModelInstanceNames.push_back(s); std::string path(p); ExtractSingleModel(path); @@ -138,7 +138,7 @@ 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; while (p < buf + size) { @@ -147,7 +147,7 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) char* s = GetPlainName(p); fixnamen(s, strlen(s)); fixname2(s, strlen(s)); - WmoInstansName.push_back(s); + WmoInstanceNames.push_back(s); ExtractSingleWmo(path); @@ -157,16 +157,16 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) } } //====================== - else if (!strcmp(fourcc,"MDDF")) + else if (!strcmp(fourcc, "MDDF")) { 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); } } } @@ -174,24 +174,24 @@ bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY) { 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); } } } //====================== - 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 1f9937394e1..7a421cafeae 100644 --- a/src/tools/vmap4_extractor/adtfile.h +++ b/src/tools/vmap4_extractor/adtfile.h @@ -23,104 +23,45 @@ #include "wmo.h" #include "model.h" -#define TILESIZE (533.33333f) -#define CHUNKSIZE ((TILESIZE) / 16.0f) -#define UNITSIZE (CHUNKSIZE / 8.0f) - -class Liquid; - -typedef struct -{ - float x; - float y; - float z; -}svec; - -struct vec -{ - double x; - double y; - double z; -}; - -struct triangle -{ - vec v[3]; -}; - -typedef struct +#pragma pack(push, 1) +namespace ADT { - float v9[16*8+1][16*8+1]; - float v8[16*8][16*8]; -}Cell; - -typedef struct -{ - double v9[9][9]; - double v8[8][8]; - uint16 area_id; - //Liquid *lq; - float waterlevel[9][9]; - uint8 flag; -}chunk; - -typedef struct -{ - chunk ch[16][16]; -}mcell; - -struct MapChunkHeader -{ - uint32 flags; - uint32 ix; - uint32 iy; - uint32 nLayers; - uint32 nDoodadRefs; - uint32 ofsHeight; - uint32 ofsNormal; - uint32 ofsLayer; - uint32 ofsRefs; - uint32 ofsAlpha; - uint32 sizeAlpha; - uint32 ofsShadow; - uint32 sizeShadow; - uint32 areaid; - uint32 nMapObjRefs; - uint32 holes; - uint16 s1; - uint16 s2; - uint32 d1; - uint32 d2; - uint32 d3; - uint32 predTex; - uint32 nEffectDoodad; - uint32 ofsSndEmitters; - uint32 nSndEmitters; - uint32 ofsLiquid; - uint32 sizeLiquid; - float zpos; - float xpos; - float ypos; - uint32 textureId; - uint32 props; - uint32 effectId; -}; + 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; + uint16 NameSet; + uint16 Scale; + }; +} +#pragma pack(pop) class ADTFile { private: - //size_t mcnk_offsets[256], mcnk_sizes[256]; - MPQFile ADT; - //mcell Mcell; + MPQFile _file; std::string Adtfilename; public: ADTFile(char* filename); ~ADTFile(); - int nWMO; - int nMDX; - std::vector<std::string> WmoInstansName; - std::vector<std::string> ModelInstansName; + std::vector<std::string> WmoInstanceNames; + std::vector<std::string> 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 fd9d516b8d0..253d70880e9 100644 --- a/src/tools/vmap4_extractor/gameobject_extract.cpp +++ b/src/tools/vmap4_extractor/gameobject_extract.cpp @@ -20,7 +20,7 @@ #include "dbcfile.h" #include "adtfile.h" #include "vmapexport.h" - +#include "VMapDefinitions.h" #include <algorithm> #include <stdio.h> @@ -75,6 +75,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); @@ -93,8 +95,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")) @@ -112,6 +116,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 527e34b6b94..1d20441bbca 100644 --- a/src/tools/vmap4_extractor/model.cpp +++ b/src/tools/vmap4_extractor/model.cpp @@ -19,7 +19,9 @@ #include "vmapexport.h" #include "model.h" #include "wmo.h" +#include "adtfile.h" #include "mpq_libmpq04.h" +#include "VMapDefinitions.h" #include <cassert> #include <algorithm> #include <cstdio> @@ -76,7 +78,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; @@ -142,29 +144,17 @@ Vec3D fixCoordSystem2(Vec3D v) return Vec3D(v.x, v.z, v.y); } -ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile) - : id(0), scale(0), flags(0) +void Doodad::Extract(ADT::MDDF const& doodadDef, 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; + 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; @@ -174,38 +164,24 @@ 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 flags = MOD_M2; if (tileX == 65 && tileY == 65) flags |= MOD_WORLDSPAWN; - //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(&doodadDef.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 - ); */ } diff --git a/src/tools/vmap4_extractor/model.h b/src/tools/vmap4_extractor/model.h index c44448b5423..0bfdecbd6e9 100644 --- a/src/tools/vmap4_extractor/model.h +++ b/src/tools/vmap4_extractor/model.h @@ -25,6 +25,7 @@ #include <vector> class MPQFile; +namespace ADT { struct MDDF; } Vec3D fixCoordSystem(Vec3D v); @@ -51,17 +52,9 @@ public: ~Model() { _unload(); } }; -class ModelInstance +namespace Doodad { -public: - uint32 id; - Vec3D pos, rot; - uint16 scale, flags; - float sc; - - ModelInstance() : id(0), scale(0), flags(0), sc(0.0f) {} - ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); - -}; + void Extract(ADT::MDDF const& doodadDef, char const* ModelInstName, 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 3038f8b6dfa..04fe0f7d218 100644 --- a/src/tools/vmap4_extractor/vec3d.h +++ b/src/tools/vmap4_extractor/vec3d.h @@ -138,6 +138,13 @@ public: } }; +class AaBox3D +{ +public: + Vec3D min; + Vec3D max; +}; + class Vec2D { public: diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index e83698de620..29824785015 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -64,7 +64,6 @@ bool preciseVectorData = false; //static const char * szWorkDirMaps = ".\\Maps"; char const* szWorkDirWmo = "./Buildings"; -char const* szRawVMAPMagic = "VMAP044"; // Local testing functions @@ -147,7 +146,7 @@ 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; @@ -172,13 +171,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); 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(id, map_ids[i].id)) + if (WDT.init(map_ids[i].id)) { printf("Processing Map %u\n[", map_ids[i].id); for (int x=0; x<64; ++x) diff --git a/src/tools/vmap4_extractor/vmapexport.h b/src/tools/vmap4_extractor/vmapexport.h index cc7ef2b885b..c46f9ceb971 100644 --- a/src/tools/vmap4_extractor/vmapexport.h +++ b/src/tools/vmap4_extractor/vmapexport.h @@ -29,7 +29,6 @@ enum ModelFlags }; extern const char * szWorkDirWmo; -extern const char * szRawVMAPMagic; // vmap magic string for extracted raw vmap data 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 c46b4a7c6ab..faa66ca1031 100644 --- a/src/tools/vmap4_extractor/wdtfile.cpp +++ b/src/tools/vmap4_extractor/wdtfile.cpp @@ -20,6 +20,7 @@ #include "wdtfile.h" #include "adtfile.h" +#include "StringFormat.h" #include <cstdio> char * wdtGetPlainName(char * FileName) @@ -31,14 +32,14 @@ char * wdtGetPlainName(char * FileName) return FileName; } -WDTFile::WDTFile(char* file_name, char* file_name1) : gnWMO(0), WDT(file_name) +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; @@ -56,15 +57,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")) { @@ -75,7 +76,7 @@ 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; while (p < buf + size) { @@ -85,7 +86,7 @@ bool WDTFile::init(char* /*map_id*/, unsigned int mapID) fixnamen(s, strlen(s)); fixname2(s, strlen(s)); p = p + strlen(p) + 1; - gWmoInstansName.push_back(s); + _wmoNames.push_back(s); ExtractSingleWmo(path); } @@ -97,27 +98,26 @@ 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); } } } - WDT.seek((int)nextpos); + _file.seek((int)nextpos); } - WDT.close(); + _file.close(); fclose(dirfile); return true; } WDTFile::~WDTFile(void) { - 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 f4cadadb40e..bc11073b803 100644 --- a/src/tools/vmap4_extractor/wdtfile.h +++ b/src/tools/vmap4_extractor/wdtfile.h @@ -30,14 +30,13 @@ public: WDTFile(char* file_name, char* file_name1); ~WDTFile(void); - bool init(char* map_id, unsigned int mapID); + bool init(uint32 mapId); ADTFile* GetMap(int x, int z); - std::vector<std::string> gWmoInstansName; - int gnWMO; + std::vector<std::string> _wmoNames; private: - MPQFile WDT; + MPQFile _file; std::string filename; }; diff --git a/src/tools/vmap4_extractor/wmo.cpp b/src/tools/vmap4_extractor/wmo.cpp index 8be14bc38ee..da301b7599e 100644 --- a/src/tools/vmap4_extractor/wmo.cpp +++ b/src/tools/vmap4_extractor/wmo.cpp @@ -17,10 +17,12 @@ */ #include "vmapexport.h" +#include "adtfile.h" #include "wmo.h" #include "vec3d.h" #include "mpq_libmpq04.h" +#include "VMapDefinitions.h" #include <cstdio> #include <cstdlib> #include <cassert> @@ -124,7 +126,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); @@ -136,14 +138,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(filename.c_str()); if(f.isEof ()) @@ -180,9 +182,19 @@ bool WMOGroup::open() f.read(&nBatchB, 2); f.read(&nBatchC, 4); f.read(&fogIdx, 4); - f.read(&liquidType, 4); + f.read(&groupLiquid, 4); f.read(&groupWMOID,4); + // according to WoW.Dev Wiki: + if (rootWMO->flags & 4) + groupLiquid = GetLiquidTypeId(groupLiquid); + else if (groupLiquid == 15) + groupLiquid = 0; + else + groupLiquid = GetLiquidTypeId(groupLiquid + 1); + + if (groupLiquid) + liquflags |= 2; } else if (!strcmp(fourcc,"MOPY")) { @@ -218,7 +230,7 @@ bool WMOGroup::open() { 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); @@ -226,6 +238,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]; @@ -398,78 +423,54 @@ int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool precise } //------LIQU------------------------ - if (LiquEx_size != 0) + if (liquflags & 3) { - int LIQU_h[] = {0x5551494C, static_cast<int>(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles*hlq->ytiles};// "LIQU" - fwrite(LIQU_h, 4, 2, output); - - // according to WoW.Dev Wiki: - uint32 liquidEntry; - if (rootWMO->flags & 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) + int LIQU_totalSize = sizeof(uint32); + if (liquflags & 1) { - 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; - } + LIQU_totalSize += sizeof(WMOLiquidHeader); + LIQU_totalSize += LiquEx_size / sizeof(WMOLiquidVert) * sizeof(float); + LIQU_totalSize += hlq->xtiles * hlq->ytiles; } - - hlq->type = liquidEntry; + int LIQU_h[] = { 0x5551494C, LIQU_totalSize };// "LIQU" + fwrite(LIQU_h, 4, 2, output); /* 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.close(); */ - 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); + 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<uint8>(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; @@ -481,33 +482,11 @@ 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) +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]); // 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---------------- @@ -531,46 +510,38 @@ 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 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(&mapObjDef.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 1c68b49ee49..d3e22dcd686 100644 --- a/src/tools/vmap4_extractor/wmo.h +++ b/src/tools/vmap4_extractor/wmo.h @@ -18,8 +18,6 @@ #ifndef WMO_H #define WMO_H -#define TILESIZE (533.33333f) -#define CHUNKSIZE ((TILESIZE) / 16.0f) #include <string> #include <set> @@ -43,6 +41,7 @@ enum MopyFlags class WMOInstance; class WMOManager; class MPQFile; +namespace ADT { struct MODF; } /* for whatever reason a certain company just can't stick to one coordinate system... */ static inline Vec3D fixCoords(Vec3D const& v){ return Vec3D(v.z, v.x, v.y); } @@ -63,17 +62,17 @@ public: 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 +106,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; @@ -118,24 +117,14 @@ public: WMOGroup(std::string const& filename); ~WMOGroup(); - bool open(); + bool open(WMORoot* rootWMO); int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData); + uint32 GetLiquidTypeId(uint32 liquidTypeId); }; -class WMOInstance +namespace MapObject { - static std::set<int> 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, FILE* pDirfile); -}; + void Extract(ADT::MODF const& mapObjDef, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile); +} #endif |