mirror of
https://github.com/mangosfour/server.git
synced 2025-12-12 01:37:00 +00:00
1220 lines
36 KiB
C++
1220 lines
36 KiB
C++
/*
|
|
* Copyright (C) 2005-2012 MaNGOS <http://getmangos.com/>
|
|
*
|
|
* 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, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "MapManager.h"
|
|
#include "Log.h"
|
|
#include "GridStates.h"
|
|
#include "CellImpl.h"
|
|
#include "Map.h"
|
|
#include "DBCEnums.h"
|
|
#include "DBCStores.h"
|
|
#include "GridMap.h"
|
|
#include "VMapFactory.h"
|
|
#include "MoveMap.h"
|
|
#include "World.h"
|
|
#include "Policies/SingletonImp.h"
|
|
#include "Util.h"
|
|
|
|
char const* MAP_MAGIC = "MAPS";
|
|
char const* MAP_VERSION_MAGIC = "v1.2";
|
|
char const* MAP_AREA_MAGIC = "AREA";
|
|
char const* MAP_HEIGHT_MAGIC = "MHGT";
|
|
char const* MAP_LIQUID_MAGIC = "MLIQ";
|
|
|
|
GridMap::GridMap()
|
|
{
|
|
m_flags = 0;
|
|
|
|
// Area data
|
|
m_gridArea = 0;
|
|
m_area_map = NULL;
|
|
|
|
// Height level data
|
|
m_gridHeight = INVALID_HEIGHT_VALUE;
|
|
m_gridGetHeight = &GridMap::getHeightFromFlat;
|
|
m_V9 = NULL;
|
|
m_V8 = NULL;
|
|
|
|
// Liquid data
|
|
m_liquidType = 0;
|
|
m_liquid_offX = 0;
|
|
m_liquid_offY = 0;
|
|
m_liquid_width = 0;
|
|
m_liquid_height = 0;
|
|
m_liquidLevel = INVALID_HEIGHT_VALUE;
|
|
m_liquid_type = NULL;
|
|
m_liquid_map = NULL;
|
|
}
|
|
|
|
GridMap::~GridMap()
|
|
{
|
|
unloadData();
|
|
}
|
|
|
|
bool GridMap::loadData(char* filename)
|
|
{
|
|
// Unload old data if exist
|
|
unloadData();
|
|
|
|
GridMapFileHeader header;
|
|
// Not return error if file not found
|
|
FILE* in = fopen(filename, "rb");
|
|
if (!in)
|
|
return true;
|
|
|
|
fread(&header, sizeof(header), 1, in);
|
|
if (header.mapMagic == *((uint32 const*)(MAP_MAGIC)) &&
|
|
header.versionMagic == *((uint32 const*)(MAP_VERSION_MAGIC)) &&
|
|
IsAcceptableClientBuild(header.buildMagic))
|
|
{
|
|
// loadup area data
|
|
if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize))
|
|
{
|
|
sLog.outError("Error loading map area data\n");
|
|
fclose(in);
|
|
return false;
|
|
}
|
|
|
|
// loadup height data
|
|
if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize))
|
|
{
|
|
sLog.outError("Error loading map height data\n");
|
|
fclose(in);
|
|
return false;
|
|
}
|
|
|
|
// loadup liquid data
|
|
if (header.liquidMapOffset && !loadGridMapLiquidData(in, header.liquidMapOffset, header.liquidMapSize))
|
|
{
|
|
sLog.outError("Error loading map liquids data\n");
|
|
fclose(in);
|
|
return false;
|
|
}
|
|
|
|
fclose(in);
|
|
return true;
|
|
}
|
|
|
|
sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.", filename);
|
|
fclose(in);
|
|
return false;
|
|
}
|
|
|
|
void GridMap::unloadData()
|
|
{
|
|
if (m_area_map)
|
|
delete[] m_area_map;
|
|
|
|
if (m_V9)
|
|
delete[] m_V9;
|
|
|
|
if (m_V8)
|
|
delete[] m_V8;
|
|
|
|
if (m_liquid_type)
|
|
delete[] m_liquid_type;
|
|
|
|
if (m_liquid_map)
|
|
delete[] m_liquid_map;
|
|
|
|
m_area_map = NULL;
|
|
m_V9 = NULL;
|
|
m_V8 = NULL;
|
|
m_liquid_type = NULL;
|
|
m_liquid_map = NULL;
|
|
m_gridGetHeight = &GridMap::getHeightFromFlat;
|
|
}
|
|
|
|
bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/)
|
|
{
|
|
GridMapAreaHeader header;
|
|
fseek(in, offset, SEEK_SET);
|
|
fread(&header, sizeof(header), 1, in);
|
|
if (header.fourcc != *((uint32 const*)(MAP_AREA_MAGIC)))
|
|
return false;
|
|
|
|
m_gridArea = header.gridArea;
|
|
if (!(header.flags & MAP_AREA_NO_AREA))
|
|
{
|
|
m_area_map = new uint16 [16 * 16];
|
|
fread(m_area_map, sizeof(uint16), 16 * 16, in);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/)
|
|
{
|
|
GridMapHeightHeader header;
|
|
fseek(in, offset, SEEK_SET);
|
|
fread(&header, sizeof(header), 1, in);
|
|
if (header.fourcc != *((uint32 const*)(MAP_HEIGHT_MAGIC)))
|
|
return false;
|
|
|
|
m_gridHeight = header.gridHeight;
|
|
if (!(header.flags & MAP_HEIGHT_NO_HEIGHT))
|
|
{
|
|
if ((header.flags & MAP_HEIGHT_AS_INT16))
|
|
{
|
|
m_uint16_V9 = new uint16 [129 * 129];
|
|
m_uint16_V8 = new uint16 [128 * 128];
|
|
fread(m_uint16_V9, sizeof(uint16), 129 * 129, in);
|
|
fread(m_uint16_V8, sizeof(uint16), 128 * 128, in);
|
|
m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535;
|
|
m_gridGetHeight = &GridMap::getHeightFromUint16;
|
|
}
|
|
else if ((header.flags & MAP_HEIGHT_AS_INT8))
|
|
{
|
|
m_uint8_V9 = new uint8 [129 * 129];
|
|
m_uint8_V8 = new uint8 [128 * 128];
|
|
fread(m_uint8_V9, sizeof(uint8), 129 * 129, in);
|
|
fread(m_uint8_V8, sizeof(uint8), 128 * 128, in);
|
|
m_gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255;
|
|
m_gridGetHeight = &GridMap::getHeightFromUint8;
|
|
}
|
|
else
|
|
{
|
|
m_V9 = new float [129 * 129];
|
|
m_V8 = new float [128 * 128];
|
|
fread(m_V9, sizeof(float), 129 * 129, in);
|
|
fread(m_V8, sizeof(float), 128 * 128, in);
|
|
m_gridGetHeight = &GridMap::getHeightFromFloat;
|
|
}
|
|
}
|
|
else
|
|
m_gridGetHeight = &GridMap::getHeightFromFlat;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GridMap::loadGridMapLiquidData(FILE* in, uint32 offset, uint32 /*size*/)
|
|
{
|
|
GridMapLiquidHeader header;
|
|
fseek(in, offset, SEEK_SET);
|
|
fread(&header, sizeof(header), 1, in);
|
|
if (header.fourcc != *((uint32 const*)(MAP_LIQUID_MAGIC)))
|
|
return false;
|
|
|
|
m_liquidType = header.liquidType;
|
|
m_liquid_offX = header.offsetX;
|
|
m_liquid_offY = header.offsetY;
|
|
m_liquid_width = header.width;
|
|
m_liquid_height = header.height;
|
|
m_liquidLevel = header.liquidLevel;
|
|
|
|
if (!(header.flags & MAP_LIQUID_NO_TYPE))
|
|
{
|
|
m_liquid_type = new uint8 [16 * 16];
|
|
fread(m_liquid_type, sizeof(uint8), 16 * 16, in);
|
|
}
|
|
|
|
if (!(header.flags & MAP_LIQUID_NO_HEIGHT))
|
|
{
|
|
m_liquid_map = new float [m_liquid_width * m_liquid_height];
|
|
fread(m_liquid_map, sizeof(float), m_liquid_width * m_liquid_height, in);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
uint16 GridMap::getArea(float x, float y)
|
|
{
|
|
if (!m_area_map)
|
|
return m_gridArea;
|
|
|
|
x = 16 * (32 - x / SIZE_OF_GRIDS);
|
|
y = 16 * (32 - y / SIZE_OF_GRIDS);
|
|
int lx = (int)x & 15;
|
|
int ly = (int)y & 15;
|
|
return m_area_map[lx * 16 + ly];
|
|
}
|
|
|
|
float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const
|
|
{
|
|
return m_gridHeight;
|
|
}
|
|
|
|
float GridMap::getHeightFromFloat(float x, float y) const
|
|
{
|
|
if (!m_V8 || !m_V9)
|
|
return m_gridHeight;
|
|
|
|
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
|
|
int x_int = (int)x;
|
|
int y_int = (int)y;
|
|
x -= x_int;
|
|
y -= y_int;
|
|
x_int &= (MAP_RESOLUTION - 1);
|
|
y_int &= (MAP_RESOLUTION - 1);
|
|
|
|
// Height stored as: h5 - its v8 grid, h1-h4 - its v9 grid
|
|
// +--------------> X
|
|
// | h1-------h2 Coordinates is:
|
|
// | | \ 1 / | h1 0,0
|
|
// | | \ / | h2 0,1
|
|
// | | 2 h5 3 | h3 1,0
|
|
// | | / \ | h4 1,1
|
|
// | | / 4 \ | h5 1/2,1/2
|
|
// | h3-------h4
|
|
// V Y
|
|
// For find height need
|
|
// 1 - detect triangle
|
|
// 2 - solve linear equation from triangle points
|
|
// Calculate coefficients for solve h = a*x + b*y + c
|
|
|
|
float a, b, c;
|
|
// Select triangle:
|
|
if (x + y < 1)
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 1 triangle (h1, h2, h5 points)
|
|
float h1 = m_V9[(x_int) * 129 + y_int];
|
|
float h2 = m_V9[(x_int + 1) * 129 + y_int];
|
|
float h5 = 2 * m_V8[x_int * 128 + y_int];
|
|
a = h2 - h1;
|
|
b = h5 - h1 - h2;
|
|
c = h1;
|
|
}
|
|
else
|
|
{
|
|
// 2 triangle (h1, h3, h5 points)
|
|
float h1 = m_V9[x_int * 129 + y_int ];
|
|
float h3 = m_V9[x_int * 129 + y_int + 1];
|
|
float h5 = 2 * m_V8[x_int * 128 + y_int];
|
|
a = h5 - h1 - h3;
|
|
b = h3 - h1;
|
|
c = h1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 3 triangle (h2, h4, h5 points)
|
|
float h2 = m_V9[(x_int + 1) * 129 + y_int ];
|
|
float h4 = m_V9[(x_int + 1) * 129 + y_int + 1];
|
|
float h5 = 2 * m_V8[x_int * 128 + y_int];
|
|
a = h2 + h4 - h5;
|
|
b = h4 - h2;
|
|
c = h5 - h4;
|
|
}
|
|
else
|
|
{
|
|
// 4 triangle (h3, h4, h5 points)
|
|
float h3 = m_V9[(x_int) * 129 + y_int + 1];
|
|
float h4 = m_V9[(x_int + 1) * 129 + y_int + 1];
|
|
float h5 = 2 * m_V8[x_int * 128 + y_int];
|
|
a = h4 - h3;
|
|
b = h3 + h4 - h5;
|
|
c = h5 - h4;
|
|
}
|
|
}
|
|
// Calculate height
|
|
return a * x + b * y + c;
|
|
}
|
|
|
|
float GridMap::getHeightFromUint8(float x, float y) const
|
|
{
|
|
if (!m_uint8_V8 || !m_uint8_V9)
|
|
return m_gridHeight;
|
|
|
|
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
|
|
int x_int = (int)x;
|
|
int y_int = (int)y;
|
|
x -= x_int;
|
|
y -= y_int;
|
|
x_int &= (MAP_RESOLUTION - 1);
|
|
y_int &= (MAP_RESOLUTION - 1);
|
|
|
|
int32 a, b, c;
|
|
uint8* V9_h1_ptr = &m_uint8_V9[x_int * 128 + x_int + y_int];
|
|
if (x + y < 1)
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 1 triangle (h1, h2, h5 points)
|
|
int32 h1 = V9_h1_ptr[ 0];
|
|
int32 h2 = V9_h1_ptr[129];
|
|
int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int];
|
|
a = h2 - h1;
|
|
b = h5 - h1 - h2;
|
|
c = h1;
|
|
}
|
|
else
|
|
{
|
|
// 2 triangle (h1, h3, h5 points)
|
|
int32 h1 = V9_h1_ptr[0];
|
|
int32 h3 = V9_h1_ptr[1];
|
|
int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int];
|
|
a = h5 - h1 - h3;
|
|
b = h3 - h1;
|
|
c = h1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 3 triangle (h2, h4, h5 points)
|
|
int32 h2 = V9_h1_ptr[129];
|
|
int32 h4 = V9_h1_ptr[130];
|
|
int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int];
|
|
a = h2 + h4 - h5;
|
|
b = h4 - h2;
|
|
c = h5 - h4;
|
|
}
|
|
else
|
|
{
|
|
// 4 triangle (h3, h4, h5 points)
|
|
int32 h3 = V9_h1_ptr[ 1];
|
|
int32 h4 = V9_h1_ptr[130];
|
|
int32 h5 = 2 * m_uint8_V8[x_int * 128 + y_int];
|
|
a = h4 - h3;
|
|
b = h3 + h4 - h5;
|
|
c = h5 - h4;
|
|
}
|
|
}
|
|
|
|
// Calculate height
|
|
return (float)((a * x) + (b * y) + c) * m_gridIntHeightMultiplier + m_gridHeight;
|
|
}
|
|
|
|
float GridMap::getHeightFromUint16(float x, float y) const
|
|
{
|
|
if (!m_uint16_V8 || !m_uint16_V9)
|
|
return m_gridHeight;
|
|
|
|
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
|
|
int x_int = (int)x;
|
|
int y_int = (int)y;
|
|
x -= x_int;
|
|
y -= y_int;
|
|
x_int &= (MAP_RESOLUTION - 1);
|
|
y_int &= (MAP_RESOLUTION - 1);
|
|
|
|
int32 a, b, c;
|
|
uint16* V9_h1_ptr = &m_uint16_V9[x_int * 128 + x_int + y_int];
|
|
if (x + y < 1)
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 1 triangle (h1, h2, h5 points)
|
|
int32 h1 = V9_h1_ptr[ 0];
|
|
int32 h2 = V9_h1_ptr[129];
|
|
int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int];
|
|
a = h2 - h1;
|
|
b = h5 - h1 - h2;
|
|
c = h1;
|
|
}
|
|
else
|
|
{
|
|
// 2 triangle (h1, h3, h5 points)
|
|
int32 h1 = V9_h1_ptr[0];
|
|
int32 h3 = V9_h1_ptr[1];
|
|
int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int];
|
|
a = h5 - h1 - h3;
|
|
b = h3 - h1;
|
|
c = h1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (x > y)
|
|
{
|
|
// 3 triangle (h2, h4, h5 points)
|
|
int32 h2 = V9_h1_ptr[129];
|
|
int32 h4 = V9_h1_ptr[130];
|
|
int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int];
|
|
a = h2 + h4 - h5;
|
|
b = h4 - h2;
|
|
c = h5 - h4;
|
|
}
|
|
else
|
|
{
|
|
// 4 triangle (h3, h4, h5 points)
|
|
int32 h3 = V9_h1_ptr[ 1];
|
|
int32 h4 = V9_h1_ptr[130];
|
|
int32 h5 = 2 * m_uint16_V8[x_int * 128 + y_int];
|
|
a = h4 - h3;
|
|
b = h3 + h4 - h5;
|
|
c = h5 - h4;
|
|
}
|
|
}
|
|
|
|
// Calculate height
|
|
return (float)((a * x) + (b * y) + c) * m_gridIntHeightMultiplier + m_gridHeight;
|
|
}
|
|
|
|
float GridMap::getLiquidLevel(float x, float y)
|
|
{
|
|
if (!m_liquid_map)
|
|
return m_liquidLevel;
|
|
|
|
x = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
y = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
|
|
int cx_int = ((int)x & (MAP_RESOLUTION - 1)) - m_liquid_offY;
|
|
int cy_int = ((int)y & (MAP_RESOLUTION - 1)) - m_liquid_offX;
|
|
|
|
if (cx_int < 0 || cx_int >= m_liquid_height)
|
|
return INVALID_HEIGHT_VALUE;
|
|
|
|
if (cy_int < 0 || cy_int >= m_liquid_width)
|
|
return INVALID_HEIGHT_VALUE;
|
|
|
|
return m_liquid_map[cx_int * m_liquid_width + cy_int];
|
|
}
|
|
|
|
uint8 GridMap::getTerrainType(float x, float y)
|
|
{
|
|
if (!m_liquid_type)
|
|
return (uint8)m_liquidType;
|
|
|
|
x = 16 * (32 - x / SIZE_OF_GRIDS);
|
|
y = 16 * (32 - y / SIZE_OF_GRIDS);
|
|
int lx = (int)x & 15;
|
|
int ly = (int)y & 15;
|
|
return m_liquid_type[lx * 16 + ly];
|
|
}
|
|
|
|
// Get water state on map
|
|
GridMapLiquidStatus GridMap::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData* data)
|
|
{
|
|
// Check water type (if no water return)
|
|
if (!m_liquid_type && !m_liquidType)
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
// Get cell
|
|
float cx = MAP_RESOLUTION * (32 - x / SIZE_OF_GRIDS);
|
|
float cy = MAP_RESOLUTION * (32 - y / SIZE_OF_GRIDS);
|
|
|
|
int x_int = (int)cx & (MAP_RESOLUTION - 1);
|
|
int y_int = (int)cy & (MAP_RESOLUTION - 1);
|
|
|
|
// Check water type in cell
|
|
uint8 type = m_liquid_type ? m_liquid_type[(x_int >> 3) * 16 + (y_int >> 3)] : m_liquidType;
|
|
if (type == 0)
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
// Check req liquid type mask
|
|
if (ReqLiquidType && !(ReqLiquidType & type))
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
// Check water level:
|
|
// Check water height map
|
|
int lx_int = x_int - m_liquid_offY;
|
|
if (lx_int < 0 || lx_int >= m_liquid_height)
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
int ly_int = y_int - m_liquid_offX;
|
|
if (ly_int < 0 || ly_int >= m_liquid_width)
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
// Get water level
|
|
float liquid_level = m_liquid_map ? m_liquid_map[lx_int * m_liquid_width + ly_int] : m_liquidLevel;
|
|
|
|
// Get ground level (sub 0.2 for fix some errors)
|
|
float ground_level = getHeight(x, y);
|
|
|
|
// Check water level and ground level
|
|
if (liquid_level < ground_level || z < ground_level - 2)
|
|
return LIQUID_MAP_NO_WATER;
|
|
|
|
// All ok in water -> store data
|
|
if (data)
|
|
{
|
|
data->type = type;
|
|
data->level = liquid_level;
|
|
data->depth_level = ground_level;
|
|
}
|
|
|
|
// For speed check as int values
|
|
int delta = int((liquid_level - z) * 10);
|
|
|
|
// Get position delta
|
|
if (delta > 20) // Under water
|
|
return LIQUID_MAP_UNDER_WATER;
|
|
|
|
if (delta > 0) // In water
|
|
return LIQUID_MAP_IN_WATER;
|
|
|
|
if (delta > -1) // Walk on water
|
|
return LIQUID_MAP_WATER_WALK;
|
|
// Above water
|
|
return LIQUID_MAP_ABOVE_WATER;
|
|
}
|
|
|
|
bool GridMap::ExistMap(uint32 mapid, int gx, int gy)
|
|
{
|
|
int len = sWorld.GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
|
|
char* tmp = new char[len];
|
|
snprintf(tmp, len, (char*)(sWorld.GetDataPath() + "maps/%03u%02u%02u.map").c_str(), mapid, gx, gy);
|
|
|
|
FILE* pf = fopen(tmp, "rb");
|
|
|
|
if (!pf)
|
|
{
|
|
sLog.outError("Check existing of map file '%s': not exist!", tmp);
|
|
delete[] tmp;
|
|
return false;
|
|
}
|
|
|
|
GridMapFileHeader header;
|
|
fread(&header, sizeof(header), 1, pf);
|
|
if (header.mapMagic != *((uint32 const*)(MAP_MAGIC)) ||
|
|
header.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC)) ||
|
|
!IsAcceptableClientBuild(header.buildMagic))
|
|
{
|
|
sLog.outError("Map file '%s' is non-compatible version (outdated?). Please, create new using ad.exe program.", tmp);
|
|
delete [] tmp;
|
|
fclose(pf); //close file before return
|
|
return false;
|
|
}
|
|
|
|
delete [] tmp;
|
|
fclose(pf);
|
|
return true;
|
|
}
|
|
|
|
bool GridMap::ExistVMap(uint32 mapid, int gx, int gy)
|
|
{
|
|
if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager())
|
|
{
|
|
if (vmgr->isMapLoadingEnabled())
|
|
{
|
|
// x and y are swapped !! => fixed now
|
|
bool exists = vmgr->existsMap((sWorld.GetDataPath() + "vmaps").c_str(), mapid, gx, gy);
|
|
if (!exists)
|
|
{
|
|
std::string name = vmgr->getDirFileName(mapid, gx, gy);
|
|
sLog.outError("VMap file '%s' is missing or point to wrong version vmap file, redo vmaps with latest vmap_assembler.exe program", (sWorld.GetDataPath() + "vmaps/" + name).c_str());
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
TerrainInfo::TerrainInfo(uint32 mapid) : m_mapId(mapid)
|
|
{
|
|
for (int k = 0; k < MAX_NUMBER_OF_GRIDS; ++k)
|
|
{
|
|
for (int i = 0; i < MAX_NUMBER_OF_GRIDS; ++i)
|
|
{
|
|
m_GridMaps[i][k] = NULL;
|
|
m_GridRef[i][k] = 0;
|
|
}
|
|
}
|
|
|
|
//clean up GridMap objects every minute
|
|
const uint32 iCleanUpInterval = 60;
|
|
//schedule start randlomly
|
|
const uint32 iRandomStart = urand(20, 40);
|
|
|
|
i_timer.SetInterval(iCleanUpInterval * 1000);
|
|
i_timer.SetCurrent(iRandomStart * 1000);
|
|
}
|
|
|
|
TerrainInfo::~TerrainInfo()
|
|
{
|
|
for (int k = 0; k < MAX_NUMBER_OF_GRIDS; ++k)
|
|
for (int i = 0; i < MAX_NUMBER_OF_GRIDS; ++i)
|
|
delete m_GridMaps[i][k];
|
|
|
|
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(m_mapId);
|
|
MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(m_mapId);
|
|
}
|
|
|
|
GridMap* TerrainInfo::Load(const uint32 x, const uint32 y)
|
|
{
|
|
MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS);
|
|
MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS);
|
|
|
|
//reference grid as a first step
|
|
RefGrid(x, y);
|
|
|
|
//quick check if GridMap already loaded
|
|
GridMap* pMap = m_GridMaps[x][y];
|
|
if (!pMap)
|
|
pMap = LoadMapAndVMap(x, y);
|
|
|
|
return pMap;
|
|
}
|
|
|
|
//schedule lazy GridMap object cleanup
|
|
void TerrainInfo::Unload(const uint32 x, const uint32 y)
|
|
{
|
|
MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS);
|
|
MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS);
|
|
|
|
if (m_GridMaps[x][y])
|
|
{
|
|
//decrease grid reference count...
|
|
if (UnrefGrid(x, y) == 0)
|
|
{
|
|
//TODO: add your additional logic here
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//call this method only
|
|
void TerrainInfo::CleanUpGrids(const uint32 diff)
|
|
{
|
|
i_timer.Update(diff);
|
|
if (!i_timer.Passed())
|
|
return;
|
|
|
|
for (int y = 0; y < MAX_NUMBER_OF_GRIDS; ++y)
|
|
{
|
|
for (int x = 0; x < MAX_NUMBER_OF_GRIDS; ++x)
|
|
{
|
|
const int16& iRef = m_GridRef[x][y];
|
|
GridMap* pMap = m_GridMaps[x][y];
|
|
|
|
//delete those GridMap objects which have refcount = 0
|
|
if (pMap && iRef == 0)
|
|
{
|
|
m_GridMaps[x][y] = NULL;
|
|
//delete grid data if reference count == 0
|
|
pMap->unloadData();
|
|
delete pMap;
|
|
|
|
//unload VMAPS...
|
|
VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(m_mapId, x, y);
|
|
|
|
//unload mmap...
|
|
MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(m_mapId, x, y);
|
|
}
|
|
}
|
|
}
|
|
|
|
i_timer.Reset();
|
|
}
|
|
|
|
int TerrainInfo::RefGrid(const uint32& x, const uint32& y)
|
|
{
|
|
MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS);
|
|
MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS);
|
|
|
|
LOCK_GUARD _lock(m_refMutex);
|
|
return (m_GridRef[x][y] += 1);
|
|
}
|
|
|
|
int TerrainInfo::UnrefGrid(const uint32& x, const uint32& y)
|
|
{
|
|
MANGOS_ASSERT(x < MAX_NUMBER_OF_GRIDS);
|
|
MANGOS_ASSERT(y < MAX_NUMBER_OF_GRIDS);
|
|
|
|
int16& iRef = m_GridRef[x][y];
|
|
|
|
LOCK_GUARD _lock(m_refMutex);
|
|
if (iRef > 0)
|
|
return (iRef -= 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
float TerrainInfo::GetHeight(float x, float y, float z, bool pUseVmaps, float maxSearchDist) const
|
|
{
|
|
// find raw .map surface under Z coordinates
|
|
float mapHeight;
|
|
float z2 = z + 2.f;
|
|
if (GridMap* gmap = const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
float _mapheight = gmap->getHeight(x, y);
|
|
|
|
// look from a bit higher pos to find the floor, ignore under surface case
|
|
if (z2 > _mapheight)
|
|
mapHeight = _mapheight;
|
|
else
|
|
mapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
|
}
|
|
else
|
|
mapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
|
|
|
float vmapHeight;
|
|
if (pUseVmaps)
|
|
{
|
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
|
if (vmgr->isHeightCalcEnabled())
|
|
{
|
|
// if mapHeight has been found search vmap height at least until mapHeight point
|
|
// this prevent case when original Z "too high above ground and vmap height search fail"
|
|
// this will not affect most normal cases (no map in instance, or stay at ground at continent)
|
|
if (mapHeight > INVALID_HEIGHT && z2 - mapHeight > maxSearchDist)
|
|
maxSearchDist = z2 - mapHeight + 1.0f; // 1.0 make sure that we not fail for case when map height near but above for vamp height
|
|
|
|
// look from a bit higher pos to find the floor
|
|
vmapHeight = vmgr->getHeight(GetMapId(), x, y, z2, maxSearchDist);
|
|
}
|
|
else
|
|
vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
|
}
|
|
else
|
|
vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
|
|
|
// mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
|
|
// vmapheight set for any under Z value or <= INVALID_HEIGHT
|
|
|
|
if (vmapHeight > INVALID_HEIGHT)
|
|
{
|
|
if (mapHeight > INVALID_HEIGHT)
|
|
{
|
|
// we have mapheight and vmapheight and must select more appropriate
|
|
|
|
// we are already under the surface or vmap height above map heigt
|
|
// or if the distance of the vmap height is less the land height distance
|
|
if (z < mapHeight || vmapHeight > mapHeight || fabs(mapHeight - z) > fabs(vmapHeight - z))
|
|
return vmapHeight;
|
|
else
|
|
return mapHeight; // better use .map surface height
|
|
|
|
}
|
|
else
|
|
return vmapHeight; // we have only vmapHeight (if have)
|
|
}
|
|
|
|
return mapHeight;
|
|
}
|
|
|
|
inline bool IsOutdoorWMO(uint32 mogpFlags, int32 adtId, int32 rootId, int32 groupId,
|
|
WMOAreaTableEntry const* wmoEntry, AreaTableEntry const* atEntry)
|
|
{
|
|
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;
|
|
|
|
if (wmoEntry)
|
|
{
|
|
if (wmoEntry->Flags & 4)
|
|
return true;
|
|
|
|
if ((wmoEntry->Flags & 2) != 0)
|
|
outdoor = false;
|
|
}
|
|
return outdoor;
|
|
}
|
|
|
|
bool TerrainInfo::IsOutdoors(float x, float y, float z) const
|
|
{
|
|
uint32 mogpFlags;
|
|
int32 adtId, rootId, groupId;
|
|
|
|
// no wmo found? -> outside by default
|
|
if (!GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
|
return true;
|
|
|
|
AreaTableEntry const* atEntry = 0;
|
|
WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
|
if (wmoEntry)
|
|
{
|
|
DEBUG_LOG("Got WMOAreaTableEntry! flag %u, areaid %u", wmoEntry->Flags, wmoEntry->areaId);
|
|
|
|
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
|
}
|
|
|
|
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
|
}
|
|
|
|
bool TerrainInfo::GetAreaInfo(float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
|
{
|
|
float vmap_z = z;
|
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
|
if (vmgr->getAreaInfo(GetMapId(), x, y, vmap_z, flags, adtId, rootId, groupId))
|
|
{
|
|
// check if there's terrain between player height and object height
|
|
if (GridMap* gmap = const_cast<TerrainInfo*>(this)->GetGrid(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;
|
|
}
|
|
|
|
uint16 TerrainInfo::GetAreaFlag(float x, float y, float z, bool* isOutdoors) const
|
|
{
|
|
uint32 mogpFlags;
|
|
int32 adtId, rootId, groupId;
|
|
WMOAreaTableEntry const* wmoEntry = 0;
|
|
AreaTableEntry const* atEntry = 0;
|
|
bool haveAreaInfo = false;
|
|
|
|
if (GetAreaInfo(x, y, z, mogpFlags, adtId, rootId, groupId))
|
|
{
|
|
haveAreaInfo = true;
|
|
wmoEntry = GetWMOAreaTableEntryByTripple(rootId, adtId, groupId);
|
|
if (wmoEntry)
|
|
atEntry = GetAreaEntryByAreaID(wmoEntry->areaId);
|
|
}
|
|
|
|
uint16 areaflag;
|
|
if (atEntry)
|
|
areaflag = atEntry->exploreFlag;
|
|
else
|
|
{
|
|
if (GridMap* gmap = const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
areaflag = gmap->getArea(x, y);
|
|
// this used while not all *.map files generated (instances)
|
|
else
|
|
areaflag = GetAreaFlagByMapId(GetMapId());
|
|
}
|
|
|
|
if (isOutdoors)
|
|
{
|
|
if (haveAreaInfo)
|
|
*isOutdoors = IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
|
|
else
|
|
*isOutdoors = true;
|
|
}
|
|
return areaflag;
|
|
}
|
|
|
|
uint8 TerrainInfo::GetTerrainType(float x, float y) const
|
|
{
|
|
if (GridMap* gmap = const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
return gmap->getTerrainType(x, y);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
uint32 TerrainInfo::GetAreaId(float x, float y, float z) const
|
|
{
|
|
return TerrainManager::GetAreaIdByAreaFlag(GetAreaFlag(x, y, z), m_mapId);
|
|
}
|
|
|
|
uint32 TerrainInfo::GetZoneId(float x, float y, float z) const
|
|
{
|
|
return TerrainManager::GetZoneIdByAreaFlag(GetAreaFlag(x, y, z), m_mapId);
|
|
}
|
|
|
|
void TerrainInfo::GetZoneAndAreaId(uint32& zoneid, uint32& areaid, float x, float y, float z) const
|
|
{
|
|
TerrainManager::GetZoneAndAreaIdByAreaFlag(zoneid, areaid, GetAreaFlag(x, y, z), m_mapId);
|
|
}
|
|
|
|
|
|
GridMapLiquidStatus TerrainInfo::getLiquidStatus(float x, float y, float z, uint8 ReqLiquidType, GridMapLiquidData* data) const
|
|
{
|
|
GridMapLiquidStatus result = LIQUID_MAP_NO_WATER;
|
|
VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager();
|
|
float liquid_level, ground_level = INVALID_HEIGHT_VALUE;
|
|
uint32 liquid_type;
|
|
if (vmgr->GetLiquidLevel(GetMapId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type))
|
|
{
|
|
DEBUG_LOG("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)
|
|
{
|
|
// All ok in water -> store data
|
|
if (data)
|
|
{
|
|
data->type = liquid_type;
|
|
data->level = liquid_level;
|
|
data->depth_level = ground_level;
|
|
}
|
|
|
|
// For speed check as int values
|
|
int delta = int((liquid_level - z) * 10);
|
|
|
|
// Get position delta
|
|
if (delta > 20) // Under water
|
|
return LIQUID_MAP_UNDER_WATER;
|
|
if (delta > 0) // In water
|
|
return LIQUID_MAP_IN_WATER;
|
|
if (delta > -1) // Walk on water
|
|
return LIQUID_MAP_WATER_WALK;
|
|
result = LIQUID_MAP_ABOVE_WATER;
|
|
}
|
|
}
|
|
if (GridMap* gmap = const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
GridMapLiquidData map_data;
|
|
GridMapLiquidStatus 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 (data)
|
|
*data = map_data;
|
|
return map_result;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool TerrainInfo::IsInWater(float x, float y, float pZ, GridMapLiquidData* data) const
|
|
{
|
|
// Check surface in x, y point for liquid
|
|
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
GridMapLiquidData liquid_status;
|
|
GridMapLiquidData* liquid_ptr = data ? data : &liquid_status;
|
|
if (getLiquidStatus(x, y, pZ, MAP_ALL_LIQUIDS, liquid_ptr))
|
|
{
|
|
//if (liquid_prt->level - liquid_prt->depth_level > 2) //???
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool TerrainInfo::IsUnderWater(float x, float y, float z) const
|
|
{
|
|
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
if (getLiquidStatus(x, y, z, MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN)&LIQUID_MAP_UNDER_WATER)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Function find higher form water or ground height for current floor
|
|
*
|
|
* @param x, y, z Coordinates original point at floor level
|
|
*
|
|
* @param pGround optional arg for retrun calculated by function work ground height, it let avoid in caller code recalculate height for point if it need
|
|
*
|
|
* @param swim z coordinate can be calculated for select above/at or under z coordinate (for fly or swim/walking by bottom)
|
|
* in last cases for in water returned under water height for avoid client set swimming unit as saty at water.
|
|
*
|
|
* @return calculated z coordinate
|
|
*/
|
|
float TerrainInfo::GetWaterOrGroundLevel(float x, float y, float z, float* pGround /*= NULL*/, bool swim /*= false*/) const
|
|
{
|
|
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
// we need ground level (including grid height version) for proper return water level in point
|
|
float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH);
|
|
if (pGround)
|
|
*pGround = ground_z;
|
|
|
|
GridMapLiquidData liquid_status;
|
|
|
|
GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
|
|
return res ? (swim ? liquid_status.level - 2.0f : liquid_status.level) : ground_z;
|
|
}
|
|
|
|
return VMAP_INVALID_HEIGHT_VALUE;
|
|
}
|
|
|
|
GridMap* TerrainInfo::GetGrid(const float x, const float y)
|
|
{
|
|
// half opt method
|
|
int gx = (int)(32 - x / SIZE_OF_GRIDS); //grid x
|
|
int gy = (int)(32 - y / SIZE_OF_GRIDS); //grid y
|
|
|
|
//quick check if GridMap already loaded
|
|
GridMap* pMap = m_GridMaps[gx][gy];
|
|
if (!pMap)
|
|
pMap = LoadMapAndVMap(gx, gy);
|
|
|
|
return pMap;
|
|
}
|
|
|
|
GridMap* TerrainInfo::LoadMapAndVMap(const uint32 x, const uint32 y)
|
|
{
|
|
//double checked lock pattern
|
|
if (!m_GridMaps[x][y])
|
|
{
|
|
LOCK_GUARD lock(m_mutex);
|
|
|
|
if (!m_GridMaps[x][y])
|
|
{
|
|
GridMap* map = new GridMap();
|
|
|
|
// map file name
|
|
char* tmp = NULL;
|
|
int len = sWorld.GetDataPath().length() + strlen("maps/%03u%02u%02u.map") + 1;
|
|
tmp = new char[len];
|
|
snprintf(tmp, len, (char*)(sWorld.GetDataPath() + "maps/%03u%02u%02u.map").c_str(), m_mapId, x, y);
|
|
sLog.outDetail("Loading map %s", tmp);
|
|
|
|
if (!map->loadData(tmp))
|
|
{
|
|
sLog.outError("Error load map file: \n %s\n", tmp);
|
|
//ASSERT(false);
|
|
}
|
|
|
|
delete [] tmp;
|
|
m_GridMaps[x][y] = map;
|
|
|
|
//load VMAPs for current map/grid...
|
|
const MapEntry* i_mapEntry = sMapStore.LookupEntry(m_mapId);
|
|
const char* mapName = i_mapEntry ? i_mapEntry->name[sWorld.GetDefaultDbcLocale()] : "UNNAMEDMAP\x0";
|
|
|
|
int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld.GetDataPath() + "vmaps").c_str(), m_mapId, x, y);
|
|
switch (vmapLoadResult)
|
|
{
|
|
case VMAP::VMAP_LOAD_RESULT_OK:
|
|
sLog.outDetail("VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x, y, x, y);
|
|
break;
|
|
case VMAP::VMAP_LOAD_RESULT_ERROR:
|
|
sLog.outDetail("Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x, y, x, y);
|
|
break;
|
|
case VMAP::VMAP_LOAD_RESULT_IGNORED:
|
|
DEBUG_LOG("Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", mapName, m_mapId, x, y, x, y);
|
|
break;
|
|
}
|
|
|
|
// load navmesh
|
|
MMAP::MMapFactory::createOrGetMMapManager()->loadMap(m_mapId, x, y);
|
|
}
|
|
}
|
|
|
|
return m_GridMaps[x][y];
|
|
}
|
|
|
|
float TerrainInfo::GetWaterLevel(float x, float y, float z, float* pGround /*= NULL*/) const
|
|
{
|
|
if (const_cast<TerrainInfo*>(this)->GetGrid(x, y))
|
|
{
|
|
// we need ground level (including grid height version) for proper return water level in point
|
|
float ground_z = GetHeight(x, y, z, true, DEFAULT_WATER_SEARCH);
|
|
if (pGround)
|
|
*pGround = ground_z;
|
|
|
|
GridMapLiquidData liquid_status;
|
|
|
|
GridMapLiquidStatus res = getLiquidStatus(x, y, ground_z, MAP_ALL_LIQUIDS, &liquid_status);
|
|
if (!res)
|
|
return VMAP_INVALID_HEIGHT_VALUE;
|
|
|
|
return liquid_status.level;
|
|
}
|
|
|
|
return VMAP_INVALID_HEIGHT_VALUE;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#define CLASS_LOCK MaNGOS::ClassLevelLockable<TerrainManager, ACE_Thread_Mutex>
|
|
INSTANTIATE_SINGLETON_2(TerrainManager, CLASS_LOCK);
|
|
INSTANTIATE_CLASS_MUTEX(TerrainManager, ACE_Thread_Mutex);
|
|
|
|
TerrainManager::TerrainManager()
|
|
{
|
|
}
|
|
|
|
TerrainManager::~TerrainManager()
|
|
{
|
|
for (TerrainDataMap::iterator it = i_TerrainMap.begin(); it != i_TerrainMap.end(); ++it)
|
|
delete it->second;
|
|
}
|
|
|
|
TerrainInfo* TerrainManager::LoadTerrain(const uint32 mapId)
|
|
{
|
|
Guard _guard(*this);
|
|
|
|
TerrainInfo* ptr = NULL;
|
|
TerrainDataMap::const_iterator iter = i_TerrainMap.find(mapId);
|
|
if (iter == i_TerrainMap.end())
|
|
{
|
|
ptr = new TerrainInfo(mapId);
|
|
i_TerrainMap[mapId] = ptr;
|
|
}
|
|
else
|
|
ptr = (*iter).second;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
void TerrainManager::UnloadTerrain(const uint32 mapId)
|
|
{
|
|
if (sWorld.getConfig(CONFIG_BOOL_GRID_UNLOAD) == 0)
|
|
return;
|
|
|
|
Guard _guard(*this);
|
|
|
|
TerrainDataMap::iterator iter = i_TerrainMap.find(mapId);
|
|
if (iter != i_TerrainMap.end())
|
|
{
|
|
TerrainInfo* ptr = (*iter).second;
|
|
//lets check if this object can be actually freed
|
|
if (ptr->IsReferenced() == false)
|
|
{
|
|
i_TerrainMap.erase(iter);
|
|
delete ptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
void TerrainManager::Update(const uint32 diff)
|
|
{
|
|
//global garbage collection for GridMap objects and VMaps
|
|
for (TerrainDataMap::iterator iter = i_TerrainMap.begin(); iter != i_TerrainMap.end(); ++iter)
|
|
iter->second->CleanUpGrids(diff);
|
|
}
|
|
|
|
void TerrainManager::UnloadAll()
|
|
{
|
|
for (TerrainDataMap::iterator it = i_TerrainMap.begin(); it != i_TerrainMap.end(); ++it)
|
|
delete it->second;
|
|
|
|
i_TerrainMap.clear();
|
|
}
|
|
|
|
uint32 TerrainManager::GetAreaIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
|
{
|
|
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
|
|
if (entry)
|
|
return entry->ID;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
uint32 TerrainManager::GetZoneIdByAreaFlag(uint16 areaflag, uint32 map_id)
|
|
{
|
|
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
|
|
if (entry)
|
|
return (entry->zone != 0) ? entry->zone : entry->ID;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void TerrainManager::GetZoneAndAreaIdByAreaFlag(uint32& zoneid, uint32& areaid, uint16 areaflag, uint32 map_id)
|
|
{
|
|
AreaTableEntry const* entry = GetAreaEntryByAreaFlagAndMap(areaflag, map_id);
|
|
|
|
areaid = entry ? entry->ID : 0;
|
|
zoneid = entry ? ((entry->zone != 0) ? entry->zone : entry->ID) : 0;
|
|
}
|