Пример #1
0
        // Look for any build options in the engine config file.
        public override void ParseProjectSettings()
        {
            base.ParseProjectSettings();

            ConfigCacheIni Ini        = new ConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", UnrealBuildTool.GetUProjectPath());
            string         ServerName = RemoteServerName;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out ServerName) && !String.IsNullOrEmpty(ServerName))
            {
                RemoteServerName = ServerName;
            }

            bool bUseRSync = false;

            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bUseRSync", out bUseRSync))
            {
                bUseRPCUtil = !bUseRSync;
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out RSyncUsername);

                string ConfigKeyPath;
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out ConfigKeyPath))
                {
                    if (File.Exists(ConfigKeyPath))
                    {
                        SSHPrivateKeyOverridePath = ConfigKeyPath;
                    }
                }
            }
        }
        // static creation functions for ini files
        public static ConfigCacheIni CreateConfigCacheIni(UnrealTargetPlatform Platform, string BaseIniName, DirectoryReference ProjectDirectory, DirectoryReference EngineDirectory = null)
        {
            if (EngineDirectory == null)
            {
                EngineDirectory = UnrealBuildTool.EngineDirectory;
            }

            string BaseIniCacheKey = BaseIniName + "_" + Platform.ToString();

            // cache base ini for use as the seed for the rest
            if (!BaseIniCache.ContainsKey(BaseIniCacheKey))
            {
                BaseIniCache.Add(BaseIniCacheKey, new ConfigCacheIni(Platform, BaseIniName, null, EngineDirectory, EngineOnly: true));
            }

            // build the new ini and cache it for later re-use
            ConfigCacheIni BaseCache = BaseIniCache[BaseIniCacheKey];
            string         Key       = GetIniPlatformName(Platform) + BaseIniName + EngineDirectory.FullName + (ProjectDirectory != null ? ProjectDirectory.FullName : "");

            if (!IniCache.ContainsKey(Key))
            {
                IniCache.Add(Key, new ConfigCacheIni(Platform, BaseIniName, ProjectDirectory, EngineDirectory, BaseCache: BaseCache));
            }
            return(IniCache[Key]);
        }
Пример #3
0
        private void WriteEntitlementsFile(string OutputFilename, FileReference ProjectFile)
        {
            // get the settings from the ini file
            // plist replacements
            // @todo tvos: Separate TVOS version?
            ConfigCacheIni Ini        = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirectoryReference.FromFile(ProjectFile));
            bool           bSupported = false;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableCloudKitSupport", out bSupported);

            Directory.CreateDirectory(Path.GetDirectoryName(OutputFilename));
            // we need to have something so Xcode will compile, so we just set the get-task-allow, since we know the value,
            // which is based on distribution or not (true means debuggable)
            StringBuilder Text = new StringBuilder();

            Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            Text.AppendLine("<plist version=\"1.0\">");
            Text.AppendLine("<dict>");
            Text.AppendLine(string.Format("\t<key>get-task-allow</key><{0}/>", /*Config.bForDistribution ? "false" : */ "true"));
            if (bSupported)
            {
                Text.AppendLine("\t<key>com.apple.developer.icloud-container-identifiers</key>");
                Text.AppendLine("\t<array>");
                Text.AppendLine("\t\t<string>iCloud.$(CFBundleIdentifier)</string>");
                Text.AppendLine("\t</array>");
                Text.AppendLine("\t<key>com.apple.developer.icloud-services</key>");
                Text.AppendLine("\t<array>");
                Text.AppendLine("\t\t<string>CloudKit</string>");
                Text.AppendLine("\t</array>");
            }
            Text.AppendLine("</dict>");
            Text.AppendLine("</plist>");
            File.WriteAllText(OutputFilename, Text.ToString());
        }
        public override void AddExtraModules(TargetInfo Target, List <string> PlatformExtraModules)
        {
            string VulkanSDKPath = Environment.GetEnvironmentVariable("VK_SDK_PATH");

            if (!String.IsNullOrEmpty(VulkanSDKPath))
            {
                ConfigCacheIni Ini             = new ConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
                bool           bSupportsVulkan = false;
                Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bSupportsVulkan", out bSupportsVulkan);

                // Make sure we have the .so to compile in the RHI.
                // Currently using static linking. This check will go away when we support dynamic linking.
                string VulkanSoPath = System.IO.Path.Combine(VulkanSDKPath, "Source/lib/libvulkan.so");
                bool   bSoExists    = System.IO.File.Exists(VulkanSoPath);

                if (bSupportsVulkan && bSoExists)
                {
                    PlatformExtraModules.Add("VulkanRHI");
                }
                else
                {
                    if (bSupportsVulkan == false)
                    {
                        Log.TraceInformationOnce("Vulkan SDK is installed, but the project disabled Vulkan (bSupportsVulkan setting in Engine). Disabling Vulkan RHI for Android");
                    }
                    else if (bSoExists == false)
                    {
                        Log.TraceInformationOnce("Vulkan SDK is installed, but [SDK]/Source/lib/libvulkan.so was not found. Disabling Vulkan RHI for Android");
                    }
                }
            }
        }
Пример #5
0
        public override void ResetBuildConfiguration(UnrealTargetPlatform InPlatform, UnrealTargetConfiguration InConfiguration)
        {
            UEBuildConfiguration.bCompileICU = true;

            // Should we enable Windows XP support
            {
                // If it wasnt set as an XML flag, check if it is requested from the commandline.
                if (!SupportWindowsXPIfAvailable)
                {
                    string[] CmdLine = Environment.GetCommandLineArgs();
                    SupportWindowsXPIfAvailable = CmdLine.Contains("-winxp", StringComparer.InvariantCultureIgnoreCase);

                    // ...check if it was supported from a config.
                    if (!SupportWindowsXPIfAvailable)
                    {
                        ConfigCacheIni Ini = new ConfigCacheIni(UnrealTargetPlatform.Win64, "Engine", UnrealBuildTool.GetUProjectPath());
                        string         MinimumOS;
                        if (Ini.GetString("/Script/WindowsTargetPlatform.WindowsTargetSettings", "MinimumOSVersion", out MinimumOS))
                        {
                            if (string.IsNullOrEmpty(MinimumOS) == false)
                            {
                                SupportWindowsXPIfAvailable = MinimumOS == "MSOS_XP";
                            }
                        }
                    }
                }

                // Win32 XP is only supported at this time.
                SupportWindowsXP = SupportWindowsXPIfAvailable && (GetCPPTargetPlatform(InPlatform) == CPPTargetPlatform.Win32);
            }
        }
Пример #6
0
        public static void ParseArchitectures()
        {
            // look in ini settings for what platforms to compile for
            ConfigCacheIni Ini           = new ConfigCacheIni(UnrealTargetPlatform.Android, "Engine", UnrealBuildTool.GetUProjectPath());
            List <string>  ProjectArches = new List <string>();
            bool           bBuild        = true;

            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArmV7", out bBuild) && bBuild)
            {
                ProjectArches.Add("-armv7");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArm64", out bBuild) && bBuild)
            {
                ProjectArches.Add("-arm64");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx86", out bBuild) && bBuild)
            {
                ProjectArches.Add("-x86");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx8664", out bBuild) && bBuild)
            {
                ProjectArches.Add("-x86_64");
            }

            // force armv7 if something went wrong
            if (ProjectArches.Count == 0)
            {
                ProjectArches.Add("-armv7");
            }

            Arches = ProjectArches.ToArray();

            // Parse selected GPU architectures
            List <string> ProjectGPUArches = new List <string>();

            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES31", out bBuild) && bBuild)
            {
                ProjectGPUArches.Add("-es31");
            }
            if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForGL4", out bBuild) && bBuild)
            {
                ProjectGPUArches.Add("-gl4");
            }
            if (ProjectGPUArches.Count == 0 || (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES2", out bBuild) && bBuild))
            {
                ProjectGPUArches.Add("-es2");
            }
            GPUArchitectures = ProjectGPUArches.ToArray();

            List <string> FullArchCombinations = new List <string>();

            foreach (string Arch in Arches)
            {
                foreach (string GPUArch in GPUArchitectures)
                {
                    FullArchCombinations.Add(Arch + GPUArch);
                }
            }
            AllComboNames = FullArchCombinations.ToArray();
        }
Пример #7
0
    public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
    {
        // look for browser
        string BrowserPath = Params.Device.Replace("HTML5@", "");

        // open the webpage
        Int32 ServerPort = 8000;

        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort);
        string WorkingDirectory = Path.GetDirectoryName(ClientApp);
        string url = Path.GetFileName(ClientApp) + ".html";
        // 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.
        bool IsCookOnTheFly = false;

        // 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.

        if (ClientCmdLine.Contains("filehostip"))
        {
            IsCookOnTheFly = true;
            url            = "http://127.0.0.1:41898/" + url;
        }

        if (IsCookOnTheFly)
        {
            url += "?cookonthefly=true";
        }
        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(), "UE4_HTML5", "user");

        string BrowserCommandline = url;

        if (LowerBrowserPath.Contains("chrome"))
        {
            BrowserCommandline += "  " + String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome"));
        }
        else if (LowerBrowserPath.Contains("firefox"))
        {
            BrowserCommandline += "  " + String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox"));
        }

        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");
        ProcessResult BrowserProcess   = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit);

        return(BrowserProcess);
    }
Пример #8
0
        private bool IsVulkanSupportEnabled()
        {
            ConfigCacheIni Ini             = new ConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
            bool           bSupportsVulkan = false;

            Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bSupportsVulkan", out bSupportsVulkan);

            return(bSupportsVulkan);
        }
		public void ParseArchitectures()
		{
			// look in ini settings for what platforms to compile for
			ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
			Arches = new List<string>();
			bool bBuild = true;
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArmV7", out bBuild) && bBuild
				|| UEBuildConfiguration.Architectures.Contains("armv7", StringComparer.OrdinalIgnoreCase))
			{
				Arches.Add("-armv7");
			}
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForArm64", out bBuild) && bBuild
				|| UEBuildConfiguration.Architectures.Contains("arm64", StringComparer.OrdinalIgnoreCase))
			{
				Arches.Add("-arm64");
			}
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx86", out bBuild) && bBuild
				|| UEBuildConfiguration.Architectures.Contains("x86", StringComparer.OrdinalIgnoreCase))
			{
				Arches.Add("-x86");
			}
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForx8664", out bBuild) && bBuild
				|| UEBuildConfiguration.Architectures.Contains("x64", StringComparer.OrdinalIgnoreCase))
			{
				Arches.Add("-x64");
			}

			// force armv7 if something went wrong
			if (Arches.Count == 0)
			{
				Arches.Add("-armv7");
			}

			// Parse selected GPU architectures
			GPUArchitectures = new List<string>();
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForES2", out bBuild) && bBuild
				|| UEBuildConfiguration.GPUArchitectures.Contains("es2", StringComparer.OrdinalIgnoreCase))
			{
				GPUArchitectures.Add("-es2");
			}
			if (Ini.GetBool("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings", "bBuildForESDeferred", out bBuild) && bBuild
				|| UEBuildConfiguration.GPUArchitectures.Contains("esdeferred", StringComparer.OrdinalIgnoreCase))
			{
				GPUArchitectures.Add("-esdeferred");
			}
			if (GPUArchitectures.Count == 0)
			{
				GPUArchitectures.Add("-es2");
			}

			AllComboNames = (from Arch in Arches
							 from GPUArch in GPUArchitectures
							 select Arch + GPUArch).ToList();
		}
    public static bool CanCreateMapPaks(ProjectParams Param)
    {
        bool UseAsyncLevelLoading = false;
        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Param.RawProjectPath), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine"));
        ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "UseAsyncLevelLoading", out UseAsyncLevelLoading);

        if (Param.Run)
            return false; 

        return UseAsyncLevelLoading;
    }
