Exemple #1
0
        public CleanSharedTempStorageNode(GUBP bp, GUBPBranchConfig BranchConfig)
        {
            var ToolsNode = BranchConfig.FindNode(ToolsForCompileNode.StaticGetFullName(UnrealTargetPlatform.Win64));
			GameNames = new HashSet<string>(BranchConfig.GUBPNodes.Values.Select(x => x.GameNameIfAnyForTempStorage()));
            AgentSharingGroup = ToolsNode.AgentSharingGroup;
        }
Exemple #2
0
		public SingleInternalToolsNode(GUBP bp, GUBPBranchConfig InBranchConfig, UnrealTargetPlatform InHostPlatform, SingleTargetProperties InProgramTarget)
			: base(InBranchConfig, InHostPlatform)
        {
			// Don't add rooteditor dependency if it isn't in the graph
			var bRootEditorNodeDoesExit = BranchConfig.HasNode(RootEditorNode.StaticGetFullName(HostPlatform));
			SetupSingleInternalToolsNode(InProgramTarget, !bRootEditorNodeDoesExit && BranchConfig.BranchOptions.bNoEditorDependenciesForTools);
        }
Exemple #3
0
        public CookNode(GUBPBranchConfig BranchConfig, UnrealTargetPlatform InHostPlatform, BranchInfo.BranchUProject InGameProj, UnrealTargetPlatform InTargetPlatform, string InCookPlatform)
            : base(InHostPlatform)
        {
            GameProj = InGameProj;
            TargetPlatform = InTargetPlatform;
            CookPlatform = InCookPlatform;
            bIsMassive = false;
            AddDependency(EditorAndToolsNode.StaticGetFullName(HostPlatform));
            bool bIsShared = false;
            // is this the "base game" or a non code project?
            if (InGameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName && GameProj.Properties.Targets.ContainsKey(TargetRules.TargetType.Editor))
            {
                var Options = InGameProj.Options(HostPlatform);
                bIsMassive = Options.bIsMassive;				
                AddDependency(EditorGameNode.StaticGetFullName(HostPlatform, GameProj));
                // add an arc to prevent cooks from running until promotable is labeled
                if (Options.bIsPromotable)
                {
                    if (!Options.bSeparateGamePromotion)
                    {
                        bIsShared = true;
                    }
                }
                else if (Options.bTestWithShared)
                {
                    bIsShared = true;
                }
				if (!BranchConfig.BranchOptions.bNoMonolithicDependenciesForCooks)
				{
					AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, GameProj, TargetPlatform));
				}
            }
            else
            {
                bIsShared = true;				
                AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, TargetPlatform));
            }
            if (bIsShared)
            {
                // add an arc to prevent cooks from running until promotable is labeled
                AddPseudodependency(WaitForTestShared.StaticGetFullName());
                AgentSharingGroup = "SharedCooks" + StaticGetHostPlatformSuffix(HostPlatform);

                // If the cook fails for the base engine, don't bother trying
                if (InGameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName && BranchConfig.HasNode(CookNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, CookPlatform)))
                {
                    AddPseudodependency(CookNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, CookPlatform));
                }

                // If the base cook platform fails, don't bother trying other ones
                string BaseCookedPlatform = Platform.Platforms[HostPlatform].GetCookPlatform(false, false, "");
                if (InGameProj.GameName == BranchConfig.Branch.BaseEngineProject.GameName && CookPlatform != BaseCookedPlatform &&
                    BranchConfig.HasNode(CookNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, BaseCookedPlatform)))
                {
                    AddPseudodependency(CookNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, BaseCookedPlatform));
                }
            }

			if(GamePlatformMonolithicsNode.IsSample(BranchConfig, GameProj))
			{
				AddDependency(WaitToPackageSamplesNode.StaticGetFullName());
				AgentSharingGroup = "SampleCooks" + StaticGetHostPlatformSuffix(HostPlatform);
			}
        }
Exemple #4
0
        public UATTestNode(GUBPBranchConfig BranchConfig, UnrealTargetPlatform InHostPlatform, BranchInfo.BranchUProject InGameProj, string InTestName, string InUATCommandLine, string InAgentSharingGroup, bool InDependsOnEditor = true, List<UnrealTargetPlatform> InDependsOnCooked = null, float InECPriority = 0.0f)
            : base(InHostPlatform)
        {
            AgentSharingGroup = InAgentSharingGroup;
            ECPriority = InECPriority;
            GameProj = InGameProj;
            TestName = InTestName;
            UATCommandLine = InUATCommandLine;
            bool bWillCook = InUATCommandLine.IndexOf("-cook") >= 0;
            DependsOnEditor = InDependsOnEditor || bWillCook;
            if (InDependsOnCooked != null)
            {
                DependsOnCooked = InDependsOnCooked;
            }
            else
            {
                DependsOnCooked = new List<UnrealTargetPlatform>();
            }
            if (DependsOnEditor)
            {
                AddDependency(EditorAndToolsNode.StaticGetFullName(HostPlatform));
                if (GameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName)
                {
                    if (GameProj.Properties.Targets.ContainsKey(TargetRules.TargetType.Editor))
                    {
                        AddDependency(EditorGameNode.StaticGetFullName(HostPlatform, GameProj));
                    }
                }
            }
            foreach (var Plat in DependsOnCooked)
            {
                AddDependency(GamePlatformCookedAndCompiledNode.StaticGetFullName(HostPlatform, GameProj, Plat));
            }         
           
            AddPseudodependency(WaitForTestShared.StaticGetFullName());
            // If the same test fails for the base engine, don't bother trying
            if (InGameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName)
            {
                if (BranchConfig.HasNode(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, TestName)))
                {
                    AddPseudodependency(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, InTestName));
                }
                else
                {
                    bool bFoundACook = false;
                    foreach (var Plat in DependsOnCooked)
                    {
                        var PlatTestName = "CookedGameTest_"  + Plat.ToString();
                        if (BranchConfig.HasNode(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, PlatTestName)))
                        {
                            AddPseudodependency(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, PlatTestName));
                            bFoundACook = true;
                        }
                    }

                    if (!bFoundACook && BranchConfig.HasNode(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, "EditorTest")))
                    {
                        AddPseudodependency(UATTestNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, "EditorTest"));
                    }

                }
            }

            if (InGameProj.GameName == BranchConfig.Branch.BaseEngineProject.GameName)
            {
                ECPriority = ECPriority + 1.0f;
            }
            if (UATCommandLine.IndexOf("-RunAutomationTests", StringComparison.InvariantCultureIgnoreCase) >= 0)
            {
                ECPriority = ECPriority - 4.0f;
                if (UATCommandLine.IndexOf("-EditorTest", StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    ECPriority = ECPriority - 4.0f;
                }
            }
            else if (UATCommandLine.IndexOf("-EditorTest", StringComparison.InvariantCultureIgnoreCase) >= 0)
            {
                ECPriority = ECPriority + 2.0f;
            }

        }
Exemple #5
0
		public static bool IsSample(GUBPBranchConfig BranchConfig, BranchInfo.BranchUProject GameProj)
		{
			return (GameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName && (GameProj.FilePath.Contains("Samples") || GameProj.FilePath.Contains("Templates")));
		}
Exemple #6
0
        public GamePlatformMonolithicsNode(GUBPBranchConfig InBranchConfig, UnrealTargetPlatform InHostPlatform, List<UnrealTargetPlatform> InActivePlatforms, BranchInfo.BranchUProject InGameProj, UnrealTargetPlatform InTargetPlatform, bool InWithXp = false, bool InPrecompiled = false)
            : base(InBranchConfig, InHostPlatform)
        {
            GameProj = InGameProj;
            TargetPlatform = InTargetPlatform;
			ActivePlatforms = InActivePlatforms;
			WithXp = InWithXp;
			Precompiled = InPrecompiled;
			EnhanceAgentRequirements = BranchConfig.BranchOptions.EnhanceAgentRequirements.Contains(StaticGetFullName(HostPlatform, GameProj, TargetPlatform, WithXp, Precompiled));

            if (TargetPlatform == UnrealTargetPlatform.PS4 || TargetPlatform == UnrealTargetPlatform.XboxOne)
            {
				// Required for PS4MapFileUtil/XboxOnePDBFileUtil
				AddDependency(ToolsNode.StaticGetFullName(InHostPlatform));
			}

			if(IsSample(BranchConfig, InGameProj))
			{
				AddDependency(WaitToPackageSamplesNode.StaticGetFullName());
			}

            if (InGameProj.GameName != BranchConfig.Branch.BaseEngineProject.GameName && GameProj.Properties.Targets.ContainsKey(TargetRules.TargetType.Editor))
            {
				if (!BranchConfig.BranchOptions.ExcludePlatformsForEditor.Contains(InHostPlatform))
				{
					AddPseudodependency(EditorGameNode.StaticGetFullName(InHostPlatform, GameProj));
				}
				if (BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, TargetPlatform)))
                {
					AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, BranchConfig.Branch.BaseEngineProject, TargetPlatform));
                }
            }
            else
            {
				if (TargetPlatform != InHostPlatform && BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(InHostPlatform, BranchConfig.Branch.BaseEngineProject, InHostPlatform, Precompiled: Precompiled)))
                {
					AddPseudodependency(GamePlatformMonolithicsNode.StaticGetFullName(InHostPlatform, BranchConfig.Branch.BaseEngineProject, InHostPlatform, Precompiled: Precompiled));
                }
            }
            if (InGameProj.Options(InHostPlatform).bTestWithShared)  /// compiling templates is only for testing purposes, and we will group them to avoid saturating the farm
            {
                AddPseudodependency(WaitForTestShared.StaticGetFullName());
                AgentSharingGroup = "TemplateMonolithics" + StaticGetHostPlatformSuffix(InHostPlatform);
            }
        }
 public abstract void AddNodes(GUBP bp, GUBPBranchConfig BranchConfig, UnrealTargetPlatform InHostPlatform, List<UnrealTargetPlatform> InActivePlatforms);
    void AddNodesForBranch(List<UnrealTargetPlatform> InitialHostPlatforms, JobInfo JobInfo, out List<BuildNode> AllNodes, out List<AggregateNode> AllAggregates, ref int TimeQuantum)
	{
		string BranchName;
		if (P4Enabled)
		{
			BranchName = P4Env.BuildRootP4;
		}
		else
		{ 
			BranchName = ParseParamValue("BranchName", "");
		}

		GUBPBranchHacker.BranchOptions BranchOptions = GetBranchOptions(BranchName);

		if (BranchOptions.QuantumOverride != 0)
		{
			TimeQuantum = BranchOptions.QuantumOverride;
		}

		bool bForceIncrementalCompile = ParseParam("ForceIncrementalCompile");
		bool bNoAutomatedTesting = ParseParam("NoAutomatedTesting") || BranchOptions.bNoAutomatedTesting;		

		List<UnrealTargetPlatform> HostPlatforms = new List<UnrealTargetPlatform>(InitialHostPlatforms);
		foreach(UnrealTargetPlatform PlatformToRemove in BranchOptions.PlatformsToRemove)
		{
			HostPlatforms.Remove(PlatformToRemove);
		}

        BranchInfo Branch = new BranchInfo(HostPlatforms);        

		List<UnrealTargetPlatform> ActivePlatforms;
        if (IsBuildMachine || ParseParam("AllPlatforms"))
        {
            ActivePlatforms = new List<UnrealTargetPlatform>();
            
			List<BranchInfo.BranchUProject> BranchCodeProjects = new List<BranchInfo.BranchUProject>();
			BranchCodeProjects.Add(Branch.BaseEngineProject);
			BranchCodeProjects.AddRange(Branch.CodeProjects);
			BranchCodeProjects.RemoveAll(Project => BranchOptions.ExcludeNodes.Contains(Project.GameName));

			foreach (var GameProj in BranchCodeProjects)
            {
                foreach (var Kind in BranchInfo.MonolithicKinds)
                {
                    if (GameProj.Properties.Targets.ContainsKey(Kind))
                    {
                        var Target = GameProj.Properties.Targets[Kind];
                        foreach (var HostPlatform in HostPlatforms)
                        {
                            var Platforms = Target.Rules.GUBP_GetPlatforms_MonolithicOnly(HostPlatform);
							var AdditionalPlatforms = Target.Rules.GUBP_GetBuildOnlyPlatforms_MonolithicOnly(HostPlatform);
							var AllPlatforms = Platforms.Union(AdditionalPlatforms);
							foreach (var Plat in AllPlatforms)
                            {
                                if (Target.Rules.SupportsPlatform(Plat) && !ActivePlatforms.Contains(Plat))
                                {
                                    ActivePlatforms.Add(Plat);
                                }
                            }
                        }
                    }
                }
            }
        }
        else
        {
            ActivePlatforms     = new List<UnrealTargetPlatform>(CommandUtils.KnownTargetPlatforms);
        }
        var SupportedPlatforms = new List<UnrealTargetPlatform>();
        foreach(var Plat in ActivePlatforms)
        {
            if(!BranchOptions.PlatformsToRemove.Contains(Plat))
            {
                SupportedPlatforms.Add(Plat);
            }
        }
        ActivePlatforms = SupportedPlatforms;
        foreach (var Plat in ActivePlatforms)
        {
            LogVerbose("Active Platform: {0}", Plat.ToString());
        }

		bool bNoIOSOnPC = HostPlatforms.Contains(UnrealTargetPlatform.Mac);

        if (HostPlatforms.Count >= 2)
        {
            // make sure each project is set up with the right assumptions on monolithics that prefer a platform.
            foreach (var CodeProj in Branch.CodeProjects)
            {
                var OptionsMac = CodeProj.Options(UnrealTargetPlatform.Mac);
                var OptionsPC = CodeProj.Options(UnrealTargetPlatform.Win64);

				var MacMonos = GamePlatformMonolithicsNode.GetMonolithicPlatformsForUProject(UnrealTargetPlatform.Mac, ActivePlatforms, CodeProj, false, bNoIOSOnPC);
				var PCMonos = GamePlatformMonolithicsNode.GetMonolithicPlatformsForUProject(UnrealTargetPlatform.Win64, ActivePlatforms, CodeProj, false, bNoIOSOnPC);

                if (!OptionsMac.bIsPromotable && OptionsPC.bIsPromotable && 
                    (MacMonos.Contains(UnrealTargetPlatform.IOS) || PCMonos.Contains(UnrealTargetPlatform.IOS)))
                {
                    throw new AutomationException("Project {0} is promotable for PC, not promotable for Mac and uses IOS monothics. Since Mac is the preferred platform for IOS, please add Mac as a promotable platform.", CodeProj.GameName);
                }
                if (OptionsMac.bIsPromotable && !OptionsPC.bIsPromotable &&
                    (MacMonos.Contains(UnrealTargetPlatform.Android) || PCMonos.Contains(UnrealTargetPlatform.Android)))
                {
                    throw new AutomationException("Project {0} is not promotable for PC, promotable for Mac and uses Android monothics. Since PC is the preferred platform for Android, please add PC as a promotable platform.", CodeProj.GameName);
                }
            }
        }

		GUBPBranchConfig BranchConfig = new GUBPBranchConfig(HostPlatforms, BranchName, Branch, BranchOptions, bForceIncrementalCompile, JobInfo);

        BranchConfig.AddNode(new VersionFilesNode());


        foreach (var HostPlatform in HostPlatforms)
        {
			BranchConfig.AddNode(new ToolsForCompileNode(BranchConfig, HostPlatform, ParseParam("Launcher")));
			
			if (!BranchOptions.ExcludePlatformsForEditor.Contains(HostPlatform))
			{
				BranchConfig.AddNode(new RootEditorNode(BranchConfig, HostPlatform));
			}
			
			BranchConfig.AddNode(new ToolsNode(BranchConfig, HostPlatform));
			
			if (!BranchOptions.ExcludePlatformsForEditor.Contains(HostPlatform))
			{
				BranchConfig.AddNode(new InternalToolsNode(BranchConfig, HostPlatform));
			
				if (HostPlatform == UnrealTargetPlatform.Win64 && ActivePlatforms.Contains(UnrealTargetPlatform.Linux))
				{
					if (!BranchOptions.ExcludePlatformsForEditor.Contains(UnrealTargetPlatform.Linux))
					{
						BranchConfig.AddNode(new ToolsCrossCompileNode(BranchConfig, HostPlatform));
					}
				}
				foreach (var ProgramTarget in Branch.BaseEngineProject.Properties.Programs)
				{
                    if (!BranchOptions.ExcludeNodes.Contains(ProgramTarget.TargetName))
                    {
                        bool bInternalOnly;
                        bool SeparateNode;
                        bool CrossCompile;

                        if (ProgramTarget.Rules.GUBP_AlwaysBuildWithTools(HostPlatform, out bInternalOnly, out SeparateNode, out CrossCompile) && ProgramTarget.Rules.SupportsPlatform(HostPlatform) && SeparateNode)
                        {
                            if (bInternalOnly)
                            {
                                BranchConfig.AddNode(new SingleInternalToolsNode(BranchConfig, HostPlatform, ProgramTarget));
                            }
                            else
                            {
                                BranchConfig.AddNode(new SingleToolsNode(BranchConfig, HostPlatform, ProgramTarget));
                            }
                        }
                        if (ProgramTarget.Rules.GUBP_IncludeNonUnityToolTest())
                        {
                            BranchConfig.AddNode(new NonUnityToolNode(HostPlatform, ProgramTarget));
                        }
                    }
				}
				foreach(var CodeProj in Branch.CodeProjects)
				{
					foreach(var ProgramTarget in CodeProj.Properties.Programs)
					{
                        if (!BranchOptions.ExcludeNodes.Contains(ProgramTarget.TargetName))
                        {
                            bool bInternalNodeOnly;
                            bool SeparateNode;
                            bool CrossCompile;

                            if (ProgramTarget.Rules.GUBP_AlwaysBuildWithTools(HostPlatform, out bInternalNodeOnly, out SeparateNode, out CrossCompile) && ProgramTarget.Rules.SupportsPlatform(HostPlatform) && SeparateNode)
                            {
                                if (bInternalNodeOnly)
                                {
                                    BranchConfig.AddNode(new SingleInternalToolsNode(BranchConfig, HostPlatform, ProgramTarget));
                                }
                                else
                                {
                                    BranchConfig.AddNode(new SingleToolsNode(BranchConfig, HostPlatform, ProgramTarget));
                                }
                            }
                            if (ProgramTarget.Rules.GUBP_IncludeNonUnityToolTest())
                            {
                                BranchConfig.AddNode(new NonUnityToolNode(HostPlatform, ProgramTarget));
                            }
                        }
					}
				}

				BranchConfig.AddNode(new EditorAndToolsNode(this, HostPlatform));
			}

            bool DoASharedPromotable = false;

            int NumSharedCode = 0;
            foreach (var CodeProj in Branch.CodeProjects)
            {
                var Options = CodeProj.Options(HostPlatform);

                if (Options.bIsPromotable && !Options.bSeparateGamePromotion)
                {
                    NumSharedCode++;
                }
            }

            var NonCodeProjectNames = new Dictionary<string, List<UnrealTargetPlatform>>();
            var NonCodeFormalBuilds = new Dictionary<string, List<TargetRules.GUBPFormalBuild>>();
            {
                var Target = Branch.BaseEngineProject.Properties.Targets[TargetRules.TargetType.Editor];

                foreach (var Codeless in Target.Rules.GUBP_NonCodeProjects_BaseEditorTypeOnly(HostPlatform))
                {
                    var Proj = Branch.FindGame(Codeless.Key);
                    if (Proj == null)
                    {
                        LogVerbose("{0} was listed as a codeless project by GUBP_NonCodeProjects_BaseEditorTypeOnly, however it does not exist in this branch.", Codeless.Key);
                    }
                    else if (Proj.Properties.bIsCodeBasedProject)
                    {
						if (!Branch.NonCodeProjects.Contains(Proj)) 
						{ 
							Branch.NonCodeProjects.Add(Proj);
							NonCodeProjectNames.Add(Codeless.Key, Codeless.Value);
						}
                    }
                    else
                    {
                        NonCodeProjectNames.Add(Codeless.Key, Codeless.Value);
                    }
                }

                var TempNonCodeFormalBuilds = Target.Rules.GUBP_GetNonCodeFormalBuilds_BaseEditorTypeOnly();
				var HostMonos = GamePlatformMonolithicsNode.GetMonolithicPlatformsForUProject(HostPlatform, ActivePlatforms, Branch.BaseEngineProject, true, bNoIOSOnPC);

                foreach (var Codeless in TempNonCodeFormalBuilds)
                {
                    if (NonCodeProjectNames.ContainsKey(Codeless.Key))
                    {
                        var PlatList = Codeless.Value;
                        var NewPlatList = new List<TargetRules.GUBPFormalBuild>();
                        foreach (var PlatPair in PlatList)
                        {
                            if (HostMonos.Contains(PlatPair.TargetPlatform))
                            {
                                NewPlatList.Add(PlatPair);
                            }
                        }
                        if (NewPlatList.Count > 0)
                        {
                            NonCodeFormalBuilds.Add(Codeless.Key, NewPlatList);
                        }
                    }
                    else
                    {
                        LogVerbose("{0} was listed as a codeless formal build GUBP_GetNonCodeFormalBuilds_BaseEditorTypeOnly, however it does not exist in this branch.", Codeless.Key);
                    }
                }
            }

            DoASharedPromotable = NumSharedCode > 0 || NonCodeProjectNames.Count > 0 || NonCodeFormalBuilds.Count > 0;

			if (!BranchOptions.ExcludePlatformsForEditor.Contains(HostPlatform))
			{
				BranchConfig.AddNode(new NonUnityTestNode(BranchConfig, HostPlatform));
			}

            if (DoASharedPromotable)
            {
                var AgentSharingGroup = "Shared_EditorTests" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);

                var Options = Branch.BaseEngineProject.Options(HostPlatform);

                if (!Options.bIsPromotable || Options.bSeparateGamePromotion)
                {
                    throw new AutomationException("We assume that if we have shared promotable, the base engine is in it.");
                }


                if (!bNoAutomatedTesting && HostPlatform == UnrealTargetPlatform.Win64) //temp hack till automated testing works on other platforms than Win64
                {

                    var EditorTests = Branch.BaseEngineProject.Properties.Targets[TargetRules.TargetType.Editor].Rules.GUBP_GetEditorTests_EditorTypeOnly(HostPlatform);
                    var EditorTestNodes = new List<string>();
                    foreach (var Test in EditorTests)
                    {
                        EditorTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, Branch.BaseEngineProject, Test.Key, Test.Value, AgentSharingGroup)));
                        
                        foreach (var NonCodeProject in Branch.NonCodeProjects)
                        {
                            if (!NonCodeProjectNames.ContainsKey(NonCodeProject.GameName))
                            {
                                continue;
                            }
                            if (HostPlatform == UnrealTargetPlatform.Mac) continue; //temp hack till mac automated testing works
                            EditorTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, NonCodeProject, Test.Key, Test.Value, AgentSharingGroup)));
                        }
                    }
                    if (EditorTestNodes.Count > 0)
                    {
                        BranchConfig.AddNode(new GameAggregateNode(HostPlatform, Branch.BaseEngineProject, "AllEditorTests", EditorTestNodes));
                    }
                }


                var ServerPlatforms = new List<UnrealTargetPlatform>();
                var GamePlatforms = new List<UnrealTargetPlatform>();

                foreach (var Kind in BranchInfo.MonolithicKinds)
                {
                    if (Branch.BaseEngineProject.Properties.Targets.ContainsKey(Kind))
                    {
                        var Target = Branch.BaseEngineProject.Properties.Targets[Kind];
                        var Platforms = Target.Rules.GUBP_GetPlatforms_MonolithicOnly(HostPlatform);
                        if (Platforms.Contains(HostPlatform))
                        {
                            // we want the host platform first since some some pseudodependencies look to see if the shared promotable exists.
                            Platforms.Remove(HostPlatform);
                            Platforms.Insert(0, HostPlatform);
                        }
                        foreach (var Plat in Platforms)
                        {
                            if (!Platform.Platforms[HostPlatform].CanHostPlatform(Plat))
                            {
                                throw new AutomationException("Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform.", Branch.BaseEngineProject.GameName, Plat.ToString(), HostPlatform.ToString());
                            }
                            if (bNoIOSOnPC && Plat == UnrealTargetPlatform.IOS && HostPlatform == UnrealTargetPlatform.Win64)
                            {
                                continue;
                            }

                            if (ActivePlatforms.Contains(Plat))
                            {
                                if (Kind == TargetRules.TargetType.Server && !ServerPlatforms.Contains(Plat))
                                {
                                    ServerPlatforms.Add(Plat);
                                }
                                if (Kind == TargetRules.TargetType.Game && !GamePlatforms.Contains(Plat))
                                {
                                    GamePlatforms.Add(Plat);
                                }
                                if (!BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, Branch.BaseEngineProject, Plat)))
                                {
									if(GamePlatformMonolithicsNode.HasPrecompiledTargets(Branch.BaseEngineProject, HostPlatform, Plat))
									{
	                                    BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, Branch.BaseEngineProject, Plat, InPrecompiled: true));
									}
                                    BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, Branch.BaseEngineProject, Plat));
                                }
								if (Plat == UnrealTargetPlatform.Win32 && Target.Rules.GUBP_BuildWindowsXPMonolithics() && Kind == TargetRules.TargetType.Game)
								{
									if (!BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, Branch.BaseEngineProject, Plat, true)))
									{
										BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, Branch.BaseEngineProject, Plat, true));
									}
	                            }
                            }
                        }
                    }
                }

                var CookedSharedAgentSharingGroup = "Shared_CookedTests" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
                var CookedSampleAgentSharingGroup = "Sample_CookedTests" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);

                var GameTestNodes = new List<string>();
                var GameCookNodes = new List<string>();
				//var FormalAgentSharingGroup = "Shared_FormalBuilds" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);


                //foreach (var Kind in BranchInfo.MonolithicKinds)//for now, non-code projects don't do client or server.
                {
                    var Kind = TargetRules.TargetType.Game;
                    if (Branch.BaseEngineProject.Properties.Targets.ContainsKey(Kind))
                    {
                        var Target = Branch.BaseEngineProject.Properties.Targets[Kind];
                        var Platforms = Target.Rules.GUBP_GetPlatforms_MonolithicOnly(HostPlatform);
                        foreach (var Plat in Platforms)
                        {
                            if (!Platform.Platforms[HostPlatform].CanHostPlatform(Plat))
                            {
                                throw new AutomationException("Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform.", Branch.BaseEngineProject.GameName, Plat.ToString(), HostPlatform.ToString());
                            }
                            if (bNoIOSOnPC && Plat == UnrealTargetPlatform.IOS && HostPlatform == UnrealTargetPlatform.Win64)
                            {
                                continue;
                            }

                            if (ActivePlatforms.Contains(Plat))
                            {
                                string CookedPlatform = Platform.Platforms[Plat].GetCookPlatform(Kind == TargetRules.TargetType.Server, Kind == TargetRules.TargetType.Client, "");								
                                if (!BranchConfig.HasNode(CookNode.StaticGetFullName(HostPlatform, Branch.BaseEngineProject, CookedPlatform)))
                                {
									GameCookNodes.Add(BranchConfig.AddNode(new CookNode(BranchConfig, HostPlatform, Branch.BaseEngineProject, Plat, CookedPlatform)));
                                }
                                if (!BranchConfig.HasNode(GamePlatformCookedAndCompiledNode.StaticGetFullName(HostPlatform, Branch.BaseEngineProject, Plat)))
                                {
									BranchConfig.AddNode(new GamePlatformCookedAndCompiledNode(BranchConfig, HostPlatform, Branch.BaseEngineProject, Plat, false));
                                }
                                var GameTests = Target.Rules.GUBP_GetGameTests_MonolithicOnly(HostPlatform, GetAltHostPlatform(HostPlatform), Plat);
                                var RequiredPlatforms = new List<UnrealTargetPlatform> { Plat };
                                if (!bNoAutomatedTesting)
                                {
                                    var ThisMonoGameTestNodes = new List<string>();	
                                    
                                    foreach (var Test in GameTests)
                                    {
                                        var TestName = Test.Key + "_" + Plat.ToString();
                                        ThisMonoGameTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, Branch.BaseEngineProject, TestName, Test.Value, CookedSharedAgentSharingGroup, false, RequiredPlatforms)));
                                    }
                                    if (ThisMonoGameTestNodes.Count > 0)
                                    {										
                                        GameTestNodes.Add(BranchConfig.AddNode(new GameAggregateNode(HostPlatform, Branch.BaseEngineProject, "CookedTests_" + Plat.ToString() + "_" + Kind.ToString() + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform), ThisMonoGameTestNodes)));
                                    }
                                }

                                foreach (var NonCodeProject in Branch.NonCodeProjects)
                                {
                                    if (!NonCodeProjectNames.ContainsKey(NonCodeProject.GameName) || !NonCodeProjectNames[NonCodeProject.GameName].Contains(Plat))
                                    {
                                        continue;
                                    }
                                    if (BranchOptions.ProjectsToCook.Contains(NonCodeProject.GameName) || BranchOptions.ProjectsToCook.Count == 0)
                                    {
										if (!BranchConfig.HasNode(CookNode.StaticGetFullName(HostPlatform, NonCodeProject, CookedPlatform)))
										{
											GameCookNodes.Add(BranchConfig.AddNode(new CookNode(BranchConfig, HostPlatform, NonCodeProject, Plat, CookedPlatform)));
										}
										if (!BranchConfig.HasNode(GamePlatformCookedAndCompiledNode.StaticGetFullName(HostPlatform, NonCodeProject, Plat)))
										{
											BranchConfig.AddNode(new GamePlatformCookedAndCompiledNode(BranchConfig, HostPlatform, NonCodeProject, Plat, false));

											if (NonCodeFormalBuilds.ContainsKey(NonCodeProject.GameName))
											{
												var PlatList = NonCodeFormalBuilds[NonCodeProject.GameName];
												foreach (var PlatPair in PlatList)
												{
													if (PlatPair.TargetPlatform == Plat)
													{
														var NodeName = BranchConfig.AddNode(new FormalBuildNode(BranchConfig, NonCodeProject, HostPlatform, new List<UnrealTargetPlatform>() { Plat }, new List<UnrealTargetConfiguration>() { PlatPair.TargetConfig }));                                                    
														// we don't want this delayed
														// this would normally wait for the testing phase, we just want to build it right away
														BranchConfig.RemovePseudodependencyFromNode(
															CookNode.StaticGetFullName(HostPlatform, NonCodeProject, CookedPlatform),
															WaitForTestShared.StaticGetFullName());
														string BuildAgentSharingGroup = "";
														if (Options.bSeparateGamePromotion)
														{
															BuildAgentSharingGroup = NonCodeProject.GameName + "_MakeFormalBuild_" + Plat.ToString() + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
															if (Plat == UnrealTargetPlatform.IOS || Plat == UnrealTargetPlatform.Android) // These trash build products, so we need to use different agents
															{
																BuildAgentSharingGroup = "";
															}
															BranchConfig.FindNode(CookNode.StaticGetFullName(HostPlatform, NonCodeProject, CookedPlatform)).AgentSharingGroup = BuildAgentSharingGroup;
															BranchConfig.FindNode(NodeName).AgentSharingGroup = BuildAgentSharingGroup;
														}
														else
														{
															//GUBPNodes[NodeName].AgentSharingGroup = FormalAgentSharingGroup;
																if (Plat == UnrealTargetPlatform.XboxOne)
															{
																BranchConfig.FindNode(NodeName).AgentSharingGroup = "";
															}
														}
														if (PlatPair.bTest)
														{
															BranchConfig.AddNode(new FormalBuildTestNode(BranchConfig, NonCodeProject, HostPlatform, Plat, PlatPair.TargetConfig));
														}
													}
												}
											}
										}

										if (!bNoAutomatedTesting)
                                        {
											if (HostPlatform == UnrealTargetPlatform.Mac || HostPlatform == UnrealTargetPlatform.Linux) continue; //temp hack till Linux and Mac automated testing works
											var ThisMonoGameTestNodes = new List<string>();
											foreach (var Test in GameTests)
											{
												var TestName = Test.Key + "_" + Plat.ToString();
												string CookedAgentSharingGroup = GamePlatformMonolithicsNode.IsSample(BranchConfig, NonCodeProject)? CookedSampleAgentSharingGroup : CookedSharedAgentSharingGroup;
												ThisMonoGameTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, NonCodeProject, TestName, Test.Value, CookedAgentSharingGroup, false, RequiredPlatforms)));
											}
											if (ThisMonoGameTestNodes.Count > 0)
											{
												GameTestNodes.Add(BranchConfig.AddNode(new GameAggregateNode(HostPlatform, NonCodeProject, "CookedTests_" + Plat.ToString() + "_" + Kind.ToString() + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform), ThisMonoGameTestNodes)));
											}
										}
									}
								}
							}
						}
					}
                }
