/// <summary> /// Creates the update script on disk. /// </summary> /// <returns>ProcessStartInfo for the update script.</returns> public static ProcessStartInfo CreateUpdateScript() { try { string updateScriptPath = GetUpdateScriptPath(); string updateScriptSource = GetUpdateScriptSource(); File.WriteAllText(updateScriptPath, updateScriptSource); if (ChecksHandler.IsRunningOnUnix()) { UnixHandler.MakeExecutable(updateScriptPath); } ProcessStartInfo updateShellProcess = new ProcessStartInfo { FileName = updateScriptPath, UseShellExecute = false, RedirectStandardOutput = false, WindowStyle = ProcessWindowStyle.Hidden }; return(updateShellProcess); } catch (IOException ioex) { Log.Warn("Failed to create update script (IOException): " + ioex.Message); return(null); } }
/// <summary> /// Attempts to parse an entry from a raw input. /// The input is expected to be in [path]:[hash]:[size] format. /// </summary> /// <returns><c>true</c>, if the input was successfully parse, <c>false</c> otherwise.</returns> /// <param name="rawInput">Raw input.</param> /// <param name="inEntry">The resulting entry.</param> public static bool TryParse(string rawInput, out ManifestEntry inEntry) { //clear out the entry for the new data inEntry = new ManifestEntry(); if (!String.IsNullOrEmpty(rawInput)) { //remove any and all bad characters from the input string, //such as \0, \n and \r. string cleanInput = Utilities.Clean(rawInput); //split the string into its three components - file, hash and size string[] entryElements = cleanInput.Split(':'); //if we have three elements (which we should always have), set them in the provided entry if (entryElements.Length == 3) { //clean the manifest path, converting \ to / on unix and / to \ on Windows. if (ChecksHandler.IsRunningOnUnix()) { inEntry.RelativePath = entryElements[0].Replace("\\", "/"); } else { inEntry.RelativePath = entryElements[0].Replace("/", "\\"); } //set the hash to the second element inEntry.Hash = entryElements[1]; //attempt to parse the final element as a long-type byte count. long parsedSize; if (long.TryParse(entryElements[2], out parsedSize)) { inEntry.Size = parsedSize; return(true); } else { //could not parse the size, parsing has failed. return(false); } } else { //wrong number of raw entry elements, parsing has failed. return(false); } } else { //no input, parsing has failed return(false); } }
/// <summary> /// Gets the name of the embedded update script. /// </summary> private static string GetUpdateScriptPath() { if (ChecksHandler.IsRunningOnUnix()) { return($@"{Path.GetTempPath()}launchpad_update.sh"); } else { return($@"{Path.GetTempPath()}launchpad_update.bat"); } }
/// <summary> /// Gets the name of the embedded update script. /// </summary> private static string GetUpdateScriptResourceName() { if (ChecksHandler.IsRunningOnUnix()) { return("Launchpad.Launcher.Resources.launchpad_update.sh"); } else { return("Launchpad.Launcher.Resources.launchpad_update.bat"); } }
/// <summary> /// Attempts to parse an entry from a raw input. /// The input is expected to be in [path]:[hash]:[size] format. /// </summary> /// <returns><c>true</c>, if the input was successfully parse, <c>false</c> otherwise.</returns> /// <param name="rawInput">Raw input.</param> /// <param name="inEntry">The resulting entry.</param> public static bool TryParse(string rawInput, out ManifestEntry inEntry) { // Clear out the entry for the new data inEntry = new ManifestEntry(); if (string.IsNullOrEmpty(rawInput)) { return(false); } string cleanInput = rawInput.RemoveLineSeparatorsAndNulls(); // Split the string into its three components - file, hash and size string[] entryElements = cleanInput.Split(':'); // If we have three elements (which we should always have), set them in the provided entry if (entryElements.Length != 3) { return(false); } // Sanitize the manifest path, converting \ to / on unix and / to \ on Windows. if (ChecksHandler.IsRunningOnUnix()) { inEntry.RelativePath = entryElements[0].Replace("\\", "/"); } else { inEntry.RelativePath = entryElements[0].Replace("/", "\\"); } // Set the hash to the second element inEntry.Hash = entryElements[1]; // Attempt to parse the final element as a long-type byte count. long parsedSize; if (!long.TryParse(entryElements[2], out parsedSize)) { // Oops. The parsing failed, so this entry is invalid. return(false); } inEntry.Size = parsedSize; return(true); }
/// <summary> /// Creates the update script on disk. /// </summary> /// <returns>ProcessStartInfo for the update script.</returns> public static ProcessStartInfo CreateUpdateScript() { try { //maintain the executable name if it was renamed to something other than 'Launchpad' string assemblyPath = Assembly.GetEntryAssembly().Location; string executableName = Path.GetFileName(assemblyPath); if (ChecksHandler.IsRunningOnUnix()) { //creating a .sh script string scriptPath = String.Format(@"{0}launchpadupdate.sh", Path.GetTempPath()); using (FileStream updateScript = File.Create(scriptPath)) { using (TextWriter tw = new StreamWriter(updateScript)) { string copyCom = String.Format("cp -rf {0} {1}", Path.GetTempPath() + "launchpad/launcher/*", ConfigHandler.GetLocalDir()); string delCom = String.Format("rm -rf {0}", Path.GetTempPath() + "launchpad"); string dirCom = String.Format("cd {0}", ConfigHandler.GetLocalDir()); string launchCom = String.Format(@"nohup ./{0} &", executableName); tw.WriteLine(@"#!/bin/sh"); tw.WriteLine("sleep 5"); tw.WriteLine(copyCom); tw.WriteLine(delCom); tw.WriteLine(dirCom); tw.WriteLine("chmod +x " + executableName); tw.WriteLine(launchCom); } } UnixHandler.MakeExecutable(scriptPath); //Now create some ProcessStartInfo for this script ProcessStartInfo updateShellProcess = new ProcessStartInfo(); updateShellProcess.FileName = scriptPath; updateShellProcess.UseShellExecute = false; updateShellProcess.RedirectStandardOutput = false; updateShellProcess.WindowStyle = ProcessWindowStyle.Hidden; return(updateShellProcess); } else { //creating a .bat script string scriptPath = String.Format(@"{0}launchpadupdate.bat", Path.GetTempPath()); using (FileStream updateScript = File.Create(scriptPath)) { using (TextWriter tw = new StreamWriter(updateScript)) { //write commands to the script //wait three seconds, then copy the new executable tw.WriteLine(String.Format(@"timeout 3 & xcopy /e /s /y ""{0}\launchpad\launcher"" ""{1}"" && rmdir /s /q {0}\launchpad", Path.GetTempPath(), ConfigHandler.GetLocalDir())); //then start the new executable tw.WriteLine(String.Format(@"start {0}", executableName)); tw.Close(); } } ProcessStartInfo updateBatchProcess = new ProcessStartInfo(); updateBatchProcess.FileName = scriptPath; updateBatchProcess.UseShellExecute = true; updateBatchProcess.RedirectStandardOutput = false; updateBatchProcess.WindowStyle = ProcessWindowStyle.Hidden; return(updateBatchProcess); } } catch (IOException ioex) { Console.WriteLine("IOException in CreateUpdateScript(): " + ioex.Message); return(null); } }
/// <summary> /// Launches the game. /// </summary> public void LaunchGame() { //start new process of the game executable try { // Do not move the argument assignment inside the gameStartInfo initializer. // It causes a TargetInvocationException crash through black magic. string gameArguments = string.Join(" ", ConfigHandler.GetGameArguments()); ProcessStartInfo gameStartInfo = new ProcessStartInfo { UseShellExecute = false, FileName = Config.GetGameExecutable(), }; gameStartInfo.Arguments = gameArguments; GameExitArgs.GameName = Config.GetGameName(); Log.Info($"Launching game. \n\tExecutable path: {gameStartInfo.FileName}"); Process gameProcess = new Process { StartInfo = gameStartInfo, EnableRaisingEvents = true }; gameProcess.Exited += delegate { if (gameProcess.ExitCode != 0) { Log.Info($"The game exited with an exit code of {gameProcess.ExitCode}. " + "There may have been issues during runtime, or the game may not have started at all."); } GameExitArgs.ExitCode = gameProcess.ExitCode; OnGameExited(); // Manual disposing gameProcess.Dispose(); }; // Make sure the game executable is flagged as such on Unix if (ChecksHandler.IsRunningOnUnix()) { Process.Start("chmod", $"+x {Config.GetGameExecutable()}"); } gameProcess.Start(); } catch (FileNotFoundException fex) { Log.Warn($"Game launch failed (FileNotFoundException): {fex.Message}"); Log.Warn("If the game executable is there, try overriding the executable name in the configuration file."); GameExitArgs.ExitCode = 2; OnGameLaunchFailed(); } catch (IOException ioex) { Log.Warn($"Game launch failed (IOException): {ioex.Message}"); GameExitArgs.ExitCode = 1; OnGameLaunchFailed(); } }