Some cleanup

pull/32/head
Miepee 5 years ago
parent 398a44e92d
commit 8f6ef8212c

@ -9,12 +9,12 @@ namespace AM2RLauncher.Gtk;
/// <summary> /// <summary>
/// The main class for the GTK project. /// The main class for the GTK project.
/// </summary> /// </summary>
static class MainClass internal static class MainClass
{ {
/// <summary> /// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions. /// The logger for <see cref="MainForm"/>, used to write any caught exceptions.
/// </summary> /// </summary>
private static readonly ILog Log = LogManager.GetLogger(typeof(MainForm)); private static readonly ILog log = LogManager.GetLogger(typeof(MainForm));
/// <summary> /// <summary>
/// The main method for the GTK project. /// The main method for the GTK project.
/// </summary> /// </summary>
@ -36,14 +36,14 @@ static class MainClass
try try
{ {
Application GTKLauncher = new Application(Eto.Platforms.Gtk); Application gtkLauncher = new Application(Eto.Platforms.Gtk);
LauncherUpdater.Main(); LauncherUpdater.Main();
GTKLauncher.UnhandledException += GTKLauncher_UnhandledException; gtkLauncher.UnhandledException += GTKLauncher_UnhandledException;
GTKLauncher.Run(new MainForm()); gtkLauncher.Run(new MainForm());
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace);
Console.WriteLine(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace); Console.WriteLine(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace);
Console.WriteLine("Check the logs at " + launcherDataPath + " for more info!"); Console.WriteLine("Check the logs at " + launcherDataPath + " for more info!");
} }
@ -54,7 +54,7 @@ static class MainClass
/// </summary> /// </summary>
private static void GTKLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e) private static void GTKLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject);
Application.Instance.Invoke(() => Application.Instance.Invoke(() =>
{ {
MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "GTK", MessageBoxType.Error); MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "GTK", MessageBoxType.Error);
@ -101,4 +101,3 @@ static class MainClass
return Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); return Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
} }
} }

@ -2,6 +2,7 @@
using log4net; using log4net;
using log4net.Config; using log4net.Config;
using System; using System;
using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
namespace AM2RLauncher.Mac; namespace AM2RLauncher.Mac;
@ -9,12 +10,12 @@ namespace AM2RLauncher.Mac;
/// <summary> /// <summary>
/// The main class for the Mac project. /// The main class for the Mac project.
/// </summary> /// </summary>
static class MainClass internal static class MainClass
{ {
/// <summary> /// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions. /// The logger for <see cref="MainForm"/>, used to write any caught exceptions.
/// </summary> /// </summary>
private static readonly ILog Log = LogManager.GetLogger(typeof(MainForm)); private static readonly ILog log = LogManager.GetLogger(typeof(MainForm));
/// <summary> /// <summary>
/// The main method for the Mac project. /// The main method for the Mac project.
@ -44,7 +45,7 @@ static class MainClass
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace);
Console.WriteLine(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace); Console.WriteLine(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace);
Console.WriteLine("Check the logs at " + launcherDataPath + " for more info!"); Console.WriteLine("Check the logs at " + launcherDataPath + " for more info!");
} }
@ -55,7 +56,7 @@ static class MainClass
/// </summary> /// </summary>
private static void MacLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e) private static void MacLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject);
Application.Instance.Invoke(() => Application.Instance.Invoke(() =>
{ {
MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "Mac", MessageBoxType.Error); MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "Mac", MessageBoxType.Error);
@ -63,8 +64,23 @@ static class MainClass
} }
// This is a duplicate of CrossPlatformOperations.GenerateCurrentPath, because trying to invoke that would cause a crash due to currentPlatform not being initialized. // This is a duplicate of CrossPlatformOperations.GenerateCurrentPath, because trying to invoke that would cause a crash due to currentPlatform not being initialized.
[return: NotNull]
private static string GenerateCurrentPath() private static string GenerateCurrentPath()
{ {
string am2rLauncherDataEnvVar = Environment.GetEnvironmentVariable("AM2RLAUNCHERDATA");
if (!String.IsNullOrWhiteSpace(am2rLauncherDataEnvVar))
{
try
{
// This will create the directories recursively if they don't exist
Directory.CreateDirectory(am2rLauncherDataEnvVar);
// Our env var is now set and directories exist
return am2rLauncherDataEnvVar;
}
catch { }
}
string nixHome = Environment.GetEnvironmentVariable("HOME"); string nixHome = Environment.GetEnvironmentVariable("HOME");
//Mac has the Path at HOME/Library/AM2RLauncher //Mac has the Path at HOME/Library/AM2RLauncher
string macPath = nixHome + "/Library/AM2RLauncher"; string macPath = nixHome + "/Library/AM2RLauncher";

@ -10,12 +10,12 @@ namespace AM2RLauncher.Wpf;
/// <summary> /// <summary>
/// The main class for the WinForms project. /// The main class for the WinForms project.
/// </summary> /// </summary>
static class MainClass internal static class MainClass
{ {
/// <summary> /// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions. /// The logger for <see cref="MainForm"/>, used to write any caught exceptions.
/// </summary> /// </summary>
private static readonly ILog Log = LogManager.GetLogger(typeof(MainForm)); private static readonly ILog log = LogManager.GetLogger(typeof(MainForm));
/// <summary> /// <summary>
/// The main method for the WinForms project. /// The main method for the WinForms project.
/// </summary> /// </summary>
@ -45,7 +45,7 @@ static class MainClass
} }
catch (Exception e) catch (Exception e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.StackTrace);
System.Windows.Forms.MessageBox.Show(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace, "Microsoft .NET Framework", System.Windows.Forms.MessageBox.Show(Language.Text.UnhandledException + "\n" + e.Message + "\n*****Stack Trace*****\n\n" + e.StackTrace, "Microsoft .NET Framework",
System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error); System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
} }
@ -56,7 +56,7 @@ static class MainClass
/// </summary> /// </summary>
private static void WinLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e) private static void WinLauncher_UnhandledException(object sender, Eto.UnhandledExceptionEventArgs e)
{ {
Log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject); log.Error("An unhandled exception has occurred: \n*****Stack Trace*****\n\n" + e.ExceptionObject);
MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "Microsoft .NET Framework", MessageBoxType.Error); MessageBox.Show(Language.Text.UnhandledException + "\n*****Stack Trace*****\n\n" + e.ExceptionObject, "Microsoft .NET Framework", MessageBoxType.Error);
} }
@ -65,8 +65,11 @@ static class MainClass
{ {
// First, we check if the user has a custom AM2RLAUNCHERDATA env var // First, we check if the user has a custom AM2RLAUNCHERDATA env var
string am2rLauncherDataEnvVar = Environment.GetEnvironmentVariable("AM2RLAUNCHERDATA"); string am2rLauncherDataEnvVar = Environment.GetEnvironmentVariable("AM2RLAUNCHERDATA");
if (!String.IsNullOrWhiteSpace(am2rLauncherDataEnvVar)) // Windows has the path where the exe is located as default
{ string defaultPath = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
if (String.IsNullOrWhiteSpace(am2rLauncherDataEnvVar))
return defaultPath;
try try
{ {
// This will create the directories recursively if they don't exist // This will create the directories recursively if they don't exist
@ -75,10 +78,9 @@ static class MainClass
// Our env var is now set and directories exist // Our env var is now set and directories exist
return am2rLauncherDataEnvVar; return am2rLauncherDataEnvVar;
} }
catch { } catch
{
return defaultPath;
} }
// Windows has the path where the exe is located as default
return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
} }
} }

