diff --git a/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs b/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs index 911dc12..a42ff54 100644 --- a/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs +++ b/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs @@ -18,7 +18,7 @@ namespace AM2RLauncher // Auto updating is fun! /// The Version that identifies this current release. - public const string VERSION = Core.Core.VERSION; + public const string VERSION = Core.Core.Version; /// The Path of the oldConfig. Only gets used Windows-only private static readonly string oldConfigPath = CrossPlatformOperations.CURRENTPATH + "/" + CrossPlatformOperations.LAUNCHERNAME + ".oldCfg"; diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs index 7758c20..0df1747 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs @@ -29,94 +29,6 @@ namespace AM2RLauncher /// private static bool isGitProcessGettingCancelled = false; - /// - /// After the has bee loaded, git pull if a repo has been cloned already. - /// - private async void PlayButtonLoadComplete(object sender, EventArgs e) - { - LoadProfilesAndAdjustLists(); - if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked) - return; - - SetPlayButtonState(PlayButtonState.Downloading); - - progressBar.Visible = true; - progressLabel.Visible = true; - progressBar.Value = 0; - - // Try to pull first. - try - { - log.Info("Attempting to pull repository " + currentMirror + "..."); - await Task.Run(() => Profile.PullPatchData(TransferProgressHandlerMethod)); - - // Thank you druid, for this case that should never happen - if (!File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")) - { - log.Error("Druid PatchData corruption occurred!"); - await Application.Instance.InvokeAsync(() => - { - MessageBox.Show(this, Text.CorruptPatchData, Text.ErrorWindowTitle, MessageBoxType.Error); - }); - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); - return; - } - } - catch (UserCancelledException ex) - { - log.Info(ex.Message); - MessageBox.Show(this, Text.CorruptPatchData, Text.ErrorWindowTitle, MessageBoxType.Error); - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); - } - catch (LibGit2SharpException ex) // This is for any exceptions from libgit - { - // Libgit2sharp error messages are always in english! - if (ex.Message.ToLower().Contains("failed to send request") || ex.Message.ToLower().Contains("connection with the server was terminated") || - ex.Message.ToLower().Contains("failed to resolve address")) - { - if (!(bool)autoUpdateAM2RCheck.Checked) - { - log.Error("Internet connection failed while attempting to pull repository" + currentMirror + "!"); - MessageBox.Show(this, Text.InternetConnectionDrop, Text.WarningWindowTitle, MessageBoxType.Warning); - } - } - else - { - log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); - MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); - } - } - catch (Exception ex) // This is if somehow any other exception might get thrown as well. - { - log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); - MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); - } - finally - { - progressBar.Visible = false; - progressLabel.Visible = false; - LoadProfilesAndAdjustLists(); - } - - // Handling for updates - if current version does not match PatchData version, rename folder so that we attempt to install! - // Also, add a non-installable profile for it so people can access the older version or delete it from the mod manager. - if (profileList.Count > 0 && Profile.IsProfileInstalled(profileList[0])) - { - ProfileXML currentXML = Serializer.Deserialize(File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/Profiles/Community Updates (Latest)/profile.xml")); - - if (currentXML.Version != profileList[0].Version) - { - log.Info("New game version (" + profileList[0].Version + ") detected! Beginning archival of version " + currentXML.Version + "..."); - Profile.ArchiveProfile(currentXML); - profileDropDown.SelectedIndex = 0; - LoadProfilesAndAdjustLists(); - } - } - - SetPlayButtonState(PlayButtonState.Install); - UpdateStateMachine(); - } - #region Misc events /// @@ -142,6 +54,10 @@ namespace AM2RLauncher /// private void DrawablePaintEvent(object sender, PaintEventArgs e) { + // Exit if sender is not a Drawable + Drawable drawable = sender as Drawable; + if (drawable == null) return; + // Get drawing variables float height = drawable.Height; float width = drawable.Width; @@ -162,7 +78,7 @@ namespace AM2RLauncher /// 1) Writes the Width, Height, the check if is currently maximized and the ProfileIndex to the Config
/// 2) Checks if current is . If yes, it creates a Warning to the end user. /// - private void MainformClosing(object sender, CancelEventArgs e) + private void MainFormClosing(object sender, CancelEventArgs e) { log.Info("Attempting to close MainForm!"); @@ -218,6 +134,89 @@ namespace AM2RLauncher #region MAIN TAB + /// + /// After the has been loaded, git pull if a repo has been cloned already. + /// + private async void PlayButtonLoadComplete(object sender, EventArgs e) + { + //Only pull if Patchdata is cloned and user wants it updated + LoadProfilesAndAdjustLists(); + if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked) + return; + + SetPlayButtonState(PlayButtonState.Downloading); + EnableProgressBarAndLabel(); + + // Try to pull + try + { + log.Info("Attempting to pull repository " + currentMirror + "..."); + await Task.Run(() => Profile.PullPatchData(TransferProgressHandlerMethod)); + } + catch (UserCancelledException ex) + { + // TODO: why do we delete patchdata if user cancels pulling? + log.Info(ex.Message); + MessageBox.Show(this, Text.CorruptPatchData, Text.ErrorWindowTitle, MessageBoxType.Error); + HelperMethods.DeleteDirectory(Core.Core.PatchDataPath); + } + // This is for any exceptions from libgit + catch (LibGit2SharpException ex) + { + string errMessage = ex.Message.ToLower(); + // Libgit2sharp error messages are always in english! + // If internet connection suddenly dropped or site not reachable + if (errMessage.Contains("failed to send request") || errMessage.Contains("connection with the server was terminated") || + errMessage.Contains("failed to resolve address")) + { + log.Error("Internet connection failed while attempting to pull repository" + currentMirror + "!"); + MessageBox.Show(this, Text.InternetConnectionDrop, Text.WarningWindowTitle, MessageBoxType.Warning); + } + // Error message on protected folders. See this for more info: https://docs.microsoft.com/en-us/microsoft-365/security/defender-endpoint/controlled-folders + else if (errMessage.Contains("access is denied")) + { + // Needs localizable text, logging and message box + // Also, check if this is the right place for it. + throw new NotImplementedException(); + } + else + { + log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); + MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); + } + } + // This is if somehow any other exception might get thrown as well. + catch (Exception ex) + { + log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); + MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); + } + // At the end of everything, reset progressBar controls + finally + { + DisableProgressBarAndProgressLabel(); + LoadProfilesAndAdjustLists(); + } + + // Handling for updates - if current version does not match PatchData version, rename folder so that we attempt to install! + // Also, add a non-installable profile for it so people can access the older version or delete it from the mod manager. + if ((profileList.Count > 0) && Profile.IsProfileInstalled(profileList[0])) + { + ProfileXML installedUpdatesProfile = Serializer.Deserialize(File.ReadAllText(Core.Core.ProfilesPath + "/Community Updates (Latest)/profile.xml")); + + if (installedUpdatesProfile.Version != profileList[0].Version) + { + log.Info("New game version (" + profileList[0].Version + ") detected! Beginning archival of version " + installedUpdatesProfile.Version + "..."); + Profile.ArchiveProfile(installedUpdatesProfile); + profileDropDown.SelectedIndex = 0; + LoadProfilesAndAdjustLists(); + } + } + + SetPlayButtonState(PlayButtonState.Install); + UpdateStateMachine(); + } + /// /// Does a bunch of stuff, depending on the current state of . /// @@ -237,37 +236,34 @@ namespace AM2RLauncher log.Info("Attempting to clone repository " + currentMirror + "..."); bool successful = true; - // Update playButton states + // Update playButton states and progress controls SetPlayButtonState(PlayButtonState.Downloading); - - // Enable progressBar - progressBar.Visible = true; - progressLabel.Visible = true; - progressBar.Value = 0; + EnableProgressBarAndLabel(); // Set up progressBar update method - var c = new CloneOptions - { - OnTransferProgress = TransferProgressHandlerMethod - }; + CloneOptions cloneOptions = new CloneOptions { OnTransferProgress = TransferProgressHandlerMethod }; - // Everything after this is on a different thread, so the rest of the launcher isn't locked up. + // Try to clone try { - if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData")) + // Cleanup invalid PatchData directory if it exists + if (Directory.Exists(Core.Core.PatchDataPath)) { log.Info("PatchData directory already exists, cleaning up..."); - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); + HelperMethods.DeleteDirectory(Core.Core.PatchDataPath); } - await Task.Run(() => Repository.Clone(currentMirror, CrossPlatformOperations.CURRENTPATH + "/PatchData", c)); + // Separate thread so launcher doesn't get locked + await Task.Run(() => Repository.Clone(currentMirror, Core.Core.PatchDataPath, cloneOptions)); } + // We deliberately cancelled this, so no error handling catch (UserCancelledException) { - // We deliberately cancelled this! successful = false; } - catch (LibGit2SharpException ex) // This is for any exceptions from libgit + //TODO: this is currently copy-pasted with the PullPatchData method. put this into a separate method. + // For any exceptions from libgit + catch (LibGit2SharpException ex) { // Libgit2sharp error messages are always in english! if (ex.Message.ToLower().Contains("failed to send request") || ex.Message.ToLower().Contains("connection with the server was terminated") || @@ -280,18 +276,19 @@ namespace AM2RLauncher { log.Error("LibGit2SharpException: " + ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); - if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData")) - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); + if (Directory.Exists(Core.Core.PatchDataPath)) + HelperMethods.DeleteDirectory(Core.Core.PatchDataPath); } successful = false; } - catch (Exception ex) // This is if somehow any other exception might get thrown as well. + // This is if somehow any other exception might get thrown as well. + catch (Exception ex) { log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + " / PatchData")) - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); + HelperMethods.DeleteDirectory(Core.Core.PatchDataPath); successful = false; } @@ -300,10 +297,7 @@ namespace AM2RLauncher currentGitObject = 0; // Reset progressBar after clone is finished - progressLabel.Visible = false; - progressLabel.Text = ""; - progressBar.Visible = false; - progressBar.Value = 0; + DisableProgressBarAndProgressLabel(); // Just need to switch this to anything that isn't an "active" state so SetUpdateState() actually does something SetPlayButtonState(PlayButtonState.Install); @@ -320,13 +314,14 @@ namespace AM2RLauncher #region Downloading case PlayButtonState.Downloading: - var result = MessageBox.Show(this, Text.CloseOnCloningText, Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); + DialogResult result = MessageBox.Show(this, Text.CloseOnCloningText, Text.WarningWindowTitle, MessageBoxButtons.YesNo, + MessageBoxType.Warning, MessageBoxDefaultButton.No); if (result != DialogResult.Yes) return; - + log.Info("User cancelled download!"); isGitProcessGettingCancelled = true; - + // We don't need to delete any folders here, the cancelled gitClone will do that automatically for us :) // But we should probably wait a bit before proceeding, since cleanup can take a while Thread.Sleep(1000); @@ -341,7 +336,6 @@ namespace AM2RLauncher log.Info("Requesting user input for AM2R_11.zip..."); OpenFileDialog fileFinder = GetSingleZipDialog(Text.Select11FileDialog); - if (fileFinder.ShowDialog(this) != DialogResult.Ok) { log.Info("User cancelled the selection."); @@ -349,7 +343,7 @@ namespace AM2RLauncher } // Default filename is whitespace - if (String.IsNullOrWhiteSpace(fileFinder.FileName)) + if (String.IsNullOrWhiteSpace(fileFinder.FileName)) { log.Error("User did not supply valid input. Cancelling import."); return; @@ -359,7 +353,7 @@ namespace AM2RLauncher if (!File.Exists(fileFinder.FileName)) { log.Error("Selected AM2R_11.zip file not found! Cancelling import."); - break; + return; } IsZipAM2R11ReturnCodes errorCode = Profile.CheckIfZipIsAM2R11(fileFinder.FileName); @@ -371,19 +365,17 @@ namespace AM2RLauncher } // We check if it exists first, because someone coughDRUIDcough might've copied it into here while on the showDialog - if (fileFinder.FileName != CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") - File.Copy(fileFinder.FileName, CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip"); + if (fileFinder.FileName != Core.Core.AM2R11File) + File.Copy(fileFinder.FileName, Core.Core.AM2R11File); log.Info("AM2R_11.zip successfully imported."); - UpdateStateMachine(); break; #endregion #region Install case PlayButtonState.Install: - progressBar.Visible = true; - progressBar.Value = 0; + EnableProgressBar(); SetPlayButtonState(PlayButtonState.Installing); // Make sure the main interface state machines properly @@ -397,13 +389,12 @@ namespace AM2RLauncher if (OS.IsUnix && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) { MessageBox.Show(this, Text.XdeltaNotFound, Text.WarningWindowTitle, MessageBoxButtons.OK); - SetPlayButtonState(PlayButtonState.Install); UpdateStateMachine(); log.Error("Xdelta not found. Aborting installing a profile..."); return; } - var progressIndicator = new Progress(UpdateProgressBar); + Progress progressIndicator = new Progress(UpdateProgressBar); bool useHqMusic = hqMusicPCCheck.Checked.Value; await Task.Run(() => Profile.InstallProfile(profileList[profileIndex.Value], useHqMusic, progressIndicator)); // This is just for visuals because the average windows end user will ask why it doesn't go to the end otherwise. @@ -415,8 +406,7 @@ namespace AM2RLauncher log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); } - progressBar.Visible = false; - progressBar.Value = 0; + DisableProgressBar(); // Just need to switch this to anything that isn't an "active" state so SetUpdateState() actually does something SetPlayButtonState(PlayButtonState.Play); @@ -476,7 +466,7 @@ namespace AM2RLauncher // Check for java, exit safely with a warning if not found! if (!CrossPlatformOperations.IsJavaInstalled()) { - MessageBox.Show(this, Text.JavaNotFound, Text.WarningWindowTitle, MessageBoxButtons.OK); + MessageBox.Show(this, Text.JavaNotFound, Text.WarningWindowTitle, MessageBoxButtons.OK); SetApkButtonState(ApkButtonState.Create); UpdateStateMachine(); log.Error("Java not found! Aborting Android APK creation."); @@ -496,25 +486,25 @@ namespace AM2RLauncher UpdateStateMachine(); if (apkButtonState != ApkButtonState.Create) return; - + SetApkButtonState(ApkButtonState.Creating); UpdateStateMachine(); - progressBar.Visible = true; + EnableProgressBar(); bool useHqMusic = hqMusicAndroidCheck.Checked.Value; - var progressIndicator = new Progress(UpdateProgressBar); + Progress progressIndicator = new Progress(UpdateProgressBar); await Task.Run(() => Profile.CreateAPK(profileList[profileIndex.Value], useHqMusic, progressIndicator)); SetApkButtonState(ApkButtonState.Create); - progressBar.Visible = false; + DisableProgressBar(); UpdateStateMachine(); } /// Gets called when user selects a different item from and changes accordingly. private void ProfileDropDownSelectedIndexChanged(object sender, EventArgs e) { - if (profileDropDown.SelectedIndex == -1 && profileDropDown.Items.Count == 0) return; + if ((profileDropDown.SelectedIndex == -1) && (profileDropDown.Items.Count == 0)) return; profileIndex = profileDropDown.SelectedIndex; log.Debug("profileDropDown.SelectedIndex has been changed to " + profileIndex + "."); @@ -522,8 +512,8 @@ namespace AM2RLauncher profileAuthorLabel.Text = Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; profileVersionLabel.Text = Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; - if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" || - profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) + if ((profileDropDown.SelectedIndex != 0) && ((profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R") || + (profileList[profileDropDown.SelectedIndex].SaveLocation == "default"))) saveWarningLabel.Visible = true; else saveWarningLabel.Visible = false; @@ -617,8 +607,9 @@ namespace AM2RLauncher log.Info("Overwriting mirror in gitconfig."); // Check if the gitConfig exists, if yes regex the gitURL, and replace it with the new current Mirror. - string gitConfigPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/.git/config"; + string gitConfigPath = Core.Core.PatchDataPath + "/.git/config"; if (!File.Exists(gitConfigPath)) return; + string gitConfig = File.ReadAllText(gitConfigPath); Regex gitURLRegex = new Regex("https://.*\\.git"); Match match = gitURLRegex.Match(gitConfig); @@ -669,7 +660,7 @@ namespace AM2RLauncher log.Info("Overwriting mirror in gitconfig."); // Check if the gitConfig exists, if yes regex the gitURL, and replace it with the new current Mirror. - string gitConfigPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/.git/config"; + string gitConfigPath = Core.Core.PatchDataPath + "/.git/config"; if (!File.Exists(gitConfigPath)) return; string gitConfig = File.ReadAllText(gitConfigPath); Match match = gitURLRegex.Match(gitConfig); @@ -720,9 +711,8 @@ namespace AM2RLauncher //TODO: move most of this into AM2RLauncher.Profile? FileInfo modFile = new FileInfo(fileFinder.FileName); - string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; string modFileName = Path.GetFileNameWithoutExtension(modFile.Name); - string extractedModDir = modsDir + "/" + modFileName; + string extractedModDir = Core.Core.ModsPath + "/" + modFileName; // Check first, if the directory is already there, if yes, throw error if (Directory.Exists(extractedModDir)) @@ -805,7 +795,7 @@ namespace AM2RLauncher updateModButton.ToolTip = HelperMethods.GetText(Text.UpdateModButtonToolTip, profileName); } - profileButton.Enabled = Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileName); + profileButton.Enabled = Directory.Exists(Core.Core.ProfilesPath + "/" + profileName); profileButton.ToolTip = HelperMethods.GetText(Text.OpenProfileFolderToolTip, profileName); saveButton.Enabled = true; saveButton.ToolTip = HelperMethods.GetText(Text.OpenSaveFolderToolTip, profileName); @@ -826,7 +816,7 @@ namespace AM2RLauncher return; ProfileXML profile = profileList[modSettingsProfileDropDown.SelectedIndex]; log.Info("User opened the profile directory for profile " + profile.Name + ", which is " + profile.SaveLocation); - CrossPlatformOperations.OpenFolder(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name); + CrossPlatformOperations.OpenFolder(Core.Core.ProfilesPath + "/" + profile.Name); } /// @@ -895,9 +885,8 @@ namespace AM2RLauncher //TODO: move most of this into AM2RLauncher.Profile? FileInfo modFile = new FileInfo(fileFinder.FileName); - string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; string extractedName = Path.GetFileNameWithoutExtension(modFile.Name) + "_new"; - string extractedModDir = modsDir + "/" + extractedName; + string extractedModDir = Core.Core.ModsPath + "/" + extractedName; // If for some reason old files remain, delete them so that extraction doesn't throw if (Directory.Exists(extractedModDir)) @@ -927,7 +916,7 @@ namespace AM2RLauncher HelperMethods.DeleteDirectory(extractedModDir); return; } - + // If user doesn't want to update, cleanup DialogResult updateResult = MessageBox.Show(this, HelperMethods.GetText(Text.UpdateModWarning, currentProfile.Name), Text.WarningWindowTitle, MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); @@ -951,7 +940,7 @@ namespace AM2RLauncher DeleteProfileAndAdjustLists(currentProfile); // Rename directory to take the old one's place - string originalFolder = modsDir + "/" + Path.GetFileNameWithoutExtension(modFile.Name); + string originalFolder = Core.Core.ModsPath + "/" + Path.GetFileNameWithoutExtension(modFile.Name); Directory.Move(extractedModDir, originalFolder); // Adjust our lists so it gets recognized diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs index 443fc0f..cbd4f3d 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs @@ -84,5 +84,31 @@ namespace AM2RLauncher fileDialog.Filters.Add(new FileFilter(Text.ZipArchiveText, ".zip")); return fileDialog; } + + private void DisableProgressBar() + { + progressBar.Visible = false; + progressBar.Value = 0; + } + + private void EnableProgressBar() + { + progressBar.Visible = true; + progressBar.Value = 0; + } + + private void DisableProgressBarAndProgressLabel() + { + DisableProgressBar(); + progressLabel.Visible = false; + progressLabel.Text = ""; + } + + private void EnableProgressBarAndLabel() + { + EnableProgressBar(); + progressLabel.Visible = true; + progressLabel.Text = ""; + } } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs index 4e53564..54a8e7d 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs @@ -188,7 +188,7 @@ namespace AM2RLauncher log.Info("Start the launcher with Size: " + ClientSize.Width + ", " + ClientSize.Height); if (Boolean.Parse(CrossPlatformOperations.ReadFromConfig("IsMaximized"))) Maximize(); - drawable = new Drawable { BackgroundColor = colBGNoAlpha }; + Drawable drawable = new Drawable { BackgroundColor = colBGNoAlpha }; // Drawable paint event drawable.Paint += DrawablePaintEvent; @@ -275,7 +275,7 @@ namespace AM2RLauncher // Profiles dropdown - // Yes, we know this looks horrific on GTK. Sorry. + // Yes, we know this looks horrific on GTK. Sorry. // We're not exactly in a position to rewrite the entire DropDown object as a Drawable child, but if you want to, you're more than welcome! // Mac gets a default BackgroundColor because it looks waaaaaaay better. profileDropDown = new DropDown @@ -354,11 +354,11 @@ namespace AM2RLauncher // Version number label - Label versionLabel = new Label + Label versionLabel = new Label { Text = "v" + VERSION + (isThisRunningFromWine ? "-WINE" : ""), Width = 48, TextAlignment = TextAlignment.Right, TextColor = colGreen, - Font = new Font(SystemFont.Default, 12) + Font = new Font(SystemFont.Default, 12) }; // Tie everything together @@ -605,7 +605,7 @@ namespace AM2RLauncher mirrorDropDown = new DropDown(); mirrorDropDown.Items.AddRange(mirrorDescriptionList); // As above, find a way to get this inside the dropDown definition - mirrorIndex = (Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) < mirrorDropDown.Items.Count) ? Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) + mirrorIndex = (Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) < mirrorDropDown.Items.Count) ? Int32.Parse(CrossPlatformOperations.ReadFromConfig("MirrorIndex")) : 0; mirrorDropDown.SelectedIndex = mirrorIndex; @@ -784,7 +784,7 @@ namespace AM2RLauncher log.Info("All UI objects have been initialized, UI has been set up."); log.Info("Beginning event linkage..."); - Closing += MainformClosing; + Closing += MainFormClosing; showButton.Click += ShowButtonClick; profileDropDown.SelectedIndexChanged += ProfileDropDownSelectedIndexChanged; languageDropDown.SelectedIndexChanged += LanguageDropDownSelectedIndexChanged; @@ -858,10 +858,6 @@ namespace AM2RLauncher /// of so that Eto's annoying IListItem interface is appeased. Used for mirror name display in DropDowns. private List mirrorDescriptionList; - // UI Elements - /// The main control of the main page, used to draw the and hold the main interface. - private Drawable drawable; - /// A that acts as the main Button private ColorButton playButton; /// A which is only used for creating APK's diff --git a/AM2RLauncher/AM2RLauncherCore/Core.cs b/AM2RLauncher/AM2RLauncherCore/Core.cs index aca50d3..2beecac 100644 --- a/AM2RLauncher/AM2RLauncherCore/Core.cs +++ b/AM2RLauncher/AM2RLauncherCore/Core.cs @@ -17,17 +17,37 @@ public static class Core public static readonly ILog Log = LogManager.GetLogger(typeof(Core)); /// The Version that identifies this current release. - public const string VERSION = "2.2.0"; + public const string Version = "2.2.0"; /// - /// Checks if this is run via WINE. + /// Indicates whether or not we have established an internet connection. /// - public static readonly bool IsThisRunningFromWine = CheckIfRunFromWINE(); + public static readonly bool IsInternetThere = HelperMethods.IsConnectedToInternet(); /// - /// Indicates whether or not we have established an internet connection. + /// Path where the Launcher's PatchData folder is located. /// - public static readonly bool IsInternetThere = HelperMethods.IsConnectedToInternet(); + public static readonly string PatchDataPath = CrossPlatformOperations.CURRENTPATH + "/PatchData"; + + /// + /// Path where the AM2R_11.zip is located. + /// + public static readonly string AM2R11File = CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip"; + + /// + /// Path where the Launcher's Profiles folder is located. + /// + public static readonly string ProfilesPath = CrossPlatformOperations.CURRENTPATH + "/Profiles"; + + /// + /// Path where the Launcher's Mods folder is located. + /// + public static readonly string ModsPath = CrossPlatformOperations.CURRENTPATH + "/Mods"; + + /// + /// Checks if this is run via WINE. + /// + public static readonly bool IsThisRunningFromWine = CheckIfRunFromWINE(); /// /// Checks if this is ran from WINE @@ -35,9 +55,9 @@ public static class Core /// if run from WINE, if not. private static bool CheckIfRunFromWINE() { - if (OS.IsWindows && Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Wine") != null) + if (OS.IsWindows && (Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Wine") != null)) return true; - + return false; } diff --git a/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs b/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs index 2482028..c45837e 100644 --- a/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs +++ b/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs @@ -17,7 +17,7 @@ public static class CrossPlatformOperations /// /// The logger for , used to write any caught exceptions. /// - private static readonly ILog log = Core.Log; + private static readonly ILog log = LogManager.GetLogger(typeof(CrossPlatformOperations)); /// /// Name of the Launcher executable. @@ -410,7 +410,7 @@ public static class CrossPlatformOperations if (originalOutput == output || !File.Exists(output)) return; - + File.Delete(originalOutput); File.Move(output, originalOutput); } @@ -458,7 +458,8 @@ public static class CrossPlatformOperations /// $AM2RLAUNCHERDATA environment variable is read and folders are recursively generated. /// The current OS is checked. For Windows, the path where the executable is located will be returned.
/// For Linux, $XDG_DATA_HOME/AM2RLauncher will be returned. - /// Should $XDG_DATA_HOME be empty, it will default to $HOME/.local/share.
+ /// Should $XDG_DATA_HOME be empty, it will default to $HOME/.local/share.
+ /// For Mac, HOME/Library/AM2RLauncher" will be returned. /// The path where the executable is located will be returned. /// /// Should any errors occur, it falls down to the next step. diff --git a/AM2RLauncher/AM2RLauncherCore/Profile.cs b/AM2RLauncher/AM2RLauncherCore/Profile.cs index 270a525..77d1ca8 100644 --- a/AM2RLauncher/AM2RLauncherCore/Profile.cs +++ b/AM2RLauncher/AM2RLauncherCore/Profile.cs @@ -59,7 +59,7 @@ public static class Profile // If we have a cache, return that instead if (isAM2R11InstalledCache != null) return isAM2R11InstalledCache.Value; - string am2r11file = CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip"; + string am2r11file = Core.AM2R11File; // Return safely if file doesn't exist if (!File.Exists(am2r11file)) return false; lastAM2R11ZipMD5 = HelperMethods.CalculateMD5(am2r11file); @@ -82,15 +82,14 @@ public static class Profile private static void InvalidateAM2R11InstallCache() { // If the file exists, and its hash matches with ours, don't invalidate - if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") && - HelperMethods.CalculateMD5(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") == lastAM2R11ZipMD5) + if ((HelperMethods.CalculateMD5(Core.AM2R11File) == lastAM2R11ZipMD5)) return; isAM2R11InstalledCache = null; } /// - /// Checks if a Zip file is a valid AM2R_1.1 zip. + /// Checks if a Zip file is a valid AM2R_1.1 zip. /// /// Full Path to the Zip file to check. /// detailing the result @@ -152,35 +151,34 @@ public static class Profile ///
public static void PullPatchData(Func transferProgressHandlerMethod) { - using (var repo = new Repository(CrossPlatformOperations.CURRENTPATH + "/PatchData")) - { - // Permanently undo commits not pushed to remote - Branch originMaster = repo.Branches.ToList().FirstOrDefault(b => b.FriendlyName.Contains("origin/master") || b.FriendlyName.Contains("origin/main")); - - if (originMaster == null) - throw new UserCancelledException("Neither branch 'master' nor branch 'main' could be found! Corrupted or invalid git repo ? Deleting PatchData..."); + using Repository repo = new Repository(Core.PatchDataPath); - repo.Reset(ResetMode.Hard, originMaster.Tip); + // Throw if we neither have a master nor main branch + Branch originMaster = repo.Branches.FirstOrDefault(b => b.FriendlyName.Contains("origin/master") || b.FriendlyName.Contains("origin/main")); + if (originMaster == null) + throw new UserCancelledException("Neither branch 'master' nor branch 'main' could be found! Corrupted or invalid git repo?"); - // Credential information to fetch + // Permanently undo commits not pushed to remote + repo.Reset(ResetMode.Hard, originMaster.Tip); - PullOptions options = new PullOptions(); - options.FetchOptions = new FetchOptions(); - options.FetchOptions.OnTransferProgress += tp => transferProgressHandlerMethod(tp); + // Credential information to fetch + PullOptions options = new PullOptions + { + FetchOptions = new FetchOptions { OnTransferProgress = tp => transferProgressHandlerMethod(tp)} + }; - // User information to create a merge commit - var signature = new Signature("null", "null", DateTimeOffset.Now); + // Create dummy user information to create a merge commit + Signature signature = new Signature("null", "null", DateTimeOffset.Now); - // Pull - try - { - Commands.Pull(repo, signature, options); - } - catch - { - log.Error("Repository pull attempt failed!"); - return; - } + // Pull + try + { + Commands.Pull(repo, signature, options); + } + catch + { + log.Error("Repository pull attempt failed!"); + return; } log.Info("Repository pulled successfully."); } @@ -196,19 +194,19 @@ public static class Profile List profileList = new List(); // Check for and add the Community Updates profile - if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")) + if (File.Exists(Core.PatchDataPath + "/profile.xml")) { - ProfileXML profile = Serializer.Deserialize(File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")); + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(Core.PatchDataPath + "/profile.xml")); profile.DataPath = "/PatchData/data"; profileList.Add(profile); } // Safety check to generate the Mods folder if it does not exist - if (!Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Mods")) - Directory.CreateDirectory(CrossPlatformOperations.CURRENTPATH + "/Mods"); + if (!Directory.Exists(Core.ModsPath)) + Directory.CreateDirectory(Core.ModsPath); // Get Mods folder info - DirectoryInfo modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods"); + DirectoryInfo modsDir = new DirectoryInfo(Core.ModsPath); // Add all extracted profiles in Mods to the profileList. foreach (DirectoryInfo dir in modsDir.GetDirectories()) @@ -254,19 +252,19 @@ public static class Profile log.Info("Archiving " + profile.Name); - string profileArchivePath = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; + string profileArchivePath = Core.ProfilesPath + "/" + profile.Name; // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. if (!Directory.Exists(profileArchivePath)) { // Rename current profile if we have it installed - if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName)) - Directory.Move(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName, profileArchivePath); + if (Directory.Exists(Core.ProfilesPath + "/" + originalName)) + Directory.Move(Core.ProfilesPath + "/" + originalName, profileArchivePath); // Set as non-installable so that it's just treated as a launching reference profile.Installable = false; - string modArchivePath = CrossPlatformOperations.CURRENTPATH + "/Mods/" + profile.Name; + string modArchivePath = Core.ModsPath + "/" + profile.Name; // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. if (!Directory.Exists(modArchivePath)) @@ -284,7 +282,7 @@ public static class Profile // If our desired rename already exists, it's probably a user archive... so we just delete the original folder and move on with installation of the new version. else { - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName); + HelperMethods.DeleteDirectory(Core.ProfilesPath + "/" + originalName); log.Info("Cancelling archival! User-defined archive in Profiles already exists."); } } @@ -310,8 +308,8 @@ public static class Profile } // Delete folder in Profiles - if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name); + if (Directory.Exists(Core.ProfilesPath + "/" + profile.Name)) + HelperMethods.DeleteDirectory(Core.ProfilesPath + "/" + profile.Name); log.Info("Successfully deleted profile " + profile.Name + "."); } @@ -326,13 +324,13 @@ public static class Profile { log.Info("Installing profile " + profile.Name + "..."); - string profilesHomePath = CrossPlatformOperations.CURRENTPATH + "/Profiles"; + string profilesHomePath = Core.ProfilesPath; string profilePath = profilesHomePath + "/" + profile.Name; // Failsafe for Profiles directory if (!Directory.Exists(profilesHomePath)) Directory.CreateDirectory(profilesHomePath); - + // This failsafe should NEVER get triggered, but Miepee's broken this too much for me to trust it otherwise. if (Directory.Exists(profilePath)) Directory.Delete(profilePath, true); @@ -363,7 +361,7 @@ public static class Profile } // Extract 1.1 - ZipFile.ExtractToDirectory(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip", profilePath); + ZipFile.ExtractToDirectory(Core.AM2R11File, profilePath); // Extracted 1.1 progress.Report(33); @@ -383,7 +381,7 @@ public static class Profile { datawin = "game.unx"; // Use the exe name based on the desktop file in the AppImage, rather than hard coding it. - string desktopContents = File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir/AM2R.desktop"); + string desktopContents = File.ReadAllText(Core.PatchDataPath + "/data/AM2R.AppDir/AM2R.desktop"); exe = Regex.Match(desktopContents, @"(?<=Exec=).*").Value; log.Info("According to AppImage desktop file, using \"" + exe + "\" as game name."); } @@ -448,7 +446,7 @@ public static class Profile // HQ music if (!profile.UsesCustomMusic && useHqMusic) - HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/HDR_HQ_in-game_music", profilePath); + HelperMethods.DirectoryCopy(Core.PatchDataPath + "/data/HDR_HQ_in-game_music", profilePath); // Linux post-process @@ -463,7 +461,7 @@ public static class Profile File.Move(file.FullName, file.DirectoryName + "/" + file.Name.ToLower()); // Copy AppImage template to here - HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir", profilePath + "/AM2R.AppDir/"); + HelperMethods.DirectoryCopy(Core.PatchDataPath + "/data/AM2R.AppDir", profilePath + "/AM2R.AppDir/"); // Safety checks, in case the folders don't exist Directory.CreateDirectory(profilePath + "/AM2R.AppDir/usr/bin/"); @@ -482,7 +480,7 @@ public static class Profile Directory.SetCurrentDirectory(profilePath); Console.SetError(new StreamWriter(Stream.Null)); Environment.SetEnvironmentVariable("ARCH", "x86_64"); - Process.Start(CrossPlatformOperations.CURRENTPATH + "/PatchData/utilities/appimagetool-x86_64.AppImage", "-n AM2R.AppDir")?.WaitForExit(); + Process.Start(Core.PatchDataPath + "/utilities/appimagetool-x86_64.AppImage", "-n AM2R.AppDir")?.WaitForExit(); Directory.SetCurrentDirectory(workingDir); Console.SetError(cliError); @@ -504,9 +502,9 @@ public static class Profile if (Directory.Exists(profilePath + "/lang/fonts")) Directory.Delete(profilePath + "/lang/fonts", true); // Move Frameworks, Info.plist and PkgInfo over - HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/Frameworks", profilePath.Replace("Resources", "Frameworks")); + HelperMethods.DirectoryCopy(Core.PatchDataPath + "/data/Frameworks", profilePath.Replace("Resources", "Frameworks")); File.Copy(dataPath + "/Info.plist", profilePath.Replace("Resources", "") + "/Info.plist", true); - File.Copy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/PkgInfo", profilePath.Replace("Resources", "") + "/PkgInfo", true); + File.Copy(Core.PatchDataPath + "/data/PkgInfo", profilePath.Replace("Resources", "") + "/PkgInfo", true); //Put profilePath back to what it was before profilePath = profilesHomePath + "/" + profile.Name; } @@ -529,9 +527,9 @@ public static class Profile /// if yes, if not. public static bool IsProfileInstalled(ProfileXML profile) { - if (OS.IsWindows) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.exe"); - if (OS.IsLinux) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.AppImage"); - if (OS.IsMac) return Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.app"); + if (OS.IsWindows) return File.Exists(Core.ProfilesPath + "/" + profile.Name + "/AM2R.exe"); + if (OS.IsLinux) return File.Exists(Core.ProfilesPath + "/" + profile.Name + "/AM2R.AppImage"); + if (OS.IsMac) return Directory.Exists(Core.ProfilesPath + "/" + profile.Name + "/AM2R.app"); log.Error(OS.Name + " can't have profiles installed!"); return false; @@ -555,8 +553,8 @@ public static class Profile log.Info("Creating Android APK for profile " + profile.Name + "."); // Create working dir after some cleanup - string apktoolPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/utilities/android/apktool.jar", - uberPath = CrossPlatformOperations.CURRENTPATH + "/PatchData/utilities/android/uber-apk-signer.jar", + string apktoolPath = Core.PatchDataPath + "/utilities/android/apktool.jar", + uberPath = Core.PatchDataPath + "/utilities/android/uber-apk-signer.jar", tempDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/temp").FullName, dataPath = CrossPlatformOperations.CURRENTPATH + profile.DataPath; if (Directory.Exists(tempDir)) @@ -573,11 +571,11 @@ public static class Profile // Add datafiles: 1.1, new datafiles, hq music, am2r.ini string workingDir = tempDir + "/AM2RWrapper/assets"; - ZipFile.ExtractToDirectory(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip", workingDir); + ZipFile.ExtractToDirectory(Core.AM2R11File, workingDir); HelperMethods.DirectoryCopy(dataPath + "/files_to_copy", workingDir); if (useHqMusic) - HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/HDR_HQ_in-game_music", workingDir); + HelperMethods.DirectoryCopy(Core.PatchDataPath + "/data/HDR_HQ_in-game_music", workingDir); // Yes, I'm aware this is dumb. If you've got any better ideas for how to copy a seemingly randomly named .ini from this folder to the APK, please let me know. foreach (FileInfo file in new DirectoryInfo(dataPath).GetFiles().Where(f => f.Name.EndsWith("ini"))) File.Copy(file.FullName, workingDir + "/" + file.Name); @@ -657,7 +655,7 @@ public static class Profile StreamWriter stream = File.AppendText(logDir.FullName + "/" + profile.Name + ".txt"); - stream.WriteLine("AM2RLauncher " + Core.VERSION + " log generated at " + date); + stream.WriteLine("AM2RLauncher " + Core.Version + " log generated at " + date); if (Core.IsThisRunningFromWine) stream.WriteLine("Using WINE!"); @@ -671,7 +669,7 @@ public static class Profile ProcessStartInfo proc = new ProcessStartInfo(); - proc.WorkingDirectory = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; + proc.WorkingDirectory = Core.ProfilesPath + "/" + profile.Name; proc.FileName = proc.WorkingDirectory + "/AM2R.exe"; proc.Arguments = arguments; @@ -726,7 +724,7 @@ public static class Profile string terminalOutput = null; startInfo.UseShellExecute = false; - startInfo.WorkingDirectory = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; + startInfo.WorkingDirectory = Core.ProfilesPath + "/" + profile.Name; startInfo.FileName = startInfo.WorkingDirectory + "/AM2R.AppImage"; log.Info("CWD of Profile is " + startInfo.WorkingDirectory); @@ -773,7 +771,7 @@ public static class Profile StreamWriter stream = File.AppendText(logDir.FullName + "/" + profile.Name + ".txt"); // Write general info - stream.WriteLine("AM2RLauncher " + Core.VERSION + " log generated at " + date); + stream.WriteLine("AM2RLauncher " + Core.Version + " log generated at " + date); // Write what was in the terminal stream.WriteLine(terminalOutput); @@ -802,7 +800,7 @@ public static class Profile StreamWriter stream = File.AppendText(logDir.FullName + "/" + profile.Name + ".txt"); - stream.WriteLine("AM2RLauncher " + Core.VERSION + " log generated at " + date); + stream.WriteLine("AM2RLauncher " + Core.Version + " log generated at " + date); stream.Flush(); @@ -813,7 +811,7 @@ public static class Profile ProcessStartInfo proc = new ProcessStartInfo(); - proc.WorkingDirectory = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; + proc.WorkingDirectory = Core.ProfilesPath + "/" + profile.Name; proc.FileName = "open"; proc.Arguments = arguments; @@ -835,6 +833,6 @@ public static class Profile 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(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml") && Repository.IsValid(CrossPlatformOperations.CURRENTPATH + "/PatchData"); + return File.Exists(Core.PatchDataPath + "/profile.xml") && Repository.IsValid(Core.PatchDataPath); } } \ No newline at end of file