Core/Maps: Move terrain data handling out of Map class
Port From (https://github.com/TrinityCore/TrinityCore/commit/16a06346aea16ffd6ee84081cedfdb0c75ac0b38)
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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; } }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
+73
-711
@@ -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;
|
||||
@@ -1750,96 +1531,59 @@ namespace Game.Maps
|
||||
_corpseBones.Clear();
|
||||
}
|
||||
|
||||
GridMap GetGridMap(uint mapId, float x, float y)
|
||||
public static bool IsInWMOInterior(uint mogpFlags)
|
||||
{
|
||||
// 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;
|
||||
return (mogpFlags & 0x2000) != 0;
|
||||
}
|
||||
|
||||
public bool HasChildMapGridFile(uint mapId, uint gx, uint gy)
|
||||
public void GetFullTerrainStatusForPosition(PhaseShift phaseShift, float x, float y, float z, PositionFullTerrainStatus data, 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)];
|
||||
m_terrain.GetFullTerrainStatusForPosition(phaseShift, x, y, z, data, reqLiquidType, collisionHeight, _dynamicTree);
|
||||
}
|
||||
|
||||
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, float collisionHeight = MapConst.DefaultCollesionHeight)
|
||||
{
|
||||
float ground = 0f;
|
||||
return GetWaterOrGroundLevel(phaseShift, x, y, z, ref ground);
|
||||
return m_terrain.GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, null, collisionHeight);
|
||||
}
|
||||
|
||||
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, ref float ground, bool swim = false, float collisionHeight = MapConst.DefaultCollesionHeight)
|
||||
public ZLiquidStatus GetLiquidStatus(PhaseShift phaseShift, float x, float y, float z, LiquidHeaderTypeFlags reqLiquidType, LiquidData data, float collisionHeight = MapConst.DefaultCollesionHeight)
|
||||
{
|
||||
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.GetLiquidStatus(phaseShift, x, y, z, reqLiquidType, data, collisionHeight);
|
||||
}
|
||||
|
||||
public float GetStaticHeight(PhaseShift phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
|
||||
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint mogpflags, out int adtId, out int rootId, out int groupId)
|
||||
{
|
||||
// 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.GetAreaInfo(phaseShift, x, y, z, out mogpflags, out adtId, out rootId, out groupId, _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, Position pos)
|
||||
{
|
||||
return m_terrain.GetAreaId(phaseShift, pos.posX, pos.posY, pos.posZ, _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 GetAreaId(PhaseShift phaseShift, float x, float y, float z)
|
||||
{
|
||||
return m_terrain.GetAreaId(phaseShift, x, y, z, _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, Position pos)
|
||||
{
|
||||
return m_terrain.GetZoneId(phaseShift, pos.posX, pos.posY, pos.posZ, _dynamicTree);
|
||||
}
|
||||
|
||||
return mapHeight; // better use .map surface height
|
||||
}
|
||||
public uint GetZoneId(PhaseShift phaseShift, float x, float y, float z)
|
||||
{
|
||||
return m_terrain.GetZoneId(phaseShift, x, y, z, _dynamicTree);
|
||||
}
|
||||
|
||||
return vmapHeight; // we have only vmapHeight (if have)
|
||||
}
|
||||
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 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,13 +3151,7 @@ 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()
|
||||
{
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -400,48 +380,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)
|
||||
{
|
||||
lock (_mapsLock)
|
||||
@@ -494,8 +432,5 @@ namespace Game.Entities
|
||||
uint _nextInstanceId;
|
||||
MapUpdater m_updater;
|
||||
uint _scheduledScripts;
|
||||
|
||||
// parent map links
|
||||
MultiMap<uint, uint> _parentMapData;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user