@ -1,5 +1,4 @@
using AM2RLauncher.Core; using AM2RLauncher.Core;
using Eto;
using Eto.Forms; using Eto.Forms;
using log4net; using log4net;
using System; using System;
@ -21,41 +20,41 @@ namespace AM2RLauncher
public const string VERSION = Core.Core.VERSION; public const string VERSION = Core.Core.VERSION;
/// <summary>The Path of the oldConfig. Only gets used Windows-only</summary> /// <summary>The Path of the oldConfig. Only gets used Windows-only</summary>
private static readonly string OldConfigPath = CrossPlatformOperations.CURRENTPATH + "/" + CrossPlatformOperations.LAUNCHERNAME + ".oldCfg"; private static readonly string oldConfigPath = CrossPlatformOperations.CURRENTPATH + "/" + CrossPlatformOperations.LAUNCHERNAME + ".oldCfg";
/// <summary>The actual Path where the executable is stored, only used for updating.</summary> /// <summary>The actual Path where the executable is stored, only used for updating.</summary>
//TODO: for mac, this reports the path of the mac runner, not the actual .app //TODO: for mac, this reports the path of the mac runner, not the actual .app
private static readonly string UpdatePath = OS.IsWindows ? CrossPlatformOperations.CURRENTPATH : Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); private static readonly string updatePath = OS.IsWindows ? CrossPlatformOperations.CURRENTPATH : Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
//TODO: Mac support for this in general //TODO: Mac support for this in general
/// <summary> /// <summary>
/// Our log object, that handles logging the current execution to a file. /// Our log object, that handles logging the current execution to a file.
/// </summary> /// </summary>
private static readonly ILog Log = LogManager.GetLogger(typeof(MainForm)); private static readonly ILog log = LogManager.GetLogger(typeof(MainForm));
/// <summary> /// <summary>
/// Performs the entire AM2RLauncher update procedure. /// Performs the entire AM2RLauncher update procedure.
/// </summary> /// </summary>
public static void Main() public static void Main()
{ {
Log.Info("Running update check..."); log.Info("Running update check...");
// Update section // Update section
// Clean old files that have been left // Clean old files that have been left
if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak")) if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak"))
{ {
Log.Info("AM2RLauncher.bak detected. Removing file."); log.Info("AM2RLauncher.bak detected. Removing file.");
File.Delete(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak"); File.Delete(CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak");
} }
if (OS.IsWindows && File.Exists(OldConfigPath)) if (OS.IsWindows && File.Exists(oldConfigPath))
{ {
Log.Info(CrossPlatformOperations.LAUNCHERNAME + ".oldCfg detected. Removing file."); log.Info(CrossPlatformOperations.LAUNCHERNAME + ".oldCfg detected. Removing file.");
File.Delete(OldConfigPath); File.Delete(oldConfigPath);
} }
if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/oldLib")) if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/oldLib"))
{ {
Log.Info("Old lib folder detected, removing folder."); log.Info("Old lib folder detected, removing folder.");
Directory.Delete(CrossPlatformOperations.CURRENTPATH + "/oldLib", true); Directory.Delete(CrossPlatformOperations.CURRENTPATH + "/oldLib", true);
} }
@ -80,11 +79,11 @@ namespace AM2RLauncher
} }
// Check settings if autoUpdateLauncher is set to true // Check settings if autoUpdateLauncher is set to true
bool autoUpdate = bool.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")); bool autoUpdate = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher"));
if (autoUpdate) if (autoUpdate)
{ {
Log.Info("AutoUpdate Launcher set to true!"); log.Info("AutoUpdate Launcher set to true!");
// This is supposed to fix the updater throwing an exception on windows 7 and earlier(?) // This is supposed to fix the updater throwing an exception on windows 7 and earlier(?)
// See this for information: https://stackoverflow.com/q/2859790 and https://stackoverflow.com/a/50977774 // See this for information: https://stackoverflow.com/q/2859790 and https://stackoverflow.com/a/50977774
@ -102,7 +101,7 @@ namespace AM2RLauncher
} }
catch (WebException) catch (WebException)
{ {
Log.Error("WebException caught! Displaying MessageBox."); log.Error("WebException caught! Displaying MessageBox.");
MessageBox.Show(Language.Text.NoInternetConnection); MessageBox.Show(Language.Text.NoInternetConnection);
return; return;
} }
@ -116,24 +115,24 @@ namespace AM2RLauncher
for (int i = 0; i < localVersionArray.Length; i++) for (int i = 0; i < localVersionArray.Length; i++)
{ {
int onlineNum = int.Parse(onlineVersionArray[i]); int onlineNum = Int32.Parse(onlineVersionArray[i]);
int localNum = int.Parse(localVersionArray[i]); int localNum = Int32.Parse(localVersionArray[i]);
if (onlineNum > localNum) if (onlineNum > localNum)
{ {
isCurrentVersionOutdated = true; isCurrentVersionOutdated = true;
break; break;
} }
else if (localNum > onlineNum) if (localNum > onlineNum)
break; break;
} }
Log.Info((isCurrentVersionOutdated ? "Updating" : "Not Updating") + " from " + VERSION + " to " + onlineVersion); log.Info((isCurrentVersionOutdated ? "Updating" : "Not Updating") + " from " + VERSION + " to " + onlineVersion);
// No new update, exiting // No new update, exiting
if (!isCurrentVersionOutdated) if (!isCurrentVersionOutdated)
return; return;
Log.Info("Current version (" + VERSION + ") is outdated! Initiating update for version " + onlineVersion + "."); log.Info("Current version (" + VERSION + ") is outdated! Initiating update for version " + onlineVersion + ".");
string tmpUpdatePath = CrossPlatformOperations.CURRENTPATH + "/tmpupdate/"; string tmpUpdatePath = CrossPlatformOperations.CURRENTPATH + "/tmpupdate/";
string zipPath = CrossPlatformOperations.CURRENTPATH + "/launcher.zip"; string zipPath = CrossPlatformOperations.CURRENTPATH + "/launcher.zip";
@ -152,31 +151,31 @@ namespace AM2RLauncher
if (OS.IsWindows) platformSuffix = "_win"; if (OS.IsWindows) platformSuffix = "_win";
else if (OS.IsLinux) platformSuffix = "_lin"; else if (OS.IsLinux) platformSuffix = "_lin";
Log.Info("Downloading https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip to " + zipPath + "."); log.Info("Downloading https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip to " + zipPath + ".");
client.DownloadFile("https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip", zipPath); client.DownloadFile("https://github.com/AM2R-Community-Developers/AM2RLauncher/releases/latest/download/AM2RLauncher_" + onlineVersion + platformSuffix + ".zip", zipPath);
Log.Info("File successfully downloaded."); log.Info("File successfully downloaded.");
} }
} }
catch (UnauthorizedAccessException) catch (UnauthorizedAccessException)
{ {
Log.Error("UnauthorizedAccessException caught! Displaying MessageBox."); log.Error("UnauthorizedAccessException caught! Displaying MessageBox.");
MessageBox.Show(Language.Text.UnauthorizedAccessMessage); MessageBox.Show(Language.Text.UnauthorizedAccessMessage);
return; return;
} }
ZipFile.ExtractToDirectory(zipPath, tmpUpdatePath); ZipFile.ExtractToDirectory(zipPath, tmpUpdatePath);
Log.Info("Updates successfully extracted to " + tmpUpdatePath); log.Info("Updates successfully extracted to " + tmpUpdatePath);
File.Delete(zipPath); File.Delete(zipPath);
File.Move(UpdatePath + "/" + CrossPlatformOperations.LAUNCHERNAME, CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak"); File.Move(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME, CrossPlatformOperations.CURRENTPATH + "/AM2RLauncher.bak");
if (OS.IsWindows) File.Move(CrossPlatformOperations.LAUNCHERNAME + ".config", CrossPlatformOperations.LAUNCHERNAME + ".oldCfg"); if (OS.IsWindows) File.Move(CrossPlatformOperations.LAUNCHERNAME + ".config", CrossPlatformOperations.LAUNCHERNAME + ".oldCfg");
foreach (var file in new DirectoryInfo(tmpUpdatePath).GetFiles()) foreach (var file in new DirectoryInfo(tmpUpdatePath).GetFiles())
{ {
Log.Info("Moving " + file.FullName + " to " + CrossPlatformOperations.CURRENTPATH + "/" + file.Name); log.Info("Moving " + file.FullName + " to " + CrossPlatformOperations.CURRENTPATH + "/" + file.Name);
File.Copy(file.FullName, UpdatePath + "/" + file.Name, true); File.Copy(file.FullName, updatePath + "/" + file.Name, true);
} }
// For windows, the actual application is in "AM2RLauncher.dll". Which means, we need to update the lib folder as well. // For windows, the actual application is in "AM2RLauncher.dll". Which means, we need to update the lib folder as well.
if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib")) if (OS.IsWindows && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib"))
@ -207,16 +206,16 @@ namespace AM2RLauncher
CrossPlatformOperations.CopyOldConfigToNewConfig(); CrossPlatformOperations.CopyOldConfigToNewConfig();
Log.Info("Files extracted. Preparing to restart executable..."); log.Info("Files extracted. Preparing to restart executable...");
if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x ./AM2RLauncher.Gtk"); if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x ./AM2RLauncher.Gtk");
System.Diagnostics.Process.Start(UpdatePath + "/" + CrossPlatformOperations.LAUNCHERNAME); System.Diagnostics.Process.Start(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME);
Environment.Exit(0); Environment.Exit(0);
} }
else else
{ {
Log.Info("AutoUpdate Launcher set to false. Exiting update check."); log.Info("AutoUpdate Launcher set to false. Exiting update check.");
} }
} }
} }

