diff --git a/AM2RLauncher/AM2RLauncher/AM2RLauncher.csproj b/AM2RLauncher/AM2RLauncher/AM2RLauncher.csproj index a389b88..70925ba 100644 --- a/AM2RLauncher/AM2RLauncher/AM2RLauncher.csproj +++ b/AM2RLauncher/AM2RLauncher/AM2RLauncher.csproj @@ -2,6 +2,7 @@ netstandard2.0 + latest Resources\LauncherIcon.ico Lojemiru, Miepee AM2R-Community-Developers diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs b/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs index cf7163b..9be81eb 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs +++ b/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs @@ -1,9 +1,10 @@ //------------------------------------------------------------------------------ // -// This code was generated by a tool. +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 // -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. // //------------------------------------------------------------------------------ @@ -11,32 +12,46 @@ namespace AM2RLauncher.Language { using System; - [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [System.Diagnostics.DebuggerNonUserCodeAttribute()] - [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Text { - private static System.Resources.ResourceManager resourceMan; + private static global::System.Resources.ResourceManager resourceMan; - private static System.Globalization.CultureInfo resourceCulture; + private static global::System.Globalization.CultureInfo resourceCulture; - [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Text() { } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Resources.ResourceManager ResourceManager { + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { get { - if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly); + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly); resourceMan = temp; } return resourceMan; } } - [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] - public static System.Globalization.CultureInfo Culture { + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -45,538 +60,809 @@ namespace AM2RLauncher.Language { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die ABORT ähnelt. + /// public static string Abort { get { return ResourceManager.GetString("Abort", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die ADD NEW MOD ähnelt. + /// public static string AddNewMod { get { return ResourceManager.GetString("AddNewMod", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select a mod to be installed. ähnelt. + /// public static string AddNewModToolTip { get { return ResourceManager.GetString("AddNewModToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Can't create an APK. ähnelt. + /// public static string ApkButtonDisabledToolTip { get { return ResourceManager.GetString("ApkButtonDisabledToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Create an APK for $NAME ähnelt. + /// public static string ApkButtonEnabledToolTip { get { return ResourceManager.GetString("ApkButtonEnabledToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Do you want to archive $NAME? ähnelt. + /// + public static string ArchiveMod { + get { + return ResourceManager.GetString("ArchiveMod", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die This is an archive of a previously installed Community Update. It cannot be re-installed and will remove itself if its game files are deleted. It shares saves with the currently installed Community Updates, so be sure to create a backup of your saves before running this profile! ähnelt. + /// public static string ArchiveNotesCommunityUpdates { get { return ResourceManager.GetString("ArchiveNotesCommunityUpdates", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die This is an archive of a previously installed Mod. It cannot be re-installed and will remove itself if its game files are deleted. ähnelt. + /// + public static string ArchiveNotesMods { + get { + return ResourceManager.GetString("ArchiveNotesMods", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Author(s): ähnelt. + /// public static string Author { get { return ResourceManager.GetString("Author", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Automatically update AM2R ähnelt. + /// public static string AutoUpdateAM2R { get { return ResourceManager.GetString("AutoUpdateAM2R", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Automatically update the AM2RLauncher ähnelt. + /// public static string AutoUpdateLauncher { get { return ResourceManager.GetString("AutoUpdateLauncher", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Changelog ähnelt. + /// public static string ChangelogTab { get { return ResourceManager.GetString("ChangelogTab", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Are you sure you want to cancel this now? This will delete all your progress! ähnelt. + /// public static string CloseOnCloningText { get { return ResourceManager.GetString("CloseOnCloningText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Sorry, you can't close this while it's installing! Please wait until it's finished. ähnelt. + /// public static string CloseOnInstallingText { get { return ResourceManager.GetString("CloseOnInstallingText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die There was a problem with your Patchdata folder. It has been deleted, please download it again. ähnelt. + /// public static string CorruptPatchData { get { return ResourceManager.GetString("CorruptPatchData", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die CREATE APK ähnelt. + /// public static string CreateAPK { get { return ResourceManager.GetString("CreateAPK", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die CREATING APK ähnelt. + /// public static string CreatingAPK { get { return ResourceManager.GetString("CreatingAPK", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Current profile: ähnelt. + /// public static string CurrentProfile { get { return ResourceManager.GetString("CurrentProfile", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Enter custom game environment variables: ähnelt. + /// public static string CustomEnvVarLabel { get { return ResourceManager.GetString("CustomEnvVarLabel", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Use custom download mirror ähnelt. + /// public static string CustomMirrorCheck { get { return ResourceManager.GetString("CustomMirrorCheck", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME couldn't be deleted. ähnelt. + /// public static string DeleteModButtonCantDelete { get { return ResourceManager.GetString("DeleteModButtonCantDelete", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME was successfully deleted! ähnelt. + /// public static string DeleteModButtonSuccess { get { return ResourceManager.GetString("DeleteModButtonSuccess", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die DELETE MOD ähnelt. + /// public static string DeleteModButtonText { get { return ResourceManager.GetString("DeleteModButtonText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Delete $NAME. ähnelt. + /// public static string DeleteModButtonToolTip { get { return ResourceManager.GetString("DeleteModButtonToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die This will delete all files for $NAME. Are you sure you want to continue? ähnelt. + /// public static string DeleteModWarning { get { return ResourceManager.GetString("DeleteModWarning", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The Official AM2R Discord ähnelt. + /// public static string DiscordToolTip { get { return ResourceManager.GetString("DiscordToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die DOWNLOAD ähnelt. + /// public static string Download { get { return ResourceManager.GetString("Download", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die DOWNLOADING ähnelt. + /// public static string Downloading { get { return ResourceManager.GetString("Downloading", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Download source: ähnelt. + /// public static string DownloadSource { get { return ResourceManager.GetString("DownloadSource", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Error ähnelt. + /// public static string ErrorWindowTitle { get { return ResourceManager.GetString("ErrorWindowTitle", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The Community-Developers Github Page ähnelt. + /// public static string GithubToolTip { get { return ResourceManager.GetString("GithubToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Use high quality music when patching to Android ähnelt. + /// public static string HighQualityAndroid { get { return ResourceManager.GetString("HighQualityAndroid", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Use high quality music when patching to PC ähnelt. + /// public static string HighQualityPC { get { return ResourceManager.GetString("HighQualityPC", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die INSTALL ähnelt. + /// public static string Install { get { return ResourceManager.GetString("Install", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die INSTALLING ähnelt. + /// public static string Installing { get { return ResourceManager.GetString("Installing", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Couldn't establish an internet connection! Try again later! ähnelt. + /// public static string InternetConnectionDrop { get { return ResourceManager.GetString("InternetConnectionDrop", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME is an invalid git URL! ähnelt. + /// public static string InvalidGitURL { get { return ResourceManager.GetString("InvalidGitURL", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Java not found! Cannot generate an APK without a Java installation. Please make sure that Java is installed and added to PATH. ähnelt. + /// public static string JavaNotFound { get { return ResourceManager.GetString("JavaNotFound", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Launcher Language: (requires restart to take effect) ähnelt. + /// public static string LanguageNotice { get { return ResourceManager.GetString("LanguageNotice", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Settings ähnelt. + /// public static string LauncherSettingsTab { get { return ResourceManager.GetString("LauncherSettingsTab", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die GitHub (Primary) ähnelt. + /// public static string MirrorGithubText { get { return ResourceManager.GetString("MirrorGithubText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die GitLab (Mirror) ähnelt. + /// public static string MirrorGitlabText { get { return ResourceManager.GetString("MirrorGitlabText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME is already installed! ähnelt. + /// public static string ModIsAlreadyInstalledMessage { get { return ResourceManager.GetString("ModIsAlreadyInstalledMessage", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME cannot be installed! It's for $OS. Download the $CURRENTOS version instead if it exists, or ask the mod authors to make one. ähnelt. + /// public static string ModIsForWrongOS { get { return ResourceManager.GetString("ModIsForWrongOS", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME is an invalid AM2R mod! ähnelt. + /// public static string ModIsInvalidMessage { get { return ResourceManager.GetString("ModIsInvalidMessage", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Mod Settings ähnelt. + /// + public static string ModSettingsTab { + get { + return ResourceManager.GetString("ModSettingsTab", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die $NAME was successfully added! Go to the Play Tab in order to install it! ähnelt. + /// public static string ModSuccessfullyInstalledMessage { get { return ResourceManager.GetString("ModSuccessfullyInstalledMessage", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die News ähnelt. + /// public static string NewsTab { get { return ResourceManager.GetString("NewsTab", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Couldn't establish an internet connection! You can still play the game, but updates will not occur until the launcher is restarted and can connect to the internet. ähnelt. + /// public static string NoInternetConnection { get { return ResourceManager.GetString("NoInternetConnection", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die OPEN PROFILE FOLDER ähnelt. + /// public static string OpenProfileFolder { get { return ResourceManager.GetString("OpenProfileFolder", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Opens the folder where game files are located for $NAME. ähnelt. + /// public static string OpenProfileFolderToolTip { get { return ResourceManager.GetString("OpenProfileFolderToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die OPEN PROFILE SAVE FOLDER ähnelt. + /// public static string OpenSaveFolder { get { return ResourceManager.GetString("OpenSaveFolder", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Opens the folder where save files are located for $NAME. ähnelt. + /// public static string OpenSaveFolderToolTip { get { return ResourceManager.GetString("OpenSaveFolderToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die PLAY ähnelt. + /// public static string Play { get { return ResourceManager.GetString("Play", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Currently downloading . . . ähnelt. + /// public static string PlayButtonDownladingToolTip { get { return ResourceManager.GetString("PlayButtonDownladingToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Download the necessary patch files. ähnelt. + /// public static string PlayButtonDownloadToolTip { get { return ResourceManager.GetString("PlayButtonDownloadToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Currently installing. . . ähnelt. + /// public static string PlayButtonInstallingToolTip { get { return ResourceManager.GetString("PlayButtonInstallingToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Install $NAME ähnelt. + /// public static string PlayButtonInstallToolTip { get { return ResourceManager.GetString("PlayButtonInstallToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Currently already playing! ähnelt. + /// public static string PlayButtonPlayingToolTip { get { return ResourceManager.GetString("PlayButtonPlayingToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Play ähnelt. + /// public static string PlayButtonPlayToolTip { get { return ResourceManager.GetString("PlayButtonPlayToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select your AM2R_1.1.zip ähnelt. + /// public static string PlayButtonSelect11ToolTip { get { return ResourceManager.GetString("PlayButtonSelect11ToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die PLAYING ähnelt. + /// public static string Playing { get { return ResourceManager.GetString("Playing", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Play ähnelt. + /// public static string PlayTab { get { return ResourceManager.GetString("PlayTab", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Create game debug logs ähnelt. + /// public static string ProfileDebugCheckBox { get { return ResourceManager.GetString("ProfileDebugCheckBox", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Profile notes: ähnelt. + /// public static string ProfileNotes { get { return ResourceManager.GetString("ProfileNotes", resourceCulture); } } - public static string ProfileSettingsTab { - get { - return ResourceManager.GetString("ProfileSettingsTab", resourceCulture); - } - } - + /// + /// Sucht eine lokalisierte Zeichenfolge, die Progress: ähnelt. + /// public static string ProgressbarProgress { get { return ResourceManager.GetString("ProgressbarProgress", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The Official AM2R Subreddit ähnelt. + /// public static string RedditToolTip { get { return ResourceManager.GetString("RedditToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die WARNING: This profile uses the default save location! This could corrupt your save data - please ensure that you have made a backup. ähnelt. + /// public static string SaveLocationWarning { get { return ResourceManager.GetString("SaveLocationWarning", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die SELECT AM2R_1.1.zip ähnelt. + /// public static string Select11 { get { return ResourceManager.GetString("Select11", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select AM2R_1.1.zip ähnelt. + /// public static string Select11FileDialog { get { return ResourceManager.GetString("Select11FileDialog", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select your Mod ähnelt. + /// public static string SelectModFileDialog { get { return ResourceManager.GetString("SelectModFileDialog", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Success ähnelt. + /// public static string SuccessWindowTitle { get { return ResourceManager.GetString("SuccessWindowTitle", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die System Language ähnelt. + /// public static string SystemLanguage { get { return ResourceManager.GetString("SystemLanguage", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Show Launcher ähnelt. + /// public static string TrayButtonShow { get { return ResourceManager.GetString("TrayButtonShow", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Can't access the Folder in order to download the update! Consider moving the program, or disabling auto-updates. ähnelt. + /// public static string UnauthorizedAccessMessage { get { return ResourceManager.GetString("UnauthorizedAccessMessage", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Unhandled Exception has occured in your Application. ähnelt. + /// public static string UnhandledException { get { return ResourceManager.GetString("UnhandledException", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select Mod Update ähnelt. + /// public static string UpdateMod { get { return ResourceManager.GetString("UpdateMod", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die UPDATE MOD ähnelt. + /// public static string UpdateModButtonText { get { return ResourceManager.GetString("UpdateModButtonText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Select a zip to update $NAME. ähnelt. + /// public static string UpdateModButtonToolTip { get { return ResourceManager.GetString("UpdateModButtonToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Can't update $NAME with $SELECT. Add $SELECT as a new mod instead! ähnelt. + /// public static string UpdateModButtonWrongMod { get { return ResourceManager.GetString("UpdateModButtonWrongMod", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die This will replace all files for $NAME with the selected new version. Are you sure you want to continue? ähnelt. + /// public static string UpdateModWarning { get { return ResourceManager.GetString("UpdateModWarning", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Version: ähnelt. + /// public static string VersionLabel { get { return ResourceManager.GetString("VersionLabel", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt. + /// public static string WarningWindowOk { get { return ResourceManager.GetString("WarningWindowOk", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The AM2RLauncher can NOT validate custom mirror links. + /// + ///If somebody is telling you to paste a link in this field, they may be trying to infect your computer. + /// + ///Proceed with caution. ähnelt. + /// public static string WarningWindowText { get { return ResourceManager.GetString("WarningWindowText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die WARNING ähnelt. + /// public static string WarningWindowTitle { get { return ResourceManager.GetString("WarningWindowTitle", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Xdelta not found! Cannot install Profiles without it. Please install xdelta3 from your local package manager. ähnelt. + /// public static string XdeltaNotFound { get { return ResourceManager.GetString("XdeltaNotFound", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The Community-Developers YouTube Channel ähnelt. + /// public static string YoutubeToolTip { get { return ResourceManager.GetString("YoutubeToolTip", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die Zip Archives (*.zip) ähnelt. + /// public static string ZipArchiveText { get { return ResourceManager.GetString("ZipArchiveText", resourceCulture); } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die The selected Zip is not AM2R 1.1! Please choose another Zip file. ähnelt. + /// public static string ZipIsNotAM2R11 { get { return ResourceManager.GetString("ZipIsNotAM2R11", resourceCulture); } } - - public static string ArchiveMod { - get { - return ResourceManager.GetString("ArchiveMod", resourceCulture); - } - } - - public static string ArchiveNotesMods { - get { - return ResourceManager.GetString("ArchiveNotesMods", resourceCulture); - } - } } } diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.de.resx b/AM2RLauncher/AM2RLauncher/Language/Text.de.resx index 7afcf65..e85bf93 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.de.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.de.resx @@ -303,7 +303,7 @@ Profilnotizen: - + Mod-Einstellungen diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.es.resx b/AM2RLauncher/AM2RLauncher/Language/Text.es.resx index e87658f..792fdef 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.es.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.es.resx @@ -303,7 +303,7 @@ Anotaciones del Perfil: - + Opciones de mods diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx b/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx index ce46b2c..8e96f44 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx @@ -305,7 +305,7 @@ ce profil ! Notes de profil : - + Paramètres du mod diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.it.resx b/AM2RLauncher/AM2RLauncher/Language/Text.it.resx index a2b4aab..2dc3ba2 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.it.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.it.resx @@ -303,7 +303,7 @@ Note di profilo: - + Impostazioni mod diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx b/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx index e1997f4..bfe6dcb 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx @@ -303,7 +303,7 @@ プロファイルの注釈: - + MOD設定 diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx b/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx index b790b60..1181924 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx @@ -300,7 +300,7 @@ Notas do perfil: - + Configurações de mod diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.resx b/AM2RLauncher/AM2RLauncher/Language/Text.resx index 85a2c55..93defbd 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.resx @@ -303,7 +303,7 @@ Profile notes: - + Mod Settings diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx b/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx index 9059258..67d709d 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx @@ -303,7 +303,7 @@ Заметки профиля: - + Настройки модификаций diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx b/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx index 22c5e72..4fe06ef 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx @@ -303,7 +303,7 @@ 游戏实例说明: - + Mod 设置 diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs index 6f87feb..7328a95 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs @@ -1,5 +1,6 @@ using AM2RLauncher.Core; using AM2RLauncher.Core.XML; +using AM2RLauncher.Language; using Eto.Forms; using LibGit2Sharp; using System; @@ -13,6 +14,8 @@ using System.Threading.Tasks; namespace AM2RLauncher { + //TODO: comment a bunch of this stuf for readability + /// /// Methods for UI Events that get triggered go in here /// @@ -35,7 +38,7 @@ namespace AM2RLauncher if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked) return; - SetPlayButtonState(UpdateState.Downloading); + SetPlayButtonState(PlayButtonState.Downloading); progressBar.Visible = true; progressLabel.Visible = true; @@ -53,7 +56,7 @@ namespace AM2RLauncher log.Error("Druid PatchData corruption occurred!"); await Application.Instance.InvokeAsync(() => { - MessageBox.Show(Language.Text.CorruptPatchData, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + MessageBox.Show(this, Text.CorruptPatchData, Text.ErrorWindowTitle, MessageBoxType.Error); }); HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); return; @@ -62,7 +65,7 @@ namespace AM2RLauncher catch (UserCancelledException ex) { log.Info(ex.Message); - MessageBox.Show(Language.Text.CorruptPatchData, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + MessageBox.Show(this, Text.CorruptPatchData, Text.ErrorWindowTitle, MessageBoxType.Error); HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/PatchData"); } catch (LibGit2SharpException ex) // This is for any exceptions from libgit @@ -74,19 +77,19 @@ namespace AM2RLauncher if (!(bool)autoUpdateAM2RCheck.Checked) { log.Error("Internet connection failed while attempting to pull repository" + currentMirror + "!"); - MessageBox.Show(Language.Text.InternetConnectionDrop, Language.Text.WarningWindowTitle, MessageBoxType.Warning); + MessageBox.Show(this, Text.InternetConnectionDrop, Text.WarningWindowTitle, MessageBoxType.Warning); } } else { log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); - MessageBox.Show(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + 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(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); } finally { @@ -110,10 +113,111 @@ namespace AM2RLauncher } } - SetPlayButtonState(UpdateState.Install); + SetPlayButtonState(PlayButtonState.Install); UpdateStateMachine(); } + #region Misc events + + /// + /// Fires when the profile layout completes loading. This makes sure that if has nothing in it "on boot", + /// that everything is disabled. + /// + private void ProfileLayoutLoadComplete(object sender, EventArgs e) + { + // Safety check + if ((modSettingsProfileDropDown == null) || (modSettingsProfileDropDown.Items.Count != 0)) return; + addModButton.Enabled = false; + settingsProfileLabel.TextColor = colInactive; + modSettingsProfileDropDown.Enabled = false; + profileButton.Enabled = false; + saveButton.Enabled = false; + updateModButton.Enabled = false; + deleteModButton.Enabled = false; + profileNotesTextArea.TextColor = colInactive; + } + + /// + /// The calls this when you're resizing, in order to resize and scale the application accordingly. + /// + private void DrawablePaintEvent(object sender, PaintEventArgs e) + { + // Get drawing variables + float height = drawable.Height; + float width = drawable.Width; + //TODO: apparently winforms is the big outlier here. Works normal on wpf, I have *no* idea why, seems related to our image. issue has been submitted at eto + float scaleDivisor = OS.IsWindows ? formBG.Width : formBG.Height; + + float scale = height / scaleDivisor; + + // Do the actual scaling + e.Graphics.ScaleTransform(scale); + + // Draw the image, change x offset with some absurd wizardry written at 5 AM + e.Graphics.DrawImage(formBG, ((width / 2) - (height / 1.4745f)) / scale, 0); + } + + /// + /// Gets called when user tries to close . This does a few things:
+ /// 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) + { + log.Info("Attempting to close MainForm!"); + + CrossPlatformOperations.WriteToConfig("Width", ClientSize.Width); + CrossPlatformOperations.WriteToConfig("Height", ClientSize.Height); + CrossPlatformOperations.WriteToConfig("IsMaximized", this.WindowState == WindowState.Maximized); + CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString()); + + switch (updateState) + { + // If we're currently still downloading, ask first if user really wants to close and cancel the event if necessary + case PlayButtonState.Downloading: + { + var result = MessageBox.Show(this, Text.CloseOnCloningText, Text.WarningWindowTitle, MessageBoxButtons.YesNo, + MessageBoxType.Warning, MessageBoxDefaultButton.No); + + if (result == DialogResult.No) + e.Cancel = true; + else + isGitProcessGettingCancelled = true; + // We don't need to delete any folders here, the cancelled gitClone will do that automatically for us :) + break; + } + // We can't close during installing, so we cancel the event. + case PlayButtonState.Installing: + { + MessageBox.Show(this, Text.CloseOnInstallingText, Text.WarningWindowTitle, MessageBoxButtons.OK, MessageBoxType.Warning); + e.Cancel = true; + break; + } + } + + // This needs to be made invisible, otherwise a tray indicator will be visible (on linux?) that clicking crashes the application + //TODO: this sounds like an eto bug. check if this can get reproduced. + trayIndicator.Visible = false; + + if (e.Cancel) + log.Info("Cancelled MainForm closing event during UpdateState." + updateState + "."); + else + log.Info("Successfully closed MainForm. Exiting main thread."); + } + + /// Gets called when gets clicked and shows the and brings it to the front again. + private void ShowButtonClick(object sender, EventArgs e) + { + log.Info("User has opened the launcher from system tray."); + + this.Show(); + this.BringToFront(); + } + + #endregion + + #region MAIN TAB + /// /// Does a bunch of stuff, depending on the current state of . /// @@ -128,13 +232,13 @@ namespace AM2RLauncher switch (updateState) { #region Download - case UpdateState.Download: + case PlayButtonState.Download: log.Info("Attempting to clone repository " + currentMirror + "..."); bool successful = true; // Update playButton states - SetPlayButtonState(UpdateState.Downloading); + SetPlayButtonState(PlayButtonState.Downloading); // Enable progressBar progressBar.Visible = true; @@ -170,12 +274,12 @@ namespace AM2RLauncher ex.Message.ToLower().Contains("failed to resolve address")) { log.Error("Internet connection dropped while attempting to clone repository" + currentMirror + "!"); - MessageBox.Show(Language.Text.InternetConnectionDrop, Language.Text.WarningWindowTitle, MessageBoxType.Warning); + MessageBox.Show(this, Text.InternetConnectionDrop, Text.WarningWindowTitle, MessageBoxType.Warning); } else { log.Error("LibGit2SharpException: " + ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); - MessageBox.Show(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + 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"); } @@ -184,7 +288,7 @@ namespace AM2RLauncher 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(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + 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"); @@ -202,7 +306,7 @@ namespace AM2RLauncher progressBar.Value = 0; // Just need to switch this to anything that isn't an "active" state so SetUpdateState() actually does something - SetPlayButtonState(UpdateState.Install); + SetPlayButtonState(PlayButtonState.Install); // This needs to be run BEFORE the state check so that the Mod Settings tab doesn't weird out LoadProfilesAndAdjustLists(); @@ -215,15 +319,14 @@ namespace AM2RLauncher #region Downloading - case UpdateState.Downloading: - var result = MessageBox.Show(Language.Text.CloseOnCloningText, Language.Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); - if (result == DialogResult.No) + case PlayButtonState.Downloading: + var result = MessageBox.Show(this, Text.CloseOnCloningText, Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); + if (result != DialogResult.Yes) return; - else - { - log.Info("User cancelled download!"); - isGitProcessGettingCancelled = true; - } + + 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); @@ -233,18 +336,11 @@ namespace AM2RLauncher #endregion #region Select11 - case UpdateState.Select11: + case PlayButtonState.Select11: log.Info("Requesting user input for AM2R_11.zip..."); - OpenFileDialog fileFinder = new OpenFileDialog - { - Directory = new Uri(CrossPlatformOperations.CURRENTPATH), - MultiSelect = false, - Title = Language.Text.Select11FileDialog - }; - - fileFinder.Filters.Add(new FileFilter(Language.Text.ZipArchiveText, ".zip")); + OpenFileDialog fileFinder = GetSingleZipDialog(Text.Select11FileDialog); if (fileFinder.ShowDialog(this) != DialogResult.Ok) { @@ -252,50 +348,43 @@ namespace AM2RLauncher return; } - if (!String.IsNullOrWhiteSpace(fileFinder.FileName)) // This is default + // Default filename is whitespace + if (String.IsNullOrWhiteSpace(fileFinder.FileName)) { - if (Directory.Exists(fileFinder.FileName)) - { - // This can happen on linux, and maybe windows as well - log.Error("User selected a Directory. Cancelling import."); - return; - } - - IsZipAM2R11ReturnCodes errorCode = Profile.CheckIfZipIsAM2R11(fileFinder.FileName); - if (errorCode != IsZipAM2R11ReturnCodes.Successful) - { - log.Error("User tried to input invalid AM2R_11.zip file (" + errorCode + "). Cancelling import."); - MessageBox.Show(Language.Text.ZipIsNotAM2R11 + "\n\nError Code: " + errorCode, Language.Text.ErrorWindowTitle, MessageBoxType.Error); - return; - } - - // If either a directory was selected or the file somehow went missing, cancel - if (!File.Exists(fileFinder.FileName)) - { - log.Error("Selected AM2R_11.zip file not found! Cancelling import."); - break; - } - - // We check if it exists first, because someone coughDRUIDcough might've copied it into here while on the showDialog - if (!File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip")) - File.Copy(fileFinder.FileName, CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip"); + log.Error("User did not supply valid input. Cancelling import."); + return; + } - log.Info("AM2R_11.zip successfully imported."); + // If either a directory was selected or the file somehow went missing, cancel + if (!File.Exists(fileFinder.FileName)) + { + log.Error("Selected AM2R_11.zip file not found! Cancelling import."); + break; } - else + + IsZipAM2R11ReturnCodes errorCode = Profile.CheckIfZipIsAM2R11(fileFinder.FileName); + if (errorCode != IsZipAM2R11ReturnCodes.Successful) { - log.Error("User did not supply valid input. Cancelling import."); + log.Error("User tried to input invalid AM2R_11.zip file (" + errorCode + "). Cancelling import."); + MessageBox.Show(this, Text.ZipIsNotAM2R11 + "\n\nError Code: " + errorCode, Text.ErrorWindowTitle, MessageBoxType.Error); + return; } + // 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"); + + log.Info("AM2R_11.zip successfully imported."); + UpdateStateMachine(); break; #endregion #region Install - case UpdateState.Install: + case PlayButtonState.Install: progressBar.Visible = true; progressBar.Value = 0; - SetPlayButtonState(UpdateState.Installing); + SetPlayButtonState(PlayButtonState.Installing); // Make sure the main interface state machines properly UpdateApkState(); @@ -304,50 +393,46 @@ namespace AM2RLauncher // If the file cannot be launched due to anti-virus shenanigans or any other reason, we try catch here try { - // Check if xdelta is installed on linux´and exit if not - if ((OS.IsUnix) && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) + // Check if xdelta is installed on unix and exit if not + if (OS.IsUnix && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) { - MessageBox.Show(Language.Text.XdeltaNotFound, Language.Text.WarningWindowTitle, MessageBoxButtons.OK); + MessageBox.Show(this, Text.XdeltaNotFound, Text.WarningWindowTitle, MessageBoxButtons.OK); - SetPlayButtonState(UpdateState.Install); + SetPlayButtonState(PlayButtonState.Install); UpdateStateMachine(); log.Error("Xdelta not found. Aborting installing a profile..."); - break; + return; } var 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. if (OS.IsWindows) - Thread.Sleep(1000); + Thread.Sleep(500); } catch (Exception ex) { log.Error(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace); - MessageBox.Show(ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Language.Text.ErrorWindowTitle, MessageBoxType.Error); + MessageBox.Show(this, ex.Message + "\n*****Stack Trace*****\n\n" + ex.StackTrace, Text.ErrorWindowTitle, MessageBoxType.Error); } progressBar.Visible = false; progressBar.Value = 0; // Just need to switch this to anything that isn't an "active" state so SetUpdateState() actually does something - SetPlayButtonState(UpdateState.Play); - + SetPlayButtonState(PlayButtonState.Play); UpdateStateMachine(); - break; #endregion #region Play - case UpdateState.Play: + case PlayButtonState.Play: if (!IsProfileIndexValid()) return; ProfileXML profile = profileList[profileIndex.Value]; - Visible = false; - - SetPlayButtonState(UpdateState.Playing); + SetPlayButtonState(PlayButtonState.Playing); // Make sure the main interface state machines properly UpdateApkState(); @@ -356,8 +441,6 @@ namespace AM2RLauncher this.ShowInTaskbar = false; trayIndicator.Visible = true; WindowState windowStateBeforeLaunching = this.WindowState; - if (windowStateBeforeLaunching == WindowState.Maximized) - this.WindowState = WindowState.Normal; Minimize(); string envVarText = customEnvVarTextBox?.Text; @@ -369,66 +452,41 @@ namespace AM2RLauncher trayIndicator.Visible = false; Show(); BringToFront(); - if (windowStateBeforeLaunching == WindowState.Maximized) - Maximize(); - - SetPlayButtonState(UpdateState.Play); - - UpdateStateMachine(); - Visible = true; + WindowState = windowStateBeforeLaunching; + SetPlayButtonState(PlayButtonState.Play); + UpdateStateMachine(); break; #endregion - default: break; + default: throw new NotImplementedException("Encountered invalid update state: " + updateState + "!"); } } - /// - /// This is just a helper method for the git commands in order to have a progress bar display for them. - /// - private bool TransferProgressHandlerMethod(TransferProgress transferProgress) - { - // Thank you random issue on the gitlib2sharp repo!!!! - // Also tldr; rtfm - if (isGitProcessGettingCancelled) return false; - - // This needs to be in an Invoke, in order to access the variables from the main thread - // Otherwise this will throw a runtime exception - Application.Instance.Invoke(() => - { - progressBar.MinValue = 0; - progressBar.MaxValue = transferProgress.TotalObjects; - if (currentGitObject >= transferProgress.ReceivedObjects) - return; - progressLabel.Text = Language.Text.ProgressbarProgress + " " + transferProgress.ReceivedObjects + " (" + ((int)transferProgress.ReceivedBytes / 1000000) + "MB) / " + transferProgress.TotalObjects + " objects"; - currentGitObject = transferProgress.ReceivedObjects; - progressBar.Value = transferProgress.ReceivedObjects; - }); - - return true; - } - /// /// Does stuff, depending on the current state of . /// private async void ApkButtonClickEvent(object sender, EventArgs e) { + // If we're currently creating something, exit + if (apkButtonState == ApkButtonState.Creating) return; + // Check for java, exit safely with a warning if not found! if (!CrossPlatformOperations.IsJavaInstalled()) { - MessageBox.Show(Language.Text.JavaNotFound, Language.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."); return; } - // Check if xdelta is installed on linux + + // Check if xdelta is installed on unix, exit with a warning if not. if (OS.IsUnix && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) { - MessageBox.Show(Language.Text.XdeltaNotFound, Language.Text.WarningWindowTitle, MessageBoxButtons.OK); + MessageBox.Show(this, Text.XdeltaNotFound, Text.WarningWindowTitle, MessageBoxButtons.OK); SetApkButtonState(ApkButtonState.Create); UpdateStateMachine(); log.Error("Xdelta not found. Aborting Android APK creation..."); @@ -440,7 +498,6 @@ namespace AM2RLauncher if (apkButtonState == ApkButtonState.Create) { SetApkButtonState(ApkButtonState.Creating); - UpdateStateMachine(); progressBar.Visible = true; @@ -450,639 +507,465 @@ namespace AM2RLauncher await Task.Run(() => Profile.CreateAPK(profileList[profileIndex.Value], useHqMusic, progressIndicator)); SetApkButtonState(ApkButtonState.Create); - progressBar.Visible = false; + 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; + + profileIndex = profileDropDown.SelectedIndex; + log.Debug("profileDropDown.SelectedIndex has been changed to " + profileIndex + "."); + + 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")) + saveWarningLabel.Visible = true; + else + saveWarningLabel.Visible = false; UpdateStateMachine(); } + #endregion + /// - /// Runs on 's DocumentLoaded event. Manages the warning for no internet connection. + /// If no internet access is available, this changes the content of to an empty page only displaying . /// - private void NewsWebViewDocumentLoaded(object sender, WebViewLoadedEventArgs e) + /// The to change the contents of. + /// The that should be displayed. + private void ChangeToEmptyPageOnNoInternet(TabPage tabPage, Label errorLabel) { - if (!isInternetThere) + if (isInternetThere) + return; + + tabPage.Content = new TableLayout { - newsPage.Content = new TableLayout + Rows = { - Rows = - { - null, - newsNoConnectionLabel, - null - } - }; - } + null, + errorLabel, + null + } + }; } - /// - /// Runs on 's DocumentLoaded event. Manages the warning for no internet connection. - /// - private void ChangelogWebViewDocumentLoaded(object sender, WebViewLoadedEventArgs e) + #region SETTINGS + + /// Gets called when user selects a different item from and writes that to the config. + private void LanguageDropDownSelectedIndexChanged(object sender, EventArgs e) { - if (!isInternetThere) - { - changelogPage.Content = new TableLayout - { - Rows = - { - null, - changelogNoConnectionLabel, - null - } - }; - } + log.Info("languageDropDown.SelectedIndex has been changed to " + languageDropDown.SelectedIndex + "."); + CrossPlatformOperations.WriteToConfig("Language", languageDropDown.SelectedIndex == 0 ? "Default" : languageDropDown.Items[languageDropDown.SelectedIndex].Text); + } + + /// Gets called when gets clicked and writes its new value to the config. + private void AutoUpdateAM2RCheckChanged(object sender, EventArgs e) + { + log.Info("Auto Update AM2R has been set to " + autoUpdateAM2RCheck.Checked + "."); + CrossPlatformOperations.WriteToConfig("AutoUpdateAM2R", (bool)autoUpdateAM2RCheck.Checked); + } + + /// Gets called when gets clicked and writes its new value to the config. + private void AutoUpdateLauncherCheckChanged(object sender, EventArgs e) + { + log.Info("Auto Update Launcher has been set to " + autoUpdateAM2RCheck.Checked + "."); + CrossPlatformOperations.WriteToConfig("AutoUpdateLauncher", (bool)autoUpdateAM2RCheck.Checked); + } + + /// Gets called when gets clicked and writes its new value to the config. + private void HqMusicPCCheckChanged(object sender, EventArgs e) + { + log.Info("PC HQ Music option has been changed to " + hqMusicPCCheck.Checked); + CrossPlatformOperations.WriteToConfig("MusicHQPC", hqMusicPCCheck.Checked); + } + + /// Gets called when gets clicked and writes its new value to the config. + private void HqMusicAndroidCheckChanged(object sender, EventArgs e) + { + log.Info("Android HQ Music option has been changed to " + hqMusicAndroidCheck.Checked); + CrossPlatformOperations.WriteToConfig("MusicHQAndroid", hqMusicAndroidCheck.Checked); } /// - /// Runs when is clicked. Brings up a file select to select a mod, and adds that to the mod directory. + /// Gets called when gets clicked, and writes it's new value to the config. /// - private void AddModButtonClicked(object sender, EventArgs e) + private void ProfileDebugLogCheckedChanged(object sender, EventArgs e) { - log.Info("User requested to add mod. Requesting user input for new mod .zip..."); - - OpenFileDialog fileFinder = new OpenFileDialog - { - Directory = new Uri(CrossPlatformOperations.CURRENTPATH), - MultiSelect = false, - Title = Language.Text.SelectModFileDialog - }; + log.Info("Create Game Debug Logs option has been set to " + profileDebugLogCheck.Checked + "."); + CrossPlatformOperations.WriteToConfig("ProfileDebugLog", profileDebugLogCheck.Checked); + } - fileFinder.Filters.Add(new FileFilter(Language.Text.ZipArchiveText, ".zip")); + /// Gets called when user selects a different item from . + /// It then writes that to the config, and if is not + /// it also overwrites the upstream URL in .git/config. + private void MirrorDropDownSelectedIndexChanged(object sender, EventArgs e) + { + currentMirror = mirrorList[mirrorDropDown.SelectedIndex]; - if (fileFinder.ShowDialog(this) != DialogResult.Ok) - { - log.Info("User cancelled the Mod selection."); - return; - } + log.Info("Current mirror has been set to " + currentMirror + "."); - if (String.IsNullOrWhiteSpace(fileFinder.FileName)) - { - log.Error("User did not supply valid input. Cancelling import."); - LoadProfilesAndAdjustLists(); - return; - } + CrossPlatformOperations.WriteToConfig("MirrorIndex", mirrorDropDown.SelectedIndex); - log.Info("User selected \"" + fileFinder.FileName + "\""); + // Don't overwrite the git config while we download!!! + if (updateState == PlayButtonState.Downloading) return; - // If either a directory was selected or the file somehow went missing, cancel - if (!File.Exists(fileFinder.FileName)) - { - log.Error("Selected mod .zip file not found! Cancelling import."); - return; - } + log.Info("Overwriting mirror in gitconfig."); - FileInfo modFile = new FileInfo(fileFinder.FileName); + // 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"; + if (!File.Exists(gitConfigPath)) return; + string gitConfig = File.ReadAllText(gitConfigPath); + Regex gitURLRegex = new Regex("https://.*\\.git"); + Match match = gitURLRegex.Match(gitConfig); + gitConfig = gitConfig.Replace(match.Value, currentMirror); + File.WriteAllText(gitConfigPath, gitConfig); + } - string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; - string extractedName = modFile.Name.Replace(".zip", ""); + /// Gets called when gets clicked, displays a warning + /// and enables accordingly. + private void CustomMirrorCheckChanged(object sender, EventArgs e) + { + log.Info("Use Custom Mirror option has been set to " + customMirrorCheck.Checked + "."); + CrossPlatformOperations.WriteToConfig("CustomMirrorEnabled", (bool)customMirrorCheck.Checked); - // Extract it and see if it contains a profile.xml. If not, this is invalid + EnableMirrorControlsAccordingly(); - // Check first, if the directory is already there, if yes, throw a message - if (Directory.Exists(modsDir + "/" + extractedName)) + // Create warning dialog when enabling + if ((bool)customMirrorCheck.Checked) { - ProfileXML profile2 = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); - log.Error("Mod is already imported as " + extractedName + "! Cancelling mod import."); - - MessageBox.Show(Language.Text.ModIsAlreadyInstalledMessage.Replace("$NAME", profile2.Name), Language.Text.WarningWindowTitle, MessageBoxType.Warning); - return; - } - // Directory doesn't exist -> extract! - ZipFile.ExtractToDirectory(fileFinder.FileName, modsDir + "/" + extractedName); - log.Info("Imported and extracted mod .zip as " + extractedName); - - // Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup - if (!File.Exists(modsDir + "/" + extractedName + "/profile.xml")) - { - log.Error(fileFinder.FileName + " does not contain profile.xml! Cancelling mod import."); - - MessageBox.Show(Language.Text.ModIsInvalidMessage.Replace("$NAME", extractedName), Language.Text.ErrorWindowTitle, MessageBoxType.Error); - Directory.Delete(modsDir + "/" + extractedName, true); - File.Delete(CrossPlatformOperations.CURRENTPATH + "/Mods/" + modFile.Name); - return; - } - - ProfileXML profile = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); - - // Check if the OS versions match - if (OS.Name != profile.OperatingSystem) - { - log.Error("Mod is for " + profile.OperatingSystem + " while current OS is " + OS.Name + ". Cancelling mod import."); - - MessageBox.Show(Language.Text.ModIsForWrongOS.Replace("$NAME", profile.Name).Replace("$OS", profile.OperatingSystem).Replace("$CURRENTOS", OS.Name), - Language.Text.ErrorWindowTitle, MessageBoxType.Error); - HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); - return; + MessageBox.Show(this, Text.WarningWindowText, Text.WarningWindowTitle, MessageBoxType.Warning); + currentMirror = customMirrorTextBox.Text; } - - // Check by *name*, if the mod was installed already - if (profileList.FirstOrDefault(p => p.Name == profile.Name) != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) + else { - log.Error(profile.Name + " is already installed."); - MessageBox.Show(Language.Text.ModIsAlreadyInstalledMessage.Replace("$NAME", profile.Name), Language.Text.WarningWindowTitle, MessageBoxType.Warning); - HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); - return; + // Revert mirror to selected index in mirror dropdown + currentMirror = mirrorList[mirrorDropDown.SelectedIndex]; } - - log.Info(profile.Name + " successfully installed."); - MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); - - LoadProfilesAndAdjustLists(); - // Adjust profileIndex to point to newly added mod. if its not found for whatever reason, we default to first community updates - settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == profile.Name); - if (settingsProfileDropDown.SelectedIndex == -1) - settingsProfileDropDown.SelectedIndex = 0; - } - - /// - /// This opens the game files directory for the current profile. - /// - private void ProfilesButtonClickEvent(object sender, EventArgs e) - { - if (!IsProfileIndexValid()) - return; - log.Info("User opened the profile directory for profile " + profileList[settingsProfileDropDown.SelectedIndex].Name + - ", which is " + profileList[settingsProfileDropDown.SelectedIndex].SaveLocation); - CrossPlatformOperations.OpenFolder(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileList[settingsProfileDropDown.SelectedIndex].Name); } /// - /// This opens the save directory for the current profile. - /// - private void SaveButtonClickEvent(object sender, EventArgs e) - { - if (!IsProfileIndexValid()) - return; - log.Info("User opened the save directory for profile " + profileList[settingsProfileDropDown.SelectedIndex].Name + ", which is " + profileList[settingsProfileDropDown.SelectedIndex].SaveLocation); - CrossPlatformOperations.OpenFolder(profileList[settingsProfileDropDown.SelectedIndex].SaveLocation); - } - - /// - /// Enabled / disables and accordingly. + /// If the has lost focus, we set its text as the new . /// - private void SettingsProfileDropDownSelectedIndexChanged(object sender, EventArgs e) + private void CustomMirrorTextBoxLostFocus(object sender, EventArgs e) { - if (settingsProfileDropDown.SelectedIndex == -1 && settingsProfileDropDown.Items.Count == 0) return; - - log.Info("SettingsProfileDropDown.SelectedIndex has been changed to " + settingsProfileDropDown.SelectedIndex + "."); - if (settingsProfileDropDown.SelectedIndex <= 0 || settingsProfileDropDown.Items.Count == 0) - { - deleteModButton.Enabled = false; - deleteModButton.ToolTip = null; - updateModButton.Enabled = false; - updateModButton.ToolTip = null; - profileNotesTextArea.TextColor = colInactive; - } - else + // Check first, if the text is a valid git repo + Regex gitURLRegex = new Regex("https://.*\\.git"); + string mirrorText = customMirrorTextBox.Text; + if (!gitURLRegex.IsMatch(mirrorText)) { - deleteModButton.Enabled = true; - deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); - // On non-installable profiles we want to disable updating - updateModButton.Enabled = profileList[settingsProfileDropDown.SelectedIndex].Installable; - updateModButton.ToolTip = Language.Text.UpdateModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + log.Info("User used " + mirrorText + " as a custom Mirror, didn't pass git validation test."); + MessageBox.Show(this, HelperMethods.GetText(Text.InvalidGitURL, mirrorText), Text.ErrorWindowTitle, MessageBoxType.Error); + return; } - profileButton.Enabled = Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileList[settingsProfileDropDown.SelectedIndex].Name); - profileButton.ToolTip = Language.Text.OpenProfileFolderToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); - saveButton.Enabled = true; - saveButton.ToolTip = Language.Text.OpenSaveFolderToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + currentMirror = mirrorText; + CrossPlatformOperations.WriteToConfig("CustomMirrorText", currentMirror); - if (settingsProfileDropDown.SelectedIndex < 0 || settingsProfileDropDown.Items.Count == 0) - return; - profileNotesTextArea.TextColor = colGreen; - profileNotesTextArea.Text = Language.Text.ProfileNotes + "\n" + profileList[settingsProfileDropDown.SelectedIndex].ProfileNotes; + 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"; + if (!File.Exists(gitConfigPath)) return; + string gitConfig = File.ReadAllText(gitConfigPath); + Match match = gitURLRegex.Match(gitConfig); + gitConfig = gitConfig.Replace(match.Value, currentMirror); + File.WriteAllText(gitConfigPath, gitConfig); - /// - /// Fires when the profile layout completes loading. This makes sure that if has nothing in it "on boot", - /// that everything is disabled. - /// - private void ProfileLayoutLoadComplete(object sender, EventArgs e) - { - // Safety check - if ((settingsProfileDropDown == null) || (settingsProfileDropDown.Items.Count != 0)) return; - addModButton.Enabled = false; - settingsProfileLabel.TextColor = colInactive; - settingsProfileDropDown.Enabled = false; - profileButton.Enabled = false; - saveButton.Enabled = false; - updateModButton.Enabled = false; - deleteModButton.Enabled = false; - profileNotesTextArea.TextColor = colInactive; + log.Info("Custom Mirror has been set to " + currentMirror + "."); } /// - /// The calls this when you're resizing, in order to resize and scale the application accordingly. + /// If has lost focus, we write its text to the config. /// - private void DrawablePaintEvent(object sender, PaintEventArgs e) + private void CustomEnvVarTextBoxLostFocus(object sender, EventArgs e) { - // Get drawing variables - float height = drawable.Height; - float width = drawable.Width; - 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. - float scale = height / scaleDivisor; - - // Do the actual scaling - e.Graphics.ScaleTransform(scale); - - // Draw the image, change x offset with some absurd wizardry written at 5 AM - e.Graphics.DrawImage(formBG, ((width / 2) - (height / 1.4745f)) / scale, 0); + log.Info("Custom Environment variables have been set to \"" + customEnvVarTextBox.Text + "\"."); + CrossPlatformOperations.WriteToConfig("CustomEnvVar", customEnvVarTextBox.Text); } - #region ICON EVENTS - - /// Gets called when gets clicked. - private void RedditIconOnClick(object sender, EventArgs e) { CrossPlatformOperations.OpenURL("https://www.reddit.com/r/AM2R"); } - /// Gets called when gets clicked. - private void GithubIconOnClick(object sender, EventArgs e) { CrossPlatformOperations.OpenURL("https://www.github.com/AM2R-Community-Developers"); } - /// Gets called when gets clicked. - private void YoutubeIconOnClick(object sender, EventArgs e) { CrossPlatformOperations.OpenURL("https://www.youtube.com/c/AM2RCommunityUpdates"); } - /// Gets called when gets clicked. - private void DiscordIconOnClick(object sender, EventArgs e) { CrossPlatformOperations.OpenURL("https://discord.gg/nk7UYPbd5u"); } - #endregion - /// Gets called when gets clicked and shows the and brings it to the front again. - private void ShowButtonClick(object sender, EventArgs e) - { - log.Info("User has opened the launcher from system tray."); - - this.Show(); - this.BringToFront(); - } + #region MOD SETTINGS - /// Gets called when gets clicked and writes its new value to the config. - private void HqMusicPCCheckChanged(object sender, EventArgs e) + /// + /// Runs when is clicked. Brings up a file select to select a mod, and adds that to the mod directory. + /// + private void AddModButtonClicked(object sender, EventArgs e) { - log.Info("PC HQ Music option has been changed to " + hqMusicPCCheck.Checked); - CrossPlatformOperations.WriteToConfig("MusicHQPC", hqMusicPCCheck.Checked); - } + log.Info("User requested to add mod. Requesting user input for new mod .zip..."); - /// Gets called when gets clicked and writes its new value to the config. - private void HqMusicAndroidCheckChanged(object sender, EventArgs e) - { - log.Info("Android HQ Music option has been changed to " + hqMusicAndroidCheck.Checked); - CrossPlatformOperations.WriteToConfig("MusicHQAndroid", hqMusicAndroidCheck.Checked); - } + OpenFileDialog fileFinder = GetSingleZipDialog(Text.SelectModFileDialog); - /// 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; - - profileIndex = profileDropDown.SelectedIndex; - log.Debug("profileDropDown.SelectedIndex has been changed to " + profileIndex + "."); + // If user didn't press ok, cancel + if (fileFinder.ShowDialog(this) != DialogResult.Ok) + { + log.Info("User cancelled the Mod selection."); + return; + } - profileAuthorLabel.Text = Language.Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; - profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; + log.Info("User selected \"" + fileFinder.FileName + "\""); - if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" || - profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) - saveWarningLabel.Visible = true; - else - saveWarningLabel.Visible = false; + // If either a directory was selected, user pressed OK without selecting anything or the file somehow went missing, cancel + if (!File.Exists(fileFinder.FileName)) + { + log.Error("Selected mod .zip file not found! Cancelling import."); + return; + } - UpdateStateMachine(); - } + //TODO: move most of this into AM2RLauncher.Profile? - /// Gets called when user selects a different item from and writes that to the config. - private void LanguageDropDownSelectedIndexChanged(object sender, EventArgs e) - { - log.Info("languageDropDown.SelectedIndex has been changed to " + languageDropDown.SelectedIndex + "."); - CrossPlatformOperations.WriteToConfig("Language", languageDropDown.SelectedIndex == 0 ? "Default" : languageDropDown.Items[languageDropDown.SelectedIndex].Text); - } + FileInfo modFile = new FileInfo(fileFinder.FileName); + string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; + string modFileName = Path.GetFileNameWithoutExtension(modFile.Name); + string extractedModDir = modsDir + "/" + modFileName; - /// Gets called when gets clicked and writes its new value to the config. - private void AutoUpdateAM2RCheckChanged(object sender, EventArgs e) - { - log.Info("Auto Update AM2R has been set to " + autoUpdateAM2RCheck.Checked + "."); - CrossPlatformOperations.WriteToConfig("AutoUpdateAM2R", (bool)autoUpdateAM2RCheck.Checked); - } + // Check first, if the directory is already there, if yes, throw error + if (Directory.Exists(extractedModDir)) + { + string existingProfileName = Serializer.Deserialize(File.ReadAllText(extractedModDir + "/profile.xml")).Name; + log.Error("Mod is already imported as " + modFileName + "! Cancelling mod import."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModIsAlreadyInstalledMessage, existingProfileName), Text.WarningWindowTitle, MessageBoxType.Warning); + return; + } - /// Gets called when gets clicked and writes its new value to the config. - private void AutoUpdateLauncherCheckChanged(object sender, EventArgs e) - { - log.Info("Auto Update Launcher has been set to " + autoUpdateAM2RCheck.Checked + "."); - CrossPlatformOperations.WriteToConfig("AutoUpdateLauncher", (bool)autoUpdateAM2RCheck.Checked); - } + // Directory doesn't exist -> extract! + ZipFile.ExtractToDirectory(modFile.FullName, extractedModDir); + log.Info("Imported and extracted mod .zip as " + modFileName); - /// Gets called when gets clicked, displays a warning - /// and enables accordingly. - private void CustomMirrorCheckChanged(object sender, EventArgs e) - { - log.Info("Use Custom Mirror option has been set to " + customMirrorCheck.Checked + "."); - CrossPlatformOperations.WriteToConfig("CustomMirrorEnabled", (bool)customMirrorCheck.Checked); + // If profile.xml doesn't exist, throw an error and cleanup + if (!File.Exists(extractedModDir + "/profile.xml")) + { + log.Error(modFile.Name + " does not contain profile.xml! Cancelling mod import."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModIsInvalidMessage, modFileName), Text.ErrorWindowTitle, MessageBoxType.Error); + Directory.Delete(extractedModDir, true); + return; + } - bool enabled = (bool)customMirrorCheck.Checked; - customMirrorTextBox.Enabled = enabled; - mirrorDropDown.Enabled = !enabled; - // Not sure why the dropdown menu needs this hack, but the textBox does not. - if (OS.IsWindows) - mirrorDropDown.TextColor = mirrorDropDown.Enabled ? colGreen : colInactive; - mirrorLabel.TextColor = !enabled ? colGreen : colInactive; + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(extractedModDir + "/profile.xml")); - // Create warning dialog when enabling - if (enabled) + // If OS versions mismatch, throw error and cleanup + if (OS.Name != profile.OperatingSystem) { - MessageBox.Show(Language.Text.WarningWindowText, Language.Text.WarningWindowTitle, MessageBoxType.Warning); - currentMirror = customMirrorTextBox.Text; + log.Error("Mod is for " + profile.OperatingSystem + " while current OS is " + OS.Name + ". Cancelling mod import."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModIsForWrongOS, profile.Name).Replace("$OS", profile.OperatingSystem).Replace("$CURRENTOS", OS.Name), + Text.ErrorWindowTitle, MessageBoxType.Error); + HelperMethods.DeleteDirectory(extractedModDir); + return; } - else + + // If mod was installed/added by *name* already, throw error and cleanup + if (profileList.FirstOrDefault(p => p.Name == profile.Name) != null) { - // Revert mirror to selected index in mirror dropdown - currentMirror = mirrorList[mirrorDropDown.SelectedIndex]; + log.Error(profile.Name + " is already installed."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModIsAlreadyInstalledMessage, profile.Name), Text.WarningWindowTitle, MessageBoxType.Warning); + HelperMethods.DeleteDirectory(extractedModDir); + return; } - } - - /// Gets called when user selects a different item from . - /// It then writes that to the config, and if is not - /// it also overwrites the upstream URL in .git/config. - private void MirrorDropDownSelectedIndexChanged(object sender, EventArgs e) - { - currentMirror = mirrorList[mirrorDropDown.SelectedIndex]; - - log.Info("Current mirror has been set to " + currentMirror + "."); - - CrossPlatformOperations.WriteToConfig("MirrorIndex", mirrorDropDown.SelectedIndex); - - // Don't overwrite the git config while we download!!! - if (updateState == UpdateState.Downloading) return; - log.Info("Overwriting mirror in gitconfig."); + // Reload list so mod gets recognized + LoadProfilesAndAdjustLists(); + // Adjust profileIndex to point to newly added mod. if its not found for whatever reason, we default to first community updates + modSettingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == profile.Name); + if (modSettingsProfileDropDown.SelectedIndex == -1) + modSettingsProfileDropDown.SelectedIndex = 0; - // 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"; - if (!File.Exists(gitConfigPath)) return; - string gitConfig = File.ReadAllText(gitConfigPath); - Regex gitURLRegex = new Regex("https://.*\\.git"); - Match match = gitURLRegex.Match(gitConfig); - gitConfig = gitConfig.Replace(match.Value, currentMirror); - File.WriteAllText(gitConfigPath, gitConfig); + log.Info(profile.Name + " successfully added."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModSuccessfullyInstalledMessage, profile.Name), Text.SuccessWindowTitle); } /// - /// Gets called when gets clicked, and writes it's new value to the config. + /// Enabled / disables and accordingly. /// - private void ProfileDebugLogCheckedChanged(object sender, EventArgs e) + private void ModSettingsProfileDropDownSelectedIndexChanged(object sender, EventArgs e) { - log.Info("Create Game Debug Logs option has been set to " + profileDebugLogCheck.Checked + "."); - CrossPlatformOperations.WriteToConfig("ProfileDebugLog", profileDebugLogCheck.Checked); - } + if (modSettingsProfileDropDown.SelectedIndex == -1 && modSettingsProfileDropDown.Items.Count == 0) return; - /// - /// If the has lost focus, we set its text as the new . - /// - private void CustomMirrorTextBoxLostFocus(object sender, EventArgs e) - { - // Check first, if the text is a valid git repo - Regex gitURLRegex = new Regex("https://.*\\.git"); - string mirrorText = customMirrorTextBox.Text; - if (!gitURLRegex.IsMatch(mirrorText)) + string profileName = modSettingsProfileDropDown.Items[modSettingsProfileDropDown.SelectedIndex].Text; + + log.Info("SettingsProfileDropDown.SelectedIndex has been changed to " + modSettingsProfileDropDown.SelectedIndex + "."); + if (modSettingsProfileDropDown.SelectedIndex <= 0 || modSettingsProfileDropDown.Items.Count == 0) { - log.Info("User used " + mirrorText + " as a custom Mirror, didn't pass git validation test."); - MessageBox.Show(Language.Text.InvalidGitURL.Replace("$NAME", mirrorText), Language.Text.ErrorWindowTitle, MessageBoxType.Error); - return; + deleteModButton.Enabled = false; + deleteModButton.ToolTip = null; + updateModButton.Enabled = false; + updateModButton.ToolTip = null; + profileNotesTextArea.TextColor = colInactive; + } + else + { + deleteModButton.Enabled = true; + deleteModButton.ToolTip = HelperMethods.GetText(Text.DeleteModButtonToolTip, profileName); + // On non-installable profiles we want to disable updating + updateModButton.Enabled = profileList[modSettingsProfileDropDown.SelectedIndex].Installable; + updateModButton.ToolTip = HelperMethods.GetText(Text.UpdateModButtonToolTip, profileName); } - currentMirror = mirrorText; - CrossPlatformOperations.WriteToConfig("CustomMirrorText", currentMirror); - - log.Info("Overwriting mirror in gitconfig."); + profileButton.Enabled = Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileName); + profileButton.ToolTip = HelperMethods.GetText(Text.OpenProfileFolderToolTip, profileName); + saveButton.Enabled = true; + saveButton.ToolTip = HelperMethods.GetText(Text.OpenSaveFolderToolTip, profileName); - // 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"; - if (!File.Exists(gitConfigPath)) return; - string gitConfig = File.ReadAllText(gitConfigPath); - Match match = gitURLRegex.Match(gitConfig); - gitConfig = gitConfig.Replace(match.Value, currentMirror); - File.WriteAllText(gitConfigPath, gitConfig); + if (modSettingsProfileDropDown.SelectedIndex < 0 || modSettingsProfileDropDown.Items.Count == 0) + return; + profileNotesTextArea.TextColor = colGreen; + profileNotesTextArea.Text = Text.ProfileNotes + "\n" + profileList[modSettingsProfileDropDown.SelectedIndex].ProfileNotes; - log.Info("Custom Mirror has been set to " + currentMirror + "."); } /// - /// If has lost focus, we write its text to the config. + /// This opens the game files directory for the current profile. /// - private void CustomEnvVarTextBoxLostFocus(object sender, EventArgs e) + private void ProfileDataButtonClickEvent(object sender, EventArgs e) { - log.Info("Custom Environment variables have been set to \"" + customEnvVarTextBox.Text + "\"."); - CrossPlatformOperations.WriteToConfig("CustomEnvVar", customEnvVarTextBox.Text); + if (!IsProfileIndexValid()) + 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); } - /// Gets called when gets loaded. - /// Enables and changes colors for and accordingly. - private void CustomMirrorCheckLoadComplete(object sender, EventArgs e) + /// + /// This opens the save directory for the current profile. + /// + private void SaveButtonClickEvent(object sender, EventArgs e) { - bool enabled = (bool)customMirrorCheck.Checked; - customMirrorTextBox.Enabled = enabled; - mirrorDropDown.Enabled = !enabled; - if (OS.IsWindows) - mirrorDropDown.TextColor = mirrorDropDown.Enabled ? colGreen : colInactive; + if (!IsProfileIndexValid()) + return; + ProfileXML profile = profileList[modSettingsProfileDropDown.SelectedIndex]; + log.Info("User opened the save directory for profile " + profile.Name + ", which is " + profile.SaveLocation); + CrossPlatformOperations.OpenFolder(profile.SaveLocation); } /// - /// Gets called when gets clicked. Deletes the current selected in . + /// Gets called when gets clicked. Deletes the current selected in . /// private void DeleteModButtonClicked(object sender, EventArgs e) { - ProfileXML profile = profileList[settingsProfileDropDown.SelectedIndex]; + ProfileXML profile = profileList[modSettingsProfileDropDown.SelectedIndex]; log.Info("User is attempting to delete profile " + profile.Name + "."); - DialogResult result = MessageBox.Show(Language.Text.DeleteModWarning.Replace("$NAME", profile.Name), Language.Text.WarningWindowTitle, + DialogResult result = MessageBox.Show(this, HelperMethods.GetText(Text.DeleteModWarning, profile.Name), Text.WarningWindowTitle, MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); - if (result == DialogResult.Ok) - { - log.Info("User did not cancel. Proceeding to delete " + profile); - DeleteProfileAndAdjustLists(profile); - log.Info(profile + " has been deleted"); - MessageBox.Show(Language.Text.DeleteModButtonSuccess.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); - } - else + // if user didn't press ok, cancel + if (result != DialogResult.Ok) { log.Info("User has cancelled profile deletion."); + return; } + + log.Info("User did not cancel. Proceeding to delete " + profile); + DeleteProfileAndAdjustLists(profile); + log.Info(profile + " has been deleted"); + MessageBox.Show(this, HelperMethods.GetText(Text.DeleteModButtonSuccess, profile.Name), Text.SuccessWindowTitle); } /// /// Gets called, when gets clicked. Opens a window, so the user can select a zip, which will be updated over - /// the current selected in . + /// the current selected in . /// private void UpdateModButtonClicked(object sender, EventArgs e) { log.Info("User requested to update mod. Requesting user input for new mod .zip..."); - bool abort = false; - - ProfileXML currentProfile = profileList[settingsProfileDropDown.SelectedIndex]; - - OpenFileDialog fileFinder = new OpenFileDialog - { - Directory = new Uri(CrossPlatformOperations.CURRENTPATH), - MultiSelect = false, - Title = Language.Text.SelectModFileDialog - }; - - fileFinder.Filters.Add(new FileFilter(Language.Text.ZipArchiveText, ".zip")); + ProfileXML currentProfile = profileList[modSettingsProfileDropDown.SelectedIndex]; + OpenFileDialog fileFinder = GetSingleZipDialog(Text.SelectModFileDialog); + // If user didn't click OK, cancel if (fileFinder.ShowDialog(this) != DialogResult.Ok) { log.Info("User cancelled the Mod selection."); return; } - // Exit if nothing was selected - if (String.IsNullOrWhiteSpace(fileFinder.FileName)) - { - log.Info("Nothing was selected, cancelling mod update."); - LoadProfilesAndAdjustLists(); - return; - } - log.Info("User selected \"" + fileFinder.FileName + "\""); - // If either a directory was selected or the file somehow went missing, cancel + // If either a directory was selected, no file was selected or the file somehow went missing, cancel if (!File.Exists(fileFinder.FileName)) { log.Error("Selected mod .zip file not found! Cancelling mod update."); return; } - FileInfo modFile = new FileInfo(fileFinder.FileName); + //TODO: move most of this into AM2RLauncher.Profile? + FileInfo modFile = new FileInfo(fileFinder.FileName); string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; - string extractedName = modFile.Name.Replace(".zip", "_new"); - string extractedFolder = modsDir + "/" + extractedName; - - // Extract it and see if it contains a profile.xml. If not, this is invalid + string extractedName = Path.GetFileNameWithoutExtension(modFile.Name) + "_new"; + string extractedModDir = modsDir + "/" + extractedName; - // If for some reason old files remain, delete them - if (Directory.Exists(extractedFolder)) - Directory.Delete(extractedFolder, true); + // If for some reason old files remain, delete them so that extraction doesnt throw + if (Directory.Exists(extractedModDir)) + Directory.Delete(extractedModDir, true); // Directory doesn't exist -> extract! - ZipFile.ExtractToDirectory(fileFinder.FileName, extractedFolder); + ZipFile.ExtractToDirectory(fileFinder.FileName, extractedModDir); - // Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup - if (!File.Exists(extractedFolder + "/profile.xml")) + // If mod doesn't have a profile.xml, throw an error and cleanup + if (!File.Exists(extractedModDir + "/profile.xml")) { log.Error(fileFinder.FileName + " does not contain profile.xml! Cancelling mod update."); - MessageBox.Show(Language.Text.ModIsInvalidMessage.Replace("$NAME", extractedName), Language.Text.ErrorWindowTitle, MessageBoxType.Error); - Directory.Delete(extractedFolder, true); - File.Delete(CrossPlatformOperations.CURRENTPATH + "/Mods/" + modFile.Name); + MessageBox.Show(this, HelperMethods.GetText(Text.ModIsInvalidMessage, extractedName), Text.ErrorWindowTitle, MessageBoxType.Error); + Directory.Delete(extractedModDir, true); return; } // Check by *name*, if the mod was installed already - ProfileXML profile = Serializer.Deserialize(File.ReadAllText(extractedFolder + "/profile.xml")); - - if (profileList.FirstOrDefault(p => p.Name == profile.Name) != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) - { - // Mod is already installed, so we can update! - DialogResult updateResult = MessageBox.Show(Language.Text.UpdateModWarning.Replace("$NAME", currentProfile.Name), Language.Text.WarningWindowTitle, - MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(extractedModDir + "/profile.xml")); - if (updateResult == DialogResult.Ok) - { - // If the profile isn't installed, don't ask about archiving it - if (Profile.IsProfileInstalled(currentProfile)) - { - //TODO: localize - DialogResult archiveResult = MessageBox.Show(Language.Text.ArchiveMod.Replace("$NAME", currentProfile.Name + " " + Language.Text.VersionLabel + currentProfile.Version), Language.Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); - - // User wants to archive profile - if (archiveResult == DialogResult.Yes) - ArchiveProfileAndAdjustLists(currentProfile); - } - // Now we delete the profile - DeleteProfileAndAdjustLists(currentProfile); - - // Rename directory to take the old one's place - string originalFolder = modsDir + "/" + extractedName.Replace("_new", ""); - Directory.Move(extractedFolder, originalFolder); - } - else // Cancel the operation! - { - log.Error("User has cancelled mod update!"); - abort = true; - } - } - else + // If the selected mod is not installed, tell user that they should add it and cleanup + if (profileList.FirstOrDefault(p => p.Name == profile.Name) == null) { - // Cancel the operation! - // Show message to tell user that mod could not be found, install this separately log.Error("Mod is not installed! Cancelling mod update."); - MessageBox.Show(Language.Text.UpdateModButtonWrongMod.Replace("$NAME", currentProfile.Name).Replace("$SELECT", profile.Name), - Language.Text.WarningWindowTitle, MessageBoxButtons.OK); - abort = true; + MessageBox.Show(this, HelperMethods.GetText(Text.UpdateModButtonWrongMod, currentProfile.Name).Replace("$SELECT", profile.Name), + Text.WarningWindowTitle, MessageBoxButtons.OK); + HelperMethods.DeleteDirectory(extractedModDir); + return; } - - if (abort) + + // 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); + if (updateResult != DialogResult.Ok) { - // File cleanup - HelperMethods.DeleteDirectory(extractedFolder); - LoadProfilesAndAdjustLists(); + log.Error("User has cancelled mod update!"); + HelperMethods.DeleteDirectory(extractedModDir); return; } - log.Info("Successfully updated mod profile " + profile.Name + "."); - MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", currentProfile.Name), Language.Text.SuccessWindowTitle); - UpdateStateMachine(); - - LoadProfilesAndAdjustLists(); + // If the profile isn't installed, don't ask about archiving it + if (Profile.IsProfileInstalled(currentProfile)) + { + DialogResult archiveResult = MessageBox.Show(this, HelperMethods.GetText(Text.ArchiveMod, currentProfile.Name + " " + Text.VersionLabel + currentProfile.Version), Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); - settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentProfile.Name); - if (settingsProfileDropDown.SelectedIndex == -1) - settingsProfileDropDown.SelectedIndex = 0; - } + // User wants to archive profile + if (archiveResult == DialogResult.Yes) + ArchiveProfileAndAdjustLists(currentProfile); + } - /// - /// Gets called when user tries to close . This does a few things:
- /// 1) Writes the Width, Height and the check if is currently maximized 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) - { - log.Info("Attempting to close MainForm!"); + DeleteProfileAndAdjustLists(currentProfile); - CrossPlatformOperations.WriteToConfig("Width", ClientSize.Width); - CrossPlatformOperations.WriteToConfig("Height", ClientSize.Height); - CrossPlatformOperations.WriteToConfig("IsMaximized", this.WindowState == WindowState.Maximized); - CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString()); + // Rename directory to take the old one's place + string originalFolder = modsDir + "/" + Path.GetFileNameWithoutExtension(modFile.Name); + Directory.Move(extractedModDir, originalFolder); - switch (updateState) - { - case UpdateState.Downloading: - { - var result = MessageBox.Show(Language.Text.CloseOnCloningText, Language.Text.WarningWindowTitle, MessageBoxButtons.YesNo, - MessageBoxType.Warning, MessageBoxDefaultButton.No); - if (result == DialogResult.No) - { - e.Cancel = true; - } - else - isGitProcessGettingCancelled = true; - // We don't need to delete any folders here, the cancelled gitClone will do that automatically for us :) - break; - } - case UpdateState.Installing: - MessageBox.Show(Language.Text.CloseOnInstallingText, Language.Text.WarningWindowTitle, MessageBoxButtons.OK, MessageBoxType.Warning); - e.Cancel = true; - break; - } + // Adjust our lists so it gets recognized + LoadProfilesAndAdjustLists(); - // This needs to be made invisible, otherwise a tray indicator will be visible (on linux?) that clicking crashes the application - trayIndicator.Visible = false; + modSettingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentProfile.Name); + if (modSettingsProfileDropDown.SelectedIndex == -1) + modSettingsProfileDropDown.SelectedIndex = 0; - if (e.Cancel) - log.Info("Cancelled MainForm closing event during UpdateState." + updateState + "."); - else - log.Info("Successfully closed MainForm. Exiting main thread."); + log.Info("Successfully updated mod profile " + profile.Name + "."); + MessageBox.Show(this, HelperMethods.GetText(Text.ModSuccessfullyInstalledMessage, currentProfile.Name), Text.SuccessWindowTitle); } + #endregion } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs index 588e014..87b6d63 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Methods.cs @@ -1,4 +1,8 @@ -using Eto.Forms; +using AM2RLauncher.Core; +using AM2RLauncher.Language; +using Eto.Forms; +using LibGit2Sharp; +using System; namespace AM2RLauncher { @@ -34,9 +38,52 @@ namespace AM2RLauncher /// Safety check function before accessing . /// /// if it is valid, if not. + //TODO: this should get a "membernotnullwhen" atttribute whenever i figure out how to apply it here private bool IsProfileIndexValid() { return profileIndex != null; } + + /// + /// This is just a helper method for the git commands in order to have a progress bar display for them. + /// + private bool TransferProgressHandlerMethod(TransferProgress transferProgress) + { + // Thank you random issue on the gitlib2sharp repo!!!! + // Also tldr; rtfm + if (isGitProcessGettingCancelled) return false; + + // This needs to be in an Invoke, in order to access the variables from the main thread + // Otherwise this will throw a runtime exception + Application.Instance.Invoke(() => + { + progressBar.MinValue = 0; + progressBar.MaxValue = transferProgress.TotalObjects; + if (currentGitObject >= transferProgress.ReceivedObjects) + return; + progressLabel.Text = Text.ProgressbarProgress + " " + transferProgress.ReceivedObjects + " (" + ((int)transferProgress.ReceivedBytes / 1000000) + "MB) / " + transferProgress.TotalObjects + " objects"; + currentGitObject = transferProgress.ReceivedObjects; + progressBar.Value = transferProgress.ReceivedObjects; + }); + + return true; + } + + /// + /// Creates a single-file, zip-filtered file dialog. + /// + /// The title of the file dialog. + /// The created file dialog. + private OpenFileDialog GetSingleZipDialog(string title = "") + { + OpenFileDialog fileDialog = new OpenFileDialog + { + Directory = new Uri(CrossPlatformOperations.CURRENTPATH), + MultiSelect = false, + Title = title + }; + fileDialog.Filters.Add(new FileFilter(Text.ZipArchiveText, ".zip")); + return fileDialog; + } } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs index 63269ae..9e7271a 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs @@ -2,6 +2,7 @@ using System; using AM2RLauncher.Core; using AM2RLauncher.Core.XML; +using AM2RLauncher.Language; namespace AM2RLauncher { @@ -18,61 +19,56 @@ namespace AM2RLauncher UpdatePlayState(); UpdateApkState(); UpdateProfileState(); - UpdateProfileSettingsState(); + UpdateModSettingsState(); } /// - /// Determines current conditions and calls accordingly. + /// Determines current conditions and calls accordingly. /// private void UpdatePlayState() { - // If not downloading or installing... - if ((updateState == UpdateState.Downloading) || (updateState == UpdateState.Installing)) + // If we're downloading or installing, dont't change anything + if ((updateState == PlayButtonState.Downloading) || (updateState == PlayButtonState.Installing)) return; - // If we're currently creating an APK... - if (apkButtonState != ApkButtonState.Creating) + // If we're currently creating an APK, we disable the play button + if (apkButtonState == ApkButtonState.Creating) { - playButton.Enabled = true; - // If PatchData is cloned... - if (Profile.IsPatchDataCloned()) - { - // If 1.1 is installed or if the current profile is invalid... - if (Profile.Is11Installed()) - { - var isProfileValid = IsProfileIndexValid(); - // If current profile is installed... - if (isProfileValid && Profile.IsProfileInstalled(profileList[profileIndex.Value])) - { - // We're ready to play! - SetPlayButtonState(UpdateState.Play); - } - // Otherwise, if profile is NOT installable... - else if (isProfileValid && profileList[profileIndex.Value].Installable == false) - { - // We delete the profile, because we can't install it and it therefore holds no value! - DeleteProfileAndAdjustLists(profileList[profileIndex.Value]); - } - // Otherwise, we still need to install. - else - { - SetPlayButtonState(UpdateState.Install); - } - } - else // We still need to select 1.1. - { - SetPlayButtonState(UpdateState.Select11); - } - } - else // We still need to download. - { - SetPlayButtonState(UpdateState.Download); - } + playButton.Enabled = false; + return; + } + + playButton.Enabled = true; + // If PatchData isn't cloned, we still need to download + if (!Profile.IsPatchDataCloned()) + { + SetPlayButtonState(PlayButtonState.Download); + return; } - else // We disable the Play button. + + // If 1.1 isn't installed, we still need to select it + if (!Profile.Is11Installed()) { - playButton.Enabled = false; + SetPlayButtonState(PlayButtonState.Select11); + return; + } + + var isProfileValid = IsProfileIndexValid(); + // If current profile is installed, we're ready to play! + if (isProfileValid && Profile.IsProfileInstalled(profileList[profileIndex.Value])) + { + SetPlayButtonState(PlayButtonState.Play); + return; } + // Otherwise, if profile is NOT installable, we delete the profile because we can't install it and therefore holds no value! + else if (isProfileValid && profileList[profileIndex.Value].Installable == false) + { + DeleteProfileAndAdjustLists(profileList[profileIndex.Value]); + return; + } + + // Otherwise, we still need to install. + SetPlayButtonState(PlayButtonState.Install); } /// @@ -83,30 +79,31 @@ namespace AM2RLauncher // Safety check if (apkButton == null) return; - + + // Our default values + apkButton.Enabled = false; + apkButton.ToolTip = Text.ApkButtonDisabledToolTip; + // If profile supports Android and if we are NOT already creating an APK... - if (IsProfileIndexValid()) + if (!IsProfileIndexValid()) + return; + + var profile = profileList[profileIndex.Value]; + if (!profile.SupportsAndroid || !profile.Installable || apkButtonState != ApkButtonState.Create) + return; + + // Switch status based on main button's state + switch (updateState) { - var profile = profileList[profileIndex.Value]; - if (profile.SupportsAndroid && profile.Installable && (apkButtonState == ApkButtonState.Create)) - { - // Switch status based on main button's state - switch (updateState) - { - case UpdateState.Download: apkButton.Enabled = false; apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; break; - case UpdateState.Downloading: apkButton.Enabled = false; apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; break; - case UpdateState.Select11: apkButton.Enabled = false; apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; break; - case UpdateState.Install: apkButton.Enabled = true; apkButton.ToolTip = Language.Text.ApkButtonEnabledToolTip.Replace("$NAME", profileDropDown?.Items[profileDropDown.SelectedIndex]?.Text ?? ""); break; - case UpdateState.Installing: apkButton.Enabled = false; apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; break; - case UpdateState.Play: apkButton.Enabled = true; apkButton.ToolTip = Language.Text.ApkButtonEnabledToolTip.Replace("$NAME", profileDropDown?.Items[profileDropDown.SelectedIndex]?.Text ?? ""); break; - case UpdateState.Playing: apkButton.Enabled = false; apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; break; - } - return; - } + case PlayButtonState.Download: + case PlayButtonState.Downloading: + case PlayButtonState.Select11: + case PlayButtonState.Installing: + case PlayButtonState.Playing: return; + + case PlayButtonState.Install: + case PlayButtonState.Play: apkButton.Enabled = true; apkButton.ToolTip = HelperMethods.GetText(Text.ApkButtonEnabledToolTip, profileDropDown?.Items[profileDropDown.SelectedIndex]?.Text ?? ""); break; } - - apkButton.Enabled = false; - apkButton.ToolTip = Language.Text.ApkButtonDisabledToolTip; } /// @@ -119,18 +116,17 @@ namespace AM2RLauncher return; switch (updateState) { - case UpdateState.Download: profileDropDown.Enabled = false; break; - case UpdateState.Downloading: profileDropDown.Enabled = false; break; - case UpdateState.Select11: profileDropDown.Enabled = true; break; - case UpdateState.Install: profileDropDown.Enabled = true; break; - case UpdateState.Installing: profileDropDown.Enabled = false; break; - case UpdateState.Play: profileDropDown.Enabled = true; break; - case UpdateState.Playing: profileDropDown.Enabled = false; break; - } - switch (apkButtonState) - { - case ApkButtonState.Creating: profileDropDown.Enabled = false; break; + case PlayButtonState.Download: + case PlayButtonState.Downloading: + case PlayButtonState.Select11: + case PlayButtonState.Installing: + case PlayButtonState.Playing: profileDropDown.Enabled = false; break; + + case PlayButtonState.Install: + case PlayButtonState.Play: profileDropDown.Enabled = true; break; + } + if (apkButtonState == ApkButtonState.Creating) profileDropDown.Enabled = false; Color col = profileDropDown.Enabled ? colGreen : colInactive; @@ -144,79 +140,81 @@ namespace AM2RLauncher /// /// Determines current conditions and enables or disables controls accordingly. /// - private void UpdateProfileSettingsState() + private void UpdateModSettingsState() { // Safety check - if (settingsProfileDropDown == null || settingsProfileDropDown.Items.Count <= 0) return; + if (modSettingsProfileDropDown == null || modSettingsProfileDropDown.Items.Count <= 0) return; bool enabled = false; switch (updateState) { - case UpdateState.Download: - case UpdateState.Downloading: - case UpdateState.Select11: - case UpdateState.Installing: - case UpdateState.Playing: enabled = false; break; - case UpdateState.Install: - case UpdateState.Play: enabled = true; break; + case PlayButtonState.Download: + case PlayButtonState.Downloading: + case PlayButtonState.Select11: + case PlayButtonState.Installing: + case PlayButtonState.Playing: enabled = false; break; + + case PlayButtonState.Install: + case PlayButtonState.Play: enabled = true; break; } if (apkButtonState == ApkButtonState.Creating) enabled = false; + string selectedProfileName = modSettingsProfileDropDown.Items[modSettingsProfileDropDown.SelectedIndex].Text; + settingsProfileLabel.TextColor = colGreen; - settingsProfileDropDown.Enabled = enabled; + modSettingsProfileDropDown.Enabled = enabled; profileButton.Enabled = enabled; - profileButton.ToolTip = Language.Text.OpenProfileFolderToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + profileButton.ToolTip = HelperMethods.GetText(Text.OpenProfileFolderToolTip, selectedProfileName); saveButton.Enabled = enabled; - saveButton.ToolTip = Language.Text.OpenSaveFolderToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + saveButton.ToolTip = HelperMethods.GetText(Text.OpenSaveFolderToolTip, selectedProfileName); addModButton.Enabled = enabled; - addModButton.ToolTip = Language.Text.AddNewModToolTip; + addModButton.ToolTip = Text.AddNewModToolTip; // Only enable these, when we're not on the community updates - if (settingsProfileDropDown.SelectedIndex > 0) + if (modSettingsProfileDropDown.SelectedIndex > 0) { - updateModButton.Enabled = profileList[settingsProfileDropDown.SelectedIndex].Installable; - updateModButton.ToolTip = Language.Text.UpdateModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + updateModButton.Enabled = profileList[modSettingsProfileDropDown.SelectedIndex].Installable; + updateModButton.ToolTip = HelperMethods.GetText(Text.UpdateModButtonToolTip, selectedProfileName); deleteModButton.Enabled = enabled; - deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); + deleteModButton.ToolTip = HelperMethods.GetText(Text.DeleteModButtonToolTip, selectedProfileName); } Color col = enabled ? colGreen : colInactive; if (OS.IsWindows) - settingsProfileDropDown.TextColor = col; + modSettingsProfileDropDown.TextColor = col; settingsProfileLabel.TextColor = col; if (enabled) - { - settingsProfileDropDown.SelectedIndex = profileDropDown.SelectedIndex; - } + modSettingsProfileDropDown.SelectedIndex = profileDropDown.SelectedIndex; } /// /// Sets the global and then changes the state of accordingly. /// /// The state that should be set to. - private void SetPlayButtonState(UpdateState state) + private void SetPlayButtonState(PlayButtonState state) { updateState = state; - string profileName = ((profileDropDown != null) && (profileDropDown.Items.Count > 0)) ? profileDropDown.Items[profileDropDown.SelectedIndex].Text : ""; switch (updateState) { - case UpdateState.Download: playButton.Enabled = true; playButton.ToolTip = Language.Text.PlayButtonDownloadToolTip; break; - case UpdateState.Downloading: playButton.Enabled = true; playButton.ToolTip = ""; playButton.ToolTip = Language.Text.PlayButtonDownladingToolTip; break; - case UpdateState.Select11: playButton.Enabled = true; playButton.ToolTip = Language.Text.PlayButtonSelect11ToolTip; break; - case UpdateState.Install: playButton.Enabled = true; playButton.ToolTip = Language.Text.PlayButtonInstallToolTip.Replace("$NAME", profileName); break; - case UpdateState.Installing: playButton.Enabled = false; playButton.ToolTip = Language.Text.PlayButtonInstallingToolTip; break; - case UpdateState.Play: playButton.Enabled = true; playButton.ToolTip = Language.Text.PlayButtonPlayToolTip.Replace("$NAME", profileName); break; - case UpdateState.Playing: playButton.Enabled = false; playButton.ToolTip = Language.Text.PlayButtonPlayingToolTip; break; + case PlayButtonState.Download: + case PlayButtonState.Downloading: + case PlayButtonState.Select11: + case PlayButtonState.Install: + case PlayButtonState.Play: playButton.Enabled = true; break; + + case PlayButtonState.Installing: + case PlayButtonState.Playing: playButton.Enabled = false; break; } playButton.Text = GetPlayButtonText(); + playButton.ToolTip = GetPlayButtonTooltip(); playButton.Invalidate(); - UpdateProfileSettingsState(); + UpdateModSettingsState(); } /// @@ -242,13 +240,33 @@ namespace AM2RLauncher { switch (updateState) { - case UpdateState.Download: return Language.Text.Download; - case UpdateState.Downloading: return Language.Text.Abort; - case UpdateState.Select11: return Language.Text.Select11; - case UpdateState.Install: return Language.Text.Install; - case UpdateState.Installing: return Language.Text.Installing; - case UpdateState.Play: return Language.Text.Play; - case UpdateState.Playing: return Language.Text.Playing; + case PlayButtonState.Download: return Text.Download; + case PlayButtonState.Downloading: return Text.Abort; + case PlayButtonState.Select11: return Text.Select11; + case PlayButtonState.Install: return Text.Install; + case PlayButtonState.Installing: return Text.Installing; + case PlayButtonState.Play: return Text.Play; + case PlayButtonState.Playing: return Text.Playing; + default: return null; + } + } + + /// + /// This returns the tooltip that should have depending on the global updateState. + /// + /// The tooltip as a , or if the current State is invalid. + private string GetPlayButtonTooltip() + { + string profileName = ((profileDropDown != null) && (profileDropDown.Items.Count > 0)) ? profileDropDown.Items[profileDropDown.SelectedIndex].Text : ""; + switch (updateState) + { + case PlayButtonState.Download: return Text.PlayButtonDownloadToolTip; + case PlayButtonState.Downloading: return Text.PlayButtonDownloadToolTip; + case PlayButtonState.Select11: return Text.PlayButtonSelect11ToolTip; + case PlayButtonState.Install: return playButton.ToolTip = HelperMethods.GetText(Text.PlayButtonInstallToolTip, profileName); + case PlayButtonState.Installing: return Text.PlayButtonInstallingToolTip; + case PlayButtonState.Play: return HelperMethods.GetText(Text.PlayButtonPlayToolTip, profileName); + case PlayButtonState.Playing: return Text.PlayButtonPlayingToolTip; default: return null; } } @@ -261,8 +279,8 @@ namespace AM2RLauncher { switch (apkButtonState) { - case ApkButtonState.Create: return Language.Text.CreateAPK; - case ApkButtonState.Creating: return Language.Text.CreatingAPK; + case ApkButtonState.Create: return Text.CreateAPK; + case ApkButtonState.Creating: return Text.CreatingAPK; default: return null; } } @@ -286,11 +304,10 @@ namespace AM2RLauncher // Archive version notes if (!profile.Installable) { - //TODO: localizations if (profile.Name.Contains("Community Updates")) - profile.ProfileNotes = Language.Text.ArchiveNotesCommunityUpdates; + profile.ProfileNotes = Text.ArchiveNotesCommunityUpdates; else - profile.ProfileNotes = Language.Text.ArchiveNotesMods + "\n\n" + profile.ProfileNotes; + profile.ProfileNotes = Text.ArchiveNotesMods + "\n\n" + profile.ProfileNotes; } profileDropDown.Items.Add(profile.Name); @@ -317,15 +334,15 @@ namespace AM2RLauncher } // Update stored profiles in the Profile Settings tab - settingsProfileDropDown.Items.Clear(); - settingsProfileDropDown.Items.AddRange(profileDropDown.Items); - settingsProfileDropDown.SelectedIndex = profileDropDown.Items.Count != 0 ? 0 : -1; + modSettingsProfileDropDown.Items.Clear(); + modSettingsProfileDropDown.Items.AddRange(profileDropDown.Items); + modSettingsProfileDropDown.SelectedIndex = profileDropDown.Items.Count != 0 ? 0 : -1; // Refresh the author and version label on the main tab if (profileList.Count > 0) { - profileAuthorLabel.Text = Language.Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; - profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; + profileAuthorLabel.Text = Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; + profileVersionLabel.Text = Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; } log.Info("Reloading UI components after loading successful."); @@ -349,5 +366,18 @@ namespace AM2RLauncher Profile.ArchiveProfile(profile); LoadProfilesAndAdjustLists(); } + + /// Enables and changes colors for and accordingly. + private void EnableMirrorControlsAccordingly() + { + bool enabled = (bool)customMirrorCheck.Checked; + customMirrorTextBox.Enabled = enabled; + mirrorDropDown.Enabled = !enabled; + // Not sure why the dropdown menu needs this hack, but the textBox does not. + //TODO: eto feature request + if (OS.IsWindows) + mirrorDropDown.TextColor = mirrorDropDown.Enabled ? colGreen : colInactive; + mirrorLabel.TextColor = !enabled ? colGreen : colInactive; + } } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs index 1fe357f..a20598e 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs @@ -1,5 +1,7 @@ using AM2RLauncher.Core; using AM2RLauncher.Core.XML; +using AM2RLauncher.Language; +using AM2RLauncher.Properties; using Eto.Drawing; using Eto.Forms; using log4net; @@ -30,15 +32,11 @@ namespace AM2RLauncher /// private const string VERSION = LauncherUpdater.VERSION; - /// - /// A of the AM2R icon. - /// - private static readonly Bitmap am2rIcon = new Bitmap(AM2RLauncher.Properties.Resources.AM2RIcon); /// - /// An enum, that has possible states for our Launcher. + /// An enum, that has possible states for the play button. /// - public enum UpdateState + public enum PlayButtonState { Download, Downloading, @@ -61,7 +59,7 @@ namespace AM2RLauncher /// /// This variable has the current global state of the Launcher. /// - private static UpdateState updateState = UpdateState.Download; + private static PlayButtonState updateState = PlayButtonState.Download; /// /// This variable has the current global statue of the . /// @@ -100,13 +98,9 @@ namespace AM2RLauncher if (OS.IsWindows) { Process current = Process.GetCurrentProcess(); - foreach (Process process in Process.GetProcessesByName(current.ProcessName)) - { - if (process.Id == current.Id) - continue; + Process process = Process.GetProcessesByName(current.ProcessName).First(p => p.Id == current.Id); + if (process != null) Core.Core.SetForegroundWindow(process.MainWindowHandle); - break; - } } Environment.Exit(0); } @@ -133,8 +127,10 @@ namespace AM2RLauncher #region VARIABLE INITIALIZATION log.Info("Beginning UI initialization..."); + Bitmap am2rIcon = new Bitmap(AM2RLauncher.Properties.Resources.AM2RIcon); + // System tray indicator - showButton = new ButtonMenuItem { Text = Language.Text.TrayButtonShow }; + ButtonMenuItem showButton = new ButtonMenuItem { Text = Text.TrayButtonShow }; trayIndicator = new TrayIndicator { Menu = new ContextMenu(showButton), @@ -150,6 +146,7 @@ namespace AM2RLauncher // Create array from validCount profileList = new List(); + //TODO: whenever profileDropDown gets rewritten to use a datastore, scrap this profileNames = new List(); foreach (var profile in profileList) { @@ -160,22 +157,6 @@ namespace AM2RLauncher string splash = Splash.GetSplash(); log.Info("Randomly chosen splash: " + splash); - // Load bitmaps - redditIcon = new Bitmap(AM2RLauncher.Properties.Resources.redditIcon48); - githubIcon = new Bitmap(AM2RLauncher.Properties.Resources.githubIcon48); - youtubeIcon = new Bitmap(AM2RLauncher.Properties.Resources.youtubeIcon48); - discordIcon = new Bitmap(AM2RLauncher.Properties.Resources.discordIcon48); - formBG = new Bitmap(AM2RLauncher.Properties.Resources.bgCentered); - - // Load colors - colGreen = Color.FromArgb(142, 188, 35); - colRed = Color.FromArgb(188, 10, 35); - colInactive = Color.FromArgb(109, 109, 109); - colBGNoAlpha = Color.FromArgb(10, 10, 10); - colBG = Color.FromArgb(10, 10, 10, 80); - if (OS.IsLinux) colBG = colBGNoAlpha; // XORG can't display alpha anyway, and Wayland breaks with it. - colBGHover = Color.FromArgb(17, 28, 13); - Font smallButtonFont = new Font(SystemFont.Default, 10); // Create mirror list - eventually this should be platform specific! @@ -189,8 +170,8 @@ namespace AM2RLauncher foreach (var mirror in mirrorList) { string text = mirror; - if (text.Contains("github.com")) text = Language.Text.MirrorGithubText; - else if (text.Contains("gitlab.com")) text = Language.Text.MirrorGitlabText; + if (text.Contains("github.com")) text = Text.MirrorGithubText; + else if (text.Contains("gitlab.com")) text = Text.MirrorGitlabText; mirrorDescriptionList.Add(new ListItem() { Key = mirror, Text = text }); } #endregion @@ -246,7 +227,7 @@ namespace AM2RLauncher // APK button apkButton = new ColorButton { - Text = Language.Text.CreateAPK, + Text = Text.CreateAPK, Height = 40, Width = 250, TextColor = colGreen, @@ -286,7 +267,7 @@ namespace AM2RLauncher { BackgroundColor = colBG, Height = 15, - Text = Language.Text.CurrentProfile, + Text = Text.CurrentProfile, TextColor = colGreen }; @@ -315,7 +296,7 @@ namespace AM2RLauncher { BackgroundColor = colBG, Height = 16, - Text = Language.Text.Author + " ", + Text = Text.Author + " ", TextColor = colGreen }; @@ -325,7 +306,7 @@ namespace AM2RLauncher { BackgroundColor = colBG, Height = 16, - Text = Language.Text.VersionLabel + " ", + Text = Text.VersionLabel + " ", TextColor = colGreen }; @@ -337,7 +318,7 @@ namespace AM2RLauncher BackgroundColor = colBG, Width = 20, Height = 55, - Text = Language.Text.SaveLocationWarning, + Text = Text.SaveLocationWarning, TextColor = colRed }; @@ -345,17 +326,21 @@ namespace AM2RLauncher // Social buttons - var redditButton = new ImageButton { ToolTip = Language.Text.RedditToolTip, Image = redditIcon }; - redditButton.Click += RedditIconOnClick; + Bitmap redditIcon = new Bitmap(Resources.redditIcon48); + var redditButton = new ImageButton { ToolTip = Text.RedditToolTip, Image = redditIcon }; + redditButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.reddit.com/r/AM2R"); - var githubButton = new ImageButton { ToolTip = Language.Text.GithubToolTip, Image = githubIcon }; - githubButton.Click += GithubIconOnClick; + Bitmap githubIcon = new Bitmap(Resources.githubIcon48); + var githubButton = new ImageButton { ToolTip = Text.GithubToolTip, Image = githubIcon }; + githubButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.github.com/AM2R-Community-Developers"); - var youtubeButton = new ImageButton { ToolTip = Language.Text.YoutubeToolTip, Image = youtubeIcon }; - youtubeButton.Click += YoutubeIconOnClick; + Bitmap youtubeIcon = new Bitmap(Resources.youtubeIcon48); + var youtubeButton = new ImageButton { ToolTip = Text.YoutubeToolTip, Image = youtubeIcon }; + youtubeButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://www.youtube.com/c/AM2RCommunityUpdates"); - var discordButton = new ImageButton { ToolTip = Language.Text.DiscordToolTip, Image = discordIcon }; - discordButton.Click += DiscordIconOnClick; + Bitmap discordIcon = new Bitmap(Resources.discordIcon48); + var discordButton = new ImageButton { ToolTip = Text.DiscordToolTip, Image = discordIcon }; + discordButton.Click += (sender, e) => CrossPlatformOperations.OpenURL("https://discord.gg/nk7UYPbd5u"); // Social button panel @@ -369,7 +354,12 @@ namespace AM2RLauncher // Version number label - versionLabel = new Label { Text = "v" + VERSION + (isThisRunningFromWine ? "-WINE" : ""), Width = 48, TextAlignment = TextAlignment.Right, TextColor = colGreen, Font = new Font(SystemFont.Default, 12) }; + Label versionLabel = new Label + { + Text = "v" + VERSION + (isThisRunningFromWine ? "-WINE" : ""), + Width = 48, TextAlignment = TextAlignment.Right, TextColor = colGreen, + Font = new Font(SystemFont.Default, 12) + }; // Tie everything together var mainLayout = new DynamicLayout(); @@ -390,33 +380,34 @@ namespace AM2RLauncher #region TABS + #region MAIN PAGE // [MAIN PAGE] - mainPage = new TabPage + TabPage mainPage = new TabPage { BackgroundColor = colBGNoAlpha, - Text = Language.Text.PlayTab, + Text = Text.PlayTab, Content = drawable }; + #endregion + #region CHANGELOG PAGE // [CHANGELOG] - - changelogUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/changelog.html"); - - changelogWebView = new WebView { Url = changelogUri }; + Uri changelogUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/changelog.html"); + WebView changelogWebView = new WebView { Url = changelogUri }; if (OS.IsUnix && !isInternetThere) changelogWebView = new WebView(); - changelogNoConnectionLabel = new Label + Label changelogNoConnectionLabel = new Label { - Text = Language.Text.NoInternetConnection, + Text = Text.NoInternetConnection, TextColor = colGreen }; - changelogPage = new TabPage + TabPage changelogPage = new TabPage { BackgroundColor = colBGNoAlpha, - Text = Language.Text.ChangelogTab, + Text = Text.ChangelogTab, Content = new TableLayout { @@ -427,22 +418,27 @@ namespace AM2RLauncher } }; + #endregion + + #region NEWS PAGE + // [NEWS] - newsUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/news.html"); - newsWebView = new WebView { Url = newsUri }; + Uri newsUri = new Uri("https://am2r-community-developers.github.io/DistributionCenter/news.html"); + WebView newsWebView = new WebView { Url = newsUri }; + //TODO: why exactly is this check necessary? if (OS.IsUnix && !isInternetThere) newsWebView = new WebView(); - newsNoConnectionLabel = new Label + Label newsNoConnectionLabel = new Label { - Text = Language.Text.NoInternetConnection, + Text = Text.NoInternetConnection, TextColor = colGreen }; - newsPage = new TabPage + TabPage newsPage = new TabPage { - Text = Language.Text.NewsTab, + Text = Text.NewsTab, BackgroundColor = colBGNoAlpha, Content = new TableLayout @@ -454,6 +450,7 @@ namespace AM2RLauncher } }; + //TODO: this is hack because on linux / mac the other way doesn't work. eto issue? if (OS.IsUnix && !isInternetThere) { changelogPage.Content = new TableLayout @@ -476,13 +473,17 @@ namespace AM2RLauncher }; } + #endregion + + #region SETTINGS PAGE + // [LAUNCHER SETTINGS] DynamicLayout settingsLayout = new DynamicLayout(); // LanguageLabel - languageLabel = new Label + Label languageLabel = new Label { - Text = Language.Text.LanguageNotice, + Text = Text.LanguageNotice, TextColor = colGreen }; @@ -490,7 +491,7 @@ namespace AM2RLauncher List languageList = new List { - Language.Text.SystemLanguage, + Text.SystemLanguage, "Deutsch", "English", "Español", @@ -525,7 +526,7 @@ namespace AM2RLauncher autoUpdateAM2RCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateAM2R")), - Text = Language.Text.AutoUpdateAM2R, + Text = Text.AutoUpdateAM2R, TextColor = colGreen }; @@ -534,7 +535,7 @@ namespace AM2RLauncher autoUpdateLauncherCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("AutoUpdateLauncher")), - Text = Language.Text.AutoUpdateLauncher, + Text = Text.AutoUpdateLauncher, TextColor = colGreen }; @@ -542,7 +543,7 @@ namespace AM2RLauncher hqMusicPCCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQPC")), - Text = Language.Text.HighQualityPC, + Text = Text.HighQualityPC, TextColor = colGreen }; @@ -550,7 +551,7 @@ namespace AM2RLauncher hqMusicAndroidCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("MusicHQAndroid")), - Text = Language.Text.HighQualityAndroid, + Text = Text.HighQualityAndroid, TextColor = colGreen }; @@ -558,17 +559,17 @@ namespace AM2RLauncher profileDebugLogCheck = new CheckBox { Checked = bool.Parse(CrossPlatformOperations.ReadFromConfig("ProfileDebugLog")), - Text = Language.Text.ProfileDebugCheckBox, + Text = Text.ProfileDebugCheckBox, TextColor = colGreen }; // Custom environment variables label - customEnvVarLabel = new Label(); + Label customEnvVarLabel = new Label(); if (OS.IsLinux) { customEnvVarLabel = new Label { - Text = Language.Text.CustomEnvVarLabel, + Text = Text.CustomEnvVarLabel, TextColor = colGreen }; } @@ -588,7 +589,7 @@ namespace AM2RLauncher // Mirror list mirrorLabel = new Label { - Text = Language.Text.DownloadSource, + Text = Text.DownloadSource, TextColor = colGreen }; @@ -611,7 +612,7 @@ namespace AM2RLauncher customMirrorCheck = new CheckBox { Checked = Boolean.Parse(CrossPlatformOperations.ReadFromConfig("CustomMirrorEnabled")), - Text = Language.Text.CustomMirrorCheck, + Text = Text.CustomMirrorCheck, TextColor = colGreen }; @@ -622,6 +623,8 @@ namespace AM2RLauncher TextColor = colGreen }; + EnableMirrorControlsAccordingly(); + settingsLayout.BeginHorizontal(); settingsLayout.AddSpace(); settingsLayout.AddColumn(null, languageLabel, languageDropDown, autoUpdateAM2RCheck, autoUpdateLauncherCheck, hqMusicPCCheck, hqMusicAndroidCheck, profileDebugLogCheck, customEnvVarLabel, (Control)customEnvVarTextBox ?? new Label(), mirrorLabel, mirrorDropDown, customMirrorCheck, customMirrorTextBox, null); @@ -631,18 +634,21 @@ namespace AM2RLauncher { BackgroundColor = colBGNoAlpha, Content = settingsLayout, - Text = Language.Text.LauncherSettingsTab + Text = Text.LauncherSettingsTab }; - // [MOD SETTINGS] + #endregion - DynamicLayout profileLayout = new DynamicLayout(); + #region MODSETTINGS PAGE + + // [MOD SETTINGS] + DynamicLayout modSettingsLayout = new DynamicLayout(); addModButton = new ColorButton { ToolTip = null, - Text = Language.Text.AddNewMod, + Text = Text.AddNewMod, Font = smallButtonFont, Height = 30, Width = 275, @@ -659,12 +665,12 @@ namespace AM2RLauncher settingsProfileLabel = new Label { - Text = Language.Text.CurrentProfile, + Text = Text.CurrentProfile, TextColor = colGreen, Width = 275 }; - settingsProfileDropDown = new DropDown + modSettingsProfileDropDown = new DropDown { TextColor = colGreen, BackgroundColor = OS.IsWindows ? colBGNoAlpha : new Color() @@ -672,14 +678,14 @@ namespace AM2RLauncher // In order to not have conflicting theming, we just always respect the users theme for dropdown on GTK. if (OS.IsLinux) - settingsProfileDropDown = new DropDown(); + modSettingsProfileDropDown = new DropDown(); - settingsProfileDropDown.Items.AddRange(profileNames); // It's actually more comfortable if it's outside, because of GTK shenanigans + modSettingsProfileDropDown.Items.AddRange(profileNames); // It's actually more comfortable if it's outside, because of GTK shenanigans profileButton = new ColorButton { ToolTip = null, - Text = Language.Text.OpenProfileFolder, + Text = Text.OpenProfileFolder, Font = smallButtonFont, Height = 30, Width = 275, @@ -692,7 +698,7 @@ namespace AM2RLauncher saveButton = new ColorButton { ToolTip = null, - Text = Language.Text.OpenSaveFolder, + Text = Text.OpenSaveFolder, Font = smallButtonFont, Height = 30, Width = 275, @@ -705,7 +711,7 @@ namespace AM2RLauncher updateModButton = new ColorButton { ToolTip = null, - Text = Language.Text.UpdateModButtonText, + Text = Text.UpdateModButtonText, Font = smallButtonFont, Height = 30, Width = 275, @@ -718,7 +724,7 @@ namespace AM2RLauncher deleteModButton = new ColorButton { ToolTip = null, - Text = Language.Text.DeleteModButtonText, + Text = Text.DeleteModButtonText, Font = smallButtonFont, Height = 30, Width = 275, @@ -736,23 +742,25 @@ namespace AM2RLauncher SpellCheck = false, Width = 275, Height = 150, - Text = Language.Text.ProfileNotes + Text = Text.ProfileNotes }; - profileLayout.BeginHorizontal(); - profileLayout.AddSpace(); - profileLayout.AddColumn(null, addModButton, modSpacer, settingsProfileLabel, settingsProfileDropDown, profileButton, saveButton, updateModButton, deleteModButton, profileNotesTextArea, null); - profileLayout.AddSpace(); + modSettingsLayout.BeginHorizontal(); + modSettingsLayout.AddSpace(); + modSettingsLayout.AddColumn(null, addModButton, modSpacer, settingsProfileLabel, modSettingsProfileDropDown, profileButton, saveButton, updateModButton, deleteModButton, profileNotesTextArea, null); + modSettingsLayout.AddSpace(); - profilePage = new TabPage + TabPage modSettingsPage = new TabPage { BackgroundColor = colBGNoAlpha, - Content = profileLayout, - Text = Language.Text.ProfileSettingsTab + Content = modSettingsLayout, + Text = Text.ModSettingsTab }; #endregion + #endregion + Content = new TabControl { Pages = @@ -765,7 +773,7 @@ namespace AM2RLauncher settingsPage, - profilePage + modSettingsPage } }; @@ -782,7 +790,6 @@ namespace AM2RLauncher hqMusicAndroidCheck.CheckedChanged += HqMusicAndroidCheckChanged; hqMusicPCCheck.CheckedChanged += HqMusicPCCheckChanged; customMirrorCheck.CheckedChanged += CustomMirrorCheckChanged; - customMirrorCheck.LoadComplete += CustomMirrorCheckLoadComplete; apkButton.Click += ApkButtonClickEvent; apkButton.LoadComplete += (sender, e) => UpdateApkState(); profileDropDown.LoadComplete += (sender, e) => UpdateProfileState(); @@ -790,11 +797,11 @@ namespace AM2RLauncher playButton.LoadComplete += PlayButtonLoadComplete; customMirrorTextBox.LostFocus += CustomMirrorTextBoxLostFocus; mirrorDropDown.SelectedIndexChanged += MirrorDropDownSelectedIndexChanged; - profileLayout.LoadComplete += ProfileLayoutLoadComplete; + modSettingsLayout.LoadComplete += ProfileLayoutLoadComplete; addModButton.Click += AddModButtonClicked; - profileButton.Click += ProfilesButtonClickEvent; + profileButton.Click += ProfileDataButtonClickEvent; saveButton.Click += SaveButtonClickEvent; - settingsProfileDropDown.SelectedIndexChanged += SettingsProfileDropDownSelectedIndexChanged; + modSettingsProfileDropDown.SelectedIndexChanged += ModSettingsProfileDropDownSelectedIndexChanged; deleteModButton.Click += DeleteModButtonClicked; updateModButton.Click += UpdateModButtonClicked; profileDebugLogCheck.CheckedChanged += ProfileDebugLogCheckedChanged; @@ -802,8 +809,8 @@ namespace AM2RLauncher customEnvVarTextBox.LostFocus += CustomEnvVarTextBoxLostFocus; //TODO: Retest if these now work on mac - newsWebView.DocumentLoaded += NewsWebViewDocumentLoaded; - changelogWebView.DocumentLoaded += ChangelogWebViewDocumentLoaded; + newsWebView.DocumentLoaded += (sender, e) => ChangeToEmptyPageOnNoInternet(newsPage, newsNoConnectionLabel); + changelogWebView.DocumentLoaded += (sender, e) => ChangeToEmptyPageOnNoInternet(changelogPage, changelogNoConnectionLabel); log.Info("Events linked successfully."); @@ -815,40 +822,32 @@ namespace AM2RLauncher // Visual studio does it like this for normal winforms projects, so I just used the same format. /// The tray indicator - TrayIndicator trayIndicator; - /// The "Show" Button on the tray indicator - ButtonMenuItem showButton; + private TrayIndicator trayIndicator; /// of s, used for actually working with profile data. + //TODO: this should be moved into AM2RLauncher.Core List profileList; /// of s so that Eto's annoying interface is appeased. Used for profile name display in DropDowns. List profileNames; - // Bitmaps - /// The Reddit icon. - private Bitmap redditIcon; - /// The Github icon. - private Bitmap githubIcon; - /// The YouTube icon. - private Bitmap youtubeIcon; - /// The Discord icon. - private Bitmap discordIcon; /// The planet Background. - private Bitmap formBG; + private readonly Bitmap formBG = new Bitmap(Resources.bgCentered); // Colors /// The main green color. - private Color colGreen; + private readonly Color colGreen = Color.FromArgb(142, 188, 35); /// The warning red color. - private Color colRed; + private readonly Color colRed = Color.FromArgb(188, 10, 35); /// The main inactive color. - private Color colInactive; + private readonly Color colInactive = Color.FromArgb(109, 109, 109); /// The black background color without alpha value. - private Color colBGNoAlpha; + private readonly Color colBGNoAlpha = Color.FromArgb(10, 10, 10); /// The black background color. - private Color colBG; + // XORG can't display alpha anyway, and Wayland breaks with it. + // TODO: that sounds like an Eto bug. investigate, try to open eto issue. + private readonly Color colBG = OS.IsLinux ? Color.FromArgb(10, 10, 10) : Color.FromArgb(10, 10, 10, 80); /// The lighter green color on hover. - private Color colBGHover; + private readonly Color colBGHover = Color.FromArgb(17, 28, 13); // Mirror lists /// of mirror s, used for actually working with mirrors. @@ -857,7 +856,7 @@ namespace AM2RLauncher private List mirrorDescriptionList; // UI Elements - /// The main control of the , used to draw the and hold the main interface. + /// 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 @@ -875,8 +874,6 @@ namespace AM2RLauncher /// A that is used to delete a mod private ColorButton deleteModButton; - /// The that gives information for . - private Label languageLabel; /// The that entitles . private Label profileLabel; /// The that gives author information for . @@ -885,22 +882,12 @@ namespace AM2RLauncher private Label profileVersionLabel; /// The that gives information for . private Label mirrorLabel; - /// The that displays , aka the current launcher version. - private Label versionLabel; - /// The that gives information for . + /// The that gives information for . private Label settingsProfileLabel; /// The that compliments . private Label progressLabel; - /// The that gives a warning on failure to load the . - private Label newsNoConnectionLabel; - /// The that gives a warning on failure to load the . - private Label changelogNoConnectionLabel; /// The that gives a warning if the current selected shares the same save location has default AM2R. private Label saveWarningLabel; - /// The that describes . - private Label customEnvVarLabel; - - /// A , that indicates wether to automatically update AM2R or not. private CheckBox autoUpdateAM2RCheck; @@ -922,38 +909,20 @@ namespace AM2RLauncher /// A where profiles can be chosen. private DropDown profileDropDown; /// A where profiles can be chosen (located in Profile Settings). - private DropDown settingsProfileDropDown; + //TODO: Use MVVM bindings: https://github.com/picoe/Eto/wiki/Data-Binding#mvvm-binding + private DropDown modSettingsProfileDropDown; /// A , where the user can input their custom mirror. private TextBox customMirrorTextBox; /// A , where the user can input their custom environment variables. private TextBox customEnvVarTextBox; - /// A , where the notes from the current selected profile in are displayed. + /// A , where the notes from the current selected profile in are displayed. private TextArea profileNotesTextArea; /// A that can be used to show progress for a specific task. private ProgressBar progressBar; - /// The Uri used by . - private Uri newsUri; - /// The Uri used by . - private Uri changelogUri; - - /// A to display the DistributionCenter news page. - private WebView newsWebView; - /// A to display the DistributionCenter changelog page. - private WebView changelogWebView; - - /// A for the Launcher's main interface. - private TabPage mainPage; - /// A for the Launcher's news integration. - private TabPage newsPage; - /// A for the Launcher's changelog integration. - private TabPage changelogPage; - /// A for the Launcher's profile settings. - private TabPage profilePage; - #endregion } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs b/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs index 5939915..2482028 100644 --- a/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs +++ b/AM2RLauncher/AM2RLauncherCore/CrossPlatformOperations.cs @@ -353,7 +353,6 @@ public static class CrossPlatformOperations try { xdelta.Start(); - xdelta.WaitForExit(); } catch (System.ComponentModel.Win32Exception) diff --git a/AM2RLauncher/AM2RLauncherCore/HelperMethods.cs b/AM2RLauncher/AM2RLauncherCore/HelperMethods.cs index ba5c66b..9ed21e9 100644 --- a/AM2RLauncher/AM2RLauncherCore/HelperMethods.cs +++ b/AM2RLauncher/AM2RLauncherCore/HelperMethods.cs @@ -1,6 +1,7 @@ using log4net; using System; using System.IO; +using System.Linq; using System.Net; using System.Security.Cryptography; @@ -160,4 +161,15 @@ public static class HelperMethods log.Info("Internet connection established!"); return true; } + + /// + /// Gets and replaces "$NAME" with . + /// + /// The text to get + /// The text to replace "$NAME" with. + /// + public static string GetText(string languageText, string replacementText = "") + { + return languageText.Replace("$NAME", replacementText); + } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncherCore/Profile.cs b/AM2RLauncher/AM2RLauncherCore/Profile.cs index 7c16c87..a03687e 100644 --- a/AM2RLauncher/AM2RLauncherCore/Profile.cs +++ b/AM2RLauncher/AM2RLauncherCore/Profile.cs @@ -47,13 +47,14 @@ public static class Profile /// /// Checks if AM2R 1.1 has been installed already, aka if a valid AM2R 1.1 Zip exists. + /// This method will store the result in a cache and return that, unless it's invalidated by . /// - /// Determines if the AM2R_11 Cache should be invalidated + /// Determines if the AM2R_11 Cache should be invalidated. /// public static bool Is11Installed(bool invalidateCache = false) { // Only invalidate if we need to - if (invalidateCache) InvalidateAM2R11InstallCacheIfNecessary(); + if (invalidateCache) InvalidateAM2R11InstallCache(); // If we have a cache, return that instead if (isAM2R11InstalledCache != null) return isAM2R11InstalledCache.Value; @@ -78,7 +79,7 @@ public static class Profile /// /// Invalidates if necessary. /// - private static void InvalidateAM2R11InstallCacheIfNecessary() + 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") && @@ -88,6 +89,64 @@ public static class Profile isAM2R11InstalledCache = null; } + /// + /// Checks if a Zip file is a valid AM2R_1.1 zip. + /// + /// Full Path to the Zip file to check. + /// detailing the result + public static IsZipAM2R11ReturnCodes CheckIfZipIsAM2R11(string zipPath) + { + const string d3dHash = "86e39e9161c3d930d93822f1563c280d"; + const string dataWinHash = "f2b84fe5ba64cb64e284be1066ca08ee"; + const string am2rHash = "15253f7a66d6ea3feef004ebbee9b438"; + + string tmpPath = Path.GetTempPath() + Path.GetFileNameWithoutExtension(zipPath); + + // Clean up in case folder exists already + if (Directory.Exists(tmpPath)) + Directory.Delete(tmpPath, true); + + Directory.CreateDirectory(tmpPath); + + // Open archive + ZipArchive am2rZip = ZipFile.OpenRead(zipPath); + + // Check if exe exists anywhere + ZipArchiveEntry am2rExe = am2rZip.Entries.FirstOrDefault(x => x.FullName.Contains("AM2R.exe")); + if (am2rExe == null) + return IsZipAM2R11ReturnCodes.MissingOrInvalidAM2RExe; + // Check if it's not in a subfolder. if it'd be in a subfolder, fullname would be "folder/AM2R.exe" + if (am2rExe.FullName != "AM2R.exe") + return IsZipAM2R11ReturnCodes.GameIsInASubfolder; + // Check validity + am2rExe.ExtractToFile(tmpPath + "/" + am2rExe.FullName); + if (HelperMethods.CalculateMD5(tmpPath + "/" + am2rExe.FullName) != am2rHash) + return IsZipAM2R11ReturnCodes.MissingOrInvalidAM2RExe; + + // Check if data.win exists / is valid + ZipArchiveEntry dataWin = am2rZip.Entries.FirstOrDefault(x => x.FullName == "data.win"); + if (dataWin == null) + return IsZipAM2R11ReturnCodes.MissingOrInvalidDataWin; + dataWin.ExtractToFile(tmpPath + "/" + dataWin.FullName); + if (HelperMethods.CalculateMD5(tmpPath + "/" + dataWin.FullName) != dataWinHash) + return IsZipAM2R11ReturnCodes.MissingOrInvalidDataWin; + + // Check if d3d.dll exists / is valid + ZipArchiveEntry d3dx = am2rZip.Entries.FirstOrDefault(x => x.FullName == "D3DX9_43.dll"); + if (d3dx == null) + return IsZipAM2R11ReturnCodes.MissingOrInvalidD3DX9_43Dll; + d3dx.ExtractToFile(tmpPath + "/" + d3dx.FullName); + if (HelperMethods.CalculateMD5(tmpPath + "/" + d3dx.FullName) != d3dHash) + return IsZipAM2R11ReturnCodes.MissingOrInvalidD3DX9_43Dll; + + // Clean up + Directory.Delete(tmpPath, true); + + // If we didn't exit before, everything is fine + log.Info("AM2R_11 check successful!"); + return IsZipAM2R11ReturnCodes.Successful; + } + /// /// Git Pulls from the repository. /// @@ -240,9 +299,7 @@ public static class Profile // Delete folder in Mods if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + profile.DataPath)) - { HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + profile.DataPath); - } // Delete the zip file in Mods if (File.Exists(CrossPlatformOperations.CURRENTPATH + profile.DataPath + ".zip")) @@ -254,9 +311,7 @@ public static class Profile // Delete folder in Profiles if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) - { HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name); - } log.Info("Successfully deleted profile " + profile.Name + "."); } @@ -497,6 +552,7 @@ public static class Profile progress.Report(100); return; } + log.Info("Creating Android APK for profile " + profile.Name + "."); // Create working dir after some cleanup @@ -782,62 +838,4 @@ public static class Profile // isValid seems to only check for a .git folder, and there are cases where that exists, but not the profile.xml return Repository.IsValid(CrossPlatformOperations.CURRENTPATH + "/PatchData") && File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml"); } - - /// - /// Checks if a Zip file is a valid AM2R_1.1 zip. - /// - /// Full Path to the Zip file to check. - /// detailing the result - public static IsZipAM2R11ReturnCodes CheckIfZipIsAM2R11(string zipPath) - { - const string d3dHash = "86e39e9161c3d930d93822f1563c280d"; - const string dataWinHash = "f2b84fe5ba64cb64e284be1066ca08ee"; - const string am2rHash = "15253f7a66d6ea3feef004ebbee9b438"; - - string tmpPath = Path.GetTempPath() + Path.GetFileNameWithoutExtension(zipPath); - - // Clean up in case folder exists already - if (Directory.Exists(tmpPath)) - Directory.Delete(tmpPath, true); - - Directory.CreateDirectory(tmpPath); - - // Open archive - ZipArchive am2rZip = ZipFile.OpenRead(zipPath); - - // Check if exe exists anywhere - ZipArchiveEntry am2rExe = am2rZip.Entries.FirstOrDefault(x => x.FullName.Contains("AM2R.exe")); - if (am2rExe == null) - return IsZipAM2R11ReturnCodes.MissingOrInvalidAM2RExe; - // Check if it's not in a subfolder. if it'd be in a subfolder, fullname would be "folder/AM2R.exe" - if (am2rExe.FullName != "AM2R.exe") - return IsZipAM2R11ReturnCodes.GameIsInASubfolder; - // Check validity - am2rExe.ExtractToFile(tmpPath + "/" + am2rExe.FullName); - if (HelperMethods.CalculateMD5(tmpPath + "/" + am2rExe.FullName) != am2rHash) - return IsZipAM2R11ReturnCodes.MissingOrInvalidAM2RExe; - - // Check if data.win exists / is valid - ZipArchiveEntry dataWin = am2rZip.Entries.FirstOrDefault(x => x.FullName == "data.win"); - if (dataWin == null) - return IsZipAM2R11ReturnCodes.MissingOrInvalidDataWin; - dataWin.ExtractToFile(tmpPath + "/" + dataWin.FullName); - if (HelperMethods.CalculateMD5(tmpPath + "/" + dataWin.FullName) != dataWinHash) - return IsZipAM2R11ReturnCodes.MissingOrInvalidDataWin; - - // Check if d3d.dll exists / is valid - ZipArchiveEntry d3dx = am2rZip.Entries.FirstOrDefault(x => x.FullName == "D3DX9_43.dll"); - if (d3dx == null) - return IsZipAM2R11ReturnCodes.MissingOrInvalidD3DX9_43Dll; - d3dx.ExtractToFile(tmpPath + "/" + d3dx.FullName); - if (HelperMethods.CalculateMD5(tmpPath + "/" + d3dx.FullName) != d3dHash) - return IsZipAM2R11ReturnCodes.MissingOrInvalidD3DX9_43Dll; - - // Clean up - Directory.Delete(tmpPath, true); - - // If we didn't exit before, everything is fine - log.Info("AM2R_11 check successful!"); - return IsZipAM2R11ReturnCodes.Successful; - } } \ No newline at end of file