Пример #11
0
        private InstalledPlatformInfo()
        {
            List <string>  InstalledPlatforms;
            ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Unknown, "Engine", (DirectoryReference)null);

            if (Ini.GetArray("InstalledPlatforms", "InstalledPlatformConfigurations", out InstalledPlatforms))
            {
                foreach (string InstalledPlatform in InstalledPlatforms)
                {
                    ParsePlatformConfiguration(InstalledPlatform);
                }
            }
        }
Пример #12
0
    public static bool CanCreateMapPaks(ProjectParams Param)
    {
        bool UseAsyncLevelLoading = false;
        var  ConfigCache          = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Param.RawProjectPath), CommandUtils.CombinePaths(CommandUtils.CmdEnv.LocalRoot, "Engine"));

        ConfigCache.GetBool("/Script/HTML5PlatformEditor.HTML5TargetSettings", "UseAsyncLevelLoading", out UseAsyncLevelLoading);

        if (Param.Run)
        {
            return(false);
        }

        return(UseAsyncLevelLoading);
    }
Пример #13
0
        // Look for any build options in the engine config file.
        public override void ParseProjectSettings()
        {
            base.ParseProjectSettings();

            string EngineIniPath = ProjectFile != null ? ProjectFile.Directory.FullName : null;

            if (String.IsNullOrEmpty(EngineIniPath))
            {
                EngineIniPath = UnrealBuildTool.GetRemoteIniPath();
            }
            ConfigCacheIni Ini        = new ConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", EngineIniPath);
            string         ServerName = RemoteServerName;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RemoteServerName", out ServerName) && !String.IsNullOrEmpty(ServerName))
            {
                RemoteServerName = ServerName;
            }

            bool bUseRSync = false;

            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bUseRSync", out bUseRSync))
            {
                bUseRPCUtil = !bUseRSync;
                string UserName = RSyncUsername;

                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "RSyncUsername", out UserName) && !String.IsNullOrEmpty(UserName))
                {
                    RSyncUsername = UserName;
                }

                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "DeltaCopyInstallPath", out OverrideDeltaCopyInstallPath))
                {
                    if (!string.IsNullOrEmpty(OverrideDeltaCopyInstallPath))
                    {
                        SSHExe   = Path.Combine(OverrideDeltaCopyInstallPath, Path.GetFileName(SSHExe));
                        RSyncExe = Path.Combine(OverrideDeltaCopyInstallPath, Path.GetFileName(RSyncExe));
                    }
                }

                string ConfigKeyPath;
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SSHPrivateKeyOverridePath", out ConfigKeyPath))
                {
                    if (File.Exists(ConfigKeyPath))
                    {
                        SSHPrivateKeyOverridePath = ConfigKeyPath;
                    }
                }
            }
        }
Пример #14
0
 public WindowsPlatformContext(UnrealTargetPlatform InPlatform, FileReference InProjectFile) : base(InPlatform, InProjectFile)
 {
     if (Platform == UnrealTargetPlatform.Win32)
     {
         // ...check if it was supported from a config.
         ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Win64, "Engine", DirectoryReference.FromFile(ProjectFile));
         string         MinimumOS;
         if (Ini.GetString("/Script/WindowsTargetPlatform.WindowsTargetSettings", "MinimumOSVersion", out MinimumOS))
         {
             if (string.IsNullOrEmpty(MinimumOS) == false)
             {
                 SupportWindowsXP = MinimumOS == "MSOS_XP";
             }
         }
     }
 }
Пример #15
0
 static void EnsureConfigCacheIsReady()
 {
     if (ConfigCache == null)
     {
         var    CmdLine     = Environment.GetCommandLineArgs();
         string ProjectPath = UnrealBuildTool.GetUProjectPath();
         if (String.IsNullOrEmpty(ProjectPath))
         {
             ParseProjectPath(CmdLine, out ProjectPath);
         }
         ConfigCache = new ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", ProjectPath);
         // always pick from the Engine the root directory and NOT the staged engine directory.
         // This breaks parse order for user & game config inis so disabled but pulling from the staged directory may still be a problem
         //string IniFile = Path.GetFullPath(Path.GetDirectoryName(UnrealBuildTool.GetUBTPath()) + "/../../") + "Config/HTML5/HTML5Engine.ini";
         //ConfigCache.ParseIniFile(IniFile);
     }
 }
Пример #16
0
    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;

        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath.FullName), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort);
        string WorkingDirectory = Path.GetDirectoryName(ClientApp);
        string url = Path.GetFileName(ClientApp) + ".html";

        if (ClientCmdLine.Contains("filehostip"))
        {
            url += "?cookonthefly=true";
        }
        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"))
        {
            BrowserCommandline += "  " + String.Format("--user-data-dir=\\\"{0}\\\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome"));
        }
        else if (LowerBrowserPath.Contains("firefox"))
        {
            BrowserCommandline += "  " + String.Format("-no-remote -profile \\\"{0}\\\"", Path.Combine(ProfileDirectory, "firefox"));
        }

        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);
    }
Пример #17
0
        public LinuxPlatformContext(FileReference InProjectFile) : base(UnrealTargetPlatform.Linux, InProjectFile)
        {
            // read settings from the config
            string EngineIniPath = ProjectFile != null ? ProjectFile.Directory.FullName : null;

            if (String.IsNullOrEmpty(EngineIniPath))
            {
                // If the project file hasn't been specified, try to get the path from -remoteini command line param
                EngineIniPath = UnrealBuildTool.GetRemoteIniPath();
            }
            DirectoryReference EngineIniDir = !String.IsNullOrEmpty(EngineIniPath) ? new DirectoryReference(EngineIniPath) : null;

            ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Linux, "Engine", EngineIniDir);

            string LinuxArchitectureString;

            if (Ini.GetString("/Script/LinuxTargetPlatform.LinuxTargetSettings", "TargetArchitecture", out LinuxArchitectureString))
            {
                LinuxArchitecture Architecture;
                if (Enum.TryParse(LinuxArchitectureString, out Architecture))
                {
                    switch (Architecture)
                    {
                    default:
                        System.Console.WriteLine("Architecture enum value {0} does not map to a valid triplet.", Architecture);
                        break;

                    case LinuxArchitecture.X86_64UnknownLinuxGnu:
                        ActiveArchitecture = "x86_64-unknown-linux-gnu";
                        break;

                    case LinuxArchitecture.ArmUnknownLinuxGnueabihf:
                        ActiveArchitecture = "arm-unknown-linux-gnueabihf";
                        break;

                    case LinuxArchitecture.AArch64UnknownLinuxGnueabi:
                        ActiveArchitecture = "aarch64-unknown-linux-gnueabi";
                        break;
                    }
                }
            }
        }
		public string GetNdkApiLevel()
		{
			// ask the .ini system for what version to use
			ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Android, "Engine", DirectoryReference.FromFile(ProjectFile));
			string NDKLevel;
			Ini.GetString("/Script/AndroidPlatformEditor.AndroidSDKSettings", "NDKAPILevel", out NDKLevel);

			if (NDKLevel == "latest")
			{
				// get a list of NDK platforms
				string PlatformsDir = Environment.ExpandEnvironmentVariables("%NDKROOT%/platforms");
				if (!Directory.Exists(PlatformsDir))
				{
					throw new BuildException("No platforms found in {0}", PlatformsDir);
				}

				// return the largest of them
				NDKLevel = GetLargestApiLevel(Directory.GetDirectories(PlatformsDir));
			}

			return NDKLevel;
		}
Пример #19
0
        /// <summary>
        /// Setup the target environment for building
        /// </summary>
        /// <param name="InBuildTarget"> The target being built</param>
        public override void SetUpEnvironment(UEBuildTarget InBuildTarget)
        {
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_IOS=1");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("PLATFORM_APPLE=1");

            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_TTS=0");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_SPEECH_RECOGNITION=0");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_DATABASE_SUPPORT=0");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_EDITOR=0");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("USE_NULL_RHI=0");
            InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("REQUIRES_ALIGNED_INT_ACCESS");

            ConfigCacheIni Ini = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirectoryReference.FromFile(ProjectFile));

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableRemoteNotificationsSupport", out bNotificationsEnabled);
            if (bNotificationsEnabled)
            {
                InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("NOTIFICATIONS_ENABLED");
            }

            if (GetActiveArchitecture() == "-simulator")
            {
                InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("WITH_SIMULATOR=1");
            }

            // we assume now we are building with IOS8 or later
            if (UEBuildConfiguration.bCompileAgainstEngine)
            {
                InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("HAS_METAL=1");
                InBuildTarget.ExtraModuleNames.Add("MetalRHI");
            }
            else
            {
                InBuildTarget.GlobalCompileEnvironment.Config.Definitions.Add("HAS_METAL=0");
            }

            InBuildTarget.GlobalLinkEnvironment.Config.AdditionalFrameworks.Add(new UEBuildFramework("GameKit"));
            InBuildTarget.GlobalLinkEnvironment.Config.AdditionalFrameworks.Add(new UEBuildFramework("StoreKit"));
        }
Пример #20
0
        public static string EmscriptenSDKPath()
        {
            var ConfigCache = new ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", UnrealBuildTool.GetUProjectPath());
            // always pick from the Engine the root directory and NOT the staged engine directory.
            string IniFile = Path.GetFullPath(Path.GetDirectoryName(UnrealBuildTool.GetUBTPath()) + "/../../") + "Config/HTML5/HTML5Engine.ini";

            ConfigCache.ParseIniFile(IniFile);

            string PlatformName = "";

            if (!Utils.IsRunningOnMono)
            {
                PlatformName = "Windows";
            }
            else
            {
                PlatformName = "Mac";
            }
            string EMCCPath;
            bool   ok = ConfigCache.GetString("HTML5SDKPaths", PlatformName, out EMCCPath);

            if (ok && System.IO.Directory.Exists(EMCCPath))
            {
                return(EMCCPath);
            }

            // try to find SDK Location from env.
            if (Environment.GetEnvironmentVariable("EMSCRIPTEN") != null &&
                System.IO.Directory.Exists(Environment.GetEnvironmentVariable("EMSCRIPTEN"))
                )
            {
                return(Environment.GetEnvironmentVariable("EMSCRIPTEN"));
            }

            return("");
        }
Пример #21
0
        private void SetupXPSupportFromConfiguration()
        {
            string[] CmdLine = Environment.GetCommandLineArgs();

            bool SupportWindowsXPIfAvailable = false;

            SupportWindowsXPIfAvailable = CmdLine.Contains("-winxp", StringComparer.InvariantCultureIgnoreCase);

            // ...check if it was supported from a config.
            if (!SupportWindowsXPIfAvailable)
            {
                ConfigCacheIni Ini = new ConfigCacheIni(UnrealTargetPlatform.Win64, "Engine", UnrealBuildTool.GetUProjectPath());
                string         MinimumOS;
                if (Ini.GetString("/Script/WindowsTargetPlatform.WindowsTargetSettings", "MinimumOSVersion", out MinimumOS))
                {
                    if (string.IsNullOrEmpty(MinimumOS) == false)
                    {
                        SupportWindowsXPIfAvailable = MinimumOS == "MSOS_XP";
                    }
                }
            }

            SupportWindowsXP = SupportWindowsXPIfAvailable;
        }
Пример #22
0
    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";

        // 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.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal);
        File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal);

        // put the HTML file to the package directory
        string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "Game.html.template");
        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;
        var   ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        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();
    }
        private void Init(UnrealTargetPlatform Platform, string BaseIniName, DirectoryReference ProjectDirectory, DirectoryReference EngineDirectory, bool EngineOnly = false, ConfigCacheIni BaseCache = null)
        {
            InitCommon();
            bIsMergingConfigs = true;
            if (EngineDirectory == null)
            {
                EngineDirectory = UnrealBuildTool.EngineDirectory;
            }

            if (BaseCache != null)
            {
                foreach (KeyValuePair <string, IniSection> Pair in BaseCache.Sections)
                {
                    Sections.Add(Pair.Key, new IniSection(Pair.Value));
                }
            }
            if (EngineOnly)
            {
                foreach (FileReference IniFileName in EnumerateEngineIniFileNames(EngineDirectory, BaseIniName, Platform))
                {
                    if (IniFileName.Exists())
                    {
                        ParseIniFile(IniFileName);
                    }
                }
            }
            else
            {
                foreach (FileReference IniFileName in EnumerateCrossPlatformIniFileNames(ProjectDirectory, EngineDirectory, Platform, BaseIniName, BaseCache != null))
                {
                    if (IniFileName.Exists())
                    {
                        ParseIniFile(IniFileName);
                    }
                }
            }
        }
Пример #24
0
        /**
         * Check for the default configuration
         *
         * return true if the project uses the default build config
         */
        public override bool HasDefaultBuildConfig(UnrealTargetPlatform Platform, string ProjectPath)
        {
            ConfigCacheIni ProjIni    = new ConfigCacheIni(Platform, "Engine", ProjectPath);
            ConfigCacheIni DefaultIni = new ConfigCacheIni(Platform, "Engine", null);

            string DefaultMinVersion = "IOS_6";
            string ProjectMinVersion = DefaultMinVersion;

            ProjIni.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out ProjectMinVersion);
            DefaultIni.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out DefaultMinVersion);
            if (DefaultMinVersion != ProjectMinVersion)
            {
                return(false);
            }

            bool bDefaultBuild = true;
            bool bProjectBuild = true;

            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArm64", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArm64", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7S", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7S", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArm64", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArm64", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7S", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7S", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }

            // determine if we need to generate the dsym
            ProjIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGenerateSYMFile", out bProjectBuild);
            DefaultIni.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGenerateSYMFile", out bDefaultBuild);
            if (bDefaultBuild != bProjectBuild)
            {
                return(false);
            }

            return(base.HasDefaultBuildConfig(Platform, ProjectPath));
        }
    public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
    {
        // look for browser
        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        string DeviceSection;

        if ( Utils.IsRunningOnMono )
        {
            DeviceSection = "HTML5DevicesMac";
        }
        else
        {
            DeviceSection = "HTML5DevicesWindows";
        }

        string browserPath;
        string DeviceName = Params.Device.Split('@')[1];
        DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on "));
        bool ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath);

        if (!ok)
            throw new System.Exception ("Incorrect browser configuration in HTML5Engine.ini ");

        // open the webpage
        string directory = Path.GetDirectoryName(ClientApp);
        string url = Path.GetFileName(ClientApp) +".html";
        // 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.
        bool IsCookOnTheFly = false;

        // 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.

        if (ClientCmdLine.Contains("filehostip"))
        {
            IsCookOnTheFly = true;
            url = "http://127.0.0.1:41898/" + url;
        }

        if (IsCookOnTheFly)
        {
            url += "?cookonthefly=true";
        }
        else
        {
            var EmscriptenSettings = ReadEmscriptenSettings();
            url = "http://127.0.0.1:8000/" + url;
            // this will be killed UBT instances dies.
            string input = String.Format(" -m SimpleHTTPServer 8000");

            string PythonName = null;
            // Check the .emscripten file for a possible python path
            if (EmscriptenSettings.ContainsKey("PYTHON"))
            {
                PythonName = EmscriptenSettings["PYTHON"];
                Log("Found python path {0} in emscripten file", PythonName);
            }
            // The AutoSDK defines this env var as part of its install. See setup.bat/unsetup.bat
            // If it's missing then just assume that python lives on the path
            if (PythonName == null && Environment.GetEnvironmentVariable("PYTHON") != null)
            {
                PythonName = Environment.GetEnvironmentVariable("PYTHON");
                Log("Found python path {0} in PYTHON Environment Variable", PythonName);
            }

            // Check if the exe exists
            if (!System.IO.File.Exists(PythonName))
            {
                Log("Either no python path can be found or it doesn't exist. Using python on PATH");
                PythonName = Utils.IsRunningOnMono ? "python" : "python.exe";
            }

            ProcessResult Result = ProcessManager.CreateProcess(PythonName, true, "html5server.log");
            Result.ProcessObject.StartInfo.FileName = PythonName;
            Result.ProcessObject.StartInfo.UseShellExecute = false;
            Result.ProcessObject.StartInfo.RedirectStandardOutput = true;
            Result.ProcessObject.StartInfo.RedirectStandardInput = true;
            Result.ProcessObject.StartInfo.WorkingDirectory = directory;
            Result.ProcessObject.StartInfo.Arguments = input;
            Result.ProcessObject.Start();

            Result.ProcessObject.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs e)
            {
                System.Console.WriteLine(e.Data);
            };

            System.Console.WriteLine("Starting Browser Process");

            // safari specific hack.
            string argument = url;
            if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono)
                argument = "";

            ProcessResult ClientProcess = Run(browserPath, argument, null, ClientRunFlags | ERunOptions.NoWaitForExit);

            ClientProcess.ProcessObject.EnableRaisingEvents = true;
            ClientProcess.ProcessObject.Exited += delegate(System.Object o, System.EventArgs e)
            {
                System.Console.WriteLine("Browser Process Ended - Killing Webserver");
                // send kill.
                Result.ProcessObject.StandardInput.Close();
                Result.ProcessObject.Kill();
            };

            // safari needs a hack.
            // http://superuser.com/questions/689315/run-safari-from-terminal-with-given-url-address-without-open-command

            if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono)
            {
                // ClientProcess.ProcessObject.WaitForInputIdle ();
                Thread.Sleep (2000);
                Process.Start("/usr/bin/osascript"," -e 'tell application \"Safari\" to open location \"" + url + "\"'" );
            }

            return ClientProcess;
        }

        System.Console.WriteLine("Browser Path " + browserPath);
        ProcessResult BrowserProcess = Run(browserPath, url, null, ClientRunFlags | ERunOptions.NoWaitForExit);

        return BrowserProcess;
    }
    public override void Package(ProjectParams Params, DeploymentContext SC, int WorkingCL)
    {
        Log("Package {0}", Params.RawProjectPath);
        var EmscriptenSettings = ReadEmscriptenSettings();

        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";

        // we need to operate in the root
        using (new PushedDirectory(Path.Combine(Params.BaseStageDirectory, "HTML5")))
        {
            string BaseSDKPath = Environment.GetEnvironmentVariable("EMSCRIPTEN");
            string PythonPath = null;

            // Check the .emscripten file for a possible python path
            if (EmscriptenSettings.ContainsKey("PYTHON"))
            {
                PythonPath = EmscriptenSettings["PYTHON"];
                Log("Found python path {0} in emscripten file", PythonPath);
            }
            // The AutoSDK defines this env var as part of its install. See setup.bat/unsetup.bat
            // If it's missing then just assume that python lives on the path
            if (PythonPath == null && Environment.GetEnvironmentVariable("PYTHON") != null)
            {
                PythonPath = Environment.GetEnvironmentVariable("PYTHON");
                Log("Found python path {0} in PYTHON Environment Variable", PythonPath);
            }

            // Check if the exe exists
            if (!System.IO.File.Exists(PythonPath))
            {
                PythonPath = null;
            }

            if (PythonPath == null)
            {
                Log("Either no python path can be found or it doesn't exist. Using python on PATH");
            }

            // make the file_packager command line
            if (Utils.IsRunningOnMono)
            {
                string PackagerPath = BaseSDKPath + "/tools/file_packager.py";
                if (PythonPath == null)
                {
                    string CmdLine = string.Format("-c \" python {0} '{1}' --preload . --js-output='{1}.js' \" ", PackagerPath, FinalDataLocation);
                    RunAndLog(CmdEnv, "/bin/bash", CmdLine);
                }
                else
                {
                    string CmdLine = string.Format("{0} '{1}' --preload . --js-output='{1}.js' ", PackagerPath, FinalDataLocation);
                    RunAndLog(CmdEnv, PythonPath, CmdLine);
                }
            }
            else
            {
                string PackagerPath = "\"" + BaseSDKPath + "\\tools\\file_packager.py\"";
                if (PythonPath == null)
                {
                    string CmdLine = string.Format("/c python {0} \"{1}\" --preload . --js-output=\"{1}.js\"", PackagerPath, FinalDataLocation);
                    RunAndLog(CmdEnv, CommandUtils.CombinePaths(Environment.SystemDirectory, "cmd.exe"), CmdLine);
                }
                else
                {
                    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";
        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.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal);
        File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal);

        // put the HTML file to the package directory
        string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "Game.html.template");
        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;
        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        int ConfigHeapSize;
        if (!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();
    }
Пример #27
0
	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";

		    // 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.SetAttributes(Path.Combine(PackagePath, GameExe), FileAttributes.Normal);
            File.SetAttributes(Path.Combine(PackagePath, GameExe) + ".mem", FileAttributes.Normal);

            // put the HTML file to the package directory
            string TemplateFile = Path.Combine(CombinePaths(CmdEnv.LocalRoot, "Engine"), "Build", "HTML5", "Game.html.template");
            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;
            var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

            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();
	}
