You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ========================== MAJOR FEATURES + CHANGES ========================== Change 3421703 on 2017/05/03 by Ben.Marsh Surround invalid character message in quotes, so it's clear when a space is listed. #jira UE-44606 Change 3422644 on 2017/05/04 by Steve.Robb Ranged-for support for TChunkedArray. Change 3422754 on 2017/05/04 by Steve.Robb IAsyncReadFileHandle made non-copyable to prevent accidental wrong stat calculation. Change 3422758 on 2017/05/04 by Steve.Robb Misc readability/standards improvements in stats code. Change 3427955 on 2017/05/08 by Steve.Robb Version fix for IOS optimization pragmas, copied from equivalent Mac code. Change 3428017 on 2017/05/08 by Steve.Robb Unused property types removed. Change 3428641 on 2017/05/08 by Ben.Marsh UAT: Remove failed attempt to separate out BuildCookRun into separate commands, which have since rotted. Change 3430407 on 2017/05/09 by Ben.Marsh UBT: Define UE_4_X_OR_LATER macros for every UE4 version greater than 4.17 (eg. UE_4_17_OR_LATER, etc...). Change 3430682 on 2017/05/09 by Gil.Gribb UE4 - Added a fatal error for asking for very large alignments from MallocBinned2 and also return the true size of the memory block in GetAllocationSize(). Change 3430685 on 2017/05/09 by Gil.Gribb UE4 - Fixed a bug with the windows async IO stuff related to an unsafe pointer cast to LPDWORD from int64*. Change 3430756 on 2017/05/09 by Ben.Marsh UBT: Switch some receipt stuff to use FileReference/DirectoryReference objects rather than raw paths. Change 3431157 on 2017/05/09 by Ben.Marsh UBT: Store absolute paths when receipts are in memory; only insert pseudo-variables for $(EngineDir) and $(ProjectDir) when saved to disk. Change 3432334 on 2017/05/10 by Graeme.Thornton Include project name in the UBT error message which appears when a plugin is missing Change 3432481 on 2017/05/10 by Gil.Gribb UE4 - Fixed code to detect cycles in parallel tick sorting. Change 3432485 on 2017/05/10 by Steve.Robb Simplified templating around bitfield offset calculation. Change 3432608 on 2017/05/10 by Steve.Robb 'bool == byte' static_assert restored after being removed in CL# 3432485. Change 3432767 on 2017/05/10 by Ben.Marsh UBT: Fix exception when a missing plugin is encountered if the target does not have a project. Change 3433031 on 2017/05/10 by Ben.Marsh UAT: Add classes to allow safer manipulation of paths within the staging directory (StagedFileReference, StagedDirectoryReference), and convert staging code over to using those and their regular filesystem counterparts (FileReference/DirectoryReference). Lots of cleanup and refactoring of staging code. Change 3433049 on 2017/05/10 by Ben.Marsh Add more diagnostic information to asserts in TStaticIndirectArrayThreadSafeRead, to try and shed light on what sort of corrupted data is being passed in from the cooker. #jira UE-44336 Change 3433097 on 2017/05/10 by Steve.Robb Value initialization fix for MakeUnique<T[]>(). Change 3433972 on 2017/05/10 by Daniel.Lamb Stop unrealpak from crashing if generating a patch with more pak files then the original game. Change 3434124 on 2017/05/10 by Ben.Marsh UAT: Remove hacky bUseWebSocketNetDriver option. Change 3434824 on 2017/05/11 by Gil.Gribb UE4 - Printed an error instead of asserting when there are missing native classes. Change 3434916 on 2017/05/11 by Ben.Marsh UAT: Separate the list of files to be staged into a separate class. Change3435427on 2017/05/11 by Gil.Gribb UE4 - Fixed attempts to load compiled in packages, which produces warnings and is slow. Change 3436240 on 2017/05/11 by Ben.Marsh UAT: Add a command to search for restricted folders under a given base directory. Change 3438068 on 2017/05/12 by James.Fox Checking in Phase 1 of the Dev-Core test map for repro purposes. UE-44996 #rb none Change 3438855 on 2017/05/15 by Robert.Manuszewski When verbose cluster logging is enabled and new object is added to an already existing cluster, the cluster will be dumped to log. Change 3438929 on 2017/05/15 by Robert.Manuszewski Merging CL # 3436939 using Dev-Core_To_Dev-LoadTimes: Fix for potential crashes caused by levels staying in memory through material references. Change 3439021 on 2017/05/15 by Ben.Marsh PR #3566: fix non-ascii characters in help command HTML converted to "?" (Contributed by kayama-shift) Change 3439079 on 2017/05/15 by Ben.Marsh PR #2832: Implement missing MessageBox (Contributed by projectgheist) Change 3439258 on 2017/05/15 by Ben.Marsh Highlight lines containing the strings "Error:" or "Warning:" in the output log, so that diagnostics from child processes are highlighted appropriately. The build system already relies similar logic for scraping diagnostics from logs, so it should be safe and predictable to check for messages in this way. #jira UE-43673 Change 3439358 on 2017/05/15 by Ben.Marsh UBT: Fix Visual Studio solution referencing the incorrect platform for existing C# project ("Any CPU" instead of "AnyCPU"). Was causing prompt to save the solution the first time it is opened. Change 3439665 on 2017/05/15 by Ben.Marsh UAT: Remove DeployPakInternalLowerCaseFilenames(). No platforms require this to be true. Change 3440735 on 2017/05/16 by Robert.Manuszewski UBT compile fix after the last merge Change 3440889 on 2017/05/16 by Ben.Marsh EC: Fix regex for matching path to source files included in error messages from the Linux toolchain. Change 3442776 on 2017/05/17 by Steve.Robb Platform fix for FPaths::IsSamePath. Change 3445411 on 2017/05/17 by Ben.Marsh UBT: Fix typo in makefile diagnostic string. Change 3446070 on 2017/05/18 by Steve.Robb Fix to array sizes in generated UFunction code, which should now handle editor-only functions. Change 3446091 on 2017/05/18 by Steve.Robb Another array size fix for generated code. Change 3446605 on 2017/05/18 by Steve.Robb BuildConfiguration option for static analysis. Change 3448601 on 2017/05/19 by Richard.Fawcett Change FWindowsPlatformProcess::ApplicationSettingsDir() so that it no longer returns a path with a mixture of "\" and "/" characters, and only contains "/" characters. This makes it consistent with other related functions like FWindowsPlatformProcess::UserSettingsDir(). Change 3449026 on 2017/05/19 by Ben.Marsh Fix whitespace in template file. Change 3449697 on 2017/05/19 by James.Fox Checking in Phase 2 of Dev-Core test map for QAGame Also enabled Blueprint and Actor clustering by default in QAGame for more thorough GC testing. Change 3451352 on 2017/05/22 by Steve.Robb UFunction flags are now viewable in the debugger. Change 3451355 on 2017/05/22 by Steve.Robb ARRAY_COUNT fix for zero-sized arrays in Clang. Change 3451379 on 2017/05/22 by Steve.Robb C++14 operator delete overloads with size, for consistency. Change 3451398 on 2017/05/22 by Graeme.Thornton Add AES and RSA encryption keys to the list of config fields that get stripped from ini files when staging When creating a pak file, do a filtered copy of all ini files to a temp directory so that all confidential fields can be stripped. Equivalent behaviour to staging a loose file distribution Change 3451476 on 2017/05/22 by Ben.Marsh Compile shipping builds for WEX and Ocean, and post telemetry for the resulting executable size. Change 3451478 on 2017/05/22 by Graeme.Thornton PR #3197: Improved log message formatting (Contributed by projectgheist) Change 3451868 on 2017/05/22 by Steve.Robb Static log category moved out of header. ENUM_CLASS_FLAGS macro used instead of explicit operators. Change 3452319 on 2017/05/22 by Ben.Marsh UBT: Add a new "package" build product type, which can be used for APK files on Android and Stub files on iOS. Treating these files as executables is causing the measured executable size to be incorrect. Change 3452607 on 2017/05/22 by Ben.Marsh UBT: Filter out folders for other platforms when searching for headers to pass to UHT. Change 3453600 on 2017/05/23 by Graeme.Thornton PR #3226 - Updated some code comments to better describe the usage of the log category definition macros Change 3453616 on 2017/05/23 by Steve.Robb Error reported instead of a crash when there's a space between UCLASS or UINTERFACE and the open parenthesis. Change 3453714 on 2017/05/23 by Ben.Marsh Build: Add some Visual Studio 2017 test compiles to the build system. Change 3453795 on 2017/05/23 by Ben.Marsh UBT: Fix parsing of command line attributes that have a specific value assigned. We should never have an '=' suffix for such arguments. Change 3454606 on 2017/05/23 by Ben.Marsh UAT: Make sure log filenames are unique by creating a 0-byte file in its place. Change 3454709 on 2017/05/23 by Ben.Marsh UBT: Enable the /permissive- option for stricter standards compliance on Visual Studio 2017. Currently have /Zc:strictStrings disabled due to violations in Windows headers; all UE4 instances have been fixed up. Change 3456445 on 2017/05/24 by Graeme.Thornton MemoryProfiler2 - Add mprof filename into title bar after opening Change 3457129 on 2017/05/24 by Ben.Marsh Fix comment for FVector::Normalize(). #jira UE-45369 #rnx Change 3457228 on 2017/05/24 by Ben.Marsh Do not allow forward-declaring Rect structs. They are not public, and it conflicts with third party libraries. #rnx Change 3458357 on 2017/05/24 by Ben.Marsh Fix name resolution issue with /permissive- in VS2017. Change 3458812 on 2017/05/25 by Robert.Manuszewski PR #2407: Fix LoadLibrary error with Microsoft Group Policy CWDIllegalinDllSearch mode 1 or 2 (Contributed by bozaro) Change 3458894 on 2017/05/25 by Robert.Manuszewski PR #2096: Fix argument parsing in DiffAssets Comandlet (Contributed by cgrebeld) Change 3461205 on 2017/05/26 by Robert.Manuszewski Fixed parameter parsing so that arguments are not parsed if not preceeded by a whitespace (for example "-Log" was parsed in "TM-Log") #jira UE-33790 Change 3464714 on 2017/05/30 by Robert.Manuszewski Fixing potential deadlock caused by a race condition when using FMallocVerifyProxy with FMallocBinned Change 3465310 on 2017/05/30 by Ben.Marsh UBT: Enable bAdaptiveUnityDisablesOptimizations by default. Change 3465346 on 2017/05/30 by Ben.Marsh UBT: Require Update 3 to be installed when compiling using VS2015. Change 3465389 on 2017/05/30 by Ben.Marsh UBT: Fix support for RTTI when creating PCHs and shared PCHs. Change 3466084 on 2017/05/30 by Ben.Marsh Fix compiling plain C files, where it would incorrectly use a C++ PCH. Change 3467018 on 2017/05/31 by Robert.Manuszewski Async loading code will now properly handle cases when the requested package could not be created. Change 3467113 on 2017/05/31 by Ben.Marsh UGS: When opening a solution in Visual Studio, always start the process in the solution's directory. Change 3467508 on 2017/05/31 by Ben.Marsh Add a function to fix a long package name so it matches the case of a file on disk. Fixes deterministic cooking issues when on-disk case changes. Change 3467510 on 2017/05/31 by Ben.Marsh Fix deterministic cooking issue caused by LODGroup only being initialized in the CDO if it's serialized, causing inconsistent delta serialization for instances. Change 3467967 on 2017/05/31 by Ben.Marsh Always allow UAT to compile on non-Windows platforms, even if a debugger is present, since MSVC is the only one that will load C# PDBs. Change 3468544 on 2017/05/31 by Ben.Marsh UBT: Add a more helpful message when a module is being compiled with implicit PCHs, but a source file is not configured correctly. Change 3469241 on 2017/06/01 by Ben.Marsh UBT: Fix single-file compile causing a different UHT manifest to be generated, potentially excluding hidden dependencies. Change 3471709 on 2017/06/02 by Daniel.Lamb Rebuild lighting commandlet now rebuilds reflections also instead of trashing them. #test None Change 3471719 on 2017/06/02 by Daniel.Lamb Fixed crash in cooker while trying to cook for multiple platforms #test Launch on shootergame windows + ps4 #jira UE-45356 Change 3472261 on 2017/06/02 by Ben.Marsh CRP: Clear out MDD logs whenever we clear out CRP logs. Change 3473169 on 2017/06/05 by Graeme.Thornton PR #3622: Log category code cleanup (Contributed by projectgheist) Change 3473176 on 2017/06/05 by Graeme.Thornton PR #3622: Log category code cleanup (Contributed by projectgheist) (Part II) - Missed some files from my previous checkin Change 3473597 on 2017/06/05 by Ben.Marsh UnrealVS: Fix massive slowdown on startup caused by searching the directory tree under the solution for *.uproject files (including intermediate folders, etc...). Now reads *.uprojectdirs files and only checks the listed directories within. Measured it taking > 30s to run before, now takes < 0.1s. Change 3473722 on 2017/06/05 by Steve.Robb GitHub #3444: UE-42521: Added missing macro's for TMap and TSet PREPROCESSOR_COMMA_SEPARATED added as a better solution for the hacky comma separator solution in the PR. Change 3475073 on 2017/06/06 by Steve.Robb Fix for TPromise's move assignment operator return value. Change 3475331 on 2017/06/06 by Ben.Marsh UAT: Fix invalid paths being generated when stripping encryption settings from config files. * In cases where INI files were in a subfolder of the Config folder (eg. Config\Localization), it was not stripping the separating slash, resulting in files being written to the root directory of the current drive. * Paths under the config folder are not guaranteed to be unique. Change 3475453 on 2017/06/06 by Ben.Marsh UBT: Add an error if a plugin lists a non-plugin module as belonging to it. #jira UE-45178 Change 3475668 on 2017/06/06 by Ben.Marsh Add a message showing when we begin creating the asset registry, since it can take a long time. #jira UE-41675 Change 3475747 on 2017/06/06 by Steve.Robb Replicated from CL# 3332960: Force a gather on hot reload, so we don't use stale state from the makefile. #jira UE-42205 Change 3475897 on 2017/06/06 by Ben.Marsh PR #3655: Improved behavior for Automation.IsBuildMachine (Contributed by projectgheist) Change 3477432 on 2017/06/07 by Robert.Manuszewski Removed AsyncIOBandwidthLimit as it was no longer being used by anything. Change3478582on 2017/06/07 by Ben.Marsh UBT: Allow setting the UE_ENGINE_DIRECTORY macro for any monolithic builds, to fix being able to debug cooked foreign projects in the binary release. Change 3480035 on 2017/06/08 by Gil.Gribb UE4 - Fixed async loading from pak files < 64k. Change 3484348 on 2017/06/12 by Robert.Manuszewski Removed private_subobject macro which was a temporary measure to make all subobjects private without breaking game code. Change 3484863 on 2017/06/12 by Steve.Robb Fix for TSparseArray::operator= corrupting non-POD objects. InCopy.ArrayMax cached in a local instead of being read each time. Const-correctness fix for element copy construction. SrcData and DestData names flipped as they were the wrong way around. Source: https://udn.unrealengine.com/questions/374840/possible-bug-in-tsparsearray-assignment-operator.html Change 3485003 on 2017/06/12 by Ben.Marsh UGS: Add support for multiple tabs. Each tab can monitor changes in a separate workspace, and scheduled syncs will run for all open tabs. Change 3485063 on 2017/06/12 by Ben.Marsh UGS: Fix a null reference exception when right clicking on the notification icon during startup. Change 3485104 on 2017/06/12 by Ben.Marsh PR #2084: [UAT] Command-line parameter to override branch name (Contributed by nbjk667) Change 3485112 on 2017/06/12 by Steve.Robb TSetElement generic constructor protected from becoming a copy constructor. Redundant #include removed from AreTypesEqual.h. Source: https://udn.unrealengine.com/questions/374840/possible-bug-in-tsparsearray-assignment-operator.html Change 3485452 on 2017/06/12 by Ben.Marsh UnrealVS: Fix command line not being updated for C# projects. IVsBuildPropertyStorage.SetPropertyValue does not seem to update properties that are cached in memory. #jira UE-45716 Change 3486182 on 2017/06/12 by Ben.Marsh UGS: Include option to selet tab names in the options menu. Change 3486189 on 2017/06/12 by Ben.Marsh UGS: Fix browse button from context menu always opening a new tab. Change 3486636 on 2017/06/13 by Steve.Robb FStatMessagesArray iteration changed to use ranged-for instead of indexing. Change 3486688 on 2017/06/13 by Steve.Robb Fix for CDO pointer replacement in non-UObject properties during hot reload. #jira UE-38146 Change 3486704 on 2017/06/13 by Ben.Marsh UGS: Fix exception when closing the last open tab. Change 3486707 on 2017/06/13 by Ben.Marsh UGS: Fix exception on load if UGS was closed with no projects open. Change 3486715 on 2017/06/13 by Ben.Marsh UGS: Change tabs to show the project file by default. Change 3486718 on 2017/06/13 by Ben.Marsh UGS: Only allow one workspace to sync at a time. Change 3486880 on 2017/06/13 by Ben.Marsh UGS: Show the sync progress of each tab via the underline on the tab button. Change 3486912 on 2017/06/13 by Ben.Marsh UGS: Include the open project and recent project list as separate top-level menu items. Change 3486914 on 2017/06/13 by Ben.Marsh UGS: Update version to 1.101. Change 3487092 on 2017/06/13 by Ben.Marsh UGS: Fix crash on startup if log window is minimized. Change 3487099 on 2017/06/13 by Ben.Marsh UGS: Update version to 1.102 Change 3487198 on 2017/06/13 by Ben.Marsh Remove debug code. Change 3487285 on 2017/06/13 by Ben.Marsh Restore Remap() function that was accidentally removed in merge. Change 3487769 on 2017/06/13 by Ben.Marsh Disable the promoted flag when using the SyncProject command on Mac; doing so prevents UE4Game being compiled when packaging blueprint projects. #jira UE-45995 Change 3487915 on 2017/06/13 by Ben.Marsh UAT: Fix exception due to collection being modified while packaging for Linux. #jira UE-46013 Change 3487972 on 2017/06/13 by Ben.Marsh UAT: Always allow staged files to overwrite previously staged files. New iOS code relies on old behavior to overwrite engine icons and metadata with game copies. #jira UE-46014 Change 3487991 on 2017/06/13 by Ben.Marsh UAT: Ensure that the directory exists before trying to create a placeholder log filename. #jira UE-46015 Change 3489062 on 2017/06/14 by Robert.Manuszewski Removed FPackageFileSummary's AdditionalPackagesToCook as it was not used by anything. This should reduce the package header size considerably for levels with many streaming sublevels. #jira UE-45563 Change 3489063 on 2017/06/14 by Robert.Manuszewski Increasing the maximum package summary size to handle levels with multiple streaming sublevels. #jira UE-45563 Change 3491552 on 2017/06/15 by Ben.Marsh Handle failures to load *MeshReduction modules. [CL 3492074 by Ben Marsh in Main branch]
870 lines
32 KiB
C#
870 lines
32 KiB
C#
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
|
|
using System;
|
|
using System.IO;
|
|
using System.Net.Http;
|
|
using System.Text;
|
|
using AutomationTool;
|
|
using UnrealBuildTool;
|
|
using System.Threading.Tasks;
|
|
using System.Collections.Generic;
|
|
using System.Security.Cryptography;
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
|
public class HTML5Platform : Platform
|
|
{
|
|
// ini configurations
|
|
static bool Compressed = false;
|
|
static bool targetingWasm = true;
|
|
static bool targetWebGL2 = true;
|
|
static bool enableIndexedDB = false; // experimental for now...
|
|
|
|
public HTML5Platform()
|
|
: base(UnrealTargetPlatform.HTML5)
|
|
{
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
void CompressFile(string Source, string Destination)
|
|
{
|
|
Log(" Compressing " + Source);
|
|
bool DeleteSource = false;
|
|
|
|
if( Source == Destination )
|
|
{
|
|
string CopyOrig = Source + ".Copy";
|
|
File.Copy(Source, CopyOrig);
|
|
Source = CopyOrig;
|
|
DeleteSource = true;
|
|
}
|
|
|
|
using (System.IO.Stream input = System.IO.File.OpenRead(Source))
|
|
{
|
|
using (var raw = System.IO.File.Create(Destination))
|
|
{
|
|
using (Stream compressor = new Ionic.Zlib.GZipStream(raw, Ionic.Zlib.CompressionMode.Compress,Ionic.Zlib.CompressionLevel.BestCompression))
|
|
{
|
|
byte[] buffer = new byte[2048];
|
|
int SizeRead = 0;
|
|
while ((SizeRead = input.Read(buffer, 0, buffer.Length)) != 0)
|
|
{
|
|
compressor.Write(buffer, 0, SizeRead);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (DeleteSource)
|
|
{
|
|
File.Delete(Source);
|
|
}
|
|
}
|
|
|
|
public override bool RequiresPackageToDeploy
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
|
|
protected void GenerateFileFromTemplate(string InTemplateFile, string InOutputFile, string InGameName, string InGameConfiguration, string InArguments, bool IsContentOnly, int HeapSize)
|
|
{
|
|
StringBuilder outputContents = new StringBuilder();
|
|
using (StreamReader reader = new StreamReader(InTemplateFile))
|
|
{
|
|
string LineStr = null;
|
|
while (reader.Peek() != -1)
|
|
{
|
|
LineStr = reader.ReadLine();
|
|
if (LineStr.Contains("%TIMESTAMP%"))
|
|
{
|
|
string TimeStamp = DateTime.UtcNow.ToString("yyyyMMddHHmm");
|
|
LineStr = LineStr.Replace("%TIMESTAMP%", TimeStamp);
|
|
}
|
|
|
|
if (LineStr.Contains("%GAME%"))
|
|
{
|
|
LineStr = LineStr.Replace("%GAME%", InGameName);
|
|
}
|
|
|
|
if (LineStr.Contains("%SERVE_COMPRESSED%"))
|
|
{
|
|
LineStr = LineStr.Replace("%SERVE_COMPRESSED%", Compressed ? "true" : "false");
|
|
}
|
|
|
|
if (LineStr.Contains("%DISABLE_INDEXEDDB%"))
|
|
{
|
|
LineStr = LineStr.Replace("%DISABLE_INDEXEDDB%",
|
|
enableIndexedDB ? "" : "enableReadFromIndexedDB = false;\nenableWriteToIndexedDB = false;");
|
|
}
|
|
|
|
if (LineStr.Contains("%HEAPSIZE%"))
|
|
{
|
|
LineStr = LineStr.Replace("%HEAPSIZE%", HeapSize.ToString() + " * 1024 * 1024");
|
|
}
|
|
|
|
if (LineStr.Contains("%CONFIG%"))
|
|
{
|
|
string TempGameName = InGameName;
|
|
if (IsContentOnly)
|
|
TempGameName = "UE4Game";
|
|
LineStr = LineStr.Replace("%CONFIG%", (InGameConfiguration != "Development" ? (TempGameName + "-HTML5-" + InGameConfiguration) : TempGameName));
|
|
}
|
|
|
|
if (LineStr.Contains("%UE4CMDLINE%"))
|
|
{
|
|
InArguments = InArguments.Replace ("\"", "");
|
|
string[] Arguments = InArguments.Split(' ');
|
|
string ArgumentString = IsContentOnly ? "'../../../" + InGameName + "/" + InGameName + ".uproject '," : "";
|
|
for (int i = 0; i < Arguments.Length - 1; ++i)
|
|
{
|
|
ArgumentString += "'" + Arguments[i] + "'" + ",' ',";
|
|
}
|
|
if (Arguments.Length > 0)
|
|
{
|
|
ArgumentString += "'" + Arguments[Arguments.Length - 1] + "'";
|
|
}
|
|
LineStr = LineStr.Replace("%UE4CMDLINE%", ArgumentString);
|
|
}
|
|
|
|
if (!targetingWasm && LineStr.Contains("const explicitlyLoadedAsmJs"))
|
|
{
|
|
LineStr = "const explicitlyLoadedAsmJs = true;";
|
|
}
|
|
|
|
if (!targetWebGL2 && LineStr.Contains("const explicitlyUseWebGL1"))
|
|
{
|
|
LineStr = "const explicitlyUseWebGL1 = true;";
|
|
}
|
|
|
|
outputContents.AppendLine(LineStr);
|
|
}
|
|
}
|
|
|
|
if (outputContents.Length > 0)
|
|
{
|
|
// Save the file
|
|
try
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(InOutputFile));
|
|
File.WriteAllText(InOutputFile, outputContents.ToString(), Encoding.UTF8);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Unable to write to the project file.
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void GenerateMacCommandFromTemplate(string InTemplateFile, string InOutputFile, string InMonoPath)
|
|
{
|
|
StringBuilder outputContents = new StringBuilder();
|
|
using (StreamReader reader = new StreamReader(InTemplateFile))
|
|
{
|
|
string InMonoPathParent = Path.GetDirectoryName(InMonoPath);
|
|
string LineStr = null;
|
|
while (reader.Peek() != -1)
|
|
{
|
|
LineStr = reader.ReadLine();
|
|
if (LineStr.Contains("${unreal_mono_pkg_path}"))
|
|
{
|
|
LineStr = LineStr.Replace("${unreal_mono_pkg_path}", InMonoPath);
|
|
}
|
|
if (LineStr.Contains("${unreal_mono_pkg_path_base}"))
|
|
{
|
|
LineStr = LineStr.Replace("${unreal_mono_pkg_path_base}", InMonoPathParent);
|
|
}
|
|
|
|
outputContents.Append(LineStr + '\n');
|
|
}
|
|
}
|
|
|
|
if (outputContents.Length > 0)
|
|
{
|
|
// Save the file. We Copy the template file to keep any permissions set to it.
|
|
try
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(InOutputFile));
|
|
if (File.Exists(InOutputFile))
|
|
{
|
|
File.SetAttributes(InOutputFile, File.GetAttributes(InOutputFile) & ~FileAttributes.ReadOnly);
|
|
File.Delete(InOutputFile);
|
|
}
|
|
File.Copy(InTemplateFile, InOutputFile);
|
|
File.SetAttributes(InOutputFile, File.GetAttributes(InOutputFile) & ~FileAttributes.ReadOnly);
|
|
using (var CmdFile = File.Open(InOutputFile, FileMode.OpenOrCreate | FileMode.Truncate))
|
|
{
|
|
Byte[] BytesToWrite = new UTF8Encoding(true).GetBytes(outputContents.ToString());
|
|
CmdFile.Write(BytesToWrite, 0, BytesToWrite.Length);
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Unable to write to the project file.
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void GetFilesToDeployOrStage(ProjectParams Params, DeploymentContext SC)
|
|
{
|
|
}
|
|
|
|
public override void GetFilesToArchive(ProjectParams Params, DeploymentContext SC)
|
|
{
|
|
if (SC.StageTargetConfigurations.Count != 1)
|
|
{
|
|
throw new AutomationException("iOS is currently only able to package one target configuration at a time, but StageTargetConfigurations contained {0} configurations", SC.StageTargetConfigurations.Count);
|
|
}
|
|
|
|
string PackagePath = Path.Combine(Path.GetDirectoryName(Params.RawProjectPath.FullName), "Binaries", "HTML5");
|
|
string ProjectDataName = Params.ShortProjectName + ".data";
|
|
|
|
// copy the "Executable" to the archive directory
|
|
string GameBasename = Path.GetFileNameWithoutExtension(Params.ProjectGameExeFilename);
|
|
if (Params.ClientConfigsToBuild[0].ToString() != "Development")
|
|
{
|
|
GameBasename += "-HTML5-" + Params.ClientConfigsToBuild[0].ToString();
|
|
}
|
|
string GameExe = GameBasename + ".js";
|
|
|
|
// put the HTML file to the package directory
|
|
string OutputFilename = (Params.ClientConfigsToBuild[0].ToString() != "Development" ?
|
|
(Params.ShortProjectName + "-HTML5-" + Params.ClientConfigsToBuild[0].ToString()) :
|
|
Params.ShortProjectName) + ".html";
|
|
|
|
// data file
|
|
SC.ArchiveFiles(PackagePath, ProjectDataName);
|
|
// data file js driver
|
|
SC.ArchiveFiles(PackagePath, ProjectDataName + ".js");
|
|
if (targetingWasm)
|
|
{
|
|
// main game code
|
|
SC.ArchiveFiles(PackagePath, GameBasename + ".wasm");
|
|
// main js file
|
|
SC.ArchiveFiles(PackagePath, GameExe);
|
|
}
|
|
else
|
|
{
|
|
// memory init file
|
|
SC.ArchiveFiles(PackagePath, GameExe + ".mem");
|
|
// maingame code
|
|
SC.ArchiveFiles(PackagePath, GameBasename + ".asm.js");
|
|
// main js file
|
|
SC.ArchiveFiles(PackagePath, GameBasename + "_asm.js");
|
|
}
|
|
// symbols file
|
|
SC.ArchiveFiles(PackagePath, GameExe + ".symbols");
|
|
// utilities
|
|
SC.ArchiveFiles(PackagePath, "Utility.js");
|
|
// landing page.
|
|
SC.ArchiveFiles(PackagePath, OutputFilename);
|
|
|
|
// Archive HTML5 Server and a Readme.
|
|
SC.ArchiveFiles(CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/"), "HTML5LaunchHelper.exe");
|
|
SC.ArchiveFiles(CombinePaths(CmdEnv.LocalRoot, "Engine/Build/HTML5/"), "Readme.txt");
|
|
SC.ArchiveFiles(PackagePath, "RunMacHTML5LaunchHelper.command");
|
|
SC.ArchiveFiles(PackagePath, ".htaccess");
|
|
|
|
if (Compressed)
|
|
{
|
|
SC.ArchiveFiles(PackagePath, ProjectDataName + "gz");
|
|
SC.ArchiveFiles(PackagePath, ProjectDataName + ".jsgz");
|
|
SC.ArchiveFiles(PackagePath, GameExe + "gz");
|
|
if (targetingWasm)
|
|
{
|
|
SC.ArchiveFiles(PackagePath, GameBasename + ".wasmgz");
|
|
}
|
|
else
|
|
{
|
|
SC.ArchiveFiles(PackagePath, GameExe + ".memgz");
|
|
SC.ArchiveFiles(PackagePath, GameExe + ".asm.jsgz");
|
|
}
|
|
SC.ArchiveFiles(PackagePath, GameExe + ".symbolsgz");
|
|
SC.ArchiveFiles(PackagePath, "Utility.jsgz");
|
|
}
|
|
else
|
|
{
|
|
// nuke old compressed files to prevent using stale files
|
|
File.Delete(ProjectDataName + "gz");
|
|
File.Delete(ProjectDataName + ".jsgz");
|
|
File.Delete(GameExe + "gz");
|
|
File.Delete(GameBasename + ".wasmgz");
|
|
File.Delete(GameExe + ".memgz");
|
|
File.Delete(GameExe + ".symbolsgz");
|
|
File.Delete("Utility.jsgz");
|
|
}
|
|
|
|
if (HTMLPakAutomation.CanCreateMapPaks(Params))
|
|
{
|
|
// find all paks.
|
|
string[] Files = Directory.GetFiles(Path.Combine(PackagePath, Params.ShortProjectName), "*", SearchOption.AllDirectories);
|
|
foreach(string PakFile in Files)
|
|
{
|
|
SC.ArchivedFiles.Add(PakFile, Path.GetFileName(PakFile));
|
|
}
|
|
}
|
|
|
|
UploadToS3(SC, OutputFilename);
|
|
}
|
|
|
|
public override IProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
|
|
{
|
|
// look for browser
|
|
string BrowserPath = Params.Devices[0].Replace("HTML5@", "");
|
|
|
|
// open the webpage
|
|
Int32 ServerPort = 8000; // HTML5LaunchHelper default
|
|
|
|
var ConfigCache = UnrealBuildTool.ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(Params.RawProjectPath), UnrealTargetPlatform.HTML5);
|
|
ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort); // LaunchOn via Editor or FrontEnd
|
|
string WorkingDirectory = Path.GetDirectoryName(ClientApp);
|
|
string url = Path.GetFileName(ClientApp) +".html";
|
|
|
|
// WARNING: splitting the following situation
|
|
// if cookonthefly is used: tell the browser to use the PROXY at DEFAULT_HTTP_FILE_SERVING_PORT
|
|
// leave the normal HTML5LaunchHelper port (ServerPort) alone -- otherwise it will collide with the PROXY port
|
|
if (ClientCmdLine.Contains("filehostip"))
|
|
{
|
|
url += "?cookonthefly=true";
|
|
Int32 ProxyPort = 41898; // DEFAULT_HTTP_FILE_SERVING_PORT
|
|
url = String.Format("http://localhost:{0}/{1}", ProxyPort, url);
|
|
}
|
|
else
|
|
{
|
|
url = String.Format("http://localhost:{0}/{1}", ServerPort, url);
|
|
}
|
|
|
|
// Check HTML5LaunchHelper source for command line args
|
|
|
|
var LowerBrowserPath = BrowserPath.ToLower();
|
|
var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory().FullName, "UE4_HTML5", "user");
|
|
|
|
string BrowserCommandline = url;
|
|
|
|
if (LowerBrowserPath.Contains("chrome"))
|
|
{
|
|
ProfileDirectory = Path.Combine(ProfileDirectory, "chrome");
|
|
// removing [--enable-logging] otherwise, chrome breaks with a bunch of the following errors:
|
|
// > ERROR:process_info.cc(631)] range at 0x7848406c00000000, size 0x1a4 fully unreadable
|
|
// leaving this note here for future reference: UE-45078
|
|
BrowserCommandline += " " + String.Format("--user-data-dir=\\\"{0}\\\" --no-first-run", ProfileDirectory);
|
|
}
|
|
else if (LowerBrowserPath.Contains("firefox"))
|
|
{
|
|
ProfileDirectory = Path.Combine(ProfileDirectory, "firefox");
|
|
BrowserCommandline += " " + String.Format("-no-remote -profile \\\"{0}\\\"", ProfileDirectory);
|
|
}
|
|
|
|
if (UnrealBuildTool.BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Linux)
|
|
{
|
|
// TODO: test on other platforms to remove this if() check
|
|
if (!Directory.Exists(ProfileDirectory))
|
|
{
|
|
Directory.CreateDirectory(ProfileDirectory);
|
|
}
|
|
}
|
|
|
|
string LauncherArguments = string.Format(" -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" ",
|
|
new object[] { BrowserPath, BrowserCommandline, ServerPort, WorkingDirectory });
|
|
|
|
var LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe");
|
|
IProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit);
|
|
|
|
return BrowserProcess;
|
|
}
|
|
|
|
public override string GetCookPlatform(bool bDedicatedServer, bool bIsClientOnly)
|
|
{
|
|
return "HTML5";
|
|
}
|
|
|
|
public override string GetCookExtraCommandLine(ProjectParams Params)
|
|
{
|
|
return HTMLPakAutomation.CanCreateMapPaks(Params) ? " -GenerateDependenciesForMaps " : "";
|
|
}
|
|
|
|
public override PakType RequiresPak(ProjectParams Params)
|
|
{
|
|
return HTMLPakAutomation.CanCreateMapPaks(Params) ? PakType.Never : PakType.Always;
|
|
}
|
|
|
|
public override string GetPlatformPakCommandLine()
|
|
{
|
|
return Compressed ? " -compress" : "";
|
|
}
|
|
|
|
public override bool DeployLowerCaseFilenames(bool bUFSFile)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public override string LocalPathToTargetPath(string LocalPath, string LocalRoot)
|
|
{
|
|
return LocalPath;//.Replace("\\", "/").Replace(LocalRoot, "../../..");
|
|
}
|
|
|
|
public override bool IsSupported { get { return true; } }
|
|
|
|
public override List<string> GetDebugFileExtentions()
|
|
{
|
|
return new List<string> { ".pdb" };
|
|
}
|
|
|
|
#region Hooks
|
|
public override void PreBuildAgenda(UE4Build Build, UE4Build.BuildAgenda Agenda)
|
|
{
|
|
}
|
|
|
|
public override List<FileReference> GetExecutableNames(DeploymentContext SC)
|
|
{
|
|
List<FileReference> ExecutableNames = new List<FileReference>();
|
|
ExecutableNames.Add(FileReference.Combine(SC.ProjectRoot, "Binaries", "HTML5", SC.ShortProjectName));
|
|
return ExecutableNames;
|
|
}
|
|
#endregion
|
|
|
|
#region AMAZON S3
|
|
public void UploadToS3(DeploymentContext SC, string OutputFilename)
|
|
{
|
|
ConfigHierarchy Ini = ConfigCache.ReadHierarchy(ConfigHierarchyType.Engine, DirectoryReference.FromFile(SC.RawProjectPath), SC.StageTargetPlatform.PlatformType);
|
|
bool Upload = false;
|
|
|
|
string Region = "";
|
|
string KeyId = "";
|
|
string AccessKey = "";
|
|
string BucketName = "";
|
|
string FolderName = "";
|
|
|
|
if (! Ini.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "UploadToS3", out Upload) || ! Upload )
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool AmazonIdentity = Ini.GetString("/Script/HTML5PlatformEditor.HTML5TargetSettings", "S3Region", out Region) &&
|
|
Ini.GetString("/Script/HTML5PlatformEditor.HTML5TargetSettings", "S3KeyID", out KeyId) &&
|
|
Ini.GetString("/Script/HTML5PlatformEditor.HTML5TargetSettings", "S3SecretAccessKey", out AccessKey) &&
|
|
Ini.GetString("/Script/HTML5PlatformEditor.HTML5TargetSettings", "S3BucketName", out BucketName);
|
|
|
|
if ( !AmazonIdentity )
|
|
{
|
|
Log("Amazon S3 Incorrectly configured");
|
|
return;
|
|
}
|
|
|
|
Ini.GetString("/Script/HTML5PlatformEditor.HTML5TargetSettings", "S3FolderName", out FolderName);
|
|
if ( FolderName == "" )
|
|
{
|
|
FolderName = SC.ShortProjectName;
|
|
}
|
|
else
|
|
{
|
|
// strip any before and after folder "/"
|
|
FolderName = Regex.Replace(Regex.Replace(FolderName, "^/+", "" ), "/+$", "");
|
|
}
|
|
|
|
List<Task> UploadTasks = new List<Task>();
|
|
long msTimeOut = 0;
|
|
foreach (KeyValuePair<string, string> Entry in SC.ArchivedFiles)
|
|
{
|
|
FileInfo Info = new FileInfo(Entry.Key);
|
|
UploadTasks.Add(UploadToS3Worker(Info, Region, KeyId, AccessKey, BucketName, FolderName));
|
|
if ( msTimeOut < Info.Length )
|
|
{
|
|
msTimeOut = Info.Length;
|
|
}
|
|
}
|
|
msTimeOut /= 100; // [miliseconds] give 10 secs for each ~MB ( (10s * 1000ms) / ( 1024KB * 1024MB * 1000ms ) )
|
|
if ( msTimeOut < (100*1000) ) // HttpClient: default timeout is 100 sec
|
|
{
|
|
msTimeOut = 100*1000;
|
|
}
|
|
Log("Upload Timeout set to: " + (msTimeOut/1000) + "secs");
|
|
Task.WaitAll(UploadTasks.ToArray(), (int)msTimeOut); // set timeout [miliseconds]
|
|
|
|
string URL = "https://" + BucketName + ".s3.amazonaws.com/" + FolderName + "/" + OutputFilename;
|
|
Log("Your project's shareable link is: " + URL);
|
|
|
|
Log("Upload Tasks finished.");
|
|
}
|
|
|
|
private static IDictionary<string, string> MimeTypeMapping = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase)
|
|
{
|
|
// the following will default to: "appication/octet-stream"
|
|
// .data .datagz
|
|
|
|
{ ".wasm", "application/wasm" },
|
|
{ ".wasmgz", "application/wasm" },
|
|
{ ".htaccess", "text/plain"},
|
|
{ ".html", "text/html"},
|
|
{ ".js", "application/x-javascript" },
|
|
{ ".jsgz", "application/x-javascript" },
|
|
{ ".symbols", "text/plain"},
|
|
{ ".symbolsgz", "text/plain"},
|
|
{ ".txt", "text/plain"}
|
|
};
|
|
|
|
static async Task UploadToS3Worker(FileInfo Info, string Region, string KeyId, string AccessKey, string BucketName, string FolderName)
|
|
{
|
|
// --------------------------------------------------
|
|
// "AWS Signature Version 4"
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
|
|
// --------------------------------------------------
|
|
Log(" Uploading " + Info.Name);
|
|
|
|
// --------------------------------------------------
|
|
// http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html
|
|
string TimeStamp = DateTime.UtcNow.ToString("yyyyMMddTHHmmssZ");
|
|
string DateExpire = DateTime.UtcNow.AddDays(1).ToString("yyyy-MM-dd");
|
|
string AWSDate = DateTime.UtcNow.AddDays(1).ToString("yyyyMMdd");
|
|
string MimeType = (MimeTypeMapping.ContainsKey(Info.Extension))
|
|
? MimeTypeMapping[Info.Extension]
|
|
: "application/octet-stream";
|
|
string MimePath = MimeType.Split('/')[0];
|
|
string AWSCredential = KeyId + "/" + AWSDate + "/" + Region + "/s3/aws4_request";
|
|
|
|
// --------------------------------------------------
|
|
string policy = "{ \"expiration\": \"" + DateExpire + "T12:00:00.000Z\"," +
|
|
" \"conditions\": [" +
|
|
" { \"bucket\": \"" + BucketName + "\" }," +
|
|
" [ \"starts-with\", \"$key\", \"" + FolderName + "/\" ]," +
|
|
" { \"acl\": \"public-read\" }," +
|
|
" [ \"starts-with\", \"$content-type\", \"" + MimePath + "/\" ],";
|
|
if (Info.Extension.EndsWith("gz"))
|
|
{
|
|
policy += " [ \"starts-with\", \"$content-encoding\", \"gzip\" ],";
|
|
}
|
|
policy += " { \"x-amz-credential\": \"" + AWSCredential + "\" }," +
|
|
" { \"x-amz-algorithm\": \"AWS4-HMAC-SHA256\" }," +
|
|
" { \"x-amz-date\": \"" + TimeStamp + "\" }" +
|
|
" ]" +
|
|
"}";
|
|
string policyBase64 = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(policy), Base64FormattingOptions.InsertLineBreaks);
|
|
|
|
// --------------------------------------------------
|
|
// http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html
|
|
var kha = KeyedHashAlgorithm.Create("HmacSHA256");
|
|
kha.Key = Encoding.UTF8.GetBytes(("AWS4" + AccessKey).ToCharArray()); // kSecret
|
|
byte[] sig = kha.ComputeHash(Encoding.UTF8.GetBytes(AWSDate));
|
|
kha.Key = sig; // kDate
|
|
|
|
sig = kha.ComputeHash(Encoding.UTF8.GetBytes(Region));
|
|
kha.Key = sig; // kRegion
|
|
|
|
sig = kha.ComputeHash(Encoding.UTF8.GetBytes("s3"));
|
|
kha.Key = sig; // kService
|
|
|
|
sig = kha.ComputeHash(Encoding.UTF8.GetBytes("aws4_request"));
|
|
kha.Key = sig; // kSigning
|
|
|
|
sig = kha.ComputeHash(Encoding.UTF8.GetBytes(policyBase64));
|
|
string signature = BitConverter.ToString(sig).Replace("-", "").ToLower(); // for Authorization
|
|
|
|
// debugging...
|
|
//Console.WriteLine("policy: [" + policy + "]");
|
|
//Console.WriteLine("policyBase64: [" + policyBase64 + "]");
|
|
//Console.WriteLine("signature: [" + signature + "]");
|
|
|
|
// --------------------------------------------------
|
|
HttpClient httpClient = new HttpClient();
|
|
var formData = new MultipartFormDataContent();
|
|
formData.Add(new StringContent(FolderName + "/" + Info.Name), "key");
|
|
formData.Add(new StringContent("public-read"), "acl");
|
|
formData.Add(new StringContent(AWSCredential), "X-Amz-Credential");
|
|
formData.Add(new StringContent("AWS4-HMAC-SHA256"), "X-Amz-Algorithm");
|
|
formData.Add(new StringContent(signature), "X-Amz-Signature");
|
|
formData.Add(new StringContent(TimeStamp), "X-Amz-Date");
|
|
formData.Add(new StringContent(policyBase64), "Policy");
|
|
formData.Add(new StringContent(MimeType), "Content-Type");
|
|
if ( Info.Extension.EndsWith("gz") )
|
|
{
|
|
formData.Add(new StringContent("gzip"), "Content-Encoding");
|
|
}
|
|
// debugging...
|
|
//Console.WriteLine("key: [" + FolderName + "/" + Info.Name + "]");
|
|
//Console.WriteLine("AWSCredential: [" + AWSCredential + "]");
|
|
//Console.WriteLine("TimeStamp: [" + TimeStamp + "]");
|
|
//Console.WriteLine("MimeType: [" + MimeType + "]");
|
|
|
|
// the file ----------------------------------------
|
|
var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(Info.FullName));
|
|
fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(MimeType);
|
|
formData.Add(fileContent, "file", Info.Name);
|
|
int adjustTimeout = (int)(Info.Length / (100*1000)); // [seconds] give 10 secs for each ~MB ( (10s * 1000ms) / ( 1024KB * 1024MB * 1000ms ) )
|
|
if ( adjustTimeout > 100 ) // default timeout is 100 sec
|
|
{
|
|
httpClient.Timeout = TimeSpan.FromSeconds(adjustTimeout); // increase timeout
|
|
}
|
|
//Console.WriteLine("httpClient Timeout: [" + httpClient.Timeout + "]" );
|
|
|
|
// upload ----------------------------------------
|
|
string URL = "https://" + BucketName + ".s3.amazonaws.com/";
|
|
var response = await httpClient.PostAsync(URL, formData);
|
|
if (response.IsSuccessStatusCode)
|
|
{
|
|
Log("Upload done: " + Info.Name);
|
|
}
|
|
else
|
|
{
|
|
var contents = response.Content.ReadAsStringAsync();
|
|
var reason = Regex.Replace(
|
|
/* grab inner block */ Regex.Replace(contents.Result, "<[^>]+>\n<[^>]+>([^<]+)</[^>]+>", "$1")
|
|
/* strip tags */ , "<([^>]+)>([^<]+)</[^>]+>", "$1 - $2\n");
|
|
|
|
//Console.WriteLine("Fail to Upload: " + Info.Name + " Header - " + response.ToString());
|
|
Console.WriteLine("Fail to Upload: " + Info.Name + "\nResponse - " + reason);
|
|
throw new Exception("FAILED TO UPLOAD: " + Info.Name);
|
|
}
|
|
}
|
|
#endregion
|
|
}
|