static bool LoadedTilesCommand(StringArguments args, CommandHandler handler) { Player player = handler.GetSession().GetPlayer(); uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), 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) { handler.SendSysMessage("NavMesh not loaded for current map."); return(true); } handler.SendSysMessage("mmap loadedtiles:"); for (int i = 0; i < navmesh.getMaxTiles(); ++i) { Detour.dtMeshTile tile = navmesh.getTile(i); if (tile.header == null) { continue; } handler.SendSysMessage("[{0:D2}, {1:D2}]", tile.header.x, tile.header.y); } return(true); }
// This function checks if the path has a small U-turn, that is, // a polygon further in the path is adjacent to the first polygon // in the path. If that happens, a shortcut is taken. // This can happen if the target (T) location is at tile boundary, // and we're (S) approaching it parallel to the tile edge. // The choice at the vertex can be arbitrary, // +---+---+ // |:::|:::| // +-S-+-T-+ // |:::| | <-- the step can end up in here, resulting U-turn path. // +---+---+ static int fixupShortcuts(dtPolyRef[] path, int npath, Detour.dtNavMeshQuery navQuery) { if (npath < 3) { return(npath); } // Get connected polygons const int maxNeis = 16; dtPolyRef[] neis = new dtPolyRef[maxNeis]; int nneis = 0; Detour.dtMeshTile tile = null; Detour.dtPoly poly = null; if (Detour.dtStatusFailed(navQuery.getAttachedNavMesh().getTileAndPolyByRef(path[0], ref tile, ref poly))) { return(npath); } for (uint k = poly.firstLink; k != Detour.DT_NULL_LINK; k = tile.links[k].next) { Detour.dtLink link = tile.links[k]; if (link.polyRef != 0) { if (nneis < maxNeis) { neis[nneis++] = link.polyRef; } } } // If any of the neighbour polygons is within the next few polygons // in the path, short cut to that polygon directly. const int maxLookAhead = 6; int cut = 0; for (int i = Math.Min(maxLookAhead, npath) - 1; i > 1 && cut == 0; i--) { for (int j = 0; j < nneis; j++) { if (path[i] == neis[j]) { cut = i; break; } } } if (cut > 1) { int offset = cut - 1; npath -= offset; for (int i = 1; i < npath; i++) { path[i] = path[i + offset]; } } return(npath); }
private void PrepareRender() { // Add to scene after building a mesh vertices = new List <Vertex>(); indices = new List <int>(); for (int i = 0; i < navMesh.getMaxTiles(); ++i) { Detour.dtMeshTile tile = navMesh.getTile(i); if (tile.header != null) { AddMeshTile(tile); } } var geom = new Mesh(); geom.Load(vertices, indices, indices.Count / 3); var mat = new MaterialDiffuse() { ShaderProgram = "diffuse", Tex = "" }; node = new Scene.Node() { Name = "NaviMesh", Material = mat, Mesh = geom }; scene.Add(node); }
static bool LoadedTilesCommand(StringArguments args, CommandHandler handler) { uint mapid = handler.GetPlayer().GetMapId(); Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(mapid); Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(mapid, handler.GetPlayer().GetInstanceId()); if (navmesh == null || navmeshquery == null) { handler.SendSysMessage("NavMesh not loaded for current map."); return(true); } handler.SendSysMessage("mmap loadedtiles:"); for (int i = 0; i < navmesh.getMaxTiles(); ++i) { Detour.dtMeshTile tile = navmesh.getTile(i); if (tile == null) { continue; } handler.SendSysMessage("[{0:D2}, {1:D2}]", tile.header.x, tile.header.y); } return(true); }
public static void ShowTilePolyDetails(DbgRenderMesh renderMesh, Detour.dtNavMesh navMesh, int tileId) { renderMesh.Clear(); UnityEngine.Random.seed = c_RandomSeed; if (navMesh == null) { renderMesh.Rebuild(); return; } Detour.dtMeshTile tile = navMesh.getTile(tileId); if (tile == null) { Debug.LogError("RcdtcsUnityUtils.ShowTilePolyDetails : Tile " + tileId + " does not exist."); return; } int detailMeshCount = tile.detailMeshes.Length; for (int i = 0; i < detailMeshCount; ++i) { Detour.dtPolyDetail pd = tile.detailMeshes[i]; Detour.dtPoly poly = tile.polys[i]; Color col = Color.green; //new Color(UnityEngine.Random.value, UnityEngine.Random.value, UnityEngine.Random.value); for (int j = 0; j < pd.triCount; ++j) { int tStart = (int)(pd.triBase + j) * 4; int[] vStarts = new int[3]; float[][] vSrc = new float[3][]; for (int k = 0; k < 3; ++k) { byte tk = tile.detailTris[tStart + k]; byte vCount = poly.vertCount; if (tk < vCount) { vStarts[k] = poly.verts[tk] * 3; vSrc[k] = tile.verts; } else { vStarts[k] = (int)(pd.vertBase + (tk - vCount)) * 3; vSrc[k] = tile.detailVerts; } } Vector3 a = new Vector3(vSrc[0][vStarts[0] + 0], vSrc[0][vStarts[0] + 1], vSrc[0][vStarts[0] + 2]); Vector3 b = new Vector3(vSrc[1][vStarts[1] + 0], vSrc[1][vStarts[1] + 1], vSrc[1][vStarts[1] + 2]); Vector3 c = new Vector3(vSrc[2][vStarts[2] + 0], vSrc[2][vStarts[2] + 1], vSrc[2][vStarts[2] + 2]); col = VaryColor(col); renderMesh.AddTriangle(new DbgRenderTriangle(a, b, c, col)); } } renderMesh.Rebuild(); }
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; } }
private void AddMeshTile(Detour.dtMeshTile tile) { var basePoly = navMesh.getPolyRefBase(tile); uint tileNum = navMesh.decodePolyIdTile(basePoly); for (int i = 0; i < tile.header.polyCount; ++i) { var p = tile.polys[i]; if (p.getType() == (byte)Detour.dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION) // Skip off-mesh links. { continue; } var pd = tile.detailMeshes[i]; for (int j = 0; j < pd.triCount; ++j) { var triIndex = (pd.triBase + j) * 4; for (int k = 0; k < 3; ++k) { if (tile.detailTris[triIndex + k] < p.vertCount) { var detailIndex = tile.detailTris[triIndex + k]; var vertIndex = p.verts[detailIndex] * 3; var vertex = new Vertex() { Position = new OpenTK.Vector3(tile.verts[vertIndex + 0], tile.verts[vertIndex + 2], tile.verts[vertIndex + 1]), Normal = new OpenTK.Vector3(), Color = new OpenTK.Vector4(0, 0, 1, 1) }; vertices.Add(vertex); indices.Add(vertices.Count - 1); } else { var detailIndex = tile.detailTris[triIndex + k]; var vertIndex = (pd.vertBase + detailIndex - p.vertCount) * 3; var vertex = new Vertex() { Position = new OpenTK.Vector3(tile.detailVerts[vertIndex + 0], tile.detailVerts[vertIndex + 2], tile.detailVerts[vertIndex + 1]), Normal = new OpenTK.Vector3(), Color = new OpenTK.Vector4(0, 0, 1, 1) }; vertices.Add(vertex); indices.Add(vertices.Count - 1); } } } } }
static bool HandleMmapStatsCommand(StringArguments args, CommandHandler handler) { Player player = handler.GetSession().GetPlayer(); uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), 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()); Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId); if (navmesh == null) { handler.SendSysMessage("NavMesh not loaded for current map."); return(true); } uint tileCount = 0; int nodeCount = 0; int polyCount = 0; int vertCount = 0; int triCount = 0; int triVertCount = 0; for (int i = 0; i < navmesh.getMaxTiles(); ++i) { Detour.dtMeshTile tile = navmesh.getTile(i); if (tile == null) { continue; } tileCount++; nodeCount += tile.header.bvNodeCount; polyCount += tile.header.polyCount; vertCount += tile.header.vertCount; triCount += tile.header.detailTriCount; triVertCount += tile.header.detailVertCount; } handler.SendSysMessage("Navmesh stats:"); handler.SendSysMessage(" {0} tiles loaded", tileCount); handler.SendSysMessage(" {0} BVTree nodes", nodeCount); handler.SendSysMessage(" {0} polygons ({1} vertices)", polyCount, vertCount); handler.SendSysMessage(" {0} triangles ({1} vertices)", triCount, triVertCount); return(true); }
static bool LocCommand(StringArguments args, CommandHandler handler) { handler.SendSysMessage("mmap tileloc:"); // grid tile location Player player = handler.GetPlayer(); int gx = (int)(32 - player.GetPositionX() / MapConst.SizeofGrids); int gy = (int)(32 - player.GetPositionY() / MapConst.SizeofGrids); float x, y, z; player.GetPosition(out x, out y, out z); handler.SendSysMessage("{0:D4}{1:D2}{2:D2}.mmtile", player.GetMapId(), gy, gx); handler.SendSysMessage("gridloc [{0}, {1}]", gx, gy); // calculate navmesh tile location uint terrainMapId = PhasingHandler.GetTerrainMapId(player.GetPhaseShift(), player.GetMap(), x, y); Detour.dtNavMesh navmesh = Global.MMapMgr.GetNavMesh(terrainMapId); Detour.dtNavMeshQuery navmeshquery = Global.MMapMgr.GetNavMeshQuery(terrainMapId, player.GetInstanceId()); if (navmesh == null || navmeshquery == null) { handler.SendSysMessage("NavMesh not loaded for current map."); return(true); } float[] min = navmesh.getParams().orig; float[] location = { y, z, x }; float[] extents = { 3.0f, 5.0f, 3.0f }; int tilex = (int)((y - min[0]) / MapConst.SizeofGrids); int tiley = (int)((x - min[2]) / MapConst.SizeofGrids); handler.SendSysMessage("Calc [{0:D2}, {1:D2}]", tilex, tiley); // navmesh poly . navmesh tile location Detour.dtQueryFilter filter = new Detour.dtQueryFilter(); float[] nothing = new float[3]; ulong polyRef = 0; if (Detour.dtStatusFailed(navmeshquery.findNearestPoly(location, extents, filter, ref polyRef, ref nothing))) { handler.SendSysMessage("Dt [??,??] (invalid poly, probably no tile loaded)"); return(true); } if (polyRef == 0) { handler.SendSysMessage("Dt [??, ??] (invalid poly, probably no tile loaded)"); } else { Detour.dtMeshTile tile = new Detour.dtMeshTile(); Detour.dtPoly poly = new Detour.dtPoly(); if (Detour.dtStatusSucceed(navmesh.getTileAndPolyByRef(polyRef, ref tile, ref poly))) { if (tile != null) { handler.SendSysMessage("Dt [{0:D2},{1:D2}]", tile.header.x, tile.header.y); return(false); } } handler.SendSysMessage("Dt [??,??] (no tile loaded)"); } return(true); }