2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
using System ;
2015-07-06 19:26:15 -04:00
using Ionic.Zip ;
using System.IO ;
using System.Web ;
using System.Net ;
2014-03-14 14:13:41 -04:00
using System.Linq ;
using System.Text ;
using AutomationTool ;
using UnrealBuildTool ;
2014-09-15 10:56:03 -04:00
using System.Threading ;
2015-07-06 19:26:15 -04:00
using System.Diagnostics ;
2015-07-04 18:45:54 -04:00
using System.Threading.Tasks ;
2015-07-06 19:26:15 -04:00
using System.Collections.Generic ;
using System.Security.Cryptography ;
using System.Text.RegularExpressions ;
2014-03-14 14:13:41 -04:00
2015-07-04 18:45:54 -04:00
2014-03-14 14:13:41 -04:00
public class HTML5Platform : Platform
{
2015-07-04 18:45:54 -04:00
public HTML5Platform ( )
2014-08-18 13:29:39 -04:00
: base ( UnrealTargetPlatform . HTML5 )
2014-03-14 14:13:41 -04:00
{
}
public override void Package ( ProjectParams Params , DeploymentContext SC , int WorkingCL )
{
2015-07-23 14:51:46 -04:00
LogConsole ( "Package {0}" , Params . RawProjectPath ) ;
2015-07-15 16:37:24 -04:00
2015-07-23 14:51:46 -04:00
LogConsole ( "Setting Emscripten SDK for packaging.." ) ;
2015-07-15 16:37:24 -04:00
HTML5SDKInfo . SetupEmscriptenTemp ( ) ;
HTML5SDKInfo . SetUpEmscriptenConfigFile ( ) ;
2015-07-04 18:45:54 -04:00
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" ;
2014-07-07 19:15:12 -04:00
2015-07-04 18:45:54 -04:00
var ConfigCache = new UnrealBuildTool . ConfigCacheIni ( UnrealTargetPlatform . HTML5 , "Engine" , Path . GetDirectoryName ( Params . RawProjectPath ) , CommandUtils . CombinePaths ( CommandUtils . CmdEnv . LocalRoot , "Engine" ) ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
if ( HTMLPakAutomation . CanCreateMapPaks ( Params ) )
{
HTMLPakAutomation PakAutomation = new HTMLPakAutomation ( Params , SC ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
// Create Necessary Paks.
PakAutomation . CreateEnginePak ( ) ;
PakAutomation . CreateGamePak ( ) ;
PakAutomation . CreateContentDirectoryPak ( ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
// Create Emscripten Package from Necessary Paks. - This will be the VFS.
PakAutomation . CreateEmscriptenDataPackage ( PackagePath , FinalDataLocation ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
// Create All Map Paks which will be downloaded on the fly.
PakAutomation . CreateMapPak ( ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
// Create Delta Paks if setup.
List < string > Paks = new List < string > ( ) ;
ConfigCache . GetArray ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "LevelTransitions" , out Paks ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
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 ( ) ;
2014-10-31 04:31:19 -04:00
2015-07-09 10:31:56 -04:00
using ( new ScopedEnvVar ( "EM_CONFIG" , HTML5SDKInfo . DOT_EMSCRIPTEN ) )
2015-07-04 18:45:54 -04:00
{
2015-07-09 10:31:56 -04:00
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 ) ;
}
2015-07-04 18:45:54 -04:00
}
}
2014-09-24 13:56:28 -04:00
2015-07-04 18:45:54 -04:00
// 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" ;
2015-02-01 12:33:30 -05:00
2015-04-08 14:53:36 -04:00
// ensure the ue4game binary exists, if applicable
string FullGameExePath = Path . Combine ( Path . GetDirectoryName ( Params . ProjectGameExeFilename ) , GameExe ) ;
if ( ! SC . IsCodeBasedProject & & ! FileExists_NoExceptions ( FullGameExePath ) )
{
2015-07-23 14:51:46 -04:00
LogConsole ( "Failed to find game application " + FullGameExePath ) ;
2015-06-30 11:40:05 -04:00
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 ) ;
2015-04-08 14:53:36 -04:00
}
2015-02-01 12:33:30 -05:00
2015-07-04 18:45:54 -04:00
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 ) ;
2015-05-18 18:27:24 -04:00
File . Copy ( Path . Combine ( Path . GetDirectoryName ( Params . ProjectGameExeFilename ) , GameExe ) + ".symbols" , Path . Combine ( PackagePath , GameExe ) + ".symbols" , true ) ;
2015-07-04 18:45:54 -04:00
}
2015-05-20 15:30:36 -04:00
2015-07-04 18:45:54 -04:00
File . SetAttributes ( Path . Combine ( PackagePath , GameExe ) , FileAttributes . Normal ) ;
File . SetAttributes ( Path . Combine ( PackagePath , GameExe ) + ".mem" , FileAttributes . Normal ) ;
2015-06-04 17:21:16 -04:00
File . SetAttributes ( Path . Combine ( PackagePath , GameExe ) + ".symbols" , FileAttributes . Normal ) ;
2015-04-08 14:53:36 -04:00
2015-06-11 15:29:20 -04:00
2015-07-04 18:45:54 -04:00
// 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" ;
2015-04-22 14:26:39 -04:00
2015-07-04 18:45:54 -04:00
// find Heap Size.
ulong HeapSize ;
2015-04-22 14:26:39 -04:00
2015-07-04 18:45:54 -04:00
int ConfigHeapSize = 0 ;
// Valuer set by Editor UI
var bGotHeapSize = ConfigCache . GetInt32 ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "HeapSize" + Params . ClientConfigsToBuild [ 0 ] . ToString ( ) , out ConfigHeapSize ) ;
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
// 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 ;
2015-07-23 14:51:46 -04:00
LogConsole ( "Could not find Heap Size setting in .ini for Client config {0}" , Params . ClientConfigsToBuild [ 0 ] . ToString ( ) ) ;
2015-07-04 18:45:54 -04:00
}
}
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
HeapSize = ( ulong ) ConfigHeapSize * 1024L * 1024L ; // convert to bytes.
2015-07-23 14:51:46 -04:00
LogConsole ( "Setting Heap size to {0} Mb " , ConfigHeapSize ) ;
2014-07-07 19:15:12 -04:00
2015-07-04 18:45:54 -04:00
GenerateFileFromTemplate ( TemplateFile , OutputFile , Params . ShortProjectName , Params . ClientConfigsToBuild [ 0 ] . ToString ( ) , Params . StageCommandline , ! Params . IsCodeBasedProject , HeapSize ) ;
2014-07-07 19:15:12 -04:00
2015-07-04 18:45:54 -04:00
string JSDir = Path . Combine ( CombinePaths ( CmdEnv . LocalRoot , "Engine" ) , "Build" , "HTML5" ) ;
string OutDir = PackagePath ;
2015-06-04 17:21:16 -04:00
// 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 ) ;
}
2015-07-04 18:45:54 -04:00
// Compress all files. These are independent tasks which can be threaded.
Task [ ] CompressionTasks = new Task [ 6 ] ;
2015-06-11 15:29:20 -04:00
//data file.
2015-07-04 18:45:54 -04:00
CompressionTasks [ 0 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( FinalDataLocation , FinalDataLocation + ".gz" ) ) ;
2015-06-11 15:29:20 -04:00
// data file .js driver.
2015-07-04 18:45:54 -04:00
CompressionTasks [ 1 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( FinalDataLocation + ".js" , FinalDataLocation + ".js.gz" ) ) ;
2015-06-11 15:29:20 -04:00
// main js.
2015-07-04 18:45:54 -04:00
CompressionTasks [ 2 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( Path . Combine ( PackagePath , GameExe ) , Path . Combine ( PackagePath , GameExe ) + ".gz" ) ) ;
2015-06-11 15:29:20 -04:00
// mem init file.
2015-07-04 18:45:54 -04:00
CompressionTasks [ 3 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( Path . Combine ( PackagePath , GameExe ) + ".mem" , Path . Combine ( PackagePath , GameExe ) + ".mem.gz" ) ) ;
2015-06-11 15:29:20 -04:00
// symbols file.
2015-07-04 18:45:54 -04:00
CompressionTasks [ 4 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( Path . Combine ( PackagePath , GameExe ) + ".symbols" , Path . Combine ( PackagePath , GameExe ) + ".symbols.gz" ) ) ;
2015-06-11 15:29:20 -04:00
// Utility
2015-07-04 18:45:54 -04:00
CompressionTasks [ 5 ] = Task . Factory . StartNew ( ( ) = > CompressFile ( OutDir + "/Utility.js" , OutDir + "/Utility.js.gz" ) ) ;
2015-06-04 17:21:16 -04:00
2015-07-04 18:45:54 -04:00
Task . WaitAll ( CompressionTasks ) ;
PrintRunTime ( ) ;
2014-03-14 14:13:41 -04:00
}
2015-06-04 17:21:16 -04:00
void CompressFile ( string Source , string Destination )
{
2015-07-23 14:51:46 -04:00
LogConsole ( " Compressing " + Source ) ;
2015-06-04 17:21:16 -04:00
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 . Exists ( Source ) )
{
File . Delete ( Source ) ;
}
}
2014-09-22 14:24:24 -04:00
2015-07-04 18:45:54 -04:00
public override bool RequiresPackageToDeploy
{
get { return true ; }
}
2014-09-22 14:24:24 -04:00
2014-05-29 17:32:36 -04:00
protected void GenerateFileFromTemplate ( string InTemplateFile , string InOutputFile , string InGameName , string InGameConfiguration , string InArguments , bool IsContentOnly , ulong HeapSize )
2014-03-14 14:13:41 -04:00
{
StringBuilder outputContents = new StringBuilder ( ) ;
using ( StreamReader reader = new StreamReader ( InTemplateFile ) )
{
string LineStr = null ;
while ( reader . Peek ( ) ! = - 1 )
{
LineStr = reader . ReadLine ( ) ;
if ( LineStr . Contains ( "%GAME%" ) )
{
LineStr = LineStr . Replace ( "%GAME%" , InGameName ) ;
}
2014-08-18 13:29:39 -04:00
if ( LineStr . Contains ( "%HEAPSIZE%" ) )
2014-05-29 17:32:36 -04:00
{
2014-08-18 13:29:39 -04:00
LineStr = LineStr . Replace ( "%HEAPSIZE%" , HeapSize . ToString ( ) ) ;
2014-05-29 17:32:36 -04:00
}
2014-03-14 14:13:41 -04:00
if ( LineStr . Contains ( "%CONFIG%" ) )
{
2015-05-18 18:27:24 -04:00
string TempGameName = InGameName ;
2014-06-18 11:36:29 -04:00
if ( IsContentOnly )
2015-05-18 18:27:24 -04:00
TempGameName = "UE4Game" ;
LineStr = LineStr . Replace ( "%CONFIG%" , ( InGameConfiguration ! = "Development" ? ( TempGameName + "-HTML5-" + InGameConfiguration ) : TempGameName ) ) ;
2014-03-14 14:13:41 -04:00
}
if ( LineStr . Contains ( "%UE4CMDLINE%" ) )
{
2014-09-15 10:56:03 -04:00
InArguments = InArguments . Replace ( "\"" , "" ) ;
2014-03-14 14:13:41 -04:00
string [ ] Arguments = InArguments . Split ( ' ' ) ;
2015-02-06 04:29:05 -05:00
string ArgumentString = IsContentOnly ? "'../../../" + InGameName + "/" + InGameName + ".uproject '," : "" ;
2014-08-18 13:29:39 -04:00
for ( int i = 0 ; i < Arguments . Length - 1 ; + + i )
2014-03-14 14:13:41 -04:00
{
ArgumentString + = "'" ;
2015-07-04 18:45:54 -04:00
ArgumentString + = Arguments [ i ] ;
2014-03-14 14:13:41 -04:00
ArgumentString + = "'" ;
ArgumentString + = ",' '," ;
}
if ( Arguments . Length > 0 )
{
ArgumentString + = "'" ;
2014-08-18 13:29:39 -04:00
ArgumentString + = Arguments [ Arguments . Length - 1 ] ;
2014-03-14 14:13:41 -04:00
ArgumentString + = "'" ;
}
LineStr = LineStr . Replace ( "%UE4CMDLINE%" , ArgumentString ) ;
}
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.
}
}
}
2014-10-29 08:01:57 -04:00
public override void GetFilesToDeployOrStage ( ProjectParams Params , DeploymentContext SC )
{
}
2014-07-07 19:15:12 -04:00
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 ) , "Binaries" , "HTML5" ) ;
string FinalDataLocation = Path . Combine ( PackagePath , Params . ShortProjectName ) + ".data" ;
// copy the "Executable" to the archive directory
string GameExe = Path . GetFileNameWithoutExtension ( Params . ProjectGameExeFilename ) ;
if ( Params . ClientConfigsToBuild [ 0 ] . ToString ( ) ! = "Development" )
{
GameExe + = "-HTML5-" + Params . ClientConfigsToBuild [ 0 ] . ToString ( ) ;
}
GameExe + = ".js" ;
// put the HTML file to the package directory
string OutputFile = Path . Combine ( PackagePath , ( Params . ClientConfigsToBuild [ 0 ] . ToString ( ) ! = "Development" ? ( Params . ShortProjectName + "-HTML5-" + Params . ClientConfigsToBuild [ 0 ] . ToString ( ) ) : Params . ShortProjectName ) ) + ".html" ;
2015-06-11 15:29:20 -04:00
// data file
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( FinalDataLocation + ".gz" ) ) ;
// data file js driver
2015-06-04 17:21:16 -04:00
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( FinalDataLocation + ".js.gz" ) ) ;
2015-06-11 15:29:20 -04:00
// main js file
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( GameExe + ".gz" ) ) ;
// memory init file
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( GameExe + ".mem.gz" ) ) ;
// symbols file
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( GameExe + ".symbols.gz" ) ) ;
// utilities
2015-06-04 17:21:16 -04:00
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( "Utility.js.gz" ) ) ;
2015-06-11 15:29:20 -04:00
// landing page.
2014-07-07 19:15:12 -04:00
SC . ArchiveFiles ( PackagePath , Path . GetFileName ( OutputFile ) ) ;
2015-04-08 14:53:36 -04:00
2015-06-04 17:21:16 -04:00
// Archive HTML5 Server and a Readme.
var LaunchHelperPath = CombinePaths ( CmdEnv . LocalRoot , "Engine/Binaries/DotNET/" ) ;
SC . ArchiveFiles ( LaunchHelperPath , "HTML5LaunchHelper.exe" ) ;
SC . ArchiveFiles ( Path . Combine ( CombinePaths ( CmdEnv . LocalRoot , "Engine" ) , "Build" , "HTML5" ) , "Readme.txt" ) ;
if ( HTMLPakAutomation . CanCreateMapPaks ( Params ) )
{
2015-06-11 15:29:20 -04:00
// find all paks.
2015-06-04 17:21:16 -04:00
string [ ] Files = Directory . GetFiles ( Path . Combine ( PackagePath , Params . ShortProjectName ) , "*" , SearchOption . AllDirectories ) ;
foreach ( string PakFile in Files )
{
var DestPak = PakFile . Replace ( PackagePath , "" ) ;
SC . ArchivedFiles . Add ( PakFile , DestPak ) ;
2015-06-11 15:29:20 -04:00
}
2015-06-04 17:21:16 -04:00
}
2015-07-06 19:26:15 -04:00
UploadToS3 ( SC ) ;
2014-07-07 19:15:12 -04:00
}
2014-03-14 14:13:41 -04:00
public override ProcessResult RunClient ( ERunOptions ClientRunFlags , string ClientApp , string ClientCmdLine , ProjectParams Params )
{
2014-10-17 04:21:41 -04:00
// look for browser
2015-07-04 18:45:54 -04:00
string BrowserPath = Params . Device . Replace ( "HTML5@" , "" ) ;
2014-03-14 14:13:41 -04:00
2014-07-21 17:06:23 -04:00
// open the webpage
2015-02-20 04:41:01 -05:00
Int32 ServerPort = 8000 ;
2015-07-04 18:45:54 -04:00
var ConfigCache = new UnrealBuildTool . ConfigCacheIni ( UnrealTargetPlatform . HTML5 , "Engine" , Path . GetDirectoryName ( Params . RawProjectPath ) , CombinePaths ( CmdEnv . LocalRoot , "Engine" ) ) ;
2015-02-20 04:41:01 -05:00
ConfigCache . GetInt32 ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "DeployServerPort" , out ServerPort ) ;
string WorkingDirectory = Path . GetDirectoryName ( ClientApp ) ;
2014-10-17 04:21:41 -04:00
string url = Path . GetFileName ( ClientApp ) + ".html" ;
2014-09-15 10:56:03 -04:00
// Are we running via cook on the fly server?
// find our http url - This is awkward because RunClient doesn't have real information that NFS is running or not.
2014-08-18 13:29:39 -04:00
bool IsCookOnTheFly = false ;
2014-09-24 14:50:15 -04:00
2014-10-17 04:21:41 -04:00
// 9/24/2014 @fixme - All this is convoluted, clean up.
// looks like cookonthefly commandline stopped adding protocol or the port :/ hard coding to DEFAULT_TCP_FILE_SERVING_PORT+1 (DEFAULT_HTTP_FILE_SERVING_PORT)
// This will fail if the NFS server is started with a different port - we need to modify driver .cs script to pass in IP/Port data correctly.
2014-09-24 14:50:15 -04:00
2014-10-17 04:21:41 -04:00
if ( ClientCmdLine . Contains ( "filehostip" ) )
{
IsCookOnTheFly = true ;
url = "http://127.0.0.1:41898/" + url ;
}
2014-07-21 17:06:23 -04:00
2014-10-17 04:21:41 -04:00
if ( IsCookOnTheFly )
{
url + = "?cookonthefly=true" ;
}
else
{
2015-07-05 22:57:28 -04:00
url = String . Format ( "http://localhost:{0}/{1}" , ServerPort , url ) ;
2014-10-17 04:21:41 -04:00
}
2014-09-02 14:36:52 -04:00
2015-02-20 04:41:01 -05:00
// Check HTML5LaunchHelper source for command line args
2015-06-04 17:21:16 -04:00
2015-07-04 18:45:54 -04:00
var LowerBrowserPath = BrowserPath . ToLower ( ) ;
2015-02-20 04:41:01 -05:00
var ProfileDirectory = Path . Combine ( Utils . GetUserSettingDirectory ( ) , "UE4_HTML5" , "user" ) ;
2015-06-04 17:21:16 -04:00
string BrowserCommandline = url ;
2015-02-20 04:41:01 -05:00
if ( LowerBrowserPath . Contains ( "chrome" ) )
{
2015-06-04 17:21:16 -04:00
BrowserCommandline + = " " + String . Format ( "--user-data-dir=\"{0}\" --enable-logging --no-first-run" , Path . Combine ( ProfileDirectory , "chrome" ) ) ;
2015-02-20 04:41:01 -05:00
}
else if ( LowerBrowserPath . Contains ( "firefox" ) )
{
2015-06-04 17:21:16 -04:00
BrowserCommandline + = " " + String . Format ( "-no-remote -profile \"{0}\"" , Path . Combine ( ProfileDirectory , "firefox" ) ) ;
2015-02-20 04:41:01 -05:00
}
2015-06-04 17:21:16 -04:00
2015-07-04 18:45:54 -04:00
string LauncherArguments = string . Format ( " -Browser=\"{0}\" + -BrowserCommandLine=\"{1}\" -ServerPort=\"{2}\" -ServerRoot=\"{3}\" " , new object [ ] { BrowserPath , BrowserCommandline , ServerPort , WorkingDirectory } ) ;
2015-02-20 04:41:01 -05:00
var LaunchHelperPath = CombinePaths ( CmdEnv . LocalRoot , "Engine/Binaries/DotNET/HTML5LaunchHelper.exe" ) ;
2015-06-04 17:21:16 -04:00
ProcessResult BrowserProcess = Run ( LaunchHelperPath , LauncherArguments , null , ClientRunFlags | ERunOptions . NoWaitForExit ) ;
2014-09-15 10:56:03 -04:00
2014-10-17 04:21:41 -04:00
return BrowserProcess ;
2014-03-14 14:13:41 -04:00
}
public override string GetCookPlatform ( bool bDedicatedServer , bool bIsClientOnly , string CookFlavor )
{
return "HTML5" ;
}
2015-07-04 18:45:54 -04:00
public override string GetCookExtraCommandLine ( ProjectParams Params )
{
return HTMLPakAutomation . CanCreateMapPaks ( Params ) ? " -GenerateDependenciesForMaps " : "" ;
}
2015-04-08 14:53:36 -04:00
2015-07-04 18:45:54 -04:00
public override List < string > GetCookExtraMaps ( )
{
var Maps = new List < string > ( ) ;
Maps . Add ( "/Engine/Maps/Entry" ) ;
return Maps ;
}
2015-04-08 14:53:36 -04:00
2014-03-14 14:13:41 -04:00
public override bool DeployPakInternalLowerCaseFilenames ( )
{
return false ;
}
2015-07-04 18:45:54 -04:00
public override PakType RequiresPak ( ProjectParams Params )
{
return HTMLPakAutomation . CanCreateMapPaks ( Params ) ? PakType . Never : PakType . Always ;
}
2014-09-23 20:31:24 -04:00
2015-02-03 05:40:53 -05:00
public override string GetPlatformPakCommandLine ( )
{
return " -compress" ;
}
2014-03-14 14:13:41 -04:00
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 ; } }
2014-08-18 13:29:39 -04:00
public override List < string > GetDebugFileExtentions ( )
{
return new List < string > { ".pdb" } ;
}
2014-03-14 14:13:41 -04:00
#region Hooks
public override void PreBuildAgenda ( UE4Build Build , UE4Build . BuildAgenda Agenda )
{
}
public override List < string > GetExecutableNames ( DeploymentContext SC , bool bIsRun = false )
{
var ExecutableNames = new List < String > ( ) ;
ExecutableNames . Add ( Path . Combine ( SC . ProjectRoot , "Binaries" , "HTML5" , SC . ShortProjectName ) ) ;
return ExecutableNames ;
}
#endregion
2015-07-06 19:26:15 -04:00
#region AMAZON S3
public void UploadToS3 ( DeploymentContext SC )
{
ConfigCacheIni Ini = new ConfigCacheIni ( SC . StageTargetPlatform . PlatformType , "Engine" , Path . GetDirectoryName ( SC . RawProjectPath ) ) ;
bool Upload = false ;
string KeyId = "" ;
string AccessKey = "" ;
string BucketName = "" ;
string FolderName = "" ;
if ( Ini . GetBool ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "UploadToS3" , out Upload ) )
{
if ( ! Upload )
return ;
}
else
{
return ;
}
bool AmazonIdentity = Ini . GetString ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "S3KeyID" , out KeyId ) & &
Ini . GetString ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "S3SecretAccessKey" , out AccessKey ) & &
Ini . GetString ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "S3BucketName" , out BucketName ) & &
Ini . GetString ( "/Script/HTML5PlatformEditor.HTML5TargetSettings" , "S3FolderName" , out FolderName ) ;
if ( ! AmazonIdentity )
{
2015-07-23 14:51:46 -04:00
LogConsole ( "Amazon S3 Incorrectly configured" ) ;
2015-07-06 19:26:15 -04:00
return ;
}
if ( FolderName = = "" )
{
FolderName = SC . ShortProjectName ;
}
List < Task > UploadTasks = new List < Task > ( ) ;
foreach ( KeyValuePair < string , string > Entry in SC . ArchivedFiles )
{
FileInfo Info = new FileInfo ( Entry . Key ) ;
UploadTasks . Add ( Task . Factory . StartNew ( ( ) = > UploadToS3Worker ( Info , KeyId , AccessKey , BucketName , FolderName ) ) ) ;
}
Task . WaitAll ( UploadTasks . ToArray ( ) ) ;
2015-07-23 14:51:46 -04:00
LogConsole ( "Upload Tasks finished." ) ;
2015-07-06 19:26:15 -04:00
}
private static IDictionary < string , string > MimeTypeMapping = new Dictionary < string , string > ( StringComparer . InvariantCultureIgnoreCase )
{
{ ".html" , "text/html" } ,
{ ".js.gz" , "application/x-javascript" } , // upload compressed javascript.
{ ".data.gz" , "appication/octet-stream" }
} ;
public void UploadToS3Worker ( FileInfo Info , string KeyId , string AccessKey , string BucketName , string FolderName )
{
2015-07-23 14:51:46 -04:00
LogConsole ( " Uploading " + Info . Name ) ;
2015-07-06 19:26:15 -04:00
// force upload files even if the timestamps haven't changed.
string TimeStamp = string . Format ( "{0:r}" , DateTime . UtcNow ) ;
string ContentType = "" ;
if ( MimeTypeMapping . ContainsKey ( Info . Extension ) )
{
ContentType = MimeTypeMapping [ Info . Extension ] ;
}
else
{
// default
ContentType = "application/octet-stream" ;
}
// URL to put things.
string URL = "http://" + BucketName + ".s3.amazonaws.com/" + FolderName + "/" + Info . Name ;
HttpWebRequest Request = ( HttpWebRequest ) WebRequest . Create ( URL ) ;
// Upload.
Request . Method = "PUT" ;
Request . Headers [ "x-amz-date" ] = TimeStamp ;
Request . Headers [ "x-amz-acl" ] = "public-read" ; // we probably want to make public read by default.
// set correct content encoding for compressed javascript.
if ( Info . Extension = = ".gz" )
{
Request . Headers [ "Content-Encoding" ] = "gzip" ;
}
Request . ContentType = ContentType ;
Request . ContentLength = Info . Length ;
//http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html
// Find Base64Encoded data.
UTF8Encoding EncodingMethod = new UTF8Encoding ( ) ;
HMACSHA1 Signature = new HMACSHA1 { Key = EncodingMethod . GetBytes ( AccessKey ) } ;
// don't change this string.
string RequestString = "PUT\n\n" + ContentType + "\n\nx-amz-acl:public-read\nx-amz-date:" + TimeStamp + "\n/" + BucketName + "/" + FolderName + "/" + Info . Name ;
Byte [ ] ComputedHash = Signature . ComputeHash ( EncodingMethod . GetBytes ( RequestString ) ) ;
var Base64Encoded = Convert . ToBase64String ( ComputedHash ) ;
// final amz auth header.
Request . Headers [ "Authorization" ] = "AWS " + KeyId + ":" + Base64Encoded ;
try
{
// may fail for really big stuff. YMMV. May need Multi part approach, we will see.
Byte [ ] FileData = File . ReadAllBytes ( Info . FullName ) ;
var requestStream = Request . GetRequestStream ( ) ;
requestStream . Write ( FileData , 0 , FileData . Length ) ;
requestStream . Close ( ) ;
using ( var response = Request . GetResponse ( ) as HttpWebResponse )
{
var reader = new StreamReader ( response . GetResponseStream ( ) ) ;
2015-07-06 20:53:10 -04:00
reader . ReadToEnd ( ) ;
2015-07-06 19:26:15 -04:00
}
}
catch ( Exception ex )
{
2015-07-23 14:51:46 -04:00
LogConsole ( "Could not connect to S3, incorrect S3 Keys? " + ex . ToString ( ) ) ;
2015-07-06 19:26:15 -04:00
throw ex ;
}
2015-07-23 14:51:46 -04:00
LogConsole ( Info . Name + " has been uploaded " ) ;
2015-07-06 19:26:15 -04:00
}
#endregion
2014-03-14 14:13:41 -04:00
}