private CompressedTile GetTileAt(int tx, int ty, int tlayer) { // Find tile based on hash. int h = Detour.ComputeTileHash(tx, ty, m_tileLutMask); var tile = m_posLookup[h]; while (tile != null) { if (tile.Header.TX == tx && tile.Header.TY == ty && tile.Header.TLayer == tlayer) { return(tile); } tile = tile.Next; } return(null); }
public int GetTilesAt(int tx, int ty, out CompressedTile[] tiles, int maxTiles) { tiles = new CompressedTile[maxTiles]; int n = 0; // Find tile based on hash. int h = Detour.ComputeTileHash(tx, ty, m_tileLutMask); var tile = m_posLookup[h]; while (tile != null) { if (tile.Header.TX == tx && tile.Header.TY == ty && n < maxTiles) { tiles[n++] = tile; } tile = tile.Next; } return(n); }
public Status QueryTiles(Vector3 bmin, Vector3 bmax, int maxResults, out CompressedTile[] results, out int resultCount) { results = new CompressedTile[maxResults]; int MAX_TILES = 32; int n = 0; float tw = m_params.Width * m_params.CellSize; float th = m_params.Height * m_params.CellSize; int tx0 = (int)Math.Floor((bmin.X - m_params.Origin.X) / tw); int tx1 = (int)Math.Floor((bmax.X - m_params.Origin.X) / tw); int ty0 = (int)Math.Floor((bmin.Z - m_params.Origin.Z) / th); int ty1 = (int)Math.Floor((bmax.Z - m_params.Origin.Z) / th); for (int ty = ty0; ty <= ty1; ++ty) { for (int tx = tx0; tx <= tx1; ++tx) { int ntiles = GetTilesAt(tx, ty, out CompressedTile[] tiles, MAX_TILES); for (int i = 0; i < ntiles; ++i) { var tile = tiles[i]; CalcTightTileBounds(tile.Header, out Vector3 tbmin, out Vector3 tbmax); if (Detour.OverlapBounds(bmin, bmax, tbmin, tbmax) && n < maxResults) { results[n++] = tiles[i]; } } } } resultCount = n; return(Status.DT_SUCCESS); }
public Node GetNode(int id, int state) { int bucket = Detour.HashRef(id) & (HashSize - 1); int i = First[bucket]; while (i != Detour.DT_NULL_IDX) { if (Nodes[i] != null && Nodes[i].Id == id && Nodes[i].State == state) { return(Nodes[i]); } i = Next[i]; } if (NodeCount >= MaxNodes) { return(null); } i = NodeCount; NodeCount++; // Init node Nodes[i] = new Node { PIdx = 0, Cost = 0, Total = 0, Id = id, State = state, Flags = 0 }; Next[i] = First[bucket]; First[bucket] = i; return(Nodes[i]); }
public int FindNodes(int id, out Node[] nodes, int maxNodes) { nodes = new Node[maxNodes]; int n = 0; int bucket = Detour.HashRef(id) & (HashSize - 1); int i = First[bucket]; while (i != Detour.DT_NULL_IDX) { if (Nodes[i].Id == id) { if (n >= maxNodes) { return(n); } nodes[n++] = Nodes[i]; } i = Next[i]; } return(n); }
public bool BuildNavMeshTile(CompressedTile tile, NavMesh navmesh) { NavMeshTileBuildContext bc = new NavMeshTileBuildContext(); int walkableClimbVx = (int)(m_params.WalkableClimb / m_params.CellHeight); // Decompress tile layer data. if (!DetourTileCache.DecompressTileCacheLayer(tile.Header, tile.Data, 0, out var layer)) { return(false); } bc.Layer = layer; // Rasterize obstacles. for (int i = 0; i < m_params.MaxObstacles; ++i) { var ob = m_obstacles[i]; if (ob.State == ObstacleState.DT_OBSTACLE_EMPTY || ob.State == ObstacleState.DT_OBSTACLE_REMOVING) { continue; } if (DetourTileCache.Contains(ob.Touched, ob.NTouched, tile)) { if (ob.Type == ObstacleType.DT_OBSTACLE_CYLINDER) { DetourTileCache.MarkCylinderArea(bc, tile.Header.BBox.Minimum, m_params.CellSize, m_params.CellHeight, ob.Cylinder.Pos, ob.Cylinder.Radius, ob.Cylinder.Height, 0); } else if (ob.Type == ObstacleType.DT_OBSTACLE_BOX) { DetourTileCache.MarkBoxArea(bc, tile.Header.BBox.Minimum, m_params.CellSize, m_params.CellHeight, ob.Box.BMin, ob.Box.BMax, 0); } else if (ob.Type == ObstacleType.DT_OBSTACLE_ORIENTED_BOX) { DetourTileCache.MarkBoxArea(bc, tile.Header.BBox.Minimum, m_params.CellSize, m_params.CellHeight, ob.OrientedBox.Center, ob.OrientedBox.HalfExtents, ob.OrientedBox.RotAux, 0); } } } // Build navmesh if (!DetourTileCache.BuildTileCacheRegions(bc, walkableClimbVx)) { return(false); } if (!DetourTileCache.BuildTileCacheContours(bc, walkableClimbVx, m_params.MaxSimplificationError)) { return(false); } if (!DetourTileCache.BuildTileCachePolyMesh(bc)) { return(false); } // Early out if the mesh tile is empty. if (bc.LMesh.NPolys == 0) { // Remove existing tile. navmesh.RemoveTile(navmesh.GetTileRefAt(tile.Header.TX, tile.Header.TY, tile.Header.TLayer), null, 0); return(true); } var param = new NavMeshCreateParams { Verts = bc.LMesh.Verts, VertCount = bc.LMesh.NVerts, Polys = bc.LMesh.Polys, PolyAreas = bc.LMesh.Areas, PolyFlags = bc.LMesh.Flags, polyCount = bc.LMesh.NPolys, nvp = Detour.DT_VERTS_PER_POLYGON, walkableHeight = m_params.WalkableHeight, walkableRadius = m_params.WalkableRadius, walkableClimb = m_params.WalkableClimb, tileX = tile.Header.TX, tileY = tile.Header.TY, tileLayer = tile.Header.TLayer, cs = m_params.CellSize, ch = m_params.CellHeight, buildBvTree = false, bmin = tile.Header.BBox.Minimum, bmax = tile.Header.BBox.Maximum, }; if (m_tmproc != null) { m_tmproc.Process(ref param, bc); } if (!Detour.CreateNavMeshData(param, out MeshData navData)) { return(false); } // Remove existing tile. navmesh.RemoveTile(navmesh.GetTileRefAt(tile.Header.TX, tile.Header.TY, tile.Header.TLayer), null, 0); // Add new tile, or leave the location empty. if (navData != null && !navmesh.AddTile(navData, TileFlagTypes.DT_TILE_FREE_DATA, 0, out int result)) { // Let the navmesh own the data. navData = null; return(false); } return(true); }