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); }
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")); } }
/// <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")); } }
/// <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); }
/// <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")); } }
/// <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); } } } }
/// <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"); } }