@ -7,7 +7,6 @@ using System.ComponentModel;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -538,7 +537,7 @@ namespace AM2RLauncher
{ {
Log.Info("User requested to add mod. Requesting user input for new mod .zip..."); Log.Info("User requested to add mod. Requesting user input for new mod .zip...");
ProfileXML addedProfile = null; ProfileXML addedProfile;
OpenFileDialog fileFinder = new OpenFileDialog OpenFileDialog fileFinder = new OpenFileDialog
{ {
@ -721,8 +720,8 @@ namespace AM2RLauncher
private void DrawablePaintEvent(object sender, PaintEventArgs e) private void DrawablePaintEvent(object sender, PaintEventArgs e)
{ {
// Get drawing variables // Get drawing variables
int height = drawable.Height; float height = drawable.Height;
int width = drawable.Width; float width = drawable.Width;
float scaleDivisor = OS.IsWindows ? 955f : 715f; // Magic brute-forced values. Don't ask questions, because we don't have answers >_> float scaleDivisor = OS.IsWindows ? 955f : 715f; // Magic brute-forced values. Don't ask questions, because we don't have answers >_>
// Also, seems like nix systems share the same scaleDivisor. Again, don't ask. // Also, seems like nix systems share the same scaleDivisor. Again, don't ask.
float scale = height / scaleDivisor; float scale = height / scaleDivisor;

@ -1,19 +1,9 @@
using Eto.Forms; using Eto.Forms;
using LibGit2Sharp;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
namespace AM2RLauncher namespace AM2RLauncher
{ {
public partial class MainForm : Form public partial class MainForm : Form
{ {
/// <summary> /// <summary>
/// Method that updates <see cref="progressBar"/>. /// Method that updates <see cref="progressBar"/>.
/// </summary> /// </summary>
@ -40,7 +30,6 @@ namespace AM2RLauncher
UpdateProgressBar(value, 0, 100); UpdateProgressBar(value, 0, 100);
} }
/// <summary> /// <summary>
/// Safety check function before accessing <see cref="profileIndex"/>. /// Safety check function before accessing <see cref="profileIndex"/>.
/// </summary> /// </summary>
@ -49,9 +38,5 @@ namespace AM2RLauncher
{ {
return profileIndex != null; return profileIndex != null;
} }
} }
} }

@ -160,13 +160,14 @@ namespace AM2RLauncher
bool enabled = false; bool enabled = false;
switch (updateState) switch (updateState)
{ {
case UpdateState.Download: enabled = false; break; case UpdateState.Download:
case UpdateState.Downloading: enabled = false; break; case UpdateState.Downloading:
case UpdateState.Select11: enabled = false; break; case UpdateState.Select11:
case UpdateState.Install: enabled = true; break; case UpdateState.Installing:
case UpdateState.Installing: enabled = false; break;
case UpdateState.Play: enabled = true; break;
case UpdateState.Playing: enabled = false; break; case UpdateState.Playing: enabled = false; break;
case UpdateState.Install:
case UpdateState.Play: enabled = true; break;
} }
if (apkButtonState == ApkButtonState.Creating) enabled = false; if (apkButtonState == ApkButtonState.Creating) enabled = false;

@ -81,21 +81,20 @@ namespace AM2RLauncher
/// </summary> /// </summary>
private static string currentMirror; private static string currentMirror;
private static bool isInternetThere = Core.Core.isInternetThere; private static bool isInternetThere = Core.Core.IsInternetThere;
private static bool isThisRunningFromWine = Core.Core.isThisRunningFromWine; private static bool isThisRunningFromWine = Core.Core.IsThisRunningFromWine;
public MainForm() private static bool singleInstance;
{
// Exit if we're already running the AM2RLauncher
// Thanks, StackOverflow! https://stackoverflow.com/questions/184084/how-to-force-c-sharp-net-app-to-run-only-one-instance-in-windows
bool singleInstance;
// This mutex needs to CONTINUE existing for the entire application's lifetime, or else the rest of this won't ever work! // This mutex needs to CONTINUE existing for the entire application's lifetime, or else the rest of this won't ever work!
// We're basically using it to key a thread and scan for other instances of that tag. // We're basically using it to key a thread and scan for other instances of that tag.
Mutex mutex = new Mutex(true, "AM2RLauncher", out singleInstance); Mutex mutex = new Mutex(true, "AM2RLauncher", out singleInstance);
public MainForm()
{
// Exit if we're already running the AM2RLauncher
// Thanks, StackOverflow! https://stackoverflow.com/questions/184084/how-to-force-c-sharp-net-app-to-run-only-one-instance-in-windows
if (!singleInstance) if (!singleInstance)
{ {
// If on Windows, set the original app to the foreground window to prevent confusion // If on Windows, set the original app to the foreground window to prevent confusion
@ -149,7 +148,7 @@ namespace AM2RLauncher
Log.Info("Actual Launcher location: " + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory)); Log.Info("Actual Launcher location: " + Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory));
// Set the language to what User wanted or choose local language // Set the language to what User wanted or choose local language
string userLanguage = Core.CrossPlatformOperations.ReadFromConfig("Language").ToLower(); string userLanguage = CrossPlatformOperations.ReadFromConfig("Language").ToLower();
if (!userLanguage.Equals("default")) if (!userLanguage.Equals("default"))
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultures(CultureTypes.AllCultures).First(c => c.NativeName.ToLower().Contains(userLanguage)); Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultures(CultureTypes.AllCultures).First(c => c.NativeName.ToLower().Contains(userLanguage));
@ -182,7 +181,7 @@ namespace AM2RLauncher
} }
// Custom splash texts // Custom splash texts
string splash = Core.Splash.GetSplash(); string splash = Splash.GetSplash();
Log.Info("Randomly chosen splash: " + splash); Log.Info("Randomly chosen splash: " + splash);
// Load bitmaps // Load bitmaps
@ -205,7 +204,7 @@ namespace AM2RLauncher
// Create mirror list - eventually this should be platform specific! // Create mirror list - eventually this should be platform specific!
// We do this as a List<Uri> so we can add more dynamically on user input... if necessary. // We do this as a List<Uri> so we can add more dynamically on user input... if necessary.
mirrorList = Core.CrossPlatformOperations.GenerateMirrorList(); mirrorList = CrossPlatformOperations.GenerateMirrorList();
// Create mirror list // Create mirror list
// We do this as a list<listItem> for 1) make this dynamic and 2) make ETO happy // We do this as a list<listItem> for 1) make this dynamic and 2) make ETO happy
@ -224,13 +223,13 @@ namespace AM2RLauncher
Title = "AM2RLauncher " + VERSION + ": " + splash; Title = "AM2RLauncher " + VERSION + ": " + splash;
MinimumSize = new Size(500, 400); MinimumSize = new Size(500, 400);
// TODO: for some reason, this sometimes doesn't work on Linux. Was reported at eto, stays here until its fixed // TODO: for some reason, this sometimes doesn't work on Linux. Was reported at eto, stays here until its fixed
ClientSize = new Size(Int32.Parse(Core.CrossPlatformOperations.ReadFromConfig("Width")), Int32.Parse(Core.CrossPlatformOperations.ReadFromConfig("Height"))); ClientSize = new Size(Int32.Parse(CrossPlatformOperations.ReadFromConfig("Width")), Int32.Parse(CrossPlatformOperations.ReadFromConfig("Height")));
if (ClientSize.Width < 500) if (ClientSize.Width < 500)
ClientSize = new Size(500, ClientSize.Height); ClientSize = new Size(500, ClientSize.Height);
if (ClientSize.Height < 400) if (ClientSize.Height < 400)
ClientSize = new Size(ClientSize.Width, 400); ClientSize = new Size(ClientSize.Width, 400);
Log.Info("Start the launcher with Size: " + ClientSize.Width + ", " + ClientSize.Height); Log.Info("Start the launcher with Size: " + ClientSize.Width + ", " + ClientSize.Height);
if (Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("IsMaximized"))) Maximize(); if (Boolean.Parse(CrossPlatformOperations.ReadFromConfig("IsMaximized"))) Maximize();
drawable = new Drawable { BackgroundColor = colBGNoAlpha }; drawable = new Drawable { BackgroundColor = colBGNoAlpha };
@ -450,7 +449,6 @@ namespace AM2RLauncher
{ {
changelogWebView changelogWebView
} }
} }
}; };
@ -541,7 +539,7 @@ namespace AM2RLauncher
languageDropDown.Items.AddRange(languageList); languageDropDown.Items.AddRange(languageList);
var tmpLanguage = Core.CrossPlatformOperations.ReadFromConfig("Language"); var tmpLanguage = CrossPlatformOperations.ReadFromConfig("Language");
languageDropDown.SelectedIndex = tmpLanguage == "Default" ? 0 : languageDropDown.Items.IndexOf(languageDropDown.Items.FirstOrDefault(x => x.Text.Equals(tmpLanguage))); languageDropDown.SelectedIndex = tmpLanguage == "Default" ? 0 : languageDropDown.Items.IndexOf(languageDropDown.Items.FirstOrDefault(x => x.Text.Equals(tmpLanguage)));
if (languageDropDown.SelectedIndex == -1) if (languageDropDown.SelectedIndex == -1)
@ -553,7 +551,7 @@ namespace AM2RLauncher
// autoUpdateAM2R checkbox // autoUpdateAM2R checkbox
autoUpdateAM2RCheck = new CheckBox autoUpdateAM2RCheck = new CheckBox
{ {
Checked = Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("AutoUpdateAM2R")), Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateAM2R")),
Text = Language.Text.AutoUpdateAM2R, Text = Language.Text.AutoUpdateAM2R,
TextColor = colGreen TextColor = colGreen
}; };
@ -562,7 +560,7 @@ namespace AM2RLauncher
// autoUpdateLauncher checkbox // autoUpdateLauncher checkbox
autoUpdateLauncherCheck = new CheckBox autoUpdateLauncherCheck = new CheckBox
{ {
Checked = Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")), Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")),
Text = Language.Text.AutoUpdateLauncher, Text = Language.Text.AutoUpdateLauncher,
TextColor = colGreen TextColor = colGreen
}; };
@ -570,7 +568,7 @@ namespace AM2RLauncher
// HQ music, PC // HQ music, PC
hqMusicPCCheck = new CheckBox hqMusicPCCheck = new CheckBox
{ {
Checked = Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("MusicHQPC")), Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQPC")),
Text = Language.Text.HighQualityPC, Text = Language.Text.HighQualityPC,
TextColor = colGreen TextColor = colGreen
}; };
@ -578,7 +576,7 @@ namespace AM2RLauncher
// HQ music, Android // HQ music, Android
hqMusicAndroidCheck = new CheckBox hqMusicAndroidCheck = new CheckBox
{ {
Checked = Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("MusicHQAndroid")), Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQAndroid")),
Text = Language.Text.HighQualityAndroid, Text = Language.Text.HighQualityAndroid,
TextColor = colGreen TextColor = colGreen
}; };
@ -639,14 +637,14 @@ namespace AM2RLauncher
// Custom mirror // Custom mirror
customMirrorCheck = new CheckBox customMirrorCheck = new CheckBox
{ {
Checked = Boolean.Parse(Core.CrossPlatformOperations.ReadFromConfig("CustomMirrorEnabled")), Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("CustomMirrorEnabled")),
Text = Language.Text.CustomMirrorCheck, Text = Language.Text.CustomMirrorCheck,
TextColor = colGreen TextColor = colGreen
}; };
customMirrorTextBox = new TextBox customMirrorTextBox = new TextBox
{ {
Text = Core.CrossPlatformOperations.ReadFromConfig("CustomMirrorText"), Text = CrossPlatformOperations.ReadFromConfig("CustomMirrorText"),
BackgroundColor = colBGNoAlpha, BackgroundColor = colBGNoAlpha,
TextColor = colGreen TextColor = colGreen
}; };

