diff --git a/src/common/Collision/Maps/MapTree.cpp b/src/common/Collision/Maps/MapTree.cpp index d65afbbfd4..b9f7378b17 100644 --- a/src/common/Collision/Maps/MapTree.cpp +++ b/src/common/Collision/Maps/MapTree.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * Copyright (C) 2008-2019 TrinityCore * Copyright (C) 2005-2010 MaNGOS * * This program is free software; you can redistribute it and/or modify it @@ -281,9 +281,16 @@ namespace VMAP } else { - if (!readChunk(tf, chunk, VMAP_MAGIC, 8)) - result = LoadResult::VersionMismatch; - fclose(tf); + std::string tilefile = basePath + getTileFileName(mapID, tileX, tileY); + FILE* tf = fopen(tilefile.c_str(), "rb"); + if (!tf) + result = LoadResult::FileNotFound; + else + { + if (!readChunk(tf, chunk, VMAP_MAGIC, 8)) + result = LoadResult::VersionMismatch; + fclose(tf); + } } fclose(rf); return result; diff --git a/src/common/Collision/Maps/TileAssembler.cpp b/src/common/Collision/Maps/TileAssembler.cpp index d5ad8a5fa6..6e210299b9 100644 --- a/src/common/Collision/Maps/TileAssembler.cpp +++ b/src/common/Collision/Maps/TileAssembler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2018 TrinityCore + * Copyright (C) 2008-2019 TrinityCore * Copyright (C) 2005-2010 MaNGOS * * This program is free software; you can redistribute it and/or modify it @@ -200,12 +200,13 @@ namespace VMAP return false; } printf("Read coordinate mapping...\n"); - uint32 mapID, check = 0; + uint32 mapID, check=0; std::map data; while (!feof(dirf)) { + check = 0; // read mapID, Flags, NameSet, UniqueId, Pos, Rot, Scale, Bound_lo, Bound_hi, name - check = fread(&mapID, sizeof(uint32), 1, dirf); + check += fread(&mapID, sizeof(uint32), 1, dirf); if (check == 0) // EoF... break; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index c83659f10d..4b950b8866 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -5077,7 +5077,7 @@ void Player::RepopAtGraveyard() AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetAreaId()); // Such zones are considered unreachable as a ghost and the player must be automatically revived - if ((!IsAlive() && zone && zone->Flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < (zone ? zone->MinElevation : -500.0f)) + if ((!IsAlive() && zone && zone->Flags & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) { ResurrectPlayer(0.5f); SpawnCorpseBones(); @@ -5115,7 +5115,7 @@ void Player::RepopAtGraveyard() SendDirectMessage(&data); } } - else if (GetPositionZ() < zone->MinElevation) + else if (GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) TeleportTo(m_homebindMapId, m_homebindX, m_homebindY, m_homebindZ, GetOrientation()); RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index fa5af8e451..4b58e2d5ad 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -429,8 +429,7 @@ void WorldSession::HandleMovementOpcodes(WorldPacket& recvPacket) plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); AreaTableEntry const* zone = sAreaTableStore.LookupEntry(plrMover->GetAreaId()); - float depth = zone ? zone->MinElevation : -500.0f; - if (movementInfo.pos.GetPositionZ() < depth) + if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY())) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 0977f57aee..f6f19bb6f1 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -51,7 +51,7 @@ #include u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','7'} }; +u_map_magic MapVersionMagic = { {'v','1','.','8'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1812,6 +1812,7 @@ GridMap::GridMap() _gridIntHeightMultiplier = 0; m_V9 = nullptr; m_V8 = nullptr; + _minHeightPlanes = nullptr; // Liquid data _liquidGlobalEntry = 0; _liquidGlobalFlags = 0; @@ -1896,6 +1897,7 @@ void GridMap::unloadData() delete[] _areaMap; delete[] m_V9; delete[] m_V8; + delete[] _minHeightPlanes; delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; @@ -1903,6 +1905,7 @@ void GridMap::unloadData() _areaMap = nullptr; m_V9 = nullptr; m_V8 = nullptr; + _minHeightPlanes = nullptr; _liquidEntry = nullptr; _liquidFlags = nullptr; _liquidMap = nullptr; @@ -1973,6 +1976,48 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) else _gridGetHeight = &GridMap::getHeightFromFlat; + if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + std::array maxHeights; + std::array minHeights; + if (fread(maxHeights.data(), sizeof(int16), maxHeights.size(), in) != maxHeights.size() || + fread(minHeights.data(), sizeof(int16), minHeights.size(), in) != minHeights.size()) + return false; + + static uint32 constexpr indices[8][3] = + { + { 3, 0, 4 }, + { 0, 1, 4 }, + { 1, 2, 4 }, + { 2, 5, 4 }, + { 5, 8, 4 }, + { 8, 7, 4 }, + { 7, 6, 4 }, + { 6, 3, 4 } + }; + + static float constexpr boundGridCoords[9][2] = + { + { 0.0f, 0.0f }, + { 0.0f, -266.66666f }, + { 0.0f, -533.33331f }, + { -266.66666f, 0.0f }, + { -266.66666f, -266.66666f }, + { -266.66666f, -533.33331f }, + { -533.33331f, 0.0f }, + { -533.33331f, -266.66666f }, + { -533.33331f, -533.33331f } + }; + + _minHeightPlanes = new G3D::Plane[8]; + for (uint32 quarterIndex = 0; quarterIndex < 8; ++quarterIndex) + _minHeightPlanes[quarterIndex] = G3D::Plane( + G3D::Vector3(boundGridCoords[indices[quarterIndex][0]][0], boundGridCoords[indices[quarterIndex][0]][1], minHeights[indices[quarterIndex][0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex][1]][0], boundGridCoords[indices[quarterIndex][1]][1], minHeights[indices[quarterIndex][1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex][2]][0], boundGridCoords[indices[quarterIndex][2]][1], minHeights[indices[quarterIndex][2]]) + ); + } + return true; } @@ -2265,6 +2310,36 @@ float GridMap::getHeightFromUint16(float x, float y) const return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight; } +float GridMap::getMinHeight(float x, float y) const +{ + if (!_minHeightPlanes) + return -500.0f; + + GridCoord gridCoord = Trinity::ComputeGridCoord(x, y); + + int32 doubleGridX = int32(std::floor(-(x - MAP_HALFSIZE) / CENTER_GRID_OFFSET)); + int32 doubleGridY = int32(std::floor(-(y - MAP_HALFSIZE) / CENTER_GRID_OFFSET)); + + float gx = x - (int32(gridCoord.x_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + float gy = y - (int32(gridCoord.y_coord) - CENTER_GRID_ID + 1) * SIZE_OF_GRIDS; + + uint32 quarterIndex = 0; + if (doubleGridY & 1) + { + if (doubleGridX & 1) + quarterIndex = 4 + (gx <= gy); + else + quarterIndex = 2 + ((-SIZE_OF_GRIDS - gx) > gy); + } + else if (doubleGridX & 1) + quarterIndex = 6 + ((-SIZE_OF_GRIDS - gx) <= gy); + else + quarterIndex = gx > gy; + + G3D::Ray ray = G3D::Ray::fromOriginAndDirection(G3D::Vector3(gx, gy, 0.0f), G3D::Vector3::unitZ()); + return ray.intersection(_minHeightPlanes[quarterIndex]).z; +} + bool GridMap::isHole(int row, int col) const { if (!_holes) @@ -2492,6 +2567,14 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float return mapHeight; // explicitly use map data } +float Map::GetMinHeight(float x, float y) const +{ + if (GridMap const* grid = const_cast(this)->GetGrid(x, y)) + return grid->getMinHeight(x, y); + + return -500.0f; +} + float Map::GetGridHeight(uint32 mapId, float x, float y) const { if (GridMap* gmap = m_parentTerrainMap->GetGrid(mapId, x, y)) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index 64e2a9e252..061705496b 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -65,6 +65,7 @@ struct ScriptInfo; struct SummonPropertiesEntry; enum Difficulty : uint8; namespace Trinity { struct ObjectUpdater; } +namespace G3D { class Plane; } namespace VMAP { enum class ModelIgnoreFlags : uint32; } struct ScriptAction @@ -112,6 +113,7 @@ struct map_areaHeader #define MAP_HEIGHT_NO_HEIGHT 0x0001 #define MAP_HEIGHT_AS_INT16 0x0002 #define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -200,6 +202,7 @@ class TC_GAME_API GridMap uint16* m_uint16_V8; uint8* m_uint8_V8; }; + G3D::Plane* _minHeightPlanes; // Height level data float _gridHeight; float _gridIntHeightMultiplier; @@ -246,6 +249,7 @@ public: uint16 getArea(float x, float y) const; inline float getHeight(float x, float y) const {return (this->*_gridGetHeight)(x, y);} + float getMinHeight(float x, float y) const; float getLiquidLevel(float x, float y) const; ZLiquidStatus GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0, float collisionHeight = 2.03128f); // DEFAULT_COLLISION_HEIGHT in Object.h bool fileExists() const { return _fileExists; } @@ -397,6 +401,7 @@ class TC_GAME_API Map : public GridRefManager // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; + float GetMinHeight(float x, float y) const; void GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr, float collisionHeight = 2.03128f) const; // DEFAULT_COLLISION_HEIGHT in Object.h diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index ee939b8ae9..1c78216524 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -16,10 +16,12 @@ * with this program. If not, see . */ -#include +#include +#include +#include #include -#include -#include +#include +#include #include #include #include @@ -35,7 +37,6 @@ #include "StormLib.h" #include "dbcfile.h" #include "Banner.h" - #include "adt.h" #include "wdt.h" #include @@ -56,6 +57,8 @@ #define OPEN_FLAGS (O_RDONLY | O_BINARY) #endif +#include + HANDLE WorldMpq = nullptr; HANDLE LocaleMpq = nullptr; @@ -416,7 +419,7 @@ void ReadLiquidTypeTable() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.7"; +static char const* MAP_VERSION_MAGIC = "v1.8"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -445,9 +448,10 @@ struct map_areaHeader uint16 gridArea; }; -#define MAP_HEIGHT_NO_HEIGHT 0x0001 -#define MAP_HEIGHT_AS_INT16 0x0002 -#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_NO_HEIGHT 0x0001 +#define MAP_HEIGHT_AS_INT16 0x0002 +#define MAP_HEIGHT_AS_INT8 0x0004 +#define MAP_HEIGHT_HAS_FLIGHT_BOUNDS 0x0008 struct map_heightHeader { @@ -505,6 +509,9 @@ 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]; +uint8 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID][8]; +int16 flight_box_max[3][3]; +int16 flight_box_min[3][3]; LiquidVertexFormatType adt_MH2O::GetLiquidVertexFormat(adt_liquid_instance const* liquidInstance) const { @@ -525,28 +532,257 @@ LiquidVertexFormatType adt_MH2O::GetLiquidVertexFormat(adt_liquid_instance const return static_cast(-1); } -bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, uint32 build, bool ignoreDeepWater) +bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8]) { - ADT_file adt; + for (uint8 i = 0; i < 8; i++) + { + for (uint8 j = 0; j < 8; j++) + { + int32 holeIdxL = (i / 2) * 4 + (j / 2); + if (((lowResHoles >> holeIdxL) & 1) == 1) + hiResHoles[i] |= (1 << j); + } + } - if (!adt.loadFile(WorldMpq, filename)) + return *((uint64*)hiResHoles) != 0; +} + +bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int /*cell_y*/, int /*cell_x*/, uint32 build, bool ignoreDeepWater) +{ + ChunkedFile adt; + + if (!adt.loadFile(WorldMpq, inputPath)) return false; + // Prepare map header + map_fileheader map; + map.mapMagic = *reinterpret_cast(MAP_MAGIC); + map.versionMagic = *reinterpret_cast(MAP_VERSION_MAGIC); + map.buildMagic = build; + + // Get area flags data + memset(area_ids, 0, sizeof(area_ids)); + memset(V9, 0, sizeof(V9)); + memset(V8, 0, sizeof(V8)); + memset(liquid_show, 0, sizeof(liquid_show)); memset(liquid_flags, 0, sizeof(liquid_flags)); memset(liquid_entry, 0, sizeof(liquid_entry)); - // Prepare map header - map_fileheader map; - map.mapMagic = *(uint32 const*)MAP_MAGIC; - map.versionMagic = *(uint32 const*)MAP_VERSION_MAGIC; - map.buildMagic = build; + memset(holes, 0, sizeof(holes)); - // Get area flags data - for (int i = 0; i < ADT_CELLS_PER_GRID; ++i) - for (int j = 0; j < ADT_CELLS_PER_GRID; ++j) - area_ids[i][j] = adt.cells[i][j]->areaid; + bool hasHoles = false; + bool hasFlightBox = false; + for (std::multimap::const_iterator itr = adt.chunks.lower_bound("MCNK"); itr != adt.chunks.upper_bound("MCNK"); ++itr) + { + adt_MCNK* mcnk = itr->second->As(); + + // Area data + area_ids[mcnk->iy][mcnk->ix] = mcnk->areaid; + + // Height + // Height values for triangles stored in order: + // 1 2 3 4 5 6 7 8 9 + // 10 11 12 13 14 15 16 17 + // 18 19 20 21 22 23 24 25 26 + // 27 28 29 30 31 32 33 34 + // . . . . . . . . + // For better get height values merge it to V9 and V8 map + // V9 height map: + // 1 2 3 4 5 6 7 8 9 + // 18 19 20 21 22 23 24 25 26 + // . . . . . . . . + // V8 height map: + // 10 11 12 13 14 15 16 17 + // 27 28 29 30 31 32 33 34 + // . . . . . . . . + + // Set map height as grid height + for (int y = 0; y <= ADT_CELL_SIZE; y++) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x <= ADT_CELL_SIZE; x++) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + V9[cy][cx] = mcnk->ypos; + } + } + + for (int y = 0; y < ADT_CELL_SIZE; y++) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x < ADT_CELL_SIZE; x++) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + V8[cy][cx] = mcnk->ypos; + } + } + + // Get custom height + if (FileChunk* chunk = itr->second->GetSubChunk("MCVT")) + { + adt_MCVT* mcvt = chunk->As(); + // get V9 height map + for (int y = 0; y <= ADT_CELL_SIZE; y++) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x <= ADT_CELL_SIZE; x++) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + V9[cy][cx] += mcvt->height_map[y*(ADT_CELL_SIZE * 2 + 1) + x]; + } + } + // get V8 height map + for (int y = 0; y < ADT_CELL_SIZE; y++) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x < ADT_CELL_SIZE; x++) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + V8[cy][cx] += mcvt->height_map[y*(ADT_CELL_SIZE * 2 + 1) + ADT_CELL_SIZE + 1 + x]; + } + } + } + + // Liquid data + if (mcnk->sizeMCLQ > 8) + { + if (FileChunk* chunk = itr->second->GetSubChunk("MCLQ")) + { + adt_MCLQ* liquid = chunk->As(); + int count = 0; + for (int y = 0; y < ADT_CELL_SIZE; ++y) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x < ADT_CELL_SIZE; ++x) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + if (liquid->flags[y][x] != 0x0F) + { + liquid_show[cy][cx] = true; + if (!ignoreDeepWater && liquid->flags[y][x] & (1 << 7)) + liquid_flags[mcnk->iy][mcnk->ix] |= MAP_LIQUID_TYPE_DARK_WATER; + ++count; + } + } + } + + uint32 c_flag = mcnk->flags; + if (c_flag & (1 << 2)) + { + liquid_entry[mcnk->iy][mcnk->ix] = 1; + liquid_flags[mcnk->iy][mcnk->ix] |= MAP_LIQUID_TYPE_WATER; // water + } + if (c_flag & (1 << 3)) + { + liquid_entry[mcnk->iy][mcnk->ix] = 2; + liquid_flags[mcnk->iy][mcnk->ix] |= MAP_LIQUID_TYPE_OCEAN; // ocean + } + if (c_flag & (1 << 4)) + { + liquid_entry[mcnk->iy][mcnk->ix] = 3; + liquid_flags[mcnk->iy][mcnk->ix] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime + } + + if (!count && liquid_flags[mcnk->iy][mcnk->ix]) + fprintf(stderr, "Wrong liquid detect in MCLQ chunk"); + + for (int y = 0; y <= ADT_CELL_SIZE; ++y) + { + int cy = mcnk->iy * ADT_CELL_SIZE + y; + for (int x = 0; x <= ADT_CELL_SIZE; ++x) + { + int cx = mcnk->ix * ADT_CELL_SIZE + x; + liquid_height[cy][cx] = liquid->liquid[y][x].height; + } + } + } + } + + // Hole data + if (!(mcnk->flags & 0x10000)) + { + if (uint16 hole = mcnk->holes) + if (TransformToHighRes(hole, holes[mcnk->iy][mcnk->ix])) + hasHoles = true; + } + else + { + memcpy(holes[mcnk->iy][mcnk->ix], mcnk->union_5_3_0.HighResHoles, sizeof(uint64)); + if (*((uint64*)holes[mcnk->iy][mcnk->ix]) != 0) + hasHoles = true; + } + } + + // Get liquid map for grid (in WOTLK used MH2O chunk) + if (FileChunk* chunk = adt.GetChunk("MH2O")) + { + adt_MH2O* h2o = chunk->As(); + for (int32 i = 0; i < ADT_CELLS_PER_GRID; i++) + { + for (int32 j = 0; j < ADT_CELLS_PER_GRID; j++) + { + adt_liquid_instance const* h = h2o->GetLiquidInstance(i, j); + if (!h) + continue; + + adt_liquid_attributes attrs = h2o->GetLiquidAttributes(i, j); + + int32 count = 0; + uint64 existsMask = h2o->GetLiquidExistsBitmap(h); + for (int32 y = 0; y < h->GetHeight(); y++) + { + int32 cy = i * ADT_CELL_SIZE + y + h->GetOffsetY(); + for (int32 x = 0; x < h->GetWidth(); x++) + { + int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX(); + if (existsMask & 1) + { + liquid_show[cy][cx] = true; + ++count; + } + existsMask >>= 1; + } + } + + liquid_entry[i][j] = h2o->GetLiquidType(h); + switch (LiquidTypes.at(liquid_entry[i][j]).SoundBank) + { + case LIQUID_TYPE_WATER: liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; break; + case LIQUID_TYPE_OCEAN: liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; if (!ignoreDeepWater && attrs.Deep) liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER; break; + case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break; + case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break; + default: + printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->LiquidType, inputPath.c_str(), i, j); + break; + } + + if (!count && liquid_flags[i][j]) + printf("Wrong liquid detect in MH2O chunk"); + + int32 pos = 0; + for (int32 y = 0; y <= h->GetHeight(); y++) + { + int32 cy = i * ADT_CELL_SIZE + y + h->GetOffsetY(); + for (int32 x = 0; x <= h->GetWidth(); x++) + { + int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX(); + liquid_height[cy][cx] = h2o->GetLiquidHeight(h, pos); + pos++; + } + } + } + } + } + + if (FileChunk* chunk = adt.GetChunk("MFBO")) + { + adt_MFBO* mfbo = chunk->As(); + memcpy(flight_box_max, &mfbo->max, sizeof(flight_box_max)); + memcpy(flight_box_min, &mfbo->min, sizeof(flight_box_min)); + hasFlightBox = true; + } //============================================ // Try pack area data @@ -566,10 +802,10 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, } map.areaMapOffset = sizeof(map); - map.areaMapSize = sizeof(map_areaHeader); + map.areaMapSize = sizeof(map_areaHeader); map_areaHeader areaHeader; - areaHeader.fourcc = *(uint32 const*)MAP_AREA_MAGIC; + areaHeader.fourcc = *reinterpret_cast(MAP_AREA_MAGIC); areaHeader.flags = 0; if (fullAreaData) { @@ -582,77 +818,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, areaHeader.gridArea = static_cast(areaId); } - // - // Get Height map from grid - // - for (int i=0;iypos; - } - } - for (int y=0; y < ADT_CELL_SIZE; y++) - { - int cy = i*ADT_CELL_SIZE + y; - for (int x=0; x < ADT_CELL_SIZE; x++) - { - int cx = j*ADT_CELL_SIZE + x; - V8[cy][cx]=cell->ypos; - } - } - // Get custom height - adt_MCVT *v = cell->getMCVT(); - if (!v) - continue; - // get V9 height map - for (int y=0; y <= ADT_CELL_SIZE; y++) - { - int cy = i*ADT_CELL_SIZE + y; - for (int x=0; x <= ADT_CELL_SIZE; x++) - { - int cx = j*ADT_CELL_SIZE + x; - V9[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+x]; - } - } - // get V8 height map - for (int y=0; y < ADT_CELL_SIZE; y++) - { - int cy = i*ADT_CELL_SIZE + y; - for (int x=0; x < ADT_CELL_SIZE; x++) - { - int cx = j*ADT_CELL_SIZE + x; - V8[cy][cx]+=v->height_map[y*(ADT_CELL_SIZE*2+1)+ADT_CELL_SIZE+1+x]; - } - } - } - } //============================================ // Try pack height data //============================================ @@ -698,9 +864,9 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, map.heightMapSize = sizeof(map_heightHeader); map_heightHeader heightHeader; - heightHeader.fourcc = *(uint32 const*)MAP_HEIGHT_MAGIC; + heightHeader.fourcc = *reinterpret_cast(MAP_HEIGHT_MAGIC); heightHeader.flags = 0; - heightHeader.gridHeight = minHeight; + heightHeader.gridHeight = minHeight; heightHeader.gridMaxHeight = maxHeight; if (maxHeight == minHeight) @@ -710,7 +876,13 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit) heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT; - // Try store as packed in uint16 or uint8 values + if (hasFlightBox) + { + heightHeader.flags |= MAP_HEIGHT_HAS_FLIGHT_BOUNDS; + map.heightMapSize += sizeof(flight_box_max) + sizeof(flight_box_min); + } + + // Try store as packed in uint16 or uint8 values if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT)) { float step = 0; @@ -720,12 +892,12 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, float diff = maxHeight - minHeight; if (diff < CONF_float_to_int8_limit) // As uint8 (max accuracy = CONF_float_to_int8_limit/256) { - heightHeader.flags |= MAP_HEIGHT_AS_INT8; + heightHeader.flags|=MAP_HEIGHT_AS_INT8; step = selectUInt8StepStore(diff); } else if (diffgetMCLQ(); - int count = 0; - if (!liquid || cell->sizeMCLQ <= 8) - continue; - - for (int y = 0; y < ADT_CELL_SIZE; y++) - { - int cy = i * ADT_CELL_SIZE + y; - for (int x = 0; x < ADT_CELL_SIZE; x++) - { - int cx = j * ADT_CELL_SIZE + x; - if (liquid->flags[y][x] != 0x0F) - { - liquid_show[cy][cx] = true; - if (!ignoreDeepWater && liquid->flags[y][x] & (1<<7)) - liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER; - ++count; - } - } - } - - uint32 c_flag = cell->flags; - if (c_flag & (1<<2)) - { - liquid_entry[i][j] = 1; - liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; // water - } - if (c_flag & (1<<3)) - { - liquid_entry[i][j] = 2; - liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; // ocean - } - if (c_flag & (1<<4)) - { - liquid_entry[i][j] = 3; - liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; // magma/slime - } - - if (!count && liquid_flags[i][j]) - fprintf(stderr, "Wrong liquid detect in MCLQ chunk"); - - for (int y = 0; y <= ADT_CELL_SIZE; y++) - { - int cy = i * ADT_CELL_SIZE + y; - for (int x = 0; x <= ADT_CELL_SIZE; x++) - { - int cx = j * ADT_CELL_SIZE + x; - liquid_height[cy][cx] = liquid->liquid[y][x].height; - } - } - } - } - - // Get liquid map for grid (in WOTLK used MH2O chunk) - adt_MH2O * h2o = adt.a_grid->getMH2O(); - if (h2o) - { - for (int32 i = 0; i < ADT_CELLS_PER_GRID; i++) - { - for(int32 j = 0; j < ADT_CELLS_PER_GRID; j++) - { - adt_liquid_instance const* h = h2o->GetLiquidInstance(i, j); - if (!h) - continue; - - adt_liquid_attributes attrs = h2o->GetLiquidAttributes(i, j); - - int32 count = 0; - uint64 existsMask = h2o->GetLiquidExistsBitmap(h); - for (int32 y = 0; y < h->GetHeight(); y++) - { - int32 cy = i * ADT_CELL_SIZE + y + h->GetOffsetY(); - for (int32 x = 0; x < h->GetWidth(); x++) - { - int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX(); - if (existsMask & 1) - { - liquid_show[cy][cx] = true; - ++count; - } - existsMask >>= 1; - } - } - - liquid_entry[i][j] = h2o->GetLiquidType(h); - switch (LiquidTypes.at(liquid_entry[i][j]).SoundBank) - { - case LIQUID_TYPE_WATER: liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; break; - case LIQUID_TYPE_OCEAN: liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; if (!ignoreDeepWater && attrs.Deep) liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER; break; - case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break; - case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break; - default: - printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->LiquidType, filename, i, j); - break; - } - - if (!count && liquid_flags[i][j]) - printf("Wrong liquid detect in MH2O chunk"); - - int32 pos = 0; - for (int32 y = 0; y <= h->GetHeight(); y++) - { - int32 cy = i * ADT_CELL_SIZE + y + h->GetOffsetY(); - for (int32 x = 0; x <= h->GetWidth(); x++) - { - int32 cx = j * ADT_CELL_SIZE + x + h->GetOffsetX(); - - liquid_height[cy][cx] = h2o->GetLiquidHeight(h, pos); - - pos++; - } - } - } - } - } - - //============================================ + //============================================ // Pack liquid data //============================================ uint16 firstLiquidType = liquid_entry[0][0]; @@ -934,7 +981,7 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, } map.liquidMapOffset = map.heightMapOffset + map.heightMapSize; map.liquidMapSize = sizeof(map_liquidHeader); - liquidHeader.fourcc = *(uint32 const*)MAP_LIQUID_MAGIC; + liquidHeader.fourcc = *reinterpret_cast(MAP_LIQUID_MAGIC); liquidHeader.flags = 0; liquidHeader.liquidType = 0; liquidHeader.offsetX = minX; @@ -965,25 +1012,6 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, map.liquidMapSize += sizeof(float)*liquidHeader.width*liquidHeader.height; } - // map hole info - uint16 holes[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; - - memset(holes, 0, sizeof(holes)); - bool hasHoles = false; - - for (int i = 0; i < ADT_CELLS_PER_GRID; ++i) - { - for (int j = 0; j < ADT_CELLS_PER_GRID; ++j) - { - adt_MCNK * cell = adt.cells[i][j]; - if (!cell) - continue; - holes[i][j] = cell->holes; - if (!hasHoles && cell->holes != 0) - hasHoles = true; - } - } - if (hasHoles) { if (map.liquidMapOffset) @@ -1000,61 +1028,68 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, } // Ok all data prepared - store it - FILE* output = fopen(filename2, "wb"); - if (!output) + std::ofstream outFile(outputPath, std::ofstream::out | std::ofstream::binary); + if (!outFile) { - printf("Can't create the output file '%s'\n", filename2); + printf("Can't create the output file '%s'\n", outputPath.c_str()); return false; } - fwrite(&map, sizeof(map), 1, output); + + outFile.write(reinterpret_cast(&map), sizeof(map)); // Store area data - fwrite(&areaHeader, sizeof(areaHeader), 1, output); + outFile.write(reinterpret_cast(&areaHeader), sizeof(areaHeader)); if (!(areaHeader.flags & MAP_AREA_NO_AREA)) - fwrite(area_ids, sizeof(area_ids), 1, output); + outFile.write(reinterpret_cast(area_ids), sizeof(area_ids)); // Store height data - fwrite(&heightHeader, sizeof(heightHeader), 1, output); + outFile.write(reinterpret_cast(&heightHeader), sizeof(heightHeader)); if (!(heightHeader.flags & MAP_HEIGHT_NO_HEIGHT)) { if (heightHeader.flags & MAP_HEIGHT_AS_INT16) { - fwrite(uint16_V9, sizeof(uint16_V9), 1, output); - fwrite(uint16_V8, sizeof(uint16_V8), 1, output); + outFile.write(reinterpret_cast(uint16_V9), sizeof(uint16_V9)); + outFile.write(reinterpret_cast(uint16_V8), sizeof(uint16_V8)); } else if (heightHeader.flags & MAP_HEIGHT_AS_INT8) { - fwrite(uint8_V9, sizeof(uint8_V9), 1, output); - fwrite(uint8_V8, sizeof(uint8_V8), 1, output); + outFile.write(reinterpret_cast(uint8_V9), sizeof(uint8_V9)); + outFile.write(reinterpret_cast(uint8_V8), sizeof(uint8_V8)); } else { - fwrite(V9, sizeof(V9), 1, output); - fwrite(V8, sizeof(V8), 1, output); + outFile.write(reinterpret_cast(V9), sizeof(V9)); + outFile.write(reinterpret_cast(V8), sizeof(V8)); } } + if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + outFile.write(reinterpret_cast(flight_box_max), sizeof(flight_box_max)); + outFile.write(reinterpret_cast(flight_box_min), sizeof(flight_box_min)); + } + // Store liquid data if need if (map.liquidMapOffset) { - fwrite(&liquidHeader, sizeof(liquidHeader), 1, output); + outFile.write(reinterpret_cast(&liquidHeader), sizeof(liquidHeader)); if (!(liquidHeader.flags & MAP_LIQUID_NO_TYPE)) { - fwrite(liquid_entry, sizeof(liquid_entry), 1, output); - fwrite(liquid_flags, sizeof(liquid_flags), 1, output); + outFile.write(reinterpret_cast(liquid_entry), sizeof(liquid_entry)); + outFile.write(reinterpret_cast(liquid_flags), sizeof(liquid_flags)); } if (!(liquidHeader.flags & MAP_LIQUID_NO_HEIGHT)) { for (int y = 0; y < liquidHeader.height; y++) - fwrite(&liquid_height[y + liquidHeader.offsetY][liquidHeader.offsetX], sizeof(float), liquidHeader.width, output); + outFile.write(reinterpret_cast(&liquid_height[y + liquidHeader.offsetY][liquidHeader.offsetX]), sizeof(float) * liquidHeader.width); } } // store hole data if (hasHoles) - fwrite(holes, map.holesSize, 1, output); + outFile.write(reinterpret_cast(holes), map.holesSize); - fclose(output); + outFile.close(); return true; } @@ -1110,15 +1145,16 @@ void ExtractMapsFromMpq(uint32 build) printf("Extract %s (%d/%u) \n", map_ids[z].name, z+1, map_count); // Loadup map grid data sprintf(mpq_map_name, "World\\Maps\\%s\\%s.wdt", map_ids[z].name, map_ids[z].name); - WDT_file wdt; + ChunkedFile wdt; if (!wdt.loadFile(WorldMpq, mpq_map_name, false)) continue; + FileChunk* chunk = wdt.GetChunk("MAIN"); for (uint32 y = 0; y < WDT_MAP_SIZE; ++y) { for (uint32 x = 0; x < WDT_MAP_SIZE; ++x) { - if (!(wdt.main->adt_list[y][x].flag & 0x1)) + if (!(chunk->As()->adt_list[y][x].flag & 0x1)) continue; sprintf(mpq_filename, "World\\Maps\\%s\\%s_%u_%u.adt", map_ids[z].name, map_ids[z].name, x, y); diff --git a/src/tools/map_extractor/adt.cpp b/src/tools/map_extractor/adt.cpp deleted file mode 100644 index f8f72dc416..0000000000 --- a/src/tools/map_extractor/adt.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2011 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#define _CRT_SECURE_NO_DEPRECATE - -#include "adt.h" -#include - -// Helper -int holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 }; -int holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 }; - -u_map_fcc MHDRMagic = { { 'R','D','H','M' } }; -u_map_fcc MCINMagic = { { 'N','I','C','M' } }; -u_map_fcc MH2OMagic = { { 'O','2','H','M' } }; -u_map_fcc MCNKMagic = { { 'K','N','C','M' } }; -u_map_fcc MCVTMagic = { { 'T','V','C','M' } }; -u_map_fcc MCLQMagic = { { 'Q','L','C','M' } }; - -bool isHole(int holes, int i, int j) -{ - int testi = i / 2; - int testj = j / 4; - if (testi > 3) testi = 3; - if (testj > 3) testj = 3; - return (holes & holetab_h[testi] & holetab_v[testj]) != 0; -} - -// -// Adt file loader class -// -ADT_file::ADT_file() -{ - a_grid = 0; -} - -ADT_file::~ADT_file() -{ - free(); -} - -void ADT_file::free() -{ - a_grid = 0; - FileLoader::free(); -} - -// -// Adt file check function -// -bool ADT_file::prepareLoadedData() -{ - // Check parent - if (!FileLoader::prepareLoadedData()) - return false; - - // Check and prepare MHDR - a_grid = (adt_MHDR*)(GetData()+8+version->size); - if (!a_grid->prepareLoadedData()) - return false; - - // funny offsets calculations because there is no mapping for them and they have variable lengths - uint8* ptr = (uint8*)a_grid + a_grid->size + 8; - uint32 mcnk_count = 0; - memset(cells, 0, ADT_CELLS_PER_GRID * ADT_CELLS_PER_GRID * sizeof(adt_MCNK*)); - while (ptr < GetData() + GetDataSize()) - { - uint32 header = *(uint32*)ptr; - uint32 size = *(uint32*)(ptr + 4); - if (header == MCNKMagic.fcc) - { - cells[mcnk_count / ADT_CELLS_PER_GRID][mcnk_count % ADT_CELLS_PER_GRID] = (adt_MCNK*)ptr; - ++mcnk_count; - } - - // move to next chunk - ptr += size + 8; - } - - if (mcnk_count != ADT_CELLS_PER_GRID * ADT_CELLS_PER_GRID) - return false; - - return true; -} - -bool adt_MHDR::prepareLoadedData() -{ - if (fcc != MHDRMagic.fcc) - return false; - - if (size != sizeof(adt_MHDR) - 8) - return false; - - // Check and prepare MCIN - if (offsMCIN && !getMCIN()->prepareLoadedData()) - return false; - - // Check and prepare MH2O - if (offsMH2O && !getMH2O()->prepareLoadedData()) - return false; - - return true; -} - -bool adt_MCIN::prepareLoadedData() -{ - if (fcc != MCINMagic.fcc) - return false; - - // Check cells data - for (int i=0; iprepareLoadedData()) - return false; - - return true; -} - -bool adt_MH2O::prepareLoadedData() -{ - if (fcc != MH2OMagic.fcc) - return false; - - // Check liquid data -// for (int i=0; iprepareLoadedData()) - return false; - // Check liquid data - if (offsMCLQ && !getMCLQ()->prepareLoadedData()) - return false; - - return true; -} - -bool adt_MCVT::prepareLoadedData() -{ - if (fcc != MCVTMagic.fcc) - return false; - - if (size != sizeof(adt_MCVT)-8) - return false; - - return true; -} - -bool adt_MCLQ::prepareLoadedData() -{ - if (fcc != MCLQMagic.fcc) - return false; - - return true; -} diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index 29d3dbde9f..e0d98fd363 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -45,29 +45,25 @@ enum LiquidType // // Adt file height map chunk // -class adt_MCVT +struct adt_MCVT { union { uint32 fcc; char fcc_txt[4]; }; uint32 size; -public: float height_map[(ADT_CELL_SIZE + 1)*(ADT_CELL_SIZE + 1) + ADT_CELL_SIZE * ADT_CELL_SIZE]; - - bool prepareLoadedData(); }; // // Adt file liquid map chunk (old) // -class adt_MCLQ +struct adt_MCLQ { union { uint32 fcc; char fcc_txt[4]; }; -public: uint32 size; float height1; float height2; @@ -84,27 +80,32 @@ public: // == 0x0F - not show liquid uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE]; uint8 data[84]; - bool prepareLoadedData(); }; // // Adt file cell chunk // -class adt_MCNK +struct adt_MCNK { - union { + union{ uint32 fcc; char fcc_txt[4]; }; -public: uint32 size; uint32 flags; uint32 ix; uint32 iy; uint32 nLayers; uint32 nDoodadRefs; - uint32 offsMCVT; // height map - uint32 offsMCNR; // Normal vectors for each vertex + union + { + struct + { + uint32 offsMCVT; // height map + uint32 offsMCNR; // Normal vectors for each vertex + } offsets; + uint8 HighResHoles[8]; + } union_5_3_0; uint32 offsMCLY; // Texture layer definitions uint32 offsMCRF; // A list of indices into the parent file's MDDF chunk uint32 offsMCAL; // Alpha maps for additional texture layers @@ -130,49 +131,8 @@ public: uint32 offsMCCV; // offsColorValues in WotLK uint32 props; uint32 effectId; - - bool prepareLoadedData(); - adt_MCVT *getMCVT() - { - if (offsMCVT) - return (adt_MCVT *)((uint8 *)this + offsMCVT); - return 0; - } - adt_MCLQ *getMCLQ() - { - if (offsMCLQ) - return (adt_MCLQ *)((uint8 *)this + offsMCLQ); - return 0; - } }; -// -// Adt file grid chunk -// -class adt_MCIN -{ - union { - uint32 fcc; - char fcc_txt[4]; - }; -public: - uint32 size; - struct adt_CELLS { - uint32 offsMCNK; - uint32 size; - uint32 flags; - uint32 asyncId; - } cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; - - bool prepareLoadedData(); - // offset from begin file (used this-84) - adt_MCNK *getMCNK(int x, int y) - { - if (cells[x][y].offsMCNK) - return (adt_MCNK *)((uint8 *)this + cells[x][y].offsMCNK - 84); - return 0; - } -}; #define ADT_LIQUID_HEADER_FULL_LIGHT 0x01 #define ADT_LIQUID_HEADER_NO_HIGHT 0x02 @@ -341,51 +301,20 @@ public: LiquidVertexFormatType GetLiquidVertexFormat(adt_liquid_instance const* liquidInstance) const; }; -// -// Adt file header chunk -// -class ADT_file; -class adt_MHDR +struct adt_MFBO { - friend class ADT_file; - - union { + union + { uint32 fcc; char fcc_txt[4]; }; -public: uint32 size; - - uint32 flags; - uint32 offsMCIN; // MCIN - uint32 offsTex; // MTEX - uint32 offsModels; // MMDX - uint32 offsModelsIds; // MMID - uint32 offsMapObejcts; // MWMO - uint32 offsMapObejctsIds; // MWID - uint32 offsDoodsDef; // MDDF - uint32 offsObjectsDef; // MODF - uint32 offsMFBO; // MFBO - uint32 offsMH2O; // MH2O - uint32 data1; - uint32 data2; - uint32 data3; - uint32 data4; - uint32 data5; - bool prepareLoadedData(); - adt_MCIN* getMCIN() { return offsMCIN ? (adt_MCIN *)((uint8 *)&flags + offsMCIN) : nullptr; } - adt_MH2O* getMH2O() { return offsMH2O ? (adt_MH2O *)((uint8 *)&flags + offsMH2O) : nullptr; } -}; - -class ADT_file : public FileLoader { -public: - bool prepareLoadedData(); - ADT_file(); - ~ADT_file(); - void free(); - - adt_MHDR* a_grid; - adt_MCNK* cells[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + struct plane + { + int16 coords[9]; + }; + plane max; + plane min; }; #pragma pack(pop) diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp index 9978c76e79..45f8de0eba 100644 --- a/src/tools/map_extractor/loadlib.cpp +++ b/src/tools/map_extractor/loadlib.cpp @@ -23,49 +23,54 @@ u_map_fcc MverMagic = { {'R','E','V','M'} }; -FileLoader::FileLoader() +ChunkedFile::ChunkedFile() { data = 0; data_size = 0; - version = 0; } -FileLoader::~FileLoader() +ChunkedFile::~ChunkedFile() { free(); } -bool FileLoader::loadFile(HANDLE mpq, char* filename, bool log) +bool ChunkedFile::loadFile(HANDLE mpq, std::string const& fileName, bool log) { free(); HANDLE file; - if (!SFileOpenFileEx(mpq, filename, SFILE_OPEN_PATCHED_FILE, &file)) + if (!SFileOpenFileEx(mpq, fileName.c_str(), SFILE_OPEN_PATCHED_FILE, &file)) { if (log) - printf("No such file %s\n", filename); + printf("No such file %s\n", fileName.c_str()); return false; } data_size = SFileGetFileSize(file, nullptr); data = new uint8[data_size]; SFileReadFile(file, data, data_size, nullptr/*bytesRead*/, nullptr); + + parseChunks(); if (prepareLoadedData()) { SFileCloseFile(file); return true; } - printf("Error loading %s\n", filename); + printf("Error loading %s\n", fileName.c_str()); SFileCloseFile(file); free(); return false; } -bool FileLoader::prepareLoadedData() +bool ChunkedFile::prepareLoadedData() { + FileChunk* chunk = GetChunk("MVER"); + if (!chunk) + return false; + // Check version - version = (file_MVER *) data; + file_MVER* version = chunk->As(); if (version->fcc != MverMagic.fcc) return false; if (version->ver != FILE_FORMAT_VERSION) @@ -73,10 +78,117 @@ bool FileLoader::prepareLoadedData() return true; } -void FileLoader::free() +void ChunkedFile::free() { - if (data) delete[] data; + for (auto chunk : chunks) + delete chunk.second; + + chunks.clear(); + + delete[] data; data = 0; data_size = 0; - version = 0; } + +u_map_fcc InterestingChunks[] = +{ + { { 'R', 'E', 'V', 'M' } }, + { { 'N', 'I', 'A', 'M' } }, + { { 'O', '2', 'H', 'M' } }, + { { 'K', 'N', 'C', 'M' } }, + { { 'T', 'V', 'C', 'M' } }, + { { 'O', 'M', 'W', 'M' } }, + { { 'Q', 'L', 'C', 'M' } }, + { { 'O', 'B', 'F', 'M' } } +}; + +bool IsInterestingChunk(u_map_fcc const& fcc) +{ + for (u_map_fcc const& f : InterestingChunks) + if (f.fcc == fcc.fcc) + return true; + + return false; +} + +void ChunkedFile::parseChunks() +{ + uint8* ptr = GetData(); + // Make sure there's enough data to read u_map_fcc struct and the uint32 size after it + while (ptr <= GetData() + GetDataSize() - 8) + { + u_map_fcc header = *(u_map_fcc*)ptr; + if (IsInterestingChunk(header)) + { + uint32 size = *(uint32*)(ptr + 4); + if (size <= data_size) + { + std::swap(header.fcc_txt[0], header.fcc_txt[3]); + std::swap(header.fcc_txt[1], header.fcc_txt[2]); + + FileChunk* chunk = new FileChunk(ptr, size); + chunk->parseSubChunks(); + chunks.insert({ std::string(header.fcc_txt, 4), chunk }); + } + + // move to next chunk + ptr += size + 8; + } + else + ++ptr; + } +} + +FileChunk* ChunkedFile::GetChunk(std::string const& name) +{ + auto range = chunks.equal_range(name); + if (std::distance(range.first, range.second) == 1) + return range.first->second; + + return NULL; +} + +FileChunk::~FileChunk() +{ + for (auto subchunk : subchunks) + delete subchunk.second; + + subchunks.clear(); +} + +void FileChunk::parseSubChunks() +{ + uint8* ptr = data + 8; // skip self + while (ptr < data + size) + { + u_map_fcc header = *(u_map_fcc*)ptr; + if (IsInterestingChunk(header)) + { + uint32 subsize = *(uint32*)(ptr + 4); + if (subsize < size) + { + std::swap(header.fcc_txt[0], header.fcc_txt[3]); + std::swap(header.fcc_txt[1], header.fcc_txt[2]); + + FileChunk* chunk = new FileChunk(ptr, subsize); + chunk->parseSubChunks(); + subchunks.insert({ std::string(header.fcc_txt, 4), chunk }); + } + + // move to next chunk + ptr += subsize + 8; + } + else + ++ptr; + } +} + +FileChunk* FileChunk::GetSubChunk(std::string const& name) +{ + auto range = subchunks.equal_range(name); + if (std::distance(range.first, range.second) == 1) + return range.first->second; + + return NULL; +} + diff --git a/src/tools/map_extractor/loadlib/loadlib.h b/src/tools/map_extractor/loadlib/loadlib.h index c855739d59..b5b7bb29f9 100644 --- a/src/tools/map_extractor/loadlib/loadlib.h +++ b/src/tools/map_extractor/loadlib/loadlib.h @@ -21,6 +21,8 @@ #include "StormLib.h" #include "Define.h" +#include +#include #define FILE_FORMAT_VERSION 18 @@ -45,20 +47,47 @@ struct file_MVER uint32 ver; }; +struct file_MWMO +{ + u_map_fcc fcc; + uint32 size; + char FileList[1]; +}; -class FileLoader{ +class FileChunk +{ +public: + FileChunk(uint8* data_, uint32 size_) : data(data_), size(size_) { } + ~FileChunk(); + + uint8* data; + uint32 size; + + template + T* As() { return (T*)data; } + void parseSubChunks(); + std::multimap subchunks; + FileChunk* GetSubChunk(std::string const& name); +}; + +class ChunkedFile +{ +public: uint8 *data; uint32 data_size; -public: - virtual bool prepareLoadedData(); + uint8 *GetData() {return data;} uint32 GetDataSize() {return data_size;} - file_MVER *version; - FileLoader(); - ~FileLoader(); - bool loadFile(HANDLE mpq, char *filename, bool log = true); - virtual void free(); + ChunkedFile(); + virtual ~ChunkedFile(); + bool prepareLoadedData(); + bool loadFile(HANDLE mpq, std::string const& fileName, bool log = true); + void free(); + + void parseChunks(); + std::multimap chunks; + FileChunk* GetChunk(std::string const& name); }; #pragma pack(pop) diff --git a/src/tools/map_extractor/wdt.cpp b/src/tools/map_extractor/wdt.cpp deleted file mode 100644 index d3826e505a..0000000000 --- a/src/tools/map_extractor/wdt.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2008-2018 TrinityCore - * Copyright (C) 2005-2011 MaNGOS - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see . - */ - -#define _CRT_SECURE_NO_DEPRECATE - -#include "wdt.h" - -u_map_fcc MWMOMagic = { {'O', 'M', 'W', 'M'} }; -u_map_fcc MPHDMagic = { {'D', 'H', 'P', 'M'} }; -u_map_fcc MAINMagic = { {'N', 'I', 'A', 'M'} }; - -bool wdt_MWMO::prepareLoadedData() -{ - if (fcc != MWMOMagic.fcc) - return false; - return true; -} - -bool wdt_MPHD::prepareLoadedData() -{ - if (fcc != MPHDMagic.fcc) - return false; - return true; -} - -bool wdt_MAIN::prepareLoadedData() -{ - if (fcc != MAINMagic.fcc) - return false; - return true; -} - -WDT_file::WDT_file() -{ - mphd = 0; - main = 0; - wmo = 0; -} - -WDT_file::~WDT_file() -{ - free(); -} - -void WDT_file::free() -{ - mphd = 0; - main = 0; - wmo = 0; - FileLoader::free(); -} - -bool WDT_file::prepareLoadedData() -{ - // Check parent - if (!FileLoader::prepareLoadedData()) - return false; - - mphd = (wdt_MPHD *)((uint8*)version+version->size+8); - if (!mphd->prepareLoadedData()) - return false; - main = (wdt_MAIN *)((uint8*)mphd + mphd->size+8); - if (!main->prepareLoadedData()) - return false; - wmo = (wdt_MWMO *)((uint8*)main+ main->size+8); - if (!wmo->prepareLoadedData()) - wmo = nullptr; // optional as of cataclysm - return true; -} diff --git a/src/tools/map_extractor/wdt.h b/src/tools/map_extractor/wdt.h index ec1186cee0..361677a613 100644 --- a/src/tools/map_extractor/wdt.h +++ b/src/tools/map_extractor/wdt.h @@ -27,62 +27,21 @@ #pragma pack(push, 1) -class wdt_MWMO{ - union{ - uint32 fcc; - char fcc_txt[4]; - }; -public: - uint32 size; - bool prepareLoadedData(); -}; - -class wdt_MPHD{ - union{ +class wdt_MAIN +{ + union + { uint32 fcc; char fcc_txt[4]; }; public: uint32 size; - uint32 data1; - uint32 data2; - uint32 data3; - uint32 data4; - uint32 data5; - uint32 data6; - uint32 data7; - uint32 data8; - bool prepareLoadedData(); -}; - -class wdt_MAIN{ - union{ - uint32 fcc; - char fcc_txt[4]; - }; -public: - uint32 size; - - struct adtData{ + struct adtData + { uint32 flag; uint32 data1; } adt_list[64][64]; - - bool prepareLoadedData(); -}; - -class WDT_file : public FileLoader{ -public: - bool prepareLoadedData(); - - WDT_file(); - ~WDT_file(); - void free(); - - wdt_MPHD *mphd; - wdt_MAIN *main; - wdt_MWMO *wmo; }; #pragma pack(pop) diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index b6e3f1cdca..fdc7e34987 100644 --- a/src/tools/mmaps_generator/TerrainBuilder.cpp +++ b/src/tools/mmaps_generator/TerrainBuilder.cpp @@ -80,7 +80,7 @@ struct map_liquidHeader namespace MMAP { - char const* MAP_VERSION_MAGIC = "v1.7"; + char const* MAP_VERSION_MAGIC = "v1.8"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { }