Example #1
0
        /// <summary>
        /// Reads a config hierarchy (or retrieve it from the cache)
        /// </summary>
        /// <param name="Type">The type of hierarchy to read</param>
        /// <param name="ProjectDir">The project directory to read the hierarchy for</param>
        /// <param name="Platform">Which platform to read platform-specific config files for</param>
        /// <returns>The requested config hierarchy</returns>
        public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given.
            ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform);

            // Try to get the cached hierarchy with this key
            ConfigHierarchy Hierarchy;

            if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy))
            {
                List <ConfigFile> Files = new List <ConfigFile>();
                foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform))
                {
                    ConfigFile File;
                    if (TryReadFile(IniFileName, out File))
                    {
                        Files.Add(File);
                    }
                }

                Hierarchy = new ConfigHierarchy(Files);
                HierarchyKeyToHierarchy.Add(Key, Hierarchy);
            }
            return(Hierarchy);
        }
Example #2
0
 /// <summary>
 /// Construct a key from an archive
 /// </summary>
 /// <param name="Reader">Archive to read from</param>
 public ConfigDependencyKey(BinaryArchiveReader Reader)
 {
     Type        = (ConfigHierarchyType)Reader.ReadInt();
     ProjectDir  = Reader.ReadDirectoryReference();
     Platform    = Reader.ReadUnrealTargetPlatform();
     SectionName = Reader.ReadString();
     KeyName     = Reader.ReadString();
 }
Example #3
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="Type">The config hierarchy type</param>
 /// <param name="ProjectDir">Project directory to read config files from</param>
 /// <param name="Platform">The platform being built</param>
 /// <param name="SectionName">The section name</param>
 /// <param name="KeyName">The key name</param>
 public ConfigDependencyKey(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform, string SectionName, string KeyName)
 {
     this.Type        = Type;
     this.ProjectDir  = ProjectDir;
     this.Platform    = Platform;
     this.SectionName = SectionName;
     this.KeyName     = KeyName;
 }
Example #4
0
        /// <summary>
        /// Reads a config hierarchy (or retrieve it from the cache)
        /// </summary>
        /// <param name="Type">The type of hierarchy to read</param>
        /// <param name="ProjectDir">The project directory to read the hierarchy for</param>
        /// <param name="Platform">Which platform to read platform-specific config files for</param>
        /// <param name="GeneratedConfigDir">Base directory for generated configs</param>
        /// <returns>The requested config hierarchy</returns>
        public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform, DirectoryReference GeneratedConfigDir = null)
        {
            // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given.
            ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform);

            // Try to get the cached hierarchy with this key
            ConfigHierarchy Hierarchy;

            if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy))
            {
                List <ConfigFile> Files = new List <ConfigFile>();
                foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform))
                {
                    ConfigFile File;
                    if (TryReadFile(IniFileName, out File))
                    {
                        Files.Add(File);
                    }
                }

                // If we haven't been given a generated project dir, but we do have a project then the generated configs
                // should go into ProjectDir/Saved
                if (GeneratedConfigDir == null && ProjectDir != null)
                {
                    GeneratedConfigDir = DirectoryReference.Combine(ProjectDir, "Saved");
                }

                if (GeneratedConfigDir != null)
                {
                    // We know where the generated version of this config file lives, so we can read it back in
                    // and include any user settings from there in our hierarchy
                    string        BaseIniName            = Enum.GetName(typeof(ConfigHierarchyType), Type);
                    string        PlatformName           = ConfigHierarchy.GetIniPlatformName(Platform);
                    FileReference DestinationIniFilename = FileReference.Combine(GeneratedConfigDir, "Config", PlatformName, BaseIniName + ".ini");
                    ConfigFile    File;
                    if (TryReadFile(DestinationIniFilename, out File))
                    {
                        Files.Add(File);
                    }
                }

                // Handle command line overrides
                string[] CmdLine            = Environment.GetCommandLineArgs();
                string   IniConfigArgPrefix = "-ini:" + Enum.GetName(typeof(ConfigHierarchyType), Type) + ":";
                foreach (string CmdLineArg in CmdLine)
                {
                    if (CmdLineArg.StartsWith(IniConfigArgPrefix))
                    {
                        ConfigFile OverrideFile = new ConfigFile(CmdLineArg.Substring(IniConfigArgPrefix.Length));
                        Files.Add(OverrideFile);
                    }
                }

                Hierarchy = new ConfigHierarchy(Files);
                HierarchyKeyToHierarchy.Add(Key, Hierarchy);
            }
            return(Hierarchy);
        }
