private static string PerformBasicReplacements(string InString, string BaseIniName)
        {
            string OutString = InString.Replace("{TYPE}", BaseIniName);

            OutString = OutString.Replace("{USERSETTINGS}", Utils.GetUserSettingDirectory().FullName);
            OutString = OutString.Replace("{USER}", GetUserDir());

            return(OutString);
        }
Beispiel #2
0
        private static string GetLayerPath(ConfigLayer Layer, string PlatformExtensionName, string IniPlatformName, DirectoryReference ProjectDir, string BaseIniName,
                                           out bool bHasPlatformTag, out bool bHasProjectTag, out bool bHasExpansionTag)
        {
            // cache some platform extension information that can be used inside the loops
            string PlatformExtensionEngineConfigDir  = DirectoryReference.Combine(UnrealBuildTool.EnginePlatformExtensionsDirectory, PlatformExtensionName).FullName;
            string PlatformExtensionProjectConfigDir = ProjectDir != null?DirectoryReference.Combine(UnrealBuildTool.ProjectPlatformExtensionsDirectory(ProjectDir), PlatformExtensionName).FullName : null;

            bool bHasPlatformExtensionEngineConfigDir  = Directory.Exists(PlatformExtensionEngineConfigDir);
            bool bHasPlatformExtensionProjectConfigDir = PlatformExtensionProjectConfigDir != null && Directory.Exists(PlatformExtensionProjectConfigDir);

            bHasPlatformTag  = Layer.Path.Contains("{PLATFORM}");
            bHasProjectTag   = Layer.Path.Contains("{PROJECT}");
            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 && IniPlatformName == "None") ||
                (bHasProjectTag && ProjectDir == null) ||
                (bHasUserTag && GetUserDir() == null))
            {
                return(null);
            }

            // 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);
            LayerPath = LayerPath.Replace("{USER}", GetUserDir());

            return(LayerPath);
        }
 /// <summary>
 /// Determes the path to the game-agnostic saved directory (same as FPaths::GameAgnosticSavedDir())
 /// </summary>
 /// <returns></returns>
 public static DirectoryReference GetGameAgnosticSavedDir()
 {
     if (UnrealBuildTool.IsEngineInstalled())
     {
         return(DirectoryReference.Combine(Utils.GetUserSettingDirectory(), "UnrealEngine", String.Format("{0}.{1}", ReadOnlyBuildVersion.Current.MajorVersion, ReadOnlyBuildVersion.Current.MinorVersion), "Saved"));
     }
     else
     {
         return(DirectoryReference.Combine(UnrealBuildTool.EngineDirectory, "Saved"));
     }
 }
Beispiel #4
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"));
            }
        }
