Core/MMaps: Remove phased tile support

This commit is contained in:
hondacrx
2018-02-26 13:33:46 -05:00
parent 3c4bc098c8
commit dae1a77089
5 changed files with 16 additions and 291 deletions
+7 -280
View File
@@ -34,15 +34,6 @@ 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()
{
foreach (MapRecord mapEntry in CliDB.MapStorage.Values)
{
if (mapEntry.ParentMapID != -1)
phaseMapData.Add((uint)mapEntry.ParentMapID, mapEntry.Id);
}
}
MMapData GetMMapData(uint mapId)
{
return loadedMMaps.LookupByKey(mapId);
@@ -84,7 +75,7 @@ namespace Game
Log.outInfo(LogFilter.Maps, "MMAP:loadMapData: Loaded {0:D4}.mmap", mapId);
// store inside our map list
loadedMMaps[mapId] = new MMapData(mesh, mapId);
loadedMMaps[mapId] = new MMapData(mesh);
return true;
}
}
@@ -145,14 +136,6 @@ namespace Game
mmap.loadedTileRefs.Add(packedGridPos, tileRef);
++loadedTiles;
Log.outInfo(LogFilter.Maps, "MMAP:loadMap: Loaded mmtile {0:D4}[{1:D2}, {2:D2}]", mapId, x, y);
var phasedMaps = phaseMapData.LookupByKey(mapId);
if (!phasedMaps.Empty())
{
mmap.AddBaseTile(packedGridPos, data, fileHeader, fileHeader.size);
LoadPhaseTiles(phasedMaps, x, y);
}
return true;
}
@@ -161,89 +144,6 @@ namespace Game
}
}
PhasedTile LoadTile(uint mapId, int x, int y)
{
// load this tile . mmaps/MMMXXYY.mmtile
string filename = string.Format(TILE_FILE_NAME_FORMAT, Global.WorldMgr.GetDataPath(), mapId, x, y);
if (!File.Exists(filename))
{
// Not all tiles have phased versions, don't flood this msg
return null;
}
PhasedTile pTile = new PhasedTile();
using (BinaryReader reader = new BinaryReader(new FileStream(filename, FileMode.Open, FileAccess.Read)))
{
// read header
pTile.fileHeader = reader.ReadStruct<MmapTileHeader>();
Array.Reverse(pTile.fileHeader.mmapMagic);
if (new string(pTile.fileHeader.mmapMagic) != MapConst.mmapMagic)
{
Log.outError(LogFilter.Maps, "MMAP.LoadTile: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
return null;
}
if (pTile.fileHeader.mmapVersion != MapConst.mmapVersion)
{
Log.outError(LogFilter.Maps, "MMAP:LoadTile: {0:D4}{1:D2}{2:D2}.mmtile was built with generator v{3}, expected v{4}", mapId, x, y, pTile.fileHeader.mmapVersion, MapConst.mmapVersion);
return null;
}
pTile.data = new Detour.dtRawTileData();
pTile.data.FromBytes(reader.ReadBytes((int)pTile.fileHeader.size), 0);
if (pTile.data.ToBytes().Length == 0)
{
Log.outError(LogFilter.Maps, "MMAP.LoadTile: Bad header or data in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
return null;
}
}
return pTile;
}
void LoadPhaseTiles(List<uint> phasedMapData, int x, int y)
{
Log.outDebug(LogFilter.Maps, "MMAP.LoadPhaseTiles: Loading phased mmtiles for map {0}, X: {1}, Y: {2}", phasedMapData.FirstOrDefault(), x, y);
uint packedGridPos = packTileID(x, y);
foreach (uint phaseMapId in phasedMapData)
{
PhasedTile data = LoadTile(phaseMapId, x, y);
// only a few tiles have terrain swaps, do not write error for them
if (data != null)
{
Log.outDebug(LogFilter.Maps, "MMAP.LoadPhaseTiles: Loaded phased {0:D4}{1:D2}{2:D2}.mmtile for root phase map {3}", phaseMapId, x, y, phasedMapData.FirstOrDefault());
if (!_phaseTiles.ContainsKey(phaseMapId))
_phaseTiles[phaseMapId] = new Dictionary<uint, PhasedTile>();
_phaseTiles[phaseMapId][packedGridPos] = data;
}
}
}
void UnloadPhaseTile(List<uint> phasedMapData, int x, int y)
{
Log.outDebug(LogFilter.Maps, "MMAP.UnloadPhaseTile: Unloading phased mmtile for map {0}, X: {1}, Y: {2}", phasedMapData.FirstOrDefault(), x, y);
uint packedGridPos = packTileID(x, y);
foreach (uint phaseMapId in phasedMapData.ToList())
{
var phasedTileDic = _phaseTiles.LookupByKey(phaseMapId);
if (phasedTileDic == null)
continue;
var phaseTile = phasedTileDic.LookupByKey(packedGridPos);
if (phaseTile != null)
{
Log.outDebug(LogFilter.Maps, "MMAP.UnloadPhaseTile: Unloaded phased {0:D4}{1:D2}{2:D2}.mmtile for root phase map {3}", phaseMapId, x, y, phasedMapData.FirstOrDefault());
phasedTileDic.Remove(packedGridPos);
}
}
}
public bool unloadMap(uint mapId, uint x, uint y)
{
// check if we have this map loaded
@@ -281,13 +181,6 @@ namespace Game
mmap.loadedTileRefs.Remove(packedGridPos);
--loadedTiles;
Log.outInfo(LogFilter.Maps, "MMAP:unloadMap: Unloaded mmtile {0:D4}[{1:D2}, {2:D2}] from {3:D4}", mapId, x, y, mapId);
var phasedMaps = phaseMapData.LookupByKey(mapId);
if (!phasedMaps.Empty())
{
mmap.DeleteBaseTile(packedGridPos);
UnloadPhaseTile(phasedMaps, (int)x, (int)y);
}
return true;
}
@@ -314,12 +207,6 @@ namespace Game
Log.outError(LogFilter.Maps, "MMAP:unloadMap: Could not unload {0:D4}{1:D2}{2:D2}.mmtile from navmesh", mapId, x, y);
else
{
var phasedMaps = phaseMapData.LookupByKey(mapId);
if (!phasedMaps.Empty())
{
mmap.DeleteBaseTile(i.Key);
UnloadPhaseTile(phasedMaps, (int)x, (int)y);
}
--loadedTiles;
Log.outInfo(LogFilter.Maps, "MMAP:unloadMap: Unloaded mmtile {0:D4} [{1:D2}, {2:D2}] from {3:D4}", mapId, x, y, mapId);
}
@@ -354,16 +241,16 @@ namespace Game
return true;
}
public Detour.dtNavMesh GetNavMesh(uint mapId, List<uint> swaps)
public Detour.dtNavMesh GetNavMesh(uint mapId)
{
MMapData mmap = GetMMapData(mapId);
if (mmap == null)
return null;
return mmap.GetNavMesh(swaps);
return mmap.navMesh;
}
public Detour.dtNavMeshQuery GetNavMeshQuery(uint mapId, uint instanceId, List<uint> swaps)
public Detour.dtNavMeshQuery GetNavMeshQuery(uint mapId, uint instanceId)
{
MMapData mmap = GetMMapData(mapId);
if (mmap == null)
@@ -373,7 +260,7 @@ namespace Game
{
// allocate mesh query
Detour.dtNavMeshQuery query = new Detour.dtNavMeshQuery();
if (Detour.dtStatusFailed(query.init(mmap.GetNavMesh(swaps), 1024)))
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;
@@ -389,181 +276,21 @@ namespace Game
public uint getLoadedTilesCount() { return loadedTiles; }
public int getLoadedMapsCount() { return loadedMMaps.Count; }
public Dictionary<uint, PhasedTile> GetPhaseTileContainer(uint mapId) { return _phaseTiles.LookupByKey(mapId); }
Dictionary<uint, MMapData> loadedMMaps = new Dictionary<uint, MMapData>();
MultiMap<uint, uint> phaseMapData = new MultiMap<uint, uint>();
Dictionary<uint, Dictionary<uint, PhasedTile>> _phaseTiles = new Dictionary<uint, Dictionary<uint, PhasedTile>>();
uint loadedTiles;
}
public class MMapData
{
public MMapData(Detour.dtNavMesh mesh, uint mapId)
public MMapData(Detour.dtNavMesh mesh)
{
navMesh = mesh;
_mapId = mapId;
}
void RemoveSwap(PhasedTile ptile, uint swap, uint packedXY)
{
uint x = (packedXY >> 16);
uint y = (packedXY & 0x0000FFFF);
if (!loadedPhasedTiles[swap].Contains(packedXY))
{
Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: mmtile {0:D4}[{1:D2}, {2:D2}] unload skipped, due to not loaded", swap, x, y);
return;
}
Detour.dtMeshHeader header = ptile.data.header;
Detour.dtRawTileData data;
// remove old tile
if (Detour.dtStatusFailed(navMesh.removeTile(loadedTileRefs[packedXY], out data)))
Log.outError(LogFilter.Maps, "MMapData.RemoveSwap: Could not unload phased {0:D4}{1:D2}{2:D2}.mmtile from navmesh", swap, x, y);
else
{
Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Unloaded phased {0:D4}{1:D2}{2:D2}.mmtile from navmesh", swap, x, y);
// restore base tile
ulong loadedRef = 0;
if (Detour.dtStatusSucceed(navMesh.addTile(_baseTiles[packedXY].data, 0, 0, ref loadedRef)))
{
Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Loaded base mmtile {0:D4}[{1:D2}, {2:D2}] into {0:D4}[{1:D2}, {2:D2}]", _mapId, x, y, _mapId, header.x, header.y);
}
else
Log.outError(LogFilter.Maps, "MMapData.RemoveSwap: Could not load base {0:D4}{1:D2}{2:D2}.mmtile to navmesh", _mapId, x, y);
loadedTileRefs[packedXY] = loadedRef;
}
loadedPhasedTiles.Remove(swap, packedXY);
if (loadedPhasedTiles[swap].Empty())
{
_activeSwaps.Remove(swap);
Log.outDebug(LogFilter.Maps, "MMapData.RemoveSwap: Fully removed swap {0} from map {1}", swap, _mapId);
}
}
void AddSwap(PhasedTile ptile, uint swap, uint packedXY)
{
uint x = (packedXY >> 16);
uint y = (packedXY & 0x0000FFFF);
if (!loadedTileRefs.ContainsKey(packedXY))
{
Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to not loaded base tile on map {3}", swap, x, y, _mapId);
return;
}
if (loadedPhasedTiles[swap].Contains(packedXY))
{
Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: WARNING! phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to already loaded on map {3}", swap, x, y, _mapId);
return;
}
Detour.dtMeshHeader header = ptile.data.header;
Detour.dtMeshTile oldTile = navMesh.getTileByRef(loadedTileRefs[packedXY]);
if (oldTile == null)
{
Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: phased mmtile {0:D4}[{1:D2}, {2:D2}] load skipped, due to not loaded base tile ref on map {3}", swap, x, y, _mapId);
return;
}
// header xy is based on the swap map's tile set, wich doesn't have all the same tiles as root map, so copy the xy from the orignal header
header.x = oldTile.header.x;
header.y = oldTile.header.y;
Detour.dtRawTileData data;
// remove old tile
if (Detour.dtStatusFailed(navMesh.removeTile(loadedTileRefs[packedXY], out data)))
Log.outError(LogFilter.Maps, "MMapData.AddSwap: Could not unload {0:D4}{1:D2}{2:D2}.mmtile from navmesh", _mapId, x, y);
else
{
Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: Unloaded {0:D4}{1:D2}{2:D2}.mmtile from navmesh", _mapId, x, y);
_activeSwaps.Add(swap);
loadedPhasedTiles.Add(swap, packedXY);
// add new swapped tile
ulong loadedRef = 0;
if (Detour.dtStatusSucceed(navMesh.addTile(ptile.data, 0, 0, ref loadedRef)))
Log.outDebug(LogFilter.Maps, "MMapData.AddSwap: Loaded phased mmtile {0:D4}[{1:D2}, {2:D2}] into {0:D4}[{1:D2}, {2:D2}]", swap, x, y, _mapId, header.x, header.y);
else
Log.outError(LogFilter.Maps, "MMapData.AddSwap: Could not load {0:D4}{1:D2}{2:D2}.mmtile to navmesh", swap, x, y);
loadedTileRefs[packedXY] = loadedRef;
}
}
public Detour.dtNavMesh GetNavMesh(List<uint> swaps)
{
foreach (uint swap in _activeSwaps)
{
if (!swaps.Contains(swap)) // swap not active
{
var ptc = Global.MMapMgr.GetPhaseTileContainer(swap);
foreach (var pair in ptc)
RemoveSwap(pair.Value, swap, pair.Key); // remove swap
}
}
// for each of the calling unit's terrain swaps
foreach (uint swap in swaps)
{
if (!_activeSwaps.Contains(swap)) // swap not active
{
// for each of the terrain swap's xy tiles
var ptc = Global.MMapMgr.GetPhaseTileContainer(swap);
if (ptc != null)
{
foreach (var pair in ptc)
AddSwap(pair.Value, swap, pair.Key); // add swap
}
}
}
return navMesh;
}
public void AddBaseTile(uint packedGridPos, Detour.dtRawTileData data, MmapTileHeader fileHeader, uint dataSize)
{
if (!_baseTiles.ContainsKey(packedGridPos))
{
PhasedTile phasedTile = new PhasedTile();
phasedTile.data = data;
phasedTile.fileHeader = fileHeader;
phasedTile.dataSize = (int)dataSize;
_baseTiles[packedGridPos] = phasedTile;
}
}
public void DeleteBaseTile(uint packedGridPos)
{
var phaseTile = _baseTiles.LookupByKey(packedGridPos);
if (phaseTile != null)
{
_baseTiles.Remove(packedGridPos);
}
}
public Dictionary<uint, Detour.dtNavMeshQuery> navMeshQueries = new Dictionary<uint, Detour.dtNavMeshQuery>(); // instanceId to query
public Detour.dtNavMesh navMesh;
public Dictionary<uint, ulong> loadedTileRefs = new Dictionary<uint, ulong>();
MultiMap<uint, uint> loadedPhasedTiles = new MultiMap<uint, uint>();
uint _mapId;
Dictionary<uint, PhasedTile> _baseTiles = new Dictionary<uint, PhasedTile>();
List<uint> _activeSwaps = new List<uint>();
}
public class PhasedTile
{
public Detour.dtRawTileData data;
public MmapTileHeader fileHeader;
public int dataSize;
public Dictionary<uint, ulong> loadedTileRefs = new Dictionary<uint, ulong>(); // maps [map grid coords] to [dtTile]
}
[StructLayout(LayoutKind.Sequential)]