#if false
                //for now, non-code projects don't do client or server.
                foreach (var ServerPlatform in ServerPlatforms)
                {
                    var ServerTarget = Branch.BaseEngineProject.Properties.Targets[TargetRules.TargetType.Server];
                    foreach (var GamePlatform in GamePlatforms)
                    {
                        var Target = Branch.BaseEngineProject.Properties.Targets[TargetRules.TargetType.Game];

                        foreach (var NonCodeProject in Branch.NonCodeProjects)
                        {
                            if (!NonCodeProjectNames.ContainsKey(NonCodeProject.GameName) || !NonCodeProjectNames.ContainsKey(NonCodeProject.GameName) ||
                                    !NonCodeProjectNames[NonCodeProject.GameName].Contains(ServerPlatform)  || !NonCodeProjectNames[NonCodeProject.GameName].Contains(GamePlatform) )
                            {
                                continue;
                            }

                            var ClientServerTests = Target.Rules.GUBP_GetClientServerTests_MonolithicOnly(HostPlatform, GetAltHostPlatform(HostPlatform), ServerPlatform, GamePlatform);
                            var RequiredPlatforms = new List<UnrealTargetPlatform> { ServerPlatform };
                            if (ServerPlatform != GamePlatform)
                            {
                                RequiredPlatforms.Add(GamePlatform);
                            }
                            foreach (var Test in ClientServerTests)
                            {
                                GameTestNodes.Add(AddNode(new UATTestNode(this, HostPlatform, NonCodeProject, Test.Key + "_" + GamePlatform.ToString() + "_" + ServerPlatform.ToString(), Test.Value, false, RequiredPlatforms, true)));
                            }
                        }
                    }
                }
