public static void CreateStagingManifest(ProjectParams Params, DeploymentContext SC) { if (!Params.Stage) { return; } var ThisPlatform = SC.StageTargetPlatform; LogConsole("Creating Staging Manifest..."); if (Params.HasDLCName) { string DLCName = Params.DLCName; // Making a plugin, grab the binaries too SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName), "*.uplugin", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4-*.so", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4-*.dll", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4Server-*.so", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4Server-*.dll", true, null, null, true); // Put all of the cooked dir into the staged dir // Dedicated server cook doesn't save shaders so no Engine dir is created if ((!SC.DedicatedServer) && (!Params.DLCIncludeEngineContent)) { if (Directory.Exists(CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform, "Engine"))) { SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { CommandUtils.CombinePaths("Engine", "*") }, "", true, !Params.UsePak(SC.StageTargetPlatform)); } } SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { "AssetRegistry.bin" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); return; } ThisPlatform.GetFilesToDeployOrStage(Params, SC); // Stage any extra runtime dependencies from the receipts foreach(TargetReceipt Receipt in SC.StageTargetReceipts) { SC.StageRuntimeDependenciesFromReceipt(Receipt); } // Get the build.properties file // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file // @todo: Maybe there should be a new category - UFSNotForPak string BuildPropertiesPath = CombinePaths(SC.LocalRoot, "Engine/Build"); if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { BuildPropertiesPath = BuildPropertiesPath.ToLowerInvariant(); } SC.StageFiles(StagedFileType.NonUFS, BuildPropertiesPath, "Build.version", false, null, null, true); // move the UE4Commandline.txt file to the root of the stage // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file // @todo: Maybe there should be a new category - UFSNotForPak string CommandLineFile = "UE4CommandLine.txt"; if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { CommandLineFile = CommandLineFile.ToLowerInvariant(); } SC.StageFiles(StagedFileType.NonUFS, GetIntermediateCommandlineDir(SC), CommandLineFile, false, null, "", true, false); ConfigCacheIni PlatformGameConfig = new ConfigCacheIni(SC.StageTargetPlatform.PlatformType, "Game", CommandUtils.GetDirectoryName(Params.RawProjectPath)); var ProjectContentRoot = CombinePaths(SC.ProjectRoot, "Content"); var StageContentRoot = CombinePaths(SC.RelativeProjectRootForStage, "Content"); if (!Params.CookOnTheFly && !Params.SkipCookOnTheFly) // only stage the UFS files if we are not using cook on the fly { // Initialize internationalization preset. string InternationalizationPreset = null; // Use parameters if provided. if (string.IsNullOrEmpty(InternationalizationPreset)) { InternationalizationPreset = Params.InternationalizationPreset; } // Use configuration if otherwise lacking an internationalization preset. if (string.IsNullOrEmpty(InternationalizationPreset)) { if (PlatformGameConfig != null) { PlatformGameConfig.GetString("/Script/UnrealEd.ProjectPackagingSettings", "InternationalizationPreset", out InternationalizationPreset); } } // Error if no preset has been provided. if (string.IsNullOrEmpty(InternationalizationPreset)) { throw new AutomationException("No internationalization preset was specified for packaging. This will lead to fatal errors when launching. Specify preset via commandline (-I18NPreset=) or project packaging settings (InternationalizationPreset)."); } // Initialize cultures to stage. List<string> CulturesToStage = null; // Use parameters if provided. if (Params.CulturesToCook != null && Params.CulturesToCook.Count > 0) { CulturesToStage = Params.CulturesToCook; } // Use configuration if otherwise lacking cultures to stage. if (CulturesToStage == null || CulturesToStage.Count == 0) { if (PlatformGameConfig != null) { PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "CulturesToStage", out CulturesToStage); } } // Error if no cultures have been provided. if (CulturesToStage == null || CulturesToStage.Count == 0) { throw new AutomationException("No cultures were specified for cooking and packaging. This will lead to fatal errors when launching. Specify culture codes via commandline (-CookCultures=) or using project packaging settings (+CulturesToStage)."); } // Stage ICU internationalization data from Engine. SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), true, !Params.UsePak(SC.StageTargetPlatform)); // Engine ufs (content) SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Config"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. // Stat prefix/suffix files (used for FPSChart, etc...) //@TODO: Avoid packaging stat files in shipping builds (only 6 KB, but still more than zero) SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Stats"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); if (Params.bUsesSlate) { if (Params.bUsesSlateEditorStyle) { SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Editor/Slate"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); } SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Content/Slate"), "*", true, new string[] { "*.uasset" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Slate"), true, !Params.UsePak(SC.StageTargetPlatform)); } foreach (string Culture in CulturesToStage) { StageLocalizationDataForCulture(SC, Culture, CombinePaths(SC.LocalRoot, "Engine/Content/Localization/Engine"), null, !Params.UsePak(SC.StageTargetPlatform)); } // Engine & Game Plugins. Push the Engine/Source working directory so UBT code has a correct RelativeEnginePath in ReadAvailablePlugins ProjectDescriptor Project = ProjectDescriptor.FromFile(SC.RawProjectPath); Log("Searching for plugins with CurrentWorkingDir: " + Directory.GetCurrentDirectory()); Log("Searching for plugins in: " + SC.RawProjectPath); List<PluginInfo> AvailablePlugins = Plugins.ReadAvailablePlugins(CombinePaths(SC.LocalRoot, "Engine"), SC.RawProjectPath); foreach (PluginInfo Plugin in AvailablePlugins) { Log("Considering Plugin for Stage: " + Plugin.FileName); if (UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType)) { Log("EnabledPlugin: " + Plugin.FileName); SC.StageFiles(StagedFileType.UFS, Plugin.Directory, "*.uplugin", false, null, null, true, !Params.UsePak(SC.StageTargetPlatform), null, true, false); } } // Game ufs (content) SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot), "*.uproject", false, null, CombinePaths(SC.RelativeProjectRootForStage), true, !Params.UsePak(SC.StageTargetPlatform)); if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.HTML5 && SC.bUseWebsocketNetDriver) { var EngineIniPath = Path.Combine(SC.ProjectRoot, "Config", "DefaultEngine.ini"); var IntermediateEngineIniDir = Path.Combine(GetIntermediateCommandlineDir(SC), SC.RelativeProjectRootForStage, "Config"); Directory.CreateDirectory(IntermediateEngineIniDir); var IntermediateEngineIniPath = Path.Combine(IntermediateEngineIniDir, "DefaultEngine.ini"); List<String> IniLines = new List<String>(); if (File.Exists(EngineIniPath)) { IniLines = File.ReadAllLines(EngineIniPath).ToList(); } IniLines.Add("[/Script/Engine.GameEngine]"); IniLines.Add("!NetDriverDefinitions=ClearArray"); IniLines.Add("+NetDriverDefinitions=(DefName=\"GameNetDriver\", DriverClassName=\"/Script/HTML5Networking.WebSocketNetDriver\", DriverClassNameFallback=\"/Script/HTML5Networking.WebSocketNetDriver\")"); File.WriteAllLines(IntermediateEngineIniPath, IniLines); SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, new string[] {"DefaultEngine.ini"}, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. SC.StageFiles(StagedFileType.UFS, IntermediateEngineIniDir, "*.ini", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. } else { SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. } foreach (string Culture in CulturesToStage) { StageLocalizationDataForCulture(SC, Culture, CombinePaths(SC.ProjectRoot, "Content/Localization/Game"), CombinePaths(SC.RelativeProjectRootForStage, "Content/Localization/Game"), !Params.UsePak(SC.StageTargetPlatform)); } // Stage any additional UFS and NonUFS paths specified in the project ini files; these dirs are relative to the game content directory if (PlatformGameConfig != null) { List<string> ExtraUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsUFS", out ExtraUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' foreach (var PathStr in ExtraUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } List<string> ExtraNonUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' foreach (var PathStr in ExtraNonUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } } StagedFileType StagedFileTypeForMovies = StagedFileType.NonUFS; if (Params.FileServer) { // UFS is required when using a file server StagedFileTypeForMovies = StagedFileType.UFS; } if (SC.StageTargetPlatform.StageMovies) { SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.LocalRoot, "Engine/Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Engine/Content/Movies"), true, !Params.UsePak(SC.StageTargetPlatform)); SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.ProjectRoot, "Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Movies"), true, !Params.UsePak(SC.StageTargetPlatform)); } // eliminate the sand box SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform), "*", true, new string[] { "*.json" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); // CrashReportClient is a standalone slate app that does not look in the generated pak file, so it needs the Content/Slate and Shaders/StandaloneRenderer folders Non-UFS // @todo Make CrashReportClient more portable so we don't have to do this if (SC.bStageCrashReporter && UnrealBuildTool.UnrealBuildTool.PlatformSupportsCrashReporter(SC.StageTargetPlatform.PlatformType) && !SC.DedicatedServer) { //If the .dat file needs to be staged as NonUFS for non-Windows/Linux hosts we need to change the casing as we do with the build properties file above. SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate")); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Shaders/StandaloneRenderer")); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), false, true); // Linux platform stages ICU in GetFilesToDeployOrStage(), accounting for the actual architecture if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win32 || SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Mac) { SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Binaries/ThirdParty/ICU")); } // SSL libraries are only available for Win64 builds. // @see FPerforceSourceControlProvider::LoadSSLLibraries if (SC.StageTargetPlatform.PlatformType == UnrealTargetPlatform.Win64) { SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Binaries/ThirdParty/OpenSSL")); } } } else { if (PlatformGameConfig != null) { List<string> ExtraNonUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' foreach (var PathStr in ExtraNonUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } } } }
public static void CreateStagingManifest(ProjectParams Params, DeploymentContext SC) { if (!Params.Stage) { return; } var ThisPlatform = SC.StageTargetPlatform; Log("Creating Staging Manifest..."); if (Params.HasDLCName) { string DLCName = Params.DLCName; // Making a plugin, grab the binaries too SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName), "*.uplugin", false, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4-*.so", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4-*.dll", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "libUE4Server-*.so", true, null, null, true); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Binaries"), "UE4Server-*.dll", true, null, null, true); // Put all of the cooked dir into the staged dir string PlatformCookDir = CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform); string[] ExcludeWildCards = {"AssetRegistry.bin"}; // Stage any loose files in the root folder SC.StageFiles(StagedFileType.UFS, PlatformCookDir, "*", false, ExcludeWildCards, SC.RelativeProjectRootForStage, true, !Params.UsePak(SC.StageTargetPlatform)); // Stage each sub directory separately so that we can skip Engine if need be string[] SubDirs = CommandUtils.FindDirectories(true, "*", false, new string[] { PlatformCookDir }); foreach (string SubDir in SubDirs) { // Dedicated server cook doesn't save shaders so no Engine dir is created if ((!SC.DedicatedServer) && (!Params.DLCIncludeEngineContent) && CommandUtils.GetLastDirectoryName(SubDir).Equals("Engine", StringComparison.InvariantCultureIgnoreCase)) { continue; } // SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Plugins", DLCName, "Saved", "Cooked", SC.CookPlatform), "*", true, new[] { CommandUtils.CombinePaths("Engine", "*") }, "", true, !Params.UsePak(SC.StageTargetPlatform)); string MountPoint = SubDir.Substring(PlatformCookDir.Length); if ( MountPoint.StartsWith("\\") || MountPoint.StartsWith("/") ) { MountPoint = MountPoint.Substring(1); } SC.StageFiles(StagedFileType.UFS, SubDir, "*", true, ExcludeWildCards, MountPoint, true, !Params.UsePak(SC.StageTargetPlatform)); //SC.StageFiles(StagedFileType.UFS, SubDir, "*", true, ExcludeWildCards, SC.RelativeProjectRootForStage, true, !Params.UsePak(SC.StageTargetPlatform)); } return; } ThisPlatform.GetFilesToDeployOrStage(Params, SC); // Stage any extra runtime dependencies from the receipts foreach(StageTarget Target in SC.StageTargets) { SC.StageRuntimeDependenciesFromReceipt(Target.Receipt, Target.RequireFilesExist, Params.UsePak(SC.StageTargetPlatform)); } // Get the build.properties file // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file // @todo: Maybe there should be a new category - UFSNotForPak string BuildPropertiesPath = CombinePaths(SC.LocalRoot, "Engine/Build"); if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { BuildPropertiesPath = BuildPropertiesPath.ToLowerInvariant(); } SC.StageFiles(StagedFileType.NonUFS, BuildPropertiesPath, "Build.version", false, null, null, true); // move the UE4Commandline.txt file to the root of the stage // this file needs to be treated as a UFS file for casing, but NonUFS for being put into the .pak file // @todo: Maybe there should be a new category - UFSNotForPak string CommandLineFile = "UE4CommandLine.txt"; if (SC.StageTargetPlatform.DeployLowerCaseFilenames(true)) { CommandLineFile = CommandLineFile.ToLowerInvariant(); } SC.StageFiles(StagedFileType.NonUFS, GetIntermediateCommandlineDir(SC), CommandLineFile, false, null, "", true, false); ConfigCacheIni PlatformGameConfig = ConfigCacheIni.CreateConfigCacheIni(SC.StageTargetPlatform.IniPlatformType, "Game", new DirectoryReference(CommandUtils.GetDirectoryName(Params.RawProjectPath.FullName))); var ProjectContentRoot = CombinePaths(SC.ProjectRoot, "Content"); var StageContentRoot = CombinePaths(SC.RelativeProjectRootForStage, "Content"); if (!Params.CookOnTheFly && !Params.SkipCookOnTheFly) // only stage the UFS files if we are not using cook on the fly { // Initialize internationalization preset. string InternationalizationPreset = null; // Use parameters if provided. if (string.IsNullOrEmpty(InternationalizationPreset)) { InternationalizationPreset = Params.InternationalizationPreset; } // Use configuration if otherwise lacking an internationalization preset. if (string.IsNullOrEmpty(InternationalizationPreset)) { if (PlatformGameConfig != null) { PlatformGameConfig.GetString("/Script/UnrealEd.ProjectPackagingSettings", "InternationalizationPreset", out InternationalizationPreset); } } // Error if no preset has been provided. if (string.IsNullOrEmpty(InternationalizationPreset)) { throw new AutomationException("No internationalization preset was specified for packaging. This will lead to fatal errors when launching. Specify preset via commandline (-I18NPreset=) or project packaging settings (InternationalizationPreset)."); } // Initialize cultures to stage. List<string> CulturesToStage = null; // Use parameters if provided. if (Params.CulturesToCook != null && Params.CulturesToCook.Count > 0) { CulturesToStage = Params.CulturesToCook; } // Use configuration if otherwise lacking cultures to stage. if (CulturesToStage == null || CulturesToStage.Count == 0) { if (PlatformGameConfig != null) { PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "CulturesToStage", out CulturesToStage); } } // Error if no cultures have been provided. if (CulturesToStage == null || CulturesToStage.Count == 0) { throw new AutomationException("No cultures were specified for cooking and packaging. This will lead to fatal errors when launching. Specify culture codes via commandline (-CookCultures=) or using project packaging settings (+CulturesToStage)."); } // Stage ICU internationalization data from Engine. SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), true, !Params.UsePak(SC.StageTargetPlatform)); // Engine ufs (content) SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.LocalRoot, "Engine/Config"), "*", true, null, null, false, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. foreach (string Culture in CulturesToStage) { StageLocalizationDataForCulture(SC, Culture, CombinePaths(SC.LocalRoot, "Engine/Content/Localization/Engine"), null, !Params.UsePak(SC.StageTargetPlatform)); } // Game ufs (content) SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot), "*.uproject", false, null, CombinePaths(SC.RelativeProjectRootForStage), true, !Params.UsePak(SC.StageTargetPlatform)); if (SC.StageTargetPlatform.PlatformType != UnrealTargetPlatform.HTML5 && SC.bUseWebsocketNetDriver) { var EngineIniPath = Path.Combine(SC.ProjectRoot, "Config", "DefaultEngine.ini"); var IntermediateEngineIniDir = Path.Combine(GetIntermediateCommandlineDir(SC), SC.RelativeProjectRootForStage, "Config"); Directory.CreateDirectory(IntermediateEngineIniDir); var IntermediateEngineIniPath = Path.Combine(IntermediateEngineIniDir, "DefaultEngine.ini"); List<String> IniLines = new List<String>(); if (File.Exists(EngineIniPath)) { IniLines = File.ReadAllLines(EngineIniPath).ToList(); } IniLines.Add("[/Script/Engine.GameEngine]"); IniLines.Add("!NetDriverDefinitions=ClearArray"); IniLines.Add("+NetDriverDefinitions=(DefName=\"GameNetDriver\", DriverClassName=\"/Script/HTML5Networking.WebSocketNetDriver\", DriverClassNameFallback=\"/Script/HTML5Networking.WebSocketNetDriver\")"); File.WriteAllLines(IntermediateEngineIniPath, IniLines); SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, new string[] {"DefaultEngine.ini"}, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. SC.StageFiles(StagedFileType.UFS, IntermediateEngineIniDir, "*.ini", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. } else { SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Config"), "*", true, null, CombinePaths(SC.RelativeProjectRootForStage, "Config"), true, !Params.UsePak(SC.StageTargetPlatform)); // TODO: Exclude localization data generation config files. } // Stage all project localization targets { var ProjectLocRootDirectory = CombinePaths(SC.ProjectRoot, "Content/Localization"); if (DirectoryExists(ProjectLocRootDirectory)) { string[] ProjectLocTargetDirectories = CommandUtils.FindDirectories(true, "*", false, new string[] { ProjectLocRootDirectory }); foreach (string ProjectLocTargetDirectory in ProjectLocTargetDirectories) { foreach (string Culture in CulturesToStage) { StageLocalizationDataForCulture(SC, Culture, ProjectLocTargetDirectory, null, !Params.UsePak(SC.StageTargetPlatform)); } } } } // Stage all plugin localization targets { ProjectDescriptor Project = ProjectDescriptor.FromFile(SC.RawProjectPath.FullName); List<PluginInfo> AvailablePlugins = Plugins.ReadAvailablePlugins(new DirectoryReference(CombinePaths(SC.LocalRoot, "Engine")), new FileReference(CombinePaths(SC.ProjectRoot, Params.ShortProjectName + ".uproject")), Project.AdditionalPluginDirectories); foreach (var Plugin in AvailablePlugins) { if (!UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType, TargetRules.TargetType.Game) && UProjectInfo.IsPluginEnabledForProject(Plugin, Project, SC.StageTargetPlatform.PlatformType, TargetRules.TargetType.Client)) { // skip editor plugins continue; } if (Plugin.Descriptor.LocalizationTargets == null || Plugin.Descriptor.LocalizationTargets.Length == 0) { // skip plugins with no localization targets continue; } foreach (var LocalizationTarget in Plugin.Descriptor.LocalizationTargets) { if (LocalizationTarget.LoadingPolicy != LocalizationTargetDescriptorLoadingPolicy.Always && LocalizationTarget.LoadingPolicy != LocalizationTargetDescriptorLoadingPolicy.Game) { // skip targets not loaded by the game continue; } var PluginLocTargetDirectory = CombinePaths(Plugin.Directory.FullName, "Content", "Localization", LocalizationTarget.Name); if (DirectoryExists(PluginLocTargetDirectory)) { foreach (string Culture in CulturesToStage) { StageLocalizationDataForCulture(SC, Culture, PluginLocTargetDirectory, null, !Params.UsePak(SC.StageTargetPlatform)); } } } } } // Stage any additional UFS and NonUFS paths specified in the project ini files; these dirs are relative to the game content directory if (PlatformGameConfig != null) { List<string> ExtraUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsUFS", out ExtraUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' foreach (var PathStr in ExtraUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } List<string> ExtraNonUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' // NonUFS files are never in pak files and should always be remapped foreach (var PathStr in ExtraNonUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, true); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, true); } } } } StagedFileType StagedFileTypeForMovies = StagedFileType.NonUFS; if (Params.FileServer) { // UFS is required when using a file server StagedFileTypeForMovies = StagedFileType.UFS; } if (SC.StageTargetPlatform.StageMovies && !SC.DedicatedServer) { bool bRemap = (StagedFileTypeForMovies == StagedFileType.NonUFS); SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.LocalRoot, "Engine/Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Engine/Content/Movies"), true, bRemap); SC.StageFiles(StagedFileTypeForMovies, CombinePaths(SC.ProjectRoot, "Content/Movies"), "*", true, new string[] { "*.uasset", "*.umap" }, CombinePaths(SC.RelativeProjectRootForStage, "Content/Movies"), true, bRemap); } // eliminate the sand box SC.StageFiles(StagedFileType.UFS, CombinePaths(SC.ProjectRoot, "Saved", "Cooked", SC.CookPlatform), "*", true, new string[] { "*.json" }, "", true, !Params.UsePak(SC.StageTargetPlatform)); // CrashReportClient is a standalone slate app that does not look in the generated pak file, so it needs the Content/Slate and Shaders/StandaloneRenderer folders Non-UFS // @todo Make CrashReportClient more portable so we don't have to do this if (SC.bStageCrashReporter && UnrealBuildTool.UnrealBuildTool.PlatformSupportsCrashReporter(SC.StageTargetPlatform.PlatformType)) { //If the .dat file needs to be staged as NonUFS for non-Windows/Linux hosts we need to change the casing as we do with the build properties file above. SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Content/Slate")); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine/Shaders/StandaloneRenderer")); SC.StageFiles(StagedFileType.NonUFS, CombinePaths(SC.LocalRoot, "Engine", "Content", "Internationalization", InternationalizationPreset), "*", true, null, CombinePaths("Engine", "Content", "Internationalization"), false, true); // Get the architecture in use string Architecture = Params.SpecifiedArchitecture; if (string.IsNullOrEmpty(Architecture)) { Architecture = ""; var BuildPlatform = UEBuildPlatform.GetBuildPlatform(SC.StageTargetPlatform.PlatformType, true); if (BuildPlatform != null) { Architecture = BuildPlatform.CreateContext(Params.RawProjectPath).GetActiveArchitecture(); } } // Get the target receipt path for CrashReportClient DirectoryReference EngineDir = new DirectoryReference(CombinePaths(SC.LocalRoot, "Engine")); string ReceiptFileName = TargetReceipt.GetDefaultPath(EngineDir.FullName, "CrashReportClient", SC.StageTargetPlatform.PlatformType, UnrealTargetConfiguration.Shipping, Architecture); if (!File.Exists(ReceiptFileName)) { throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Missing receipt '{0}'. Check that this target has been built.", Path.GetFileName(ReceiptFileName)); } // Read the receipt for this target TargetReceipt Receipt; if (!TargetReceipt.TryRead(ReceiptFileName, out Receipt)) { throw new AutomationException("Missing or invalid target receipt ({0})", ReceiptFileName); } // Stage any runtime dependencies for CrashReportClient Receipt.ExpandPathVariables(EngineDir, EngineDir); SC.StageRuntimeDependenciesFromReceipt(Receipt, true, Params.UsePak(SC.StageTargetPlatform)); // Add config files. SC.StageFiles( StagedFileType.NonUFS, CombinePaths( SC.LocalRoot, "Engine/Programs/CrashReportClient/Config" ) ); } } else { if (PlatformGameConfig != null) { List<string> ExtraNonUFSDirs; if (PlatformGameConfig.GetArray("/Script/UnrealEd.ProjectPackagingSettings", "DirectoriesToAlwaysStageAsNonUFS", out ExtraNonUFSDirs)) { // Each string has the format '(Path="TheDirToStage")' foreach (var PathStr in ExtraNonUFSDirs) { var PathParts = PathStr.Split('"'); if (PathParts.Length == 3) { var RelativePath = PathParts[1]; SC.StageFiles(StagedFileType.NonUFS, CombinePaths(ProjectContentRoot, RelativePath)); } else if (PathParts.Length == 1) { var RelativePath = PathParts[0]; SC.StageFiles(StagedFileType.UFS, CombinePaths(ProjectContentRoot, RelativePath), "*", true, null, CombinePaths(StageContentRoot, RelativePath), true, !Params.UsePak(SC.StageTargetPlatform)); } } } } } }