Example #5
0
        /// <summary>
        /// Reads a config hierarchy (or retrieve it from the cache)
        /// </summary>
        /// <param name="Type">The type of hierarchy to read</param>
        /// <param name="ProjectDir">The project directory to read the hierarchy for</param>
        /// <param name="Platform">Which platform to read platform-specific config files for</param>
        /// <returns>The requested config hierarchy</returns>
        public static ConfigHierarchy ReadHierarchy(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            // Get the key to use for the cache. It cannot be null, so we use the engine directory if a project directory is not given.
            ConfigHierarchyKey Key = new ConfigHierarchyKey(Type, ProjectDir, Platform);

            // Try to get the cached hierarchy with this key
            ConfigHierarchy Hierarchy;

            lock (HierarchyKeyToHierarchy)
            {
                if (!HierarchyKeyToHierarchy.TryGetValue(Key, out Hierarchy))
                {
                    // Find all the input files
                    List <ConfigFile> Files = new List <ConfigFile>();
                    foreach (FileReference IniFileName in ConfigHierarchy.EnumerateConfigFileLocations(Type, ProjectDir, Platform))
                    {
                        ConfigFile File;
                        if (TryReadFile(IniFileName, out File))
                        {
                            Files.Add(File);
                        }
                    }

                    // Handle command line overrides
                    string[] CmdLine            = Environment.GetCommandLineArgs();
                    string   IniConfigArgPrefix = "-ini:" + Enum.GetName(typeof(ConfigHierarchyType), Type) + ":";
                    foreach (string CmdLineArg in CmdLine)
                    {
                        if (CmdLineArg.StartsWith(IniConfigArgPrefix))
                        {
                            ConfigFile OverrideFile = new ConfigFile(CmdLineArg.Substring(IniConfigArgPrefix.Length));
                            Files.Add(OverrideFile);
                        }
                    }

                    // Create the hierarchy
                    Hierarchy = new ConfigHierarchy(Files);
                    HierarchyKeyToHierarchy.Add(Key, Hierarchy);
                }
            }
            return(Hierarchy);
        }
