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); }
bool FindAttachmentConfiguration(ModuleInfo TargetModule, ModuleInfo IncomingModule, ref Matrix4x4 IncomingModuleTransform, int IncomingDoorIndex, List <Bounds> OccupiedBounds, ref SnapAttachmentConfiguration OutAttachmentConfig) { int NumDoors = TargetModule.ConnectionTransforms.Length; if (IncomingDoorIndex >= NumDoors) { return(false); } if (IncomingDoorIndex < 0 || IncomingModule == null) { OutAttachmentConfig.AttachedModule = TargetModule; OutAttachmentConfig.AttachedModuleDoorIndex = random.Range(0, NumDoors - 1); OutAttachmentConfig.AttachedModuleWorldBounds = TargetModule.Bounds; OutAttachmentConfig.AttachedModuleTransform = Matrix4x4.identity; return(true); } if (IncomingDoorIndex >= NumDoors) { return(false); } Matrix4x4 IncomingDoorTransform = IncomingModule.ConnectionTransforms[IncomingDoorIndex]; bool bFoundValid = false; int[] ShuffledIndices = MathUtils.GetShuffledIndices(NumDoors, random); for (int si = 0; si < ShuffledIndices.Length; si++) { int Index = ShuffledIndices[si]; Matrix4x4 AttachmentDoorTransform = TargetModule.ConnectionTransforms[Index]; // Align the module with a door that fits the incoming door Matrix4x4 ModuleTransform = FindAttachmentTransform(ref IncomingModuleTransform, ref IncomingDoorTransform, ref AttachmentDoorTransform); if (!snapConfig.RotateModulesToFit) { // Rotation is not allowed. Check if we rotated the module var moduleRotation = Matrix.GetRotation(ref ModuleTransform); if (Mathf.Abs(moduleRotation.eulerAngles.y) > 0.1f) { // Module was rotated continue; } } { // Calculate the bounds of the module Bounds ModuleWorldBounds = TargetModule.Bounds; ModuleWorldBounds = MathUtils.TransformBounds(ModuleTransform, ModuleWorldBounds); Bounds ContractedModuleWorldBounds = ModuleWorldBounds; ContractedModuleWorldBounds.Expand(-1 * (snapConfig.CollisionTestContraction)); // Check if this module would intersect with any of the existing modules bool bIntersects = false; foreach (var OccupiedBound in OccupiedBounds) { if (ContractedModuleWorldBounds.Intersects(OccupiedBound)) { // intersects. Do not spawn a module here bIntersects = true; break; } } if (bIntersects) { continue; } // We found a valid module. Use this OutAttachmentConfig.AttachedModule = TargetModule; OutAttachmentConfig.AttachedModuleDoorIndex = Index; OutAttachmentConfig.AttachedModuleWorldBounds = ModuleWorldBounds; OutAttachmentConfig.AttachedModuleTransform = ModuleTransform; bFoundValid = true; break; } } return(bFoundValid); }