@ -2,7 +2,6 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFramework>netstandard2.0</TargetFramework>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>

@ -1,17 +1,14 @@
using AM2RLauncher.Core.XML; using log4net;
using log4net;
using System; using System;
using System.Collections.Generic;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
{
/// <summary> /// <summary>
/// Class that has core stuff that doesn't fit anywhere else /// Class that has core stuff that doesn't fit anywhere else
/// </summary> /// </summary>
public static class Core public static class Core
{ {
/// <summary> /// <summary>
/// Our log object, that handles logging the current execution to a file. /// Our log object, that handles logging the current execution to a file.
/// </summary> /// </summary>
@ -23,12 +20,12 @@ namespace AM2RLauncher.Core
/// <summary> /// <summary>
/// Checks if this is run via WINE. /// Checks if this is run via WINE.
/// </summary> /// </summary>
public static bool isThisRunningFromWine = CheckIfRunFromWINE(); public static readonly bool IsThisRunningFromWine = CheckIfRunFromWINE();
/// <summary> /// <summary>
/// Indicates whether or not we have established an internet connection. /// Indicates whether or not we have established an internet connection.
/// </summary> /// </summary>
public static readonly bool isInternetThere = HelperMethods.IsConnectedToInternet(); public static readonly bool IsInternetThere = HelperMethods.IsConnectedToInternet();
/// <summary> /// <summary>
/// Checks if this is ran from WINE /// Checks if this is ran from WINE
@ -49,5 +46,4 @@ namespace AM2RLauncher.Core
/// <returns></returns> /// <returns></returns>
[DllImport("user32.dll")] [DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd); public static extern bool SetForegroundWindow(IntPtr hWnd);
}
} }

@ -7,17 +7,17 @@ using System.IO;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
/// <summary>
/// Class that does operations that work cross-platform.
/// </summary>
public static class CrossPlatformOperations
{ {
/// <summary> /// <summary>
/// Class that does operations that work cross-platform. /// The logger for <see cref="Core"/>, used to write any caught exceptions.
/// </summary>
public static class CrossPlatformOperations
{
/// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions.
/// </summary> /// </summary>
private static readonly ILog Log = Core.Log; private static readonly ILog log = Core.Log;
/// <summary> /// <summary>
/// Name of the Launcher executable. /// Name of the Launcher executable.
@ -67,7 +67,7 @@ namespace AM2RLauncher.Core
"https://gitlab.com/am2r-community-developers/AM2R-Autopatcher-Windows.git" "https://gitlab.com/am2r-community-developers/AM2R-Autopatcher-Windows.git"
}; };
} }
else if (OS.IsLinux) if (OS.IsLinux)
{ {
return new List<string> return new List<string>
{ {
@ -75,7 +75,7 @@ namespace AM2RLauncher.Core
"https://gitlab.com/am2r-community-developers/AM2R-Autopatcher-Linux.git" "https://gitlab.com/am2r-community-developers/AM2R-Autopatcher-Linux.git"
}; };
} }
else if (OS.IsMac) if (OS.IsMac)
{ {
return new List<string> return new List<string>
{ {
@ -84,12 +84,11 @@ namespace AM2RLauncher.Core
}; };
} }
else // Should never occur, but...
{ // Should never occur, but...
Log.Error(OS.Name + " has no mirror lists!"); log.Error(OS.Name + " has no mirror lists!");
return new List<string>(); return new List<string>();
} }
}
/// <summary> /// <summary>
/// Reads the Launcher config file on the current Platform and returns the value for <paramref name="property"/>. /// Reads the Launcher config file on the current Platform and returns the value for <paramref name="property"/>.
@ -98,7 +97,7 @@ namespace AM2RLauncher.Core
/// <returns>The value from <paramref name="property"/> as a string</returns> /// <returns>The value from <paramref name="property"/> as a string</returns>
public static string ReadFromConfig(string property) public static string ReadFromConfig(string property)
{ {
Log.Info($"Reading {property} from config."); log.Info($"Reading {property} from config.");
if (OS.IsWindows) if (OS.IsWindows)
{ {
// We use the configuration manager in order to read `property` from the app.config and then return it // We use the configuration manager in order to read `property` from the app.config and then return it
@ -106,7 +105,7 @@ namespace AM2RLauncher.Core
if (appConfig == null) throw new ArgumentException("The property " + property + " could not be found."); if (appConfig == null) throw new ArgumentException("The property " + property + " could not be found.");
return appConfig.ConnectionString; return appConfig.ConnectionString;
} }
else if (OS.IsUnix) if (OS.IsUnix)
{ {
string launcherConfigPath = NIXLAUNCHERCONFIGPATH; string launcherConfigPath = NIXLAUNCHERCONFIGPATH;
string launcherConfigFilePath = launcherConfigPath + "/config.xml"; string launcherConfigFilePath = launcherConfigPath + "/config.xml";
@ -122,14 +121,11 @@ namespace AM2RLauncher.Core
// Deserialize the config xml into launcherConfig // Deserialize the config xml into launcherConfig
launcherConfig = XML.Serializer.Deserialize<XML.LauncherConfigXML>(File.ReadAllText(launcherConfigFilePath)); launcherConfig = XML.Serializer.Deserialize<XML.LauncherConfigXML>(File.ReadAllText(launcherConfigFilePath));
if (launcherConfig[property] == null)
return null;
// This uses the indexer, which means, we can use the variable in order to get the property. Look at LauncherConfigXML for more info // This uses the indexer, which means, we can use the variable in order to get the property. Look at LauncherConfigXML for more info
return launcherConfig[property]?.ToString(); return launcherConfig[property]?.ToString();
} }
else
Log.Error(OS.Name + " has no config to read from!"); log.Error(OS.Name + " has no config to read from!");
return null; return null;
} }
@ -140,7 +136,7 @@ namespace AM2RLauncher.Core
/// <param name="value">The value that will be written.</param> /// <param name="value">The value that will be written.</param>
public static void WriteToConfig(string property, object value) public static void WriteToConfig(string property, object value)
{ {
Log.Info($"Writing {value} of type {value.GetType()} to {property} to config."); log.Info($"Writing {value} of type {value.GetType()} to {property} to config.");
if (OS.IsWindows) if (OS.IsWindows)
{ {
// We use the configuration manager in order to read from the app.config, change the value and save it // We use the configuration manager in order to read from the app.config, change the value and save it
@ -176,7 +172,7 @@ namespace AM2RLauncher.Core
File.WriteAllText(launcherConfigFilePath, XML.Serializer.Serialize<XML.LauncherConfigXML>(launcherConfig)); File.WriteAllText(launcherConfigFilePath, XML.Serializer.Serialize<XML.LauncherConfigXML>(launcherConfig));
} }
else else
Log.Error(OS.Name + " has no config to write to!"); log.Error(OS.Name + " has no config to write to!");
} }
/// <summary> /// <summary>
@ -211,7 +207,7 @@ namespace AM2RLauncher.Core
File.WriteAllText(launcherConfigFilePath, XML.Serializer.Serialize<XML.LauncherConfigXML>(launcherConfig)); File.WriteAllText(launcherConfigFilePath, XML.Serializer.Serialize<XML.LauncherConfigXML>(launcherConfig));
} }
else else
Log.Error(OS.Name + " has no config to transfer over!"); log.Error(OS.Name + " has no config to transfer over!");
} }
/// <summary> /// <summary>
@ -227,7 +223,7 @@ namespace AM2RLauncher.Core
else if (OS.IsMac) else if (OS.IsMac)
Process.Start("open", url); Process.Start("open", url);
else else
Log.Error(OS.Name + " can't open URLs!"); log.Error(OS.Name + " can't open URLs!");
} }
/// <summary> /// <summary>
@ -242,7 +238,7 @@ namespace AM2RLauncher.Core
: path.Replace("~", NIXHOME); : path.Replace("~", NIXHOME);
if (!Directory.Exists(realPath)) if (!Directory.Exists(realPath))
{ {
Log.Info(realPath + " did not exist and was created"); log.Info(realPath + " did not exist and was created");
Directory.CreateDirectory(realPath); Directory.CreateDirectory(realPath);
} }
@ -256,7 +252,7 @@ namespace AM2RLauncher.Core
else if (OS.IsMac) else if (OS.IsMac)
Process.Start("open", $"\"{realPath}\""); Process.Start("open", $"\"{realPath}\"");
else else
Log.Error(OS.Name + " can't open folders!"); log.Error(OS.Name + " can't open folders!");
} }
/// <summary> /// <summary>
@ -272,7 +268,7 @@ namespace AM2RLauncher.Core
: path.Replace("~", NIXHOME); : path.Replace("~", NIXHOME);
if (!File.Exists(realPath)) if (!File.Exists(realPath))
{ {
Log.Error(realPath + "did not exist, operation to open its folder was cancelled!"); log.Error(realPath + "did not exist, operation to open its folder was cancelled!");
return; return;
} }
@ -285,7 +281,7 @@ namespace AM2RLauncher.Core
else if (OS.IsMac) else if (OS.IsMac)
Process.Start("open", $"-R \"{realPath}\""); Process.Start("open", $"-R \"{realPath}\"");
else else
Log.Error(OS.Name + " can't open select files in file explorer!"); log.Error(OS.Name + " can't open select files in file explorer!");
} }
/// <summary> /// <summary>
@ -396,13 +392,10 @@ namespace AM2RLauncher.Core
Arguments = arguments Arguments = arguments
}; };
using (Process proc = new Process { StartInfo = parameters }) using Process proc = new Process { StartInfo = parameters };
{
proc.Start(); proc.Start();
proc.WaitForExit(); proc.WaitForExit();
} }
}
else if (OS.IsUnix) else if (OS.IsUnix)
{ {
ProcessStartInfo parameters = new ProcessStartInfo ProcessStartInfo parameters = new ProcessStartInfo
@ -412,23 +405,20 @@ namespace AM2RLauncher.Core
WorkingDirectory = CURRENTPATH WorkingDirectory = CURRENTPATH
}; };
using (Process proc = Process.Start(parameters)) using Process proc = Process.Start(parameters);
{
proc?.WaitForExit(); proc?.WaitForExit();
} }
}
if (originalOutput != output && File.Exists(output)) if (originalOutput == output || !File.Exists(output))
{ return;
File.Delete(originalOutput); File.Delete(originalOutput);
File.Move(output, originalOutput); File.Move(output, originalOutput);
} }
}
public static void RunJavaJar(string arguments = null, string workingDirectory = null) public static void RunJavaJar(string arguments = null, string workingDirectory = null)
{ {
if (workingDirectory == null) workingDirectory ??= Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
workingDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
string proc = "", string proc = "",
javaArgs = ""; javaArgs = "";
@ -487,18 +477,18 @@ namespace AM2RLauncher.Core
Directory.CreateDirectory(am2rLauncherDataEnvVar); Directory.CreateDirectory(am2rLauncherDataEnvVar);
// Our env var is now set and directories exist // Our env var is now set and directories exist
Log.Info("CurrentPath is set to " + am2rLauncherDataEnvVar); log.Info("CurrentPath is set to " + am2rLauncherDataEnvVar);
return am2rLauncherDataEnvVar; return am2rLauncherDataEnvVar;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error($"There was an error with '{am2rLauncherDataEnvVar}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults."); log.Error($"There was an error with '{am2rLauncherDataEnvVar}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults.");
} }
} }
if (OS.IsWindows) if (OS.IsWindows)
{ {
Log.Info("Using default Windows CurrentPath."); log.Info("Using default Windows CurrentPath.");
// Windows has the path where the exe is located as default // Windows has the path where the exe is located as default
return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location); return Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
} }
@ -508,7 +498,7 @@ namespace AM2RLauncher.Core
string xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME"); string xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
if (String.IsNullOrWhiteSpace(xdgDataHome)) if (String.IsNullOrWhiteSpace(xdgDataHome))
{ {
Log.Info("Using default Linux CurrentPath."); log.Info("Using default Linux CurrentPath.");
xdgDataHome = NIXHOME + "/.local/share"; xdgDataHome = NIXHOME + "/.local/share";
} }
@ -521,12 +511,12 @@ namespace AM2RLauncher.Core
Directory.CreateDirectory(xdgDataHome); Directory.CreateDirectory(xdgDataHome);
// Our env var is now set and directories exist // Our env var is now set and directories exist
Log.Info("CurrentPath is set to " + xdgDataHome); log.Info("CurrentPath is set to " + xdgDataHome);
return xdgDataHome; return xdgDataHome;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error($"There was an error with '{xdgDataHome}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults."); log.Error($"There was an error with '{xdgDataHome}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults.");
} }
} }
else if (OS.IsMac) else if (OS.IsMac)
@ -536,21 +526,20 @@ namespace AM2RLauncher.Core
try try
{ {
Directory.CreateDirectory(macPath); Directory.CreateDirectory(macPath);
Log.Info("Using default Mac CurrentPath."); log.Info("Using default Mac CurrentPath.");
return macPath; return macPath;
} }
catch (Exception ex) catch (Exception ex)
{ {
Log.Error($"There was an error with '{macPath}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults."); log.Error($"There was an error with '{macPath}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults.");
} }
} }
else else
Log.Error(OS.Name + " has no current path!"); log.Error(OS.Name + " has no current path!");
Log.Info("Something went wrong, falling back to the default CurrentPath."); log.Info("Something went wrong, falling back to the default CurrentPath.");
return Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); return Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
} }
}
} }

