private void CollectEdgesBetweenFloorLists(int bx, int by, List <NavMeshBuilderFloorDesc> center, int nx, int ny, Dictionary <EdgeVertex, List <EdgeVertex> > edgesOut) { List <NavMeshBuilderFloorDesc> neighbor = GetFloorDescListNoCheck(nx, ny); if (neighbor == null) { return; } var directionToNeighbor = NavMeshUtil.DetermineDirection(bx, by, nx, ny); var directionFromNeighbor = NavMeshUtil.GetInverseDirection(directionToNeighbor); foreach (var floor in center) { // check if direction to neighbor is blocked. if ((floor.DirectionFlags & directionToNeighbor) != 0) { continue; } List <EdgeVertex> list = null; foreach (var neighborFloor in neighbor) { // check if direction from neighbor is blocked. if ((neighborFloor.DirectionFlags & directionFromNeighbor) != 0) { continue; } if (Math.Abs(floor.Z100i - neighborFloor.Z100i) / 100.0f > m_maxZStep) { continue; } if (list == null) { var p0 = new EdgeVertex { BX = (ushort)bx, BY = (ushort)by, Z100i = floor.Z100i }; if (!edgesOut.TryGetValue(p0, out list)) { list = new List <EdgeVertex>(); edgesOut.Add(p0, list); } } list.Add(new EdgeVertex { BX = (ushort)nx, BY = (ushort)ny, Z100i = neighborFloor.Z100i }); break; // each floor connects to 0 or 1 neighbor in 1 direction. } } }
// WARNING! on failure, m_floorData will be left in a bad state. private void FixDirectionFlagsToMatchSubgraphs(Dictionary <EdgeVertex, List <EdgeVertex> > edges, List <HashSet <EdgeVertex> > subgraphs) { // mark all directions as blocked, then for each subgraph // visit edges/vertices and unblock directions. // clear all to 'blocked' foreach (var fl in m_floorData) { if (fl != null) { for (int i = 0; i < fl.Count; i++) { fl[i] = new NavMeshBuilderFloorDesc(fl[i].Z100i, 0xFF); } } } foreach (var sg in subgraphs) { foreach (var v in sg) { var neighborEdges = edges[v]; foreach (var n in neighborEdges) { var dirToNeighbor = NavMeshUtil.DetermineDirection(v.BX, v.BY, n.BX, n.BY); var dirFromNeighbor = NavMeshUtil.GetInverseDirection(dirToNeighbor); // update 'to' neighbor // need to find which floor data entry is mine var meContainedInList = m_floorData[v.BY * m_blockWidth + v.BX]; // next, find me bool foundMe = false; for (int j = 0; j < meContainedInList.Count; j++) { if (meContainedInList[j].Z100i == v.Z100i) { // unblock me to neighbor meContainedInList[j] = new NavMeshBuilderFloorDesc(v.Z100i, (byte)(meContainedInList[j].DirectionFlags & ~dirToNeighbor)); foundMe = true; break; } } if (!foundMe) { throw new InvalidOperationException("vertex should exist in floor data!"); } // update 'from' neighbor var neighborContainedInList = m_floorData[n.BY * m_blockWidth + n.BX]; bool foundNeighbor = false; for (int j = 0; j < neighborContainedInList.Count; j++) { if (neighborContainedInList[j].Z100i == n.Z100i) { // unblock neighbor to me neighborContainedInList[j] = new NavMeshBuilderFloorDesc(n.Z100i, (byte)(neighborContainedInList[j].DirectionFlags & ~dirFromNeighbor)); foundNeighbor = true; break; } } if (!foundNeighbor) { throw new InvalidOperationException("neighbor vertex should exist in floor data!"); } } } } }