void ConnectIslandRecursive(int IslandId, Dictionary <int, List <FloorIslandAdjacency> > AdjacencyByIslands, HashSet <int> IslandVisited, System.Random random, FloorDoorManager DoorManager, Dictionary <int, FloorChunk> IslandToChunkMap) { if (IslandVisited.Contains(IslandId)) { return; } IslandVisited.Add(IslandId); if (!AdjacencyByIslands.ContainsKey(IslandId)) { // No adjacent islands return; } List <FloorIslandAdjacency> AdjacentNodes = AdjacencyByIslands[IslandId]; HashSet <int> AdjacentIslands = new HashSet <int>(); foreach (FloorIslandAdjacency AdjacentNode in AdjacentNodes) { AdjacentIslands.Add(AdjacentNode.A.IslandId); AdjacentIslands.Add(AdjacentNode.B.IslandId); } AdjacentIslands.Remove(IslandId); IslandNodePriorityPredicate SortPredicate = new IslandNodePriorityPredicate(IslandToChunkMap); int[] AdjacentIslandArray = new List <int>(AdjacentIslands).ToArray(); System.Array.Sort(AdjacentIslandArray, SortPredicate); foreach (int AdjacentIsland in AdjacentIslandArray) { if (IslandVisited.Contains(AdjacentIsland)) { continue; } // Find all the adjacent cells between these two islands List <FloorIslandAdjacency> EdgeNodes = new List <FloorIslandAdjacency>(); foreach (FloorIslandAdjacency AdjacentNode in AdjacentNodes) { if (AdjacentNode.A.IslandId == AdjacentIsland || AdjacentNode.B.IslandId == AdjacentIsland) { EdgeNodes.Add(AdjacentNode); } } // Connect a door in any one of the edge nodes if (EdgeNodes.Count > 0) { int Index = random.Next(0, EdgeNodes.Count); FloorIslandAdjacency DoorEdge = EdgeNodes[Index]; // Create a door here DoorManager.RegisterDoor(DoorEdge.A.Location, DoorEdge.B.Location); // Move into this room now ConnectIslandRecursive(AdjacentIsland, AdjacencyByIslands, IslandVisited, random, DoorManager, IslandToChunkMap); } } }
void CreateDoors(int y) { // Tag all islands // Create adjacency list // Do a DFS on the tagged islands and connect the islands with doors HashSet <IntVector> Visited = new HashSet <IntVector>(); List <FloorIslandNode> IslandNodes = new List <FloorIslandNode>(); int TotalIslands = 0; // Tag islands with a flood fill. This helps if custom volume split existing // rooms into multiple parts and needs to be treated separately (islands) { int IslandId = 0; for (int x = 0; x < floorPlanConfig.BuildingSize.x; x++) { for (int z = 0; z < floorPlanConfig.BuildingSize.z; z++) { IntVector Location = new IntVector(x, y, z); if (!Visited.Contains(Location)) { // Flood fill from here Visited.Add(Location); FloodFill(Location, IslandId, Visited, IslandNodes, ChunkDB); IslandId++; } } } TotalIslands = IslandId; } // Create a node map for faster access Dictionary <IntVector, FloorIslandNode> IslandNodeByLocation = new Dictionary <IntVector, FloorIslandNode>(); foreach (FloorIslandNode Node in IslandNodes) { if (Node.IslandId == -1) { continue; } IslandNodeByLocation.Add(Node.Location, Node); } // Create adjacency list for each island List <FloorIslandAdjacency> AdjacencyList = new List <FloorIslandAdjacency>(); for (int x = 0; x < floorPlanConfig.BuildingSize.x; x++) { for (int z = 0; z < floorPlanConfig.BuildingSize.z; z++) { IntVector Loc00 = new IntVector(x, y, z); if (!IslandNodeByLocation.ContainsKey(Loc00)) { continue; } FloorIslandNode Node00 = IslandNodeByLocation[Loc00]; if (Node00.IslandId == -1) { continue; } // Test along the left cell { IntVector Loc10 = new IntVector(x + 1, y, z); if (IslandNodeByLocation.ContainsKey(Loc10)) { FloorIslandNode Node10 = IslandNodeByLocation[Loc10]; if (Node10.IslandId != -1 && Node00.IslandId != Node10.IslandId) { // Different adjacent nodes. Add to the list FloorIslandAdjacency Adjacency = new FloorIslandAdjacency(); Adjacency.A = Node00; Adjacency.B = Node10; AdjacencyList.Add(Adjacency); } } } // Test along the bottom cell { IntVector Loc01 = new IntVector(x, y, z + 1); if (IslandNodeByLocation.ContainsKey(Loc01)) { FloorIslandNode Node01 = IslandNodeByLocation[Loc01]; if (Node01.IslandId != -1 && Node00.IslandId != Node01.IslandId) { // Different adjacent nodes. Add to the list FloorIslandAdjacency Adjacency = new FloorIslandAdjacency(); Adjacency.A = Node00; Adjacency.B = Node01; AdjacencyList.Add(Adjacency); } } } } } // Create another lookup for faster access Dictionary <int, List <FloorIslandAdjacency> > AdjacencyByIsland = new Dictionary <int, List <FloorIslandAdjacency> >(); foreach (FloorIslandAdjacency Adjacency in AdjacencyList) { int IslandA = Adjacency.A.IslandId; int IslandB = Adjacency.B.IslandId; if (!AdjacencyByIsland.ContainsKey(IslandA)) { AdjacencyByIsland.Add(IslandA, new List <FloorIslandAdjacency>()); } if (!AdjacencyByIsland.ContainsKey(IslandB)) { AdjacencyByIsland.Add(IslandB, new List <FloorIslandAdjacency>()); } AdjacencyByIsland[IslandA].Add(Adjacency); AdjacencyByIsland[IslandB].Add(Adjacency); } Dictionary <int, FloorChunk> IslandToChunkMap = new Dictionary <int, FloorChunk>(); foreach (FloorIslandNode IslandNode in IslandNodes) { if (IslandToChunkMap.ContainsKey(IslandNode.IslandId)) { continue; } IslandToChunkMap.Add(IslandNode.IslandId, IslandNode.Chunk); } // Connect the islands to the main network with doors HashSet <int> IslandVisited = new HashSet <int>(); for (int IslandId = 0; IslandId < TotalIslands; IslandId++) { ConnectIslandRecursive(IslandId, AdjacencyByIsland, IslandVisited, random, DoorManager, IslandToChunkMap); } }