Core/Entities: Phasing rewrite

This commit is contained in:
hondacrx
2018-03-28 11:09:30 -04:00
parent caad52f636
commit fa35d60f60
72 changed files with 2254 additions and 1146 deletions
+7 -2
View File
@@ -43,6 +43,7 @@ namespace Game.Maps
if (!File.Exists(filename))
return true;
_fileExists = true;
using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
{
mapFileHeader header = reader.ReadStruct<mapFileHeader>();
@@ -72,6 +73,7 @@ namespace Game.Maps
_liquidFlags = null;
_liquidMap = null;
_gridGetHeight = getHeightFromFlat;
_fileExists = false;
}
void LoadAreaData(BinaryReader reader, uint offset)
@@ -435,8 +437,8 @@ namespace Game.Maps
};
Cell cell = new Cell(x, y);
float gx = x - (cell.GetGridX() - MapConst.CenterGridId + 1) *MapConst.SizeofGrids;
float gy = y - (cell.GetGridY() - MapConst.CenterGridId + 1) *MapConst.SizeofGrids;
float gx = x - (cell.GetGridX() - MapConst.CenterGridId + 1) * MapConst.SizeofGrids;
float gy = y - (cell.GetGridY() - MapConst.CenterGridId + 1) * MapConst.SizeofGrids;
uint quarterIndex = 0;
if (cell.GetCellY() < MapConst.MaxCells / 2)
@@ -595,6 +597,8 @@ namespace Game.Maps
public float getHeight(float x, float y) { return _gridGetHeight(x, y); }
public bool fileExists() { return _fileExists; }
#region Fields
delegate float GetHeight(float x, float y);
@@ -627,6 +631,7 @@ namespace Game.Maps
byte _liquidOffY;
byte _liquidWidth;
byte _liquidHeight;
bool _fileExists;
#endregion
}
+1 -1
View File
@@ -727,7 +727,7 @@ namespace Game.Maps
{
var players = instance.GetPlayers();
foreach (var player in players)
player.SendUpdatePhasing();
PhasingHandler.SendToPlayer(player);
}
public void UpdateCombatResurrection(uint diff)
+89 -26
View File
@@ -34,19 +34,27 @@ namespace Game
const string MAP_FILE_NAME_FORMAT = "{0}/mmaps/{1:D4}.mmap";
const string TILE_FILE_NAME_FORMAT = "{0}/mmaps/{1:D4}{2:D2}{3:D2}.mmtile";
public void Initialize(MultiMap<uint, uint> mapData)
{
childMapData = mapData;
foreach (var pair in mapData)
parentMapData[pair.Value] = pair.Key;
}
MMapData GetMMapData(uint mapId)
{
return loadedMMaps.LookupByKey(mapId);
}
bool loadMapData(uint mapId)
bool loadMapData(string basePath, uint mapId)
{
// we already have this map loaded?
if (loadedMMaps.ContainsKey(mapId) && loadedMMaps[mapId] != null)
return true;
// load and init dtNavMesh - read parameters from file
string filename = string.Format(MAP_FILE_NAME_FORMAT, Global.WorldMgr.GetDataPath(), mapId);
string filename = string.Format(MAP_FILE_NAME_FORMAT, basePath, mapId);
if (!File.Exists(filename))
{
Log.outError(LogFilter.Maps, "Could not open mmap file {0}", filename);
@@ -80,15 +88,30 @@ namespace Game
}
}
uint packTileID(int x, int y)
uint packTileID(uint x, uint y)
{
return (uint)(x << 16 | y);
return (x << 16 | y);
}
public bool loadMap(uint mapId, int x, int y)
public bool loadMap(string basePath, uint mapId, uint x, uint y)
{
// make sure the mmap is loaded and ready to load tiles
if (!loadMapData(mapId))
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)
{
// make sure the mmap is loaded and ready to load tiles
if (!loadMapData(basePath, mapId))
return false;
// get this mmap data
@@ -101,14 +124,20 @@ namespace Game
return false;
// load this tile . mmaps/MMMXXYY.mmtile
string filename = string.Format(TILE_FILE_NAME_FORMAT, Global.WorldMgr.GetDataPath(), mapId, x, y);
if (!File.Exists(filename))
string fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, mapId, x, y);
if (!File.Exists(fileName))
{
Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", filename);
if (parentMapData.ContainsKey(mapId))
fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, parentMapData[mapId], x, y);
}
if (!File.Exists(fileName))
{
Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", fileName);
return false;
}
using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
using (BinaryReader reader = new BinaryReader(new FileStream(fileName, FileMode.Open, FileAccess.Read)))
{
MmapTileHeader fileHeader = reader.ReadStruct<MmapTileHeader>();
Array.Reverse(fileHeader.mmapMagic);
@@ -144,7 +173,52 @@ 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;
MMapData mmap = loadedMMaps[mapId];
if (mmap.navMeshQueries.ContainsKey(instanceId))
return true;
// allocate mesh query
Detour.dtNavMeshQuery query = new Detour.dtNavMeshQuery();
if (Detour.dtStatusFailed(query.init(mmap.navMesh, 1024)))
{
Log.outError(LogFilter.Maps, "MMAP.GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {0:D4} instanceId {1}", mapId, instanceId);
return false;
}
Log.outDebug(LogFilter.Maps, "MMAP.GetNavMeshQuery: created dtNavMeshQuery for mapId {0:D4} instanceId {1}", mapId, instanceId);
mmap.navMeshQueries.Add(instanceId, query);
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)
{
// check if we have this map loaded
MMapData mmap = GetMMapData(mapId);
@@ -156,7 +230,7 @@ namespace Game
}
// check if we have this tile loaded
uint packedGridPos = packTileID((int)x, (int)y);
uint packedGridPos = packTileID(x, y);
if (!mmap.loadedTileRefs.ContainsKey(packedGridPos))
{
// file may not exist, therefore not loaded
@@ -164,7 +238,7 @@ namespace Game
return false;
}
ulong tileRef = mmap.loadedTileRefs.LookupByKey(packedGridPos);
ulong tileRef = mmap.loadedTileRefs[packedGridPos];
// unload, and mark as non loaded
Detour.dtRawTileData data;
@@ -256,20 +330,6 @@ namespace Game
if (mmap == null)
return null;
if (!mmap.navMeshQueries.ContainsKey(instanceId))
{
// allocate mesh query
Detour.dtNavMeshQuery query = new Detour.dtNavMeshQuery();
if (Detour.dtStatusFailed(query.init(mmap.navMesh, 1024)))
{
Log.outError(LogFilter.Maps, "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {0} instanceId {1}", mapId, instanceId);
return null;
}
Log.outInfo(LogFilter.Maps, "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId {0} instanceId {1}", mapId, instanceId);
mmap.navMeshQueries.Add(instanceId, query);
}
return mmap.navMeshQueries[instanceId];
}
@@ -278,6 +338,9 @@ namespace Game
Dictionary<uint, MMapData> loadedMMaps = new Dictionary<uint, MMapData>();
uint loadedTiles;
MultiMap<uint, uint> childMapData = new MultiMap<uint, uint>();
Dictionary<uint, uint> parentMapData = new Dictionary<uint, uint>();
}
public class MMapData
+199 -108
View File
@@ -48,7 +48,16 @@ namespace Game.Maps
i_gridExpiry = expiry;
_defaultLight = Global.DB2Mgr.GetDefaultMapLight(id);
m_parentMap = parent ?? this;
if (parent)
{
m_parentMap = parent;
m_childTerrainMaps = m_parentMap.m_childTerrainMaps;
}
else
{
m_parentMap = this;
m_childTerrainMaps = new List<Map>();
}
for (uint x = 0; x < MapConst.MaxGrids; ++x)
{
@@ -69,6 +78,8 @@ namespace Game.Maps
GetGuidSequenceGenerator(HighGuid.Transport).Set(Global.ObjectMgr.GetGenerator(HighGuid.Transport).GetNextAfterMaxUsed());
Global.MMapMgr.loadMapInstance(Global.WorldMgr.GetDataPath(), GetId(), i_InstanceId);
Global.ScriptMgr.OnCreateMap(this);
}
@@ -112,7 +123,10 @@ namespace Game.Maps
void LoadMMap(uint gx, uint gy)
{
if (Global.MMapMgr.loadMap(GetId(), (int)gx, (int)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.outInfo(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);
@@ -138,39 +152,62 @@ namespace Game.Maps
void LoadMap(uint gx, uint gy, bool reload = false)
{
if (i_InstanceId != 0)
LoadMapImpl(this, gx, gy, reload);
foreach (Map childBaseMap in m_childTerrainMaps)
LoadMapImpl(childBaseMap, gx, gy, reload);
}
void LoadMapImpl(Map map, uint gx, uint gy, bool reload)
{
if (map.i_InstanceId != 0)
{
if (GridMaps[gx][gy] != null)
if (map.GridMaps[gx][gy] != null)
return;
// load grid map for base map
if (m_parentMap.GridMaps[gx][gy] == null)
m_parentMap.EnsureGridCreated(new GridCoord(63 - gx, 63 - gy));
if (map.m_parentMap.GridMaps[gx][gy] == null)
map.m_parentMap.EnsureGridCreated(new GridCoord(63 - gx, 63 - gy));
((MapInstanced)m_parentMap).AddGridMapReference(new GridCoord(gx, gy));
GridMaps[gx][gy] = m_parentMap.GridMaps[gx][gy];
map.m_parentMap.ToMapInstanced().AddGridMapReference(new GridCoord(gx, gy));
map.GridMaps[gx][gy] = map.m_parentMap.GridMaps[gx][gy];
return;
}
if (GridMaps[gx][gy] != null && !reload)
if (map.GridMaps[gx][gy] != null && !reload)
return;
if (GridMaps[gx][gy] != null)
if (map.GridMaps[gx][gy] != null)
{
Log.outInfo(LogFilter.Maps, "Unloading previously loaded map {0} before reloading.", GetId());
Global.ScriptMgr.OnUnloadGridMap(this, GridMaps[gx][gy], gx, gy);
Log.outInfo(LogFilter.Maps, "Unloading previously loaded map {0} before reloading.", map.GetId());
Global.ScriptMgr.OnUnloadGridMap(map, map.GridMaps[gx][gy], gx, gy);
GridMaps[gx][gy] = null;
map.GridMaps[gx][gy] = null;
}
// map file name
string filename = string.Format("{0}/maps/{1:D4}_{2:D2}_{3:D2}.map", Global.WorldMgr.GetDataPath(), GetId(), gx, gy);
string filename = string.Format("{0}/maps/{1:D4}_{2:D2}_{3:D2}.map", Global.WorldMgr.GetDataPath(), map.GetId(), gx, gy);
Log.outInfo(LogFilter.Maps, "Loading map {0}", filename);
// loading data
GridMaps[gx][gy] = new GridMap();
if (!GridMaps[gx][gy].loadData(filename))
map.GridMaps[gx][gy] = new GridMap();
if (!map.GridMaps[gx][gy].loadData(filename))
Log.outError(LogFilter.Maps, "Error loading map file: {0}", filename);
Global.ScriptMgr.OnLoadGridMap(this, GridMaps[gx][gy], gx, gy);
Global.ScriptMgr.OnLoadGridMap(map, map.GridMaps[gx][gy], gx, gy);
}
void UnloadMap(Map map, uint gx, uint gy)
{
if (map.i_InstanceId == 0)
{
if (map.GridMaps[gx][gy] != null)
{
map.GridMaps[gx][gy].unloadData();
map.GridMaps[gx][gy] = null;
}
}
else
map.m_parentMap.ToMapInstanced().RemoveGridMapReference(new GridCoord(gx, gy));
map.GridMaps[gx][gy] = null;
}
void LoadMapAndVMap(uint gx, uint gy)
@@ -415,7 +452,7 @@ namespace Game.Maps
player.m_clientGUIDs.Clear();
player.UpdateObjectVisibility(false);
player.SendUpdatePhasing();
PhasingHandler.SendToPlayer(player);
if (player.IsAlive())
ConvertCorpseToBones(player.GetGUID());
@@ -466,8 +503,6 @@ namespace Game.Maps
if (obj.isActiveObject())
AddToActive(obj);
obj.RebuildTerrainSwaps();
//something, such as vehicle, needs to be update immediately
//also, trigger needs to cast spell, if not update, cannot see visual
obj.UpdateObjectVisibilityOnCreate();
@@ -499,6 +534,7 @@ namespace Game.Maps
{
var data = new UpdateData(GetId());
obj.BuildCreateUpdateBlockForPlayer(data, player);
player.m_visibleTransports.Add(obj.GetGUID());
UpdateObject packet;
data.BuildPacket(out packet);
player.SendPacket(packet);
@@ -804,9 +840,14 @@ namespace Game.Maps
UpdateObject packet;
data.BuildPacket(out packet);
foreach (var pl in players)
if (pl.GetTransport() != obj)
pl.SendPacket(packet);
foreach (var player in players)
{
if (player.GetTransport() != obj)
{
player.SendPacket(packet);
player.m_visibleTransports.Remove(obj.GetGUID());
}
}
}
if (!_transports.Contains(obj))
@@ -1541,20 +1582,19 @@ namespace Game.Maps
uint gx = (MapConst.MaxGrids - 1) - x;
uint gy = (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]) don't check for GridMaps[gx][gy], we might have to unload vmaps
{
foreach (Map childBaseMap in m_childTerrainMaps)
UnloadMap(childBaseMap, gx, gy);
UnloadMap(this, gx, gy);
if (i_InstanceId == 0)
{
if (GridMaps[gx][gy] != null)
{
GridMaps[gx][gy].unloadData();
}
Global.VMapMgr.unloadMap(GetId(), gx, gy);
Global.MMapMgr.unloadMap(GetId(), gx, gy);
}
else
((MapInstanced)m_parentMap).RemoveGridMapReference(new GridCoord(gx, gy));
GridMaps[gx][gy] = null;
}
Log.outDebug(LogFilter.Maps, "Unloading grid[{0}, {1}] for map {2} finished", x, y, GetId());
return true;
@@ -1624,49 +1664,79 @@ namespace Game.Maps
if (!m_scriptSchedule.Empty())
Global.MapMgr.DecreaseScheduledScriptCount((uint)m_scriptSchedule.Count);
if (m_parentMap == this)
m_childTerrainMaps = null;
Global.MMapMgr.unloadMapInstance(GetId(), i_InstanceId);
}
private GridMap GetGridMap(float x, float y)
{
// half opt method
var gx = (uint)(32 - x / MapConst.SizeofGrids); //grid x
var gy = (uint)(32 - y / MapConst.SizeofGrids); //grid y
var gx = (uint)(MapConst.CenterGridId - x / MapConst.SizeofGrids); //grid x
var gy = (uint)(MapConst.CenterGridId - y / MapConst.SizeofGrids); //grid y
// ensure GridMap is loaded
EnsureGridCreated(new GridCoord(63 - gx, 63 - gy));
EnsureGridCreated(new GridCoord((MapConst.MaxGrids - 1) - gx, (MapConst.MaxGrids - 1) - gy));
return GridMaps[gx][gy];
}
public float GetWaterOrGroundLevel(List<uint> phases, float x, float y, float z)
GridMap GetGridMap(uint mapId, float x, float y)
{
float ground = 0f;
return GetWaterOrGroundLevel(phases, x, y, z, ref ground);
if (GetId() == mapId)
return GetGridMap(x, y);
// 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].fileExists())
grid = childMap.GridMaps[gx][gy];
return grid;
}
public float GetWaterOrGroundLevel(List<uint> phases, float x, float y, float z, ref float ground, bool swim = false)
public bool HasGridMap(uint mapId, uint gx, uint gy)
{
var childMap = m_childTerrainMaps.Find(childTerrainMap => childTerrainMap.GetId() == mapId);
return childMap != null && childMap.GridMaps[gx][gy] != null && childMap.GridMaps[gx][gy].fileExists();
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z)
{
float ground = 0f;
return GetWaterOrGroundLevel(phaseShift, x, y, z, ref ground);
}
public float GetWaterOrGroundLevel(PhaseShift phaseShift, float x, float y, float z, ref float ground, bool swim = false)
{
if (GetGridMap(x, y) != null)
{
// we need ground level (including grid height version) for proper return water level in point
float ground_z = GetHeight(phases, x, y, z, true, 50.0f);
float ground_z = GetHeight(phaseShift, x, y, z, true, 50.0f);
ground = ground_z;
LiquidData liquid_status;
ZLiquidStatus res = getLiquidStatus(x, y, ground_z, MapConst.MapAllLiquidTypes, out liquid_status);
ZLiquidStatus res = getLiquidStatus(phaseShift, x, y, ground_z, MapConst.MapAllLiquidTypes, out liquid_status);
return res != ZLiquidStatus.NoWater ? liquid_status.level : ground_z;
}
return MapConst.VMAPInvalidHeightValue;
}
public float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
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;
GridMap gmap = GetGridMap(x, y);
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
GridMap gmap = GetGridMap(terrainMapId, x, y);
if (gmap != null)
{
float gridHeight = gmap.getHeight(x, y);
@@ -1679,7 +1749,7 @@ namespace Game.Maps
if (checkVMap)
{
if (Global.VMapMgr.isHeightCalcEnabled())
vmapHeight = Global.VMapMgr.getHeight(GetId(), x, y, z + 2.0f, maxSearchDist);
vmapHeight = Global.VMapMgr.getHeight(terrainMapId, x, y, z + 2.0f, maxSearchDist);
// look from a bit higher pos to find the floor
}
@@ -1736,13 +1806,13 @@ namespace Game.Maps
return outdoor;
}
public bool IsOutdoors(float x, float y, float z)
public bool IsOutdoors(PhaseShift phaseShift, float x, float y, float z)
{
uint mogpFlags;
int adtId, rootId, groupId;
// no wmo found? . outside by default
if (!GetAreaInfo(x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
if (!GetAreaInfo(phaseShift, x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
return true;
AreaTableRecord atEntry = null;
@@ -1756,7 +1826,7 @@ namespace Game.Maps
return IsOutdoorWMO(mogpFlags, adtId, rootId, groupId, wmoEntry, atEntry);
}
private bool GetAreaInfo(float x, float y, float z, out uint flags, out int adtId, out int rootId, out int groupId)
private bool GetAreaInfo(PhaseShift phaseShift, float x, float y, float z, out uint flags, out int adtId, out int rootId, out int groupId)
{
flags = 0;
adtId = 0;
@@ -1764,10 +1834,11 @@ namespace Game.Maps
groupId = 0;
float vmap_z = z;
if (Global.VMapMgr.getAreaInfo(GetId(), x, y, ref vmap_z, out flags, out adtId, out rootId, out groupId))
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
if (Global.VMapMgr.getAreaInfo(terrainMapId, x, y, ref vmap_z, out flags, out adtId, out rootId, out groupId))
{
// check if there's terrain between player height and object height
GridMap gmap = GetGridMap(x, y);
GridMap gmap = GetGridMap(terrainMapId, x, y);
if (gmap != null)
{
float _mapheight = gmap.getHeight(x, y);
@@ -1781,13 +1852,13 @@ namespace Game.Maps
return false;
}
public uint GetAreaId(float x, float y, float z)
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z)
{
bool throwaway;
return GetAreaId(x, y, z, out throwaway);
return GetAreaId(phaseShift, x, y, z, out throwaway);
}
public uint GetAreaId(float x, float y, float z, out bool isOutdoors)
public uint GetAreaId(PhaseShift phaseShift, float x, float y, float z, out bool isOutdoors)
{
uint mogpFlags;
int adtId, rootId, groupId;
@@ -1796,7 +1867,7 @@ namespace Game.Maps
bool haveAreaInfo = false;
uint areaId = 0;
if (GetAreaInfo(x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
if (GetAreaInfo(phaseShift, x, y, z, out mogpFlags, out adtId, out rootId, out groupId))
{
haveAreaInfo = true;
wmoEntry = Global.DB2Mgr.GetWMOAreaTable(rootId, adtId, groupId);
@@ -1809,7 +1880,7 @@ namespace Game.Maps
if (areaId == 0)
{
GridMap gmap = GetGridMap(x, y);
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
areaId = gmap.getArea(x, y);
@@ -1826,9 +1897,9 @@ namespace Game.Maps
return areaId;
}
public uint GetZoneId(float x, float y, float z)
public uint GetZoneId(PhaseShift phaseShift, float x, float y, float z)
{
uint areaId = GetAreaId(x, y, z);
uint areaId = GetAreaId(phaseShift, x, y, z);
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaId);
if (area != null)
if (area.ParentAreaID != 0)
@@ -1837,38 +1908,38 @@ namespace Game.Maps
return areaId;
}
public void GetZoneAndAreaId(out uint zoneid, out uint areaid, float x, float y, float z)
public void GetZoneAndAreaId(PhaseShift phaseShift, out uint zoneid, out uint areaid, float x, float y, float z)
{
areaid = zoneid = GetAreaId(x, y, z);
areaid = zoneid = GetAreaId(phaseShift, x, y, z);
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(areaid);
if (area != null)
if (area.ParentAreaID != 0)
zoneid = area.ParentAreaID;
}
private byte GetTerrainType(float x, float y)
private byte GetTerrainType(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGridMap(x, y);
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.getTerrainType(x, y);
return 0;
}
public ZLiquidStatus getLiquidStatus(float x, float y, float z, byte ReqLiquidType)
public ZLiquidStatus getLiquidStatus(PhaseShift phaseShift, float x, float y, float z, byte ReqLiquidType)
{
LiquidData throwaway;
return getLiquidStatus(x, y, z, ReqLiquidType, out throwaway);
return getLiquidStatus(phaseShift, x, y, z, ReqLiquidType, out throwaway);
}
public ZLiquidStatus getLiquidStatus(float x, float y, float z, byte ReqLiquidType, out LiquidData data)
public ZLiquidStatus getLiquidStatus(PhaseShift phaseShift, float x, float y, float z, byte ReqLiquidType, out LiquidData data)
{
data = new LiquidData();
var result = ZLiquidStatus.NoWater;
float liquid_level = MapConst.InvalidHeight;
float ground_level = MapConst.InvalidHeight;
uint liquid_type = 0;
if (Global.VMapMgr.GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, ref liquid_level, ref ground_level, ref liquid_type))
uint terrainMapId = PhasingHandler.GetTerrainMapId(phaseShift, this, x, y);
if (Global.VMapMgr.GetLiquidLevel(terrainMapId, x, y, z, ReqLiquidType, ref liquid_level, ref ground_level, ref liquid_type))
{
Log.outDebug(LogFilter.Maps, "getLiquidStatus(): vmap liquid level: {0} ground: {1} type: {2}",
liquid_level, ground_level, liquid_type);
@@ -1887,7 +1958,7 @@ namespace Game.Maps
if (liquid_type != 0 && liquid_type < 21)
{
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(GetAreaId(x, y, z));
AreaTableRecord area = CliDB.AreaTableStorage.LookupByKey(GetAreaId(phaseShift, x, y, z));
if (area != null)
{
uint overrideLiquid = area.LiquidTypeID[liquidFlagType];
@@ -1926,7 +1997,7 @@ namespace Game.Maps
}
}
GridMap gmap = GetGridMap(x, y);
GridMap gmap = GetGridMap(terrainMapId, x, y);
if (gmap != null)
{
var map_data = new LiquidData();
@@ -1946,27 +2017,27 @@ namespace Game.Maps
return result;
}
public float GetWaterLevel(float x, float y)
public float GetWaterLevel(PhaseShift phaseShift, float x, float y)
{
GridMap gmap = GetGridMap(x, y);
GridMap gmap = GetGridMap(PhasingHandler.GetTerrainMapId(phaseShift, this, x, y), x, y);
if (gmap != null)
return gmap.getLiquidLevel(x, y);
return 0;
}
public bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, List<uint> phases)
public bool isInLineOfSight(PhaseShift phaseShift, float x1, float y1, float z1, float x2, float y2, float z2)
{
return Global.VMapMgr.isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2)
&& _dynamicTree.isInLineOfSight(new Vector3(x1, y1, z1), new Vector3(x2, y2, z2), phases);
return Global.VMapMgr.isInLineOfSight(PhasingHandler.GetTerrainMapId(phaseShift, this, x1, y1), x1, y1, z1, x2, y2, z2)
&& _dynamicTree.isInLineOfSight(new Vector3(x1, y1, z1), new Vector3(x2, y2, z2), phaseShift);
}
public bool getObjectHitPos(List<uint> phases, float x1, float y1, float z1, float x2, float y2, float z2, out float rx, out float ry, out float rz, float modifyDist)
public bool getObjectHitPos(PhaseShift phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, out float rx, out float ry, out float rz, float modifyDist)
{
var startPos = new Vector3(x1, y1, z1);
var dstPos = new Vector3(x2, y2, z2);
var resultPos = new Vector3();
bool result = _dynamicTree.getObjectHitPos(phases, startPos, dstPos, ref resultPos, modifyDist);
bool result = _dynamicTree.getObjectHitPos(startPos, dstPos, ref resultPos, modifyDist, phaseShift);
rx = resultPos.X;
ry = resultPos.Y;
@@ -1974,22 +2045,19 @@ namespace Game.Maps
return result;
}
public float GetHeight(List<uint> phases, float x, float y, float z, bool vmap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
public float GetHeight(PhaseShift phaseShift, float x, float y, float z, bool vmap = true, float maxSearchDist = MapConst.DefaultHeightSearch)
{
return Math.Max(GetHeight(x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phases));
return Math.Max(GetStaticHeight(phaseShift, x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift));
}
public bool IsInWater(float x, float y, float pZ)
public bool IsInWater(PhaseShift phaseShift, float x, float y, float pZ)
{
return Convert.ToBoolean(getLiquidStatus(x, y, pZ, MapConst.MapAllLiquidTypes) &
(ZLiquidStatus.InWater | ZLiquidStatus.UnderWater));
return Convert.ToBoolean(getLiquidStatus(phaseShift, x, y, pZ, MapConst.MapAllLiquidTypes) & (ZLiquidStatus.InWater | ZLiquidStatus.UnderWater));
}
public bool IsUnderWater(float x, float y, float z)
public bool IsUnderWater(PhaseShift phaseShift, float x, float y, float z)
{
return
Convert.ToBoolean(getLiquidStatus(x, y, z, MapConst.MapLiquidTypeWater | MapConst.MapLiquidTypeOcean) &
ZLiquidStatus.UnderWater);
return Convert.ToBoolean(getLiquidStatus(phaseShift, x, y, z, MapConst.MapLiquidTypeWater | MapConst.MapLiquidTypeOcean) & ZLiquidStatus.UnderWater);
}
private bool CheckGridIntegrity(Creature c, bool moved)
@@ -2007,30 +2075,32 @@ namespace Game.Maps
return i_mapRecord != null ? i_mapRecord.MapName[Global.WorldMgr.GetDefaultDbcLocale()] : "UNNAMEDMAP";
}
public void SendInitSelf(Player pl)
public void SendInitSelf(Player player)
{
var data = new UpdateData(pl.GetMapId());
var data = new UpdateData(player.GetMapId());
// attach to player data current transport data
Transport transport = pl.GetTransport();
if (transport != null)
transport.BuildCreateUpdateBlockForPlayer(data, pl);
pl.BuildCreateUpdateBlockForPlayer(data, pl);
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
Transport transport = player.GetTransport();
if (transport != null)
{
foreach (WorldObject obj in transport.GetPassengers())
transport.BuildCreateUpdateBlockForPlayer(data, player);
player.m_visibleTransports.Add(transport.GetGUID());
}
player.BuildCreateUpdateBlockForPlayer(data, player);
// build other passengers at transport also (they always visible and marked as visible and will not send at visibility update at add to map
if (transport != null)
{
foreach (WorldObject passenger in transport.GetPassengers())
{
if (pl != obj && pl.HaveAtClient(obj))
obj.BuildCreateUpdateBlockForPlayer(data, pl);
if (player != passenger && player.HaveAtClient(passenger))
passenger.BuildCreateUpdateBlockForPlayer(data, player);
}
}
UpdateObject packet;
data.BuildPacket(out packet);
pl.SendPacket(packet);
player.SendPacket(packet);
}
void SendInitTransports(Player player)
@@ -2040,7 +2110,10 @@ namespace Game.Maps
foreach (Transport transport in _transports)
{
if (transport != player.GetTransport() && player.IsInPhase(transport))
{
transport.BuildCreateUpdateBlockForPlayer(transData, player);
player.m_visibleTransports.Add(transport.GetGUID());
}
}
UpdateObject packet;
@@ -2052,27 +2125,39 @@ namespace Game.Maps
{
var transData = new UpdateData(player.GetMapId());
foreach (Transport transport in _transports)
{
if (transport != player.GetTransport())
{
transport.BuildOutOfRangeUpdateBlock(transData);
player.m_visibleTransports.Remove(transport.GetGUID());
}
}
UpdateObject packet;
transData.BuildPacket(out packet);
player.SendPacket(packet);
}
public void SendUpdateTransportVisibility(Player player, List<uint> previousPhases)
public void SendUpdateTransportVisibility(Player player)
{
// Hack to send out transports
UpdateData transData = new UpdateData(player.GetMapId());
foreach (var trans in _transports)
foreach (var transport in _transports)
{
if (trans == player.GetTransport())
continue;
if (player.IsInPhase(trans) && !previousPhases.Intersect(trans.GetPhases()).Any())
trans.BuildCreateUpdateBlockForPlayer(transData, player);
else if (!player.IsInPhase(trans))
trans.BuildOutOfRangeUpdateBlock(transData);
var hasTransport = player.m_visibleTransports.Contains(transport.GetGUID());
if (player.IsInPhase(transport))
{
if (!hasTransport)
{
transport.BuildCreateUpdateBlockForPlayer(transData, player);
player.m_visibleTransports.Add(transport.GetGUID());
}
}
else
{
transport.BuildOutOfRangeUpdateBlock(transData);
player.m_visibleTransports.Remove(transport.GetGUID());
}
}
UpdateObject packet;
@@ -2525,7 +2610,7 @@ namespace Game.Maps
continue;
foreach (var phaseId in phases[guid])
corpse.SetInPhase(phaseId, false, true);
PhasingHandler.AddPhase(corpse, phaseId, false);
AddCorpse(corpse);
} while (result.NextRow());
@@ -2604,7 +2689,7 @@ namespace Game.Maps
bones.SetUInt32Value(CorpseFields.Flags, corpse.GetUInt32Value(CorpseFields.Flags) | (uint)CorpseFlags.Bones);
bones.CopyPhaseFrom(corpse);
PhasingHandler.InheritPhaseShift(bones, corpse);
AddCorpse(bones);
@@ -2847,6 +2932,10 @@ namespace Game.Maps
return m_parentMap;
}
public void AddChildTerrainMap(Map map) { m_childTerrainMaps.Add(map); }
public void UnlinkAllChildTerrainMaps() { m_childTerrainMaps.Clear(); }
public uint GetInstanceId()
{
return i_InstanceId;
@@ -3225,7 +3314,8 @@ namespace Game.Maps
return null;
// Set the summon to the summoner's phase
summon.CopyPhaseFrom(summoner);
if (summoner)
PhasingHandler.InheritPhaseShift(summon, summoner);
summon.SetUInt32Value(UnitFields.CreatedBySpell, spellId);
@@ -4219,6 +4309,7 @@ namespace Game.Maps
protected List<WorldObject> m_activeNonPlayers = new List<WorldObject>();
protected List<Player> m_activePlayers = new List<Player>();
Map m_parentMap;
List<Map> m_childTerrainMaps = new List<Map>();
SortedMultiMap<long, ScriptAction> m_scriptSchedule = new SortedMultiMap<long, ScriptAction>();
BitArray marked_cells = new BitArray(MapConst.TotalCellsPerMap * MapConst.TotalCellsPerMap);
+108 -74
View File
@@ -37,10 +37,15 @@ namespace Game.Entities
public void Initialize()
{
//todo needs alot of support for threadsafe.
//int num_threads= WorldConfig.GetIntValue(WorldCfg.Numthreads);
int num_threads = WorldConfig.GetIntValue(WorldCfg.Numthreads);
// Start mtmaps if needed.
//if (num_threads > 0)
//m_updater = new MapUpdater(WorldConfig.GetIntValue(WorldCfg.Numthreads));
if (num_threads > 0)
m_updater = new MapUpdater(WorldConfig.GetIntValue(WorldCfg.Numthreads));
}
public void InitializeParentMapData(MultiMap<uint, uint> mapData)
{
_parentMapData = mapData;
}
public void InitializeVisibilityDistanceInfo()
@@ -52,31 +57,46 @@ namespace Game.Entities
public Map CreateBaseMap(uint id)
{
Map map = FindBaseMap(id);
if (map == null)
{
lock (this)
var entry = CliDB.MapStorage.LookupByKey(id);
Contract.Assert(entry != null);
if (entry.ParentMapID != -1)
{
CreateBaseMap((uint)entry.ParentMapID);
var entry = CliDB.MapStorage.LookupByKey(id);
Contract.Assert(entry != null);
if (entry.Instanceable())
map = new MapInstanced(id, i_gridCleanUpDelay);
else
{
map = new Map(id, i_gridCleanUpDelay, 0, Difficulty.None);
map.LoadRespawnTimes();
map.LoadCorpseData();
}
i_maps[id] = map;
// must have been created by parent map
map = FindBaseMap(id);
return map;
}
lock(_mapsLock)
map = CreateBaseMap_i(entry);
}
Contract.Assert(map != null);
return map;
}
Map CreateBaseMap_i(MapRecord mapEntry)
{
Map map;
if (mapEntry.Instanceable())
map = new MapInstanced(mapEntry.Id, i_gridCleanUpDelay);
else
{
map = new Map(mapEntry.Id, i_gridCleanUpDelay, 0, Difficulty.None);
map.LoadRespawnTimes();
map.LoadCorpseData();
}
i_maps[mapEntry.Id] = map;
foreach (uint childMapId in _parentMapData[mapEntry.Id])
map.AddChildTerrainMap(CreateBaseMap_i(CliDB.MapStorage.LookupByKey(childMapId)));
return map;
}
public Map FindBaseNonInstanceMap(uint mapId)
{
Map map = FindBaseMap(mapId);
@@ -206,20 +226,14 @@ namespace Game.Entities
var time = (uint)i_timer.GetCurrent();
foreach (var map in i_maps.Values.ToList())
{
//if (!m_updater)
//m_updater.Enqueue(map, (uint)i_timer.GetCurrent());
//else
map.Update(time);
if (m_updater != null)
m_updater.Enqueue(map, (uint)i_timer.GetCurrent());
else
map.Update(time);
}
//List<System.Threading.Tasks.Task> tasks = new List<System.Threading.Tasks.Task>();
//foreach (var map in i_maps.Values.ToList())
{
//tasks.Add(System.Threading.Tasks.Task.Factory.StartNew(() => map.Update(time)));
}
//System.Threading.Tasks.Task.WaitAll(tasks.ToArray());
//if (!m_updater)
// m_updater.Wait();
if (m_updater != null)
m_updater.Wait();
foreach (var map in i_maps.ToList())
map.Value.DelayedUpdate(time);
@@ -251,6 +265,10 @@ namespace Game.Entities
public void UnloadAll()
{
// first unlink child maps
foreach (var pair in i_maps)
pair.Value.UnlinkAllChildTerrainMaps();
foreach (var pair in i_maps.ToList())
{
pair.Value.UnloadAll();
@@ -260,34 +278,40 @@ namespace Game.Entities
public uint GetNumInstances()
{
uint ret = 0;
foreach (var pair in i_maps.ToList())
lock (_mapsLock)
{
Map map = pair.Value;
if (!map.Instanceable())
continue;
var maps = ((MapInstanced)map).GetInstancedMaps();
foreach (var imap in maps)
if (imap.Value.IsDungeon())
ret++;
uint ret = 0;
foreach (var pair in i_maps.ToList())
{
Map map = pair.Value;
if (!map.Instanceable())
continue;
var maps = ((MapInstanced)map).GetInstancedMaps();
foreach (var imap in maps)
if (imap.Value.IsDungeon())
ret++;
}
return ret;
}
return ret;
}
public uint GetNumPlayersInInstances()
{
uint ret = 0;
foreach (var pair in i_maps)
lock (_mapsLock)
{
Map map = pair.Value;
if (!map.Instanceable())
continue;
var maps = ((MapInstanced)map).GetInstancedMaps();
foreach (var imap in maps)
if (imap.Value.IsDungeon())
ret += (uint)imap.Value.GetPlayers().Count;
uint ret = 0;
foreach (var pair in i_maps)
{
Map map = pair.Value;
if (!map.Instanceable())
continue;
var maps = ((MapInstanced)map).GetInstancedMaps();
foreach (var imap in maps)
if (imap.Value.IsDungeon())
ret += (uint)imap.Value.GetPlayers().Count;
}
return ret;
}
return ret;
}
public void InitInstanceIds()
@@ -361,54 +385,60 @@ namespace Game.Entities
return i_maps.LookupByKey(mapId);
}
uint GetAreaId(uint mapid, float x, float y, float z)
uint GetAreaId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
Map m = CreateBaseMap(mapid);
return m.GetAreaId(x, y, z);
return m.GetAreaId(phaseShift, x, y, z);
}
public uint GetZoneId(uint mapid, float x, float y, float z)
public uint GetZoneId(PhaseShift phaseShift, uint mapid, float x, float y, float z)
{
Map m = CreateBaseMap(mapid);
return m.GetZoneId(x, y, z);
return m.GetZoneId(phaseShift, x, y, z);
}
public void GetZoneAndAreaId(out uint zoneid, out uint areaid, uint mapid, float x, float y, float 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(out zoneid, out areaid, x, y, z);
m.GetZoneAndAreaId(phaseShift, out zoneid, out areaid, x, y, z);
}
public void DoForAllMaps(Action<Map> worker)
{
foreach (var map in i_maps.Values)
lock (_mapsLock)
{
MapInstanced mapInstanced = map.ToMapInstanced();
if (mapInstanced)
foreach (var map in i_maps.Values)
{
var instances = mapInstanced.GetInstancedMaps();
foreach (var instance in instances.Values)
worker(instance);
MapInstanced mapInstanced = map.ToMapInstanced();
if (mapInstanced)
{
var instances = mapInstanced.GetInstancedMaps();
foreach (var instance in instances.Values)
worker(instance);
}
else
worker(map);
}
else
worker(map);
}
}
public void DoForAllMapsWithMapId(uint mapId, Action<Map> worker)
{
var map = i_maps.LookupByKey(mapId);
if (map != null)
lock (_mapsLock)
{
MapInstanced mapInstanced = map.ToMapInstanced();
if (mapInstanced)
var map = i_maps.LookupByKey(mapId);
if (map != null)
{
var instances = mapInstanced.GetInstancedMaps();
foreach (var instance in instances)
worker(instance.Value);
MapInstanced mapInstanced = map.ToMapInstanced();
if (mapInstanced)
{
var instances = mapInstanced.GetInstancedMaps();
foreach (var instance in instances)
worker(instance.Value);
}
else
worker(map);
}
else
worker(map);
}
}
@@ -419,10 +449,14 @@ namespace Game.Entities
Dictionary<uint, Map> i_maps = new Dictionary<uint, Map>();
IntervalTimer i_timer = new IntervalTimer();
object _mapsLock= new object();
uint i_gridCleanUpDelay;
Dictionary<uint, bool> _instanceIds = new Dictionary<uint, bool>();
uint _nextInstanceId;
//MapUpdater m_updater;
MapUpdater m_updater;
uint _scheduledScripts;
// parent map links
MultiMap<uint, uint> _parentMapData;
}
}
+44 -11
View File
@@ -348,7 +348,7 @@ namespace Game.Maps
_transportAnimations[transportEntry] = animNode;
}
public Transport CreateTransport(uint entry, ulong guid = 0, Map map = null, uint phaseid = 0, uint phasegroup = 0)
public Transport CreateTransport(uint entry, ulong guid = 0, Map map = null, PhaseUseFlagsValues phaseUseFlags = 0, uint phaseId = 0, uint phaseGroupId = 0)
{
// instance case, execute GetGameObjectEntry hook
if (map != null)
@@ -388,12 +388,7 @@ namespace Game.Maps
if (!trans.Create(guidLow, entry, mapId, x, y, z, o, 255))
return null;
if (phaseid != 0)
trans.SetInPhase(phaseid, false, true);
if (phasegroup != 0)
foreach (var ph in Global.DB2Mgr.GetPhasesForGroup(phasegroup))
trans.SetInPhase(ph, false, true);
PhasingHandler.InitDbPhaseShift(trans.GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId);
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(mapId);
if (mapEntry != null)
@@ -424,7 +419,7 @@ namespace Game.Maps
uint oldMSTime = Time.GetMSTime();
SQLResult result = DB.World.Query("SELECT guid, entry, phaseid, phasegroup FROM transports");
SQLResult result = DB.World.Query("SELECT guid, entry, phaseUseFlags, phaseid, phasegroup FROM transports");
uint count = 0;
if (!result.IsEmpty())
@@ -433,13 +428,51 @@ namespace Game.Maps
{
ulong guid = result.Read<ulong>(0);
uint entry = result.Read<uint>(1);
uint phaseid = result.Read<uint>(2);
uint phasegroup = result.Read<uint>(3);
PhaseUseFlagsValues phaseUseFlags = (PhaseUseFlagsValues)result.Read<byte>(2);
uint phaseId = result.Read<uint>(3);
uint phaseGroupId = result.Read<uint>(4);
if (Convert.ToBoolean(phaseUseFlags & ~PhaseUseFlagsValues.All))
{
Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) with unknown `phaseUseFlags` set, removed unknown value.");
phaseUseFlags &= PhaseUseFlagsValues.All;
}
if (phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.AlwaysVisible) && phaseUseFlags.HasAnyFlag(PhaseUseFlagsValues.Inverse))
{
Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) has both `phaseUseFlags` PHASE_USE_FLAGS_ALWAYS_VISIBLE and PHASE_USE_FLAGS_INVERSE," +
" removing PHASE_USE_FLAGS_INVERSE.");
phaseUseFlags &= ~PhaseUseFlagsValues.Inverse;
}
if (phaseGroupId != 0 && phaseId != 0)
{
Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) with both `phaseid` and `phasegroup` set, `phasegroup` set to 0");
phaseGroupId = 0;
}
if (phaseId != 0)
{
if (!CliDB.PhaseStorage.ContainsKey(phaseId))
{
Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) with `phaseid` {phaseId} does not exist, set to 0");
phaseId = 0;
}
}
if (phaseGroupId != 0)
{
if (Global.DB2Mgr.GetPhasesForGroup(phaseGroupId).Empty())
{
Log.outError(LogFilter.Sql, $"Table `transports` have transport (GUID: {guid} Entry: {entry}) with `phaseGroup` {phaseGroupId} does not exist, set to 0");
phaseGroupId = 0;
}
}
TransportTemplate tInfo = GetTransportTemplate(entry);
if (tInfo != null)
if (!tInfo.inInstance)
if (CreateTransport(entry, guid, null, phaseid, phasegroup))
if (CreateTransport(entry, guid, null, phaseUseFlags, phaseId, phaseGroupId))
++count;
} while (result.NextRow());