@ -1,26 +1,21 @@
using LibGit2Sharp; using log4net;
using log4net;
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net; using System.Net;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
/// <summary>
/// Class that has various Helper functions. Basically anything that could be used outside the Launcher resides here.
/// </summary>
public static class HelperMethods
{ {
/// <summary>
/// Class that has various Helper functions. Basically anything that could be used outside the Launcher resides here.
/// </summary>
public static class HelperMethods
{
// Load reference to logger // Load reference to logger
/// <summary> /// <summary>
/// Our log object, that handles logging the current execution to a file. /// Our log object, that handles logging the current execution to a file.
/// </summary> /// </summary>
private static readonly ILog Log = Core.Log; private static readonly ILog log = Core.Log;
// Thank you, Microsoft docs: https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories // Thank you, Microsoft docs: https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories
// Slightly modified by adding overwriteFiles bool, as we need to replace readme, music, etc. // Slightly modified by adding overwriteFiles bool, as we need to replace readme, music, etc.
@ -107,15 +102,11 @@ namespace AM2RLauncher.Core
if (!File.Exists(filename)) if (!File.Exists(filename))
return ""; return "";
using (var stream = File.OpenRead(filename)) using var stream = File.OpenRead(filename);
{ using var md5 = MD5.Create();
using (var md5 = MD5.Create())
{
var hash = md5.ComputeHash(stream); var hash = md5.ComputeHash(stream);
return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();
} }
}
}
/// <summary> /// <summary>
/// Performs recursive rollover on a set of log files. /// Performs recursive rollover on a set of log files.
@ -129,9 +120,9 @@ namespace AM2RLauncher.Core
string fileName; string fileName;
// If not the original file, set the new index and get the new fileName. // If not the original file, set the new index and get the new fileName.
if (char.IsNumber(endChar)) if (Char.IsNumber(endChar))
{ {
index = int.Parse(endChar.ToString()) + 1; index = Int32.Parse(endChar.ToString()) + 1;
fileName = logFile.Remove(logFile.Length - 1) + index; fileName = logFile.Remove(logFile.Length - 1) + index;
} }
else // Otherwise, if the original file, just set fileName to log.txt.1. else // Otherwise, if the original file, just set fileName to log.txt.1.
@ -139,16 +130,12 @@ namespace AM2RLauncher.Core
// If new name already exists, run the rollover algorithm on it! // If new name already exists, run the rollover algorithm on it!
if (File.Exists(fileName)) if (File.Exists(fileName))
{
RecursiveRollover(fileName, max); RecursiveRollover(fileName, max);
}
//TODO: this can fail if one doesnt have permissions to move or delete the file //TODO: this can fail if one doesnt have permissions to move or delete the file
// If index is less than max, rename file. // If index is less than max, rename file.
if (index < max) if (index < max)
{
File.Move(logFile, fileName); File.Move(logFile, fileName);
}
else // Otherwise, delete the file. else // Otherwise, delete the file.
File.Delete(logFile); File.Delete(logFile);
} }
@ -159,19 +146,18 @@ namespace AM2RLauncher.Core
/// <returns><see langword="true"/> if we have internet, <see langword="false"/> if not.</returns> /// <returns><see langword="true"/> if we have internet, <see langword="false"/> if not.</returns>
public static bool IsConnectedToInternet() public static bool IsConnectedToInternet()
{ {
Log.Info("Checking internet connection..."); log.Info("Checking internet connection...");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://github.com"); HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://github.com");
try try
{ {
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); HttpWebResponse _ = (HttpWebResponse)request.GetResponse();
} }
catch (WebException) catch (WebException)
{ {
Log.Info("Internet connection failed."); log.Info("Internet connection failed.");
return false; return false;
} }
Log.Info("Internet connection established!"); log.Info("Internet connection established!");
return true; return true;
} }
}
} }

@ -1,15 +1,12 @@
using System; using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
/// <summary>
/// Class that has information about the current running operating system.
/// </summary>
public static class OS
{ {
/// <summary>
/// Class that has information about the current running operating system.
/// </summary>
public class OS
{
/// <summary> /// <summary>
/// Determines if the current OS is Windows. /// Determines if the current OS is Windows.
/// </summary> /// </summary>
@ -33,21 +30,20 @@ namespace AM2RLauncher.Core
/// <summary> /// <summary>
/// Gets a string representation of the current OS. /// Gets a string representation of the current OS.
/// </summary> /// </summary>
public static readonly string Name = DetermineOSName(); public static readonly string Name = DetermineOsName();
/// <summary> /// <summary>
/// Generates a string representation of the current OS /// Generates a string representation of the current OS
/// </summary> /// </summary>
private static string DetermineOSName() private static string DetermineOsName()
{ {
if (IsWindows) if (IsWindows)
return "Windows"; return "Windows";
else if (IsLinux) if (IsLinux)
return "Linux"; return "Linux";
else if (IsMac) if (IsMac)
return "Mac"; return "Mac";
else
return "Unknown OS"; return "Unknown OS";
} }
}
} }