Beispiel #5
0
        /// <summary>
        /// Creates a rules assembly
        /// </summary>
        /// <param name="Scope">Scope for items created from this assembly</param>
        /// <param name="RootDirectories">The root directories to create rules for</param>
        /// <param name="AssemblyPrefix">A prefix for the assembly file name</param>
        /// <param name="Plugins">List of plugins to include in this assembly</param>
        /// <param name="bReadOnly">Whether the assembly should be marked as installed</param>
        /// <param name="bSkipCompile">Whether to skip compilation for this assembly</param>
        /// <param name="Parent">The parent rules assembly</param>
        /// <returns>New rules assembly</returns>
        private static RulesAssembly CreateEngineOrEnterpriseRulesAssembly(RulesScope Scope, List <DirectoryReference> RootDirectories, string AssemblyPrefix, IReadOnlyList <PluginInfo> Plugins, bool bReadOnly, bool bSkipCompile, RulesAssembly Parent)
        {
            // Scope hierarchy
            RulesScope PluginsScope  = new RulesScope(Scope.Name + " Plugins", Scope);
            RulesScope ProgramsScope = new RulesScope(Scope.Name + " Programs", PluginsScope);

            // Find the shared modules, excluding the programs directory. These are used to create an assembly with the bContainsEngineModules flag set to true.
            Dictionary <FileReference, ModuleRulesContext> ModuleFileToContext = new Dictionary <FileReference, ModuleRulesContext>();
            ModuleRulesContext DefaultModuleContext = new ModuleRulesContext(Scope, RootDirectories[0]);

            foreach (DirectoryReference RootDirectory in RootDirectories)
            {
                using (Timeline.ScopeEvent("Finding engine modules"))
                {
                    DirectoryReference SourceDirectory = DirectoryReference.Combine(RootDirectory, "Source");

                    AddEngineModuleRulesWithContext(SourceDirectory, "Runtime", DefaultModuleContext, UHTModuleType.EngineRuntime, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "Developer", DefaultModuleContext, UHTModuleType.EngineDeveloper, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "Editor", DefaultModuleContext, UHTModuleType.EngineEditor, ModuleFileToContext);
                    AddEngineModuleRulesWithContext(SourceDirectory, "ThirdParty", DefaultModuleContext, UHTModuleType.EngineThirdParty, ModuleFileToContext);
                }
            }

            // Add all the plugin modules too (don't need to loop over RootDirectories since the plugins come in already found
            using (Timeline.ScopeEvent("Finding plugin modules"))
            {
                ModuleRulesContext PluginsModuleContext = new ModuleRulesContext(PluginsScope, RootDirectories[0]);
                FindModuleRulesForPlugins(Plugins, PluginsModuleContext, ModuleFileToContext);
            }

            // Get the path to store any generated assemblies
            DirectoryReference AssemblyDir = RootDirectories[0];

            if (UnrealBuildTool.IsFileInstalled(FileReference.Combine(AssemblyDir, AssemblyPrefix)))
            {
                DirectoryReference UserDir = Utils.GetUserSettingDirectory();
                if (UserDir != null)
                {
                    ReadOnlyBuildVersion Version = ReadOnlyBuildVersion.Current;
                    AssemblyDir = DirectoryReference.Combine(UserDir, "UnrealEngine", String.Format("{0}.{1}", Version.MajorVersion, Version.MinorVersion));
                }
            }

            // Create the assembly
            FileReference EngineAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "Rules" + FrameworkAssemblyExtension);
            RulesAssembly EngineAssembly         = new RulesAssembly(Scope, RootDirectories, Plugins, ModuleFileToContext, new List <FileReference>(), EngineAssemblyFileName, bContainsEngineModules: true, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: Parent);

            List <FileReference> ProgramTargetFiles = new List <FileReference>();
            Dictionary <FileReference, ModuleRulesContext> ProgramModuleFiles = new Dictionary <FileReference, ModuleRulesContext>();

            foreach (DirectoryReference RootDirectory in RootDirectories)
            {
                DirectoryReference SourceDirectory   = DirectoryReference.Combine(RootDirectory, "Source");
                DirectoryReference ProgramsDirectory = DirectoryReference.Combine(SourceDirectory, "Programs");

                // Also create a scope for them, and update the UHT module type
                ModuleRulesContext ProgramsModuleContext = new ModuleRulesContext(ProgramsScope, RootDirectory);
                ProgramsModuleContext.DefaultUHTModuleType = UHTModuleType.Program;

                using (Timeline.ScopeEvent("Finding program modules"))
                {
                    // Find all the rules files
                    AddModuleRulesWithContext(ProgramsDirectory, ProgramsModuleContext, ProgramModuleFiles);
                }

                using (Timeline.ScopeEvent("Finding program targets"))
                {
                    ProgramTargetFiles.AddRange(FindAllRulesFiles(SourceDirectory, RulesFileType.Target));
                }
            }

            // Create a path to the assembly that we'll either load or compile
            FileReference ProgramAssemblyFileName = FileReference.Combine(AssemblyDir, "Intermediate", "Build", "BuildRules", AssemblyPrefix + "ProgramRules" + FrameworkAssemblyExtension);
            RulesAssembly ProgramAssembly         = new RulesAssembly(ProgramsScope, RootDirectories, new List <PluginInfo>().AsReadOnly(), ProgramModuleFiles, ProgramTargetFiles, ProgramAssemblyFileName, bContainsEngineModules: false, DefaultBuildSettings: BuildSettingsVersion.Latest, bReadOnly: bReadOnly, bSkipCompile: bSkipCompile, Parent: EngineAssembly);

            // Return the combined assembly
            return(ProgramAssembly);
        }