Пример #28
0
    public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
    {
        // look for browser
        var           ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));
        bool          ok          = false;
        List <string> Devices;
        string        browserPath = "";
        string        DeviceName  = Params.Device.Split('@')[1];

        DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on "));

        if (ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5SDKSettings", "DeviceMap", out Devices))
        {
            foreach (var Dev in Devices)
            {
                var Matched = Regex.Match(Dev, "\\(DeviceName=\"(.*)\",DevicePath=\\(FilePath=\"(.*)\"\\)\\)", RegexOptions.IgnoreCase);
                if (Matched.Success && Matched.Groups[1].ToString() == DeviceName)
                {
                    browserPath = Matched.Groups[2].ToString();
                    ok          = true;
                    break;
                }
            }
        }

        if (!ok && HTML5SDKInfo.bAllowFallbackSDKSettings)
        {
            string DeviceSection;

            if (Utils.IsRunningOnMono)
            {
                DeviceSection = "HTML5DevicesMac";
            }
            else
            {
                DeviceSection = "HTML5DevicesWindows";
            }

            ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath);
        }

        if (!ok)
        {
            throw new System.Exception("Incorrect browser configuration in HTML5Engine.ini ");
        }

        // open the webpage
        Int32 ServerPort = 8000;

        ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort);
        string WorkingDirectory = Path.GetDirectoryName(ClientApp);
        string url  = Path.GetFileName(ClientApp) + ".html";
        string args = "-m ";
        // 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.
        bool IsCookOnTheFly = false;

        // 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.

        if (ClientCmdLine.Contains("filehostip"))
        {
            IsCookOnTheFly = true;
            url            = "http://127.0.0.1:41898/" + url;
        }

        if (IsCookOnTheFly)
        {
            url += "?cookonthefly=true";
        }
        else
        {
            url   = String.Format("http://127.0.0.1:{0}/{1}", ServerPort, url);
            args += String.Format("-h -s {0} ", ServerPort);
        }

        // Check HTML5LaunchHelper source for command line args
        var LowerBrowserPath = browserPath.ToLower();

        args += String.Format("-b \"{0}\" -p \"{1}\" -w \"{2}\" ", browserPath, HTML5SDKInfo.PythonPath(), WorkingDirectory);
        args += url + " ";
        var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory(), "UE4_HTML5", "user");

        if (LowerBrowserPath.Contains("chrome"))
        {
            args += String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome"));
        }
        else if (LowerBrowserPath.Contains("firefox"))
        {
            args += String.Format("-no-remote -profile \"{0}\" -jsconsole", Path.Combine(ProfileDirectory, "firefox"));
        }
        //else if (browserPath.Contains("Safari")) {}

        var           LaunchHelperPath = CombinePaths(CmdEnv.LocalRoot, "Engine/Binaries/DotNET/HTML5LaunchHelper.exe");
        ProcessResult BrowserProcess   = Run(LaunchHelperPath, args, null, ClientRunFlags | ERunOptions.NoWaitForExit);

        return(BrowserProcess);
    }
	public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
	{
		// look for browser
		var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));
		bool ok = false;
		List<string> Devices;
		string browserPath = "";
		string DeviceName = Params.Device.Split('@')[1];
		DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on "));

		if (ConfigCache.GetArray("/Script/HTML5PlatformEditor.HTML5SDKSettings", "DeviceMap", out Devices))
		{
			foreach (var Dev in Devices)
			{
				var Matched = Regex.Match(Dev, "\\(DeviceName=\"(.*)\",DevicePath=\\(FilePath=\"(.*)\"\\)\\)", RegexOptions.IgnoreCase);
				if (Matched.Success && Matched.Groups[1].ToString() == DeviceName)
				{
					browserPath = Matched.Groups[2].ToString();
					ok = true;
					break;
				}
			}
		}

		if (!ok && HTML5SDKInfo.bAllowFallbackSDKSettings)
		{
			string DeviceSection;

			if (Utils.IsRunningOnMono)
			{
				DeviceSection = "HTML5DevicesMac";
			}
			else
			{
				DeviceSection = "HTML5DevicesWindows";
			}

			ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath);
		}

		if (!ok)
		{
			throw new System.Exception("Incorrect browser configuration in HTML5Engine.ini ");
		}

		// open the webpage
		Int32 ServerPort = 8000;
		ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort);
		string WorkingDirectory = Path.GetDirectoryName(ClientApp);
		string url = Path.GetFileName(ClientApp) +".html";
		// 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.
		bool IsCookOnTheFly = false;

		// 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. 

		if (ClientCmdLine.Contains("filehostip"))
		{
			IsCookOnTheFly = true; 
			url = "http://127.0.0.1:41898/" + url; 
		}

		if (IsCookOnTheFly)
		{
			url += "?cookonthefly=true";
		}
		else
		{
			url = String.Format("http://{2}:{0}/{1}", ServerPort, url, Environment.MachineName);
		}

		// Check HTML5LaunchHelper source for command line args

		var LowerBrowserPath = browserPath.ToLower();
		var ProfileDirectory = Path.Combine(Utils.GetUserSettingDirectory(), "UE4_HTML5", "user");

		string BrowserCommandline = url; 

		if (LowerBrowserPath.Contains("chrome"))
		{
			BrowserCommandline  += "  " + String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome"));
		}
		else if (LowerBrowserPath.Contains("firefox"))
		{
			BrowserCommandline += "  " +  String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox"));
		}

		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");
		ProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit);
	
		return BrowserProcess;

	}
    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();
    }
Пример #31
0
    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();
    }
