Core/Maps: Move terrain data handling out of Map class

Port From (https://github.com/TrinityCore/TrinityCore/commit/16a06346aea16ffd6ee84081cedfdb0c75ac0b38)
This commit is contained in:
hondacrx
2022-07-24 16:31:00 -04:00
parent c4344fbf66
commit 3cd58e4a17
25 changed files with 1035 additions and 960 deletions
+3 -3
View File
@@ -108,7 +108,7 @@ namespace Game.Chat
handler.SendSysMessage("tileloc [{0}, {1}]", gx, gy);
// calculate navmesh tile location
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), x, y);
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap().GetTerrain(), x, y);
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId);
Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, player.GetInstanceId());
if (navmesh == null || navmeshquery == null)
@@ -160,7 +160,7 @@ namespace Game.Chat
static bool HandleMmapLoadedTilesCommand(CommandHandler handler)
{
Player player = handler.GetSession().GetPlayer();
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), player.GetPositionX(), player.GetPositionY());
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap().GetTerrain(), player.GetPositionX(), player.GetPositionY());
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId);
Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, handler.GetPlayer().GetInstanceId());
if (navmesh == null || navmeshquery == null)
@@ -186,7 +186,7 @@ namespace Game.Chat
static bool HandleMmapStatsCommand(CommandHandler handler)
{
Player player = handler.GetSession().GetPlayer();
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), player.GetPositionX(), player.GetPositionY());
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap().GetTerrain(), player.GetPositionX(), player.GetPositionY());
handler.SendSysMessage("mmap stats:");
handler.SendSysMessage(" global mmap pathfinding is {0}abled", Global.DisableMgr.IsPathfindingEnabled(player.GetMapId()) ? "En" : "Dis");
handler.SendSysMessage(" {0} maps loaded with {1} tiles overall", Global.MMapMgr.GetLoadedMapsCount(), Global.MMapMgr.GetLoadedTilesCount());
+6 -6
View File
@@ -671,11 +671,11 @@ namespace Game.Chat
GridCoord gridCoord = GridDefines.ComputeGridCoord(obj.GetPositionX(), obj.GetPositionY());
// 63? WHY?
uint gridX = (MapConst.MaxGrids - 1) - gridCoord.X_coord;
uint gridY = (MapConst.MaxGrids - 1) - gridCoord.Y_coord;
int gridX = (int)((MapConst.MaxGrids - 1) - gridCoord.X_coord);
int gridY = (int)((MapConst.MaxGrids - 1) - gridCoord.Y_coord);
bool haveMap = Map.ExistMap(mapId, gridX, gridY);
bool haveVMap = Map.ExistVMap(mapId, gridX, gridY);
bool haveMap = TerrainInfo.ExistMap(mapId, gridX, gridY);
bool haveVMap = TerrainInfo.ExistVMap(mapId, gridX, gridY);
bool haveMMap = (Global.DisableMgr.IsPathfindingEnabled(mapId) && Global.MMapMgr.GetNavMesh(handler.GetSession().GetPlayer().GetMapId()) != null);
if (haveVMap)
@@ -706,8 +706,8 @@ namespace Game.Chat
handler.SendSysMessage(CypherStrings.GridPosition, cell.GetGridX(), cell.GetGridY(), cell.GetCellX(), cell.GetCellY(), obj.GetInstanceId(),
zoneX, zoneY, groundZ, floorZ, map.GetMinHeight(obj.GetPhaseShift(), obj.GetPositionX(), obj.GetPositionY()), haveMap, haveVMap, haveMMap);
LiquidData liquidStatus;
ZLiquidStatus status = map.GetLiquidStatus(obj.GetPhaseShift(), obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, out liquidStatus);
LiquidData liquidStatus = new();
ZLiquidStatus status = map.GetLiquidStatus(obj.GetPhaseShift(), obj.GetPositionX(), obj.GetPositionY(), obj.GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, liquidStatus);
if (liquidStatus != null)
handler.SendSysMessage(CypherStrings.LiquidStatus, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status);
+1 -1
View File
@@ -230,7 +230,7 @@ namespace Game.Chat
handler.SendSysMessage(CypherStrings.TeleportingTo, nameLink, handler.GetCypherString(CypherStrings.Offline), locationName);
Player.SavePositionInDB(new WorldLocation(mapId, pos), Global.MapMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, new WorldLocation(mapId, pos)), player.GetGUID(), null);
Player.SavePositionInDB(new WorldLocation(mapId, pos), Global.TerrainMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, new WorldLocation(mapId, pos)), player.GetGUID(), null);
}
return true;
@@ -35,7 +35,8 @@ namespace Game.Collision
Success,
FileNotFound,
VersionMismatch,
ReadFromFileFailed
ReadFromFileFailed,
DisabledInConfig
}
public class VMapManager : Singleton<VMapManager>
@@ -46,40 +47,15 @@ namespace Game.Collision
public void Initialize(MultiMap<uint, uint> mapData)
{
iChildMapData = mapData;
foreach (var pair in mapData)
iParentMapData[pair.Value] = pair.Key;
}
public VMAPLoadResult LoadMap(uint mapId, uint x, uint y)
public LoadResult LoadMap(uint mapId, int x, int y)
{
var result = VMAPLoadResult.Ignored;
if (IsMapLoadingEnabled())
{
LoadResult parentLoadResult = LoadSingleMap(mapId, x, y);
if (parentLoadResult == LoadResult.Success || parentLoadResult == LoadResult.FileNotFound)
{
if (parentLoadResult == LoadResult.Success)
result = VMAPLoadResult.OK;
// else VMAP_LOAD_RESULT_IGNORED
if (!IsMapLoadingEnabled())
return LoadResult.DisabledInConfig;
var childMaps = iChildMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
{
LoadResult childLoadResult = LoadSingleMap(childMapId, x, y);
if (childLoadResult != LoadResult.Success && childLoadResult != LoadResult.FileNotFound)
result = VMAPLoadResult.Error;
}
}
else
result = VMAPLoadResult.Error;
}
return result;
}
LoadResult LoadSingleMap(uint mapId, uint tileX, uint tileY)
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree == null)
{
@@ -94,19 +70,10 @@ namespace Game.Collision
instanceTree = newTree;
}
return instanceTree.LoadMapTile(tileX, tileY, this);
return instanceTree.LoadMapTile(x, y, this);
}
public void UnloadMap(uint mapId, uint x, uint y)
{
var childMaps = iChildMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
UnloadSingleMap(childMapId, x, y);
UnloadSingleMap(mapId, x, y);
}
void UnloadSingleMap(uint mapId, uint x, uint y)
public void UnloadMap(uint mapId, int x, int y)
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -120,15 +87,6 @@ namespace Game.Collision
}
public void UnloadMap(uint mapId)
{
var childMaps = iChildMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
UnloadSingleMap(childMapId);
UnloadSingleMap(mapId);
}
void UnloadSingleMap(uint mapId)
{
var instanceTree = iInstanceMapTrees.LookupByKey(mapId);
if (instanceTree != null)
@@ -329,7 +287,7 @@ namespace Game.Collision
}
}
public LoadResult ExistsMap(uint mapId, uint x, uint y)
public LoadResult ExistsMap(uint mapId, int x, int y)
{
return StaticMapTree.CanLoadMap(VMapPath, mapId, x, y, this);
}
@@ -367,7 +325,6 @@ namespace Game.Collision
Dictionary<string, ManagedModel> iLoadedModelFiles = new();
Dictionary<uint, StaticMapTree> iInstanceMapTrees = new();
MultiMap<uint, uint> iChildMapData = new();
Dictionary<uint, uint> iParentMapData = new();
bool _enableLineOfSightCalc;
bool _enableHeightCalc;
+7 -7
View File
@@ -108,7 +108,7 @@ namespace Game.Collision
iLoadedTiles.Clear();
}
public LoadResult LoadMapTile(uint tileX, uint tileY, VMapManager vm)
public LoadResult LoadMapTile(int tileX, int tileY, VMapManager vm)
{
if (iTreeValues == null)
{
@@ -183,7 +183,7 @@ namespace Game.Collision
return result;
}
public void UnloadMapTile(uint tileX, uint tileY, VMapManager vm)
public void UnloadMapTile(int tileX, int tileY, VMapManager vm)
{
uint tileID = PackTileID(tileX, tileY);
if (!iLoadedTiles.ContainsKey(tileID))
@@ -233,10 +233,10 @@ namespace Game.Collision
iLoadedTiles.Remove(tileID);
}
static uint PackTileID(uint tileX, uint tileY) { return tileX << 16 | tileY; }
static void UnpackTileID(uint ID, ref uint tileX, ref uint tileY) { tileX = ID >> 16; tileY = ID & 0xFF; }
static uint PackTileID(int tileX, int tileY) { return (uint)(tileX << 16 | tileY); }
static void UnpackTileID(int ID, ref int tileX, ref int tileY) { tileX = ID >> 16; tileY = ID & 0xFF; }
static TileFileOpenResult OpenMapTileFile(string vmapPath, uint mapID, uint tileX, uint tileY, VMapManager vm)
static TileFileOpenResult OpenMapTileFile(string vmapPath, uint mapID, int tileX, int tileY, VMapManager vm)
{
TileFileOpenResult result = new();
result.Name = vmapPath + GetTileFileName(mapID, tileX, tileY);
@@ -265,7 +265,7 @@ namespace Game.Collision
return result;
}
public static LoadResult CanLoadMap(string vmapPath, uint mapID, uint tileX, uint tileY, VMapManager vm)
public static LoadResult CanLoadMap(string vmapPath, uint mapID, int tileX, int tileY, VMapManager vm)
{
string fullname = vmapPath + VMapManager.GetMapFileName(mapID);
if (!File.Exists(fullname))
@@ -290,7 +290,7 @@ namespace Game.Collision
return LoadResult.Success;
}
public static string GetTileFileName(uint mapID, uint tileX, uint tileY)
public static string GetTileFileName(uint mapID, int tileX, int tileY)
{
return $"{mapID:D4}_{tileY:D2}_{tileX:D2}.vmtile";
}
+1 -1
View File
@@ -3556,7 +3556,7 @@ namespace Game.Entities
// Unit is flying, check for potential collision via vmaps
if (path.GetPathType().HasFlag(PathType.NotUsingPath))
{
col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap(), pos.posX, pos.posY),
col = Global.VMapMgr.GetObjectHitPos(PhasingHandler.GetTerrainMapId(GetPhaseShift(), GetMap().GetTerrain(), pos.posX, pos.posY),
pos.posX, pos.posY, pos.posZ + halfHeight,
destx, desty, destz + halfHeight,
out destx, out desty, out destz, -0.5f);
+3 -4
View File
@@ -615,7 +615,7 @@ namespace Game.Entities
if (!createPosition.TransportGuid.HasValue)
{
homebind.WorldRelocate(createPosition.Loc);
homebindAreaId = Global.MapMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, homebind);
homebindAreaId = Global.TerrainMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, homebind);
saveHomebindToDb();
ok = true;
@@ -631,7 +631,7 @@ namespace Game.Entities
Cypher.Assert(loc != null, "Missing fallback graveyard location for faction {GetTeamId()}");
homebind.WorldRelocate(loc.Loc);
homebindAreaId = Global.MapMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, loc.Loc);
homebindAreaId = Global.TerrainMgr.GetAreaId(PhasingHandler.EmptyPhaseShift, loc.Loc);
saveHomebindToDb();
}
@@ -3806,7 +3806,6 @@ namespace Game.Entities
return 0;
uint zone = result.Read<ushort>(0);
if (zone == 0)
{
// stored zone is zero, use generic and slow zone detection
@@ -3825,7 +3824,7 @@ namespace Game.Entities
if (!CliDB.MapStorage.ContainsKey(map))
return 0;
zone = Global.MapMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, map, posx, posy, posz);
zone = Global.TerrainMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, map, posx, posy, posz);
if (zone > 0)
{
+1 -1
View File
@@ -763,7 +763,7 @@ namespace Game.Entities
mountFlags = (AreaMountFlags)areaTable.MountFlags;
}
ZLiquidStatus liquidStatus = GetMap().GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, out _);
ZLiquidStatus liquidStatus = GetMap().GetLiquidStatus(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, null);
isSubmerged = liquidStatus.HasAnyFlag(ZLiquidStatus.UnderWater) || HasUnitMovementFlag(MovementFlag.Swimming);
isInWater = liquidStatus.HasAnyFlag(ZLiquidStatus.InWater | ZLiquidStatus.UnderWater);
+1
View File
@@ -67,6 +67,7 @@ public static class Global
public static ArenaTeamManager ArenaTeamMgr { get { return ArenaTeamManager.Instance; } }
//Maps System
public static TerrainManager TerrainMgr { get { return TerrainManager.Instance; } }
public static MapManager MapMgr { get { return MapManager.Instance; } }
public static MMapManager MMapMgr { get { return MMapManager.Instance; } }
public static VMapManager VMapMgr { get { return VMapManager.Instance; } }
+3 -3
View File
@@ -804,7 +804,7 @@ namespace Game
uint MapId = location.GetMapId();
// search for zone associated closest graveyard
uint zoneId = Global.MapMgr.GetZoneId(conditionObject ? conditionObject.GetPhaseShift() : PhasingHandler.EmptyPhaseShift, MapId, x, y, z);
uint zoneId = Global.TerrainMgr.GetZoneId(conditionObject ? conditionObject.GetPhaseShift() : PhasingHandler.EmptyPhaseShift, MapId, x, y, z);
if (zoneId == 0)
{
if (z > -500)
@@ -3647,7 +3647,7 @@ namespace Game
if (WorldConfig.GetBoolValue(WorldCfg.CalculateCreatureZoneAreaData))
{
PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap);
Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
Global.TerrainMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_CREATURE_ZONE_AREA_DATA);
stmt.AddValue(0, zoneId);
@@ -4440,7 +4440,7 @@ namespace Game
if (WorldConfig.GetBoolValue(WorldCfg.CalculateGameobjectZoneAreaData))
{
PhasingHandler.InitDbVisibleMapId(phaseShift, data.terrainSwapMap);
Global.MapMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
Global.TerrainMgr.GetZoneAndAreaId(phaseShift, out uint zoneId, out uint areaId, data.MapId, data.SpawnPoint);
PreparedStatement stmt = DB.World.GetPreparedStatement(WorldStatements.UPD_GAMEOBJECT_ZONE_AREA_DATA);
stmt.AddValue(0, zoneId);
+1 -1
View File
@@ -2068,7 +2068,7 @@ namespace Game.Groups
WorldSafeLocsEntry graveyardLocation = Global.ObjectMgr.GetClosestGraveYard(
new WorldLocation(instanceEntrance.target_mapId, instanceEntrance.target_X, instanceEntrance.target_Y, instanceEntrance.target_Z),
SendMsgTo.GetTeam(), null);
uint zoneId = Global.MapMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, graveyardLocation.Loc.GetMapId(),
uint zoneId = Global.TerrainMgr.GetZoneId(PhasingHandler.EmptyPhaseShift, graveyardLocation.Loc.GetMapId(),
graveyardLocation.Loc.GetPositionX(), graveyardLocation.Loc.GetPositionY(), graveyardLocation.Loc.GetPositionZ());
foreach (MemberSlot member in GetMemberSlots())
+3 -3
View File
@@ -241,13 +241,13 @@ namespace Game
if (corpseMapEntry.IsDungeon() && corpseMapEntry.CorpseMapID >= 0)
{
// if corpse map have entrance
Map entranceMap = Global.MapMgr.CreateBaseMap((uint)corpseMapEntry.CorpseMapID);
if (entranceMap != null)
TerrainInfo entranceTerrain = Global.TerrainMgr.LoadTerrain((uint)corpseMapEntry.CorpseMapID);
if (entranceTerrain != null)
{
mapID = (uint)corpseMapEntry.CorpseMapID;
x = corpseMapEntry.Corpse.X;
y = corpseMapEntry.Corpse.Y;
z = entranceMap.GetHeight(player.GetPhaseShift(), x, y, MapConst.MaxHeight);
z = entranceTerrain.GetStaticHeight(player.GetPhaseShift(), x, y, MapConst.MaxHeight);
}
}
}
+3
View File
@@ -40,7 +40,10 @@ namespace Game.Maps
public LoadResult LoadData(string filename)
{
// Unload old data if exist
UnloadData();
// Not return error if file not found
if (!File.Exists(filename))
return LoadResult.FileNotFound;
+4 -45
View File
@@ -32,8 +32,6 @@ namespace Game
public void Initialize(MultiMap<uint, uint> mapData)
{
childMapData = mapData;
foreach (var pair in mapData)
parentMapData[pair.Value] = pair.Key;
}
@@ -82,27 +80,12 @@ namespace Game
return true;
}
uint PackTileID(uint x, uint y)
uint PackTileID(int x, int y)
{
return (x << 16 | y);
return (uint)(x << 16 | y);
}
public bool LoadMap(string basePath, uint mapId, uint x, uint y)
{
// make sure the mmap is loaded and ready to load tiles
if (!LoadMapImpl(basePath, mapId, x, y))
return false;
bool success = true;
var childMaps = childMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
if (!LoadMapImpl(basePath, childMapId, x, y))
success = false;
return success;
}
bool LoadMapImpl(string basePath, uint mapId, uint x, uint y)
public bool LoadMap(string basePath, uint mapId, int x, int y)
{
// make sure the mmap is loaded and ready to load tiles
if (!LoadMapData(basePath, mapId))
@@ -164,20 +147,6 @@ namespace Game
}
public bool LoadMapInstance(string basePath, uint mapId, uint instanceId)
{
if (!LoadMapInstanceImpl(basePath, mapId, instanceId))
return false;
bool success = true;
var childMaps = childMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
if (!LoadMapInstanceImpl(basePath, childMapId, instanceId))
success = false;
return success;
}
bool LoadMapInstanceImpl(string basePath, uint mapId, uint instanceId)
{
if (!LoadMapData(basePath, mapId))
return false;
@@ -199,16 +168,7 @@ namespace Game
return true;
}
public bool UnloadMap(uint mapId, uint x, uint y)
{
var childMaps = childMapData.LookupByKey(mapId);
foreach (uint childMapId in childMaps)
UnloadMapImpl(childMapId, x, y);
return UnloadMapImpl(mapId, x, y);
}
bool UnloadMapImpl(uint mapId, uint x, uint y)
public bool UnloadMap(uint mapId, int x, int y)
{
// check if we have this map loaded
MMapData mmap = GetMMapData(mapId);
@@ -327,7 +287,6 @@ namespace Game
Dictionary<uint, MMapData> loadedMMaps = new();
uint loadedTiles;
MultiMap<uint, uint> childMapData = new();
Dictionary<uint, uint> parentMapData = new();
}
+75 -713
View File
@@ -45,29 +45,14 @@ namespace Game.Maps
m_VisibleDistance = SharedConst.DefaultVisibilityDistance;
m_VisibilityNotifyPeriod = SharedConst.DefaultVisibilityNotifyPeriod;
i_gridExpiry = expiry;
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 List<Map>();
}
m_terrain = Global.TerrainMgr.LoadTerrain(id);
for (uint x = 0; x < MapConst.MaxGrids; ++x)
{
i_grids[x] = new Grid[MapConst.MaxGrids];
GridMaps[x] = new GridMap[MapConst.MaxGrids];
GridMapReference[x] = new ushort[MapConst.MaxGrids];
for (uint y = 0; y < MapConst.MaxGrids; ++y)
{
//z code
GridMaps[x][y] = null;
SetGrid(null, x, y);
}
}
@@ -117,191 +102,9 @@ namespace Game.Maps
Global.OutdoorPvPMgr.DestroyOutdoorPvPForMap(this);
Global.BattleFieldMgr.DestroyBattlefieldsForMap(this);
if (m_parentMap == this)
m_childTerrainMaps = null;
Global.MMapMgr.UnloadMapInstance(GetId(), i_InstanceId);
}
public void DiscoverGridMapFiles()
{
string tileListName = $"{Global.WorldMgr.GetDataPath()}/maps/{GetId():D4}.tilelist";
// tile list is optional
if (File.Exists(tileListName))
{
using var reader = new BinaryReader(new FileStream(tileListName, FileMode.Open, FileAccess.Read));
var mapMagic = reader.ReadUInt32();
var versionMagic = reader.ReadUInt32();
if (mapMagic == MapConst.MapMagic && versionMagic == MapConst.MapVersionMagic)
{
var build = reader.ReadUInt32();
byte[] tilesData = reader.ReadArray<byte>(MapConst.MaxGrids * MapConst.MaxGrids);
for (uint gx = 0; gx < MapConst.MaxGrids; ++gx)
for (uint gy = 0; gy < MapConst.MaxGrids; ++gy)
i_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)] = tilesData[(int)(gx * MapConst.MaxGrids + gy)] == 49; // char of 1
return;
}
}
for (uint gx = 0; gx < MapConst.MaxGrids; ++gx)
for (uint gy = 0; gy < MapConst.MaxGrids; ++gy)
i_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)] = ExistMap(GetId(), gx, gy);
}
Map GetRootParentTerrainMap()
{
Map map = this;
while (map != map.m_parentTerrainMap)
map = map.m_parentTerrainMap;
return map;
}
public static bool ExistMap(uint mapid, uint gx, uint gy)
{
string fileName = $"{Global.WorldMgr.GetDataPath()}/maps/{mapid:D4}_{gx:D2}_{gy:D2}.map";
if (!File.Exists(fileName))
{
Log.outError(LogFilter.Maps, "Map file '{0}': does not exist!", fileName);
return false;
}
using var reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
var header = reader.Read<MapFileHeader>();
if (header.mapMagic != MapConst.MapMagic || (header.versionMagic != MapConst.MapVersionMagic && header.versionMagic != MapConst.MapVersionMagic2)) // Hack for some different extractors using v2.0 header
{
Log.outError(LogFilter.Maps, "Map file '{0}' is from an incompatible map version ({1}), {2} is expected. Please recreate using the mapextractor.",
fileName, header.versionMagic, MapConst.MapVersionMagic);
return false;
}
return true;
}
public static bool ExistVMap(uint mapid, uint gx, uint gy)
{
if (Global.VMapMgr.IsMapLoadingEnabled())
{
LoadResult result = Global.VMapMgr.ExistsMap(mapid, gx, gy);
string name = VMapManager.GetMapFileName(mapid);
switch (result)
{
case LoadResult.Success:
break;
case LoadResult.FileNotFound:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "vmaps/" + name}' does not exist");
Log.outError(LogFilter.Maps, $"Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({Global.WorldMgr.GetDataPath() + "vmaps/"}), or correct the DataDir setting in your worldserver.conf file.");
return false;
case LoadResult.VersionMismatch:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "vmaps/" + name}e' couldn't b loaded");
Log.outError(LogFilter.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 LoadResult.ReadFromFileFailed:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "vmaps/" + name}' couldn't be loaded");
Log.outError(LogFilter.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 LoadMMap(uint gx, uint gy)
{
if (!Global.DisableMgr.IsPathfindingEnabled(GetId()))
return;
if (Global.MMapMgr.LoadMap(Global.WorldMgr.GetDataPath(), GetId(), gx, gy))
Log.outInfo(LogFilter.Maps, "MMAP loaded name:{0}, id:{1}, x:{2}, y:{3} (mmap rep.: x:{4}, y:{5})", GetMapName(), GetId(), gx, gy, gx, gy);
else
Log.outWarn(LogFilter.Maps, "Could not load MMAP name:{0}, id:{1}, x:{2}, y:{3} (mmap rep.: x:{4}, y:{5})", GetMapName(), GetId(), gx, gy, gx, gy);
}
void LoadVMap(uint gx, uint gy)
{
if (!Global.VMapMgr.IsMapLoadingEnabled())
return;
// x and y are swapped !!
VMAPLoadResult vmapLoadResult = Global.VMapMgr.LoadMap(GetId(), gx, gy);
switch (vmapLoadResult)
{
case VMAPLoadResult.OK:
Log.outInfo(LogFilter.Maps, "VMAP loaded name:{0}, id:{1}, x:{2}, y:{3} (vmap rep.: x:{4}, y:{5})", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAPLoadResult.Error:
Log.outInfo(LogFilter.Maps, "Could not load VMAP name:{0}, id:{1}, x:{2}, y:{3} (vmap rep.: x:{4}, y:{5})", GetMapName(), GetId(), gx, gy, gx, gy);
break;
case VMAPLoadResult.Ignored:
Log.outDebug(LogFilter.Maps, "Ignored VMAP name:{0}, id:{1}, x:{2}, y:{3} (vmap rep.: x:{4}, y:{5})", GetMapName(), GetId(), gx, gy, gx, gy);
break;
}
}
void LoadMap(uint gx, uint gy)
{
LoadMapImpl(this, gx, gy);
foreach (Map childBaseMap in m_childTerrainMaps)
childBaseMap.LoadMap(gx, gy);
}
void LoadMapImpl(Map map, uint gx, uint gy)
{
if (map.GridMaps[gx][gy] != null)
return;
// map file name
string fileName = $"{Global.WorldMgr.GetDataPath()}/maps/{map.GetId():D4}_{gx:D2}_{gy:D2}.map";
Log.outInfo(LogFilter.Maps, "Loading map {0}", fileName);
// loading data
GridMap gridMap = new();
LoadResult gridMapLoadResult = gridMap.LoadData(fileName);
if (gridMapLoadResult == LoadResult.Success)
map.GridMaps[gx][gy] = gridMap;
else
{
map.i_gridFileExists[(int)(gx * MapConst.MaxGrids + 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] != null)
break;
parentTerrain = parentTerrain.m_parentTerrainMap;
}
}
if (map.GridMaps[gx][gy] != null)
Global.ScriptMgr.OnLoadGridMap(map, map.GridMaps[gx][gy], gx, gy);
else if (gridMapLoadResult == LoadResult.ReadFromFileFailed)
Log.outError(LogFilter.Maps, $"Error loading map file: {fileName}");
}
void UnloadMap(uint gx, uint gy)
{
foreach (Map childBaseMap in m_childTerrainMaps)
childBaseMap.UnloadMap(gx, gy);
UnloadMapImpl(this, gx, gy);
}
void UnloadMapImpl(Map map, uint gx, uint gy)
{
map.GridMaps[gx][gy] = null;
}
void LoadMapAndVMap(uint gx, uint gy)
{
LoadMap(gx, gy);
// Only load the data for the base map
if (this == m_parentMap)
{
LoadVMap(gx, gy);
LoadMMap(gx, gy);
}
}
public void LoadAllCells()
{
for (uint cellX = 0; cellX < MapConst.TotalCellsPerMap; cellX++)
@@ -443,22 +246,10 @@ namespace Game.Maps
SetGrid(grid, p.X_coord, p.Y_coord);
//z coord
uint gx = (MapConst.MaxGrids - 1) - p.X_coord;
uint gy = (MapConst.MaxGrids - 1) - p.Y_coord;
int gx = (int)((MapConst.MaxGrids - 1) - p.X_coord);
int gy = (int)((MapConst.MaxGrids - 1) - p.Y_coord);
if (GridMaps[gx][gy] == null)
{
Map rootParentTerrainMap = m_parentMap.GetRootParentTerrainMap();
if (m_parentMap.GridMaps[gx][gy] == null)
rootParentTerrainMap.LoadMapAndVMap(gx, gy);
if (m_parentMap.GridMaps[gx][gy] != null)
{
GridMaps[gx][gy] = m_parentMap.GridMaps[gx][gy];
++rootParentTerrainMap.GridMapReference[gx][gy];
}
}
m_terrain.LoadMapAndVMap(gx, gy);
}
}
@@ -1680,20 +1471,10 @@ namespace Game.Maps
Cypher.Assert(i_objectsToRemove.Empty());
SetGrid(null, x, y);
uint gx = (MapConst.MaxGrids - 1) - x;
uint gy = (MapConst.MaxGrids - 1) - y;
int gx = (int)((MapConst.MaxGrids - 1) - x);
int gy = (int)((MapConst.MaxGrids - 1) - y);
// delete grid map, but don't delete if it is from parent map (and thus only reference)
if (GridMaps[gx][gy] != null)
{
Map terrainRoot = m_parentMap.GetRootParentTerrainMap();
if (--terrainRoot.GridMapReference[gx][gy] == 0)
{
m_parentMap.GetRootParentTerrainMap().UnloadMap(gx, gy);
Global.VMapMgr.UnloadMap(terrainRoot.GetId(), gx, gy);
Global.MMapMgr.UnloadMap(terrainRoot.GetId(), gx, gy);
}
}
m_terrain.UnloadMap(gx, gy);
Log.outDebug(LogFilter.Maps, "Unloading grid[{0}, {1}] for map {2} finished", x, y, GetId());
return true;
@@ -1748,98 +1529,61 @@ namespace Game.Maps
_corpsesByCell.Clear();
_corpsesByPlayer.Clear();
_corpseBones.Clear();
}
public static bool IsInWMOInterior(uint mogpFlags)
{
return (mogpFlags & 0x2000) != 0;
}
GridMap GetGridMap(uint mapId, float x, float y)
public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
{
// half opt method
uint gx = (uint)(MapConst.CenterGridId - x / MapConst.SizeofGrids); //grid x
uint gy = (uint)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y
// ensure GridMap is loaded
EnsureGridCreated(new GridCoord((MapConst.MaxGrids - 1) - gx, (MapConst.MaxGrids - 1) - gy));
GridMap grid = GridMaps[gx][gy];
var childMap = m_childTerrainMaps.Find(childTerrainMap => childTerrainMap.GetId() == mapId);
if (childMap != null && childMap.GridMaps[gx][gy] != null)
grid = childMap.GridMaps[gx][gy];
return grid;
m_terrain.GetFullTerrainStatusForPosition(phaseShift, x, y, z, data, reqLiquidType, collisionHeight, _dynamicTree);
}
public bool HasChildMapGridFile(uint mapId, uint gx, uint gy)
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
{
var childMap = m_childTerrainMaps.Find(childTerrainMap => childTerrainMap.GetId() == mapId);
return childMap != null && childMap.i_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)];
return m_terrain.GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, null, collisionHeight);
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, float collisionHeight = MapConst.DefaultCollesionHeight)
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, LiquidData data, float collisionHeight = MapConst.DefaultCollesionHeight)
{
float ground = 0f;
return GetWaterOrGroundLevel(phaseShift, x, y, z, ref ground);
return m_terrain.GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, data, collisionHeight);
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, ref float ground, bool swim = false, float collisionHeight = MapConst.DefaultCollesionHeight)
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint mogpflags, out int adtId, out int rootId, out int groupId)
{
if (GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y) != null)
{
// we need ground level (including grid height version) for proper return water level in point
float ground_z = GetHeight(phaseShift, x, y, z + MapConst.ZOffsetFindHeight, true, 50.0f);
ground = ground_z;
LiquidData liquid_status;
ZLiquidStatus res = GetLiquidStatus(phaseShift, x, y, ground_z, LiquidHeaderTypeFlags.AllLiquids, out liquid_status, collisionHeight);
switch (res)
{
case ZLiquidStatus.AboveWater:
return Math.Max(liquid_status.level, ground_z);
case ZLiquidStatus.NoWater:
return ground_z;
default:
return liquid_status.level;
}
}
return MapConst.VMAPInvalidHeightValue;
return m_terrain.GetAreaInfo(phaseShift, x, y, z, out mogpflags, out adtId, out rootId, out groupId, _dynamicTree);
}
public float GetStaticHeight(PhaseShift phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
public uint GetAreaId(PhaseShift phaseShift, Position pos)
{
// find raw .map surface under Z coordinates
float mapHeight = MapConst.VMAPInvalidHeightValue;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
float gridHeight = GetGridHeight(phaseShift, x, y);
if (MathFunctions.fuzzyGe(z, gridHeight - MapConst.GroundHeightTolerance))
mapHeight = gridHeight;
return m_terrain.GetAreaId(phaseShift, pos.posX, pos.posY, pos.posZ, _dynamicTree);
}
float vmapHeight = MapConst.VMAPInvalidHeightValue;
if (checkVMap)
{
if (Global.VMapMgr.IsHeightCalcEnabled())
vmapHeight = Global.VMapMgr.GetHeight(terrainMapId, x, y, z, maxSearchDist);
}
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z)
{
return m_terrain.GetAreaId(phaseShift, x, y, z, _dynamicTree);
}
// mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
// vmapheight set for any under Z value or <= INVALID_HEIGHT
if (vmapHeight > MapConst.InvalidHeight)
{
if (mapHeight > MapConst.InvalidHeight)
{
// we have mapheight and vmapheight and must select more appropriate
public uint GetZoneId(PhaseShift phaseShift, Position pos)
{
return m_terrain.GetZoneId(phaseShift, pos.posX, pos.posY, pos.posZ, _dynamicTree);
}
// vmap height above map height
// or if the distance of the vmap height is less the land height distance
if (vmapHeight > mapHeight || Math.Abs(mapHeight - z) > Math.Abs(vmapHeight - z))
return vmapHeight;
public uint GetZoneId(PhaseShift phaseShift, float x, float y, float z)
{
return m_terrain.GetZoneId(phaseShift, x, y, z, _dynamicTree);
}
return mapHeight; // better use .map surface height
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, Position pos)
{
m_terrain.GetZoneAndAreaId(phaseShift, out zoneid, out areaid, pos.posX, pos.posY, pos.posZ, _dynamicTree);
}
return vmapHeight; // we have only vmapHeight (if have)
}
return mapHeight; // explicitly use map data
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, float x, float y, float z)
{
m_terrain.GetZoneAndAreaId(phaseShift, out zoneid, out areaid, x, y, z, _dynamicTree);
}
public float GetHeight(PhaseShift phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
@@ -1852,412 +1596,50 @@ namespace Game.Maps
return GetHeight(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), vmap, maxSearchDist);
}
public float GetGridHeight(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.GetHeight(x, y);
return MapConst.VMAPInvalidHeightValue;
}
public float GetMinHeight(PhaseShift phaseShift, float x, float y)
{
GridMap grid = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (grid != null)
return grid.GetMinHeight(x, y);
return -500.0f;
return m_terrain.GetMinHeight(phaseShift, x, y);
}
public static bool IsInWMOInterior(uint mogpFlags)
public float GetGridHeight(PhaseShift phaseShift, float x, float y)
{
return (mogpFlags & 0x2000) != 0;
return m_terrain.GetGridHeight(phaseShift, x, y);
}
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint mogpflags, out int adtId, out int rootId, out int groupId)
public float GetStaticHeight(PhaseShift phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
{
mogpflags = 0;
adtId = 0;
rootId = 0;
groupId = 0;
float vmap_z = z;
float dynamic_z = z;
float check_z = z;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
uint vflags;
int vadtId;
int vrootId;
int vgroupId;
uint dflags;
int dadtId;
int drootId;
int dgroupId;
bool hasVmapAreaInfo = Global.VMapMgr.GetAreaInfo(terrainMapId, x, y, ref vmap_z, out vflags, out vadtId, out vrootId, out vgroupId);
bool hasDynamicAreaInfo = _dynamicTree.GetAreaInfo(x, y, ref dynamic_z, phaseShift, out dflags, out dadtId, out drootId, out dgroupId);
if (hasVmapAreaInfo)
{
if (hasDynamicAreaInfo && dynamic_z > vmap_z)
{
check_z = dynamic_z;
mogpflags = dflags;
adtId = dadtId;
rootId = drootId;
groupId = dgroupId;
}
else
{
check_z = vmap_z;
mogpflags = vflags;
adtId = vadtId;
rootId = vrootId;
groupId = vgroupId;
}
}
else if (hasDynamicAreaInfo)
{
check_z = dynamic_z;
mogpflags = dflags;
adtId = dadtId;
rootId = drootId;
groupId = dgroupId;
}
if (hasVmapAreaInfo || hasDynamicAreaInfo)
{
// check if there's terrain between player height and object height
GridMap gmap = GetGridMap(terrainMapId, x, y);
if (gmap != null)
{
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;
}
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z)
{
uint mogpFlags;
int adtId, rootId, groupId;
float vmapZ = z;
bool hasVmapArea = GetAreaInfo(phaseShift, x, y, vmapZ, out mogpFlags, out adtId, out rootId, out groupId);
uint gridAreaId = 0;
float gridMapHeight = MapConst.InvalidHeight;
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
{
gridAreaId = gmap.GetArea(x, y);
gridMapHeight = gmap.GetHeight(x, y);
}
uint areaId = 0;
// floor is the height we are closer to (but only if above)
if (hasVmapArea && MathFunctions.fuzzyGe(z, vmapZ - MapConst.GroundHeightTolerance) && (MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || vmapZ > gridMapHeight))
{
// wmo found
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
if (wmoEntry != null)
areaId = wmoEntry.AreaTableID;
if (areaId == 0)
areaId = gridAreaId;
}
else
areaId = gridAreaId;
if (areaId == 0)
areaId = i_mapRecord.AreaTableID;
return areaId;
}
public uint GetAreaId(PhaseShift phaseShift, Position pos) { return GetAreaId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public uint GetZoneId(PhaseShift phaseShift, float x, float y, float z)
{
uint areaId = GetAreaId(phaseShift, x, y, z);
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaId);
if (area != null)
if (area.ParentAreaID != 0)
return area.ParentAreaID;
return areaId;
}
public uint GetZoneId(PhaseShift phaseShift, Position pos) { return GetZoneId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, float x, float y, float z)
{
areaid = zoneid = GetAreaId(phaseShift, x, y, z);
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaid);
if (area != null)
if (area.ParentAreaID != 0)
zoneid = area.ParentAreaID;
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, Position pos) { GetZoneAndAreaId(phaseShift, out zoneid, out areaid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
{
return GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, out _, collisionHeight);
}
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, out LiquidData data, float collisionHeight = MapConst.DefaultCollesionHeight)
{
data = new LiquidData();
var result = ZLiquidStatus.NoWater;
float liquid_level = MapConst.InvalidHeight;
float ground_level = MapConst.InvalidHeight;
uint liquid_type = 0;
uint mogpFlags = 0;
bool useGridLiquid = true;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
if (Global.VMapMgr.GetLiquidLevel(terrainMapId, x, y, z, (byte)reqLiquidType, ref liquid_level, ref ground_level, ref liquid_type, ref mogpFlags))
{
useGridLiquid = !IsInWMOInterior(mogpFlags);
Log.outDebug(LogFilter.Maps, "getLiquidStatus(): vmap liquid level: {0} ground: {1} type: {2}",
liquid_level, ground_level, liquid_type);
// Check water level and ground level
if (liquid_level > ground_level && MathFunctions.fuzzyGe(z, ground_level - MapConst.GroundHeightTolerance))
{
// All ok in water . store data
// hardcoded in client like this
if (GetId() == 530 && liquid_type == 2)
liquid_type = 15;
uint liquidFlagType = 0;
LiquidTypeRecord liq = CliDB.LiquidTypeStorage.LookupByKey(liquid_type);
if (liq != null)
liquidFlagType = liq.SoundBank;
if (liquid_type != 0 && liquid_type < 21)
{
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(GetAreaId(phaseShift, x, y, z));
if (area != null)
{
uint overrideLiquid = area.LiquidTypeID[liquidFlagType];
if (overrideLiquid == 0 && area.ParentAreaID != 0)
{
area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
if (area != null)
overrideLiquid = area.LiquidTypeID[liquidFlagType];
}
liq = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
if (liq != null)
{
liquid_type = overrideLiquid;
liquidFlagType = liq.SoundBank;
}
}
}
data.level = liquid_level;
data.depth_level = ground_level;
data.entry = liquid_type;
data.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType);
float delta = liquid_level - z;
// Get position delta
if (delta > collisionHeight) // Under water
return ZLiquidStatus.UnderWater;
if (delta > 0.0f) // In water
return ZLiquidStatus.InWater;
if (delta > -0.1f) // Walk on water
return ZLiquidStatus.WaterWalk;
result = ZLiquidStatus.AboveWater;
}
}
if (useGridLiquid)
{
GridMap gmap = GetGridMap(terrainMapId, x, y);
if (gmap != null)
{
var map_data = new LiquidData();
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 != ZLiquidStatus.NoWater && (map_data.level > ground_level))
{
// hardcoded in client like this
if (GetId() == 530 && map_data.entry == 2)
map_data.entry = 15;
data = map_data;
return map_result;
}
}
}
return result;
}
public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, LiquidHeaderTypeFlags reqLiquidType, float collisionHeight = MapConst.DefaultCollesionHeight)
{
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
GridMap gmap = GetGridMap(terrainMapId, x, y);
AreaAndLiquidData vmapData = Global.VMapMgr.GetAreaAndLiquidData(terrainMapId, x, y, z, (byte)reqLiquidType);
AreaAndLiquidData dynData = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseShift, (byte)reqLiquidType);
uint gridAreaId = 0;
float gridMapHeight = MapConst.InvalidHeight;
if (gmap != null)
{
gridAreaId = gmap.GetArea(x, y);
gridMapHeight = gmap.GetHeight(x, y);
}
bool useGridLiquid = true;
AreaAndLiquidData wmoData = null;
// floor is the height we are closer to (but only if above)
data.FloorZ = MapConst.InvalidHeight;
if (gridMapHeight > MapConst.InvalidHeight && MathFunctions.fuzzyGe(z, gridMapHeight - MapConst.GroundHeightTolerance))
data.FloorZ = gridMapHeight;
if (vmapData.floorZ > MapConst.InvalidHeight &&
MathFunctions.fuzzyGe(z, vmapData.floorZ - MapConst.GroundHeightTolerance) &&
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || 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 > MapConst.InvalidHeight &&
MathFunctions.fuzzyGe(z, dynData.floorZ - MapConst.GroundHeightTolerance) &&
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || dynData.floorZ > gridMapHeight) &&
(MathFunctions.fuzzyLt(z, vmapData.floorZ - MapConst.GroundHeightTolerance) || dynData.floorZ > vmapData.floorZ))
{
data.FloorZ = dynData.floorZ;
wmoData = dynData;
}
if (wmoData != null)
{
if (wmoData.areaInfo.HasValue)
{
data.areaInfo = new(wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.GroupId, wmoData.areaInfo.Value.MogpFlags);
// wmo found
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.GroupId);
data.outdoors = (wmoData.areaInfo.Value.MogpFlags & 0x8) != 0;
if (wmoEntry != null)
{
data.AreaId = wmoEntry.AreaTableID;
if ((wmoEntry.Flags & 4) != 0)
data.outdoors = true;
else if ((wmoEntry.Flags & 2) != 0)
data.outdoors = false;
}
if (data.AreaId == 0)
data.AreaId = gridAreaId;
useGridLiquid = !IsInWMOInterior(wmoData.areaInfo.Value.MogpFlags);
}
}
else
{
data.outdoors = true;
data.AreaId = gridAreaId;
var areaEntry1 = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
if (areaEntry1 != null)
data.outdoors = ((AreaFlags)areaEntry1.Flags[0] & (AreaFlags.Inside | AreaFlags.Outside)) != AreaFlags.Inside;
}
if (data.AreaId == 0)
data.AreaId = i_mapRecord.AreaTableID;
var areaEntry = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
// liquid processing
data.LiquidStatus = ZLiquidStatus.NoWater;
if (wmoData != null && wmoData.liquidInfo.HasValue && wmoData.liquidInfo.Value.Level > wmoData.floorZ)
{
uint liquidType = wmoData.liquidInfo.Value.LiquidType;
if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks
liquidType = 15;
uint liquidFlagType = 0;
var liquidData = CliDB.LiquidTypeStorage.LookupByKey(liquidType);
if (liquidData != null)
liquidFlagType = liquidData.SoundBank;
if (liquidType != 0 && liquidType < 21 && areaEntry != null)
{
uint overrideLiquid = areaEntry.LiquidTypeID[liquidFlagType];
if (overrideLiquid == 0 && areaEntry.ParentAreaID != 0)
{
var zoneEntry = CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID);
if (zoneEntry != null)
overrideLiquid = zoneEntry.LiquidTypeID[liquidFlagType];
}
var overrideData = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
if (overrideData != null)
{
liquidType = overrideLiquid;
liquidFlagType = overrideData.SoundBank;
}
}
data.LiquidInfo = new();
data.LiquidInfo.level = wmoData.liquidInfo.Value.Level;
data.LiquidInfo.depth_level = wmoData.floorZ;
data.LiquidInfo.entry = liquidType;
data.LiquidInfo.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType);
float delta = wmoData.liquidInfo.Value.Level - z;
if (delta > collisionHeight)
data.LiquidStatus = ZLiquidStatus.UnderWater;
else if (delta > 0.0f)
data.LiquidStatus = ZLiquidStatus.InWater;
else if (delta > -0.1f)
data.LiquidStatus = ZLiquidStatus.WaterWalk;
else
data.LiquidStatus = ZLiquidStatus.AboveWater;
}
// look up liquid data from grid map
if (gmap != null && useGridLiquid)
{
LiquidData gridMapLiquid = new();
ZLiquidStatus gridMapStatus = gmap.GetLiquidStatus(x, y, z, reqLiquidType, gridMapLiquid, collisionHeight);
if (gridMapStatus != ZLiquidStatus.NoWater && (wmoData == null || gridMapLiquid.level > wmoData.floorZ))
{
if (GetId() == 530 && gridMapLiquid.entry == 2)
gridMapLiquid.entry = 15;
data.LiquidInfo = gridMapLiquid;
data.LiquidStatus = gridMapStatus;
}
}
return m_terrain.GetStaticHeight(phaseShift, x, y, z, checkVMap, maxSearchDist);
}
public float GetWaterLevel(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.GetLiquidLevel(x, y);
return 0;
return m_terrain.GetWaterLevel(phaseShift, x, y);
}
public bool IsInWater(PhaseShift phaseShift, float x, float y, float z, LiquidData data)
{
return m_terrain.IsInWater(phaseShift, x, y, z, data);
}
public bool IsUnderWater(PhaseShift phaseShift, float x, float y, float z)
{
return m_terrain.IsUnderWater(phaseShift, x, y, z);
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, float collisionHeight = MapConst.DefaultCollesionHeight)
{
float ground = 0;
return m_terrain.GetWaterOrGroundLevel(phaseShift, x, y, z, ref ground, false, collisionHeight, _dynamicTree);
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, ref float ground, bool swim = false, float collisionHeight = MapConst.DefaultCollesionHeight)
{
return m_terrain.GetWaterOrGroundLevel(phaseShift, x, y, z, ref ground, swim, collisionHeight, _dynamicTree);
}
public bool IsInLineOfSight(PhaseShift phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, LineOfSightChecks checks, ModelIgnoreFlags ignoreFlags)
{
if (checks.HasAnyFlag(LineOfSightChecks.Vmap) && !Global.VMapMgr.IsInLineOfSight(PhasingHandler.GetTerrainMapId(phaseShift, this, x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags))
if (checks.HasAnyFlag(LineOfSightChecks.Vmap) && !Global.VMapMgr.IsInLineOfSight(PhasingHandler.GetTerrainMapId(phaseShift, m_terrain, x1, y1), x1, y1, z1, x2, y2, z2, ignoreFlags))
return false;
if (WorldConfig.GetBoolValue(WorldCfg.CheckGobjectLos) && checks.HasAnyFlag(LineOfSightChecks.Gobject) && !_dynamicTree.IsInLineOfSight(new Vector3(x1, y1, z1), new Vector3(x2, y2, z2), phaseShift))
@@ -2280,19 +1662,9 @@ namespace Game.Maps
return result;
}
public bool IsInWater(PhaseShift phaseShift, float x, float y, float pZ)
{
return Convert.ToBoolean(GetLiquidStatus(phaseShift, x, y, pZ, LiquidHeaderTypeFlags.AllLiquids) & (ZLiquidStatus.InWater | ZLiquidStatus.UnderWater));
}
public bool IsUnderWater(PhaseShift phaseShift, float x, float y, float z)
{
return Convert.ToBoolean(GetLiquidStatus(phaseShift, x, y, z, LiquidHeaderTypeFlags.Water | LiquidHeaderTypeFlags.Ocean) & ZLiquidStatus.UnderWater);
}
public string GetMapName()
{
return i_mapRecord != null ? i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()] : "UNNAMEDMAP";
return i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()];
}
public void SendInitSelf(Player player)
@@ -3779,14 +3151,8 @@ namespace Game.Maps
return i_gridExpiry;
}
public void AddChildTerrainMap(Map map)
{
m_childTerrainMaps.Add(map);
map.m_parentTerrainMap = this;
}
public void UnlinkAllChildTerrainMaps() { m_childTerrainMaps.Clear(); }
public TerrainInfo GetTerrain() { return m_terrain; }
public uint GetInstanceId()
{
return i_InstanceId;
@@ -5254,8 +4620,6 @@ namespace Game.Maps
bool _areaTriggersToMoveLock;
List<AreaTrigger> _areaTriggersToMove = new();
GridMap[][] GridMaps = new GridMap[MapConst.MaxGrids][];
ushort[][] GridMapReference = new ushort[MapConst.MaxGrids][];
DynamicMapTree _dynamicTree = new();
SortedSet<RespawnInfo> _respawnTimes = new(new CompareRespawnInfo());
@@ -5274,12 +4638,10 @@ namespace Game.Maps
List<WorldObject> i_worldObjects = new();
protected List<WorldObject> m_activeNonPlayers = new();
protected List<Player> m_activePlayers = new();
Map m_parentMap; // points to MapInstanced or self (always same map id)
Map m_parentTerrainMap; // points to m_parentMap of MapEntry::ParentMapID
List<Map> m_childTerrainMaps = new(); // contains m_parentMap of maps that have MapEntry::ParentMapID == GetId()
TerrainInfo m_terrain;
SortedMultiMap<long, ScriptAction> m_scriptSchedule = new();
BitSet i_gridFileExists = new(MapConst.MaxGrids * MapConst.MaxGrids); // cache what grids are available for this map (not including parent/child maps)
BitSet marked_cells = new(MapConst.TotalCellsPerMap * MapConst.TotalCellsPerMap);
public Dictionary<ulong, CreatureGroup> CreatureGroupHolder = new();
internal uint i_InstanceId;
-65
View File
@@ -43,11 +43,6 @@ namespace Game.Entities
m_updater = new MapUpdater(WorldConfig.GetIntValue(WorldCfg.Numthreads));
}
public void InitializeParentMapData(MultiMap<uint, uint> mapData)
{
_parentMapData = mapData;
}
public void InitializeVisibilityDistanceInfo()
{
foreach (var pair in i_maps)
@@ -85,13 +80,8 @@ namespace Game.Entities
else
map = new Map(mapEntry.Id, i_gridCleanUpDelay, 0, Difficulty.None);
map.DiscoverGridMapFiles();
i_maps[mapEntry.Id] = map;
foreach (uint childMapId in _parentMapData[mapEntry.Id])
map.AddChildTerrainMap(CreateBaseMap_i(CliDB.MapStorage.LookupByKey(childMapId)));
if (!mapEntry.Instanceable())
{
map.LoadRespawnTimes();
@@ -240,16 +230,6 @@ namespace Game.Entities
i_timer.SetCurrent(0);
}
public bool ExistMapAndVMap(uint mapid, float x, float y)
{
GridCoord p = GridDefines.ComputeGridCoord(x, y);
uint gx = (MapConst.MaxGrids - 1) - p.X_coord;
uint gy = (MapConst.MaxGrids - 1) - p.Y_coord;
return Map.ExistMap(mapid, gx, gy) && Map.ExistVMap(mapid, gx, gy);
}
public bool IsValidMAP(uint mapId)
{
return CliDB.MapStorage.ContainsKey(mapId);
@@ -399,48 +379,6 @@ namespace Game.Entities
{
return i_maps.LookupByKey(mapId);
}
public uint GetAreaId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
Map m = CreateBaseMap(mapid);
return m.GetAreaId(phaseShift, x, y, z);
}
public uint GetAreaId(PhaseShift phaseShift, uint mapid, Position pos)
{
return GetAreaId(phaseShift, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
}
public uint GetAreaId(PhaseShift phaseShift, WorldLocation loc)
{
return GetAreaId(phaseShift, loc.GetMapId(), loc);
}
public uint GetZoneId(PhaseShift phaseShift, uint mapid, Position pos) { return GetZoneId(phaseShift, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public uint GetZoneId(PhaseShift phaseShift, WorldLocation loc) { return GetZoneId(phaseShift, loc.GetMapId(), loc); }
public uint GetZoneId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
Map m = CreateBaseMap(mapid);
return m.GetZoneId(phaseShift, x, y, z);
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, uint mapid, float x, float y, float z)
{
Map m = CreateBaseMap(mapid);
m.GetZoneAndAreaId(phaseShift, out zoneid, out areaid, x, y, z);
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, uint mapid, Position pos)
{
GetZoneAndAreaId(phaseShift, out zoneid, out areaid, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ());
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, WorldLocation loc)
{
GetZoneAndAreaId(phaseShift, out zoneid, out areaid, loc.GetMapId(), loc);
}
public void DoForAllMaps(Action<Map> worker)
{
@@ -494,8 +432,5 @@ namespace Game.Entities
uint _nextInstanceId;
MapUpdater m_updater;
uint _scheduledScripts;
// parent map links
MultiMap<uint, uint> _parentMapData;
}
}
+893
View File
@@ -0,0 +1,893 @@
/*
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
using Framework.Constants;
using Game.Collision;
using Game.DataStorage;
using Game.Entities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace Game.Maps
{
public class TerrainManager : Singleton<TerrainManager>
{
Dictionary<uint, TerrainInfo> _terrainMaps = new();
// parent map links
MultiMap<uint, uint> _parentMapData = new();
TerrainManager() { }
public void InitializeParentMapData(MultiMap<uint, uint> mapData)
{
_parentMapData = mapData;
}
public TerrainInfo LoadTerrain(uint mapId)
{
var entry = CliDB.MapStorage.LookupByKey(mapId);
if (entry == null)
return null;
while (entry.ParentMapID != -1 || entry.CosmeticParentMapID != -1)
{
uint parentMapId = (uint)(entry.ParentMapID != -1 ? entry.ParentMapID : entry.CosmeticParentMapID);
entry = CliDB.MapStorage.LookupByKey(parentMapId);
if (entry == null)
break;
mapId = parentMapId;
}
var terrain = _terrainMaps.LookupByKey(mapId);
if (terrain != null)
return terrain;
TerrainInfo terrainInfo = LoadTerrainImpl(mapId);
_terrainMaps[mapId] = terrainInfo;
return terrainInfo;
}
public void UnloadAll()
{
_terrainMaps.Clear();
}
public void Update(uint diff)
{
// global garbage collection
foreach (var (mapId, terrain) in _terrainMaps)
terrain?.CleanUpGrids(diff);
}
public uint GetAreaId(PhaseShift phaseShift, uint mapid, Position pos) { return GetAreaId(phaseShift, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public uint GetAreaId(PhaseShift phaseShift, WorldLocation loc) { return GetAreaId(phaseShift, loc.GetMapId(), loc); }
public uint GetAreaId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
TerrainInfo terrain = LoadTerrain(mapid);
if (terrain != null)
return terrain.GetAreaId(phaseShift, x, y, z);
return 0;
}
public uint GetZoneId(PhaseShift phaseShift, uint mapid, Position pos) { return GetZoneId(phaseShift, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public uint GetZoneId(PhaseShift phaseShift, WorldLocation loc) { return GetZoneId(phaseShift, loc.GetMapId(), loc); }
public uint GetZoneId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
TerrainInfo terrain = LoadTerrain(mapid);
if (terrain != null)
return terrain.GetZoneId(phaseShift, x, y, z);
return 0;
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, uint mapid, Position pos) { GetZoneAndAreaId(phaseShift, out zoneid, out areaid, mapid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); }
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, WorldLocation loc) { GetZoneAndAreaId(phaseShift, out zoneid, out areaid, loc.GetMapId(), loc); }
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, uint mapid, float x, float y, float z)
{
zoneid = areaid = 0;
TerrainInfo terrain = LoadTerrain(mapid);
if (terrain != null)
terrain.GetZoneAndAreaId(phaseShift, out zoneid, out areaid, x, y, z);
}
TerrainInfo LoadTerrainImpl(uint mapId)
{
TerrainInfo rootTerrain = new TerrainInfo(mapId);
rootTerrain.DiscoverGridMapFiles();
foreach (uint childMapId in _parentMapData[mapId])
rootTerrain.AddChildTerrain(LoadTerrainImpl(childMapId));
return rootTerrain;
}
public static bool ExistMapAndVMap(uint mapid, float x, float y)
{
GridCoord p = GridDefines.ComputeGridCoord(x, y);
int gx = (int)((MapConst.MaxGrids - 1) - p.X_coord);
int gy = (int)((MapConst.MaxGrids - 1) - p.Y_coord);
return TerrainInfo.ExistMap(mapid, gx, gy) && TerrainInfo.ExistVMap(mapid, gx, gy);
}
}
public class TerrainInfo
{
uint _mapId;
TerrainInfo _parentTerrain;
List<TerrainInfo> _childTerrain = new();
object _loadMutex = new();
GridMap[][] _gridMap = new GridMap[MapConst.MaxGrids][];
ushort[][] _referenceCountFromMap = new ushort[MapConst.MaxGrids][];
BitSet _gridFileExists = new(MapConst.MaxGrids * MapConst.MaxGrids); // cache what grids are available for this map (not including parent/child maps)
static TimeSpan CleanupInterval = TimeSpan.FromMinutes(1);
// global garbage collection timer
TimeTracker _cleanupTimer;
public TerrainInfo(uint mapId)
{
_mapId = mapId;
_cleanupTimer = new TimeTracker(RandomHelper.RandTime(CleanupInterval / 2, CleanupInterval));
for (var i = 0; i < MapConst.MaxGrids; ++i)
{
_gridMap[i] = new GridMap[MapConst.MaxGrids];
_referenceCountFromMap[i] = new ushort[MapConst.MaxGrids];
}
}
public string GetMapName()
{
return CliDB.MapStorage.LookupByKey(GetId()).MapName[Global.WorldMgr.GetDefaultDbcLocale()];
}
public void DiscoverGridMapFiles()
{
string tileListName = $"{Global.WorldMgr.GetDataPath()}/maps/{GetId():D4}.tilelist";
// tile list is optional
if (File.Exists(tileListName))
{
using var reader = new BinaryReader(new FileStream(tileListName, FileMode.Open, FileAccess.Read));
var mapMagic = reader.ReadUInt32();
var versionMagic = reader.ReadUInt32();
if (mapMagic == MapConst.MapMagic && versionMagic == MapConst.MapVersionMagic)
{
var build = reader.ReadUInt32();
byte[] tilesData = reader.ReadArray<byte>(MapConst.MaxGrids * MapConst.MaxGrids);
for (uint gx = 0; gx < MapConst.MaxGrids; ++gx)
for (uint gy = 0; gy < MapConst.MaxGrids; ++gy)
_gridFileExists[(int)(gx * MapConst.MaxGrids + gy)] = tilesData[(int)(gx * MapConst.MaxGrids + gy)] == 49; // char of 1
return;
}
}
for (int gx = 0; gx < MapConst.MaxGrids; ++gx)
for (int gy = 0; gy < MapConst.MaxGrids; ++gy)
_gridFileExists[gx * MapConst.MaxGrids + gy] = ExistMap(GetId(), gx, gy, false);
}
public static bool ExistMap(uint mapid, int gx, int gy, bool log = true)
{
string fileName = $"{Global.WorldMgr.GetDataPath()}/maps/{mapid:D4}_{gx:D2}_{gy:D2}.map";
bool ret = false;
if (!File.Exists(fileName))
{
if (log)
{
Log.outError(LogFilter.Maps, $"Map file '{fileName}' does not exist!");
Log.outError(LogFilter.Maps, $"Please place MAP-files (*.map) in the appropriate directory ({Global.WorldMgr.GetDataPath() + "/maps/"}), or correct the DataDir setting in your worldserver.conf file.");
}
}
else
{
using var reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read));
var header = reader.Read<MapFileHeader>();
if (header.mapMagic != MapConst.MapMagic || (header.versionMagic != MapConst.MapVersionMagic && header.versionMagic != MapConst.MapVersionMagic2)) // Hack for some different extractors using v2.0 header
{
if (log)
Log.outError(LogFilter.Maps, $"Map file '{fileName}' is from an incompatible map version ({header.versionMagic}), {MapConst.MapVersionMagic} 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.");
}
else
ret = true;
}
return ret;
}
public static bool ExistVMap(uint mapid, int gx, int gy)
{
if (Global.VMapMgr.IsMapLoadingEnabled())
{
LoadResult result = Global.VMapMgr.ExistsMap(mapid, gx, gy);
string name = VMapManager.GetMapFileName(mapid);//, gx, gy);
switch (result)
{
case LoadResult.Success:
break;
case LoadResult.FileNotFound:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "/vmaps/" + name}' does not exist");
Log.outError(LogFilter.Maps, $"Please place VMAP files (*.vmtree and *.vmtile) in the vmap directory ({Global.WorldMgr.GetDataPath() + "/vmaps/"}), or correct the DataDir setting in your worldserver.conf file.");
return false;
case LoadResult.VersionMismatch:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "/vmaps/" + name}' couldn't be loaded");
Log.outError(LogFilter.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 LoadResult.ReadFromFileFailed:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "/vmaps/" + name}' couldn't be loaded");
Log.outError(LogFilter.Maps, "This is because VMAP files are corrupted, please re-extract the maps with the tools compiled with this module.");
return false;
case LoadResult.DisabledInConfig:
Log.outError(LogFilter.Maps, $"VMap file '{Global.WorldMgr.GetDataPath() + "/vmaps/" + name}' couldn't be loaded");
Log.outError(LogFilter.Maps, "This is because VMAP is disabled in config file.");
return false;
}
}
return true;
}
public bool HasChildTerrainGridFile(uint mapId, int gx, int gy)
{
var childMap = _childTerrain.Find(childTerrain => childTerrain.GetId() == mapId);
return childMap != null && childMap._gridFileExists[gx * MapConst.MaxGrids + gy];
}
public void AddChildTerrain(TerrainInfo childTerrain)
{
childTerrain._parentTerrain = this;
_childTerrain.Add(childTerrain);
}
public void LoadMapAndVMap(int gx, int gy)
{
if (++_referenceCountFromMap[gx][gy] != 1) // check if already loaded
return;
//std::lock_guard < std::mutex > lock (_loadMutex) ;
LoadMapAndVMapImpl(gx, gy);
}
public void LoadMapAndVMapImpl(int gx, int gy)
{
LoadMap(gx, gy);
LoadVMap(gx, gy);
LoadMMap(gx, gy);
foreach (TerrainInfo childTerrain in _childTerrain)
childTerrain.LoadMapAndVMapImpl(gx, gy);
}
public void LoadMap(int gx, int gy)
{
if (_gridMap[gx][gy] != null)
return;
if (!_gridFileExists[gx * MapConst.MaxGrids + gy])
return;
// map file name
string fileName = $"{Global.WorldMgr.GetDataPath()}/maps/{GetId():D4}_{gx:D2}_{gy:D2}.map";
Log.outInfo(LogFilter.Maps, $"Loading map {fileName}");
// loading data
GridMap gridMap = new();
LoadResult gridMapLoadResult = gridMap.LoadData(fileName);
if (gridMapLoadResult == LoadResult.Success)
_gridMap[gx][gy] = gridMap;
else
_gridFileExists[gx * MapConst.MaxGrids + gy] = false;
if (gridMapLoadResult == LoadResult.ReadFromFileFailed)
Log.outError(LogFilter.Maps, $"Error loading map file: {fileName}");
}
public void LoadVMap(int gx, int gy)
{
if (!Global.VMapMgr.IsMapLoadingEnabled())
return;
// x and y are swapped !!
LoadResult vmapLoadResult = Global.VMapMgr.LoadMap(GetId(), gx, gy);
switch (vmapLoadResult)
{
case LoadResult.Success:
Log.outDebug(LogFilter.Maps, $"VMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
break;
default:
Log.outError(LogFilter.Maps, $"Could not load VMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
break;
case LoadResult.DisabledInConfig:
Log.outDebug(LogFilter.Maps, $"Ignored VMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (vmap rep.: x:{gx}, y:{gy})");
break;
}
}
public void LoadMMap(int gx, int gy)
{
if (!Global.DisableMgr.IsPathfindingEnabled(GetId()))
return;
bool mmapLoadResult = Global.MMapMgr.LoadMap(Global.WorldMgr.GetDataPath(), GetId(), gx, gy);
if (mmapLoadResult)
Log.outDebug(LogFilter.Maps, $"MMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy})");
else
Log.outWarn(LogFilter.Maps, $"Could not load MMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy})");
}
public void UnloadMap(int gx, int gy)
{
--_referenceCountFromMap[gx][gy];
// unload later
}
public void UnloadMapImpl(int gx, int gy)
{
_gridMap[gx][gy] = null;
Global.VMapMgr.UnloadMap(GetId(), gx, gy);
Global.MMapMgr.UnloadMap(GetId(), gx, gy);
foreach (var childTerrain in _childTerrain)
childTerrain.UnloadMapImpl(gx, gy);
}
public GridMap GetGrid(uint mapId, float x, float y, bool loadIfMissing = true)
{
// half opt method
int gx = (int)(MapConst.CenterGridId - x / MapConst.SizeofGrids); //grid x
int gy = (int)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y
// ensure GridMap is loaded
if (_gridMap[gx][gy] == null && loadIfMissing)
{
//std::lock_guard < std::mutex > lock (_loadMutex) ;
LoadMapAndVMapImpl(gx, gy);
}
GridMap grid = _gridMap[gx][gy];
if (mapId != GetId())
{
var childMap = _childTerrain.Find(childTerrain => childTerrain.GetId() == mapId);
if (childMap != null && childMap._gridMap[gx][gy] != null)
grid = childMap.GetGrid(mapId, x, y, false);
}
return grid;
}
public void CleanUpGrids(uint diff)
{
_cleanupTimer.Update(diff);
if (!_cleanupTimer.Passed())
return;
// delete those GridMap objects which have refcount = 0
for (int x = 0; x < MapConst.MaxGrids; ++x)
for (int y = 0; y < MapConst.MaxGrids; ++y)
if (_gridMap[x][y] != null && _referenceCountFromMap[x][y] == 0)
UnloadMapImpl(x, y);
_cleanupTimer.Reset(CleanupInterval);
}
public static bool IsInWMOInterior(uint mogpFlags)
{
return (mogpFlags & 0x2000) != 0;
}
public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, LiquidHeaderTypeFlags reqLiquidType = LiquidHeaderTypeFlags.AllLiquids, float collisionHeight = MapConst.DefaultCollesionHeight, DynamicMapTree dynamicMapTree = null)
{
AreaAndLiquidData dynData = null;
AreaAndLiquidData wmoData = null;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
GridMap gmap = GetGrid(terrainMapId, x, y);
AreaAndLiquidData vmapData = Global.VMapMgr.GetAreaAndLiquidData(terrainMapId, x, y, z, (byte)reqLiquidType);
if (dynamicMapTree != null)
dynData = dynamicMapTree.GetAreaAndLiquidData(x, y, z, phaseShift, (byte)reqLiquidType);
uint gridAreaId = 0;
float gridMapHeight = MapConst.InvalidHeight;
if (gmap != null)
{
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 = MapConst.InvalidHeight;
if (gridMapHeight > MapConst.InvalidHeight && MathFunctions.fuzzyGe(z, gridMapHeight - MapConst.GroundHeightTolerance))
data.FloorZ = gridMapHeight;
if (vmapData.floorZ > MapConst.InvalidHeight &&
MathFunctions.fuzzyGe(z, vmapData.floorZ - MapConst.GroundHeightTolerance) &&
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || 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 > MapConst.InvalidHeight &&
MathFunctions.fuzzyGe(z, dynData.floorZ - MapConst.GroundHeightTolerance) &&
(MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || dynData.floorZ > gridMapHeight) &&
(MathFunctions.fuzzyLt(z, vmapData.floorZ - MapConst.GroundHeightTolerance) || dynData.floorZ > vmapData.floorZ))
{
data.FloorZ = dynData.floorZ;
wmoData = dynData;
}
if (wmoData != null)
{
if (wmoData.areaInfo.HasValue)
{
data.areaInfo = new(wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.GroupId, wmoData.areaInfo.Value.MogpFlags);
// wmo found
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(wmoData.areaInfo.Value.RootId, wmoData.areaInfo.Value.AdtId, wmoData.areaInfo.Value.GroupId);
data.outdoors = (wmoData.areaInfo.Value.MogpFlags & 0x8) != 0;
if (wmoEntry != null)
{
data.AreaId = wmoEntry.AreaTableID;
if ((wmoEntry.Flags & 4) != 0)
data.outdoors = true;
else if ((wmoEntry.Flags & 2) != 0)
data.outdoors = false;
}
if (data.AreaId == 0)
data.AreaId = gridAreaId;
useGridLiquid = !IsInWMOInterior(wmoData.areaInfo.Value.MogpFlags);
}
}
else
{
data.outdoors = true;
data.AreaId = gridAreaId;
var areaEntry1 = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
if (areaEntry1 != null)
data.outdoors = ((AreaFlags)areaEntry1.Flags[0] & (AreaFlags.Inside | AreaFlags.Outside)) != AreaFlags.Inside;
}
if (data.AreaId == 0)
data.AreaId = CliDB.MapStorage.LookupByKey(GetId()).AreaTableID;
var areaEntry = CliDB.AreaTableStorage.LookupByKey(data.AreaId);
// liquid processing
data.LiquidStatus = ZLiquidStatus.NoWater;
if (wmoData != null && wmoData.liquidInfo.HasValue && wmoData.liquidInfo.Value.Level > wmoData.floorZ)
{
uint liquidType = wmoData.liquidInfo.Value.LiquidType;
if (GetId() == 530 && liquidType == 2) // gotta love hacks
liquidType = 15;
uint liquidFlagType = 0;
var liquidData = CliDB.LiquidTypeStorage.LookupByKey(liquidType);
if (liquidData != null)
liquidFlagType = liquidData.SoundBank;
if (liquidType != 0 && liquidType < 21 && areaEntry != null)
{
uint overrideLiquid = areaEntry.LiquidTypeID[liquidFlagType];
if (overrideLiquid == 0 && areaEntry.ParentAreaID != 0)
{
var zoneEntry = CliDB.AreaTableStorage.LookupByKey(areaEntry.ParentAreaID);
if (zoneEntry != null)
overrideLiquid = zoneEntry.LiquidTypeID[liquidFlagType];
}
var overrideData = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
if (overrideData != null)
{
liquidType = overrideLiquid;
liquidFlagType = overrideData.SoundBank;
}
}
data.LiquidInfo = new();
data.LiquidInfo.level = wmoData.liquidInfo.Value.Level;
data.LiquidInfo.depth_level = wmoData.floorZ;
data.LiquidInfo.entry = liquidType;
data.LiquidInfo.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType);
float delta = wmoData.liquidInfo.Value.Level - z;
if (delta > collisionHeight)
data.LiquidStatus = ZLiquidStatus.UnderWater;
else if (delta > 0.0f)
data.LiquidStatus = ZLiquidStatus.InWater;
else if (delta > -0.1f)
data.LiquidStatus = ZLiquidStatus.WaterWalk;
else
data.LiquidStatus = ZLiquidStatus.AboveWater;
}
// look up liquid data from grid map
if (gmap != null && useGridLiquid)
{
LiquidData gridMapLiquid = new();
ZLiquidStatus gridMapStatus = gmap.GetLiquidStatus(x, y, z, reqLiquidType, gridMapLiquid, collisionHeight);
if (gridMapStatus != ZLiquidStatus.NoWater && (wmoData == null || gridMapLiquid.level > wmoData.floorZ))
{
if (GetId() == 530 && gridMapLiquid.entry == 2)
gridMapLiquid.entry = 15;
data.LiquidInfo = gridMapLiquid;
data.LiquidStatus = gridMapStatus;
}
}
}
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags ReqLiquidType, LiquidData data = null, float collisionHeight = MapConst.DefaultCollesionHeight)
{
ZLiquidStatus result = ZLiquidStatus.NoWater;
float liquid_level = MapConst.InvalidHeight;
float ground_level = MapConst.InvalidHeight;
uint liquid_type = 0;
uint mogpFlags = 0;
bool useGridLiquid = true;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
if (Global.VMapMgr.GetLiquidLevel(terrainMapId, x, y, z, (byte)ReqLiquidType, ref liquid_level, ref ground_level, ref liquid_type, ref mogpFlags))
{
useGridLiquid = !IsInWMOInterior(mogpFlags);
Log.outDebug(LogFilter.Maps, $"GetLiquidStatus(): vmap liquid level: {liquid_level} ground: {ground_level} type: {liquid_type}");
// Check water level and ground level
if (liquid_level > ground_level && MathFunctions.fuzzyGe(z, ground_level - MapConst.GroundHeightTolerance))
{
// All ok in water . store data
if (data != null)
{
// hardcoded in client like this
if (GetId() == 530 && liquid_type == 2)
liquid_type = 15;
uint liquidFlagType = 0;
var liq = CliDB.LiquidTypeStorage.LookupByKey(liquid_type);
if (liq != null)
liquidFlagType = liq.SoundBank;
if (liquid_type != 0 && liquid_type < 21)
{
var area = CliDB.AreaTableStorage.LookupByKey(GetAreaId(phaseShift, x, y, z));
if (area != null)
{
uint overrideLiquid = area.LiquidTypeID[liquidFlagType];
if (overrideLiquid == 0 && area.ParentAreaID != 0)
{
area = CliDB.AreaTableStorage.LookupByKey(area.ParentAreaID);
if (area != null)
overrideLiquid = area.LiquidTypeID[liquidFlagType];
}
var liq1 = CliDB.LiquidTypeStorage.LookupByKey(overrideLiquid);
if (liq1 != null)
{
liquid_type = overrideLiquid;
liquidFlagType = liq1.SoundBank;
}
}
}
data.level = liquid_level;
data.depth_level = ground_level;
data.entry = liquid_type;
data.type_flags = (LiquidHeaderTypeFlags)(1 << (int)liquidFlagType);
}
float delta = liquid_level - z;
// Get position delta
if (delta > collisionHeight) // Under water
return ZLiquidStatus.UnderWater;
if (delta > 0.0f) // In water
return ZLiquidStatus.InWater;
if (delta > -0.1f) // Walk on water
return ZLiquidStatus.WaterWalk;
result = ZLiquidStatus.AboveWater;
}
}
if (useGridLiquid)
{
GridMap gmap = GetGrid(terrainMapId, x, y);
if (gmap != null)
{
LiquidData map_data = new();
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 != ZLiquidStatus.NoWater && (map_data.level > ground_level))
{
if (data != null)
{
// hardcoded in client like this
if (GetId() == 530 && map_data.entry == 2)
map_data.entry = 15;
data = map_data;
}
return map_result;
}
}
}
return result;
}
public bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint mogpflags, out int adtId, out int rootId, out int groupId, DynamicMapTree dynamicMapTree = null)
{
mogpflags = 0;
adtId = 0;
rootId = 0;
groupId = 0;
float vmap_z = z;
float dynamic_z = z;
float check_z = z;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
uint vflags;
int vadtId;
int vrootId;
int vgroupId;
uint dflags = 0;
int dadtId = 0;
int drootId = 0;
int dgroupId = 0;
bool hasVmapAreaInfo = Global.VMapMgr.GetAreaInfo(terrainMapId, x, y, ref vmap_z, out vflags, out vadtId, out vrootId, out vgroupId);
bool hasDynamicAreaInfo = dynamicMapTree != null ? dynamicMapTree.GetAreaInfo(x, y, ref dynamic_z, phaseShift, out dflags, out dadtId, out drootId, out dgroupId) : false;
if (hasVmapAreaInfo)
{
if (hasDynamicAreaInfo && dynamic_z > vmap_z)
{
check_z = dynamic_z;
mogpflags = dflags;
adtId = dadtId;
rootId = drootId;
groupId = dgroupId;
}
else
{
check_z = vmap_z;
mogpflags = vflags;
adtId = vadtId;
rootId = vrootId;
groupId = vgroupId;
}
}
else if (hasDynamicAreaInfo)
{
check_z = dynamic_z;
mogpflags = dflags;
adtId = dadtId;
rootId = drootId;
groupId = dgroupId;
}
if (hasVmapAreaInfo || hasDynamicAreaInfo)
{
// check if there's terrain between player height and object height
GridMap gmap = GetGrid(terrainMapId, x, y);
if (gmap != null)
{
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;
}
public uint GetAreaId(PhaseShift phaseShift, Position pos, DynamicMapTree dynamicMapTree = null) { return GetAreaId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), dynamicMapTree); }
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z, DynamicMapTree dynamicMapTree = null)
{
uint mogpFlags;
int adtId, rootId, groupId;
float vmapZ = z;
bool hasVmapArea = GetAreaInfo(phaseShift, x, y, vmapZ, out mogpFlags, out adtId, out rootId, out groupId, dynamicMapTree);
uint gridAreaId = 0;
float gridMapHeight = MapConst.InvalidHeight;
GridMap gmap = GetGrid(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
{
gridAreaId = gmap.GetArea(x, y);
gridMapHeight = gmap.GetHeight(x, y);
}
uint areaId = 0;
// floor is the height we are closer to (but only if above)
if (hasVmapArea && MathFunctions.fuzzyGe(z, vmapZ - MapConst.GroundHeightTolerance) && (MathFunctions.fuzzyLt(z, gridMapHeight - MapConst.GroundHeightTolerance) || vmapZ > gridMapHeight))
{
// wmo found
var wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
if (wmoEntry != null)
areaId = wmoEntry.AreaTableID;
if (areaId == 0)
areaId = gridAreaId;
}
else
areaId = gridAreaId;
if (areaId == 0)
areaId = CliDB.MapStorage.LookupByKey(GetId()).AreaTableID;
return areaId;
}
public uint GetZoneId(PhaseShift phaseShift, Position pos, DynamicMapTree dynamicMapTree = null) { return GetZoneId(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), dynamicMapTree); }
public uint GetZoneId(PhaseShift phaseShift, float x, float y, float z, DynamicMapTree dynamicMapTree = null)
{
uint areaId = GetAreaId(phaseShift, x, y, z, dynamicMapTree);
var area = CliDB.AreaTableStorage.LookupByKey(areaId);
if (area != null)
if (area.ParentAreaID != 0)
return area.ParentAreaID;
return areaId;
}
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, Position pos, DynamicMapTree dynamicMapTree = null) { GetZoneAndAreaId(phaseShift, out zoneid, out areaid, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), dynamicMapTree); }
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, float x, float y, float z, DynamicMapTree dynamicMapTree = null)
{
areaid = zoneid = GetAreaId(phaseShift, x, y, z, dynamicMapTree);
var area = CliDB.AreaTableStorage.LookupByKey(areaid);
if (area != null)
if (area.ParentAreaID != 0)
zoneid = area.ParentAreaID;
}
public float GetMinHeight(PhaseShift phaseShift, float x, float y)
{
GridMap grid = GetGrid(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (grid != null)
return grid.GetMinHeight(x, y);
return -500.0f;
}
public float GetGridHeight(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGrid(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.GetHeight(x, y);
return MapConst.VMAPInvalidHeightValue;
}
public float GetStaticHeight(PhaseShift phaseShift, Position pos, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch) { return GetStaticHeight(phaseShift, pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), checkVMap, maxSearchDist); }
public float GetStaticHeight(PhaseShift phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
{
// find raw .map surface under Z coordinates
float mapHeight = MapConst.VMAPInvalidHeightValue;
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
float gridHeight = GetGridHeight(phaseShift, x, y);
if (MathFunctions.fuzzyGe(z, gridHeight - MapConst.GroundHeightTolerance))
mapHeight = gridHeight;
float vmapHeight = MapConst.VMAPInvalidHeightValue;
if (checkVMap)
{
if (Global.VMapMgr.IsHeightCalcEnabled())
vmapHeight = Global.VMapMgr.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 > MapConst.InvalidHeight)
{
if (mapHeight > MapConst.InvalidHeight)
{
// 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 || Math.Abs(mapHeight - z) > Math.Abs(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
}
public float GetWaterLevel(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGrid(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.GetLiquidLevel(x, y);
else
return 0;
}
public bool IsInWater(PhaseShift phaseShift, float x, float y, float pZ, LiquidData data = null)
{
LiquidData liquid_status = new();
LiquidData liquid_ptr = data != null ? data : liquid_status;
return (GetLiquidStatus(phaseShift, x, y, pZ, LiquidHeaderTypeFlags.AllLiquids, liquid_ptr) & (ZLiquidStatus.InWater | ZLiquidStatus.UnderWater)) != 0;
}
public bool IsUnderWater(PhaseShift phaseShift, float x, float y, float z)
{
return (GetLiquidStatus(phaseShift, x, y, z, LiquidHeaderTypeFlags.Water | LiquidHeaderTypeFlags.Ocean) & ZLiquidStatus.UnderWater) != 0;
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, ref float ground, bool swim = false, float collisionHeight = MapConst.DefaultCollesionHeight, DynamicMapTree dynamicMapTree = null)
{
if (GetGrid(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y) != null)
{
// we need ground level (including grid height version) for proper return water level in point
float ground_z = GetStaticHeight(phaseShift, x, y, z + MapConst.ZOffsetFindHeight, true, 50.0f);
if (dynamicMapTree != null)
ground_z = Math.Max(ground_z, dynamicMapTree.GetHeight(x, y, z + MapConst.ZOffsetFindHeight, 50.0f, phaseShift));
ground = ground_z;
LiquidData liquid_status = new();
ZLiquidStatus res = GetLiquidStatus(phaseShift, x, y, ground_z, LiquidHeaderTypeFlags.AllLiquids, liquid_status, collisionHeight);
switch (res)
{
case ZLiquidStatus.AboveWater:
return Math.Max(liquid_status.level, ground_z);
case ZLiquidStatus.NoWater:
return ground_z;
default:
return liquid_status.level;
}
}
return MapConst.VMAPInvalidHeightValue;
}
public uint GetId() { return _mapId; }
}
}
@@ -38,7 +38,7 @@ namespace Game.Movement
_navMeshQuery = null;
Log.outDebug(LogFilter.Maps, "PathGenerator:PathGenerator for {0}", _source.GetGUID().ToString());
uint mapId = PhasingHandler.GetTerrainMapId(_source.GetPhaseShift(), _source.GetMap(), _source.GetPositionX(), _source.GetPositionY());
uint mapId = PhasingHandler.GetTerrainMapId(_source.GetPhaseShift(), _source.GetMap().GetTerrain(), _source.GetPositionX(), _source.GetPositionY());
if (Global.DisableMgr.IsPathfindingEnabled(_source.GetMapId()))
{
_navMesh = Global.MMapMgr.GetNavMesh(mapId);
@@ -904,8 +904,8 @@ namespace Game.Movement
NavTerrainFlag GetNavTerrain(float x, float y, float z)
{
LiquidData data;
ZLiquidStatus liquidStatus = _source.GetMap().GetLiquidStatus(_source.GetPhaseShift(), x, y, z, LiquidHeaderTypeFlags.AllLiquids, out data, _source.GetCollisionHeight());
LiquidData data = new();
ZLiquidStatus liquidStatus = _source.GetMap().GetLiquidStatus(_source.GetPhaseShift(), x, y, z, LiquidHeaderTypeFlags.AllLiquids, data, _source.GetCollisionHeight());
if (liquidStatus == ZLiquidStatus.NoWater)
return NavTerrainFlag.Ground;
+7 -7
View File
@@ -552,23 +552,23 @@ namespace Game
return obj.GetPhaseShift().CanSee(phaseShift);
}
public static uint GetTerrainMapId(PhaseShift phaseShift, Map map, float x, float y)
public static uint GetTerrainMapId(PhaseShift phaseShift, TerrainInfo terrain, float x, float y)
{
if (phaseShift.VisibleMapIds.Empty())
return map.GetId();
return terrain.GetId();
if (phaseShift.VisibleMapIds.Count == 1)
return phaseShift.VisibleMapIds.First().Key;
GridCoord gridCoord = GridDefines.ComputeGridCoord(x, y);
uint gx = ((MapConst.MaxGrids - 1) - gridCoord.X_coord);
uint gy = ((MapConst.MaxGrids - 1) - gridCoord.Y_coord);
int gx = (int)((MapConst.MaxGrids - 1) - gridCoord.X_coord);
int gy = (int)((MapConst.MaxGrids - 1) - gridCoord.Y_coord);
foreach (var visibleMap in phaseShift.VisibleMapIds)
if (map.HasChildMapGridFile(visibleMap.Key, gx, gy))
if (terrain.HasChildTerrainGridFile(visibleMap.Key, gx, gy))
return visibleMap.Key;
return map.GetId();
return terrain.GetId();
}
public static void SetAlwaysVisible(WorldObject obj, bool apply, bool updateVisibility)
@@ -705,7 +705,7 @@ namespace Game
{
if (!summonGuid.IsEmpty())
{
Creature summon = unit.GetMap().GetCreature(summonGuid);
Creature summon = ObjectAccessor.GetCreature(unit, summonGuid);
if (summon != null)
if (_visited.Add(summon))
func(summon);
-6
View File
@@ -205,12 +205,6 @@ namespace Game.Scripting
// Called just before the map is destroyed.
public virtual void OnDestroy(T map) { }
// Called when a grid map is loaded.
public virtual void OnLoadGridMap(T map, GridMap gmap, uint gx, uint gy) { }
// Called when a grid map is unloaded.
public virtual void OnUnloadGridMap(T map, GridMap gmap, uint gx, uint gy) { }
// Called when a player enters the map.
public virtual void OnPlayerEnter(T map, Player player) { }
-31
View File
@@ -564,37 +564,6 @@ namespace Game.Scripting
if (record != null && record.IsBattleground())
ForEach<BattlegroundMapScript>(p => p.OnDestroy(map.ToBattlegroundMap()));
}
public void OnLoadGridMap(Map map, GridMap gmap, uint gx, uint gy)
{
Cypher.Assert(map != null);
Cypher.Assert(gmap != null);
var record = map.GetEntry();
if (record != null && record.IsWorldMap())
ForEach<WorldMapScript>(p => p.OnLoadGridMap(map, gmap, gx, gy));
if (record != null && record.IsDungeon())
ForEach<InstanceMapScript>(p => p.OnLoadGridMap(map.ToInstanceMap(), gmap, gx, gy));
if (record != null && record.IsBattleground())
ForEach<BattlegroundMapScript>(p => p.OnLoadGridMap(map.ToBattlegroundMap(), gmap, gx, gy));
}
public void OnUnloadGridMap(Map map, GridMap gmap, uint gx, uint gy)
{
Cypher.Assert(map != null);
Cypher.Assert(gmap != null);
var record = map.GetEntry();
if (record != null && record.IsWorldMap())
ForEach<WorldMapScript>(p => p.OnUnloadGridMap(map, gmap, gx, gy));
if (record != null && record.IsDungeon())
ForEach<InstanceMapScript>(p => p.OnUnloadGridMap(map.ToInstanceMap(), gmap, gx, gy));
if (record != null && record.IsBattleground())
ForEach<BattlegroundMapScript>(p => p.OnUnloadGridMap(map.ToBattlegroundMap(), gmap, gx, gy));
}
public void OnPlayerEnterMap(Map map, Player player)
{
Cypher.Assert(map != null);
+2 -2
View File
@@ -941,8 +941,8 @@ namespace Game.Spells
float ground = m_caster.GetMapHeight(x, y, z);
float liquidLevel = MapConst.VMAPInvalidHeightValue;
LiquidData liquidData;
if (m_caster.GetMap().GetLiquidStatus(m_caster.GetPhaseShift(), x, y, z, LiquidHeaderTypeFlags.AllLiquids, out liquidData, m_caster.GetCollisionHeight()) != 0)
LiquidData liquidData = new();
if (m_caster.GetMap().GetLiquidStatus(m_caster.GetPhaseShift(), x, y, z, LiquidHeaderTypeFlags.AllLiquids, liquidData, m_caster.GetCollisionHeight()) != 0)
liquidLevel = liquidData.level;
if (liquidLevel <= ground) // When there is no liquid Map.GetWaterOrGroundLevel returns ground level
+7 -5
View File
@@ -404,10 +404,10 @@ namespace Game
Global.ObjectMgr.SetHighestGuids();
if (!Global.MapMgr.ExistMapAndVMap(0, -6240.32f, 331.033f) || !Global.MapMgr.ExistMapAndVMap(0, -8949.95f, -132.493f)
|| !Global.MapMgr.ExistMapAndVMap(1, -618.518f, -4251.67f) || !Global.MapMgr.ExistMapAndVMap(0, 1676.35f, 1677.45f)
|| !Global.MapMgr.ExistMapAndVMap(1, 10311.3f, 832.463f) || !Global.MapMgr.ExistMapAndVMap(1, -2917.58f, -257.98f)
|| (WorldConfig.GetIntValue(WorldCfg.Expansion) != 0 && (!Global.MapMgr.ExistMapAndVMap(530, 10349.6f, -6357.29f) || !Global.MapMgr.ExistMapAndVMap(530, -3961.64f, -13931.2f))))
if (!TerrainManager.ExistMapAndVMap(0, -6240.32f, 331.033f) || !TerrainManager.ExistMapAndVMap(0, -8949.95f, -132.493f)
|| !TerrainManager.ExistMapAndVMap(1, -618.518f, -4251.67f) || !TerrainManager.ExistMapAndVMap(0, 1676.35f, 1677.45f)
|| !TerrainManager.ExistMapAndVMap(1, 10311.3f, 832.463f) || !TerrainManager.ExistMapAndVMap(1, -2917.58f, -257.98f)
|| (WorldConfig.GetIntValue(WorldCfg.Expansion) != 0 && (!TerrainManager.ExistMapAndVMap(530, 10349.6f, -6357.29f) || !TerrainManager.ExistMapAndVMap(530, -3961.64f, -13931.2f))))
{
Log.outError(LogFilter.ServerLoading, "Unable to load critical files - server shutting down !!!");
Environment.Exit(1);
@@ -467,7 +467,7 @@ namespace Game
mapData.Add((uint)mapEntry.CosmeticParentMapID, mapEntry.Id);
}
Global.MapMgr.InitializeParentMapData(mapData);
Global.TerrainMgr.InitializeParentMapData(mapData);
Global.VMapMgr.Initialize(mapData);
Global.MMapMgr.Initialize(mapData);
@@ -1441,6 +1441,8 @@ namespace Game
Global.MapMgr.Update(diff);
_worldUpdateTime.RecordUpdateTimeDuration("UpdateMapMgr");
Global.TerrainMgr.Update(diff);
if (WorldConfig.GetBoolValue(WorldCfg.AutoBroadcast))
{
if (m_timers[WorldTimers.AutoBroadcast].Passed())
+2 -2
View File
@@ -591,8 +591,8 @@ namespace Scripts.Spells.Generic
{
Unit caster = GetCaster();
Position summonPos = caster.GetPosition();
LiquidData liquidStatus;
if (caster.GetMap().GetLiquidStatus(caster.GetPhaseShift(), caster.GetPositionX(), caster.GetPositionY(), caster.GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, out liquidStatus, caster.GetCollisionHeight()) != ZLiquidStatus.NoWater)
LiquidData liquidStatus = new();
if (caster.GetMap().GetLiquidStatus(caster.GetPhaseShift(), caster.GetPositionX(), caster.GetPositionY(), caster.GetPositionZ(), LiquidHeaderTypeFlags.AllLiquids, liquidStatus, caster.GetCollisionHeight()) != ZLiquidStatus.NoWater)
summonPos.posZ = liquidStatus.level;
dest.Relocate(summonPos);
}
+1
View File
@@ -121,6 +121,7 @@ namespace WorldServer
WorldSocketMgr.StopNetwork();
Global.MapMgr.UnloadAll(); // unload all grids (including locked in memory)
Global.TerrainMgr.UnloadAll();
Global.ScriptMgr.Unload();
// set server offline