@ -2,45 +2,42 @@
using LibGit2Sharp; using LibGit2Sharp;
using log4net; using log4net;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
/// <summary>
/// An enum, that has possible return codes for <see cref="Profile.CheckIfZipIsAM2R11"/>.
/// </summary>
public enum IsZipAM2R11ReturnCodes
{ {
/// <summary>
/// An enum, that has possible return codes for <see cref="HelperMethods.CheckIfZipIsAM2R11"/>.
/// </summary>
public enum IsZipAM2R11ReturnCodes
{
Successful, Successful,
MissingOrInvalidAM2RExe, MissingOrInvalidAM2RExe,
MissingOrInvalidD3DX9_43Dll, MissingOrInvalidD3DX9_43Dll,
MissingOrInvalidDataWin, MissingOrInvalidDataWin,
GameIsInASubfolder GameIsInASubfolder
} }
/// <summary> /// <summary>
/// Class that has methods related to AM2RLauncher profiles. /// Class that has methods related to AM2RLauncher profiles.
/// </summary> /// </summary>
public static class Profile public static class Profile
{ {
/// <summary> /// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions. /// The logger for <see cref="Core"/>, used to write any caught exceptions.
/// </summary> /// </summary>
private static readonly ILog Log = Core.Log; private static readonly ILog log = Core.Log;
/// <summary> /// <summary>
/// Caches the result of <see cref="Is11Installed"/> so that we don't extract and verify it too often. /// Caches the result of <see cref="Is11Installed"/> so that we don't extract and verify it too often.
/// </summary> /// </summary>
private static bool? isAM2R11InstalledCache = null; private static bool? isAM2R11InstalledCache;
/// <summary> /// <summary>
/// Caches the MD5 hash of the provided AM2R_11.zip so we don't end up checking the zip if it hasn't changed. /// Caches the MD5 hash of the provided AM2R_11.zip so we don't end up checking the zip if it hasn't changed.
@ -62,11 +59,11 @@ namespace AM2RLauncher.Core
// Return safely if file doesn't exist // Return safely if file doesn't exist
if (!File.Exists(am2r11file)) return false; if (!File.Exists(am2r11file)) return false;
lastAM2R11ZipMD5 = HelperMethods.CalculateMD5(am2r11file); lastAM2R11ZipMD5 = HelperMethods.CalculateMD5(am2r11file);
var returnCode = Profile.CheckIfZipIsAM2R11(am2r11file); var returnCode = CheckIfZipIsAM2R11(am2r11file);
// Check if it's valid, if not log it, rename it and silently leave // Check if it's valid, if not log it, rename it and silently leave
if (returnCode != IsZipAM2R11ReturnCodes.Successful) if (returnCode != IsZipAM2R11ReturnCodes.Successful)
{ {
Log.Info("Detected invalid AM2R_11 zip with following error code: " + returnCode); log.Info("Detected invalid AM2R_11 zip with following error code: " + returnCode);
HelperMethods.RecursiveRollover(am2r11file); HelperMethods.RecursiveRollover(am2r11file);
isAM2R11InstalledCache = false; isAM2R11InstalledCache = false;
return false; return false;
@ -91,7 +88,7 @@ namespace AM2RLauncher.Core
/// <summary> /// <summary>
/// Git Pulls from the repository. /// Git Pulls from the repository.
/// </summary> /// </summary>
public static void PullPatchData(Func<TransferProgress, bool> TransferProgressHandlerMethod) public static void PullPatchData(Func<TransferProgress, bool> transferProgressHandlerMethod)
{ {
using (var repo = new Repository(CrossPlatformOperations.CURRENTPATH + "/PatchData")) using (var repo = new Repository(CrossPlatformOperations.CURRENTPATH + "/PatchData"))
{ {
@ -107,7 +104,7 @@ namespace AM2RLauncher.Core
PullOptions options = new PullOptions(); PullOptions options = new PullOptions();
options.FetchOptions = new FetchOptions(); options.FetchOptions = new FetchOptions();
options.FetchOptions.OnTransferProgress += (tp) => TransferProgressHandlerMethod(tp); options.FetchOptions.OnTransferProgress += tp => transferProgressHandlerMethod(tp);
// User information to create a merge commit // User information to create a merge commit
var signature = new Signature("null", "null", DateTimeOffset.Now); var signature = new Signature("null", "null", DateTimeOffset.Now);
@ -119,20 +116,22 @@ namespace AM2RLauncher.Core
} }
catch catch
{ {
Log.Error("Repository pull attempt failed!"); log.Error("Repository pull attempt failed!");
return; return;
} }
} }
Log.Info("Repository pulled successfully."); log.Info("Repository pulled successfully.");
} }
/// <summary> /// <summary>
/// Installs <paramref name="profile"/>. /// Installs <paramref name="profile"/>.
/// </summary> /// </summary>
/// <param name="profile"><see cref="ProfileXML"/> to be installed.</param> /// <param name="profile"><see cref="ProfileXML"/> to be installed.</param>
/// <param name="useHqMusic">Wether to patch this with high quality music or not.</param>
/// <param name="progress">Provides the current progress of this method.</param>
public static void InstallProfile(ProfileXML profile, bool useHqMusic, IProgress<int> progress) public static void InstallProfile(ProfileXML profile, bool useHqMusic, IProgress<int> progress)
{ {
Log.Info("Installing profile " + profile.Name + "..."); log.Info("Installing profile " + profile.Name + "...");
string profilesHomePath = CrossPlatformOperations.CURRENTPATH + "/Profiles"; string profilesHomePath = CrossPlatformOperations.CURRENTPATH + "/Profiles";
string profilePath = profilesHomePath + "/" + profile.Name; string profilePath = profilesHomePath + "/" + profile.Name;
@ -168,7 +167,7 @@ namespace AM2RLauncher.Core
Directory.CreateDirectory(profilePath + "/Resources"); Directory.CreateDirectory(profilePath + "/Resources");
profilePath += "/Resources"; profilePath += "/Resources";
Log.Info("ProfileInstallation: Created folder structure."); log.Info("ProfileInstallation: Created folder structure.");
} }
// Extract 1.1 // Extract 1.1
@ -176,7 +175,7 @@ namespace AM2RLauncher.Core
// Extracted 1.1 // Extracted 1.1
progress.Report(33); progress.Report(33);
Log.Info("Profile folder created and AM2R_11.zip extracted."); log.Info("Profile folder created and AM2R_11.zip extracted.");
// Set local datapath for installation files // Set local datapath for installation files
var dataPath = CrossPlatformOperations.CURRENTPATH + profile.DataPath; var dataPath = CrossPlatformOperations.CURRENTPATH + profile.DataPath;
@ -194,7 +193,7 @@ namespace AM2RLauncher.Core
// Use the exe name based on the desktop file in the appimage, rather than hardcoding it. // Use the exe name based on the desktop file in the appimage, rather than hardcoding it.
string desktopContents = File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir/AM2R.desktop"); string desktopContents = File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir/AM2R.desktop");
exe = Regex.Match(desktopContents, @"(?<=Exec=).*").Value; exe = Regex.Match(desktopContents, @"(?<=Exec=).*").Value;
Log.Info("According to AppImage desktop file, using \"" + exe + "\" as game name."); log.Info("According to AppImage desktop file, using \"" + exe + "\" as game name.");
} }
else if (OS.IsMac) else if (OS.IsMac)
{ {
@ -203,10 +202,10 @@ namespace AM2RLauncher.Core
} }
else else
{ {
Log.Error(OS.Name + " does not have valid runner / data.win names!"); log.Error(OS.Name + " does not have valid runner / data.win names!");
} }
Log.Info("Attempting to patch in " + profilePath); log.Info("Attempting to patch in " + profilePath);
if (OS.IsWindows) if (OS.IsWindows)
{ {
@ -244,13 +243,13 @@ namespace AM2RLauncher.Core
} }
else else
{ {
Log.Error(OS.Name + " does not have patching methods!"); log.Error(OS.Name + " does not have patching methods!");
} }
// Applied patch // Applied patch
if (OS.IsWindows || OS.IsMac) progress.Report(66); if (OS.IsWindows || OS.IsMac) progress.Report(66);
else if (OS.IsLinux) progress.Report(44); // Linux will take a bit longer, due to appimage creation else if (OS.IsLinux) progress.Report(44); // Linux will take a bit longer, due to appimage creation
Log.Info("xdelta patch(es) applied."); log.Info("xdelta patch(es) applied.");
// Install new datafiles // Install new datafiles
HelperMethods.DirectoryCopy(dataPath + "/files_to_copy", profilePath); HelperMethods.DirectoryCopy(dataPath + "/files_to_copy", profilePath);
@ -283,7 +282,7 @@ namespace AM2RLauncher.Core
File.Copy(profilePath + "/" + exe, profilePath + "/AM2R.AppDir/usr/bin/" + exe); File.Copy(profilePath + "/" + exe, profilePath + "/AM2R.AppDir/usr/bin/" + exe);
progress.Report(66); progress.Report(66);
Log.Info("Gtk-specific formatting finished."); log.Info("Gtk-specific formatting finished.");
// Temp save the currentWorkingDirectory and console.error, change it to profilePath and null, call the script, and change it back. // Temp save the currentWorkingDirectory and console.error, change it to profilePath and null, call the script, and change it back.
string workingDir = Directory.GetCurrentDirectory(); string workingDir = Directory.GetCurrentDirectory();
@ -321,13 +320,13 @@ namespace AM2RLauncher.Core
// Copy profile.xml so we can grab data to compare for updates later! // Copy profile.xml so we can grab data to compare for updates later!
// tldr; check if we're in PatchData or not // tldr; check if we're in PatchData or not
if (new DirectoryInfo(dataPath)?.Parent?.Name == "PatchData") if (new DirectoryInfo(dataPath).Parent?.Name == "PatchData")
File.Copy(dataPath + "/../profile.xml", profilePath + "/profile.xml"); File.Copy(dataPath + "/../profile.xml", profilePath + "/profile.xml");
else File.Copy(dataPath + "/profile.xml", profilePath + "/profile.xml"); else File.Copy(dataPath + "/profile.xml", profilePath + "/profile.xml");
// Installed datafiles // Installed datafiles
progress.Report(100); progress.Report(100);
Log.Info("Successfully installed profile " + profile.Name + "."); log.Info("Successfully installed profile " + profile.Name + ".");
} }
/// <summary> /// <summary>
@ -338,10 +337,10 @@ namespace AM2RLauncher.Core
public static bool IsProfileInstalled(ProfileXML profile) public static bool IsProfileInstalled(ProfileXML profile)
{ {
if (OS.IsWindows) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.exe"); if (OS.IsWindows) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.exe");
else if (OS.IsLinux) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.AppImage"); if (OS.IsLinux) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.AppImage");
else if (OS.IsMac) return Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.app"); if (OS.IsMac) return Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.app");
Log.Error(OS.Name + " can't have profiles installed!"); log.Error(OS.Name + " can't have profiles installed!");
return false; return false;
} }
@ -349,6 +348,8 @@ namespace AM2RLauncher.Core
/// Creates an APK of the selected <paramref name="profile"/>. /// Creates an APK of the selected <paramref name="profile"/>.
/// </summary> /// </summary>
/// <param name="profile"><see cref="ProfileXML"/> to be compiled into an APK.</param> /// <param name="profile"><see cref="ProfileXML"/> to be compiled into an APK.</param>
/// <param name="useHqMusic">Wether to create the APK with high quality music or not.</param>
/// <param name="progress">Provides the current progress of this method.</param>
public static void CreateAPK(ProfileXML profile, bool useHqMusic, IProgress<int> progress) public static void CreateAPK(ProfileXML profile, bool useHqMusic, IProgress<int> progress)
{ {
// Overall safety check just in case of bad situations // Overall safety check just in case of bad situations
@ -357,7 +358,7 @@ namespace AM2RLauncher.Core
progress.Report(100); progress.Report(100);
return; return;
} }
Log.Info("Creating Android APK for profile " + profile.Name + "."); log.Info("Creating Android APK for profile " + profile.Name + ".");
// Create working dir after some cleanup // Create working dir after some cleanup
string apktoolPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/utilities/android/apktool.jar", string apktoolPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/utilities/android/apktool.jar",
@ -368,12 +369,12 @@ namespace AM2RLauncher.Core
Directory.Delete(tempDir, true); Directory.Delete(tempDir, true);
Directory.CreateDirectory(tempDir); Directory.CreateDirectory(tempDir);
Log.Info("Cleanup, variables, and working directory created."); log.Info("Cleanup, variables, and working directory created.");
progress.Report(14); progress.Report(14);
// Decompile AM2RWrapper.apk // Decompile AM2RWrapper.apk
CrossPlatformOperations.RunJavaJar("\"" + apktoolPath + "\" d \"" + dataPath + "/android/AM2RWrapper.apk\"", tempDir); CrossPlatformOperations.RunJavaJar("\"" + apktoolPath + "\" d \"" + dataPath + "/android/AM2RWrapper.apk\"", tempDir);
Log.Info("AM2RWrapper decompiled."); log.Info("AM2RWrapper decompiled.");
progress.Report(28); progress.Report(28);
// Add datafiles: 1.1, new datafiles, hq music, am2r.ini // Add datafiles: 1.1, new datafiles, hq music, am2r.ini
@ -387,12 +388,12 @@ namespace AM2RLauncher.Core
foreach (FileInfo file in new DirectoryInfo(dataPath).GetFiles().Where(f => f.Name.EndsWith("ini"))) foreach (FileInfo file in new DirectoryInfo(dataPath).GetFiles().Where(f => f.Name.EndsWith("ini")))
File.Copy(file.FullName, workingDir + "/" + file.Name); File.Copy(file.FullName, workingDir + "/" + file.Name);
Log.Info("AM2R_11.zip extracted and datafiles copied into AM2RWrapper."); log.Info("AM2R_11.zip extracted and datafiles copied into AM2RWrapper.");
progress.Report(42); progress.Report(42);
// Patch data.win to game.droid // Patch data.win to game.droid
CrossPlatformOperations.ApplyXdeltaPatch(workingDir + "/data.win", dataPath + "/droid.xdelta", workingDir + "/game.droid"); CrossPlatformOperations.ApplyXdeltaPatch(workingDir + "/data.win", dataPath + "/droid.xdelta", workingDir + "/game.droid");
Log.Info("game.droid successfully patched."); log.Info("game.droid successfully patched.");
progress.Report(56); progress.Report(56);
// Delete unnecessary files // Delete unnecessary files
@ -410,12 +411,12 @@ namespace AM2RLauncher.Core
string apktoolText = File.ReadAllText(workingDir + "/../apktool.yml"); string apktoolText = File.ReadAllText(workingDir + "/../apktool.yml");
apktoolText = apktoolText.Replace("doNotCompress:", "doNotCompress:\n- ogg"); apktoolText = apktoolText.Replace("doNotCompress:", "doNotCompress:\n- ogg");
File.WriteAllText(workingDir + "/../apktool.yml", apktoolText); File.WriteAllText(workingDir + "/../apktool.yml", apktoolText);
Log.Info("Unnecessary files removed, apktool.yml modified to prevent ogg compression."); log.Info("Unnecessary files removed, apktool.yml modified to prevent ogg compression.");
progress.Report(70); progress.Report(70);
// Rebuild APK // Rebuild APK
CrossPlatformOperations.RunJavaJar("\"" + apktoolPath + "\" b AM2RWrapper -o \"" + profile.Name + ".apk\"", tempDir); CrossPlatformOperations.RunJavaJar("\"" + apktoolPath + "\" b AM2RWrapper -o \"" + profile.Name + ".apk\"", tempDir);
Log.Info("AM2RWrapper rebuilt into " + profile.Name + ".apk."); log.Info("AM2RWrapper rebuilt into " + profile.Name + ".apk.");
progress.Report(84); progress.Report(84);
// Debug-sign APK // Debug-sign APK
@ -423,12 +424,12 @@ namespace AM2RLauncher.Core
// Extra file cleanup // Extra file cleanup
File.Copy(tempDir + "/" + profile.Name + "-aligned-debugSigned.apk", CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk", true); File.Copy(tempDir + "/" + profile.Name + "-aligned-debugSigned.apk", CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk", true);
Log.Info(profile.Name + ".apk signed and moved to " + CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk."); log.Info(profile.Name + ".apk signed and moved to " + CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk.");
HelperMethods.DeleteDirectory(tempDir); HelperMethods.DeleteDirectory(tempDir);
// Done // Done
progress.Report(100); progress.Report(100);
Log.Info("Successfully created Android APK for profile " + profile.Name + "."); log.Info("Successfully created Android APK for profile " + profile.Name + ".");
CrossPlatformOperations.OpenFolderAndSelectFile(CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk"); CrossPlatformOperations.OpenFolderAndSelectFile(CrossPlatformOperations.CURRENTPATH + "/" + profile.Name + ".apk");
} }
@ -443,7 +444,7 @@ namespace AM2RLauncher.Core
DirectoryInfo logDir = new DirectoryInfo(savePath + "/logs"); DirectoryInfo logDir = new DirectoryInfo(savePath + "/logs");
string date = String.Join("-", DateTime.Now.ToString().Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)); string date = String.Join("-", DateTime.Now.ToString().Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));
Log.Info("Launching game profile " + profile.Name + "."); log.Info("Launching game profile " + profile.Name + ".");
if (OS.IsWindows) 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 save path/logs and create time based logs. Creates the folder if necessary.
@ -452,7 +453,7 @@ namespace AM2RLauncher.Core
// Game logging // Game logging
if (useLogging) if (useLogging)
{ {
Log.Info("Performing logging setup for profile " + profile.Name + "."); log.Info("Performing logging setup for profile " + profile.Name + ".");
if (!Directory.Exists(logDir.FullName)) if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName); Directory.CreateDirectory(logDir.FullName);
@ -464,7 +465,7 @@ namespace AM2RLauncher.Core
stream.WriteLine("AM2RLauncher " + Core.VERSION + " log generated at " + date); stream.WriteLine("AM2RLauncher " + Core.VERSION + " log generated at " + date);
if (Core.isThisRunningFromWine) if (Core.IsThisRunningFromWine)
stream.WriteLine("Using WINE!"); stream.WriteLine("Using WINE!");
stream.Flush(); stream.Flush();
@ -480,20 +481,19 @@ namespace AM2RLauncher.Core
proc.FileName = proc.WorkingDirectory + "/AM2R.exe"; proc.FileName = proc.WorkingDirectory + "/AM2R.exe";
proc.Arguments = arguments; proc.Arguments = arguments;
Log.Info("CWD of Profile is " + proc.WorkingDirectory); log.Info("CWD of Profile is " + proc.WorkingDirectory);
using (var p = Process.Start(proc)) using var p = Process.Start(proc);
{
Core.SetForegroundWindow(p.MainWindowHandle); Core.SetForegroundWindow(p.MainWindowHandle);
p.WaitForExit(); p.WaitForExit();
} }
}
else if (OS.IsLinux) else if (OS.IsLinux)
{ {
ProcessStartInfo startInfo = new ProcessStartInfo(); ProcessStartInfo startInfo = new ProcessStartInfo();
Log.Info("Is the environment textbox null or whitespace = " + String.IsNullOrWhiteSpace(envVars)); log.Info("Is the environment textbox null or whitespace = " + String.IsNullOrWhiteSpace(envVars));
//TODO: make this more readable at one day
if (!String.IsNullOrWhiteSpace(envVars)) if (!String.IsNullOrWhiteSpace(envVars))
{ {
for (int i = 0; i < envVars.Count(f => f == '='); i++) for (int i = 0; i < envVars.Count(f => f == '='); i++)
@ -503,7 +503,7 @@ namespace AM2RLauncher.Core
envVars = envVars.Replace(variable + "=", ""); envVars = envVars.Replace(variable + "=", "");
// This thing here is the value parser. Since values are sometimes in quotes, i need to compensate for them. // This thing here is the value parser. Since values are sometimes in quotes, i need to compensate for them.
int valueSubstringLength = 0; 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[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) if (envVars.IndexOf(' ') >= 0)
@ -523,7 +523,7 @@ namespace AM2RLauncher.Core
string value = envVars.Substring(0, valueSubstringLength); string value = envVars.Substring(0, valueSubstringLength);
envVars = envVars.Substring(value.Length); envVars = envVars.Substring(value.Length);
Log.Info("Adding variable \"" + variable + "\" with value \"" + value + "\""); log.Info("Adding variable \"" + variable + "\" with value \"" + value + "\"");
startInfo.EnvironmentVariables[variable] = value; startInfo.EnvironmentVariables[variable] = value;
} }
} }
@ -535,12 +535,12 @@ namespace AM2RLauncher.Core
startInfo.WorkingDirectory = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; startInfo.WorkingDirectory = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name;
startInfo.FileName = startInfo.WorkingDirectory + "/AM2R.AppImage"; startInfo.FileName = startInfo.WorkingDirectory + "/AM2R.AppImage";
Log.Info("CWD of Profile is " + startInfo.WorkingDirectory); log.Info("CWD of Profile is " + startInfo.WorkingDirectory);
Log.Info("Launching game with following variables: "); log.Info("Launching game with following variables: ");
foreach (System.Collections.DictionaryEntry item in startInfo.EnvironmentVariables) foreach (System.Collections.DictionaryEntry item in startInfo.EnvironmentVariables)
{ {
Log.Info("Key: \"" + item.Key + "\" Value: \"" + item.Value + "\""); log.Info("Key: \"" + item.Key + "\" Value: \"" + item.Value + "\"");
} }
using (Process p = new Process()) using (Process p = new Process())
@ -549,10 +549,10 @@ namespace AM2RLauncher.Core
if (useLogging) if (useLogging)
{ {
p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardOutput = true;
p.OutputDataReceived += (sender, e) => { terminalOutput += e.Data + "\n"; }; p.OutputDataReceived += (_, e) => { terminalOutput += e.Data + "\n"; };
p.StartInfo.RedirectStandardError = true; p.StartInfo.RedirectStandardError = true;
p.ErrorDataReceived += (sender, e) => { terminalOutput += e.Data + "\n"; }; p.ErrorDataReceived += (_, e) => { terminalOutput += e.Data + "\n"; };
} }
p.Start(); p.Start();
@ -568,7 +568,7 @@ namespace AM2RLauncher.Core
if (terminalOutput != null) if (terminalOutput != null)
{ {
Log.Info("Performed logging setup for profile " + profile.Name + "."); log.Info("Performed logging setup for profile " + profile.Name + ".");
if (!Directory.Exists(logDir.FullName)) if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName); Directory.CreateDirectory(logDir.FullName);
@ -598,7 +598,7 @@ namespace AM2RLauncher.Core
// Game logging // Game logging
if (useLogging) if (useLogging)
{ {
Log.Info("Performing logging setup for profile " + profile.Name + "."); log.Info("Performing logging setup for profile " + profile.Name + ".");
if (!Directory.Exists(logDir.FullName)) if (!Directory.Exists(logDir.FullName))
Directory.CreateDirectory(logDir.FullName); Directory.CreateDirectory(logDir.FullName);
@ -623,17 +623,15 @@ namespace AM2RLauncher.Core
proc.FileName = "open"; proc.FileName = "open";
proc.Arguments = arguments; proc.Arguments = arguments;
Log.Info("CWD of Profile is " + proc.WorkingDirectory); log.Info("CWD of Profile is " + proc.WorkingDirectory);
using (var p = Process.Start(proc)) using var p = Process.Start(proc);
{
p?.WaitForExit(); p?.WaitForExit();
} }
}
else else
Log.Error(OS.Name + " cannot run games!"); log.Error(OS.Name + " cannot run games!");
Log.Info("Profile " + profile.Name + " process exited."); log.Info("Profile " + profile.Name + " process exited.");
} }
/// <summary> /// <summary>
@ -700,8 +698,7 @@ namespace AM2RLauncher.Core
Directory.Delete(tmpPath, true); Directory.Delete(tmpPath, true);
// If we didn't exit before, everything is fine // If we didn't exit before, everything is fine
Log.Info("AM2R_11 check successful!"); log.Info("AM2R_11 check successful!");
return IsZipAM2R11ReturnCodes.Successful; return IsZipAM2R11ReturnCodes.Successful;
} }
}
} }

