diff options
author | Shauren <shauren.trinity@gmail.com> | 2016-02-09 00:14:58 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2016-02-09 00:14:58 +0100 |
commit | 4f78efd4633f79285f176b61367a067b2cd90e2b (patch) | |
tree | 252dff34f55f084d097aecea3d269882d6286b0d /src | |
parent | b9f1dffa14fbd340634b035e05e59063d0028bfa (diff) |
Core/Maps: Parse MFBO adt chunk to properly handle height where player counts as falling under the map
* This fixes the height at which player is instantly killed when falling from The Frozen Throne
* Set PLAYER_FLAGS_IS_OUT_OF_BOUNDS on players under the map to enable release spirit button while still falling
Note: Extracting new maps is required
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/DataStores/DBCStructure.h | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 7 | ||||
-rw-r--r-- | src/server/game/Handlers/MovementHandler.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 62 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 11 | ||||
-rw-r--r-- | src/tools/map_extractor/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/tools/map_extractor/System.cpp | 107 | ||||
-rw-r--r-- | src/tools/map_extractor/adt.h | 16 | ||||
-rw-r--r-- | src/tools/map_extractor/loadlib.cpp | 3 | ||||
-rw-r--r-- | src/tools/mmaps_generator/TerrainBuilder.cpp | 2 |
10 files changed, 186 insertions, 30 deletions
diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index f051184b7e7..ec334fb3b8f 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -34,9 +34,6 @@ struct AnimKitEntry //uint32 LowDefAnimKitID; // 3 }; -// Temporary define until max depth is found somewhere (adt?) -#define MAX_MAP_DEPTH -5000 - struct AreaTableEntry { uint32 ID; // 0 diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index b3007affd83..7e30a125827 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -4235,6 +4235,7 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) // remove death flag + set aura SetByteValue(UNIT_FIELD_BYTES_1, 3, 0x00); + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); // This must be called always even on Players with race != RACE_NIGHTELF in case of faction change RemoveAurasDueToSpell(20584); // RACE_NIGHTELF speed bonuses @@ -4635,7 +4636,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[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < MAX_MAP_DEPTH) + if ((!IsAlive() && zone && zone->Flags[0] & AREA_FLAG_NEED_FLY) || GetTransport() || GetPositionZ() < GetMap()->GetMinHeight(GetPositionX(), GetPositionY())) { ResurrectPlayer(0.5f); SpawnCorpseBones(); @@ -4670,8 +4671,10 @@ void Player::RepopAtGraveyard() GetSession()->SendPacket(packet.Write()); } } - else if (GetPositionZ() < MAX_MAP_DEPTH) + 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); } bool Player::CanJoinConstantChannelInZone(ChatChannelsEntry const* channel, AreaTableEntry const* zone) const diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp index fb391229340..3ab9f683dea 100644 --- a/src/server/game/Handlers/MovementHandler.cpp +++ b/src/server/game/Handlers/MovementHandler.cpp @@ -382,7 +382,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov plrMover->UpdateFallInformationIfNeed(movementInfo, opcode); - if (movementInfo.pos.GetPositionZ() < MAX_MAP_DEPTH) + if (movementInfo.pos.GetPositionZ() < plrMover->GetMap()->GetMinHeight(movementInfo.pos.GetPositionX(), movementInfo.pos.GetPositionY())) { if (!(plrMover->GetBattleground() && plrMover->GetBattleground()->HandlePlayerUnderMap(_player))) { @@ -391,6 +391,7 @@ void WorldSession::HandleMovementOpcodes(WorldPackets::Movement::ClientPlayerMov /// @todo discard movement packets after the player is rooted if (plrMover->IsAlive()) { + plrMover->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_IS_OUT_OF_BOUNDS); plrMover->EnvironmentalDamage(DAMAGE_FALL_TO_VOID, GetPlayer()->GetMaxHealth()); // player can be alive if GM/etc // change the death state to CORPSE to prevent the death timer from diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 510d678821b..304f1ef7c2a 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -40,7 +40,7 @@ #include "Weather.h" u_map_magic MapMagic = { {'M','A','P','S'} }; -u_map_magic MapVersionMagic = { {'v','1','.','6'} }; +u_map_magic MapVersionMagic = { {'v','1','.','7'} }; u_map_magic MapAreaMagic = { {'A','R','E','A'} }; u_map_magic MapHeightMagic = { {'M','H','G','T'} }; u_map_magic MapLiquidMagic = { {'M','L','I','Q'} }; @@ -1655,13 +1655,15 @@ GridMap::GridMap() _flags = 0; // Area data _gridArea = 0; - _areaMap = NULL; + _areaMap = nullptr; // Height level data _gridHeight = INVALID_HEIGHT; _gridGetHeight = &GridMap::getHeightFromFlat; _gridIntHeightMultiplier = 0; - m_V9 = NULL; - m_V8 = NULL; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; // Liquid data _liquidType = 0; _liquidOffX = 0; @@ -1669,9 +1671,9 @@ GridMap::GridMap() _liquidWidth = 0; _liquidHeight = 0; _liquidLevel = INVALID_HEIGHT; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; } GridMap::~GridMap() @@ -1734,15 +1736,19 @@ void GridMap::unloadData() delete[] _areaMap; delete[] m_V9; delete[] m_V8; + delete[] _maxHeight; + delete[] _minHeight; delete[] _liquidEntry; delete[] _liquidFlags; delete[] _liquidMap; - _areaMap = NULL; - m_V9 = NULL; - m_V8 = NULL; - _liquidEntry = NULL; - _liquidFlags = NULL; - _liquidMap = NULL; + _areaMap = nullptr; + m_V9 = nullptr; + m_V8 = nullptr; + _maxHeight = nullptr; + _minHeight = nullptr; + _liquidEntry = nullptr; + _liquidFlags = nullptr; + _liquidMap = nullptr; _gridGetHeight = &GridMap::getHeightFromFlat; } @@ -1807,6 +1813,16 @@ bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) } else _gridGetHeight = &GridMap::getHeightFromFlat; + + if (header.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + _maxHeight = new float[16 * 16]; + _minHeight = new float[16 * 16]; + if (fread(_maxHeight, sizeof(float), 16 * 16, in) != 16 * 16 || + fread(_minHeight, sizeof(float), 16 * 16, in) != 16 * 16) + return false; + } + return true; } @@ -2077,6 +2093,18 @@ 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 (!_minHeight) + return -500.0f; + + x = 16 * (CENTER_GRID_ID - x / SIZE_OF_GRIDS); + y = 16 * (CENTER_GRID_ID - y / SIZE_OF_GRIDS); + int lx = (int)x & 15; + int ly = (int)y & 15; + return _minHeight[lx * 16 + ly]; +} + float GridMap::getLiquidLevel(float x, float y) const { if (!_liquidMap) @@ -2277,6 +2305,14 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float return mapHeight; // explicitly use map data } +float Map::GetMinHeight(float x, float y) const +{ + if (GridMap const* grid = const_cast<Map*>(this)->GetGrid(x, y)) + return grid->getMinHeight(x, y); + + return -500.0f; +} + inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry) { bool outdoor = true; diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index bf8770cfd30..bf29a257419 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -100,9 +100,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 { @@ -168,6 +169,8 @@ class GridMap uint16* m_uint16_V8; uint8* m_uint8_V8; }; + float* _maxHeight; + float* _minHeight; // Height level data float _gridHeight; float _gridIntHeightMultiplier; @@ -208,6 +211,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; uint8 getTerrainType(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = 0); @@ -329,6 +333,7 @@ class Map : public GridRefManager<NGridType> // 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 GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; + float GetMinHeight(float x, float y) const; ZLiquidStatus getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index 32fccaa2038..58435a51121 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -14,6 +14,7 @@ file(GLOB_RECURSE sources *.cpp *.h) include_directories ( ${CMAKE_SOURCE_DIR}/dep/CascLib/src ${CMAKE_SOURCE_DIR}/dep/cppformat + ${CMAKE_SOURCE_DIR}/dep/g3dlite/include ${CMAKE_SOURCE_DIR}/src/common ${CMAKE_SOURCE_DIR}/src/common/Utilities ${CMAKE_SOURCE_DIR}/src/server/shared @@ -31,6 +32,7 @@ target_link_libraries(mapextractor casc common format + g3dlib ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 2d36df68df1..a079ab42367 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -40,6 +40,8 @@ #include "adt.h" #include "wdt.h" +#include <G3D/Plane.h> + namespace { const char* HumanReadableCASCError(int error) @@ -351,7 +353,7 @@ void ReadLiquidTypeTableDBC() // Map file format data static char const* MAP_MAGIC = "MAPS"; -static char const* MAP_VERSION_MAGIC = "v1.6"; +static char const* MAP_VERSION_MAGIC = "v1.7"; static char const* MAP_AREA_MAGIC = "AREA"; static char const* MAP_HEIGHT_MAGIC = "MHGT"; static char const* MAP_LIQUID_MAGIC = "MLIQ"; @@ -380,9 +382,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 { @@ -442,14 +445,17 @@ 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]; -bool TransformToHighRes(uint16 holes, uint8 hiResHoles[8]) +float flight_box_max[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; +float flight_box_min[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; + +bool TransformToHighRes(uint16 lowResHoles, uint8 hiResHoles[8]) { for (uint8 i = 0; i < 8; i++) { for (uint8 j = 0; j < 8; j++) { int32 holeIdxL = (i / 2) * 4 + (j / 2); - if (((holes >> holeIdxL) & 1) == 1) + if (((lowResHoles >> holeIdxL) & 1) == 1) hiResHoles[i] |= (1 << j); } } @@ -482,6 +488,7 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int memset(holes, 0, sizeof(holes)); bool hasHoles = false; + bool hasFlightBox = false; for (std::multimap<std::string, FileChunk*>::const_iterator itr = adt.chunks.lower_bound("MCNK"); itr != adt.chunks.upper_bound("MCNK"); ++itr) { @@ -696,6 +703,82 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } } + if (FileChunk* chunk = adt.GetChunk("MFBO")) + { + static uint32 const indices[] = + { + 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 const boundGridCoords[] = + { + 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 + }; + + adt_MFBO* mfbo = chunk->As<adt_MFBO>(); + for (int gy = 0; gy < ADT_CELLS_PER_GRID; ++gy) + { + for (int gx = 0; gx < ADT_CELLS_PER_GRID; ++gx) + { + int32 quarterIndex = 0; + if (gy > ADT_CELLS_PER_GRID / 2) + { + if (gx > ADT_CELLS_PER_GRID / 2) + { + quarterIndex = 4 + gx < gy; + } + else + quarterIndex = 2; + } + else if (gx > ADT_CELLS_PER_GRID / 2) + { + quarterIndex = 7; + } + else + quarterIndex = gx > gy; + + quarterIndex *= 3; + G3D::Plane planeMax( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->max.coords[indices[quarterIndex + 2]]) + ); + + G3D::Plane planeMin( + G3D::Vector3(boundGridCoords[indices[quarterIndex + 0] * 2 + 0], boundGridCoords[indices[quarterIndex + 0] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 0]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 1] * 2 + 0], boundGridCoords[indices[quarterIndex + 1] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 1]]), + G3D::Vector3(boundGridCoords[indices[quarterIndex + 2] * 2 + 0], boundGridCoords[indices[quarterIndex + 2] * 2 + 1], mfbo->min.coords[indices[quarterIndex + 2]]) + ); + + auto non_nan_distance = [](G3D::Plane const& plane){ + auto d = plane.distance(G3D::Vector3(0.0f, 0.0f, 0.0f)); + assert(!G3D::isNaN(d)); + return d; + }; + + flight_box_max[gy][gx] = non_nan_distance(planeMax); + flight_box_min[gy][gx] = non_nan_distance(planeMin); + } + } + + hasFlightBox = true; + } + //============================================ // Try pack area data //============================================ @@ -787,6 +870,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int if (CONF_allow_float_to_int && (maxHeight - minHeight) < CONF_flat_height_delta_limit) heightHeader.flags |= MAP_HEIGHT_NO_HEIGHT; + 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)) { @@ -958,6 +1047,12 @@ bool ConvertADT(std::string const& inputPath, std::string const& outputPath, int } } + if (heightHeader.flags & MAP_HEIGHT_HAS_FLIGHT_BOUNDS) + { + outFile.write(reinterpret_cast<char*>(flight_box_max), sizeof(flight_box_max)); + outFile.write(reinterpret_cast<char*>(flight_box_min), sizeof(flight_box_min)); + } + // Store liquid data if need if (map.liquidMapOffset) { diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index 0c3b3780c16..bb6980507b7 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -219,6 +219,22 @@ struct adt_MH2O }; +struct adt_MFBO +{ + union + { + uint32 fcc; + char fcc_txt[4]; + }; + uint32 size; + struct plane + { + int16 coords[9]; + }; + plane max; + plane min; +}; + #pragma pack(pop) #endif diff --git a/src/tools/map_extractor/loadlib.cpp b/src/tools/map_extractor/loadlib.cpp index 39bbe5b1412..067683577f4 100644 --- a/src/tools/map_extractor/loadlib.cpp +++ b/src/tools/map_extractor/loadlib.cpp @@ -96,7 +96,8 @@ u_map_fcc InterestingChunks[] = { { 'K', 'N', 'C', 'M' } }, { { 'T', 'V', 'C', 'M' } }, { { 'O', 'M', 'W', 'M' } }, - { { 'Q', 'L', 'C', 'M' } } + { { 'Q', 'L', 'C', 'M' } }, + { { 'O', 'B', 'F', 'M' } } }; bool IsInterestingChunk(u_map_fcc const& fcc) diff --git a/src/tools/mmaps_generator/TerrainBuilder.cpp b/src/tools/mmaps_generator/TerrainBuilder.cpp index 33832f8986d..c4a32882c1d 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.6"; + char const* MAP_VERSION_MAGIC = "v1.7"; TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ } TerrainBuilder::~TerrainBuilder() { } |