Example #6
0
        /// <summary>
        /// Returns a list of INI filenames for the given project
        /// </summary>
        public static IEnumerable <FileReference> EnumerateConfigFileLocations(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            string BaseIniName  = Enum.GetName(typeof(ConfigHierarchyType), Type);
            string PlatformName = GetIniPlatformName(Platform);

            // Engine/Config/Base.ini (included in every ini type, required)
            yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", "Base.ini"));

            // Engine/Config/Base* ini
            yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", "Base" + BaseIniName + ".ini"));

            if (Platform != UnrealTargetPlatform.Unknown)
            {
                // Engine/Config/Platform/BasePlatform* ini
                yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", PlatformName, "Base" + PlatformName + BaseIniName + ".ini"));
            }

            // Engine/Config/NotForLicensees/Base* ini
            yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", "NotForLicensees", "Base" + BaseIniName + ".ini"));

            // NOTE: 4.7: See comment in GetSourceIniHierarchyFilenames()
            // Engine/Config/NoRedist/Base* ini
            // yield return Path.Combine(EngineDirectory, "Config", "NoRedist", "Base" + BaseIniName + ".ini");

            if (ProjectDir != null)
            {
                // Game/Config/Default* ini
                yield return(FileReference.Combine(ProjectDir, "Config", "Default" + BaseIniName + ".ini"));

                // Game/Config/NotForLicensees/Default* ini
                yield return(FileReference.Combine(ProjectDir, "Config", "NotForLicensees", "Default" + BaseIniName + ".ini"));

                // Game/Config/NoRedist/Default* ini
                yield return(FileReference.Combine(ProjectDir, "Config", "NoRedist", "Default" + BaseIniName + ".ini"));
            }

            if (Platform != UnrealTargetPlatform.Unknown)
            {
                // Engine/Config/Platform/Platform* ini
                yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", PlatformName, PlatformName + BaseIniName + ".ini"));

                // Engine/Config/NotForLicensees/Platform/Platform* ini
                yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", "NotForLicensees", PlatformName, PlatformName + BaseIniName + ".ini"));

                // Engine/Config/NoRedist/Platform/Platform* ini
                yield return(FileReference.Combine(UnrealBuildTool.EngineDirectory, "Config", "NoRedist", PlatformName, PlatformName + BaseIniName + ".ini"));

                if (ProjectDir != null)
                {
                    // Game/Config/Platform/Platform* ini
                    yield return(FileReference.Combine(ProjectDir, "Config", PlatformName, PlatformName + BaseIniName + ".ini"));

                    // Engine/Config/NotForLicensees/Platform/Platform* ini
                    yield return(FileReference.Combine(ProjectDir, "Config", "NotForLicensees", PlatformName, PlatformName + BaseIniName + ".ini"));

                    // Engine/Config/NoRedist/Platform/Platform* ini
                    yield return(FileReference.Combine(ProjectDir, "Config", "NoRedist", PlatformName, PlatformName + BaseIniName + ".ini"));
                }
            }

            DirectoryReference UserSettingsFolder = Utils.GetUserSettingDirectory();             // Match FPlatformProcess::UserSettingsDir()

            if (UserSettingsFolder != null)
            {
                // <AppData>/UE4/EngineConfig/User* ini
                yield return(FileReference.Combine(UserSettingsFolder, "Unreal Engine", "Engine", "Config", "User" + BaseIniName + ".ini"));
            }

            // Some user accounts (eg. SYSTEM on Windows) don't have a home directory. Ignore them if Environment.GetFolderPath() returns an empty string.
            string PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);

            if (!String.IsNullOrEmpty(PersonalFolder))
            {
                DirectoryReference PersonalConfigFolder;                 // Match FPlatformProcess::UserDir()
                if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
                {
                    PersonalConfigFolder = DirectoryReference.Combine(new DirectoryReference(PersonalFolder), "Documents");
                }
                else if (Environment.OSVersion.Platform == PlatformID.Unix)
                {
                    PersonalConfigFolder = DirectoryReference.Combine(new DirectoryReference(PersonalFolder), "Documents");
                }
                else
                {
                    PersonalConfigFolder = new DirectoryReference(PersonalFolder);
                }

                // <Documents>/UE4/EngineConfig/User* ini
                yield return(FileReference.Combine(PersonalConfigFolder, "Unreal Engine", "Engine", "Config", "User" + BaseIniName + ".ini"));
            }

            // Game/Config/User* ini
            if (ProjectDir != null)
            {
                yield return(FileReference.Combine(ProjectDir, "Config", "User" + BaseIniName + ".ini"));
            }
        }
Example #7
0
 private ConfigHierarchy GetConfigCacheIni(ConfigHierarchyType Type)
 {
     return(ConfigCache.ReadHierarchy(Type, DirectoryReference.FromFile(ProjectFile), UnrealTargetPlatform.Lumin));
 }
        /// <summary>
        /// Get a ConfigHierarchy of the type you want with platform-specific config for the given Role. This object can be used to read .ini config values.
        /// Default params return the client platform's game config.
        /// This looks for the workspace files for the project that you are trying to run your test on. The config directory for that project must exist to find valid results.
        /// </summary>
        public static ConfigHierarchy GetConfigHierarchy(UnrealTestContext TestContext, ConfigHierarchyType ConfigType = ConfigHierarchyType.Game, UnrealTargetRole TargetRole = UnrealTargetRole.Client)
        {
            string ProjectPath = Path.Combine(Environment.CurrentDirectory, TestContext.BuildInfo.ProjectName);

            if (!Directory.Exists(ProjectPath))
            {
                Log.Warning(string.Format("Directory does not exist at {0}! Returned ConfigHierarchy will not contain any config values. Make sure to sync the config directory for the project you are trying to run.", ProjectPath));
            }

            return(ConfigCache.ReadHierarchy(ConfigType, new DirectoryReference(ProjectPath), TestContext.GetRoleContext(TargetRole).Platform));
        }