@ -1,13 +1,13 @@
using System; using System;
using System.Linq; using System.Linq;
namespace AM2RLauncher.Core namespace AM2RLauncher.Core;
/// <summary>
/// Class only for providing Splashes
/// </summary>
public static class Splash
{ {
/// <summary>
/// Class only for providing Splashes
/// </summary>
public static class Splash
{
/// <summary> /// <summary>
/// Cross-Platform splash strings /// Cross-Platform splash strings
/// </summary> /// </summary>
@ -96,7 +96,7 @@ namespace AM2RLauncher.Core
/// <summary> /// <summary>
/// Combined splash strings /// Combined splash strings
/// </summary> /// </summary>
private static readonly string[] combinedSplash = combineSplashes(); private static readonly string[] combinedSplash = CombineSplashes();
/// <summary> /// <summary>
/// Get a random splash string, according to the current OS. /// Get a random splash string, according to the current OS.
@ -114,7 +114,7 @@ namespace AM2RLauncher.Core
/// Creates a string srray which is <see cref="generalSplash"/> concatonated with the splash array for the current OS /// Creates a string srray which is <see cref="generalSplash"/> concatonated with the splash array for the current OS
/// </summary> /// </summary>
/// <returns>A string array where <see cref="generalSplash"/> and the splash array for the current OS have been concatonated.</returns> /// <returns>A string array where <see cref="generalSplash"/> and the splash array for the current OS have been concatonated.</returns>
private static string[] combineSplashes() private static string[] CombineSplashes()
{ {
string[] totalSplashes; string[] totalSplashes;
if (OS.IsWindows) if (OS.IsWindows)
@ -127,5 +127,4 @@ namespace AM2RLauncher.Core
totalSplashes = generalSplash; totalSplashes = generalSplash;
return totalSplashes; return totalSplashes;
} }
}
} }

