diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs
index 30fb782..6fda62d 100644
--- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs
+++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs
@@ -322,7 +322,7 @@ public partial class MainForm
else
{
// We know that profiles exist at this point, so we're going to point it to 0 instead so the following code doesn't fail
- if (profIndexString == "null")
+ if ((profIndexString == "null") || String.IsNullOrWhiteSpace(profIndexString))
profIndexString = "0";
// We parse from the settings, and check if profiles got deleted from the last time the launcher has been selected. if yes, we revert the last selection to 0;
diff --git a/AM2RLauncher/AM2RLauncherLib/Core.cs b/AM2RLauncher/AM2RLauncherLib/Core.cs
index 33883b5..17a31c4 100644
--- a/AM2RLauncher/AM2RLauncherLib/Core.cs
+++ b/AM2RLauncher/AM2RLauncherLib/Core.cs
@@ -43,7 +43,7 @@ public static class Core
public static readonly string ModsPath = CrossPlatformOperations.CurrentPath + "/Mods";
///
- /// This is used on Windows only. This sets a window to be in foreground, is used i.e. to fix am2r just being hidden.
+ /// This is used on Windows only. This sets a window to be in foreground. It's used i.e. to fix AM2R just being hidden.
///
/// Pointer to the process you want to have in the foreground.
///
diff --git a/AM2RLauncher/AM2RLauncherLib/HelperMethods.cs b/AM2RLauncher/AM2RLauncherLib/HelperMethods.cs
index 7e0fd29..013af9c 100644
--- a/AM2RLauncher/AM2RLauncherLib/HelperMethods.cs
+++ b/AM2RLauncher/AM2RLauncherLib/HelperMethods.cs
@@ -61,7 +61,6 @@ public static class HelperMethods
}
-
///
/// This is a custom method, that deletes a Directory. The reason this is used, instead of ,
/// is because this one sets the attributes of all files to be deletable, while does not do that on it's own.
@@ -113,6 +112,7 @@ public static class HelperMethods
///
/// The log file to begin the rollover from.
/// The maximum amount of log files to retain. Default is 9, as that's the highest digit.
+ //TODO: double check this method
public static void RecursiveRollover(string logFile, int max = 9)
{
int index = 1;
diff --git a/AM2RLauncher/AM2RLauncherLib/Profile.cs b/AM2RLauncher/AM2RLauncherLib/Profile.cs
index 5a5413e..ee2c6ef 100644
--- a/AM2RLauncher/AM2RLauncherLib/Profile.cs
+++ b/AM2RLauncher/AM2RLauncherLib/Profile.cs
@@ -2,10 +2,13 @@
using log4net;
using System;
using System.Collections.Generic;
+using System.Collections.Specialized;
using System.Diagnostics;
+using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
+using System.Text;
using System.Text.RegularExpressions;
using AM2RLauncherLib.XML;
@@ -150,6 +153,16 @@ public static class Profile
return IsZipAM2R11ReturnCodes.Successful;
}
+ ///
+ /// Checks if the repository has been validly cloned already.
+ ///
+ /// if yes, if not.
+ public static bool IsPatchDataCloned()
+ {
+ // isValid seems to only check for a .git folder, and there are cases where that exists, but not the profile.xml
+ return File.Exists($"{Core.PatchDataPath}/profile.xml") && Repository.IsValid(Core.PatchDataPath);
+ }
+
///
/// Git Pulls patching content from the repository.
///
@@ -634,21 +647,25 @@ public static class Profile
}
///
- /// Runs the Game, works cross platform.
+ /// Runs the game from a given profile.
///
+ /// The that should be run.
+ /// Whether game logging should take place.
+ /// Environment variables with which the game should be launched. Linux only.
public static void RunGame(ProfileXML profile, bool useLogging, string envVars = "")
{
- //TODO: double check this and clean
- // These are used on both windows and linux for game logging
- string savePath = OS.IsWindows ? profile.SaveLocation.Replace("%localappdata%", Environment.GetEnvironmentVariable("LOCALAPPDATA"))
- : profile.SaveLocation.Replace("~", CrossPlatformOperations.Home);
+ // These are used on all OS for game logging
+ string savePath = OS.IsWindows ? Environment.ExpandEnvironmentVariables(profile.SaveLocation)
+ : profile.SaveLocation.Replace("~", CrossPlatformOperations.Home);
DirectoryInfo logDir = new DirectoryInfo($"{savePath}/logs");
- string date = String.Join("-", DateTime.Now.ToString().Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
+ string date = DateTime.Now.ToString("yyyy.MM.dd HH-mm-ss");
+ string logFile = $"{logDir.FullName}/{profile.Name}.txt";
+ string gameDirectory = $"{Core.ProfilesPath}/{profile.Name}";
log.Info($"Launching game profile {profile.Name}.");
if (OS.IsWindows)
{
- // Sets the arguments to empty, or to the profiles save path/logs and create time based logs. Creates the folder if necessary.
+ // Sets the arguments to empty, or to the profiles' logs folder to create time based logs.
string arguments = "";
// Game logging
@@ -656,143 +673,111 @@ public static class Profile
{
log.Info($"Performing logging setup for profile {profile.Name}.");
+ // Check if directory exists, and roll log file over if necessary
if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName);
- if (File.Exists($"{logDir.FullName}/{profile.Name}.txt"))
- HelperMethods.RecursiveRollover($"{logDir.FullName}/{profile.Name}.txt", 5);
-
- StreamWriter stream = File.AppendText($"{logDir.FullName}/{profile.Name}.txt");
-
- stream.WriteLine($"AM2RLauncher {Core.Version} log generated at {date}");
+ if (File.Exists(logFile))
+ HelperMethods.RecursiveRollover(logFile, 5);
+ // Write log header to file
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.Append($"AM2RLauncher {Core.Version} log generated at {date}");
if (OS.IsThisRunningFromWine)
- stream.WriteLine("Using WINE!");
-
- stream.Flush();
+ stringBuilder.Append("Using WINE!");
+ File.WriteAllText(logFile, stringBuilder.ToString());
- stream.Close();
-
- arguments = $"-debugoutput \"{logDir.FullName}/{profile.Name}.txt\" -output \"{logDir.FullName}/{profile.Name}.txt\"";
+ arguments = $"-debugoutput \"{logFile}\" -output \"{logFile}\"";
}
- ProcessStartInfo proc = new ProcessStartInfo();
- proc.WorkingDirectory = $"{Core.ProfilesPath}/{profile.Name}";
- proc.FileName = $"{proc.WorkingDirectory}/AM2R.exe";
- proc.Arguments = arguments;
+ ProcessStartInfo processStartInfo = new ProcessStartInfo
+ {
+ WorkingDirectory = gameDirectory,
+ FileName = $"{gameDirectory}/AM2R.exe",
+ Arguments = arguments
+ };
- log.Info($"CWD of Profile is {proc.WorkingDirectory}");
+ log.Info($"CWD of Profile is {processStartInfo.WorkingDirectory}");
- using Process p = Process.Start(proc);
- Core.SetForegroundWindow(p.MainWindowHandle);
- p.WaitForExit();
+ using Process process = new Process { StartInfo = processStartInfo };
+ process.Start();
+ Core.SetForegroundWindow(process.MainWindowHandle);
+ process.WaitForExit();
}
else if (OS.IsLinux)
{
-
ProcessStartInfo startInfo = new ProcessStartInfo();
log.Info($"User does {(String.IsNullOrWhiteSpace(envVars) ? "not" : "")} have custom environment variables set.");
- //TODO: make this more readable at one day
+ // Set environment variables to startInfo
if (!String.IsNullOrWhiteSpace(envVars))
{
- for (int i = 0; i < envVars.Count(f => f == '='); i++)
+ // All env vars are of format "myVar=myValue foo=bar" etc., so split them by space
+ string[] providedVariables = envVars.Split(' ');
+ foreach (string providedVariable in providedVariables)
{
- // Env var variable
- string variable = envVars.Substring(0, envVars.IndexOf('='));
- envVars = envVars.Replace($"{variable}=", "");
-
- // This thing here is the value parser. Since values are sometimes in quotes, i need to compensate for them.
- int valueSubstringLength;
- if (envVars[0] != '"') // If value is not embedded in "", check if there are spaces left. If yes, get the index of the space, if not that was the last
- {
- if (envVars.IndexOf(' ') >= 0)
- valueSubstringLength = envVars.IndexOf(' ') + 1;
- else
- valueSubstringLength = envVars.Length;
- }
- else // If value is embedded in "", check if there are spaces after the "". if yes, get index of that, if not that was the last
- {
- int secondQuoteIndex = envVars.IndexOf('"', envVars.IndexOf('"') + 1);
- if (envVars.IndexOf(' ', secondQuoteIndex) >= 0)
- valueSubstringLength = envVars.IndexOf(' ', secondQuoteIndex) + 1;
- else
- valueSubstringLength = envVars.Length;
- }
- // Env var value
- string value = envVars.Substring(0, valueSubstringLength);
- envVars = envVars.Substring(value.Length);
+ // After that, we split by '=' where the left is the variable and right is the value
+ // If there is a malformed env var, this will throw.
+ string[] variableAsArray = providedVariable.Split('=');
+ string variable = variableAsArray[0];
+ string value = variableAsArray[1];
log.Info($"Adding user variable \"{variable}\" with value \"{value}\"");
startInfo.EnvironmentVariables[variable] = value;
}
}
- // If we're supposed to log profiles, add events that track those and append them to this var. otherwise keep it null
- string terminalOutput = null;
-
startInfo.UseShellExecute = false;
- startInfo.WorkingDirectory = $"{Core.ProfilesPath}/{profile.Name}";
- startInfo.FileName = $"{startInfo.WorkingDirectory}/AM2R.AppImage";
+ startInfo.WorkingDirectory = gameDirectory;
+ startInfo.FileName = $"{gameDirectory}/AM2R.AppImage";
log.Info($"CWD of Profile is {startInfo.WorkingDirectory}");
- log.Debug("Launching game with following variables: ");
- foreach (System.Collections.DictionaryEntry item in startInfo.EnvironmentVariables)
+ if (log.IsDebugEnabled)
{
- log.Debug($"Key: \"{item.Key}\" Value: \"{item.Value}\"");
+ log.Debug("Launching game with following variables: ");
+ foreach (System.Collections.DictionaryEntry item in startInfo.EnvironmentVariables)
+ log.Debug($"Key: \"{item.Key}\" Value: \"{item.Value}\"");
}
- using (Process p = new Process())
- {
- p.StartInfo = startInfo;
- if (useLogging)
- {
- p.StartInfo.RedirectStandardOutput = true;
- p.OutputDataReceived += (_, e) => { terminalOutput += $"{e.Data}\n"; };
-
- p.StartInfo.RedirectStandardError = true;
- p.ErrorDataReceived += (_, e) => { terminalOutput += $"{e.Data}\n"; };
- }
-
- p.Start();
-
- if (useLogging)
- {
- p.BeginOutputReadLine();
- p.BeginErrorReadLine();
- }
-
- p.WaitForExit();
- }
+ using Process process = new Process();
+ process.StartInfo = startInfo;
- if (terminalOutput != null)
+ // Game logging
+ if (useLogging)
{
- log.Info($"Performed logging setup for profile {profile.Name}.");
+ log.Info($"Performing logging setup for profile {profile.Name}.");
+ // Check if directory exists, and roll log file over if necessary
if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName);
- if (File.Exists($"{logDir.FullName}/{profile.Name}.txt"))
- HelperMethods.RecursiveRollover($"{logDir.FullName}/{profile.Name}.txt", 5);
-
- StreamWriter stream = File.AppendText($"{logDir.FullName}/{profile.Name}.txt");
-
- // Write general info
- stream.WriteLine($"AM2RLauncher {Core.Version} log generated at {date}");
+ if (File.Exists(logFile))
+ HelperMethods.RecursiveRollover(logFile, 5);
- // Write what was in the terminal
- stream.WriteLine(terminalOutput);
+ // Write log header to file
+ File.WriteAllText(logFile, $"AM2RLauncher {Core.Version} log generated at {date}");
- stream.Flush();
+ // Append STDOUT and STDERR to file if we get anything.
+ // Should this maybe be done synchronously?
+ process.StartInfo.RedirectStandardOutput = true;
+ process.OutputDataReceived += (_, e) => { File.AppendAllText(logFile, $"{e.Data}\n"); };
- stream.Close();
+ process.StartInfo.RedirectStandardError = true;
+ process.ErrorDataReceived += (_, e) => { File.AppendAllText(logFile, $"{e.Data}\n"); };
}
+ process.Start();
+ if (useLogging)
+ {
+ process.BeginOutputReadLine();
+ process.BeginErrorReadLine();
+ }
+ process.WaitForExit();
}
else if (OS.IsMac)
{
- // Sets the arguments to only open the game, or append the profiles save path/logs and create time based logs. Creates the folder if necessary.
+ // Sets the arguments to only open, or to the profiles' logs folder to create time based logs.
string arguments = "AM2R.app -W";
// Game logging
@@ -800,47 +785,35 @@ public static class Profile
{
log.Info($"Performing logging setup for profile {profile.Name}.");
+ // Check if directory exists, and roll log file over if necessary
if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName);
- if (File.Exists($"{logDir.FullName}/{profile.Name}.txt"))
- HelperMethods.RecursiveRollover($"{logDir.FullName}/{profile.Name}.txt", 5);
-
- StreamWriter stream = File.AppendText($"{logDir.FullName}/{profile.Name}.txt");
-
- stream.WriteLine($"AM2RLauncher {Core.Version} log generated at {date}");
-
- stream.Flush();
+ if (File.Exists(logFile))
+ HelperMethods.RecursiveRollover(logFile, 5);
- stream.Close();
+ // Write log header to file
+ File.WriteAllText(logFile, $"AM2RLauncher {Core.Version} log generated at {date}");
- arguments += $" --stdout \"{logDir.FullName}/{profile.Name}.txt\" --stderr \"{logDir.FullName}/{profile.Name}.txt\"";
+ arguments += $" --stdout \"{logFile}\" --stderr \"{logFile}\"";
}
- ProcessStartInfo proc = new ProcessStartInfo();
-
- proc.WorkingDirectory = $"{Core.ProfilesPath}/{profile.Name}";
- proc.FileName = "open";
- proc.Arguments = arguments;
+ ProcessStartInfo processStartInfo = new ProcessStartInfo
+ {
+ WorkingDirectory = gameDirectory,
+ FileName = "open",
+ Arguments = arguments
+ };
- log.Info($"CWD of Profile is {proc.WorkingDirectory}");
+ log.Info($"CWD of Profile is {processStartInfo.WorkingDirectory}");
- using Process p = Process.Start(proc);
- p?.WaitForExit();
+ using Process process = new Process { StartInfo = processStartInfo };
+ process.Start();
+ process.WaitForExit();
}
else
log.Error($"{OS.Name} cannot run games!");
log.Info($"Profile {profile.Name} process exited.");
}
-
- ///
- /// Checks if the repository has been validly cloned already.
- ///
- /// if yes, if not.
- public static bool IsPatchDataCloned()
- {
- // isValid seems to only check for a .git folder, and there are cases where that exists, but not the profile.xml
- return File.Exists($"{Core.PatchDataPath}/profile.xml") && Repository.IsValid(Core.PatchDataPath);
- }
}
\ No newline at end of file