void FixupDoorStates(ModuleBuildNode rootNode) { var moduleConnections = new Dictionary <GameObject, SnapConnection[]>(); TraverseTree(rootNode, delegate(ModuleBuildNode node) { if (!moduleConnections.ContainsKey(node.spawnedModule)) { var connections = node.spawnedModule.GetComponentsInChildren <SnapConnection>(); moduleConnections.Add(node.spawnedModule, connections); } }); // Set everything to wall foreach (var connections in moduleConnections.Values) { foreach (var connection in connections) { connection.UpdateDoorState(false); } } var stack = new Stack <ModuleBuildNode>(); stack.Push(rootNode); while (stack.Count > 0) { ModuleBuildNode top = stack.Pop(); if (top == null) { continue; } ModuleBuildNode parent = top.Parent; if (parent != null) { if (top.spawnedModule != null && parent.spawnedModule != null) { int ParentDoorIndex = top.IncomingDoorIndex; int TopDoorIndex = top.AttachmentConfig.AttachedModuleDoorIndex; var parentConnection = GetArrayEntry <SnapConnection>(ParentDoorIndex, moduleConnections[parent.spawnedModule]); var topConnection = GetArrayEntry <SnapConnection>(TopDoorIndex, moduleConnections[top.spawnedModule]); if (parentConnection != null) { parentConnection.UpdateDoorState(true); } if (topConnection != null) { topConnection.UpdateDoorState(true); } } } foreach (var extension in top.Extensions) { stack.Push(extension); } } }
static void CalculateOccupiedBounds(ModuleBuildNode Node, List <Bounds> OccupiedBounds) { if (Node == null) { return; } OccupiedBounds.Add(Node.AttachmentConfig.AttachedModuleWorldBounds); foreach (var ChildNode in Node.Extensions) { CalculateOccupiedBounds(ChildNode, OccupiedBounds); } }
void TraverseTree(ModuleBuildNode RootNode, VisitTreeNodeDelegate VisitTreeNode) { var stack = new Stack <ModuleBuildNode>(); stack.Push(RootNode); while (stack.Count > 0) { ModuleBuildNode Top = stack.Pop(); if (Top == null) { continue; } VisitTreeNode(Top); // Add children foreach (ModuleBuildNode Extension in Top.Extensions) { stack.Push(Extension); } } }
ModuleBuildNode BuildLayoutRecursive(ModuleGrowthNode GrowthNode, List <Bounds> OccupiedBounds, int DepthFromStart, int DesiredDepth, bool bMainBranch, bool bForceIgnoreEndModule, SnapLayoutBuildState RecursiveState) { if (RecursiveState.NumTries >= snapConfig.MaxProcessingPower) { return(null); } RecursiveState.NumTries++; if (DepthFromStart > DesiredDepth) { return(null); } ModuleGrowthNode Top = GrowthNode; // Pick a door from this module to extend int BestValidMainBranchDifference = int.MaxValue; ModuleBuildNode BestBuildNode = null; int SnapModuleListLength = RecursiveState.ModuleInfoList.Count; int[] ShuffledIndices = MathUtils.GetShuffledIndices(SnapModuleListLength, random); for (int si = 0; si < ShuffledIndices.Length; si++) { int Index = ShuffledIndices[si]; ModuleInfo Module = RecursiveState.ModuleInfoList[Index]; var AttachmentConfig = new SnapAttachmentConfiguration(); if (!FindAttachmentConfiguration(Module, Top.IncomingModule, ref Top.ModuleTransform, Top.IncomingModuleDoorIndex, OccupiedBounds, ref AttachmentConfig)) { continue; } var BuildNode = new ModuleBuildNode(); BuildNode.AttachmentConfig = AttachmentConfig; BuildNode.IncomingDoorIndex = Top.IncomingModuleDoorIndex; BuildNode.Module = Module; if (DepthFromStart == DesiredDepth) { // This has to be the leaf node return(BuildNode); } if (BestBuildNode == null) { BestBuildNode = BuildNode; } // We found a valid module. Use this OccupiedBounds.Add(AttachmentConfig.AttachedModuleWorldBounds); int AttachmentDoorIndex = AttachmentConfig.AttachedModuleDoorIndex; // Extend from this door further for (int ExtensionDoorIndex = 0; ExtensionDoorIndex < Module.ConnectionTransforms.Length; ExtensionDoorIndex++) { if (ExtensionDoorIndex == AttachmentDoorIndex && Top.IncomingModuleDoorIndex != -1) { // Don't want to extend from the door we came in through continue; } int ModuleCountContribution = 1; // Grow this branch further var NextNode = new ModuleGrowthNode(); NextNode.IncomingModuleDoorIndex = ExtensionDoorIndex; NextNode.ModuleTransform = AttachmentConfig.AttachedModuleTransform; NextNode.IncomingModule = Module; ModuleBuildNode ExtensionNode = BuildLayoutRecursive(NextNode, OccupiedBounds, DepthFromStart + ModuleCountContribution, DesiredDepth, bMainBranch, false, RecursiveState); if (ExtensionNode != null) { int BranchLength = DepthFromStart + ExtensionNode.DepthFromLeaf; int ValidDistanceDifference = Mathf.Abs(BranchLength - DesiredDepth); if (ValidDistanceDifference < BestValidMainBranchDifference || RecursiveState.bFoundBestBuild) { BestValidMainBranchDifference = ValidDistanceDifference; BuildNode.Extensions.Clear(); ExtensionNode.Parent = BuildNode; BuildNode.Extensions.Add(ExtensionNode); BuildNode.DepthFromLeaf = Mathf.Max(BuildNode.DepthFromLeaf, ExtensionNode.DepthFromLeaf + ModuleCountContribution); BestBuildNode = BuildNode; } if (BranchLength >= DesiredDepth) { // We found a branch with the desired length RecursiveState.bFoundBestBuild = true; } if (RecursiveState.bFoundBestBuild) { break; } } } // Remove it since we move out OccupiedBounds.Remove(AttachmentConfig.AttachedModuleWorldBounds); if (RecursiveState.bFoundBestBuild) { break; } } return(BestBuildNode); }
// This is called by the builders that do not support theming public override void BuildNonThemedDungeon(DungeonSceneProvider sceneProvider) { random = new System.Random((int)config.Seed); propSockets.Clear(); // We know that the dungeon prefab would have the appropriate config and models attached to it // Cast and save it for future reference snapConfig = config as SnapConfig; snapModel = model as SnapModel; if (snapConfig == null) { Debug.LogError("No snap config script found in dungeon game object"); return; } if (snapModel == null) { Debug.LogError("No snap model script found in dungeon game object"); return; } // Generate the module info list var ModuleInfos = new List <ModuleInfo>(); { var RegisteredModuleList = new List <GameObject>(); RegisteredModuleList.AddRange(snapConfig.Modules); RegisteredModuleList.AddRange(snapConfig.StartModules); RegisteredModuleList.AddRange(snapConfig.EndModules); RegisteredModuleList.AddRange(snapConfig.BranchEndModules); var RegisteredModules = new HashSet <GameObject>(RegisteredModuleList); foreach (var RegisteredModule in RegisteredModules) { var moduleInfo = GenerateModuleInfo(RegisteredModule); ModuleInfos.Add(moduleInfo); } } var StartNode = new ModuleGrowthNode(); StartNode.IncomingModuleDoorIndex = -1; StartNode.startNode = true; StartNode.ModuleTransform = Matrix4x4.identity; var OccupiedBounds = new List <Bounds>(); var LayoutBuildState = new SnapLayoutBuildState(); LayoutBuildState.ModuleInfoList = ModuleInfos; // Build the main branch ModuleBuildNode BuildNode = BuildLayoutRecursive(StartNode, OccupiedBounds, 1, snapConfig.MainBranchSize, true, false, LayoutBuildState); // Build the side branches { var MainBranchNodes = new List <ModuleBuildNode>(); // Grab the nodes in the main branch { ModuleBuildNode BranchNode = BuildNode; while (BranchNode != null) { BranchNode.bMainBranch = true; MainBranchNodes.Add(BranchNode); // Move forward if (BranchNode.Extensions.Count == 0) { break; } BranchNode = BranchNode.Extensions[0]; } } // Iterate through the nodes in the main branch and start branching out for (int i = 0; i < MainBranchNodes.Count; i++) { ModuleBuildNode BranchStartNode = MainBranchNodes[i]; ModuleBuildNode BranchNextNode = i + 1 < MainBranchNodes.Count ? MainBranchNodes[i + 1] : null; ModuleInfo BranchModule = BranchStartNode.Module; int IncomingDoorIndex = BranchStartNode.IncomingDoorIndex; int OutgoingDoorIndex = BranchNextNode != null ? BranchNextNode.IncomingDoorIndex : -1; int NumDoors = BranchModule.ConnectionTransforms.Length; for (int DoorIndex = 0; DoorIndex < NumDoors; DoorIndex++) { if (DoorIndex == IncomingDoorIndex || DoorIndex == OutgoingDoorIndex) { // These doors are already extended continue; } bool bGrowFromHere = (random.NextFloat() < snapConfig.SideBranchProbability); if (!bGrowFromHere) { continue; } // TODO: Optimize me. it recalculates the the bounds for the whole tree for every main branch node OccupiedBounds.Clear(); CalculateOccupiedBounds(BuildNode, OccupiedBounds); var BranchGrowNode = new ModuleGrowthNode(); BranchGrowNode.IncomingModuleDoorIndex = DoorIndex; BranchGrowNode.IncomingModule = BranchStartNode.Module; BranchGrowNode.ModuleTransform = BranchStartNode.AttachmentConfig.AttachedModuleTransform; LayoutBuildState = new SnapLayoutBuildState(); LayoutBuildState.ModuleInfoList = ModuleInfos; ModuleBuildNode BranchBuildNode = BuildLayoutRecursive(BranchGrowNode, OccupiedBounds, 1, snapConfig.SideBranchSize, false, false, LayoutBuildState); if (BranchBuildNode != null) { // Make sure we don't end up with an undesirable leaf node if (BranchBuildNode.Extensions.Count == 0 && BranchBuildNode.Module != null && snapConfig.SideBranchSize > 1) { continue; } BranchBuildNode.Parent = BranchStartNode; BranchStartNode.Extensions.Add(BranchBuildNode); } } } } snapModel.ResetModel(); sceneProvider.OnDungeonBuildStart(); // Spawn the modules and register them in the model { var spawnedModuleList = new List <SnapModule>(); TraverseTree(BuildNode, delegate(ModuleBuildNode Node) { // Spawn a module at this location ModuleInfo moduleInfo = Node.Module; var templateInfo = new GameObjectPropTypeData(); templateInfo.Template = moduleInfo.ModuleTemplate; templateInfo.NodeId = moduleInfo.ModuleGuid.ToString(); templateInfo.Offset = Matrix4x4.identity; templateInfo.IsStaticObject = true; Node.spawnedModule = sceneProvider.AddGameObject(templateInfo, Node.AttachmentConfig.AttachedModuleTransform); // Register this in the model var snapModule = new SnapModule(); snapModule.InstanceID = Node.ModuleInstanceID; spawnedModuleList.Add(snapModule); }); snapModel.modules = spawnedModuleList.ToArray(); } // Generate the list of connections { var connectionList = new List <SnapModuleConnection>(); TraverseTree(BuildNode, delegate(ModuleBuildNode Node) { if (Node.Parent != null) { var Connection = new SnapModuleConnection(); Connection.ModuleAInstanceID = Node.ModuleInstanceID; Connection.DoorAIndex = Node.AttachmentConfig.AttachedModuleDoorIndex; Connection.ModuleBInstanceID = Node.Parent.ModuleInstanceID; Connection.DoorBIndex = Node.IncomingDoorIndex; connectionList.Add(Connection); } }); snapModel.connections = connectionList.ToArray(); } sceneProvider.OnDungeonBuildStop(); FixupDoorStates(BuildNode); }