public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { Log("Package {0}", Params.RawProjectPath); Log("Setting Emscripten SDK for packaging.."); HTML5SDKInfo.SetupEmscriptenTemp(); HTML5SDKInfo.SetUpEmscriptenConfigFile(); string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } // ini configurations var ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5); bool targetingAsmjs = false; // inverted checked - this will be going away soon... bool targetWebGL1 = false; // inverted checked - this will be going away soon... if (ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetAsmjs", out targetingAsmjs)) { targetingWasm = !targetingAsmjs; } if (ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "TargetWebGL1", out targetWebGL1)) { targetWebGL2 = !targetWebGL1; } // Debug and Development builds are not uncompressed to: // - speed up iteration times // - ensure (IndexedDB) data are not cached/used // Shipping builds "can be": // - compressed // - (IndexedDB) cached if (Params.ClientConfigsToBuild[0].ToString() == "Shipping") { ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "Compressed", out Compressed); ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableIndexedDB", out enableIndexedDB); } Log("HTML5Platform.Automation: TargetWasm = " + targetingWasm); Log("HTML5Platform.Automation: TargetWebGL2 = " + targetWebGL2); Log("HTML5Platform.Automation: Compressed = " + Compressed); Log("HTML5Platform.Automation: EnableIndexedDB = " + enableIndexedDB); string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, FinalDataLocation); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List <string> Paks = new List <string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root string PythonPath = HTML5SDKInfo.Python(); string PackagerPath = HTML5SDKInfo.EmscriptenPackager(); using (new ScopedEnvVar("EM_CONFIG", HTML5SDKInfo.DOT_EMSCRIPTEN)) { using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\" --no-heap-copy", PackagerPath, FinalDataLocation); RunAndLog(CmdEnv, PythonPath, CmdLine); } } } // copy the "Executable" to the package directory string GameBasename = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename); if (Params.ClientConfigsToBuild[0].ToString() != "Development") { GameBasename += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString(); } // no extension string GameBasepath = Path.GetDirectoryName(Params.ProjectGameExeFilename); string FullGameBasePath = Path.Combine(GameBasepath, GameBasename); string FullPackageGameBasePath = Path.Combine(PackagePath, GameBasename); // with extension string GameExe = GameBasename + ".js"; string FullGameExePath = Path.Combine(GameBasepath, GameExe); string FullPackageGameExePath = Path.Combine(PackagePath, GameExe); // special case -- this will be removed when asm.js has been deprecated string ASMJS_FullPackageGameExePath = Path.Combine(PackagePath, GameBasename + "_asm.js"); // ensure the ue4game binary exists, if applicable if (!SC.IsCodeBasedProject && !FileExists_NoExceptions(FullGameExePath)) { Log("Failed to find game application " + FullGameExePath); throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } if (FullGameExePath != FullPackageGameExePath) // TODO: remove this check { File.Copy(FullGameExePath + ".symbols", FullPackageGameExePath + ".symbols", true); if (targetingWasm) { File.Copy(FullGameBasePath + ".wasm", FullPackageGameBasePath + ".wasm", true); File.Copy(FullGameExePath, FullPackageGameExePath, true); } else { File.Copy(FullGameExePath + ".mem", FullPackageGameExePath + ".mem", true); File.Copy(FullGameBasePath + ".asm.js", FullPackageGameBasePath + ".asm.js", true); } } File.SetAttributes(FullPackageGameExePath + ".symbols", FileAttributes.Normal); if (targetingWasm) { File.SetAttributes(FullPackageGameBasePath + ".wasm", FileAttributes.Normal); File.SetAttributes(FullPackageGameExePath, FileAttributes.Normal); } else { File.SetAttributes(FullPackageGameExePath + ".mem", FileAttributes.Normal); File.SetAttributes(FullPackageGameBasePath + ".asm.js", FileAttributes.Normal); File.Copy(FullGameExePath, ASMJS_FullPackageGameExePath, true); // --separate-asm // UE-45058 File.SetAttributes(ASMJS_FullPackageGameExePath, FileAttributes.Normal); } // put the HTML file to the package directory string TemplateFile = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5/GameX.html.template"); string OutputFile = Path.Combine(PackagePath, (Params.ClientConfigsToBuild[0].ToString() != "Development" ? (Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) : Params.ShortProjectName)) + ".html"; GenerateFileFromTemplate(TemplateFile, OutputFile, Params.ShortProjectName, Params.ClientConfigsToBuild[0].ToString(), Params.StageCommandline, !Params.IsCodeBasedProject, HTML5SDKInfo.HeapSize(ConfigCache, Params.ClientConfigsToBuild[0].ToString())); string MacBashTemplateFile = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5/RunMacHTML5LaunchHelper.command.template"); string MacBashOutputFile = Path.Combine(PackagePath, "RunMacHTML5LaunchHelper.command"); string MonoPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/BatchFiles/Mac/SetupMono.sh"); GenerateMacCommandFromTemplate(MacBashTemplateFile, MacBashOutputFile, MonoPath); string htaccessTemplate = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5/htaccess.template"); string htaccesspath = Path.Combine(PackagePath, ".htaccess"); if (File.Exists(htaccesspath)) { FileAttributes attributes = File.GetAttributes(htaccesspath); if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { attributes &= ~FileAttributes.ReadOnly; File.SetAttributes(htaccesspath, attributes); } } File.Copy(htaccessTemplate, htaccesspath, true); string JSDir = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5"); string OutDir = PackagePath; // Gather utlity .js files and combine into one file string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js"); string DestinationFile = OutDir + "/Utility.js"; File.Delete(DestinationFile); foreach (var UtilityFile in UtilityJavaScriptFiles) { string Data = File.ReadAllText(UtilityFile); File.AppendAllText(DestinationFile, Data); } if (Compressed) { Log("Build configuration is " + Params.ClientConfigsToBuild[0].ToString() + ", so (gzip) compressing files for web servers."); // Compress all files. These are independent tasks which can be threaded. List <Task> CompressionTasks = new List <Task>(); // Note that the main .data file is never gzip compressed, because we rely on UnrealPak having compressed it already (above), and gzipping the pak file on // top is showing negligible benefit. Check the console output from UnrealPak run to verify that it is indeed compressed. // CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FinalDataLocation, FinalDataLocation + "gz"))); // data file .js driver. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FinalDataLocation + ".js", FinalDataLocation + ".jsgz"))); if (targetingWasm) { // main game code CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameBasePath + ".wasm", FullPackageGameBasePath + ".wasmgz"))); // main js. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath, FullPackageGameExePath + "gz"))); } else { // mem init file. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath + ".mem", FullPackageGameExePath + ".memgz"))); // main js. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameBasePath + ".asm.js", FullPackageGameBasePath + ".asm.jsgz"))); // main game code CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ASMJS_FullPackageGameExePath, ASMJS_FullPackageGameExePath + "gz"))); } // symbols file. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(FullPackageGameExePath + ".symbols", FullPackageGameExePath + ".symbolsgz"))); // Utility CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(OutDir + "/Utility.js", OutDir + "/Utility.jsgz"))); Task.WaitAll(CompressionTasks.ToArray()); } else { Log("Build configuration is " + Params.ClientConfigsToBuild[0].ToString() + ", so not compressing. Build Shipping configuration to compress files to save space."); // nuke old compressed files to prevent using stale files File.Delete(FinalDataLocation + "gz"); File.Delete(FinalDataLocation + ".jsgz"); File.Delete(FullPackageGameExePath + "gz"); File.Delete(FullPackageGameBasePath + ".wasmgz"); File.Delete(FullPackageGameExePath + ".memgz"); File.Delete(FullPackageGameExePath + ".symbolsgz"); File.Delete(OutDir + "/Utility.jsgz"); } File.Copy(CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"), CombinePaths(OutDir, "HTML5LaunchHelper.exe"), true); // Task.WaitAll(CompressionTasks); PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { Log("Package {0}", Params.RawProjectPath); Log("Setting Emscripten SDK for packaging.."); HTML5SDKInfo.SetupEmscriptenTemp(); HTML5SDKInfo.SetUpEmscriptenConfigFile(); string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine")); if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, FinalDataLocation); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List<string> Paks = new List<string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root string PythonPath = HTML5SDKInfo.Python(); string PackagerPath = HTML5SDKInfo.EmscriptenPackager(); using (new ScopedEnvVar("EM_CONFIG", HTML5SDKInfo.DOT_EMSCRIPTEN)) { using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\"", PackagerPath, FinalDataLocation); RunAndLog(CmdEnv, PythonPath, CmdLine); } } } // copy the "Executable" to the package directory string GameExe = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename); if (Params.ClientConfigsToBuild[0].ToString() != "Development") { GameExe += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString(); } GameExe += ".js"; // ensure the ue4game binary exists, if applicable string FullGameExePath = Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe); if (!SC.IsCodeBasedProject && !FileExists_NoExceptions(FullGameExePath)) { Log("Failed to find game application " + FullGameExePath); throw new AutomationException(ErrorCodes.Error_MissingExecutable, "Stage Failed. Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } if (Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) != Path.Combine(PackagePath, GameExe)) { File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe), Path.Combine(PackagePath, GameExe), true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".mem", Path.Combine(PackagePath, GameExe) + ".mem", true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbols", true); } File.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".symbols", FileAttributes.Normal); // put the HTML file to the package directory string TemplateFileName = "GameX.html.template"; string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", TemplateFileName); string OutputFile = Path.Combine(PackagePath, (Params.ClientConfigsToBuild[0].ToString() != "Development" ? (Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) : Params.ShortProjectName)) + ".html"; // find Heap Size. ulong HeapSize; int ConfigHeapSize = 0; // Valuer set by Editor UI var bGotHeapSize = ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize); // Fallback if the previous method failed if (!bGotHeapSize && !ConfigCache.GetInt32("BuildSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize)) // in Megs. { // we couldn't find a per config heap size, look for a common one. if (!ConfigCache.GetInt32("BuildSettings", "HeapSize", out ConfigHeapSize)) { ConfigHeapSize = Params.IsCodeBasedProject ? 1024 : 512; Log("Could not find Heap Size setting in .ini for Client config {0}", Params.ClientConfigsToBuild[0].ToString()); } } HeapSize = (ulong)ConfigHeapSize * 1024L * 1024L; // convert to bytes. Log("Setting Heap size to {0} Mb ", ConfigHeapSize); GenerateFileFromTemplate(TemplateFile, OutputFile, Params.ShortProjectName, Params.ClientConfigsToBuild[0].ToString(), Params.StageCommandline, !Params.IsCodeBasedProject, HeapSize); string MacBashTemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "RunMacHTML5LaunchHelper.command.template"); string MacBashOutputFile = Path.Combine(PackagePath, "RunMacHTML5LaunchHelper.command"); string MonoPath = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "BatchFiles", "Mac", "SetupMono.sh"); GenerateMacCommandFromTemplate(MacBashTemplateFile, MacBashOutputFile, MonoPath); string JSDir = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5"); string OutDir = PackagePath; // Gather utlity .js files and combine into one file string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js"); string DestinationFile = OutDir + "/Utility.js"; foreach( var UtilityFile in UtilityJavaScriptFiles) { string Data = File.ReadAllText(UtilityFile); File.AppendAllText(DestinationFile, Data); } // Compress all files. These are independent tasks which can be threaded. Task[] CompressionTasks = new Task[6]; //data file. CompressionTasks[0] = Task.Factory.StartNew( () => CompressFile(FinalDataLocation, FinalDataLocation + ".gz")); // data file .js driver. CompressionTasks[1] = Task.Factory.StartNew( () => CompressFile(FinalDataLocation + ".js" , FinalDataLocation + ".js.gz")); // main js. CompressionTasks[2] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe), Path.Combine(PackagePath, GameExe) + ".gz")); // mem init file. CompressionTasks[3] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe) + ".mem", Path.Combine(PackagePath, GameExe) + ".mem.gz")); // symbols file. CompressionTasks[4] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbols.gz")); // Utility CompressionTasks[5] = Task.Factory.StartNew(() => CompressFile(OutDir + "/Utility.js", OutDir + "/Utility.js.gz")); File.Copy(CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"),CombinePaths(OutDir, "HTML5LaunchHelper.exe"),true); Task.WaitAll(CompressionTasks); PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { LogInformation("Package {0}", Params.RawProjectPath); LogInformation("Setting Emscripten SDK for packaging.."); HTML5SDKInfo.SetupEmscriptenTemp(); HTML5SDKInfo.SetUpEmscriptenConfigFile(); // ---------------------------------------- // ini configurations ConfigHierarchy ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5); // Debug and Development builds are not compressed to: // - speed up iteration times // - ensure (IndexedDB) data are not cached/used // Shipping builds "can be": // - compressed // - (IndexedDB) cached string ProjectConfiguration = Params.ClientConfigsToBuild[0].ToString(); if (ProjectConfiguration == "Shipping") { ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "Compressed", out Compressed); ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "EnableIndexedDB", out enableIndexedDB); } LogInformation("HTML5Platform.Automation: Compressed = " + Compressed); LogInformation("HTML5Platform.Automation: EnableIndexedDB = " + enableIndexedDB); // ---------------------------------------- // package directory string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } string _ProjectNameExtra = ProjectConfiguration != "Development" ? "-HTML5-" + ProjectConfiguration : ""; string _ProjectFullpath = Params.GetProjectExeForPlatform(UnrealTargetPlatform.HTML5).ToString(); string _ProjectFilename = Path.GetFileNameWithoutExtension(_ProjectFullpath) + _ProjectNameExtra; string SrcUE4GameBasename = Path.Combine(Path.GetDirectoryName(_ProjectFullpath), _ProjectFilename); string UE4GameBasename = Path.Combine(PackagePath, _ProjectFilename); string ProjectBasename = Path.Combine(PackagePath, Params.ShortProjectName + _ProjectNameExtra); // ---------------------------------------- // packaging if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, ProjectBasename + ".data"); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List <string> Paks = new List <string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root string PythonPath = HTML5SDKInfo.Python(); string EmPackagerPath = HTML5SDKInfo.EmscriptenPackager(); using (new ScopedEnvVar("EM_CONFIG", HTML5SDKInfo.DOT_EMSCRIPTEN)) { using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\" --no-heap-copy", EmPackagerPath, ProjectBasename + ".data"); RunAndLog(CmdEnv, PythonPath, CmdLine); } } } // ---------------------------------------- // copy to package directory // ensure the ue4game binary exists, if applicable if (!FileExists_NoExceptions(SrcUE4GameBasename + ".js")) { LogInformation("Failed to find game application " + SrcUE4GameBasename + ".js"); throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", SrcUE4GameBasename + ".js"); } if (!Params.IsCodeBasedProject) { // template project - need to copy over UE4Game.* File.Copy(SrcUE4GameBasename + ".wasm", UE4GameBasename + ".wasm", true); File.Copy(SrcUE4GameBasename + ".js", UE4GameBasename + ".js", true); File.Copy(SrcUE4GameBasename + ".js.symbols", UE4GameBasename + ".js.symbols", true); File.SetAttributes(UE4GameBasename + ".wasm", FileAttributes.Normal); File.SetAttributes(UE4GameBasename + ".js", FileAttributes.Normal); File.SetAttributes(UE4GameBasename + ".js.symbols", FileAttributes.Normal); } // else, c++ projects will compile "to" PackagePath // note: ( ProjectBasename + ".data" ) already created above (!HTMLPakAutomation.CanCreateMapPaks()) // ---------------------------------------- // generate HTML files to the package directory // custom HTML, JS (if any), and CSS (if any) template files string LocalBuildPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5"); string BuildPath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Build", "HTML5"); string TemplateFile = CombinePaths(BuildPath, "project_template.html"); if (!File.Exists(TemplateFile)) { // fall back to default UE4 template files BuildPath = LocalBuildPath; TemplateFile = CombinePaths(BuildPath, "project_template.html"); } GenerateFileFromTemplate(TemplateFile, ProjectBasename + ".html", Params, ConfigCache); TemplateFile = CombinePaths(BuildPath, "project_template.js"); if (File.Exists(TemplateFile)) { GenerateFileFromTemplate(TemplateFile, ProjectBasename + ".UE4.js", Params, ConfigCache); } TemplateFile = CombinePaths(BuildPath, "project_template.css"); if (File.Exists(TemplateFile)) { GenerateFileFromTemplate(TemplateFile, ProjectBasename + ".css", Params, ConfigCache); } // ---------------------------------------- // (development) support files string MacBashTemplateFile = CombinePaths(LocalBuildPath, "RunMacHTML5LaunchHelper_template.command"); string MacBashOutputFile = Path.Combine(PackagePath, "RunMacHTML5LaunchHelper.command"); string MonoPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Build/BatchFiles/Mac/SetupMono.sh"); GenerateMacCommandFromTemplate(MacBashTemplateFile, MacBashOutputFile, MonoPath); // ........................................ string htaccesspath = Path.Combine(PackagePath, ".htaccess"); if (File.Exists(htaccesspath)) { FileAttributes attributes = File.GetAttributes(htaccesspath); if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { attributes &= ~FileAttributes.ReadOnly; File.SetAttributes(htaccesspath, attributes); } } File.Copy(CombinePaths(LocalBuildPath, "htaccess_template.txt"), htaccesspath, true); // ---------------------------------------- // final copies // Gather utlity .js files and combine into one file string DestinationFile = PackagePath + "/Utility.js"; File.Delete(DestinationFile); // spelling this out - one file at a time (i.e. don't slurp in project_template.js) File.AppendAllText(DestinationFile, File.ReadAllText(CombinePaths(LocalBuildPath, "json2.js"))); File.AppendAllText(DestinationFile, File.ReadAllText(CombinePaths(LocalBuildPath, "jstorage.js"))); File.AppendAllText(DestinationFile, File.ReadAllText(CombinePaths(LocalBuildPath, "moz_binarystring.js"))); if (Compressed) { LogInformation("Build configuration is " + ProjectConfiguration + ", so (gzip) compressing files for web servers."); // Compress all files. These are independent tasks which can be threaded. List <Task> CompressionTasks = new List <Task>(); CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(UE4GameBasename + ".wasm", UE4GameBasename + ".wasmgz"))); // main game code CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(UE4GameBasename + ".js", UE4GameBasename + ".jsgz"))); // main js (emscripten) CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(UE4GameBasename + ".js.symbols", UE4GameBasename + ".js.symbolsgz"))); // symbols fil. CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(PackagePath + "/Utility.js", PackagePath + "/Utility.jsgz"))); // Utility CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ProjectBasename + ".data", ProjectBasename + ".datagz"))); // DATA file CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ProjectBasename + ".data.js", ProjectBasename + ".data.jsgz"))); // DATA file .js driver (emscripten) if (File.Exists(ProjectBasename + ".UE4.js")) { CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ProjectBasename + ".UE4.js", ProjectBasename + ".UE4.jsgz"))); // UE4 js } if (File.Exists(ProjectBasename + ".css")) { CompressionTasks.Add(Task.Factory.StartNew(() => CompressFile(ProjectBasename + ".css", ProjectBasename + ".cssgz"))); // UE4 css } Task.WaitAll(CompressionTasks.ToArray()); } else { LogInformation("Build configuration is " + ProjectConfiguration + ", so not compressing. Build Shipping configuration to compress files to save space."); // nuke old compressed files to prevent using stale files File.Delete(UE4GameBasename + ".wasmgz"); File.Delete(UE4GameBasename + ".jsgz"); File.Delete(UE4GameBasename + ".js.symbolsgz"); File.Delete(PackagePath + "/Utility.jsgz"); File.Delete(ProjectBasename + ".datagz"); File.Delete(ProjectBasename + ".data.jsgz"); File.Delete(ProjectBasename + ".UE4.jsgz"); File.Delete(ProjectBasename + ".cssgz"); } File.Copy(CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"), CombinePaths(PackagePath, "HTML5LaunchHelper.exe"), true); // Task.WaitAll(CompressionTasks); PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { Log("Package {0}", Params.RawProjectPath); Log("Setting Emscripten SDK for packaging.."); HTML5SDKInfo.SetupEmscriptenTemp(); HTML5SDKInfo.SetUpEmscriptenConfigFile(); string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath.FullName), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine")); if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, FinalDataLocation); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List <string> Paks = new List <string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root string PythonPath = HTML5SDKInfo.Python(); string PackagerPath = HTML5SDKInfo.EmscriptenPackager(); using (new ScopedEnvVar("EM_CONFIG", HTML5SDKInfo.DOT_EMSCRIPTEN)) { using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\"", PackagerPath, FinalDataLocation); RunAndLog(CmdEnv, PythonPath, CmdLine); } } } // copy the "Executable" to the package directory string GameExe = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename); if (Params.ClientConfigsToBuild[0].ToString() != "Development") { GameExe += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString(); } GameExe += ".js"; // ensure the ue4game binary exists, if applicable string FullGameExePath = Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe); if (!SC.IsCodeBasedProject && !FileExists_NoExceptions(FullGameExePath)) { Log("Failed to find game application " + FullGameExePath); throw new AutomationException(ExitCode.Error_MissingExecutable, "Stage Failed. Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } if (Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) != Path.Combine(PackagePath, GameExe)) { File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe), Path.Combine(PackagePath, GameExe), true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".mem", Path.Combine(PackagePath, GameExe) + ".mem", true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbols", true); } File.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".symbols", FileAttributes.Normal); // put the HTML file to the package directory string TemplateFileName = "GameX.html.template"; string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", TemplateFileName); string OutputFile = Path.Combine(PackagePath, (Params.ClientConfigsToBuild[0].ToString() != "Development" ? (Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) : Params.ShortProjectName)) + ".html"; // find Heap Size. ulong HeapSize; int ConfigHeapSize = 0; // Valuer set by Editor UI var bGotHeapSize = ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize); // Fallback if the previous method failed if (!bGotHeapSize && !ConfigCache.GetInt32("/Script/BuildSettings.BuildSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize)) // in Megs. { // we couldn't find a per config heap size, look for a common one. if (!ConfigCache.GetInt32("/Script/BuildSettings.BuildSettings", "HeapSize", out ConfigHeapSize)) { ConfigHeapSize = Params.IsCodeBasedProject ? 1024 : 512; Log("Could not find Heap Size setting in .ini for Client config {0}", Params.ClientConfigsToBuild[0].ToString()); } } HeapSize = (ulong)ConfigHeapSize * 1024L * 1024L; // convert to bytes. Log("Setting Heap size to {0} Mb ", ConfigHeapSize); GenerateFileFromTemplate(TemplateFile, OutputFile, Params.ShortProjectName, Params.ClientConfigsToBuild[0].ToString(), Params.StageCommandline, !Params.IsCodeBasedProject, HeapSize); string MacBashTemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "RunMacHTML5LaunchHelper.command.template"); string MacBashOutputFile = Path.Combine(PackagePath, "RunMacHTML5LaunchHelper.command"); string MonoPath = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "BatchFiles", "Mac", "SetupMono.sh"); GenerateMacCommandFromTemplate(MacBashTemplateFile, MacBashOutputFile, MonoPath); string htaccessTemplate = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "htaccess.template"); string htaccesspath = Path.Combine(PackagePath, ".htaccess"); if (File.Exists(htaccesspath)) { FileAttributes attributes = File.GetAttributes(htaccesspath); if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) { attributes &= ~FileAttributes.ReadOnly; File.SetAttributes(htaccesspath, attributes); } } File.Copy(htaccessTemplate, htaccesspath, true); string JSDir = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5"); string OutDir = PackagePath; // Gather utlity .js files and combine into one file string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js"); string DestinationFile = OutDir + "/Utility.js"; File.Delete(DestinationFile); foreach (var UtilityFile in UtilityJavaScriptFiles) { string Data = File.ReadAllText(UtilityFile); File.AppendAllText(DestinationFile, Data); } // Compress all files. These are independent tasks which can be threaded. Task[] CompressionTasks = new Task[6]; //data file. CompressionTasks[0] = Task.Factory.StartNew(() => CompressFile(FinalDataLocation, FinalDataLocation + "gz")); // data file .js driver. CompressionTasks[1] = Task.Factory.StartNew(() => CompressFile(FinalDataLocation + ".js", FinalDataLocation + ".jsgz")); // main js. CompressionTasks[2] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe), Path.Combine(PackagePath, GameExe) + "gz")); // mem init file. CompressionTasks[3] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe) + ".mem", Path.Combine(PackagePath, GameExe) + ".memgz")); // symbols file. CompressionTasks[4] = Task.Factory.StartNew(() => CompressFile(Path.Combine(PackagePath, GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbolsgz")); // Utility CompressionTasks[5] = Task.Factory.StartNew(() => CompressFile(OutDir + "/Utility.js", OutDir + "/Utility.jsgz")); File.Copy(CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe"), CombinePaths(OutDir, "HTML5LaunchHelper.exe"), true); Task.WaitAll(CompressionTasks); PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { Log("Package {0}", Params.RawProjectPath); string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine")); if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, FinalDataLocation); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List<string> Paks = new List<string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string PythonPath = HTML5SDKInfo.PythonPath(); string PackagerPath = HTML5SDKInfo.EmscriptenPackager(); string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\"", PackagerPath, FinalDataLocation); RunAndLog(CmdEnv, PythonPath, CmdLine); } } // packaging created 2 files - .data.js and .data file. lets compress them. CompressFile(FinalDataLocation, FinalDataLocation); CompressFile(FinalDataLocation + ".js", FinalDataLocation + ".js.gz"); File.Delete(FinalDataLocation + ".js"); // copy the "Executable" to the package directory string GameExe = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename); if (Params.ClientConfigsToBuild[0].ToString() != "Development") { GameExe += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString(); } GameExe += ".js"; // ensure the ue4game binary exists, if applicable string FullGameExePath = Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe); if (!SC.IsCodeBasedProject && !FileExists_NoExceptions(FullGameExePath)) { Log("Failed to find game application " + FullGameExePath); AutomationTool.ErrorReporter.Error("Stage Failed.", (int)AutomationTool.ErrorCodes.Error_MissingExecutable); throw new AutomationException("Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } if (Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) != Path.Combine(PackagePath, GameExe)) { // compress all javascript files in place. Log("Compressing and Copying main js executable"); CompressFile(FullGameExePath, Path.Combine(PackagePath, GameExe) + ".gz"); Log("Compressing and copying memory Initialization file"); CompressFile(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".mem", (Path.Combine(PackagePath, GameExe) + ".mem")); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbols", true); } File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".symbols", FileAttributes.Normal); // put the HTML file to the package directory bool UseExperimentalTemplate = false; ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "UseExperimentalTemplate", out UseExperimentalTemplate); string TemplateFileName = UseExperimentalTemplate ? "GameX.html.template" : "Game.html.template"; string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", TemplateFileName); string OutputFile = Path.Combine(PackagePath, (Params.ClientConfigsToBuild[0].ToString() != "Development" ? (Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) : Params.ShortProjectName)) + ".html"; // find Heap Size. ulong HeapSize; int ConfigHeapSize = 0; // Valuer set by Editor UI var bGotHeapSize = ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize); // Fallback if the previous method failed if (!bGotHeapSize && !ConfigCache.GetInt32("BuildSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize)) // in Megs. { // we couldn't find a per config heap size, look for a common one. if (!ConfigCache.GetInt32("BuildSettings", "HeapSize", out ConfigHeapSize)) { ConfigHeapSize = Params.IsCodeBasedProject ? 1024 : 512; Log("Could not find Heap Size setting in .ini for Client config {0}", Params.ClientConfigsToBuild[0].ToString()); } } HeapSize = (ulong)ConfigHeapSize * 1024L * 1024L; // convert to bytes. Log("Setting Heap size to {0} Mb ", ConfigHeapSize); GenerateFileFromTemplate(TemplateFile, OutputFile, Params.ShortProjectName, Params.ClientConfigsToBuild[0].ToString(), Params.StageCommandline, !Params.IsCodeBasedProject, HeapSize); string JSDir = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5"); string OutDir = PackagePath; // Gather utlity .js files and combine into one file string[] UtilityJavaScriptFiles = Directory.GetFiles(JSDir, "*.js"); string DestinationFile = OutDir + "/Utility.js"; foreach( var UtilityFile in UtilityJavaScriptFiles) { string Data = File.ReadAllText(UtilityFile); File.AppendAllText(DestinationFile, Data); } CompressFile(DestinationFile, DestinationFile + ".gz"); // delete uncompressed file. if (File.Exists(DestinationFile)) { File.Delete(DestinationFile); } PrintRunTime(); }
public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL) { Log("Package {0}", Params.RawProjectPath); string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath), "Binaries", "HTML5"); if (!Directory.Exists(PackagePath)) { Directory.CreateDirectory(PackagePath); } string FinalDataLocation = Path.Combine(PackagePath, Params.ShortProjectName) + ".data"; var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine")); if (HTMLPakAutomation.CanCreateMapPaks(Params)) { HTMLPakAutomation PakAutomation = new HTMLPakAutomation(Params, SC); // Create Necessary Paks. PakAutomation.CreateEnginePak(); PakAutomation.CreateGamePak(); PakAutomation.CreateContentDirectoryPak(); // Create Emscripten Package from Necessary Paks. - This will be the VFS. PakAutomation.CreateEmscriptenDataPackage(PackagePath, FinalDataLocation); // Create All Map Paks which will be downloaded on the fly. PakAutomation.CreateMapPak(); // Create Delta Paks if setup. List <string> Paks = new List <string>(); ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5TargetSettings", "LevelTransitions", out Paks); if (Paks != null) { foreach (var Pak in Paks) { var Matched = Regex.Matches(Pak, "\"[^\"]+\"", RegexOptions.IgnoreCase); string MapFrom = Path.GetFileNameWithoutExtension(Matched[0].ToString().Replace("\"", "")); string MapTo = Path.GetFileNameWithoutExtension(Matched[1].ToString().Replace("\"", "")); PakAutomation.CreateDeltaMapPaks(MapFrom, MapTo); } } } else { // we need to operate in the root using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5"))) { string PythonPath = HTML5SDKInfo.PythonPath(); string PackagerPath = HTML5SDKInfo.EmscriptenPackager(); string CmdLine = string.Format("\"{0}\" \"{1}\" --preload . --js-output=\"{1}.js\"", PackagerPath, FinalDataLocation); RunAndLog(CmdEnv, PythonPath, CmdLine); } } // copy the "Executable" to the package directory string GameExe = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename); if (Params.ClientConfigsToBuild[0].ToString() != "Development") { GameExe += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString(); } GameExe += ".js"; // ensure the ue4game binary exists, if applicable string FullGameExePath = Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe); if (!SC.IsCodeBasedProject && !FileExists_NoExceptions(FullGameExePath)) { Log("Failed to find game application " + FullGameExePath); AutomationTool.ErrorReporter.Error("Stage Failed.", (int)AutomationTool.ErrorCodes.Error_MissingExecutable); throw new AutomationException("Could not find application {0}. You may need to build the UE4 project with your target configuration and platform.", FullGameExePath); } if (Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) != Path.Combine(PackagePath, GameExe)) { File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe), Path.Combine(PackagePath, GameExe), true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".mem", Path.Combine(PackagePath, GameExe) + ".mem", true); File.Copy(Path.Combine(Path.GetDirectoryName(Params.ProjectGameExeFilename), GameExe) + ".symbols", Path.Combine(PackagePath, GameExe) + ".symbols", true); } File.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal); File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".symbols", FileAttributes.Normal); // put the HTML file to the package directory bool UseExperimentalTemplate = false; ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "UseExperimentalTemplate", out UseExperimentalTemplate); string TemplateFileName = UseExperimentalTemplate ? "GameX.html.template" : "Game.html.template"; string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", TemplateFileName); string OutputFile = Path.Combine(PackagePath, (Params.ClientConfigsToBuild[0].ToString() != "Development" ? (Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) : Params.ShortProjectName)) + ".html"; // find Heap Size. ulong HeapSize; int ConfigHeapSize = 0; // Valuer set by Editor UI var bGotHeapSize = ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize); // Fallback if the previous method failed if (!bGotHeapSize && !ConfigCache.GetInt32("BuildSettings", "HeapSize" + Params.ClientConfigsToBuild[0].ToString(), out ConfigHeapSize)) // in Megs. { // we couldn't find a per config heap size, look for a common one. if (!ConfigCache.GetInt32("BuildSettings", "HeapSize", out ConfigHeapSize)) { ConfigHeapSize = Params.IsCodeBasedProject ? 1024 : 512; Log("Could not find Heap Size setting in .ini for Client config {0}", Params.ClientConfigsToBuild[0].ToString()); } } HeapSize = (ulong)ConfigHeapSize * 1024L * 1024L; // convert to bytes. Log("Setting Heap size to {0} Mb ", ConfigHeapSize); GenerateFileFromTemplate(TemplateFile, OutputFile, Params.ShortProjectName, Params.ClientConfigsToBuild[0].ToString(), Params.StageCommandline, !Params.IsCodeBasedProject, HeapSize); // copy the jstorage files to the binaries directory string JSDir = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5"); string OutDir = PackagePath; File.Copy(JSDir + "/json2.js", OutDir + "/json2.js", true); File.SetAttributes(OutDir + "/json2.js", FileAttributes.Normal); File.Copy(JSDir + "/jStorage.js", OutDir + "/jStorage.js", true); File.SetAttributes(OutDir + "/jStorage.js", FileAttributes.Normal); File.Copy(JSDir + "/moz_binarystring.js", OutDir + "/moz_binarystring.js", true); File.SetAttributes(OutDir + "/moz_binarystring.js", FileAttributes.Normal); PrintRunTime(); }