Beispiel #6
0
        /// <summary>
        /// Returns a list of INI filenames for the given project
        /// </summary>
        private static IEnumerable <string> EnumerateCrossPlatformIniFileNames(string ProjectDirectory, string EngineDirectory, UnrealTargetPlatform Platform, string BaseIniName)
        {
            // Engine/Config/Base.ini (included in every ini type, required)
            yield return(Path.Combine(EngineDirectory, "Config", "Base.ini"));

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

            // Engine/Config/NotForLicensees/Base* ini
            yield return(Path.Combine(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 (!String.IsNullOrEmpty(ProjectDirectory))
            {
                // Game/Config/Default* ini
                yield return(Path.Combine(ProjectDirectory, "Config", "Default" + BaseIniName + ".ini"));

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

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

            string PlatformName = GetIniPlatformName(Platform);

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

                if (!String.IsNullOrEmpty(ProjectDirectory))
                {
                    // Game/Config/Platform/Platform* ini
                    yield return(Path.Combine(ProjectDirectory, "Config", PlatformName, PlatformName + BaseIniName + ".ini"));
                }
            }

            string UserSettingsFolder = Utils.GetUserSettingDirectory(); // Match FPlatformProcess::UserSettingsDir()
            string PersonalFolder     = null;                            // Match FPlatformProcess::UserDir()

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
            {
                PersonalFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Documents");
            }
            else if (Environment.OSVersion.Platform == PlatformID.Unix)
            {
                PersonalFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Documents");
            }
            else
            {
                PersonalFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            }

            // <AppData>/UE4/EngineConfig/User* ini
            yield return(Path.Combine(UserSettingsFolder, "Unreal Engine", "Engine", "Config", "User" + BaseIniName + ".ini"));

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

            // Game/Config/User* ini
            if (!String.IsNullOrEmpty(ProjectDirectory))
            {
                yield return(Path.Combine(ProjectDirectory, "Config", "User" + BaseIniName + ".ini"));
            }
        }
Beispiel #7
0
        /// <summary>
        /// Initialize the config system with the given types
        /// </summary>
        /// <param name="OverrideCacheFile">Force use of the cached XML config without checking if it's valid (useful for remote builds)</param>
        public static void ReadConfigFiles(FileReference OverrideCacheFile)
        {
            // Find all the configurable types
            List <Type> ConfigTypes = FindConfigurableTypes();

            // Update the cache if necessary
            if (OverrideCacheFile != null)
            {
                // Set the cache file to the overriden value
                CacheFile = OverrideCacheFile;

                // Never rebuild the cache; just try to load it.
                if (!XmlConfigData.TryRead(CacheFile, ConfigTypes, out Values))
                {
                    throw new BuildException("Unable to load XML config cache ({0})", CacheFile);
                }
            }
            else
            {
                // Get the default cache file
                CacheFile = FileReference.Combine(UnrealBuildTool.EngineDirectory, "Intermediate", "Build", "XmlConfigCache.bin");
                if (UnrealBuildTool.IsEngineInstalled())
                {
                    DirectoryReference UserSettingsDir = Utils.GetUserSettingDirectory();
                    if (UserSettingsDir != null)
                    {
                        CacheFile = FileReference.Combine(UserSettingsDir, "UnrealEngine", String.Format("XmlConfigCache-{0}.bin", UnrealBuildTool.RootDirectory.FullName.Replace(":", "").Replace(Path.DirectorySeparatorChar, '+')));
                    }
                }

                // Find all the input files
                FileReference[] InputFiles = FindInputFiles().Select(x => x.Location).ToArray();

                // Get the path to the schema
                FileReference SchemaFile = GetSchemaLocation();

                // Try to read the existing cache from disk
                XmlConfigData CachedValues;
                if (IsCacheUpToDate(CacheFile, InputFiles) && FileReference.Exists(SchemaFile))
                {
                    if (XmlConfigData.TryRead(CacheFile, ConfigTypes, out CachedValues) && Enumerable.SequenceEqual(InputFiles, CachedValues.InputFiles))
                    {
                        Values = CachedValues;
                    }
                }

                // If that failed, regenerate it
                if (Values == null)
                {
                    // Find all the configurable fields from the given types
                    Dictionary <string, Dictionary <string, FieldInfo> > CategoryToFields = new Dictionary <string, Dictionary <string, FieldInfo> >();
                    FindConfigurableFields(ConfigTypes, CategoryToFields);

                    // Create a schema for the config files
                    XmlSchema Schema = CreateSchema(CategoryToFields);
                    if (!UnrealBuildTool.IsEngineInstalled())
                    {
                        WriteSchema(Schema, SchemaFile);
                    }

                    // Read all the XML files and validate them against the schema
                    Dictionary <Type, Dictionary <FieldInfo, object> > TypeToValues = new Dictionary <Type, Dictionary <FieldInfo, object> >();
                    foreach (FileReference InputFile in InputFiles)
                    {
                        if (!TryReadFile(InputFile, CategoryToFields, TypeToValues, Schema))
                        {
                            throw new BuildException("Failed to properly read XML file : {0}", InputFile.FullName);
                        }
                    }

                    // Make sure the cache directory exists
                    DirectoryReference.CreateDirectory(CacheFile.Directory);

                    // Create the new cache
                    Values = new XmlConfigData(InputFiles, TypeToValues.ToDictionary(x => x.Key, x => x.Value.ToArray()));
                    Values.Write(CacheFile);
                }
            }

            // Apply all the static field values
            foreach (KeyValuePair <Type, KeyValuePair <FieldInfo, object>[]> TypeValuesPair in Values.TypeToValues)
            {
                foreach (KeyValuePair <FieldInfo, object> FieldValuePair in TypeValuesPair.Value)
                {
                    if (FieldValuePair.Key.IsStatic)
                    {
                        object Value = InstanceValue(FieldValuePair.Value, FieldValuePair.Key.FieldType);
                        FieldValuePair.Key.SetValue(null, Value);
                    }
                }
            }
        }
Beispiel #8
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");
			}
		}