33#include <G3D/g3dmath.h>
60 if (fread(mapMagic.data(), mapMagic.size(), 1, tileList.get()) == 1
62 && fread(&versionMagic,
sizeof(versionMagic), 1, tileList.get()) == 1
64 && fread(&build,
sizeof(build), 1, tileList.get()) == 1
87 TC_LOG_ERROR(
"maps",
"Map file '{}' does not exist!", fileName);
88 TC_LOG_ERROR(
"maps",
"Please place MAP-files (*.map) in the appropriate directory ({}), or correct the DataDir setting in your worldserver.conf file.", (
sWorld->GetDataPath() +
"maps/"));
94 if (fread(&header,
sizeof(header), 1, file.get()) == 1)
99 TC_LOG_ERROR(
"maps",
"Map file '{}' is from an incompatible map version (%.*s v{}), %.*s v{} 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.",
114 if (vmgr->isMapLoadingEnabled())
117 std::string name = vmgr->getDirFileName(mapid, gx, gy);
123 TC_LOG_ERROR(
"maps",
"VMap file '{}' does not exist", (
sWorld->GetDataPath() +
"vmaps/" + name));
124 TC_LOG_ERROR(
"maps",
"Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({}), or correct the DataDir setting in your worldserver.conf file.", (
sWorld->GetDataPath() +
"vmaps/"));
127 TC_LOG_ERROR(
"maps",
"VMap file '{}' couldn't be loaded", (
sWorld->GetDataPath() +
"vmaps/" + name));
128 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.");
131 TC_LOG_ERROR(
"maps",
"VMap file '{}' couldn't be loaded", (
sWorld->GetDataPath() +
"vmaps/" + name));
132 TC_LOG_ERROR(
"maps",
"This is because VMAP files are corrupted, please re-extract the maps with the tools compiled with this module.");
135 TC_LOG_ERROR(
"maps",
"VMap file '{}' couldn't be loaded", (
sWorld->GetDataPath() +
"vmaps/" + name));
136 TC_LOG_ERROR(
"maps",
"This is because VMAP is disabled in config file.");
147 auto childMapItr = std::find_if(
_childTerrain.begin(),
_childTerrain.end(), [mapId](std::shared_ptr<TerrainInfo>
const& childTerrain) { return childTerrain->GetId() == mapId; });
153 childTerrain->_parentTerrain =
this;
170 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
171 childTerrain->LoadMMapInstanceImpl(mapId, instanceId);
180 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
181 childTerrain->LoadMapAndVMapImpl(gx, gy);
203 std::unique_ptr<GridMap> gridMap = std::make_unique<GridMap>();
206 _gridMap[gx][gy] = std::move(gridMap);
211 TC_LOG_ERROR(
"maps",
"Error loading map file: {}", fileName);
220 switch (vmapLoadResult)
223 TC_LOG_DEBUG(
"maps",
"VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
227 TC_LOG_ERROR(
"maps",
"Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
230 TC_LOG_DEBUG(
"maps",
"Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
245 TC_LOG_DEBUG(
"mmaps.tiles",
"MMAP loaded name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
247 TC_LOG_WARN(
"mmaps.tiles",
"Could not load MMAP name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
260 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
261 childTerrain->UnloadMMapInstanceImpl(mapId, instanceId);
270 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
271 childTerrain->UnloadMapImpl(gx, gy);
295 if (mapId !=
GetId())
297 auto childMapItr = std::find_if(
_childTerrain.begin(),
_childTerrain.end(), [mapId](std::shared_ptr<TerrainInfo>
const& childTerrain) { return childTerrain->GetId() == mapId; });
298 if (childMapItr !=
_childTerrain.end() && (*childMapItr)->_gridMap[gx][gy])
299 grid = (*childMapItr)->GetGrid(mapId, x, y,
false);
322 return (mogpFlags & 0x2000) != 0;
342 gridAreaId = gmap->
getArea(x, y);
346 bool useGridLiquid =
true;
351 data.
floorZ = gridMapHeight;
385 if (wmoEntry->
Flags & 4)
387 else if (wmoEntry->
Flags & 2)
415 if (
GetId() == 530 && liquidType == 2)
418 uint32 liquidFlagType = 0;
420 liquidFlagType = liquidData->SoundBank;
422 if (liquidType && liquidType < 21 && areaEntry)
429 overrideLiquid = zoneEntry->
LiquidTypeID[liquidFlagType];
434 liquidType = overrideLiquid;
435 liquidFlagType = overrideData->SoundBank;
447 if (delta > collisionHeight)
449 else if (delta > 0.0f)
451 else if (delta > -0.1f)
461 if (gmap && useGridLiquid)
467 if (
GetId() == 530 && gridMapLiquid.
entry == 2)
468 gridMapLiquid.
entry = 15;
480 bool useGridLiquid =
true;
496 uint32 liquidFlagType = 0;
498 liquidFlagType = liq->SoundBank;
504 uint32 overrideLiquid = area->LiquidTypeID[liquidFlagType];
505 if (!overrideLiquid && area->ParentAreaID)
509 overrideLiquid = area->LiquidTypeID[liquidFlagType];
515 liquidFlagType = liq->SoundBank;
531 if (delta > collisionHeight)
533 else if (delta > 0.0f)
535 else if (delta > -0.1f)
556 ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight);
584 bool hasDynamicAreaInfo = dynamicMapTree ? dynamicMapTree->
getAreaAndLiquidData(x, y, z, phaseShift, {}, ddata) && ddata.
areaInfo.has_value() :
false;
595 else if (hasDynamicAreaInfo)
600 if (hasVmapAreaInfo || hasDynamicAreaInfo)
605 float mapHeight = gmap->getHeight(x, y);
607 if (z + 2.0f > mapHeight && mapHeight > check_z)
618 int32 adtId, rootId, groupId;
620 bool hasVmapArea =
GetAreaInfo(phaseShift, mapId, x, y, vmapZ, mogpFlags, adtId, rootId, groupId, dynamicMapTree);
626 gridAreaId = gmap->getArea(x, y);
627 gridMapHeight = gmap->getHeight(x, y);
637 areaId = wmoEntry->AreaTableID;
656 return area->ParentAreaID;
663 areaid = zoneid =
GetAreaId(phaseShift, mapId, x, y, z, dynamicMapTree);
666 zoneid = area->ParentAreaID;
672 return grid->getMinHeight(x, y);
680 return gmap->getHeight(x, y);
692 mapHeight = gridHeight;
699 vmapHeight = vmgr->
getHeight(terrainMapId, x, y, z, maxSearchDist);
712 if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
727 return gmap->getLiquidLevel(x, y);
735 LiquidData* liquid_ptr = data ? data : &liquid_status;
762 return std::max<float>(liquid_status.
level, ground_z);
766 return liquid_status.
level;
797 entry =
sMapStore.LookupEntry(parentMapId);
806 if (std::shared_ptr<TerrainInfo> terrain = itr->second.lock())
823 if (std::shared_ptr<TerrainInfo> terrain = terrainRef.lock())
824 terrain->CleanUpGrids(diff);
829 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
830 return t->GetAreaId(phaseShift, mapid, x, y, z);
836 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
837 return t->GetZoneId(phaseShift, mapid, x, y, z);
843 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
844 t->GetZoneAndAreaId(phaseShift, mapid, zoneid, areaid, x, y, z);
849 std::shared_ptr<TerrainInfo> rootTerrain(
new TerrainInfo(mapId));
851 rootTerrain->DiscoverGridMapFiles();
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
DB2Storage< LiquidTypeEntry > sLiquidTypeStore("LiquidType.db2", &LiquidTypeLoadInfo::Instance)
DB2Storage< AreaTableEntry > sAreaTableStore("AreaTable.db2", &AreaTableLoadInfo::Instance)
#define MAX_NUMBER_OF_GRIDS
#define VMAP_INVALID_HEIGHT_VALUE
#define VMAP_INVALID_HEIGHT
#define TC_LOG_WARN(filterType__,...)
#define TC_LOG_DEBUG(filterType__,...)
#define TC_LOG_ERROR(filterType__,...)
uint32 const MapVersionMagic
u_map_magic const MapMagic
std::array< char, 4 > u_map_magic
Represents a map magic value of 4 bytes (used in versions)
map_liquidHeaderTypeFlags
std::optional< T > Optional
Optional helper class to wrap optional values within.
Milliseconds randtime(Milliseconds min, Milliseconds max)
float const GROUND_HEIGHT_TOLERANCE
constexpr float Z_OFFSET_FIND_HEIGHT
static bool IsInWMOInterior(uint32 mogpFlags)
constexpr std::underlying_type< E >::type AsUnderlyingType(E enumValue)
float getHeight(float x, float y, float z, float maxSearchDist, PhaseShift const &phaseShift) const
bool getAreaAndLiquidData(float x, float y, float z, PhaseShift const &phaseShift, Optional< uint8 > reqLiquidType, VMAP::AreaAndLiquidData &data) const
uint16 getArea(float x, float y) const
float getHeight(float x, float y) const
ZLiquidStatus GetLiquidStatus(float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType, LiquidData *data=nullptr, float collisionHeight=2.03128f) const
static MMapManager * createOrGetMMapManager()
bool unloadMap(uint32 mapId, int32 x, int32 y)
bool loadMapInstance(std::string const &basePath, uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
bool loadMap(std::string const &basePath, uint32 mapId, int32 x, int32 y)
bool unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
static uint32 GetTerrainMapId(PhaseShift const &phaseShift, uint32 mapId, TerrainInfo const *terrain, float x, float y)
void LoadMMap(int32 gx, int32 gy)
void UnloadMMapInstanceImpl(uint32 mapId, uint32 instanceId)
float GetMinHeight(PhaseShift const &phaseShift, uint32 mapId, float x, float y)
bool GetAreaInfo(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, uint32 &mogpflags, int32 &adtId, int32 &rootId, int32 &groupId, DynamicMapTree const *dynamicMapTree=nullptr)
float GetWaterLevel(PhaseShift const &phaseShift, uint32 mapId, float x, float y)
std::atomic< uint16 > _referenceCountFromMap[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
static constexpr Milliseconds CleanupInterval
void LoadMMapInstance(uint32 mapId, uint32 instanceId)
float GetStaticHeight(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, bool checkVMap=true, float maxSearchDist=DEFAULT_HEIGHT_SEARCH)
ZLiquidStatus GetLiquidStatus(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, Optional< map_liquidHeaderTypeFlags > ReqLiquidType={}, LiquidData *data=nullptr, float collisionHeight=2.03128f)
bool HasChildTerrainGridFile(uint32 mapId, int32 gx, int32 gy) const
void LoadMap(int32 gx, int32 gy)
bool IsInWater(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, LiquidData *data=nullptr)
void LoadVMap(int32 gx, int32 gy)
TimeTracker _cleanupTimer
void DiscoverGridMapFiles()
void UnloadMapImpl(int32 gx, int32 gy)
void LoadMMapInstanceImpl(uint32 mapId, uint32 instanceId)
uint32 GetAreaId(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, DynamicMapTree const *dynamicMapTree=nullptr)
void UnloadMMapInstance(uint32 mapId, uint32 instanceId)
TerrainInfo(uint32 mapId)
std::bitset< MAX_NUMBER_OF_GRIDS *MAX_NUMBER_OF_GRIDS > _loadedGrids
GridMap * GetGrid(uint32 mapId, float x, float y, bool loadIfMissing=true)
std::vector< std::shared_ptr< TerrainInfo > > _childTerrain
void GetZoneAndAreaId(PhaseShift const &phaseShift, uint32 mapId, uint32 &zoneid, uint32 &areaid, float x, float y, float z, DynamicMapTree const *dynamicMapTree=nullptr)
static bool ExistVMap(uint32 mapid, int32 gx, int32 gy)
void GetFullTerrainStatusForPosition(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, PositionFullTerrainStatus &data, Optional< map_liquidHeaderTypeFlags > reqLiquidType={}, float collisionHeight=2.03128f, DynamicMapTree const *dynamicMapTree=nullptr)
void LoadMapAndVMap(int32 gx, int32 gy)
char const * GetMapName() const
std::bitset< MAX_NUMBER_OF_GRIDS *MAX_NUMBER_OF_GRIDS > _gridFileExists
void CleanUpGrids(uint32 diff)
void UnloadMap(int32 gx, int32 gy)
static bool ExistMap(uint32 mapid, int32 gx, int32 gy, bool log=true)
void LoadMapAndVMapImpl(int32 gx, int32 gy)
float GetWaterOrGroundLevel(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, float *ground=nullptr, bool swim=false, float collisionHeight=2.03128f, DynamicMapTree const *dynamicMapTree=nullptr)
static constexpr int32 GetBitsetIndex(int32 gx, int32 gy)
std::unique_ptr< GridMap > _gridMap[MAX_NUMBER_OF_GRIDS][MAX_NUMBER_OF_GRIDS]
uint32 GetZoneId(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z, DynamicMapTree const *dynamicMapTree=nullptr)
bool IsUnderWater(PhaseShift const &phaseShift, uint32 mapId, float x, float y, float z)
void AddChildTerrain(std::shared_ptr< TerrainInfo > childTerrain)
float GetGridHeight(PhaseShift const &phaseShift, uint32 mapId, float x, float y)
std::shared_ptr< TerrainInfo > LoadTerrainImpl(uint32 mapId)
void InitializeParentMapData(std::unordered_map< uint32, std::vector< uint32 > > const &mapData)
uint32 GetAreaId(PhaseShift const &phaseShift, uint32 mapid, float x, float y, float z)
void GetZoneAndAreaId(PhaseShift const &phaseShift, uint32 &zoneid, uint32 &areaid, uint32 mapid, float x, float y, float z)
static TerrainMgr & Instance()
uint32 GetZoneId(PhaseShift const &phaseShift, uint32 mapid, float x, float y, float z)
static bool ExistMapAndVMap(uint32 mapid, float x, float y)
std::unordered_map< uint32, std::weak_ptr< TerrainInfo > > _terrainMaps
std::shared_ptr< TerrainInfo > LoadTerrain(uint32 mapId)
std::unordered_map< uint32, std::vector< uint32 > > _parentMapData
virtual float getHeight(unsigned int pMapId, float x, float y, float z, float maxSearchDist)=0
bool isHeightCalcEnabled() const
virtual bool getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, Optional< uint8 > reqLiquidType, AreaAndLiquidData &data) const =0
static VMapManager2 * createOrGetVMapManager()
LoadResult loadMap(char const *pBasePath, unsigned int mapId, int x, int y) override
void unloadMap(unsigned int mapId, int x, int y) override
bool IsPathfindingEnabled(uint32 mapId)
auto make_unique_ptr_with_deleter(T ptr, Del &&deleter)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args)
Default TC string format function.
GridCoord ComputeGridCoord(float x, float y)
constexpr std::size_t size()
std::array< uint16, 4 > LiquidTypeID
EnumFlag< map_liquidHeaderTypeFlags > type_flags
int16 CosmeticParentMapID
Optional< LiquidData > liquidInfo
Optional< WmoLocation > wmoLocation
ZLiquidStatus liquidStatus
Optional< AreaInfo > areaInfo
Optional< LiquidInfo > liquidInfo