@ -2,15 +2,15 @@
using System.Linq; using System.Linq;
using System.Xml.Serialization; using System.Xml.Serialization;
namespace AM2RLauncher.Core.XML namespace AM2RLauncher.Core.XML;
/// <summary>
/// Class that handles how the Launcher settings are saved as XML. Only affects Linux
/// </summary>
[Serializable]
[XmlRoot("settings")]
public class LauncherConfigXML
{ {
/// <summary>
/// Class that handles how the Launcher settings are saved as XML. Only affects Linux
/// </summary>
[Serializable]
[XmlRoot("settings")]
public class LauncherConfigXML
{
/// <summary>Indicates wether or not to auto-update the Launcher. Used for <see cref="MainForm.autoUpdateAM2RCheck"/></summary> /// <summary>Indicates wether or not to auto-update the Launcher. Used for <see cref="MainForm.autoUpdateAM2RCheck"/></summary>
[XmlAttribute("AutoUpdateAM2R")] [XmlAttribute("AutoUpdateAM2R")]
public bool AutoUpdateAM2R public bool AutoUpdateAM2R
@ -150,5 +150,4 @@ namespace AM2RLauncher.Core.XML
Height = height; Height = height;
IsMaximized = isMaximized; IsMaximized = isMaximized;
} }
}
} }

@ -1,15 +1,15 @@
using System; using System;
using System.Xml.Serialization; using System.Xml.Serialization;
namespace AM2RLauncher.Core.XML namespace AM2RLauncher.Core.XML;
/// <summary>
/// Class that handles how the mod settings are saved as XML.
/// </summary>
[Serializable]
[XmlRoot("message")]
public class ProfileXML
{ {
/// <summary>
/// Class that handles how the mod settings are saved as XML.
/// </summary>
[Serializable]
[XmlRoot("message")]
public class ProfileXML
{
/// <summary>Indicates the Operating system the mod was made for.</summary> /// <summary>Indicates the Operating system the mod was made for.</summary>
[XmlAttribute("OperatingSystem")] [XmlAttribute("OperatingSystem")]
public string OperatingSystem public string OperatingSystem
@ -95,5 +95,4 @@ namespace AM2RLauncher.Core.XML
Installable = installable; Installable = installable;
ProfileNotes = profileNotes; ProfileNotes = profileNotes;
} }
}
} }

@ -2,13 +2,13 @@
using System.IO; using System.IO;
using System.Text; using System.Text;
namespace AM2RLauncher.Core.XML namespace AM2RLauncher.Core.XML;
/// <summary>
/// The <c>Serializer</c> class, that serializes to and deserializes from XML files.
/// </summary>
public static class Serializer
{ {
/// <summary>
/// The <c>Serializer</c> class, that serializes to and deserializes from XML files.
/// </summary>
public static class Serializer
{
/// <summary> /// <summary>
/// Serializes <paramref name="item"/> as a <typeparamref name="T"/> to XML. /// Serializes <paramref name="item"/> as a <typeparamref name="T"/> to XML.
/// </summary> /// </summary>
@ -42,11 +42,8 @@ namespace AM2RLauncher.Core.XML
public static T Deserialize<T>(string xmlString) public static T Deserialize<T>(string xmlString)
{ {
Type t = typeof(T); Type t = typeof(T);
using (MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString))) using MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
{
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(t); System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(t);
return (T)serializer.Deserialize(memStream); return (T)serializer.Deserialize(memStream);
} }
}
}
} }
Loading…
Cancel
Save