#endif
                if (GameTestNodes.Count > 0)
                {
                    BranchConfig.AddNode(new GameAggregateNode(HostPlatform, Branch.BaseEngineProject, "AllCookedTests", GameTestNodes));
                }
            }
			
			if(HostPlatform == MakeFeaturePacksNode.GetDefaultBuildPlatform(HostPlatforms) && !BranchOptions.bNoInstalledEngine)
			{
				BranchConfig.AddNode(new MakeFeaturePacksNode(HostPlatform, Branch.AllProjects.Where(x => MakeFeaturePacksNode.IsFeaturePack(x))));
			}

            foreach (var CodeProj in Branch.CodeProjects)
            {
                var Options = CodeProj.Options(HostPlatform);

                if (!Options.bIsPromotable && !Options.bTestWithShared && !Options.bIsNonCode && !Options.bBuildAnyway)
                {
                    continue; // we skip things that aren't promotable and aren't tested - except noncode as code situations
                }
                var AgentShareName = CodeProj.GameName;
                if (!Options.bSeparateGamePromotion)
                {
					if(GamePlatformMonolithicsNode.IsSample(BranchConfig, CodeProj))
					{
						AgentShareName = "Sample";
					}
					else
					{
						AgentShareName = "Shared";
					}
                }

				if (!BranchOptions.ExcludePlatformsForEditor.Contains(HostPlatform) && !Options.bIsNonCode)
				{
					EditorGameNode Node = (EditorGameNode)BranchConfig.TryFindNode(EditorGameNode.StaticGetFullName(HostPlatform, CodeProj));
					if(Node == null)
					{
						BranchConfig.AddNode(new EditorGameNode(BranchConfig, HostPlatform, CodeProj));
					}
					else
					{
						Node.AddProject(CodeProj);
					}
				}

				if (!bNoAutomatedTesting && HostPlatform == UnrealTargetPlatform.Win64) //temp hack till automated testing works on other platforms than Win64
                {
					if (CodeProj.Properties.Targets.ContainsKey(TargetRules.TargetType.Editor))
					{
						var EditorTests = CodeProj.Properties.Targets[TargetRules.TargetType.Editor].Rules.GUBP_GetEditorTests_EditorTypeOnly(HostPlatform);
						var EditorTestNodes = new List<string>();
						string AgentSharingGroup = "";
						if (EditorTests.Count > 1)
						{
							AgentSharingGroup = AgentShareName + "_EditorTests" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
						}
						foreach (var Test in EditorTests)
						{
							EditorTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, CodeProj, Test.Key, Test.Value, AgentSharingGroup)));
							if (!Options.bTestWithShared || !BranchConfig.HasNode(WaitForTestShared.StaticGetFullName()))
							{
								BranchConfig.RemovePseudodependencyFromNode((UATTestNode.StaticGetFullName(HostPlatform, CodeProj, Test.Key)), WaitForTestShared.StaticGetFullName());
							}
						}
						if (EditorTestNodes.Count > 0)
						{
							BranchConfig.AddNode(new GameAggregateNode(HostPlatform, CodeProj, "AllEditorTests", EditorTestNodes));
						}
					}
                }

                var CookedAgentSharingGroup = AgentShareName + "_CookedTests" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
				//var FormalAgentSharingGroup = "Shared_FormalBuilds" + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
                var ServerPlatforms = new List<UnrealTargetPlatform>();
                var GamePlatforms = new List<UnrealTargetPlatform>();
                var GameTestNodes = new List<string>();
                foreach (var Kind in BranchInfo.MonolithicKinds)
                {
                    if (CodeProj.Properties.Targets.ContainsKey(Kind))
                    {
                        var Target = CodeProj.Properties.Targets[Kind];
                        var Platforms = Target.Rules.GUBP_GetPlatforms_MonolithicOnly(HostPlatform);
						var AdditionalPlatforms = Target.Rules.GUBP_GetBuildOnlyPlatforms_MonolithicOnly(HostPlatform);
						var AllPlatforms = Platforms.Union(AdditionalPlatforms);
						foreach (var Plat in AllPlatforms)
                        {
                            if (!Platform.Platforms[HostPlatform].CanHostPlatform(Plat))
                            {
                                throw new AutomationException("Project {0} asked for platform {1} with host {2}, but the host platform cannot build that platform.", CodeProj.GameName, Plat.ToString(), HostPlatform.ToString());
                            }
                            if (bNoIOSOnPC && Plat == UnrealTargetPlatform.IOS && HostPlatform == UnrealTargetPlatform.Win64)
                            {
                                continue;
                            }
							if(Plat == UnrealTargetPlatform.Win32 && Target.Rules.GUBP_BuildWindowsXPMonolithics())
							{
								if(!BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, CodeProj, Plat, true)))
								{
									BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, CodeProj, Plat, true));
								}
							}
                            if (ActivePlatforms.Contains(Plat))
                            {
                                if (Kind == TargetRules.TargetType.Server && !ServerPlatforms.Contains(Plat))
                                {
                                    ServerPlatforms.Add(Plat);
                                }
                                if (Kind == TargetRules.TargetType.Game && !GamePlatforms.Contains(Plat))
                                {
                                    GamePlatforms.Add(Plat);
                                }
                                if (!BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(HostPlatform, CodeProj, Plat)))
                                {
									if(GamePlatformMonolithicsNode.HasPrecompiledTargets(CodeProj, HostPlatform, Plat))
									{
	                                    BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, CodeProj, Plat, InPrecompiled: true));
									}
                                    BranchConfig.AddNode(new GamePlatformMonolithicsNode(BranchConfig, HostPlatform, ActivePlatforms, CodeProj, Plat));
                                }
                                var FormalBuildConfigs = Target.Rules.GUBP_GetConfigsForFormalBuilds_MonolithicOnly(HostPlatform);
								if (!AdditionalPlatforms.Contains(Plat) && (BranchOptions.ProjectsToCook.Contains(CodeProj.GameName) || BranchOptions.ProjectsToCook.Count == 0))
								{
									string CookedPlatform = Platform.Platforms[Plat].GetCookPlatform(Kind == TargetRules.TargetType.Server, Kind == TargetRules.TargetType.Client, "");
									if (Target.Rules.GUBP_AlternateCookPlatform(HostPlatform, CookedPlatform) != "")
									{
										CookedPlatform = Target.Rules.GUBP_AlternateCookPlatform(HostPlatform, CookedPlatform);
									}
									if (!BranchConfig.HasNode(CookNode.StaticGetFullName(HostPlatform, CodeProj, CookedPlatform)))
									{
										BranchConfig.AddNode(new CookNode(BranchConfig, HostPlatform, CodeProj, Plat, CookedPlatform));
									}
									if (!BranchConfig.HasNode(GamePlatformCookedAndCompiledNode.StaticGetFullName(HostPlatform, CodeProj, Plat)))
									{
										BranchConfig.AddNode(new GamePlatformCookedAndCompiledNode(BranchConfig, HostPlatform, CodeProj, Plat, true));
									}
									

									foreach (var Config in FormalBuildConfigs)
									{
										string FormalNodeName = null;                                    
										if (Kind == TargetRules.TargetType.Client)
										{
											if (Plat == Config.TargetPlatform)
											{
												FormalNodeName = BranchConfig.AddNode(new FormalBuildNode(BranchConfig, CodeProj, HostPlatform, InClientTargetPlatforms: new List<UnrealTargetPlatform>() { Config.TargetPlatform }, InClientConfigs: new List<UnrealTargetConfiguration>() { Config.TargetConfig }, InClientNotGame: true));
											}
										}
										else if (Kind == TargetRules.TargetType.Server)
										{
											if (Plat == Config.TargetPlatform)
											{
												FormalNodeName = BranchConfig.AddNode(new FormalBuildNode(BranchConfig, CodeProj, HostPlatform, InServerTargetPlatforms: new List<UnrealTargetPlatform>() { Config.TargetPlatform }, InServerConfigs: new List<UnrealTargetConfiguration>() { Config.TargetConfig }));
											}
										}
										else if (Kind == TargetRules.TargetType.Game)
										{
											if (Plat == Config.TargetPlatform)
											{
												FormalNodeName = BranchConfig.AddNode(new FormalBuildNode(BranchConfig, CodeProj, HostPlatform, InClientTargetPlatforms: new List<UnrealTargetPlatform>() { Config.TargetPlatform }, InClientConfigs: new List<UnrealTargetConfiguration>() { Config.TargetConfig }));
											}
										}
										if (FormalNodeName != null)
										{
											// we don't want this delayed
											// this would normally wait for the testing phase, we just want to build it right away
											BranchConfig.RemovePseudodependencyFromNode(
												CookNode.StaticGetFullName(HostPlatform, CodeProj, CookedPlatform),
												WaitForTestShared.StaticGetFullName());
											string BuildAgentSharingGroup = "";
											
											if (Options.bSeparateGamePromotion)
											{
												BuildAgentSharingGroup = CodeProj.GameName + "_MakeFormalBuild_" + Plat.ToString() + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform);
												if (Plat == UnrealTargetPlatform.IOS || Plat == UnrealTargetPlatform.Android || Plat == UnrealTargetPlatform.XboxOne) // These trash build products, so we need to use different agents
												{
													BuildAgentSharingGroup = "";
												}
												BranchConfig.FindNode(CookNode.StaticGetFullName(HostPlatform, CodeProj, CookedPlatform)).AgentSharingGroup = BuildAgentSharingGroup;
												BranchConfig.FindNode(FormalNodeName).AgentSharingGroup = BuildAgentSharingGroup;
											}
											else
											{
												//GUBPNodes[FormalNodeName].AgentSharingGroup = FormalAgentSharingGroup;
												if (Plat == UnrealTargetPlatform.XboxOne)
												{
													BranchConfig.FindNode(FormalNodeName).AgentSharingGroup = "";
												}
											}
											if (Config.bTest)
											{
												BranchConfig.AddNode(new FormalBuildTestNode(BranchConfig, CodeProj, HostPlatform, Plat, Config.TargetConfig));
											}																				
										}
									}
									if (!bNoAutomatedTesting && FormalBuildConfigs.Count > 0)
									{
										if (HostPlatform == UnrealTargetPlatform.Mac || HostPlatform == UnrealTargetPlatform.Linux) continue; //temp hack till Linux and Mac automated testing works
										var GameTests = Target.Rules.GUBP_GetGameTests_MonolithicOnly(HostPlatform, GetAltHostPlatform(HostPlatform), Plat);
										var RequiredPlatforms = new List<UnrealTargetPlatform> { Plat };
										var ThisMonoGameTestNodes = new List<string>();

										foreach (var Test in GameTests)
										{
											var TestNodeName = Test.Key + "_" + Plat.ToString();
											ThisMonoGameTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, CodeProj, TestNodeName, Test.Value, CookedAgentSharingGroup, false, RequiredPlatforms)));
											if (!Options.bTestWithShared || !BranchConfig.HasNode(WaitForTestShared.StaticGetFullName()))
											{
												BranchConfig.RemovePseudodependencyFromNode((UATTestNode.StaticGetFullName(HostPlatform, CodeProj, TestNodeName)), WaitForTestShared.StaticGetFullName());
											}
										}
										if (ThisMonoGameTestNodes.Count > 0)
										{
											GameTestNodes.Add(BranchConfig.AddNode(new GameAggregateNode(HostPlatform, CodeProj, "CookedTests_" + Plat.ToString() + "_" + Kind.ToString() + HostPlatformNode.StaticGetHostPlatformSuffix(HostPlatform), ThisMonoGameTestNodes)));
										}
									}
								}
							}
						}
					}
				}
				if (!bNoAutomatedTesting)
				{
					foreach (var ServerPlatform in ServerPlatforms)
					{
						foreach (var GamePlatform in GamePlatforms)
						{
							if (HostPlatform == UnrealTargetPlatform.Mac || HostPlatform == UnrealTargetPlatform.Linux) continue; //temp hack till Linux and Mac automated testing works
							var Target = CodeProj.Properties.Targets[TargetRules.TargetType.Game];
							var ClientServerTests = Target.Rules.GUBP_GetClientServerTests_MonolithicOnly(HostPlatform, GetAltHostPlatform(HostPlatform), ServerPlatform, GamePlatform);
							var RequiredPlatforms = new List<UnrealTargetPlatform> { ServerPlatform };
							if (ServerPlatform != GamePlatform)
							{
								RequiredPlatforms.Add(GamePlatform);
							}
							foreach (var Test in ClientServerTests)
							{
								var TestNodeName = Test.Key + "_" + GamePlatform.ToString() + "_" + ServerPlatform.ToString();
								GameTestNodes.Add(BranchConfig.AddNode(new UATTestNode(BranchConfig, HostPlatform, CodeProj, TestNodeName, Test.Value, CookedAgentSharingGroup, false, RequiredPlatforms)));
							}
						}
					}
					if (GameTestNodes.Count > 0)
					{
						BranchConfig.AddNode(new GameAggregateNode(HostPlatform, CodeProj, "AllCookedTests", GameTestNodes));
					}
				}
			}
		}

        BranchConfig.AddNode(new WaitForTestShared(this));
		BranchConfig.AddNode(new WaitToPackageSamplesNode(BranchConfig.HostPlatforms));

		AddCustomNodes(BranchConfig, HostPlatforms, ActivePlatforms);
        
        if (BranchConfig.HasNode(ToolsForCompileNode.StaticGetFullName(UnrealTargetPlatform.Win64)))
        {
			if (BranchConfig.HasNode(GamePlatformMonolithicsNode.StaticGetFullName(UnrealTargetPlatform.Mac, Branch.BaseEngineProject, UnrealTargetPlatform.IOS)) && BranchConfig.HasNode(ToolsNode.StaticGetFullName(UnrealTargetPlatform.Win64)))
			{
				//AddNode(new IOSOnPCTestNode(this)); - Disable IOSOnPCTest until a1011 crash is fixed
			}
			//AddNode(new VSExpressTestNode(this));
			if (ActivePlatforms.Contains(UnrealTargetPlatform.Linux) && !BranchOptions.ExcludePlatformsForEditor.Contains(UnrealTargetPlatform.Linux))
			{
				BranchConfig.AddNode(new RootEditorCrossCompileLinuxNode(BranchConfig, UnrealTargetPlatform.Win64));
			}
            // Don't run clean on temp shared storage for preflight builds. They might have broken the clean, and it extends to storage beyond this job.
            if (!BranchConfig.JobInfo.IsPreflight)
            {
                BranchConfig.AddNode(new CleanSharedTempStorageNode(this, BranchConfig));
            }
        }
