32#include <G3D/g3dmath.h>
53 if (
auto tileList = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(tileListName.c_str(),
"rb")))
59 if (fread(mapMagic.data(), mapMagic.size(), 1, tileList.get()) == 1
61 && fread(&versionMagic,
sizeof(versionMagic), 1, tileList.get()) == 1
63 && fread(&build,
sizeof(build), 1, tileList.get()) == 1
66 _gridFileExists = std::bitset<MAX_NUMBER_OF_GRIDS* MAX_NUMBER_OF_GRIDS>(tilesData, std::size(tilesData));
81 auto file = Trinity::make_unique_ptr_with_deleter<&::fclose>(fopen(fileName.c_str(),
"rb"));
86 TC_LOG_ERROR(
"maps",
"Map file '{}' does not exist!", fileName);
87 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/"));
93 if (fread(&header,
sizeof(header), 1, file.get()) == 1)
98 TC_LOG_ERROR(
"maps",
"Map file '{}' is from an incompatible map version ({} v{}), {} 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.",
99 fileName, std::string_view(header.mapMagic.data(), 4), header.versionMagic, std::string_view(
MapMagic.data(), 4),
MapVersionMagic);
113 if (vmgr->isMapLoadingEnabled())
122 TC_LOG_ERROR(
"maps",
"VMap file '{}vmaps/{}' does not exist",
sWorld->GetDataPath(), name);
123 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/"));
126 TC_LOG_ERROR(
"maps",
"VMap file '{}vmaps/{}' couldn't be loaded",
sWorld->GetDataPath(), name);
127 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.");
130 TC_LOG_ERROR(
"maps",
"VMap file '{}vmaps/{}' couldn't be loaded",
sWorld->GetDataPath(), name);
131 TC_LOG_ERROR(
"maps",
"This is because VMAP files are corrupted, please re-extract the maps with the tools compiled with this module.");
134 TC_LOG_ERROR(
"maps",
"VMap file '{}vmaps/{}' couldn't be loaded",
sWorld->GetDataPath(), name);
135 TC_LOG_ERROR(
"maps",
"This is because VMAP is disabled in config file.");
146 auto childMapItr = std::ranges::find(
_childTerrain, mapId, [](std::shared_ptr<TerrainInfo>
const& childTerrain) {
return childTerrain->GetId(); });
152 childTerrain->_parentTerrain =
this;
169 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
170 childTerrain->LoadMMapInstanceImpl(mapId, instanceId);
177 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
178 childTerrain->LoadMMapImpl(instanceId, gx, gy);
186 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
187 childTerrain->LoadMapAndVMapImpl(gx, gy);
209 std::unique_ptr<GridMap> gridMap = std::make_unique<GridMap>();
212 _gridMap[gx][gy] = std::move(gridMap);
217 TC_LOG_ERROR(
"maps",
"Error loading map file: {}", fileName);
228 TC_LOG_DEBUG(
"maps",
"VMAP loaded name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
232 TC_LOG_ERROR(
"maps",
"Could not load VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
235 TC_LOG_DEBUG(
"maps",
"Ignored VMAP name:{}, id:{}, x:{}, y:{} (vmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
250 TC_LOG_DEBUG(
"mmaps.tiles",
"MMAP loaded name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{})",
GetMapName(),
GetId(), gx, gy, gx, gy);
259 TC_LOG_WARN(
"mmaps.tiles",
"Could not load MMAP name:{}, id:{}, x:{}, y:{} (mmap rep.: x:{}, y:{}) result: {}",
GetMapName(),
GetId(), gx, gy, gx, gy,
AsUnderlyingType(mmapLoadResult));
274 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
275 childTerrain->UnloadMMapInstanceImpl(mapId, instanceId);
284 for (std::shared_ptr<TerrainInfo>
const& childTerrain :
_childTerrain)
285 childTerrain->UnloadMapImpl(gx, gy);
309 if (mapId !=
GetId())
311 auto childMapItr = std::ranges::find(
_childTerrain, mapId, [](std::shared_ptr<TerrainInfo>
const& childTerrain) {
return childTerrain->GetId(); });
312 if (childMapItr !=
_childTerrain.end() && (*childMapItr)->_gridMap[gx][gy])
313 grid = (*childMapItr)->GetGrid(mapId, x, y,
false);
337 return (mogpFlags & 0x2000) != 0;
357 gridAreaId = gmap->
getArea(x, y);
361 bool useGridLiquid =
true;
366 data.
floorZ = gridMapHeight;
396 data.
areaId = wmoEntry->AreaTableID;
427 if (
GetId() == 530 && liquidType == 2)
430 if (liquidType && liquidType < 21 && areaEntry)
436 overrideLiquid = zoneEntry->LiquidTypeID[(liquidType - 1) & 3];
440 liquidType = overrideLiquid;
451 if (delta > collisionHeight)
453 else if (delta > 0.0f)
455 else if (delta > -0.1f)
465 if (gmap && useGridLiquid)
471 if (
GetId() == 530 && gridMapLiquid.
entry == 2)
472 gridMapLiquid.
entry = 15;
484 bool useGridLiquid =
true;
504 uint32 overrideLiquid = area->LiquidTypeID[(vmapData.
liquidInfo->type - 1) & 3];
505 if (!overrideLiquid && area->ParentAreaID)
509 overrideLiquid = area->LiquidTypeID[(vmapData.
liquidInfo->type - 1) & 3];
528 if (delta > collisionHeight)
530 else if (delta > 0.0f)
532 else if (delta > -0.1f)
553 ZLiquidStatus map_result = gmap->GetLiquidStatus(x, y, z, ReqLiquidType, &map_data, collisionHeight);
581 bool hasDynamicAreaInfo = dynamicMapTree ? dynamicMapTree->
getAreaAndLiquidData(x, y, z, phaseShift, {}, ddata) && ddata.
areaInfo.has_value() :
false;
592 else if (hasDynamicAreaInfo)
597 if (hasVmapAreaInfo || hasDynamicAreaInfo)
602 float mapHeight = gmap->getHeight(x, y);
604 if (z + 2.0f > mapHeight && mapHeight > check_z)
615 int32 adtId, rootId, groupId;
617 bool hasVmapArea =
GetAreaInfo(phaseShift, mapId, x, y, vmapZ, mogpFlags, adtId, rootId, groupId, dynamicMapTree);
623 gridAreaId = gmap->getArea(x, y);
624 gridMapHeight = gmap->getHeight(x, y);
634 areaId = wmoEntry->AreaTableID;
653 return area->ParentAreaID;
660 areaid = zoneid =
GetAreaId(phaseShift, mapId, x, y, z, dynamicMapTree);
663 zoneid = area->ParentAreaID;
669 return grid->getMinHeight(x, y);
677 return gmap->getHeight(x, y);
689 mapHeight = gridHeight;
696 vmapHeight = vmgr->
getHeight(terrainMapId, x, y, z, maxSearchDist);
709 if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
724 return gmap->getLiquidLevel(x, y);
732 LiquidData* liquid_ptr = data ? data : &liquid_status;
759 return std::max<float>(liquid_status.
level, ground_z);
763 return liquid_status.
level;
794 entry =
sMapStore.LookupEntry(parentMapId);
803 if (std::shared_ptr<TerrainInfo> terrain = itr->second.lock())
820 if (std::shared_ptr<TerrainInfo> terrain = terrainRef.lock())
821 terrain->CleanUpGrids(diff);
826 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
827 return t->GetAreaId(phaseShift, mapid, x, y, z);
833 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
834 return t->GetZoneId(phaseShift, mapid, x, y, z);
840 if (std::shared_ptr<TerrainInfo> t =
LoadTerrain(mapid))
841 t->GetZoneAndAreaId(phaseShift, mapid, zoneid, areaid, x, y, z);
846 std::shared_ptr<TerrainInfo> rootTerrain(
new TerrainInfo(mapId));
848 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 TC_LOG_DEBUG(filterType__, message__,...)
#define TC_LOG_ERROR(filterType__, message__,...)
#define TC_LOG_WARN(filterType__, message__,...)
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)
#define VMAP_INVALID_HEIGHT_VALUE
#define VMAP_INVALID_HEIGHT
static uint32 GetLiquidFlags(uint32 liquidType)
static WMOAreaTableEntry const * GetWMOAreaTable(int32 rootId, int32 adtId, int32 groupId, bool allowGroupFallback)
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 * instance()
bool loadMapInstance(std::string_view basePath, uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
void unloadMap(uint32 mapId, int32 x, int32 y)
void unloadMapInstance(uint32 meshMapId, uint32 instanceMapId, uint32 instanceId)
static uint32 GetTerrainMapId(PhaseShift const &phaseShift, uint32 mapId, TerrainInfo const *terrain, float x, float y)
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 LoadMMap(uint32 instanceId, int32 gx, int32 gy)
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::array< uint64, MAX_NUMBER_OF_GRIDS > _loadedGrids
GridMap * GetGrid(uint32 mapId, float x, float y, bool loadIfMissing=true)
std::bitset< MAX_NUMBER_OF_GRIDS *MAX_NUMBER_OF_GRIDS > _gridFileExists
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
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)
TerrainInfo * _parentTerrain
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 LoadMMapImpl(uint32 instanceId, int32 gx, int32 gy)
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
static VMapManager * createOrGetVMapManager()
bool getAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional< uint8 > reqLiquidType, AreaAndLiquidData &data) const
static std::string getDirFileName(uint32 mapId, uint32 x, uint32 y)
bool isHeightCalcEnabled() const
void unloadMap(uint32 mapId, uint32 x, uint32 y)
float getHeight(uint32 mapId, float x, float y, float z, float maxSearchDist)
bool IsPathfindingEnabled(uint32 mapId)
std::string StringFormat(FormatString< Args... > fmt, Args &&... args) noexcept
Default TC string format function.
GridCoord ComputeGridCoord(float x, float y)
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