Core/MMaps: Improve mmap debugging experience for terrain swap maps

* Output terrain map id in `.mmap loc` command
* Suppress file not found errors for terrain swap maps
* Fix generating single tiles for terrain swap maps (--tile argument)
Port From (https://github.com/TrinityCore/TrinityCore/commit/6b41c3d3274653605b42f1144f554fe43eee344e)
This commit is contained in:
Hondacrx
2025-12-08 14:48:05 -05:00
parent 34e6130754
commit cef7237f8a
3 changed files with 69 additions and 34 deletions
+4 -3
View File
@@ -90,11 +90,12 @@ namespace Game.Chat
float x, y, z; float x, y, z;
player.GetPosition(out x, out y, out z); player.GetPosition(out x, out y, out z);
handler.SendSysMessage("{0:D4}{1:D2}{2:D2}.mmtile", player.GetMapId(), gy, gx);
handler.SendSysMessage("tileloc [{0}, {1}]", gx, gy);
// calculate navmesh tile location // calculate navmesh tile location
uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMapId(), player.GetMap().GetTerrain(), x, y); uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMapId(), player.GetMap().GetTerrain(), x, y);
handler.SendSysMessage($"{terrainMapId:D4}{gx:D2}{gy:D2}.mmtile");
handler.SendSysMessage($"tileloc [{gy}, {gx}]");
Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId); Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId);
Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, player.GetMapId(), player.GetInstanceId()); Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, player.GetMapId(), player.GetInstanceId());
if (navmesh == null || navmeshquery == null) if (navmesh == null || navmeshquery == null)
+41 -18
View File
@@ -27,18 +27,18 @@ namespace Game
return loadedMMaps.LookupByKey(mapId); return loadedMMaps.LookupByKey(mapId);
} }
bool LoadMapData(string basePath, uint mapId) LoadResult LoadMapData(string basePath, uint mapId)
{ {
// we already have this map loaded? // we already have this map loaded?
if (loadedMMaps.ContainsKey(mapId) && loadedMMaps[mapId] != null) if (loadedMMaps.ContainsKey(mapId) && loadedMMaps[mapId] != null)
return true; return LoadResult.AlreadyLoaded;
// load and init dtNavMesh - read parameters from file // load and init dtNavMesh - read parameters from file
string filename = string.Format(MAP_FILE_NAME_FORMAT, basePath, mapId); string filename = string.Format(MAP_FILE_NAME_FORMAT, basePath, mapId);
if (!File.Exists(filename)) if (!File.Exists(filename))
{ {
Log.outError(LogFilter.Maps, "Could not open mmap file {0}", filename); Log.outError(LogFilter.Maps, $"Could not open mmap file {filename}");
return false; return LoadResult.FileNotFound;
} }
using BinaryReader reader = new(new FileStream(filename, FileMode.Open, FileAccess.Read), Encoding.UTF8); using BinaryReader reader = new(new FileStream(filename, FileMode.Open, FileAccess.Read), Encoding.UTF8);
@@ -56,14 +56,14 @@ namespace Game
if (Detour.dtStatusFailed(mesh.init(Params))) if (Detour.dtStatusFailed(mesh.init(Params)))
{ {
Log.outError(LogFilter.Maps, "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {0:D4} from file {1}", mapId, filename); Log.outError(LogFilter.Maps, "MMAP:loadMapData: Failed to initialize dtNavMesh for mmap {0:D4} from file {1}", mapId, filename);
return false; return LoadResult.LibraryError;
} }
Log.outInfo(LogFilter.Maps, "MMAP:loadMapData: Loaded {0:D4}.mmap", mapId); Log.outInfo(LogFilter.Maps, "MMAP:loadMapData: Loaded {0:D4}.mmap", mapId);
// store inside our map list // store inside our map list
loadedMMaps[mapId] = new MMapData(mesh); loadedMMaps[mapId] = new MMapData(mesh);
return true; return LoadResult.Success;
} }
uint PackTileID(int x, int y) uint PackTileID(int x, int y)
@@ -71,11 +71,18 @@ namespace Game
return (uint)(x << 16 | y); return (uint)(x << 16 | y);
} }
public bool LoadMap(string basePath, uint mapId, int x, int y) public LoadResult LoadMap(string basePath, uint mapId, int x, int y)
{ {
// make sure the mmap is loaded and ready to load tiles // make sure the mmap is loaded and ready to load tiles
if (!LoadMapData(basePath, mapId)) LoadResult mapResult = LoadMapData(basePath, mapId);
return false; switch (mapResult)
{
case LoadResult.Success:
case LoadResult.AlreadyLoaded:
break;
default:
return mapResult;
}
// get this mmap data // get this mmap data
MMapData mmap = loadedMMaps[mapId]; MMapData mmap = loadedMMaps[mapId];
@@ -84,7 +91,7 @@ namespace Game
// check if we already have this tile loaded // check if we already have this tile loaded
uint packedGridPos = PackTileID(x, y); uint packedGridPos = PackTileID(x, y);
if (mmap.loadedTileRefs.ContainsKey(packedGridPos)) if (mmap.loadedTileRefs.ContainsKey(packedGridPos))
return false; return LoadResult.AlreadyLoaded;
// load this tile . mmaps/MMMXXYY.mmtile // load this tile . mmaps/MMMXXYY.mmtile
string fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, mapId, x, y); string fileName = string.Format(TILE_FILE_NAME_FORMAT, basePath, mapId, x, y);
@@ -95,9 +102,9 @@ namespace Game
} }
if (!File.Exists(fileName)) if (!File.Exists(fileName))
{ {
Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", fileName); Log.outDebug(LogFilter.Maps, "MMAP:loadMap: Could not open mmtile file '{0}'", fileName);
return false; return LoadResult.FileNotFound;
} }
using BinaryReader reader = new(new FileStream(fileName, FileMode.Open, FileAccess.Read)); using BinaryReader reader = new(new FileStream(fileName, FileMode.Open, FileAccess.Read));
@@ -105,13 +112,13 @@ namespace Game
if (fileHeader.mmapMagic != MapConst.mmapMagic) if (fileHeader.mmapMagic != MapConst.mmapMagic)
{ {
Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y); Log.outError(LogFilter.Maps, "MMAP:loadMap: Bad header in mmap {0:D4}{1:D2}{2:D2}.mmtile", mapId, x, y);
return false; return LoadResult.VersionMismatch;
} }
if (fileHeader.mmapVersion != MapConst.mmapVersion) if (fileHeader.mmapVersion != MapConst.mmapVersion)
{ {
Log.outError(LogFilter.Maps, "MMAP:loadMap: {0:D4}{1:D2}{2:D2}.mmtile was built with generator v{3}, expected v{4}", Log.outError(LogFilter.Maps, "MMAP:loadMap: {0:D4}{1:D2}{2:D2}.mmtile was built with generator v{3}, expected v{4}",
mapId, x, y, fileHeader.mmapVersion, MapConst.mmapVersion); mapId, x, y, fileHeader.mmapVersion, MapConst.mmapVersion);
return false; return LoadResult.VersionMismatch;
} }
var bytes = reader.ReadBytes((int)fileHeader.size); var bytes = reader.ReadBytes((int)fileHeader.size);
@@ -125,17 +132,23 @@ namespace Game
mmap.loadedTileRefs.Add(packedGridPos, tileRef); mmap.loadedTileRefs.Add(packedGridPos, tileRef);
++loadedTiles; ++loadedTiles;
Log.outInfo(LogFilter.Maps, "MMAP:loadMap: Loaded mmtile {0:D4}[{1:D2}, {2:D2}]", mapId, x, y); Log.outInfo(LogFilter.Maps, "MMAP:loadMap: Loaded mmtile {0:D4}[{1:D2}, {2:D2}]", mapId, x, y);
return true; return LoadResult.Success;
} }
Log.outError(LogFilter.Maps, "MMAP:loadMap: Could not load {0:D4}{1:D2}{2:D2}.mmtile into navmesh", mapId, x, y); Log.outError(LogFilter.Maps, "MMAP:loadMap: Could not load {0:D4}{1:D2}{2:D2}.mmtile into navmesh", mapId, x, y);
return false; return LoadResult.LibraryError;
} }
public bool LoadMapInstance(string basePath, uint meshMapId, uint instanceMapId, uint instanceId) public bool LoadMapInstance(string basePath, uint meshMapId, uint instanceMapId, uint instanceId)
{ {
if (!LoadMapData(basePath, meshMapId)) switch (LoadMapData(basePath, meshMapId))
return false; {
case LoadResult.Success:
case LoadResult.AlreadyLoaded:
break;
default:
return false;
}
MMapData mmap = loadedMMaps[meshMapId]; MMapData mmap = loadedMMaps[meshMapId];
if (mmap.navMeshQueries.ContainsKey((instanceMapId, instanceId))) if (mmap.navMeshQueries.ContainsKey((instanceMapId, instanceId)))
@@ -297,4 +310,14 @@ namespace Game
public uint size; public uint size;
public byte usesLiquids; public byte usesLiquids;
} }
enum LoadResult
{
Success,
AlreadyLoaded,
FileNotFound,
VersionMismatch,
ReadFromFileFailed,
LibraryError
}
} }
+24 -13
View File
@@ -346,11 +346,22 @@ namespace Game.Maps
if (!Global.DisableMgr.IsPathfindingEnabled(GetId())) if (!Global.DisableMgr.IsPathfindingEnabled(GetId()))
return; return;
bool mmapLoadResult = Global.MMapMgr.LoadMap(Global.WorldMgr.GetDataPath(), GetId(), gx, gy); LoadResult mmapLoadResult = Global.MMapMgr.LoadMap(Global.WorldMgr.GetDataPath(), GetId(), gx, gy);
if (mmapLoadResult) switch (mmapLoadResult)
Log.outDebug(LogFilter.Maps, $"MMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy})"); {
else case LoadResult.Success:
Log.outWarn(LogFilter.Maps, $"Could not load MMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy})"); Log.outDebug(LogFilter.Maps, $"MMAP loaded name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy})");
break;
case LoadResult.AlreadyLoaded:
break;
case LoadResult.FileNotFound:
if (_parentTerrain != null)
break; // don't log tile not found errors for child maps
goto default;
default:
Log.outWarn(LogFilter.Maps, $"Could not load MMAP name:{GetMapName()}, id:{GetId()}, x:{gx}, y:{gy} (mmap rep.: x:{gx}, y:{gy}) result: {mmapLoadResult}");
break;
}
} }
public void UnloadMap(int gx, int gy) public void UnloadMap(int gx, int gy)
@@ -703,18 +714,18 @@ namespace Game.Maps
{ {
if (hasDynamicAreaInfo && ddata.floorZ > vdata.floorZ) if (hasDynamicAreaInfo && ddata.floorZ > vdata.floorZ)
{ {
check_z = ddata.floorZ; check_z = ddata.floorZ;
groupId = ddata.areaInfo.GroupId; groupId = ddata.areaInfo.GroupId;
adtId = ddata.areaInfo.AdtId; adtId = ddata.areaInfo.AdtId;
rootId = ddata.areaInfo.RootId; rootId = ddata.areaInfo.RootId;
mogpflags = ddata.areaInfo.MogpFlags; mogpflags = ddata.areaInfo.MogpFlags;
} }
else else
{ {
check_z = vdata.floorZ; check_z = vdata.floorZ;
groupId = vdata.areaInfo.GroupId; groupId = vdata.areaInfo.GroupId;
adtId = vdata.areaInfo.AdtId; adtId = vdata.areaInfo.AdtId;
rootId = vdata.areaInfo.RootId; rootId = vdata.areaInfo.RootId;
mogpflags = vdata.areaInfo.MogpFlags; mogpflags = vdata.areaInfo.MogpFlags;
} }
} }