#if false
        // this doesn't work for lots of reasons...we can't figure out what the dependencies are until far later
        if (bPreflightBuild)
        {
            GeneralSuccessNode PreflightSuccessNode = new GeneralSuccessNode("Preflight");
            foreach (var NodeToDo in GUBPNodes)
            {
                if (NodeToDo.Value.RunInEC())
                {
                    PreflightSuccessNode.AddPseudodependency(NodeToDo.Key);
                }
            }
            AddNode(PreflightSuccessNode);
        }
#endif

		// Remove all the pseudo-dependencies on nodes specified in the branch options
		foreach(string NodeToRemovePseudoDependencies in BranchOptions.NodesToRemovePseudoDependencies)
		{
			GUBPNode Node = BranchConfig.TryFindNode(NodeToRemovePseudoDependencies);
			if(Node != null)
			{
				Node.FullNamesOfPseudodependencies.Clear();
			}
		}

		// Add aggregate nodes for every project in the branch
		foreach (BranchInfo.BranchUProject GameProj in Branch.AllProjects)
		{
			List<string> NodeNames = new List<string>();
			foreach(GUBP.GUBPNode Node in BranchConfig.GUBPNodes.Values)
			{
				if (Node.GameNameIfAnyForTempStorage() == GameProj.GameName)
				{
					NodeNames.Add(Node.GetFullName());
				}
			}
			if (NodeNames.Count > 0)
			{
				BranchConfig.AddNode(new FullGameAggregateNode(GameProj.GameName, NodeNames));
			}
		}

		// Calculate the frequency overrides
		Dictionary<string, int> FrequencyOverrides = ApplyFrequencyBarriers(BranchConfig.GUBPNodes, BranchConfig.GUBPAggregates, BranchOptions.FrequencyBarriers);

		// Get the legacy node to new node mapping
		Dictionary<GUBP.GUBPNode, BuildNode> LegacyToNewNodes = BranchConfig.GUBPNodes.Values.ToDictionary(x => x, x => x.GetBuildNode(this));

		// Convert the GUBPNodes and GUBPAggregates maps into lists
		AllNodes = new List<BuildNode>();
		AllNodes.AddRange(LegacyToNewNodes.Values);

		AllAggregates = new List<AggregateNode>();
		AllAggregates.AddRange(BranchConfig.GUBPAggregates.Values.Select(x => new LegacyAggregateNode(x)));

		// Calculate the frequencies for each node
		FindFrequenciesForNodes(BranchConfig, LegacyToNewNodes, FrequencyOverrides);

		// Get the email list for each node
		FindEmailsForNodes(BranchName, AllNodes);
	}
    private void AddCustomNodes(GUBPBranchConfig BranchConfig, List<UnrealTargetPlatform> HostPlatforms, List<UnrealTargetPlatform> ActivePlatforms)
    {
		List<GUBPNodeAdder> Adders = new List<GUBPNodeAdder>();

		Assembly[] LoadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
		foreach (Assembly Dll in LoadedAssemblies)
		{
			Type[] AllTypes = GetTypesFromAssembly(Dll);
			foreach (Type PotentialConfigType in AllTypes)
			{
				if (PotentialConfigType != typeof(GUBPNodeAdder) && typeof(GUBPNodeAdder).IsAssignableFrom(PotentialConfigType))
				{
					GUBPNodeAdder Config = Activator.CreateInstance(PotentialConfigType) as GUBPNodeAdder;
					if (Config != null)
					{
						Adders.Add(Config);
					}
				}
			}
		}

        foreach (UnrealTargetPlatform HostPlatform in HostPlatforms)
        {
			foreach(GUBPNodeAdder Adder in Adders)
			{
				Adder.AddNodes(this, BranchConfig, HostPlatform, ActivePlatforms);
			}
        }
    }