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