diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..992118d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,14 @@ +blank_issues_enabled: false +contact_links: + - name: Discord server + url: https://discord.gg/nk7UYPbd5u + about: Chat about anything AM2R related. + - name: AM2R-FAQ + url: https://am2r-community-developers.github.io/DistributionCenter/faq.html + about: Find frequently asked questions for AM2R. + - name: AM2R Issues + url: https://github.com/AM2R-Community-Developers/AM2R-Community-Updates/issues/new/choose + about: Got an issue for AM2R itself? + - name: AM2RLauncher Wiki + url: https://github.com/AM2R-Community-Developers/AM2RLauncher/wiki + about: A more in-depth documentation for features and usage of the AM2RLauncher diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c252b21..dd1569b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,10 +5,12 @@ on: branches: [ main ] paths-ignore: - 'README.md' + - '.github/**' pull_request: branches: [ main ] paths-ignore: - 'README.md' + - '.github/**' jobs: build: diff --git a/AM2RLauncher/AM2RLauncher.Gtk/Program.cs b/AM2RLauncher/AM2RLauncher.Gtk/Program.cs index a63620e..a4a9e01 100644 --- a/AM2RLauncher/AM2RLauncher.Gtk/Program.cs +++ b/AM2RLauncher/AM2RLauncher.Gtk/Program.cs @@ -5,7 +5,7 @@ using System; using System.IO; using System.Linq; using System.Text.RegularExpressions; -using GLib; +using log4net.Repository.Hierarchy; using Application = Eto.Forms.Application; using FileInfo = System.IO.FileInfo; @@ -39,12 +39,17 @@ internal static class MainClass // Configure logger XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); + // if we're on debug, always set loglevel to debug + #if DEBUG + ((Logger)log.Logger).Level = log4net.Core.Level.Debug; + #endif + // Log distro and version (if it exists) if (File.Exists("/etc/os-release")) { string osRelease = File.ReadAllText("/etc/os-release"); Regex lineRegex = new Regex(".*=.*"); - var results = lineRegex.Matches(osRelease).Cast().ToList(); + var results = lineRegex.Matches(osRelease).ToList(); var version = results.FirstOrDefault(x => x.Value.Contains("VERSION")); log.Info("Current Distro: " + results.FirstOrDefault(x => x.Value.Contains("NAME"))?.Value.Substring(5).Replace("\"", "") + (version == null ? "" : " " + version.Value.Substring(8).Replace("\"", ""))); diff --git a/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.Designer.cs b/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.Designer.cs index 1b88f02..4710aee 100644 --- a/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.Designer.cs +++ b/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.Designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,46 +11,32 @@ namespace AM2RLauncher.Gtk.Properties { using System; - /// - /// 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()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Gtk.Properties.Resources", typeof(Resources).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Gtk.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Ü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)] - internal static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,22 +45,6 @@ namespace AM2RLauncher.Gtk.Properties { } } - /// - /// Sucht eine lokalisierte Zeichenfolge, die <log4net> - /// <root> - /// <level value="ALL" /> - /// <appender-ref ref="file" /> - /// </root> - /// <appender name="file" type="log4net.Appender.RollingFileAppender"> - /// <file value="${DATADIR}/Logs/AM2RLauncher.log" /> - /// <appendToFile value="true" /> - /// <rollingStyle value="Once" /> - /// <maxSizeRollBackups value="7" /> - /// <maximumFileSize value="3MB" /> - /// <staticLogFileName value="true" /> - /// <layout type="log4net.Layout.PatternLayout"> - /// <conversionPattern value="%date [%thread] %level %logg [Rest der Zeichenfolge wurde abgeschnitten]"; ähnelt. - /// internal static string log4netContents { get { return ResourceManager.GetString("log4netContents", resourceCulture); diff --git a/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.resx b/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.resx index a2cff8e..ac17795 100644 --- a/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.resx +++ b/AM2RLauncher/AM2RLauncher.Gtk/Properties/Resources.resx @@ -120,7 +120,7 @@ <log4net> <root> - <level value="ALL" /> + <level value="INFO" /> <appender-ref ref="file" /> </root> <appender name="file" type="log4net.Appender.RollingFileAppender"> diff --git a/AM2RLauncher/AM2RLauncher.Mac/Program.cs b/AM2RLauncher/AM2RLauncher.Mac/Program.cs index f25560f..56cfdb4 100644 --- a/AM2RLauncher/AM2RLauncher.Mac/Program.cs +++ b/AM2RLauncher/AM2RLauncher.Mac/Program.cs @@ -4,6 +4,7 @@ using log4net.Config; using System; using System.Diagnostics.CodeAnalysis; using System.IO; +using log4net.Repository.Hierarchy; namespace AM2RLauncher.Mac; @@ -36,6 +37,11 @@ internal static class MainClass // Configure logger XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); + // if we're on debug, always set loglevel to debug + #if DEBUG + ((Logger)log.Logger).Level = log4net.Core.Level.Debug; + #endif + try { Application macLauncher = new Application(Eto.Platforms.Mac64); diff --git a/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.Designer.cs b/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.Designer.cs index 641e315..47418bc 100644 --- a/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.Designer.cs +++ b/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.Designer.cs @@ -1,7 +1,6 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.42000 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -10,7 +9,6 @@ namespace AM2RLauncher.Mac.Properties { using System; - using System.Reflection; [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] diff --git a/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.resx b/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.resx index a2cff8e..ac17795 100644 --- a/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.resx +++ b/AM2RLauncher/AM2RLauncher.Mac/Properties/Resources.resx @@ -120,7 +120,7 @@ <log4net> <root> - <level value="ALL" /> + <level value="INFO" /> <appender-ref ref="file" /> </root> <appender name="file" type="log4net.Appender.RollingFileAppender"> diff --git a/AM2RLauncher/AM2RLauncher.Wpf/Program.cs b/AM2RLauncher/AM2RLauncher.Wpf/Program.cs index 3c5172e..930cd56 100644 --- a/AM2RLauncher/AM2RLauncher.Wpf/Program.cs +++ b/AM2RLauncher/AM2RLauncher.Wpf/Program.cs @@ -4,6 +4,7 @@ using log4net.Config; using System; using System.IO; using System.Reflection; +using log4net.Repository.Hierarchy; namespace AM2RLauncher.Wpf; @@ -35,6 +36,11 @@ internal static class MainClass // Configure logger XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); + // if we're on debug, always set loglevel to debug + #if DEBUG + ((Logger)log.Logger).Level = log4net.Core.Level.Debug; + #endif + //Log Wine if (Core.Core.IsThisRunningFromWine) log.Info("Currently running from WINE!"); diff --git a/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.Designer.cs b/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.Designer.cs index ce32519..7de58d0 100644 --- a/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.Designer.cs +++ b/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.Designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,46 +11,32 @@ namespace AM2RLauncher.Wpf.Properties { using System; - /// - /// 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", "16.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } - /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Wpf.Properties.Resources", typeof(Resources).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Wpf.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Ü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)] - internal static global::System.Globalization.CultureInfo Culture { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,22 +45,6 @@ namespace AM2RLauncher.Wpf.Properties { } } - /// - /// Sucht eine lokalisierte Zeichenfolge, die <log4net> - /// <root> - /// <level value="ALL" /> - /// <appender-ref ref="file" /> - /// </root> - /// <appender name="file" type="log4net.Appender.RollingFileAppender"> - /// <file value="${DATADIR}/Logs/AM2RLauncher.log" /> - /// <appendToFile value="true" /> - /// <rollingStyle value="Once" /> - /// <maxSizeRollBackups value="7" /> - /// <maximumFileSize value="3MB" /> - /// <staticLogFileName value="true" /> - /// <layout type="log4net.Layout.PatternLayout"> - /// <conversionPattern value="%date [%thread] %level %logg [Rest der Zeichenfolge wurde abgeschnitten]"; ähnelt. - /// internal static string log4netContents { get { return ResourceManager.GetString("log4netContents", resourceCulture); diff --git a/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.resx b/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.resx index a2cff8e..ac17795 100644 --- a/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.resx +++ b/AM2RLauncher/AM2RLauncher.Wpf/Properties/Resources.resx @@ -120,7 +120,7 @@ <log4net> <root> - <level value="ALL" /> + <level value="INFO" /> <appender-ref ref="file" /> </root> <appender name="file" type="log4net.Appender.RollingFileAppender"> diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs b/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs index c4b1e8a..cf7163b 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs +++ b/AM2RLauncher/AM2RLauncher/Language/Text.Designer.cs @@ -1,10 +1,9 @@ //------------------------------------------------------------------------------ // -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 +// This code was generated by a tool. // -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. // //------------------------------------------------------------------------------ @@ -12,46 +11,32 @@ namespace AM2RLauncher.Language { using System; - /// - /// 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()] + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Text { - private static global::System.Resources.ResourceManager resourceMan; + private static System.Resources.ResourceManager resourceMan; - private static global::System.Globalization.CultureInfo resourceCulture; + private static System.Globalization.CultureInfo resourceCulture; - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Text() { } - /// - /// 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 { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Resources.ResourceManager ResourceManager { get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly); + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly); resourceMan = temp; } return resourceMan; } } - /// - /// Ü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 { + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + public static System.Globalization.CultureInfo Culture { get { return resourceCulture; } @@ -60,791 +45,538 @@ 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 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 ArchiveNotes { + public static string ArchiveNotesCommunityUpdates { get { - return ResourceManager.GetString("ArchiveNotes", resourceCulture); + return ResourceManager.GetString("ArchiveNotesCommunityUpdates", 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 $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); } } - /// - /// Sucht eine lokalisierte Zeichenfolge, die Mod Settings ähnelt. - /// 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 a722913..7afcf65 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.de.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.de.resx @@ -132,7 +132,7 @@ APK erstellen für $NAME - + Dies ist ein Archiv eines vorher installierten Community-Updates. Es kann nicht erneut installiert werden und wird automatisch entfernt wenn die archivierten Spieldaten gelöscht werden. Die Speicherstände sind allerdings weiterhin die aktuellen, bitte sicherheitshalber ein Backup anlegen vor dem benutzen dieses Profils! @@ -380,4 +380,10 @@ Bitte äußerste Vorsicht walten lassen. Das ausgewählte Zip-Archiv ist nicht AM2R 1.1 oder falsch geformt! Bitte ein anderes Archiv auswählen. + + $NAME archivieren? + + + Dies ist ein Archiv einer vorher installierten Mod. Es kann nicht erneut installiert werden und wird automatisch entfernt wenn die archivierten Spieldaten gelöscht werden. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.es.resx b/AM2RLauncher/AM2RLauncher/Language/Text.es.resx index e3a91d5..e87658f 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.es.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.es.resx @@ -132,7 +132,7 @@ Crear un APK para $NAME - + Esto es una copia de la Actualización de la Comunidad instalada previamente. No puede ser reinstalada y se eliminará automáticamente si se borran sus archivos de juego. Comparte las partidas guardadas con la Actualización de la Comunidad instalada actualmente, ¡así que asegúrate de crear una copia de seguridad de tus partidas antes de ejecutar este perfil! @@ -380,4 +380,10 @@ Procede con cautela. ¡El Zip seleccionado no es AM2R_1.1! Por favor elige otro archivo Zip. + + ¿Deseas archivar $NAME? + + + Esta es una versión archivada de un Mod instalado anteriormente. No puede ser reinstalada y se eliminará automáticamente si se borran sus archivos de juego. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx b/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx index 7603b52..ce46b2c 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.fr.resx @@ -132,7 +132,7 @@ Créer un APK pour $NAME - + Il s'agit d'une archive d'une mise à jour communautaire précédemment installée. Elle ne peut pas être réinstallée et se supprimera d'elle-même si ses fichiers de jeu sont supprimés. Elle partage des sauvegardes avec la mise à jour actuellement installée, donc assurez-vous de faire une sauvegarde de celles-ci avant de lancer ce profil ! @@ -382,4 +382,10 @@ Soyez prudent. Le Zip sélectionné n'est pas AM2R 1.1 ! Veuillez choisir un autre fichier Zip. + + Archive $NAME ? + + + Il s'agit d'une archive d'un mod précédemment installé. Il ne peut pas être réinstallé et se supprimera de lui-même si ses fichiers de jeu sont supprimés. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.it.resx b/AM2RLauncher/AM2RLauncher/Language/Text.it.resx index 6e2c5df..a2b4aab 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.it.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.it.resx @@ -132,7 +132,7 @@ Crea un APK per $NAME - + Questo è un archivio di un Aggiornamento Comunità installato in precedenza. Non può essere reinstallato e si rimuoverà da solo se i file di gioco saranno cancellati. Condivide i salvataggi con gli Aggiornamenti Comunità, quindi assicurati di creare un backup dei tuoi salvataggi prima di usare questo profilo! @@ -380,4 +380,10 @@ Procedi con cautela. Il Zip selezionato non è AM2R 1.1! Perfavore scegli un altro file Zip. + + Vuoi archiviare $NAME? + + + Questo è un archivio di una Mod precedentemente installata. Non può essere re-installata e si rimuoverà da sola se i suoi file di gioco vengono rimossi. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx b/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx index 75b7507..e1997f4 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.ja.resx @@ -132,7 +132,7 @@ 次のAPKを作成します: $NAME - + これは以前インストールされたCommunity Updateのアーカイブです。再インストールはできませんし、ゲームファイルが削除されると自動的に削除されます。現在インストールされているCommunity Updateとセーブデータを共有しているため、このプロファイルを実行する前に必ずセーブデータのバックアップを作成してください @@ -380,4 +380,10 @@ そのZIPファイルはAM2R v1.1ではありません! 別のZIPファイルを選んで下さい + + $NAMEをアーカイブ化しますか? + + + これは既にインストールされているMODです。再インストールはできず、またゲームファイルを削除すると自動的に削除されます。 + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx b/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx index 8c29746..b790b60 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.pt.resx @@ -132,7 +132,7 @@ Criar um APK para $NAME - + Isto é um arquivo de uma Atualização da Comunidade instalada previamente. Não é possível reinstalá-la e ela será removida automaticamente quando seus arquivos de jogo forem deletados. Os arquivos de save são compartilhados com a Atualização da Comunidade que está instalada no momento, então faça um backup de seus saves antes de executar este perfil! @@ -380,4 +380,10 @@ Prossiga com cuidado. O arquivo Zip selecionado não contém o AM2R 1.1! Por favor, selecione outro arquivo Zip + + Deseja arquivar $NAME? + + + Isso é uma versão arquivada de um Mod previamente instalado. Ele não pode ser reinstalado e será removido se seus arquivos de jogo forem deletados. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.resx b/AM2RLauncher/AM2RLauncher/Language/Text.resx index 1ba47a2..85a2c55 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.resx @@ -132,7 +132,7 @@ Create an APK for $NAME - + 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! @@ -382,4 +382,10 @@ Proceed with caution. The selected Zip is not AM2R 1.1! Please choose another Zip file. + + Do you want to archive $NAME? + + + This is an archive of a previously installed Mod. It cannot be re-installed and will remove itself if its game files are deleted. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx b/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx index 671b52a..9059258 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.ru.resx @@ -132,7 +132,7 @@ Создать APK-файл для $NAME - + Этот архив содержит ранее установленное обновление сообщества. Оно не может быть переустановлено и автоматически удалится при удалении файлов игры. Оно имеет общие файлы сохранения с текущим обновлением сообщества, поэтому не забудьте создать копию сохранений перед запуском! @@ -380,4 +380,10 @@ Указанный zip-файл не является файлом AM2R 1.1! Пожалуйста, выберите другой zip-файл. + + Архивировать $NAME? + + + Это архив, содержащий ранее установленный мод. Он не может быть переустановлен, и, при удалении файлов игры, так же будет удалён. + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx b/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx index 8308588..22c5e72 100644 --- a/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx +++ b/AM2RLauncher/AM2RLauncher/Language/Text.zh-Hans.resx @@ -132,8 +132,8 @@ 为 $NAME 创建 APK - - 这是先前安装过的社区更新版本的压缩文件,因此无法再重新安装一遍,并且在游戏文件被删除后也会自行删除。由于与当前安装的社区更新版本共用保存数据,所以请在运行该游戏实例前备份好保存数据! + + 此为以前安装过的社区更新版本的归档,无法重新安装,若对应的游戏文件被删除,该归档也会自行删除。由于和当前安装的社区更新版本共用保存数据,所以请在运行该游戏实例前备份好保存数据! 作者: @@ -382,4 +382,10 @@ 选定的文件不是 AM2R_1.1 !请选择其他 Zip 文件 + + 是否要归档 $NAME? + + + 此为以前安装过的 Mod 的归档,无法重新安装,若对应的游戏文件被删除,该归档也会自行删除。 + \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs b/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs index a2a4c93..95687a8 100644 --- a/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs +++ b/AM2RLauncher/AM2RLauncher/LauncherUpdater.cs @@ -14,7 +14,7 @@ namespace AM2RLauncher //TODO: Mac support for autoupdater in general public static class LauncherUpdater { - // How often this was broken count: 6 + // How often this was broken count: 7 // Auto updating is fun! /// The Version that identifies this current release. @@ -131,6 +131,15 @@ namespace AM2RLauncher // No new update, exiting if (!isCurrentVersionOutdated) return; + + // For mac, we just show a message box that a new version is available, because I don't want to support it yet. + // hardcoded string, since also temporarily until it gets supported one day. + if (OS.IsMac) + { + MessageBox.Show("Your current version is outdated! The newest version is " + onlineVersion + "." + + "Please recompile AM2RLauncher again or disable auto-updating"); + return; + } log.Info("Current version (" + VERSION + ") is outdated! Initiating update for version " + onlineVersion + "."); @@ -207,8 +216,7 @@ namespace AM2RLauncher CrossPlatformOperations.CopyOldConfigToNewConfig(); log.Info("Files extracted. Preparing to restart executable..."); - - if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x ./AM2RLauncher.Gtk"); + if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x " + updatePath + "./AM2RLauncher.Gtk"); System.Diagnostics.Process.Start(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME); Environment.Exit(0); diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs index 997ee6e..6f87feb 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.Events.cs @@ -31,7 +31,7 @@ namespace AM2RLauncher /// private async void PlayButtonLoadComplete(object sender, EventArgs e) { - LoadProfiles(); + LoadProfilesAndAdjustLists(); if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked) return; @@ -92,7 +92,7 @@ namespace AM2RLauncher { progressBar.Visible = false; progressLabel.Visible = false; - LoadProfiles(); + LoadProfilesAndAdjustLists(); } // Handling for updates - if current version does not match PatchData version, rename folder so that we attempt to install! @@ -104,47 +104,9 @@ namespace AM2RLauncher if (currentXML.Version != profileList[0].Version) { log.Info("New game version (" + profileList[0].Version + ") detected! Beginning archival of version " + currentXML.Version + "..."); - - string profileArchivePath = CrossPlatformOperations.CURRENTPATH + "/Profiles/Community Updates (" + currentXML.Version + ")"; - - // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. - if (!Directory.Exists(profileArchivePath)) - { - // Rename current Community Updates - Directory.Move(CrossPlatformOperations.CURRENTPATH + "/Profiles/Community Updates (Latest)", profileArchivePath); - - currentXML.Name = "Community Updates (" + currentXML.Version + ")"; - - // Set as non-installable so that it's just treated as a launching reference - currentXML.Installable = false; - currentXML.SupportsAndroid = false; - - string modArchivePath = CrossPlatformOperations.CURRENTPATH + "/Mods/" + currentXML.Name; - - // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. - if (!Directory.Exists(modArchivePath)) - { - Directory.CreateDirectory(modArchivePath); - File.WriteAllText(modArchivePath + "/profile.xml", Serializer.Serialize(currentXML)); - log.Info("Finished archival."); - } - else - { - HelperMethods.DeleteDirectory(profileArchivePath); - log.Info("Cancelling archival! User-defined archive in Mods already exists."); - } - - - } - else // If our desired rename already exists, it's probably a user archive... so we just delete the folder and move on with installation of the new version. - { - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/Community Updates (Latest)"); - log.Info("Cancelling archival! User-defined archive in Profiles already exists."); - } - + Profile.ArchiveProfile(currentXML); profileDropDown.SelectedIndex = 0; - - LoadProfiles(); + LoadProfilesAndAdjustLists(); } } @@ -160,6 +122,9 @@ namespace AM2RLauncher // State Check UpdateStateMachine(); + // Check if 1.1 is installed by forcing invalidation + Profile.Is11Installed(true); + switch (updateState) { #region Download @@ -240,7 +205,7 @@ namespace AM2RLauncher SetPlayButtonState(UpdateState.Install); // This needs to be run BEFORE the state check so that the Mod Settings tab doesn't weird out - LoadProfiles(); + LoadProfilesAndAdjustLists(); // Do a state check UpdateStateMachine(); @@ -438,7 +403,7 @@ namespace AM2RLauncher progressBar.MaxValue = transferProgress.TotalObjects; if (currentGitObject >= transferProgress.ReceivedObjects) return; - progressLabel.Text = Language.Text.ProgressbarProgress + " " + transferProgress.ReceivedObjects + " (" + (int)transferProgress.ReceivedBytes / 1000000 + "MB) / " + transferProgress.TotalObjects + " objects"; + progressLabel.Text = Language.Text.ProgressbarProgress + " " + transferProgress.ReceivedObjects + " (" + ((int)transferProgress.ReceivedBytes / 1000000) + "MB) / " + transferProgress.TotalObjects + " objects"; currentGitObject = transferProgress.ReceivedObjects; progressBar.Value = transferProgress.ReceivedObjects; }); @@ -461,7 +426,7 @@ namespace AM2RLauncher return; } // Check if xdelta is installed on linux - if ((OS.IsUnix) && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) + if (OS.IsUnix && !CrossPlatformOperations.CheckIfXdeltaIsInstalled()) { MessageBox.Show(Language.Text.XdeltaNotFound, Language.Text.WarningWindowTitle, MessageBoxButtons.OK); SetApkButtonState(ApkButtonState.Create); @@ -537,8 +502,6 @@ namespace AM2RLauncher { log.Info("User requested to add mod. Requesting user input for new mod .zip..."); - ProfileXML addedProfile; - OpenFileDialog fileFinder = new OpenFileDialog { Directory = new Uri(CrossPlatformOperations.CURRENTPATH), @@ -554,84 +517,81 @@ namespace AM2RLauncher return; } - if (!String.IsNullOrWhiteSpace(fileFinder.FileName)) // This is default + if (String.IsNullOrWhiteSpace(fileFinder.FileName)) { - log.Info("User selected \"" + fileFinder.FileName + "\""); - - // 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.Error("User did not supply valid input. Cancelling import."); + LoadProfilesAndAdjustLists(); + return; + } - FileInfo modFile = new FileInfo(fileFinder.FileName); + log.Info("User selected \"" + fileFinder.FileName + "\""); - string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; - string extractedName = modFile.Name.Replace(".zip", ""); + // 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; + } - // Extract it and see if it contains a profile.xml. If not, this is invalid + FileInfo modFile = new FileInfo(fileFinder.FileName); - // Check first, if the directory is already there, if yes, throw a message - if (Directory.Exists(modsDir + "/" + extractedName)) - { - ProfileXML profile2 = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); - log.Error("Mod is already imported as " + extractedName + "! Cancelling mod import."); + string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; + string extractedName = modFile.Name.Replace(".zip", ""); - 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."); + // Extract it and see if it contains a profile.xml. If not, this is invalid - 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; - } + // Check first, if the directory is already there, if yes, throw a message + if (Directory.Exists(modsDir + "/" + extractedName)) + { + ProfileXML profile2 = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); + log.Error("Mod is already imported as " + extractedName + "! Cancelling mod import."); - ProfileXML profile = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); + 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); - // 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."); + // 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.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(Language.Text.ModIsInvalidMessage.Replace("$NAME", extractedName), Language.Text.ErrorWindowTitle, MessageBoxType.Error); + Directory.Delete(modsDir + "/" + extractedName, true); + File.Delete(CrossPlatformOperations.CURRENTPATH + "/Mods/" + modFile.Name); + return; + } - // 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)) - { - 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; - } + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); - addedProfile = profile; - log.Info(profile.Name + " successfully installed."); - MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); + // 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; } - else + + // 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)) { - log.Error("User did not supply valid input. Cancelling import."); - LoadProfiles(); + 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; } - LoadProfiles(); - settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == addedProfile.Name); + 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; } @@ -653,11 +613,10 @@ namespace AM2RLauncher /// private void SaveButtonClickEvent(object sender, EventArgs e) { - if (IsProfileIndexValid()) - { - 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); - } + 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); } /// @@ -680,7 +639,8 @@ namespace AM2RLauncher { deleteModButton.Enabled = true; deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); - updateModButton.Enabled = true; + // 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); } @@ -775,20 +735,18 @@ namespace AM2RLauncher if (profileDropDown.SelectedIndex == -1 && profileDropDown.Items.Count == 0) return; profileIndex = profileDropDown.SelectedIndex; - log.Info("profileDropDown.SelectedIndex has been changed to " + profileIndex + "."); + log.Debug("profileDropDown.SelectedIndex has been changed to " + profileIndex + "."); profileAuthorLabel.Text = Language.Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author; profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; - CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString()); if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" || - profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) + profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) saveWarningLabel.Visible = true; else saveWarningLabel.Visible = false; UpdateStateMachine(); - } /// Gets called when user selects a different item from and writes that to the config. @@ -940,7 +898,7 @@ namespace AM2RLauncher if (result == DialogResult.Ok) { log.Info("User did not cancel. Proceeding to delete " + profile); - DeleteProfile(profile); + DeleteProfileAndAdjustLists(profile); log.Info(profile + " has been deleted"); MessageBox.Show(Language.Text.DeleteModButtonSuccess.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); } @@ -977,88 +935,107 @@ namespace AM2RLauncher return; } - if (!String.IsNullOrWhiteSpace(fileFinder.FileName)) // This is default + // Exit if nothing was selected + if (String.IsNullOrWhiteSpace(fileFinder.FileName)) { - log.Info("User selected \"" + fileFinder.FileName + "\""); + log.Info("Nothing was selected, cancelling mod update."); + LoadProfilesAndAdjustLists(); + 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 mod update."); - return; - } + log.Info("User selected \"" + fileFinder.FileName + "\""); - FileInfo modFile = new FileInfo(fileFinder.FileName); + // 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 mod update."); + return; + } - string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; - string extractedName = modFile.Name.Replace(".zip", "_new"); + FileInfo modFile = new FileInfo(fileFinder.FileName); - // Extract it and see if it contains a profile.xml. If not, this is invalid + string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; + string extractedName = modFile.Name.Replace(".zip", "_new"); + string extractedFolder = modsDir + "/" + extractedName; - // Directory doesn't exist -> extract! - ZipFile.ExtractToDirectory(fileFinder.FileName, modsDir + "/" + extractedName); + // Extract it and see if it contains a profile.xml. If not, this is invalid - // 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 update."); - 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; - } + // If for some reason old files remain, delete them + if (Directory.Exists(extractedFolder)) + Directory.Delete(extractedFolder, true); - // Check by *name*, if the mod was installed already - ProfileXML profile = Serializer.Deserialize(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); + // Directory doesn't exist -> extract! + ZipFile.ExtractToDirectory(fileFinder.FileName, extractedFolder); - 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 result = MessageBox.Show(Language.Text.UpdateModWarning.Replace("$NAME", currentProfile.Name), Language.Text.WarningWindowTitle, - MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); + // Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup + if (!File.Exists(extractedFolder + "/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); + return; + } - if (result == DialogResult.Ok) - { - // Delete profile - DeleteProfile(currentProfile); + // Check by *name*, if the mod was installed already + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(extractedFolder + "/profile.xml")); - // Rename directory to take the old one's place - string originalFolder = modsDir + "/" + extractedName.Replace("_new", ""); - Directory.Move(modsDir + "/" + extractedName, originalFolder); + 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); - } - else // Cancel the operation! + if (updateResult == DialogResult.Ok) + { + // If the profile isn't installed, don't ask about archiving it + if (Profile.IsProfileInstalled(currentProfile)) { - log.Error("User has cancelled mod update!"); - abort = true; + //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 + else // Cancel the operation! { - // 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); + log.Error("User has cancelled mod update!"); abort = true; } + } + else + { + // 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; + } - if (abort) - { - // File cleanup - HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); - LoadProfiles(); - return; - } - - log.Info("Successfully updated mod profile " + profile.Name + "."); - MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", currentProfile.Name), Language.Text.SuccessWindowTitle); - UpdateStateMachine(); + if (abort) + { + // File cleanup + HelperMethods.DeleteDirectory(extractedFolder); + LoadProfilesAndAdjustLists(); + return; } - ProfileXML currentSelectedProfile = profileList[settingsProfileDropDown.SelectedIndex]; - LoadProfiles(); - settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentSelectedProfile.Name); + log.Info("Successfully updated mod profile " + profile.Name + "."); + MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", currentProfile.Name), Language.Text.SuccessWindowTitle); + UpdateStateMachine(); + + LoadProfilesAndAdjustLists(); + + settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentProfile.Name); if (settingsProfileDropDown.SelectedIndex == -1) settingsProfileDropDown.SelectedIndex = 0; } @@ -1075,6 +1052,7 @@ namespace AM2RLauncher CrossPlatformOperations.WriteToConfig("Width", ClientSize.Width); CrossPlatformOperations.WriteToConfig("Height", ClientSize.Height); CrossPlatformOperations.WriteToConfig("IsMaximized", this.WindowState == WindowState.Maximized); + CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString()); switch (updateState) { diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs index db8106d..63269ae 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.StateMachine.cs @@ -1,6 +1,5 @@ using Eto.Drawing; using System; -using System.IO; using AM2RLauncher.Core; using AM2RLauncher.Core.XML; @@ -52,7 +51,7 @@ namespace AM2RLauncher else if (isProfileValid && profileList[profileIndex.Value].Installable == false) { // We delete the profile, because we can't install it and it therefore holds no value! - DeleteProfile(profileList[profileIndex.Value]); + DeleteProfileAndAdjustLists(profileList[profileIndex.Value]); } // Otherwise, we still need to install. else @@ -176,7 +175,7 @@ namespace AM2RLauncher // Only enable these, when we're not on the community updates if (settingsProfileDropDown.SelectedIndex > 0) { - updateModButton.Enabled = enabled; + updateModButton.Enabled = profileList[settingsProfileDropDown.SelectedIndex].Installable; updateModButton.ToolTip = Language.Text.UpdateModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); deleteModButton.Enabled = enabled; deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); @@ -269,91 +268,30 @@ namespace AM2RLauncher } /// - /// Deletes the given . Reloads the if is true. + /// Loads valid profile entries and reloads the necessary UI components. /// - private void DeleteProfile(ProfileXML profile, bool reloadProfileList = true) + private void LoadProfilesAndAdjustLists() { - log.Info("Attempting to delete profile " + profile.Name + "..."); - - // 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")) - { - File.SetAttributes(CrossPlatformOperations.CURRENTPATH + profile.DataPath + ".zip", FileAttributes.Normal); // For some reason, it was set at read only, so we undo that here - File.Delete(CrossPlatformOperations.CURRENTPATH + profile.DataPath + ".zip"); - } - - // Delete folder in Profiles - if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) - { - HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name); - } - - if (reloadProfileList) - LoadProfiles(); - - log.Info("Successfully deleted profile " + profile.Name + "."); - } - - /// - /// Scans the PatchData and Mods folders for valid profile entries, and loads them. - /// - //TODO: Seperate this (and by extension, deleteProfile) from UI and backend - private void LoadProfiles() - { - log.Info("Loading profiles..."); - // Reset loaded profiles profileDropDown.Items.Clear(); profileList.Clear(); profileIndex = null; - // Check for and add the Community Updates profile - if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")) - { - profileList.Add(Serializer.Deserialize(File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml"))); - profileList[0].DataPath = "/PatchData/data"; - } - - // Safety check to generate the Mods folder if it does not exist - if (!Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Mods")) - Directory.CreateDirectory(CrossPlatformOperations.CURRENTPATH + "/Mods"); - - // Get Mods folder info - DirectoryInfo modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods"); - - // Add all extracted profiles in Mods to the profileList. - foreach (DirectoryInfo dir in modsDir.GetDirectories()) - { - foreach (FileInfo file in dir.GetFiles()) - { - if (file.Name != "profile.xml") - continue; - ProfileXML prof = Serializer.Deserialize(File.ReadAllText(dir.FullName + "/profile.xml")); - if (prof.Installable || Profile.IsProfileInstalled(prof)) // Safety check for non-installable profiles - { - prof.DataPath = "/Mods/" + dir.Name; - profileList.Add(prof); - } - else if (!Profile.IsProfileInstalled(prof)) // If not installable and isn't installed, remove it - { - prof.DataPath = "/Mods/" + dir.Name; - DeleteProfile(prof, false); - } - } - } + // Load the profileList + profileList = Profile.LoadProfiles(); // Add profile names to the profileDropDown foreach (ProfileXML profile in profileList) { // Archive version notes if (!profile.Installable) - profile.ProfileNotes = Language.Text.ArchiveNotes; + { + //TODO: localizations + if (profile.Name.Contains("Community Updates")) + profile.ProfileNotes = Language.Text.ArchiveNotesCommunityUpdates; + else + profile.ProfileNotes = Language.Text.ArchiveNotesMods + "\n\n" + profile.ProfileNotes; + } profileDropDown.Items.Add(profile.Name); } @@ -383,8 +321,6 @@ namespace AM2RLauncher settingsProfileDropDown.Items.AddRange(profileDropDown.Items); settingsProfileDropDown.SelectedIndex = profileDropDown.Items.Count != 0 ? 0 : -1; - log.Info("Loaded " + profileList.Count + " profile(s)."); - // Refresh the author and version label on the main tab if (profileList.Count > 0) { @@ -392,7 +328,26 @@ namespace AM2RLauncher profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; } + log.Info("Reloading UI components after loading successful."); + UpdateStateMachine(); } + + + /// + /// Deletes a profile and reloads the necessary UI components. + /// + /// The profile to delete. + private void DeleteProfileAndAdjustLists(ProfileXML profile) + { + Profile.DeleteProfile(profile); + LoadProfilesAndAdjustLists(); + } + + private void ArchiveProfileAndAdjustLists(ProfileXML profile) + { + Profile.ArchiveProfile(profile); + LoadProfilesAndAdjustLists(); + } } } \ No newline at end of file diff --git a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs index de7f67f..1fe357f 100644 --- a/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs +++ b/AM2RLauncher/AM2RLauncher/MainForm/MainForm.UI.cs @@ -10,7 +10,6 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; -using System.Text.RegularExpressions; using System.Threading; namespace AM2RLauncher diff --git a/AM2RLauncher/AM2RLauncherCore/Core.cs b/AM2RLauncher/AM2RLauncherCore/Core.cs index b5b95b7..aca50d3 100644 --- a/AM2RLauncher/AM2RLauncherCore/Core.cs +++ b/AM2RLauncher/AM2RLauncherCore/Core.cs @@ -7,6 +7,8 @@ namespace AM2RLauncher.Core; /// /// Class that has core stuff that doesn't fit anywhere else /// +//TODO: "Core" is a really stupid name and either this should get renamed, or AM2RLauncher.Core should get renamed. +// I am however bad at thinking of names public static class Core { /// diff --git a/AM2RLauncher/AM2RLauncherCore/Profile.cs b/AM2RLauncher/AM2RLauncherCore/Profile.cs index e897e92..7c16c87 100644 --- a/AM2RLauncher/AM2RLauncherCore/Profile.cs +++ b/AM2RLauncher/AM2RLauncherCore/Profile.cs @@ -2,6 +2,7 @@ using LibGit2Sharp; using log4net; using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; @@ -47,10 +48,12 @@ public static class Profile /// /// Checks if AM2R 1.1 has been installed already, aka if a valid AM2R 1.1 Zip exists. /// - /// if yes, if not. - public static bool Is11Installed() + /// Determines if the AM2R_11 Cache should be invalidated + /// + public static bool Is11Installed(bool invalidateCache = false) { - InvalidateAM2R11InstallCache(); + // Only invalidate if we need to + if (invalidateCache) InvalidateAM2R11InstallCacheIfNecessary(); // If we have a cache, return that instead if (isAM2R11InstalledCache != null) return isAM2R11InstalledCache.Value; @@ -73,9 +76,9 @@ public static class Profile } /// - /// Invalidates . + /// Invalidates if necessary. /// - private static void InvalidateAM2R11InstallCache() + private static void InvalidateAM2R11InstallCacheIfNecessary() { // If the file exists, and its hash matches with ours, don't invalidate if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") && @@ -123,6 +126,141 @@ public static class Profile log.Info("Repository pulled successfully."); } + /// + /// Scans the PatchData and Mods folders for valid profile entries, creates and returns a list of them. + /// + /// A containing all valid profile entries. + public static List LoadProfiles() + { + log.Info("Loading profiles..."); + + List profileList = new List(); + + // Check for and add the Community Updates profile + if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")) + { + ProfileXML profile = Serializer.Deserialize(File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")); + profile.DataPath = "/PatchData/data"; + profileList.Add(profile); + } + + // Safety check to generate the Mods folder if it does not exist + if (!Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Mods")) + Directory.CreateDirectory(CrossPlatformOperations.CURRENTPATH + "/Mods"); + + // Get Mods folder info + DirectoryInfo modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods"); + + // Add all extracted profiles in Mods to the profileList. + foreach (DirectoryInfo dir in modsDir.GetDirectories()) + { + // If no profile.xml exists we don't add anything + if (!File.Exists(dir.FullName + "/profile.xml")) + continue; + + ProfileXML prof = Serializer.Deserialize(File.ReadAllText(dir.FullName + "/profile.xml")); + // Safety check for non-installable profiles + if (prof.Installable || IsProfileInstalled(prof)) + { + prof.DataPath = "/Mods/" + dir.Name; + profileList.Add(prof); + } + // If not installable and isn't installed, remove it + else if (!IsProfileInstalled(prof)) + { + prof.DataPath = "/Mods/" + dir.Name; + DeleteProfile(prof); + } + } + + log.Info("Loaded " + profileList.Count + " profile(s)."); + return profileList; + } + + /// + /// Archives a given Profile by making a copy with "Name (version)". Does silently nothing if user archives already exist + /// + /// The profile to archive + public static void ArchiveProfile(ProfileXML profile) + { + // temporarily serialize and deserialize to essentially "clone" the variable as otherwise we'd modify references + File.WriteAllText(Path.GetTempPath() + "/" + profile.Name, Serializer.Serialize(profile)); + profile = Serializer.Deserialize(File.ReadAllText(Path.GetTempPath() + "/" + profile.Name)); + + string originalName = profile.Name; + // Change name to include version and be unique + profile.Name += " (" + profile.Version + ")"; + // if we're archiving community updates, remove the "latest" part + profile.Name = profile.Name.Replace("Community Updates Latest", "Community Updates"); + + log.Info("Archiving " + profile.Name); + + string profileArchivePath = CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name; + + // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. + if (!Directory.Exists(profileArchivePath)) + { + // Rename current profile if we have it installed + if (Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName)) + Directory.Move(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName, profileArchivePath); + + // Set as non-installable so that it's just treated as a launching reference + profile.Installable = false; + + string modArchivePath = CrossPlatformOperations.CURRENTPATH + "/Mods/" + profile.Name; + + // Do NOT overwrite if a path with this name already exists! It is likely an existing user archive. + if (!Directory.Exists(modArchivePath)) + { + Directory.CreateDirectory(modArchivePath); + File.WriteAllText(modArchivePath + "/profile.xml", Serializer.Serialize(profile)); + log.Info("Finished archival."); + } + else + { + HelperMethods.DeleteDirectory(profileArchivePath); + log.Info("Cancelling archival! User-defined archive in Mods already exists."); + } + } + // If our desired rename already exists, it's probably a user archive... so we just delete the original folder and move on with installation of the new version. + else + { + HelperMethods.DeleteDirectory(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + originalName); + log.Info("Cancelling archival! User-defined archive in Profiles already exists."); + } + } + + /// + /// Deletes a profile from the Mods and Profiles folder. + /// + /// The profile to delete. + public static void DeleteProfile(ProfileXML profile) + { + log.Info("Attempting to delete profile " + profile.Name + "..."); + + // 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")) + { + // For some reason, it was set at read only, so we undo that here + File.SetAttributes(CrossPlatformOperations.CURRENTPATH + profile.DataPath + ".zip", FileAttributes.Normal); + File.Delete(CrossPlatformOperations.CURRENTPATH + profile.DataPath + ".zip"); + } + + // 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 + "."); + } + /// /// Installs . /// @@ -308,8 +446,9 @@ public static class Profile foreach (var file in new DirectoryInfo(profilePath).GetFiles()) if (file.Name.EndsWith(".ogg") && !File.Exists(file.DirectoryName + "/" + file.Name.ToLower())) File.Move(file.FullName, file.DirectoryName + "/" + file.Name.ToLower()); - // Loading custom fonts crashes on Mac, so we delete those - Directory.Delete(profilePath + "/lang/fonts", true); + // Loading custom fonts crashes on Mac, so we delete those if they exist + if (Directory.Exists(profilePath + "/lang/fonts")) + Directory.Delete(profilePath + "/lang/fonts", true); // Move Frameworks, Info.plist and PkgInfo over HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/Frameworks", profilePath.Replace("Resources", "Frameworks")); File.Copy(dataPath + "/Info.plist", profilePath.Replace("Resources", "") + "/Info.plist", true); @@ -491,7 +630,7 @@ public static class Profile { ProcessStartInfo startInfo = new ProcessStartInfo(); - log.Info("Is the environment textbox null or whitespace = " + String.IsNullOrWhiteSpace(envVars)); + log.Info("User does " + (String.IsNullOrWhiteSpace(envVars) ? "not" : "") + " have custom environment variables set."); //TODO: make this more readable at one day if (!String.IsNullOrWhiteSpace(envVars)) @@ -523,7 +662,7 @@ public static class Profile string value = envVars.Substring(0, valueSubstringLength); envVars = envVars.Substring(value.Length); - log.Info("Adding variable \"" + variable + "\" with value \"" + value + "\""); + log.Info("Adding user variable \"" + variable + "\" with value \"" + value + "\""); startInfo.EnvironmentVariables[variable] = value; } } @@ -537,10 +676,10 @@ public static class Profile log.Info("CWD of Profile is " + startInfo.WorkingDirectory); - log.Info("Launching game with following variables: "); + log.Debug("Launching game with following variables: "); foreach (System.Collections.DictionaryEntry item in startInfo.EnvironmentVariables) { - log.Info("Key: \"" + item.Key + "\" Value: \"" + item.Value + "\""); + log.Debug("Key: \"" + item.Key + "\" Value: \"" + item.Value + "\""); } using (Process p = new Process()) diff --git a/AM2RLauncher/AM2RLauncherCore/Splash.cs b/AM2RLauncher/AM2RLauncherCore/Splash.cs index 3f5da5a..e5d760d 100644 --- a/AM2RLauncher/AM2RLauncherCore/Splash.cs +++ b/AM2RLauncher/AM2RLauncherCore/Splash.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; namespace AM2RLauncher.Core; @@ -18,10 +18,12 @@ public static class Splash "Now with 100% more Blob Throwers!", "Speedrun THIS, I dare you.", "The broken pipe is a lie.", + "I am altering the broken pipe. Pray I don't alter it any further.", "Overcommitting to April Fool's since 2018.", "Also try Metroid II: Return of Samus!", "Also try Metroid: Samus Returns!", "Also try Prime 2D!", + "Also try Skippy the Bot!", "Trust me, it's an 'unintentional feature.'", "Coming soon to a PC near you!", "This ain't your parents' Metroid 2!", @@ -42,7 +44,8 @@ public static class Splash "S P I D E R B A L L", "Fun is infinite with Community-Developers Inc.", "You may only proceed if you wear baggy pants.", - "Did you know that games take time to develop?" + "Did you know that games take time to develop?", + "Ask the wombat." }; /// @@ -127,4 +130,4 @@ public static class Splash totalSplashes = generalSplash; return totalSplashes; } -} \ No newline at end of file +} diff --git a/README.md b/README.md index 18c0cb7..3c30308 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ On Arch Linux you can install them by running this: ### Fedora On Fedora you can install them by running this command: -`dnf install dotnet-runtime-6.0 libappindicator-gtk3 xdelta mesa-libGL.i686 pulseaudio-libs.1686 openal-soft.i686` +`sudo dnf install dotnet-runtime-6.0 libappindicator-gtk3 xdelta mesa-libGL.i686 pulseaudio-libs.1686 openal-soft.i686 java-latest-openjdk` ### Other distros For other distros refer to your local package manager for instructions.