Пример #32
0
        public override void SetUpProjectEnvironment(UnrealTargetConfiguration Configuration, TargetInfo Target = null)
        {
            if (!bInitializedProject)
            {
                base.SetUpProjectEnvironment(Configuration, Target);

                // update the configuration based on the project file
                // look in ini settings for what platforms to compile for
                ConfigCacheIni Ini        = ConfigCacheIni.CreateConfigCacheIni(Platform, "Engine", DirectoryReference.FromFile(ProjectFile));
                string         MinVersion = "IOS_8";
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
                {
                    switch (MinVersion)
                    {
                    case "IOS_61":
                        Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
                        RunTimeIOSVersion = "8.0";
                        break;

                    case "IOS_7":
                        Log.TraceWarning("IOS 7 is no longer supported in UE4 as 4.14");
                        RunTimeIOSVersion = "8.0";
                        break;

                    case "IOS_8":
                        RunTimeIOSVersion = "8.0";
                        break;

                    case "IOS_9":
                        RunTimeIOSVersion = "9.0";
                        break;

                    case "IOS_10":
                        RunTimeIOSVersion = "10.0";
                        break;
                    }
                }

                bool biPhoneAllowed = true;
                bool biPadAllowed   = true;
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPhone", out biPhoneAllowed);
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPad", out biPadAllowed);
                if (biPhoneAllowed && biPadAllowed)
                {
                    RunTimeIOSDevices = "1,2";
                }
                else if (biPadAllowed)
                {
                    RunTimeIOSDevices = "2";
                }
                else if (biPhoneAllowed)
                {
                    RunTimeIOSDevices = "1";
                }

                ProjectArches = new List <string>();
                bool bBuild = true;
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArm64", out bBuild) && bBuild)
                {
                    ProjectArches.Add("arm64");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7S", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7s");
                }

                // force armv7 if something went wrong
                if (ProjectArches.Count == 0)
                {
                    ProjectArches.Add("armv7");
                }
                NonShippingArchitectures = ProjectArches[0];
                for (int Index = 1; Index < ProjectArches.Count; ++Index)
                {
                    NonShippingArchitectures += "," + ProjectArches[Index];
                }

                ProjectArches.Clear();
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArm64", out bBuild) && bBuild)
                {
                    ProjectArches.Add("arm64");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7S", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7s");
                }

                // force armv7 if something went wrong
                if (ProjectArches.Count == 0)
                {
                    ProjectArches.Add("armv7");
                    ProjectArches.Add("arm64");
                }
                ShippingArchitectures = ProjectArches[0];
                for (int Index = 1; Index < ProjectArches.Count; ++Index)
                {
                    ShippingArchitectures += "," + ProjectArches[Index];
                }

                // determine if we need to generate the dsym
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGeneratedSYMFile", out BuildConfiguration.bGeneratedSYMFile);
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGeneratedSYMBundle", out BuildConfiguration.bGeneratedSYMBundle);

                // determie if bitcode should be generated for the shipping code
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForBitcode", out bShipForBitcode);

                // @todo tvos: We probably want to handle TVOS versions here
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalLinkerFlags", out AdditionalLinkerFlags);
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalShippingLinkerFlags", out AdditionalShippingLinkerFlags);

                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MobileProvision", out MobileProvision);
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SigningCertificate", out SigningCertificate);

                // bundle identifier
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

                bInitializedProject = true;
            }

            ProvisionData Data     = new ProvisionData();
            string        BundleId = BundleIdentifier.Replace("[PROJECT_NAME]", ((ProjectFile != null) ? ProjectFile.GetFileNameWithoutAnyExtensions() : "UE4Game")).Replace("_", "");
            bool          bIsTVOS  = GetCodesignPlatformName() == "appletvos";

            if (!ProvisionCache.ContainsKey(BundleId + " " + bIsTVOS.ToString() + " " + bForDistribtion.ToString()))
            {
                Certificate = SigningCertificate;
                Provision   = MobileProvision;
                if (!string.IsNullOrEmpty(SigningCertificate))
                {
                    // verify the certificate
                    Process IPPProcess = new Process();
                    if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
                    {
                        string IPPCmd = "\"" + UnrealBuildTool.EngineDirectory + "/Binaries/DotNET/IOS/IPhonePackager.exe\" certificates " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + BundleId + (bForDistribtion ? " -distribution" : "");
                        IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString();
                        IPPProcess.StartInfo.FileName         = UnrealBuildTool.EngineDirectory + "/Build/BatchFiles/Mac/RunMono.sh";
                        IPPProcess.StartInfo.Arguments        = IPPCmd;
                        IPPProcess.OutputDataReceived        += new DataReceivedEventHandler(IPPDataReceivedHandler);
                        IPPProcess.ErrorDataReceived         += new DataReceivedEventHandler(IPPDataReceivedHandler);
                    }
                    else
                    {
                        string IPPCmd = "certificates " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + BundleId + (bForDistribtion ? " -distribution" : "");
                        IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString();
                        IPPProcess.StartInfo.FileName         = UnrealBuildTool.EngineDirectory + "\\Binaries\\DotNET\\IOS\\IPhonePackager.exe";
                        IPPProcess.StartInfo.Arguments        = IPPCmd;
                        IPPProcess.OutputDataReceived        += new DataReceivedEventHandler(IPPDataReceivedHandler);
                        IPPProcess.ErrorDataReceived         += new DataReceivedEventHandler(IPPDataReceivedHandler);
                    }
                    Utils.RunLocalProcess(IPPProcess);
                }
                else
                {
                    Certificate      = bForDistribtion ? "iPhone Distribution" : "iPhone Developer";
                    bHaveCertificate = true;
                }

                if (string.IsNullOrEmpty(MobileProvision) || // no provision specified
                    !File.Exists((BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac ? (Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/") : (Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/Apple Computer/MobileDevice/Provisioning Profiles/")) + MobileProvision) || // file doesn't exist
                    !bHaveCertificate)    // certificate doesn't exist
                {
                    Certificate = "";
                    Provision   = "";
                    Log.TraceLog("Provision not specified or not found for " + ((ProjectFile != null) ? ProjectFile.GetFileNameWithoutAnyExtensions() : "UE4Game") + ", searching for compatible match...");
                    Process IPPProcess = new Process();
                    if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
                    {
                        string IPPCmd = "\"" + UnrealBuildTool.EngineDirectory + "/Binaries/DotNET/IOS/IPhonePackager.exe\" signing_match " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + BundleId + (bIsTVOS ? " -tvos" : "") + (bForDistribtion ? " -distribution" : "");
                        IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString();
                        IPPProcess.StartInfo.FileName         = UnrealBuildTool.EngineDirectory + "/Build/BatchFiles/Mac/RunMono.sh";
                        IPPProcess.StartInfo.Arguments        = IPPCmd;
                        IPPProcess.OutputDataReceived        += new DataReceivedEventHandler(IPPDataReceivedHandler);
                        IPPProcess.ErrorDataReceived         += new DataReceivedEventHandler(IPPDataReceivedHandler);
                    }
                    else
                    {
                        string IPPCmd = "signing_match " + ((ProjectFile != null) ? ("\"" + ProjectFile.ToString() + "\"") : "Engine") + " -bundlename " + BundleId + (bIsTVOS ? " -tvos" : "") + (bForDistribtion ? " -distribution" : "");
                        IPPProcess.StartInfo.WorkingDirectory = UnrealBuildTool.EngineDirectory.ToString();
                        IPPProcess.StartInfo.FileName         = UnrealBuildTool.EngineDirectory + "\\Binaries\\DotNET\\IOS\\IPhonePackager.exe";
                        IPPProcess.StartInfo.Arguments        = IPPCmd;
                        IPPProcess.OutputDataReceived        += new DataReceivedEventHandler(IPPDataReceivedHandler);
                        IPPProcess.ErrorDataReceived         += new DataReceivedEventHandler(IPPDataReceivedHandler);
                    }
                    Utils.RunLocalProcess(IPPProcess);
                    Log.TraceLog("Provision found for " + ((ProjectFile != null) ? ProjectFile.GetFileNameWithoutAnyExtensions() : "UE4Game") + ", Provision: " + Provision + " Certificate: " + Certificate);
                }
                // add to the dictionary
                Data.MobileProvision = Provision;
                Data.Certificate     = Certificate.Replace("\"", "");

                // read the provision to get the UUID
                string filename = (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac ? (Environment.GetEnvironmentVariable("HOME") + "/Library/MobileDevice/Provisioning Profiles/") : (Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "/Apple Computer/MobileDevice/Provisioning Profiles/")) + Data.MobileProvision;
                if (File.Exists(filename))
                {
                    string AllText = File.ReadAllText(filename);
                    int    idx     = AllText.IndexOf("<key>UUID</key>");
                    if (idx > 0)
                    {
                        idx = AllText.IndexOf("<string>", idx);
                        if (idx > 0)
                        {
                            idx      += "<string>".Length;
                            Data.UUID = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx);
                        }
                    }
                    idx = AllText.IndexOf("<key>com.apple.developer.team-identifier</key>");
                    if (idx > 0)
                    {
                        idx = AllText.IndexOf("<string>", idx);
                        if (idx > 0)
                        {
                            idx          += "<string>".Length;
                            Data.TeamUUID = AllText.Substring(idx, AllText.IndexOf("</string>", idx) - idx);
                        }
                    }
                }
                else
                {
                    Log.TraceLog("No matching provision file was discovered. Please ensure you have a compatible provision installed.");
                }
                ProvisionCache.Add(BundleId + " " + bIsTVOS.ToString() + " " + bForDistribtion.ToString(), Data);
            }
            else
            {
                Data = ProvisionCache[BundleId + " " + bIsTVOS.ToString() + " " + bForDistribtion.ToString()];
            }
            MobileProvision     = Data.MobileProvision;
            SigningCertificate  = Data.Certificate;
            MobileProvisionUUID = Data.UUID;
            TeamUUID            = Data.TeamUUID;
        }
Пример #33
0
	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();
	}
