diff options
Diffstat (limited to 'src/server/game/Maps/Map.cpp')
-rw-r--r-- | src/server/game/Maps/Map.cpp | 1372 |
1 files changed, 34 insertions, 1338 deletions
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 3c122dfd70a..440fe34bc70 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -50,6 +50,7 @@ #include "PoolMgr.h" #include "ScriptMgr.h" #include "SpellAuras.h" +#include "TerrainMgr.h" #include "Transport.h" #include "Vehicle.h" #include "VMapFactory.h" @@ -99,214 +100,9 @@ Map::~Map() sOutdoorPvPMgr->DestroyOutdoorPvPForMap(this); sBattlefieldMgr->DestroyBattlefieldsForMap(this); - if (m_parentMap == this) - delete m_childTerrainMaps; - MMAP::MMapFactory::createOrGetMMapManager()->unloadMapInstance(GetId(), i_InstanceId); } -void Map::DiscoverGridMapFiles() -{ - std::string tileListName = Trinity::StringFormat("%smaps/%04u.tilelist", sWorld->GetDataPath().c_str(), GetId()); - // tile list is optional - if (FILE* tileList = fopen(tileListName.c_str(), "rb")) - { - u_map_magic mapMagic = { }; - uint32 versionMagic = { }; - uint32 build; - char tilesData[MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS] = { }; - if (fread(mapMagic.data(), mapMagic.size(), 1, tileList) == 1 - && mapMagic == MapMagic - && fread(&versionMagic, sizeof(versionMagic), 1, tileList) == 1 - && versionMagic == MapVersionMagic - && fread(&build, sizeof(build), 1, tileList) == 1 - && fread(&tilesData[0], MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS, 1, tileList) == 1) - { - i_gridFileExists = std::bitset<MAX_NUMBER_OF_GRIDS * MAX_NUMBER_OF_GRIDS>(tilesData, std::size(tilesData)); - fclose(tileList); - return; - } - - fclose(tileList); - } - - for (uint32 gx = 0; gx < MAX_NUMBER_OF_GRIDS; ++gx) - for (uint32 gy = 0; gy < MAX_NUMBER_OF_GRIDS; ++gy) - i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = ExistMap(GetId(), gx, gy, false); -} - -Map* Map::GetRootParentTerrainMap() -{ - Map* map = this; - while (map != map->m_parentTerrainMap) - map = map->m_parentTerrainMap; - - return map; -} - -bool Map::ExistMap(uint32 mapid, int gx, int gy, bool log /*= true*/) -{ - std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), mapid, gx, gy); - - bool ret = false; - FILE* file = fopen(fileName.c_str(), "rb"); - if (!file) - { - if (log) - { - TC_LOG_ERROR("maps", "Map file '%s' does not exist!", fileName.c_str()); - TC_LOG_ERROR("maps", "Please place MAP-files (*.map) in the appropriate directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "maps/").c_str()); - } - } - else - { - map_fileheader header; - if (fread(&header, sizeof(header), 1, file) == 1) - { - if (header.mapMagic != MapMagic || header.versionMagic != MapVersionMagic) - { - if (log) - TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s v%u), %.*s v%u is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.", - fileName.c_str(), 4, header.mapMagic.data(), header.versionMagic, 4, MapMagic.data(), MapVersionMagic); - } - else - ret = true; - } - fclose(file); - } - - return ret; -} - -bool Map::ExistVMap(uint32 mapid, int gx, int gy) -{ - if (VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager()) - { - if (vmgr->isMapLoadingEnabled()) - { - VMAP::LoadResult result = vmgr->existsMap((sWorld->GetDataPath() + "vmaps").c_str(), mapid, gx, gy); - std::string name = vmgr->getDirFileName(mapid, gx, gy); - switch (result) - { - case VMAP::LoadResult::Success: - break; - case VMAP::LoadResult::FileNotFound: - TC_LOG_ERROR("maps", "VMap file '%s' does not exist", (sWorld->GetDataPath() + "vmaps/" + name).c_str()); - TC_LOG_ERROR("maps", "Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory (%s), or correct the DataDir setting in your worldserver.conf file.", (sWorld->GetDataPath() + "vmaps/").c_str()); - return false; - case VMAP::LoadResult::VersionMismatch: - TC_LOG_ERROR("maps", "VMap file '%s' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name).c_str()); - TC_LOG_ERROR("maps", "This is because the version of the VMap file and the version of this module are different, please re-extract the maps with the tools compiled with this module."); - return false; - case VMAP::LoadResult::ReadFromFileFailed: - TC_LOG_ERROR("maps", "VMap file '%s' couldn't be loaded", (sWorld->GetDataPath() + "vmaps/" + name).c_str()); - TC_LOG_ERROR("maps", "This is because VMAP files are corrupted, please re-extract the maps with the tools compiled with this module."); - return false; - } - } - } - - return true; -} - -void Map::LoadMMap(int gx, int gy) -{ - if (!DisableMgr::IsPathfindingEnabled(GetId())) - return; - - bool mmapLoadResult = MMAP::MMapFactory::createOrGetMMapManager()->loadMap(sWorld->GetDataPath(), GetId(), gx, gy); - - if (mmapLoadResult) - TC_LOG_DEBUG("mmaps.tiles", "MMAP loaded name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); - else - TC_LOG_WARN("mmaps.tiles", "Could not load MMAP name:%s, id:%d, x:%d, y:%d (mmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); -} - -void Map::LoadVMap(int gx, int gy) -{ - if (!VMAP::VMapFactory::createOrGetVMapManager()->isMapLoadingEnabled()) - return; - // x and y are swapped !! - int vmapLoadResult = VMAP::VMapFactory::createOrGetVMapManager()->loadMap((sWorld->GetDataPath()+ "vmaps").c_str(), GetId(), gx, gy); - switch (vmapLoadResult) - { - case VMAP::VMAP_LOAD_RESULT_OK: - TC_LOG_DEBUG("maps", "VMAP loaded name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case VMAP::VMAP_LOAD_RESULT_ERROR: - TC_LOG_ERROR("maps", "Could not load VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); - break; - case VMAP::VMAP_LOAD_RESULT_IGNORED: - TC_LOG_DEBUG("maps", "Ignored VMAP name:%s, id:%d, x:%d, y:%d (vmap rep.: x:%d, y:%d)", GetMapName(), GetId(), gx, gy, gx, gy); - break; - } -} - -void Map::LoadMap(int gx, int gy) -{ - LoadMapImpl(this, gx, gy); - - for (Map* childBaseMap : *m_childTerrainMaps) - childBaseMap->LoadMap(gx, gy); -} - -void Map::LoadMapImpl(Map* map, int gx, int gy) -{ - if (map->GridMaps[gx][gy]) - return; - - // map file name - std::string fileName = Trinity::StringFormat("%smaps/%04u_%02u_%02u.map", sWorld->GetDataPath().c_str(), map->GetId(), gx, gy); - TC_LOG_DEBUG("maps", "Loading map %s", fileName.c_str()); - // loading data - std::shared_ptr<GridMap> gridMap = std::make_shared<GridMap>(); - GridMap::LoadResult gridMapLoadResult = gridMap->loadData(fileName.c_str()); - if (gridMapLoadResult == GridMap::LoadResult::Ok) - map->GridMaps[gx][gy] = std::move(gridMap); - else - { - map->i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy] = false; - Map* parentTerrain = map; - while (parentTerrain != parentTerrain->m_parentTerrainMap) - { - map->GridMaps[gx][gy] = parentTerrain->m_parentTerrainMap->GridMaps[gx][gy]; - if (map->GridMaps[gx][gy]) - break; - - parentTerrain = parentTerrain->m_parentTerrainMap; - } - } - - if (map->GridMaps[gx][gy]) - sScriptMgr->OnLoadGridMap(map, map->GridMaps[gx][gy].get(), gx, gy); - else if (gridMapLoadResult == GridMap::LoadResult::InvalidFile) - TC_LOG_ERROR("maps", "Error loading map file: %s", fileName.c_str()); -} - -void Map::UnloadMap(int gx, int gy) -{ - for (Map* childBaseMap : *m_childTerrainMaps) - childBaseMap->UnloadMap(gx, gy); - - UnloadMapImpl(this, gx, gy); -} - -void Map::UnloadMapImpl(Map* map, int gx, int gy) -{ - map->GridMaps[gx][gy] = nullptr; -} - -void Map::LoadMapAndVMap(int gx, int gy) -{ - LoadMap(gx, gy); - // Only load the data for the base map - if (this == m_parentMap) - { - LoadVMap(gx, gy); - LoadMMap(gx, gy); - } -} - void Map::LoadAllCells() { for (uint32 cellX = 0; cellX < TOTAL_NUMBER_OF_CELLS_PER_MAP; cellX++) @@ -330,35 +126,20 @@ void Map::DeleteStateMachine() delete si_GridStates[GRID_STATE_REMOVAL]; } -Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* _parent): +Map::Map(uint32 id, time_t expiry, uint32 InstanceId, Difficulty SpawnMode, Map* /*_parent*/) : _creatureToMoveLock(false), _gameObjectsToMoveLock(false), _dynamicObjectsToMoveLock(false), _areaTriggersToMoveLock(false), i_mapEntry(sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode), i_InstanceId(InstanceId), m_unloadTimer(0), m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE), m_VisibilityNotifyPeriod(DEFAULT_VISIBILITY_NOTIFY_PERIOD), m_activeNonPlayersIter(m_activeNonPlayers.end()), _transportsUpdateIter(_transports.end()), -i_gridExpiry(expiry), +i_gridExpiry(expiry), m_terrain(sTerrainMgr.LoadTerrain(id)), i_scriptLock(false), _respawnCheckTimer(0) { - if (_parent) - { - m_parentMap = _parent; - m_parentTerrainMap = m_parentMap->m_parentTerrainMap; - m_childTerrainMaps = m_parentMap->m_childTerrainMaps; - } - else - { - m_parentMap = this; - m_parentTerrainMap = this; - m_childTerrainMaps = new std::vector<Map*>(); - } - for (uint32 x = 0; x < MAX_NUMBER_OF_GRIDS; ++x) { for (uint32 y = 0; y < MAX_NUMBER_OF_GRIDS; ++y) { //z code - GridMaps[x][y] = nullptr; - GridMapReference[x][y] = 0; setNGrid(nullptr, x, y); } } @@ -554,23 +335,7 @@ void Map::EnsureGridCreated_i(GridCoord const& p) int gx = (MAX_NUMBER_OF_GRIDS - 1) - p.x_coord; int gy = (MAX_NUMBER_OF_GRIDS - 1) - p.y_coord; - if (!GridMaps[gx][gy]) - { - Map* rootParentTerrainMap = m_parentMap->GetRootParentTerrainMap(); - // because LoadMapAndVMap is always entered using rootParentTerrainMap, we can only lock that once and not have to do it for every child map - std::unique_lock<std::mutex> lock(rootParentTerrainMap->_gridLock, std::defer_lock); - if (this != rootParentTerrainMap) - lock.lock(); - - if (!m_parentMap->GridMaps[gx][gy]) - rootParentTerrainMap->LoadMapAndVMap(gx, gy); - - if (m_parentMap->GridMaps[gx][gy]) - { - GridMaps[gx][gy] = m_parentMap->GridMaps[gx][gy]; - ++rootParentTerrainMap->GridMapReference[gx][gy]; - } - } + m_terrain->LoadMapAndVMap(gx, gy); } } @@ -1844,17 +1609,7 @@ bool Map::UnloadGrid(NGridType& ngrid, bool unloadAll) int gx = (MAX_NUMBER_OF_GRIDS - 1) - x; int gy = (MAX_NUMBER_OF_GRIDS - 1) - y; - // delete grid map, but don't delete if it is from parent map (and thus only reference) - if (GridMaps[gx][gy]) - { - Map* terrainRoot = m_parentMap->GetRootParentTerrainMap(); - if (!--terrainRoot->GridMapReference[gx][gy]) - { - m_parentMap->GetRootParentTerrainMap()->UnloadMap(gx, gy); - VMAP::VMapFactory::createOrGetVMapManager()->unloadMap(terrainRoot->GetId(), gx, gy); - MMAP::MMapFactory::createOrGetMMapManager()->unloadMap(terrainRoot->GetId(), gx, gy); - } - } + m_terrain->UnloadMap(gx, gy); TC_LOG_DEBUG("maps", "Unloading grid[%u, %u] for map %u finished", x, y, GetId()); return true; @@ -1913,1124 +1668,77 @@ void Map::UnloadAll() _corpseBones.clear(); } -// ***************************** -// Grid function -// ***************************** -GridMap::GridMap() -{ - _flags = 0; - // Area data - _gridArea = 0; - _areaMap = nullptr; - // Height level data - _gridHeight = INVALID_HEIGHT; - _gridGetHeight = &GridMap::getHeightFromFlat; - _gridIntHeightMultiplier = 0; - m_V9 = nullptr; - m_V8 = nullptr; - _minHeightPlanes = nullptr; - // Liquid data - _liquidGlobalEntry = 0; - _liquidGlobalFlags = map_liquidHeaderTypeFlags::NoWater; - _liquidOffX = 0; - _liquidOffY = 0; - _liquidWidth = 0; - _liquidHeight = 0; - _liquidLevel = INVALID_HEIGHT; - _liquidEntry = nullptr; - _liquidFlags = nullptr; - _liquidMap = nullptr; - _holes = nullptr; -} - -GridMap::~GridMap() -{ - unloadData(); -} - -GridMap::LoadResult GridMap::loadData(char const* filename) -{ - // Unload old data if exist - unloadData(); - - map_fileheader header; - // Not return error if file not found - FILE* in = fopen(filename, "rb"); - if (!in) - return LoadResult::FileDoesNotExist; - - if (fread(&header, sizeof(header), 1, in) != 1) - { - fclose(in); - return LoadResult::InvalidFile; - } - - if (header.mapMagic == MapMagic && header.versionMagic == MapVersionMagic) - { - // load up area data - if (header.areaMapOffset && !loadAreaData(in, header.areaMapOffset, header.areaMapSize)) - { - TC_LOG_ERROR("maps", "Error loading map area data\n"); - fclose(in); - return LoadResult::InvalidFile; - } - // load up height data - if (header.heightMapOffset && !loadHeightData(in, header.heightMapOffset, header.heightMapSize)) - { - TC_LOG_ERROR("maps", "Error loading map height data\n"); - fclose(in); - return LoadResult::InvalidFile; - } - // load up liquid data - if (header.liquidMapOffset && !loadLiquidData(in, header.liquidMapOffset, header.liquidMapSize)) - { - TC_LOG_ERROR("maps", "Error loading map liquids data\n"); - fclose(in); - return LoadResult::InvalidFile; - } - // 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 LoadResult::InvalidFile; - } - fclose(in); - return LoadResult::Ok; - } - - TC_LOG_ERROR("maps", "Map file '%s' is from an incompatible map version (%.*s v%u), %.*s v%u is expected. Please pull your source, recompile tools and recreate maps using the updated mapextractor, then replace your old map files with new files. If you still have problems search on forum for error TCE00018.", - filename, 4, header.mapMagic.data(), header.versionMagic, 4, MapMagic.data(), MapVersionMagic); - fclose(in); - return LoadResult::InvalidFile; -} - -void GridMap::unloadData() -{ - delete[] _areaMap; - delete[] m_V9; - delete[] m_V8; - delete[] _minHeightPlanes; - delete[] _liquidEntry; - delete[] _liquidFlags; - delete[] _liquidMap; - delete[] _holes; - _areaMap = nullptr; - m_V9 = nullptr; - m_V8 = nullptr; - _minHeightPlanes = nullptr; - _liquidEntry = nullptr; - _liquidFlags = nullptr; - _liquidMap = nullptr; - _holes = nullptr; - _gridGetHeight = &GridMap::getHeightFromFlat; -} - -bool GridMap::loadAreaData(FILE* in, uint32 offset, uint32 /*size*/) -{ - map_areaHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.areaMagic != MapAreaMagic) - return false; - - _gridArea = header.gridArea; - if (!header.flags.HasFlag(map_areaHeaderFlags::NoArea)) - { - _areaMap = new uint16[16 * 16]; - if (fread(_areaMap, sizeof(uint16), 16*16, in) != 16*16) - return false; - } - return true; -} - -bool GridMap::loadHeightData(FILE* in, uint32 offset, uint32 /*size*/) -{ - map_heightHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.heightMagic != MapHeightMagic) - return false; - - _gridHeight = header.gridHeight; - if (!header.flags.HasFlag(map_heightHeaderFlags::NoHeight)) - { - if (header.flags.HasFlag(map_heightHeaderFlags::HeightAsInt16)) - { - m_uint16_V9 = new uint16 [129*129]; - m_uint16_V8 = new uint16 [128*128]; - if (fread(m_uint16_V9, sizeof(uint16), 129*129, in) != 129*129 || - fread(m_uint16_V8, sizeof(uint16), 128*128, in) != 128*128) - return false; - _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 65535; - _gridGetHeight = &GridMap::getHeightFromUint16; - } - else if (header.flags.HasFlag(map_heightHeaderFlags::HeightAsInt8)) - { - m_uint8_V9 = new uint8 [129*129]; - m_uint8_V8 = new uint8 [128*128]; - if (fread(m_uint8_V9, sizeof(uint8), 129*129, in) != 129*129 || - fread(m_uint8_V8, sizeof(uint8), 128*128, in) != 128*128) - return false; - _gridIntHeightMultiplier = (header.gridMaxHeight - header.gridHeight) / 255; - _gridGetHeight = &GridMap::getHeightFromUint8; - } - else - { - m_V9 = new float [129*129]; - m_V8 = new float [128*128]; - if (fread(m_V9, sizeof(float), 129*129, in) != 129*129 || - fread(m_V8, sizeof(float), 128*128, in) != 128*128) - return false; - _gridGetHeight = &GridMap::getHeightFromFloat; - } - } - else - _gridGetHeight = &GridMap::getHeightFromFlat; - - if (header.flags.HasFlag(map_heightHeaderFlags::HasFlightBounds)) - { - std::array<int16, 9> maxHeights; - std::array<int16, 9> 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; -} - -bool GridMap::loadLiquidData(FILE* in, uint32 offset, uint32 /*size*/) -{ - map_liquidHeader header; - fseek(in, offset, SEEK_SET); - - if (fread(&header, sizeof(header), 1, in) != 1 || header.liquidMagic != MapLiquidMagic) - return false; - - _liquidGlobalEntry = header.liquidType; - _liquidGlobalFlags = header.liquidFlags; - _liquidOffX = header.offsetX; - _liquidOffY = header.offsetY; - _liquidWidth = header.width; - _liquidHeight = header.height; - _liquidLevel = header.liquidLevel; - - if (!header.flags.HasFlag(map_liquidHeaderFlags::NoType)) - { - _liquidEntry = new uint16[16*16]; - if (fread(_liquidEntry, sizeof(uint16), 16*16, in) != 16*16) - return false; - - _liquidFlags = new map_liquidHeaderTypeFlags[16*16]; - if (fread(_liquidFlags, sizeof(map_liquidHeaderTypeFlags), 16*16, in) != 16*16) - return false; - } - if (!header.flags.HasFlag(map_liquidHeaderFlags::NoHeight)) - { - _liquidMap = new float[uint32(_liquidWidth) * uint32(_liquidHeight)]; - if (fread(_liquidMap, sizeof(float), _liquidWidth*_liquidHeight, in) != (uint32(_liquidWidth) * uint32(_liquidHeight))) - return false; - } - return true; -} - -bool GridMap::loadHolesData(FILE* in, uint32 offset, uint32 /*size*/) -{ - if (fseek(in, offset, SEEK_SET) != 0) - return false; - - _holes = new uint8[16 * 16 * 8]; - if (fread(_holes, sizeof(uint8), 16 * 16 * 8, in) != 16 * 16 * 8) - return false; - - return true; -} - -uint16 GridMap::getArea(float x, float y) const -{ - if (!_areaMap) - return _gridArea; - - 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 _areaMap[lx*16 + ly]; -} - -float GridMap::getHeightFromFlat(float /*x*/, float /*y*/) const -{ - return _gridHeight; -} - -float GridMap::getHeightFromFloat(float x, float y) const -{ - if (!m_V8 || !m_V9) - return _gridHeight; - - x = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (CENTER_GRID_ID - 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); - - 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: - // | | \ 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 _gridHeight; - - x = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (CENTER_GRID_ID - 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); - - 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) - { - 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)*_gridIntHeightMultiplier + _gridHeight; -} - -float GridMap::getHeightFromUint16(float x, float y) const -{ - if (!m_uint16_V8 || !m_uint16_V9) - return _gridHeight; - - x = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (CENTER_GRID_ID - 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); - - 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) - { - 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)*_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; - int holeCol = col % 8; - - return (_holes[cellRow * 16 * 8 + cellCol * 8 + holeRow] & (1 << holeCol)) != 0; -} - -float GridMap::getMinHeight(float x, float y) const -{ - if (!_minHeightPlanes) - return -500.0f; - - GridCoord gridCoord = Trinity::ComputeGridCoordSimple(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; -} - -float GridMap::getLiquidLevel(float x, float y) const -{ - if (!_liquidMap) - return _liquidLevel; - - x = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - y = MAP_RESOLUTION * (CENTER_GRID_ID - y/SIZE_OF_GRIDS); - - int cx_int = ((int)x & (MAP_RESOLUTION-1)) - _liquidOffY; - int cy_int = ((int)y & (MAP_RESOLUTION-1)) - _liquidOffX; - - if (cx_int < 0 || cx_int >=_liquidHeight) - return INVALID_HEIGHT; - if (cy_int < 0 || cy_int >=_liquidWidth) - return INVALID_HEIGHT; - - return _liquidMap[cx_int*_liquidWidth + cy_int]; -} - -// Get water state on map -inline ZLiquidStatus GridMap::GetLiquidStatus(float x, float y, float z, Optional<map_liquidHeaderTypeFlags> ReqLiquidType, LiquidData* data, float collisionHeight) +void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, + map_liquidHeaderTypeFlags reqLiquidType, float collisionHeight) { - // Check water type (if no water return) - if (_liquidGlobalFlags == map_liquidHeaderTypeFlags::NoWater && !_liquidFlags) - return LIQUID_MAP_NO_WATER; - - // Get cell - float cx = MAP_RESOLUTION * (CENTER_GRID_ID - x/SIZE_OF_GRIDS); - float cy = MAP_RESOLUTION * (CENTER_GRID_ID - 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 - int idx=(x_int>>3)*16 + (y_int>>3); - map_liquidHeaderTypeFlags type = _liquidFlags ? _liquidFlags[idx] : _liquidGlobalFlags; - uint32 entry = _liquidEntry ? _liquidEntry[idx] : _liquidGlobalEntry; - if (LiquidTypeEntry const* liquidEntry = sLiquidTypeStore.LookupEntry(entry)) - { - type &= map_liquidHeaderTypeFlags::DarkWater; - uint32 liqTypeIdx = liquidEntry->SoundBank; - if (entry < 21) - { - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(getArea(x, y))) - { - uint32 overrideLiquid = area->LiquidTypeID[liquidEntry->SoundBank]; - if (!overrideLiquid && area->ParentAreaID) - { - area = sAreaTableStore.LookupEntry(area->ParentAreaID); - if (area) - overrideLiquid = area->LiquidTypeID[liquidEntry->SoundBank]; - } - - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - entry = overrideLiquid; - liqTypeIdx = liq->SoundBank; - } - } - } - - type |= map_liquidHeaderTypeFlags(1 << liqTypeIdx); - } - - if (type == map_liquidHeaderTypeFlags::NoWater) - return LIQUID_MAP_NO_WATER; - - // Check req liquid type mask - if (ReqLiquidType && (*ReqLiquidType & type) == map_liquidHeaderTypeFlags::NoWater) - return LIQUID_MAP_NO_WATER; - - // Check water level: - // Check water height map - int lx_int = x_int - _liquidOffY; - int ly_int = y_int - _liquidOffX; - if (lx_int < 0 || lx_int >=_liquidHeight) - return LIQUID_MAP_NO_WATER; - if (ly_int < 0 || ly_int >=_liquidWidth) - return LIQUID_MAP_NO_WATER; - - // Get water level - float liquid_level = _liquidMap ? _liquidMap[lx_int*_liquidWidth + ly_int] : _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) - return LIQUID_MAP_NO_WATER; - - // All ok in water -> store data - if (data) - { - data->entry = entry; - data->type_flags = type; - data->level = liquid_level; - data->depth_level = ground_level; - } - - // For speed check as int values - float delta = liquid_level - z; - - if (delta > collisionHeight) // Under water - return LIQUID_MAP_UNDER_WATER; - if (delta > 0.0f) // In water - return LIQUID_MAP_IN_WATER; - if (delta > -0.1f) // Walk on water - return LIQUID_MAP_WATER_WALK; - // Above water - return LIQUID_MAP_ABOVE_WATER; + m_terrain->GetFullTerrainStatusForPosition(phaseShift, x, y, z, data, reqLiquidType, collisionHeight, &_dynamicTree); } -GridMap* Map::GetGrid(uint32 mapId, float x, float y) +ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, map_liquidHeaderTypeFlags ReqLiquidType, LiquidData* data, + float collisionHeight) { - // half opt method - int gx = (int)(CENTER_GRID_ID - x / SIZE_OF_GRIDS); //grid x - int gy = (int)(CENTER_GRID_ID - y / SIZE_OF_GRIDS); //grid y - - // ensure GridMap is loaded - EnsureGridCreated(GridCoord((MAX_NUMBER_OF_GRIDS - 1) - gx, (MAX_NUMBER_OF_GRIDS - 1) - gy)); - - GridMap* grid = GridMaps[gx][gy].get(); - auto childMapItr = std::find_if(m_childTerrainMaps->begin(), m_childTerrainMaps->end(), [mapId](Map* childTerrainMap) { return childTerrainMap->GetId() == mapId; }); - if (childMapItr != m_childTerrainMaps->end() && (*childMapItr)->GridMaps[gx][gy]) - grid = (*childMapItr)->GridMaps[gx][gy].get(); - - return grid; + return m_terrain->GetLiquidStatus(phaseShift, x, y, z, ReqLiquidType, data, collisionHeight); } -bool Map::HasChildMapGridFile(uint32 mapId, int32 gx, int32 gy) const +bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) { - auto childMapItr = std::find_if(m_childTerrainMaps->begin(), m_childTerrainMaps->end(), [mapId](Map* childTerrainMap) { return childTerrainMap->GetId() == mapId; }); - return childMapItr != m_childTerrainMaps->end() && (*childMapItr)->i_gridFileExists[gx * MAX_NUMBER_OF_GRIDS + gy]; + return m_terrain->GetAreaInfo(phaseShift, x, y, z, mogpflags, adtId, rootId, groupId, &_dynamicTree); } -float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground /*= nullptr*/, bool /*swim = false*/, float collisionHeight /*= DEFAULT_COLLISION_HEIGHT*/) +uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) { - if (GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - { - // we need ground level (including grid height version) for proper return water level in point - float ground_z = GetHeight(phaseShift, x, y, z + Z_OFFSET_FIND_HEIGHT, true, 50.0f); - if (ground) - *ground = ground_z; - - LiquidData liquid_status; - - ZLiquidStatus res = GetLiquidStatus(phaseShift, x, y, ground_z, map_liquidHeaderTypeFlags::AllLiquids, &liquid_status, collisionHeight); - switch (res) - { - case LIQUID_MAP_ABOVE_WATER: - return std::max<float>(liquid_status.level, ground_z); - case LIQUID_MAP_NO_WATER: - return ground_z; - default: - return liquid_status.level; - } - } - - return VMAP_INVALID_HEIGHT_VALUE; + return m_terrain->GetAreaId(phaseShift, x, y, z, &_dynamicTree); } -float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) +uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) { - // find raw .map surface under Z coordinates - float mapHeight = VMAP_INVALID_HEIGHT_VALUE; - uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - float gridHeight = GetGridHeight(phaseShift, x, y); - if (G3D::fuzzyGe(z, gridHeight - GROUND_HEIGHT_TOLERANCE)) - mapHeight = gridHeight; - - float vmapHeight = VMAP_INVALID_HEIGHT_VALUE; - if (checkVMap) - { - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - if (vmgr->isHeightCalcEnabled()) - vmapHeight = vmgr->getHeight(terrainMapId, x, y, z, maxSearchDist); - } - - // 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 - - // vmap height above map height - // or if the distance of the vmap height is less the land height distance - if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z)) - return vmapHeight; - - return mapHeight; // better use .map surface height - } - - return vmapHeight; // we have only vmapHeight (if have) - } - - return mapHeight; // explicitly use map data + return m_terrain->GetZoneId(phaseShift, x, y, z, &_dynamicTree); } -float Map::GetGridHeight(PhaseShift const& phaseShift, float x, float y) +void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z) { - if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - return gmap->getHeight(x, y); - - return VMAP_INVALID_HEIGHT_VALUE; + return m_terrain->GetZoneAndAreaId(phaseShift, zoneid, areaid, x, y, z, &_dynamicTree); } float Map::GetMinHeight(PhaseShift const& phaseShift, float x, float y) { - if (GridMap const* grid = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - return grid->getMinHeight(x, y); - - return -500.0f; + return m_terrain->GetMinHeight(phaseShift, x, y); } -static inline bool IsInWMOInterior(uint32 mogpFlags) -{ - return (mogpFlags & 0x2000) != 0; -} - -bool Map::GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) -{ - float vmap_z = z; - float dynamic_z = z; - float check_z = z; - uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - uint32 vflags; - int32 vadtId; - int32 vrootId; - int32 vgroupId; - uint32 dflags; - int32 dadtId; - int32 drootId; - int32 dgroupId; - - bool hasVmapAreaInfo = vmgr->getAreaInfo(terrainMapId, x, y, vmap_z, vflags, vadtId, vrootId, vgroupId); - bool hasDynamicAreaInfo = _dynamicTree.getAreaInfo(x, y, dynamic_z, phaseShift, dflags, dadtId, drootId, dgroupId); - auto useVmap = [&]() { check_z = vmap_z; mogpflags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; }; - auto useDyn = [&]() { check_z = dynamic_z; mogpflags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; }; - - if (hasVmapAreaInfo) - { - if (hasDynamicAreaInfo && dynamic_z > vmap_z) - useDyn(); - else - useVmap(); - } - else if (hasDynamicAreaInfo) - { - useDyn(); - } - - if (hasVmapAreaInfo || hasDynamicAreaInfo) - { - // check if there's terrain between player height and object height - if (GridMap* gmap = 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 > check_z) - return false; - } - return true; - } - return false; -} - -uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) +float Map::GetGridHeight(PhaseShift const& phaseShift, float x, float y) { - uint32 mogpFlags; - int32 adtId, rootId, groupId; - float vmapZ = z; - bool hasVmapArea = GetAreaInfo(phaseShift, x, y, vmapZ, mogpFlags, adtId, rootId, groupId); - - uint32 gridAreaId = 0; - float gridMapHeight = INVALID_HEIGHT; - if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - { - gridAreaId = gmap->getArea(x, y); - gridMapHeight = gmap->getHeight(x, y); - } - - uint32 areaId = 0; - - // 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)) - { - // wmo found - if (WMOAreaTableEntry const* wmoEntry = sDB2Manager.GetWMOAreaTable(rootId, adtId, groupId)) - areaId = wmoEntry->AreaTableID; - - if (!areaId) - areaId = gridAreaId; - } - else - areaId = gridAreaId; - - if (!areaId) - areaId = i_mapEntry->AreaTableID; - - return areaId; + return m_terrain->GetGridHeight(phaseShift, x, y); } -uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) +float Map::GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap, float maxSearchDist) { - uint32 areaId = GetAreaId(phaseShift, x, y, z); - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaId)) - if (area->ParentAreaID) - return area->ParentAreaID; - - return areaId; + return m_terrain->GetStaticHeight(phaseShift, x, y, z, checkVMap, maxSearchDist); } -void Map::GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z) +float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) { - areaid = zoneid = GetAreaId(phaseShift, x, y, z); - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(areaid)) - if (area->ParentAreaID) - zoneid = area->ParentAreaID; + return m_terrain->GetWaterLevel(phaseShift, x, y); } -ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, map_liquidHeaderTypeFlags ReqLiquidType, LiquidData* data, float collisionHeight) +bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float z, LiquidData* data) { - ZLiquidStatus result = LIQUID_MAP_NO_WATER; - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - float liquid_level = INVALID_HEIGHT; - float ground_level = INVALID_HEIGHT; - uint32 liquid_type = 0; - uint32 mogpFlags = 0; - bool useGridLiquid = true; - uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - if (vmgr->GetLiquidLevel(terrainMapId, x, y, z, AsUnderlyingType(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 && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE)) - { - // All ok in water -> store data - if (data) - { - // hardcoded in client like this - if (GetId() == 530 && liquid_type == 2) - liquid_type = 15; - - uint32 liquidFlagType = 0; - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type)) - liquidFlagType = liq->SoundBank; - - if (liquid_type && liquid_type < 21) - { - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseShift, x, y, z))) - { - uint32 overrideLiquid = area->LiquidTypeID[liquidFlagType]; - if (!overrideLiquid && area->ParentAreaID) - { - area = sAreaTableStore.LookupEntry(area->ParentAreaID); - if (area) - overrideLiquid = area->LiquidTypeID[liquidFlagType]; - } - - if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - liquid_type = overrideLiquid; - liquidFlagType = liq->SoundBank; - } - } - } - - data->level = liquid_level; - data->depth_level = ground_level; - - data->entry = liquid_type; - data->type_flags = map_liquidHeaderTypeFlags(1 << liquidFlagType); - } - - float delta = liquid_level - z; - - // Get position delta - if (delta > collisionHeight) // Under water - return LIQUID_MAP_UNDER_WATER; - if (delta > 0.0f) // In water - return LIQUID_MAP_IN_WATER; - if (delta > -0.1f) // Walk on water - return LIQUID_MAP_WATER_WALK; - result = LIQUID_MAP_ABOVE_WATER; - } - } - - if (useGridLiquid) - { - if (GridMap* gmap = GetGrid(terrainMapId, x, y)) - { - LiquidData map_data; - ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight); - // 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) - { - // hardcoded in client like this - if (GetId() == 530 && map_data.entry == 2) - map_data.entry = 15; - - *data = map_data; - } - return map_result; - } - } - } - return result; + return m_terrain->IsInWater(phaseShift, x, y, z, data); } -void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, map_liquidHeaderTypeFlags reqLiquidType, float collisionHeight) +bool Map::IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z) { - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - VMAP::AreaAndLiquidData vmapData; - VMAP::AreaAndLiquidData dynData; - VMAP::AreaAndLiquidData* wmoData = nullptr; - uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - GridMap* gmap = GetGrid(terrainMapId, x, y); - vmgr->getAreaAndLiquidData(terrainMapId, x, y, z, AsUnderlyingType(reqLiquidType), vmapData); - _dynamicTree.getAreaAndLiquidData(x, y, z, phaseShift, AsUnderlyingType(reqLiquidType), dynData); - - uint32 gridAreaId = 0; - float gridMapHeight = INVALID_HEIGHT; - if (gmap) - { - gridAreaId = gmap->getArea(x, y); - gridMapHeight = gmap->getHeight(x, y); - } - - 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; - wmoData = &vmapData; - } - // NOTE: Objects will not detect a case when a wmo providing area/liquid despawns from under them - // but this is fine as these kind of objects are not meant to be spawned and despawned a lot - // example: Lich King platform - if (dynData.floorZ > VMAP_INVALID_HEIGHT && - G3D::fuzzyGe(z, dynData.floorZ - GROUND_HEIGHT_TOLERANCE) && - (G3D::fuzzyLt(z, gridMapHeight - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > gridMapHeight) && - (G3D::fuzzyLt(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE) || dynData.floorZ > vmapData.floorZ)) - { - data.floorZ = dynData.floorZ; - wmoData = &dynData; - } - - if (wmoData) - { - if (wmoData->areaInfo) - { - data.areaInfo.emplace(wmoData->areaInfo->adtId, wmoData->areaInfo->rootId, wmoData->areaInfo->groupId, wmoData->areaInfo->mogpFlags); - // wmo found - WMOAreaTableEntry const* wmoEntry = sDB2Manager.GetWMOAreaTable(wmoData->areaInfo->rootId, wmoData->areaInfo->adtId, wmoData->areaInfo->groupId); - data.outdoors = (wmoData->areaInfo->mogpFlags & 0x8) != 0; - if (wmoEntry) - { - data.areaId = wmoEntry->AreaTableID; - if (wmoEntry->Flags & 4) - data.outdoors = true; - else if (wmoEntry->Flags & 2) - data.outdoors = false; - } - - if (!data.areaId) - data.areaId = gridAreaId; - - useGridLiquid = !IsInWMOInterior(wmoData->areaInfo->mogpFlags); - } - } - else - { - data.outdoors = true; - data.areaId = gridAreaId; - if (AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId)) - data.outdoors = (areaEntry->Flags[0] & (AREA_FLAG_INSIDE | AREA_FLAG_OUTSIDE)) != AREA_FLAG_INSIDE; - } - - if (!data.areaId) - data.areaId = i_mapEntry->AreaTableID; - - AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(data.areaId); - - // liquid processing - data.liquidStatus = LIQUID_MAP_NO_WATER; - if (wmoData && wmoData->liquidInfo && wmoData->liquidInfo->level > wmoData->floorZ) - { - uint32 liquidType = wmoData->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->SoundBank; - - if (liquidType && liquidType < 21 && areaEntry) - { - uint32 overrideLiquid = areaEntry->LiquidTypeID[liquidFlagType]; - if (!overrideLiquid && areaEntry->ParentAreaID) - { - AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->ParentAreaID); - if (zoneEntry) - overrideLiquid = zoneEntry->LiquidTypeID[liquidFlagType]; - } - - if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - liquidType = overrideLiquid; - liquidFlagType = overrideData->SoundBank; - } - } - - data.liquidInfo.emplace(); - data.liquidInfo->level = wmoData->liquidInfo->level; - data.liquidInfo->depth_level = wmoData->floorZ; - data.liquidInfo->entry = liquidType; - data.liquidInfo->type_flags = map_liquidHeaderTypeFlags(1 << liquidFlagType); - - float delta = wmoData->liquidInfo->level - z; - if (delta > collisionHeight) - 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, collisionHeight); - if (gridMapStatus != LIQUID_MAP_NO_WATER && (!wmoData || gridMapLiquid.level > wmoData->floorZ)) - { - if (GetId() == 530 && gridMapLiquid.entry == 2) - gridMapLiquid.entry = 15; - data.liquidInfo = gridMapLiquid; - data.liquidStatus = gridMapStatus; - } - } + return m_terrain->IsUnderWater(phaseShift, x, y, z); } -float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) +float Map::GetWaterOrGroundLevel(PhaseShift const& phaseShift, float x, float y, float z, float* ground, bool swim, float collisionHeight) { - if (GridMap* gmap = GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) - return gmap->getLiquidLevel(x, y); - else - return 0; + return m_terrain->GetWaterOrGroundLevel(phaseShift, x, y, z, ground, swim, collisionHeight, &_dynamicTree); } bool Map::isInLineOfSight(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { if ((checks & LINEOFSIGHT_CHECK_VMAP) - && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(phaseShift, this, x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags)) + && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(PhasingHandler::GetTerrainMapId(phaseShift, m_terrain.get(), x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags)) return false; if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT) && !_dynamicTree.isInLineOfSight({ x1, y1, z1 }, { x2, y2, z2 }, phaseShift)) @@ -3052,21 +1760,9 @@ bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, floa return result; } -bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float pZ, LiquidData* data) -{ - LiquidData liquid_status; - LiquidData* liquid_ptr = data ? data : &liquid_status; - return (GetLiquidStatus(phaseShift, x, y, pZ, map_liquidHeaderTypeFlags::AllLiquids, liquid_ptr) & (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER)) != 0; -} - -bool Map::IsUnderWater(PhaseShift const& phaseShift, float x, float y, float z) -{ - return (GetLiquidStatus(phaseShift, x, y, z, map_liquidHeaderTypeFlags::Water | map_liquidHeaderTypeFlags::Ocean) & LIQUID_MAP_UNDER_WATER) != 0; -} - char const* Map::GetMapName() const { - return i_mapEntry ? i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()] : "UNNAMEDMAP\x0"; + return i_mapEntry->MapName[sWorld->GetDefaultDbcLocale()]; } void Map::SendInitSelf(Player* player) |