Example #9
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="Type">The hierarchy type</param>
 /// <param name="ProjectDir">The project directory to read from</param>
 /// <param name="Platform">Which platform-specific files to read</param>
 public ConfigHierarchyKey(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
 {
     this.Type       = Type;
     this.ProjectDir = ProjectDir;
     this.Platform   = Platform;
 }
 private ConfigHierarchy GetConfigCacheIni(ConfigHierarchyType Type)
 {
     // @todo Lumin: So - this is the problem with subclassing a platform currently - ini files. Lumin will use Android ini files
     // until I finish and get code over from another branch (key letter Q) that allows for insertion of a subclassed ini platform thing
     return(ConfigCache.ReadHierarchy(Type, DirectoryReference.FromFile(ProjectFile), UnrealTargetPlatform.Android));
 }
Example #11
0
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="ConfigType">Type of the config hierarchy to read from</param>
 /// <param name="SectionName">Section containing the setting</param>
 /// <param name="KeyName">Key name to search for. Optional; uses the name of the field if not set.</param>
 public ConfigFileAttribute(ConfigHierarchyType ConfigType, string SectionName, string KeyName = null)
 {
     this.ConfigType  = ConfigType;
     this.SectionName = SectionName;
     this.KeyName     = KeyName;
 }
Example #12
0
		/// <summary>
		/// Returns a list of INI filenames for the given project
		/// </summary>
		public static IEnumerable<FileReference> EnumerateConfigFileLocations(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
		{
			string BaseIniName = Enum.GetName(typeof(ConfigHierarchyType), Type);
			string PlatformName = GetIniPlatformName(Platform);

			// cache some platform extension information that can be used inside the loops
			string PlatformExtensionEngineConfigDir = DirectoryReference.Combine(UnrealBuildTool.PlatformExtensionsDirectory, Platform.ToString(), "Engine").FullName;
			string PlatformExtensionProjectConfigDir = ProjectDir != null ? DirectoryReference.Combine(UnrealBuildTool.PlatformExtensionsDirectory, Platform.ToString(), ProjectDir.GetDirectoryName()).FullName : null;
			bool bHasPlatformExtensionEngineConfigDir = Directory.Exists(PlatformExtensionEngineConfigDir);
			bool bHasPlatformExtensionProjectConfigDir = PlatformExtensionProjectConfigDir != null && Directory.Exists(PlatformExtensionProjectConfigDir);


			foreach (ConfigLayer Layer in ConfigLayers)
			{
				bool bHasPlatformTag = Layer.Path.Contains("{PLATFORM}");
				bool bHasProjectTag = Layer.Path.Contains("{PROJECT}");
				bool bHasExpansionTag = Layer.Path.Contains("{ED}") || Layer.Path.Contains("{EF}");
				bool bHasUserTag = Layer.Path.Contains("{USER}");

				// skip platform layers if we are "platform-less", or user layers without a user dir
				if (bHasPlatformTag && Platform == null ||
					bHasProjectTag && ProjectDir == null ||
					bHasUserTag && GetUserDir() == null)
				{
					continue;
				}

				// basic replacements
				string LayerPath;
				// you can only have PROJECT or ENGINE, not both
				if (bHasProjectTag)
				{
					if (bHasPlatformTag && bHasPlatformExtensionProjectConfigDir)
					{
						LayerPath = Layer.ExtProjectPath.Replace("{EXTPROJECT}", PlatformExtensionProjectConfigDir);
					}
					else
					{
						LayerPath = Layer.Path.Replace("{PROJECT}", ProjectDir.FullName);
					}
				}
				else
				{
					if (bHasPlatformTag && bHasPlatformExtensionEngineConfigDir)
					{
						LayerPath = Layer.ExtEnginePath.Replace("{EXTENGINE}", PlatformExtensionEngineConfigDir);
					}
					else
					{
						LayerPath = Layer.Path.Replace("{ENGINE}", UnrealBuildTool.EngineDirectory.FullName);
					}
				}
				LayerPath = LayerPath.Replace("{TYPE}", BaseIniName);
				LayerPath = LayerPath.Replace("{USERSETTINGS}", Utils.GetUserSettingDirectory().FullName);
				if (bHasUserTag) LayerPath = LayerPath.Replace("{USER}", GetUserDir());


				// handle expansion (and platform - the C++ code will validate that only expansion layers have platforms)
				if (bHasExpansionTag)
				{
					foreach (ConfigLayerExpansion Expansion in ConfigLayerExpansions)
					{
						// expansion replacements
						string ExpansionPath = LayerPath.Replace("{ED}", Expansion.DirectoryPrefix);
						ExpansionPath = ExpansionPath.Replace("{EF}", Expansion.FilePrefix);

						// now go up the ini parent chain
						if (bHasPlatformTag)
						{
							DataDrivenPlatformInfo.ConfigDataDrivenPlatformInfo Info = DataDrivenPlatformInfo.GetDataDrivenInfoForPlatform(PlatformName);
							if (Info != null && Info.IniParentChain != null)
							{
								// the IniParentChain
								foreach (string ParentPlatform in Info.IniParentChain)
								{
									yield return new FileReference(ExpansionPath.Replace("{PLATFORM}", ParentPlatform));
								}
							}
							// always yield the active platform last 
							yield return new FileReference(ExpansionPath.Replace("{PLATFORM}", PlatformName));
						}
						else
						{
							yield return new FileReference(ExpansionPath);
						}
					}
				}
				else
				{
					yield return new FileReference(LayerPath);
				}
			}

			// Get the generated config file too. EditorSettings overrides this from 
			if(Type == ConfigHierarchyType.EditorSettings)
			{
				yield return FileReference.Combine(GetGameAgnosticSavedDir(), "Config", PlatformName, BaseIniName + ".ini");
			}
			else
			{
				yield return FileReference.Combine(GetGeneratedConfigDir(ProjectDir), PlatformName, BaseIniName + ".ini");
			}
		}
Example #13
0
        /// <summary>
        /// Adds a new configuration value
        /// </summary>
        /// <param name="Type">The config hierarchy type</param>
        /// <param name="ProjectDir">The project directory</param>
        /// <param name="Platform">The platform being built</param>
        /// <param name="SectionName">Name of the config file section</param>
        /// <param name="KeyName">Name of the config file key</param>
        /// <param name="Values">Current values for this key</param>
        public void Add(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform, string SectionName, string KeyName, IReadOnlyList <string> Values)
        {
            ConfigDependencyKey Key = new ConfigDependencyKey(Type, ProjectDir, Platform, SectionName, KeyName);

            Dependencies[Key] = Values;
        }
Example #14
0
        /// <summary>
        /// Returns a list of INI filenames for the given project
        /// </summary>
        public static IEnumerable <FileReference> EnumerateGeneratedConfigFileLocations(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            string BaseIniName  = Enum.GetName(typeof(ConfigHierarchyType), Type);
            string PlatformName = GetIniPlatformName(Platform);

            // Get the generated config file too. EditorSettings overrides this from
            if (Type == ConfigHierarchyType.EditorSettings)
            {
                yield return(FileReference.Combine(GetGameAgnosticSavedDir(), "Config", PlatformName, BaseIniName + ".ini"));
            }
            else
            {
                yield return(FileReference.Combine(GetGeneratedConfigDir(ProjectDir), PlatformName, BaseIniName + ".ini"));
            }
        }
Example #15
0
        /// <summary>
        /// Returns a list of INI filenames for the given project
        /// </summary>
        public static IEnumerable <FileReference> EnumerateConfigFileLocations(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            string BaseIniName  = Enum.GetName(typeof(ConfigHierarchyType), Type);
            string PlatformName = GetIniPlatformName(Platform);

            foreach (ConfigLayer Layer in ConfigLayers)
            {
                bool   bHasPlatformTag, bHasProjectTag, bHasExpansionTag;
                string LayerPath = GetLayerPath(Layer, Platform.ToString(), PlatformName, ProjectDir, BaseIniName, out bHasPlatformTag, out bHasProjectTag, out bHasExpansionTag);

                // skip the layer if we aren't going to use it
                if (LayerPath == null)
                {
                    continue;
                }

                // handle expansion (and platform - the C++ code will validate that only expansion layers have platforms)
                if (bHasExpansionTag)
                {
                    foreach (ConfigLayerExpansion Expansion in ConfigLayerExpansions)
                    {
                        // expansion replacements
                        string ExpansionPath = GetExpansionPath(Expansion, LayerPath);

                        // now go up the ini parent chain
                        if (bHasPlatformTag)
                        {
                            DataDrivenPlatformInfo.ConfigDataDrivenPlatformInfo Info = DataDrivenPlatformInfo.GetDataDrivenInfoForPlatform(PlatformName);
                            if (Info != null && Info.IniParentChain != null)
                            {
                                // the IniParentChain
                                foreach (string ParentPlatform in Info.IniParentChain)
                                {
                                    // @note: We are using the ParentPlatform as both PlatformExtensionName _and_ IniPlatformName. This is because the parent
                                    // may not even exist as a UnrealTargetPlatform, and all we have is a string to look up, and it would just get the same
                                    // string back, if we did look it up. This could become an issue if Win64 becomes a PlatformExtension, and wants to have
                                    // a parent Platform, of ... something. This is likely to never be an issue, but leaving this note here just in case.
                                    string LocalLayerPath     = GetLayerPath(Layer, ParentPlatform, ParentPlatform, ProjectDir, BaseIniName, out bHasPlatformTag, out bHasProjectTag, out bHasExpansionTag);
                                    string LocalExpansionPath = GetExpansionPath(Expansion, LocalLayerPath);
                                    yield return(new FileReference(LocalExpansionPath.Replace("{PLATFORM}", ParentPlatform)));
                                }
                            }
                            // always yield the active platform last
                            yield return(new FileReference(ExpansionPath.Replace("{PLATFORM}", PlatformName)));
                        }
                        else
                        {
                            yield return(new FileReference(ExpansionPath));
                        }
                    }
                }
                else
                {
                    yield return(new FileReference(LayerPath));
                }
            }

            // Find all the generated config files
            foreach (FileReference GeneratedConfigFile in EnumerateGeneratedConfigFileLocations(Type, ProjectDir, Platform))
            {
                yield return(GeneratedConfigFile);
            }
        }
        /// <summary>
        /// Returns a list of INI filenames for the given project
        /// </summary>
        public static IEnumerable <FileReference> EnumerateConfigFileLocations(ConfigHierarchyType Type, DirectoryReference ProjectDir, UnrealTargetPlatform Platform)
        {
            string BaseIniName  = Enum.GetName(typeof(ConfigHierarchyType), Type);
            string PlatformName = GetIniPlatformName(Platform);

            foreach (string Layer in ConfigLayers)
            {
                bool bHasPlatformTag = Layer.Contains("{PLATFORM}");
                bool bHasProjectTag  = Layer.Contains("{PROJECT}");
                bool bHasUserTag     = Layer.Contains("{USER}");

                // skip certain layers if we are platform-less, project-less, or userdir-less
                if ((bHasPlatformTag && PlatformName == "None") ||
                    (bHasProjectTag && ProjectDir == null) ||
                    (bHasUserTag && GetUserDir() == null))
                {
                    continue;
                }

                string LayerPath = PerformBasicReplacements(Layer, BaseIniName);

                // we only expand engine/project inis
                if (Layer.Contains("{ENGINE}") || Layer.Contains("{PROJECT}"))
                {
                    foreach (ConfigLayerExpansion Expansion in ConfigLayerExpansions)
                    {
                        // expansion replacements
                        string ExpandedPath = PerformExpansionReplacements(Expansion, LayerPath);

                        // if nothing was replaced, then skip it, as it won't change anything
                        if (ExpandedPath == null)
                        {
                            continue;
                        }

                        // now go up the ini parent chain
                        if (bHasPlatformTag)
                        {
                            DataDrivenPlatformInfo.ConfigDataDrivenPlatformInfo Info = DataDrivenPlatformInfo.GetDataDrivenInfoForPlatform(PlatformName);
                            if (Info != null && Info.IniParentChain != null)
                            {
                                // the IniParentChain
                                foreach (string ParentPlatform in Info.IniParentChain)
                                {
                                    // @note: We are using the ParentPlatform as both PlatformExtensionName _and_ IniPlatformName. This is because the parent
                                    // may not even exist as a UnrealTargetPlatform, and all we have is a string to look up, and it would just get the same
                                    // string back, if we did look it up. This could become an issue if Win64 becomes a PlatformExtension, and wants to have
                                    // a parent Platform, of ... something. This is likely to never be an issue, but leaving this note here just in case.
                                    yield return(new FileReference(PerformFinalExpansions(ExpandedPath, ParentPlatform, ProjectDir)));
                                }
                            }
                            // always yield the active platform last
                            yield return(new FileReference(PerformFinalExpansions(ExpandedPath, PlatformName, ProjectDir)));
                        }
                        else
                        {
                            yield return(new FileReference(PerformFinalExpansions(ExpandedPath, "", ProjectDir)));
                        }
                    }
                }
                else
                {
                    yield return(new FileReference(LayerPath));
                }
            }

            // Find all the generated config files
            foreach (FileReference GeneratedConfigFile in EnumerateGeneratedConfigFileLocations(Type, ProjectDir, Platform))
            {
                yield return(GeneratedConfigFile);
            }
        }