Пример #34
0
        /// <summary>
        /// checks if the sdk is installed or has been synced
        /// </summary>
        /// <returns></returns>
        private bool HasAnySDK()
        {
            string NDKPath = Environment.GetEnvironmentVariable("NDKROOT");

            {
                var configCacheIni = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.Unknown, "Engine", (DirectoryReference)null);
                var AndroidEnv     = new Dictionary <string, string>();

                Dictionary <string, string> EnvVarNames = new Dictionary <string, string> {
                    { "ANDROID_HOME", "SDKPath" },
                    { "NDKROOT", "NDKPath" },
                    { "ANT_HOME", "ANTPath" },
                    { "JAVA_HOME", "JavaPath" }
                };

                string path;
                foreach (var kvp in EnvVarNames)
                {
                    if (configCacheIni.GetPath("/Script/AndroidPlatformEditor.AndroidSDKSettings", kvp.Value, out path) && !string.IsNullOrEmpty(path))
                    {
                        AndroidEnv.Add(kvp.Key, path);
                    }
                    else
                    {
                        var envValue = Environment.GetEnvironmentVariable(kvp.Key);
                        if (!String.IsNullOrEmpty(envValue))
                        {
                            AndroidEnv.Add(kvp.Key, envValue);
                        }
                    }
                }

                // If we are on Mono and we are still missing a key then go and find it from the .bash_profile
                if (Utils.IsRunningOnMono && !EnvVarNames.All(s => AndroidEnv.ContainsKey(s.Key)))
                {
                    string BashProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".bash_profile");
                    if (!File.Exists(BashProfilePath))
                    {
                        // Try .bashrc if didn't fine .bash_profile
                        BashProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".bashrc");
                    }
                    if (File.Exists(BashProfilePath))
                    {
                        string[] BashProfileContents = File.ReadAllLines(BashProfilePath);

                        // Walk backwards so we keep the last export setting instead of the first
                        for (int LineIndex = BashProfileContents.Length - 1; LineIndex >= 0; --LineIndex)
                        {
                            foreach (var kvp in EnvVarNames)
                            {
                                if (AndroidEnv.ContainsKey(kvp.Key))
                                {
                                    continue;
                                }

                                if (BashProfileContents[LineIndex].StartsWith("export " + kvp.Key + "="))
                                {
                                    string PathVar = BashProfileContents[LineIndex].Split('=')[1].Replace("\"", "");
                                    AndroidEnv.Add(kvp.Key, PathVar);
                                }
                            }
                        }
                    }
                }

                // Set for the process
                foreach (var kvp in AndroidEnv)
                {
                    Environment.SetEnvironmentVariable(kvp.Key, kvp.Value);
                }

                // See if we have an NDK path now...
                AndroidEnv.TryGetValue("NDKROOT", out NDKPath);
            }

            // we don't have an NDKROOT specified
            if (String.IsNullOrEmpty(NDKPath))
            {
                return(false);
            }

            NDKPath = NDKPath.Replace("\"", "");

            // need a supported llvm
            if (!Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm")) &&
                !Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.6")) &&
                !Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.5")) &&
                !Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.3")) &&
                !Directory.Exists(Path.Combine(NDKPath, @"toolchains/llvm-3.1")))
            {
                return(false);
            }
            return(true);
        }
Пример #35
0
        public override void SetUpProjectEnvironment()
        {
            if (!bInitializedProject)
            {
                base.SetUpProjectEnvironment();

                // update the configuration based on the project file
                // look in ini settings for what platforms to compile for
                ConfigCacheIni Ini        = ConfigCacheIni.CreateConfigCacheIni(Platform, "Engine", DirectoryReference.FromFile(ProjectFile));
                string         MinVersion = "IOS_7";
                if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
                {
                    switch (MinVersion)
                    {
                    case "IOS_61":
                        Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
                        RunTimeIOSVersion = "7.0";
                        break;

                    case "IOS_7":
                        RunTimeIOSVersion = "7.0";
                        break;

                    case "IOS_8":
                        RunTimeIOSVersion = "8.0";
                        break;

                    case "IOS_9":
                        RunTimeIOSVersion = "9.0";
                        break;
                    }
                }

                bool biPhoneAllowed = true;
                bool biPadAllowed   = true;
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPhone", out biPhoneAllowed);
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPad", out biPadAllowed);
                if (biPhoneAllowed && biPadAllowed)
                {
                    RunTimeIOSDevices = "1,2";
                }
                else if (biPadAllowed)
                {
                    RunTimeIOSDevices = "2";
                }
                else if (biPhoneAllowed)
                {
                    RunTimeIOSDevices = "1";
                }

                List <string> ProjectArches = new List <string>();
                bool          bBuild        = true;
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArm64", out bBuild) && bBuild)
                {
                    ProjectArches.Add("arm64");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7S", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7s");
                }

                // force armv7 if something went wrong
                if (ProjectArches.Count == 0)
                {
                    ProjectArches.Add("armv7");
                }
                NonShippingArchitectures = ProjectArches[0];
                for (int Index = 1; Index < ProjectArches.Count; ++Index)
                {
                    NonShippingArchitectures += "," + ProjectArches[Index];
                }

                ProjectArches.Clear();
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArm64", out bBuild) && bBuild)
                {
                    ProjectArches.Add("arm64");
                }
                if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7S", out bBuild) && bBuild)
                {
                    ProjectArches.Add("armv7s");
                }

                // force armv7 if something went wrong
                if (ProjectArches.Count == 0)
                {
                    ProjectArches.Add("armv7");
                    ProjectArches.Add("arm64");
                }
                ShippingArchitectures = ProjectArches[0];
                for (int Index = 1; Index < ProjectArches.Count; ++Index)
                {
                    ShippingArchitectures += "," + ProjectArches[Index];
                }

                // determine if we need to generate the dsym
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGeneratedSYMFile", out BuildConfiguration.bGeneratedSYMFile);

                // @todo tvos: We probably want to handle TVOS versions here
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalLinkerFlags", out AdditionalLinkerFlags);
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalShippingLinkerFlags", out AdditionalShippingLinkerFlags);

                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MobileProvision", out MobileProvision);
                Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "SigningCertificate", out SigningCertificate);

                bInitializedProject = true;
            }
        }
