Core/Maps: fixed several issues with liquids by merging some 335 branch commits that are taking mopg flags into account

This commit is contained in:
Ovahlord
2018-08-07 12:35:02 +02:00
parent 2008854f56
commit 3f53afd39e
17 changed files with 435 additions and 272 deletions

View File

@@ -56,6 +56,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'} };
static uint16 const holetab_h[4] = { 0x1111, 0x2222, 0x4444, 0x8888 };
static uint16 const holetab_v[4] = { 0x000F, 0x00F0, 0x0F00, 0xF000 };
#define DEFAULT_GRID_EXPIRY 300
#define MAX_GRID_LOAD_TIME 50
#define MAX_CREATURE_ATTACK_RADIUS (45.0f * sWorld->getRate(RATE_CREATURE_AGGRO))
@@ -1122,6 +1125,7 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float orie
AddToGrid(player, new_cell);
}
player->UpdatePositionData();
player->UpdateObjectVisibility(false);
}
@@ -1156,6 +1160,7 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa
if (creature->IsVehicle())
creature->GetVehicleKit()->RelocatePassengers();
creature->UpdateObjectVisibility(false);
creature->UpdatePositionData();
RemoveCreatureFromMoveList(creature);
}
@@ -1186,6 +1191,7 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float
{
go->Relocate(x, y, z, orientation);
go->UpdateModelPosition();
go->UpdatePositionData();
go->UpdateObjectVisibility(false);
RemoveGameObjectFromMoveList(go);
}
@@ -1218,6 +1224,7 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float
else
{
dynObj->Relocate(x, y, z, orientation);
dynObj->UpdatePositionData();
dynObj->UpdateObjectVisibility(false);
RemoveDynamicObjectFromMoveList(dynObj);
}
@@ -1311,6 +1318,7 @@ void Map::MoveAllCreaturesInMoveList()
if (c->IsVehicle())
c->GetVehicleKit()->RelocatePassengers();
//CreatureRelocationNotify(c, new_cell, new_cell.cellCoord());
c->UpdatePositionData();
c->UpdateObjectVisibility(false);
}
else
@@ -1365,6 +1373,7 @@ void Map::MoveAllGameObjectsInMoveList()
// update pos
go->Relocate(go->_newPosition);
go->UpdateModelPosition();
go->UpdatePositionData();
go->UpdateObjectVisibility(false);
}
else
@@ -1409,6 +1418,7 @@ void Map::MoveAllDynamicObjectsInMoveList()
{
// update pos
dynObj->Relocate(dynObj->_newPosition);
dynObj->UpdatePositionData();
dynObj->UpdateObjectVisibility(false);
}
else
@@ -1629,6 +1639,7 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly)
c->Relocate(resp_x, resp_y, resp_z, resp_o);
c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators
//CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord());
c->UpdatePositionData();
c->UpdateObjectVisibility(false);
return true;
}
@@ -1654,6 +1665,7 @@ bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly)
if (GameObjectCellRelocation(go, resp_cell))
{
go->Relocate(resp_x, resp_y, resp_z, resp_o);
go->UpdatePositionData();
go->UpdateObjectVisibility(false);
return true;
}
@@ -1809,6 +1821,7 @@ GridMap::GridMap()
_liquidEntry = nullptr;
_liquidFlags = nullptr;
_liquidMap = nullptr;
_holes = nullptr;
_fileExists = false;
}
@@ -1859,6 +1872,13 @@ bool GridMap::loadData(char const* filename)
fclose(in);
return false;
}
// loadup holes data (if any. check header.holesOffset)
if (header.holesSize && !loadHolesData(in, header.holesOffset, header.holesSize))
{
TC_LOG_ERROR("maps", "Error loading map holes data\n");
fclose(in);
return false;
}
fclose(in);
return true;
}
@@ -1877,12 +1897,14 @@ void GridMap::unloadData()
delete[] _liquidEntry;
delete[] _liquidFlags;
delete[] _liquidMap;
delete[] _holes;
_areaMap = nullptr;
m_V9 = nullptr;
m_V8 = nullptr;
_liquidEntry = nullptr;
_liquidFlags = nullptr;
_liquidMap = nullptr;
_holes = nullptr;
_gridGetHeight = &GridMap::getHeightFromFlat;
_fileExists = false;
}
@@ -1987,6 +2009,18 @@ bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
return true;
}
bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 size)
{
if (fseek(in, offset, SEEK_SET) != 0)
return false;
_holes = new uint16[16 * 16];
if (fread(_holes, sizeof(uint16), 16 * 16, in) != 16 * 16)
return false;
return true;
}
uint16 GridMap::getArea(float x, float y) const
{
if (!_areaMap)
@@ -2019,6 +2053,9 @@ float GridMap::getHeightFromFloat(float x, float y) const
x_int&=(MAP_RESOLUTION - 1);
y_int&=(MAP_RESOLUTION - 1);
if (isHole(x_int, y_int))
return INVALID_HEIGHT;
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
// +--------------> X
// | h1-------h2 Coordinates is:
@@ -2101,6 +2138,9 @@ float GridMap::getHeightFromUint8(float x, float y) const
x_int&=(MAP_RESOLUTION - 1);
y_int&=(MAP_RESOLUTION - 1);
if (isHole(x_int, y_int))
return INVALID_HEIGHT;
int32 a, b, c;
uint8 *V9_h1_ptr = &m_uint8_V9[x_int*128 + x_int + y_int];
if (x+y < 1)
@@ -2168,6 +2208,9 @@ float GridMap::getHeightFromUint16(float x, float y) const
x_int&=(MAP_RESOLUTION - 1);
y_int&=(MAP_RESOLUTION - 1);
if (isHole(x_int, y_int))
return INVALID_HEIGHT;
int32 a, b, c;
uint16 *V9_h1_ptr = &m_uint16_V9[x_int*128 + x_int + y_int];
if (x+y < 1)
@@ -2220,6 +2263,21 @@ float GridMap::getHeightFromUint16(float x, float y) const
return (float)((a * x) + (b * y) + c)*_gridIntHeightMultiplier + _gridHeight;
}
bool GridMap::isHole(int row, int col) const
{
if (!_holes)
return false;
int cellRow = row / 8; // 8 squares per cell
int cellCol = col / 8;
int holeRow = row % 8 / 2;
int holeCol = (col - (cellCol * 8)) / 2;
uint16 hole = _holes[cellRow * 16 + cellCol];
return (hole & holetab_h[holeCol] & holetab_v[holeRow]) != 0;
}
float GridMap::getLiquidLevel(float x, float y) const
{
if (!_liquidMap)
@@ -2239,19 +2297,6 @@ float GridMap::getLiquidLevel(float x, float y) const
return _liquidMap[cx_int*_liquidWidth + cy_int];
}
// Why does this return LIQUID data?
uint8 GridMap::getTerrainType(float x, float y) const
{
if (!_liquidFlags)
return 0;
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 _liquidFlags[lx*16 + ly];
}
// Get water state on map
inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, LiquidData* data)
{
@@ -2410,7 +2455,7 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float
{
float gridHeight = gmap->getHeight(x, y);
// look from a bit higher pos to find the floor, ignore under surface case
if (z + 2.0f > gridHeight)
if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE))
mapHeight = gridHeight;
}
@@ -2444,107 +2489,45 @@ float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float
return mapHeight; // explicitly use map data
}
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 /*adtId*/, int32 /*rootId*/, int32 /*groupId*/, WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
static inline bool IsInWMOInterior(uint32 mogpFlags)
{
bool outdoor = true;
if (wmoEntry && atEntry)
{
if (atEntry->flags & AREA_FLAG_OUTSIDE)
return true;
if (atEntry->flags & AREA_FLAG_INSIDE)
return false;
}
outdoor = (mogpFlags & 0x8) != 0;
if (wmoEntry)
{
if (wmoEntry->Flags & 4)
return true;
if (wmoEntry->Flags & 2)
outdoor = false;
}
return outdoor;
return (mogpFlags & 0x2000) != 0;
}
bool Map::IsOutdoors(PhaseShift const& phaseShift, float x, float y, float z) const
uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
// no wmo found? -> outside by default
if (!GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId))
return true;
AreaTableEntry const* atEntry = nullptr;
WMOAreaTableEntry const* wmoEntry= GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
if (wmoEntry)
{
TC_LOG_DEBUG("maps", "Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
}
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
}
bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const
{
float vmap_z = z;
float vmapZ;
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
if (vmgr->getAreaInfo(terrainMapId, x, y, vmap_z, flags, adtId, rootId, groupId))
{
// check if there's terrain between player height and object height
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
{
float _mapheight = gmap->getHeight(x, y);
// z + 2.0f condition taken from GetHeight(), not sure if it's such a great choice...
if (z + 2.0f > _mapheight && _mapheight > vmap_z)
return false;
}
return true;
}
return false;
}
bool hasVmapArea = VMAP::VMapFactory::createOrGetVMapManager()->getAreaInfo(terrainMapId, x, y, vmapZ, mogpFlags, adtId, rootId, groupId);
uint32 gridAreaId = 0;
float gridMapHeight = INVALID_HEIGHT;
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
{
gridAreaId = gmap->getArea(x, y);
gridMapHeight = gmap->getHeight(x, y);
}
uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const
{
uint32 mogpFlags;
int32 adtId, rootId, groupId;
WMOAreaTableEntry const* wmoEntry = nullptr;
AreaTableEntry const* atEntry = nullptr;
bool haveAreaInfo = false;
uint32 areaId = 0;
if (GetAreaInfo(phaseShift, x, y, z, mogpFlags, adtId, rootId, groupId))
// floor is the height we are closer to (but only if above)
if (hasVmapArea && G3D::fuzzyGe(z, vmapZ - GROUND_HEIGHT_TOLERANCE) && (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapZ > gridMapHeight))
{
haveAreaInfo = true;
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
if (wmoEntry)
{
// wmo found
if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId))
areaId = wmoEntry->areaId;
atEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId);
}
if (!areaId)
areaId = gridAreaId;
}
else
areaId = gridAreaId;
if (!areaId)
{
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
areaId = gmap->getArea(x, y);
areaId = i_mapEntry->linked_zone;
// this used while not all *.map files generated (instances)
if (!areaId)
areaId = i_mapEntry->linked_zone;
}
if (isOutdoors)
{
if (haveAreaInfo)
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
else
*isOutdoors = true;
}
return areaId;
}
@@ -2566,14 +2549,6 @@ void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32&
zoneid = area->zone;
}
uint8 Map::GetTerrainType(PhaseShift const& phaseShift, float x, float y) const
{
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))
return gmap->getTerrainType(x, y);
else
return 0;
}
ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data) const
{
ZLiquidStatus result = LIQUID_MAP_NO_WATER;
@@ -2582,11 +2557,14 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float
float ground_level = INVALID_HEIGHT;
uint32 liquid_type = 0;
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
uint32 mogpFlags = 0;
bool useGridLiquid = true;
if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags))
{
useGridLiquid = !IsInWMOInterior(mogpFlags);
TC_LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: %f ground: %f type: %u", liquid_level, ground_level, liquid_type);
// Check water level and ground level
if (liquid_level > ground_level && z > ground_level - 2)
if (liquid_level > ground_level && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE))
{
// All ok in water -> store data
if (data)
@@ -2639,27 +2617,157 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float
}
}
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
if (useGridLiquid)
{
LiquidData map_data;
ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data);
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level))
if (GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y))
{
if (data)
LiquidData map_data;
ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data);
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
if (map_result != LIQUID_MAP_NO_WATER && (map_data.level > ground_level))
{
// hardcoded in client like this
if (GetId() == 530 && map_data.entry == 2)
map_data.entry = 15;
if (data)
{
// hardcoded in client like this
if (GetId() == 530 && map_data.entry == 2)
map_data.entry = 15;
*data = map_data;
*data = map_data;
}
return map_result;
}
return map_result;
}
}
return result;
}
void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType) const
{
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
VMAP::AreaAndLiquidData vmapData;
uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y);
GridMap* gmap = m_parentTerrainMap->GetGrid(terrainMapId, x, y);
vmgr->getAreaAndLiquidData(terrainMapId, x, y, z, reqLiquidType, vmapData);
uint32 gridAreaId = 0;
float gridMapHeight = INVALID_HEIGHT;
if (gmap)
{
gridAreaId = gmap->getArea(x, y);
gridMapHeight = gmap->getHeight(x, y);
}
bool vmapLocation = false;
bool useGridLiquid = true;
// floor is the height we are closer to (but only if above)
data.floorZ = VMAP_INVALID_HEIGHT;
if (gridMapHeight > INVALID_HEIGHT && G3D::fuzzyGe(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE))
data.floorZ = gridMapHeight;
if (vmapData.floorZ > VMAP_INVALID_HEIGHT &&
G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) &&
(G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || vmapData.floorZ > gridMapHeight))
{
data.floorZ = vmapData.floorZ;
vmapLocation = true;
}
if (vmapLocation)
{
if (vmapData.areaInfo)
{
data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags);
// wmo found
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId);
data.outdoors = (vmapData.areaInfo->mogpFlags & 0x8) != 0;
if (wmoEntry)
{
data.areaId = wmoEntry->areaId;
if (wmoEntry->Flags & 4)
data.outdoors = true;
else if (wmoEntry->Flags & 2)
data.outdoors = false;
}
if (!data.areaId)
data.areaId = gridAreaId;
useGridLiquid = !IsInWMOInterior(vmapData.areaInfo->mogpFlags);
}
}
else
{
data.outdoors = true;
data.areaId = gridAreaId;
if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId))
data.outdoors = (areaEntry->flags & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE;
}
if (!data.areaId)
data.areaId = i_mapEntry->linked_zone;
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId);
// liquid processing
data.liquidStatus = LIQUID_MAP_NO_WATER;
if (vmapLocation && vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ)
{
uint32 liquidType = vmapData.liquidInfo->type;
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
liquidType = 15;
uint32 liquidFlagType = 0;
if (LiquidTypeEntry const* liquidData = sLiquidTypeStore.LookupEntry(liquidType))
liquidFlagType = liquidData->Type;
if (liquidType && liquidType < 21 && areaEntry)
{
uint32 overrideLiquid = areaEntry->LiquidTypeOverride[liquidFlagType];
if (!overrideLiquid && areaEntry->zone)
{
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->zone);
if (zoneEntry)
overrideLiquid = zoneEntry->LiquidTypeOverride[liquidFlagType];
}
if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid))
{
liquidType = overrideLiquid;
liquidFlagType = overrideData->Type;
}
}
data.liquidInfo = boost::in_place();
data.liquidInfo->level = vmapData.liquidInfo->level;
data.liquidInfo->depth_level = vmapData.floorZ;
data.liquidInfo->entry = liquidType;
data.liquidInfo->type_flags = 1 << liquidFlagType;
float delta = vmapData.liquidInfo->level - z;
if (delta > 2.0f)
data.liquidStatus = LIQUID_MAP_UNDER_WATER;
else if (delta > 0.0f)
data.liquidStatus = LIQUID_MAP_IN_WATER;
else if (delta > -0.1f)
data.liquidStatus = LIQUID_MAP_WATER_WALK;
else
data.liquidStatus = LIQUID_MAP_ABOVE_WATER;
}
// look up liquid data from grid map
if (gmap && useGridLiquid)
{
LiquidData gridMapLiquid;
ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid);
if (gridMapStatus != LIQUID_MAP_NO_WATER && (gridMapLiquid.level > vmapData.floorZ))
{
if (GetId() == 530 && gridMapLiquid.entry == 2)
gridMapLiquid.entry = 15;
data.liquidInfo = gridMapLiquid;
data.liquidStatus = gridMapStatus;
}
}
}
float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const
{
if (GridMap* gmap = m_parentTerrainMap->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y))