Пример #36
0
        public override void SetUpProjectEnvironment(UnrealTargetPlatform InPlatform)
        {
            base.SetUpProjectEnvironment(InPlatform);

            // update the configuration based on the project file
            // look in ini settings for what platforms to compile for
            ConfigCacheIni Ini        = new ConfigCacheIni(InPlatform, "Engine", UnrealBuildTool.GetUProjectPath());
            string         MinVersion = "IOS_6";

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
            {
                switch (MinVersion)
                {
                case "IOS_61":
                    RunTimeIOSVersion = "6.1";
                    break;

                case "IOS_7":
                    RunTimeIOSVersion = "7.0";
                    break;

                case "IOS_8":
                    RunTimeIOSVersion = "8.0";
                    break;
                }
            }

            bool biPhoneAllowed = true;
            bool biPadAllowed   = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPhone", out biPhoneAllowed);
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsIPad", out biPadAllowed);
            if (biPhoneAllowed && biPadAllowed)
            {
                RunTimeIOSDevices = "1,2";
            }
            else if (biPadAllowed)
            {
                RunTimeIOSDevices = "2";
            }
            else if (biPhoneAllowed)
            {
                RunTimeIOSDevices = "1";
            }

            List <string> ProjectArches = new List <string>();
            bool          bBuild        = true;

            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7", out bBuild) && bBuild)
            {
                ProjectArches.Add("armv7");
            }
            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArm64", out bBuild) && bBuild)
            {
                ProjectArches.Add("arm64");
            }
            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDevForArmV7S", out bBuild) && bBuild)
            {
                ProjectArches.Add("armv7s");
            }

            // force armv7 if something went wrong
            if (ProjectArches.Count == 0)
            {
                ProjectArches.Add("armv7");
            }
            NonShippingArchitectures = ProjectArches[0];
            for (int Index = 1; Index < ProjectArches.Count; ++Index)
            {
                NonShippingArchitectures += "," + ProjectArches[Index];
            }

            ProjectArches.Clear();
            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7", out bBuild) && bBuild)
            {
                ProjectArches.Add("armv7");
            }
            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArm64", out bBuild) && bBuild)
            {
                ProjectArches.Add("arm64");
            }
            if (Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bShipForArmV7S", out bBuild) && bBuild)
            {
                ProjectArches.Add("armv7s");
            }

            // force armv7 if something went wrong
            if (ProjectArches.Count == 0)
            {
                ProjectArches.Add("armv7");
                ProjectArches.Add("arm64");
            }
            ShippingArchitectures = ProjectArches[0];
            for (int Index = 1; Index < ProjectArches.Count; ++Index)
            {
                ShippingArchitectures += "," + ProjectArches[Index];
            }

            // determine if we need to generate the dsym
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bGenerateSYMFile", out BuildConfiguration.bGeneratedSYMFile);
        }
Пример #37
0
        public static bool GenerateIOSPList(string ProjectDirectory, bool bIsUE4Game, string GameName, string ProjectName, string InEngineDir, string AppDirectory, UEDeployIOS InThis = null)
        {
            // generate the Info.plist for future use
            string BuildDirectory        = ProjectDirectory + "/Build/IOS";
            bool   bSkipDefaultPNGs      = false;
            string IntermediateDirectory = (bIsUE4Game ? InEngineDir : ProjectDirectory) + "/Intermediate/IOS";
            string PListFile             = IntermediateDirectory + "/" + GameName + "-Info.plist";

            ProjectName = !String.IsNullOrEmpty(ProjectName) ? ProjectName : GameName;
            VersionUtilities.BuildDirectory = BuildDirectory;
            VersionUtilities.GameName       = GameName;

            // read the old file
            string OldPListData = File.Exists(PListFile) ? File.ReadAllText(PListFile) : "";

            // determine if there is a launch.xib
            string LaunchXib = InEngineDir + "/Build/IOS/Resources/Interface/LaunchScreen.xib";

            if (File.Exists(BuildDirectory + "/Resources/Interface/LaunchScreen.xib"))
            {
                LaunchXib = BuildDirectory + "/Resources/Interface/LaunchScreen.xib";
            }

            // get the settings from the ini file
            // plist replacements
            DirectoryReference DirRef = bIsUE4Game ? (!string.IsNullOrEmpty(UnrealBuildTool.GetRemoteIniPath()) ? new DirectoryReference(UnrealBuildTool.GetRemoteIniPath()) : null) : new DirectoryReference(ProjectDirectory);
            ConfigCacheIni     Ini    = ConfigCacheIni.CreateConfigCacheIni(UnrealTargetPlatform.IOS, "Engine", DirRef);

            // orientations
            string SupportedOrientations = "";
            bool   bSupported            = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsPortraitOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortrait</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsUpsideDownOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeLeftOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n" : "";
            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsLandscapeRightOrientation", out bSupported);
            SupportedOrientations += bSupported ? "\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n" : "";

            // bundle display name
            string BundleDisplayName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleDisplayName", out BundleDisplayName);

            // bundle identifier
            string BundleIdentifier;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleIdentifier", out BundleIdentifier);

            // bundle name
            string BundleName;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "BundleName", out BundleName);

            // disable https requirement
            bool bDisableHTTPS;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bDisableHTTPS", out bDisableHTTPS);

            // short version string
            string BundleShortVersion;

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "VersionInfo", out BundleShortVersion);

            // required capabilities
            string RequiredCaps = "";

            if (InThis != null)
            {
                // required capabilities
                RequiredCaps += InThis.IOSPlatformContext.GetRequiredCapabilities();
            }

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsOpenGLES2", out bSupported);
            RequiredCaps += bSupported ? "\t\t<string>opengles-2</string>\n" : "";
            if (!bSupported)
            {
                Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bSupportsMetal", out bSupported);
                RequiredCaps += bSupported ? "\t\t<string>metal</string>\n" : "";
            }

            // minimum iOS version
            string MinVersion;

            if (Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "MinimumiOSVersion", out MinVersion))
            {
                switch (MinVersion)
                {
                case "IOS_61":
                    Log.TraceWarning("IOS 6 is no longer supported in UE4 as 4.11");
                    MinVersion = "7.0";
                    break;

                case "IOS_7":
                    MinVersion = "7.0";
                    break;

                case "IOS_8":
                    MinVersion = "8.0";
                    break;

                case "IOS_9":
                    MinVersion = "9.0";
                    break;
                }
            }
            else
            {
                MinVersion = "7.0";
            }

            // Get Facebook Support details
            bool bEnableFacebookSupport = true;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableFacebookSupport", out bEnableFacebookSupport);

            // Write the Facebook App ID if we need it.
            string FacebookAppID = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "FacebookAppID", out FacebookAppID);
            bEnableFacebookSupport = bEnableFacebookSupport && !string.IsNullOrWhiteSpace(FacebookAppID);

            // Add remote-notifications as background mode
            bool bRemoteNotificationsSupported = false;

            Ini.GetBool("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "bEnableRemoteNotificationsSupport", out bRemoteNotificationsSupported);

            // extra plist data
            string ExtraData = "";

            Ini.GetString("/Script/IOSRuntimeSettings.IOSRuntimeSettings", "AdditionalPlistData", out ExtraData);

            // generate the plist file
            StringBuilder Text = new StringBuilder();

            Text.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Text.AppendLine("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
            Text.AppendLine("<plist version=\"1.0\">");
            Text.AppendLine("<dict>");
            Text.AppendLine("\t<key>CFBundleURLTypes</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleURLName</key>");
            Text.AppendLine("\t\t\t<string>com.Epic.Unreal</string>");
            Text.AppendLine("\t\t\t<key>CFBundleURLSchemes</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine(string.Format("\t\t\t\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            if (bEnableFacebookSupport)
            {
                // This is needed for facebook login to redirect back to the app after completion.
                Text.AppendLine(string.Format("\t\t\t\t<string>fb{0}</string>", FacebookAppID));
            }
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleDevelopmentRegion</key>");
            Text.AppendLine("\t<string>English</string>");
            Text.AppendLine("\t<key>CFBundleDisplayName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleDisplayName, ProjectName)));
            Text.AppendLine("\t<key>CFBundleExecutable</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", bIsUE4Game ? "UE4Game" : GameName));
            Text.AppendLine("\t<key>CFBundleIdentifier</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleIdentifier.Replace("[PROJECT_NAME]", ProjectName).Replace("_", "")));
            Text.AppendLine("\t<key>CFBundleInfoDictionaryVersion</key>");
            Text.AppendLine("\t<string>6.0</string>");
            Text.AppendLine("\t<key>CFBundleName</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", EncodeBundleName(BundleName, ProjectName)));
            Text.AppendLine("\t<key>CFBundlePackageType</key>");
            Text.AppendLine("\t<string>APPL</string>");
            Text.AppendLine("\t<key>CFBundleSignature</key>");
            Text.AppendLine("\t<string>????</string>");
            Text.AppendLine("\t<key>CFBundleVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", VersionUtilities.UpdateBundleVersion(OldPListData)));
            Text.AppendLine("\t<key>CFBundleShortVersionString</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", BundleShortVersion));
            Text.AppendLine("\t<key>LSRequiresIPhoneOS</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIStatusBarHidden</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIRequiresFullScreen</key>");
            Text.AppendLine("\t<true/>");
            Text.AppendLine("\t<key>UIViewControllerBasedStatusBarAppearance</key>");
            Text.AppendLine("\t<false/>");
            Text.AppendLine("\t<key>UISupportedInterfaceOrientations</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in SupportedOrientations.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>UIRequiredDeviceCapabilities</key>");
            Text.AppendLine("\t<array>");
            foreach (string Line in RequiredCaps.Split("\r\n".ToCharArray()))
            {
                if (!string.IsNullOrWhiteSpace(Line))
                {
                    Text.AppendLine(Line);
                }
            }
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>CFBundleIcons</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon57.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            Text.AppendLine("\t<key>CFBundleIcons~ipad</key>");
            Text.AppendLine("\t<dict>");
            Text.AppendLine("\t\t<key>CFBundlePrimaryIcon</key>");
            Text.AppendLine("\t\t<dict>");
            Text.AppendLine("\t\t\t<key>CFBundleIconFiles</key>");
            Text.AppendLine("\t\t\t<array>");
            Text.AppendLine("\t\t\t\t<string>Icon29.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon40.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon50.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon72.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>Icon76.png</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t\t<string>[email protected]</string>");
            Text.AppendLine("\t\t\t</array>");
            Text.AppendLine("\t\t\t<key>UIPrerenderedIcon</key>");
            Text.AppendLine("\t\t\t<true/>");
            Text.AppendLine("\t\t</dict>");
            Text.AppendLine("\t</dict>");
            if (File.Exists(LaunchXib))
            {
                // TODO: compile the xib via remote tool
                Text.AppendLine("\t<key>UILaunchStoryboardName</key>");
                Text.AppendLine("\t<string>LaunchScreen</string>");
                bSkipDefaultPNGs = true;
            }
            else
            {
                // this is a temp way to inject the iphone 6 images without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPhoneConfigs =
                {
                    "Default-IPhone6-Landscape",     "Landscape", "{375, 667}", "8.0",
                    "Default-IPhone6",               "Portrait",  "{375, 667}", "8.0",
                    "Default-IPhone6Plus-Landscape", "Landscape", "{414, 736}", "8.0",
                    "Default-IPhone6Plus-Portrait",  "Portrait",  "{414, 736}", "8.0",
                    "Default",                       "Landscape", "{320, 480}", "7.0",
                    "Default",                       "Portrait",  "{320, 480}", "7.0",
                    "Default-568h",                  "Landscape", "{320, 568}", "7.0",
                    "Default-568h",                  "Portrait",  "{320, 568}", "7.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~iphone</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPhoneConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPhoneConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }

                // close it out
                Text.AppendLine("\t</array>");

                // this is a temp way to inject the iPad Pro without needing to upgrade everyone's plist
                // eventually we want to generate this based on what the user has set in the project settings
                string[] IPadConfigs =
                {
                    "Default-Landscape",      "Landscape", "{768, 1024}",  "7.0",
                    "Default-Portrait",       "Portrait",  "{768, 1024}",  "7.0",
                    "Default-Landscape-1336", "Landscape", "{1024, 1366}", "9.0",
                    "Default-Portrait-1336",  "Portrait",  "{1024, 1366}", "9.0",
                };

                Text.AppendLine("\t<key>UILaunchImages~ipad</key>");
                Text.AppendLine("\t<array>");
                for (int ConfigIndex = 0; ConfigIndex < IPadConfigs.Length; ConfigIndex += 4)
                {
                    Text.AppendLine("\t\t<dict>");
                    Text.AppendLine("\t\t\t<key>UILaunchImageMinimumOSVersion</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 3]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageName</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 0]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageOrientation</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 1]));
                    Text.AppendLine("\t\t\t<key>UILaunchImageSize</key>");
                    Text.AppendLine(string.Format("\t\t\t<string>{0}</string>", IPadConfigs[ConfigIndex + 2]));
                    Text.AppendLine("\t\t</dict>");
                }
                Text.AppendLine("\t</array>");
            }
            Text.AppendLine("\t<key>CFBundleSupportedPlatforms</key>");
            Text.AppendLine("\t<array>");
            Text.AppendLine("\t\t<string>iPhoneOS</string>");
            Text.AppendLine("\t</array>");
            Text.AppendLine("\t<key>MinimumOSVersion</key>");
            Text.AppendLine(string.Format("\t<string>{0}</string>", MinVersion));
            // disable exempt encryption
            Text.AppendLine("\t<key>ITSAppUsesNonExemptEncryption</key>");
            Text.AppendLine("\t<false/>");

            // disable HTTPS requirement
            if (bDisableHTTPS)
            {
                Text.AppendLine("\t<key>NSAppTransportSecurity</key>");
                Text.AppendLine("\t\t<dict>");
                Text.AppendLine("\t\t\t<key>NSAllowsArbitraryLoads</key><true/>");
                Text.AppendLine("\t\t</dict>");
            }

            if (bEnableFacebookSupport)
            {
                Text.AppendLine("\t<key>FacebookAppID</key>");
                Text.AppendLine(string.Format("\t<string>{0}</string>", FacebookAppID));
            }
            if (!string.IsNullOrEmpty(ExtraData))
            {
                ExtraData = ExtraData.Replace("\\n", "\n");
                foreach (string Line in ExtraData.Split("\r\n".ToCharArray()))
                {
                    if (!string.IsNullOrWhiteSpace(Line))
                    {
                        Text.AppendLine("\t" + Line);
                    }
                }
            }

            // Add remote-notifications as background mode
            if (bRemoteNotificationsSupported)
            {
                Text.AppendLine("\t<key>UIBackgroundModes</key>");
                Text.AppendLine("\t<array>");
                Text.AppendLine("\t\t<string>remote-notification</string>");
                Text.AppendLine("\t</array>");
            }

            Text.AppendLine("</dict>");
            Text.AppendLine("</plist>");

            // Create the intermediate directory if needed
            if (!Directory.Exists(IntermediateDirectory))
            {
                Directory.CreateDirectory(IntermediateDirectory);
            }

            if (InThis != null && InThis.UPL != null)
            {
                // Allow UPL to modify the plist here
                XDocument XDoc;
                try
                {
                    XDoc = XDocument.Parse(Text.ToString());
                }
                catch (Exception e)
                {
                    throw new BuildException("plist is invalid {0}\n{1}", e, Text.ToString());
                }

                XDoc.DocumentType.InternalSubset = "";
                InThis.UPL.ProcessPluginNode("None", "iosPListUpdates", "", ref XDoc);
                string result = XDoc.Declaration.ToString() + "\n" + XDoc.ToString().Replace("<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"[]>", "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">");
                File.WriteAllText(PListFile, result);
            }
            else
            {
                File.WriteAllText(PListFile, Text.ToString());
            }

            if (BuildHostPlatform.Current.Platform == UnrealTargetPlatform.Mac)
            {
                if (!Directory.Exists(AppDirectory))
                {
                    Directory.CreateDirectory(AppDirectory);
                }
                File.WriteAllText(AppDirectory + "/Info.plist", Text.ToString());
            }

            return(bSkipDefaultPNGs);
        }
    public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
    {
        // look for browser
        string BrowserPath = Params.Device.Replace("HTML5@", "");

        // open the webpage
        Int32 ServerPort = 8000;

        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));
        ConfigCache.GetInt32("/Script/HTML5PlatformEditor.HTML5TargetSettings", "DeployServerPort", out ServerPort);
        string WorkingDirectory = Path.GetDirectoryName(ClientApp);
        string url = Path.GetFileName(ClientApp) +".html";
        // 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.
        bool IsCookOnTheFly = false;

        // 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.

        if (ClientCmdLine.Contains("filehostip"))
        {
            IsCookOnTheFly = true;
            url = "http://127.0.0.1:41898/" + url;
        }

        if (IsCookOnTheFly)
        {
            url += "?cookonthefly=true";
        }
        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(), "UE4_HTML5", "user");

        string BrowserCommandline = url;

        if (LowerBrowserPath.Contains("chrome"))
        {
            BrowserCommandline  += "  " + String.Format("--user-data-dir=\"{0}\" --enable-logging --no-first-run", Path.Combine(ProfileDirectory, "chrome"));
        }
        else if (LowerBrowserPath.Contains("firefox"))
        {
            BrowserCommandline += "  " +  String.Format("-no-remote -profile \"{0}\"", Path.Combine(ProfileDirectory, "firefox"));
        }

        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");
        ProcessResult BrowserProcess = Run(LaunchHelperPath, LauncherArguments, null, ClientRunFlags | ERunOptions.NoWaitForExit);

        return BrowserProcess;
    }
    public override ProcessResult RunClient(ERunOptions ClientRunFlags, string ClientApp, string ClientCmdLine, ProjectParams Params)
    {
        // look for browser
        var ConfigCache = new UnrealBuildTool.ConfigCacheIni(UnrealTargetPlatform.HTML5, "Engine", Path.GetDirectoryName(Params.RawProjectPath), CombinePaths(CmdEnv.LocalRoot, "Engine"));

        string DeviceSection;

        if ( Utils.IsRunningOnMono )
        {
            DeviceSection = "HTML5DevicesMac";
        }
        else
        {
            DeviceSection = "HTML5DevicesWindows";
        }

        string browserPath;
        string DeviceName = Params.Device.Split('@')[1];
        DeviceName = DeviceName.Substring(0, DeviceName.LastIndexOf(" on "));
        bool ok = ConfigCache.GetString(DeviceSection, DeviceName, out browserPath);

        if (!ok)
            throw new System.Exception ("Incorrect browser configuration in HTML5Engine.ini ");

        // open the webpage
        string directory = Path.GetDirectoryName(ClientApp);
        string url = Path.GetFileName(ClientApp) +".html";
        // 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.
        bool IsCookOnTheFly = false;

        // 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.

        if (ClientCmdLine.Contains("filehostip"))
        {
            IsCookOnTheFly = true;
            url = "http://127.0.0.1:41898/" + url;
        }

        if (IsCookOnTheFly)
        {
            url += "?cookonthefly=true";
        }
        else
        {
            url = "http://127.0.0.1:8000/" + url;
            // this will be killed UBT instances dies.
            string input = String.Format(" -m SimpleHTTPServer 8000");

            string PythonPath = HTML5SDKInfo.PythonPath();
            ProcessResult Result = ProcessManager.CreateProcess(PythonPath, true, "html5server.log");
            Result.ProcessObject.StartInfo.FileName = PythonPath;
            Result.ProcessObject.StartInfo.UseShellExecute = false;
            Result.ProcessObject.StartInfo.RedirectStandardOutput = true;
            Result.ProcessObject.StartInfo.RedirectStandardInput = true;
            Result.ProcessObject.StartInfo.WorkingDirectory = directory;
            Result.ProcessObject.StartInfo.Arguments = input;
            Result.ProcessObject.Start();

            Result.ProcessObject.OutputDataReceived += delegate(object sender, System.Diagnostics.DataReceivedEventArgs e)
            {
                System.Console.WriteLine(e.Data);
            };

            System.Console.WriteLine("Starting Browser Process");

            // safari specific hack.
            string argument = url;
            if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono)
                argument = "";

            // Chrome issue. Firefox may work like this in the future
            bool bBrowserWillSpawnProcess = browserPath.Contains("chrome") || (browserPath.Contains("Google Chrome") && Utils.IsRunningOnMono);

            ProcessResult SubProcess = null;
            ProcessResult ClientProcess = Run(browserPath, argument, null, ClientRunFlags | ERunOptions.NoWaitForExit);
            var ProcStartTime = ClientProcess.ProcessObject.StartTime;
            var ProcName = ClientProcess.ProcessObject.ProcessName;

            ClientProcess.ProcessObject.EnableRaisingEvents = true;
            ClientProcess.ProcessObject.Exited += delegate(System.Object o, System.EventArgs e)
            {
                System.Console.WriteLine("Browser Process Ended (PID={0})", ClientProcess.ProcessObject.Id);
                var bFoundChildProcess = false;
                if (bBrowserWillSpawnProcess)
                {
                    // Chrome spawns a process from the tab it opens and then lets the process we spawned die, so
                    // catch that process and attach to that instead.
                    var CurrentProcesses = Process.GetProcesses();
                    foreach (var item in CurrentProcesses)
                    {
                        if (item.Id != ClientProcess.ProcessObject.Id && item.ProcessName == ProcName && item.StartTime >= ProcStartTime && item.StartTime <= ClientProcess.ProcessObject.ExitTime)
                        {
                            var PID = item.Id;
                            System.Console.WriteLine("Found Process {0} with PID {1} which started at {2}. Waiting on that process to end.", item.ProcessName, item.Id, item.StartTime.ToString());
                            SubProcess = new ProcessResult(item.ProcessName, item, true, item.ProcessName);
                            item.EnableRaisingEvents = true;
                            item.Exited += delegate(System.Object o2, System.EventArgs e2)
                            {
                                System.Console.WriteLine("Browser Process Ended (PID={0}) - Killing Webserver", PID);
                                Result.ProcessObject.StandardInput.Close();
                                Result.ProcessObject.Kill();
                            };
                            bFoundChildProcess = true;
                        }
                    }
                }

                if (!bFoundChildProcess)
                {
                    System.Console.WriteLine("- Killing Webserver PID({0})", Result.ProcessObject.Id);
                    Result.ProcessObject.StandardInput.Close();
                    Result.ProcessObject.Kill();
                }
            };

            if (bBrowserWillSpawnProcess)
            {
                //Wait for it to do so...
                ClientProcess.ProcessObject.WaitForExit();
                ClientProcess = SubProcess;
            }

            // safari needs a hack.
            // http://superuser.com/questions/689315/run-safari-from-terminal-with-given-url-address-without-open-command

            if (browserPath.Contains ("Safari") && Utils.IsRunningOnMono)
            {
                // ClientProcess.ProcessObject.WaitForInputIdle ();
                Thread.Sleep (2000);
                Process.Start("/usr/bin/osascript"," -e 'tell application \"Safari\" to open location \"" + url + "\"'" );
            }

            return ClientProcess;
        }

        System.Console.WriteLine("Browser Path " + browserPath);
        ProcessResult BrowserProcess = Run(browserPath, url, null, ClientRunFlags | ERunOptions.NoWaitForExit);

        return BrowserProcess;
    }