Merge branch 'AM2R-Community-Developers:main' into main

pull/32/head
Miepee 4 years ago committed by GitHub
commit 66d7c7a896
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -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

@ -5,10 +5,12 @@ on:
branches: [ main ] branches: [ main ]
paths-ignore: paths-ignore:
- 'README.md' - 'README.md'
- '.github/**'
pull_request: pull_request:
branches: [ main ] branches: [ main ]
paths-ignore: paths-ignore:
- 'README.md' - 'README.md'
- '.github/**'
jobs: jobs:
build: build:

@ -5,7 +5,7 @@ using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using GLib; using log4net.Repository.Hierarchy;
using Application = Eto.Forms.Application; using Application = Eto.Forms.Application;
using FileInfo = System.IO.FileInfo; using FileInfo = System.IO.FileInfo;
@ -39,12 +39,17 @@ internal static class MainClass
// Configure logger // Configure logger
XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); 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) // Log distro and version (if it exists)
if (File.Exists("/etc/os-release")) if (File.Exists("/etc/os-release"))
{ {
string osRelease = File.ReadAllText("/etc/os-release"); string osRelease = File.ReadAllText("/etc/os-release");
Regex lineRegex = new Regex(".*=.*"); Regex lineRegex = new Regex(".*=.*");
var results = lineRegex.Matches(osRelease).Cast<Match>().ToList(); var results = lineRegex.Matches(osRelease).ToList();
var version = results.FirstOrDefault(x => x.Value.Contains("VERSION")); var version = results.FirstOrDefault(x => x.Value.Contains("VERSION"));
log.Info("Current Distro: " + results.FirstOrDefault(x => x.Value.Contains("NAME"))?.Value.Substring(5).Replace("\"", "") + log.Info("Current Distro: " + results.FirstOrDefault(x => x.Value.Contains("NAME"))?.Value.Substring(5).Replace("\"", "") +
(version == null ? "" : " " + version.Value.Substring(8).Replace("\"", ""))); (version == null ? "" : " " + version.Value.Substring(8).Replace("\"", "")));

@ -1,10 +1,9 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// Dieser Code wurde von einem Tool generiert. // This code was generated by a tool.
// Laufzeitversion:4.0.30319.42000
// //
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn // Changes to this file may cause incorrect behavior and will be lost if
// der Code erneut generiert wird. // the code is regenerated.
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -12,46 +11,32 @@ namespace AM2RLauncher.Gtk.Properties {
using System; using System;
/// <summary> [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. [System.Diagnostics.DebuggerNonUserCodeAttribute()]
/// </summary> [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
// 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()]
internal class Resources { 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() { internal Resources() {
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. internal static System.Resources.ResourceManager ResourceManager {
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.Equals(null, resourceMan)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Gtk.Properties.Resources", typeof(Resources).Assembly); System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Gtk.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
} }
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle internal static System.Globalization.CultureInfo Culture {
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get { get {
return resourceCulture; return resourceCulture;
} }
@ -60,22 +45,6 @@ namespace AM2RLauncher.Gtk.Properties {
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die &lt;log4net&gt;
/// &lt;root&gt;
/// &lt;level value=&quot;ALL&quot; /&gt;
/// &lt;appender-ref ref=&quot;file&quot; /&gt;
/// &lt;/root&gt;
/// &lt;appender name=&quot;file&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;&gt;
/// &lt;file value=&quot;${DATADIR}/Logs/AM2RLauncher.log&quot; /&gt;
/// &lt;appendToFile value=&quot;true&quot; /&gt;
/// &lt;rollingStyle value=&quot;Once&quot; /&gt;
/// &lt;maxSizeRollBackups value=&quot;7&quot; /&gt;
/// &lt;maximumFileSize value=&quot;3MB&quot; /&gt;
/// &lt;staticLogFileName value=&quot;true&quot; /&gt;
/// &lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&gt;
/// &lt;conversionPattern value=&quot;%date [%thread] %level %logg [Rest der Zeichenfolge wurde abgeschnitten]&quot;; ähnelt.
/// </summary>
internal static string log4netContents { internal static string log4netContents {
get { get {
return ResourceManager.GetString("log4netContents", resourceCulture); return ResourceManager.GetString("log4netContents", resourceCulture);

@ -120,7 +120,7 @@
<data name="log4netContents" xml:space="preserve"> <data name="log4netContents" xml:space="preserve">
<value>&lt;log4net&gt; <value>&lt;log4net&gt;
&lt;root&gt; &lt;root&gt;
&lt;level value="ALL" /&gt; &lt;level value="INFO" /&gt;
&lt;appender-ref ref="file" /&gt; &lt;appender-ref ref="file" /&gt;
&lt;/root&gt; &lt;/root&gt;
&lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt; &lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt;

@ -4,6 +4,7 @@ using log4net.Config;
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO; using System.IO;
using log4net.Repository.Hierarchy;
namespace AM2RLauncher.Mac; namespace AM2RLauncher.Mac;
@ -36,6 +37,11 @@ internal static class MainClass
// Configure logger // Configure logger
XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); 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 try
{ {
Application macLauncher = new Application(Eto.Platforms.Mac64); Application macLauncher = new Application(Eto.Platforms.Mac64);

@ -1,7 +1,6 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // 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 // Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated. // the code is regenerated.
@ -10,7 +9,6 @@
namespace AM2RLauncher.Mac.Properties { namespace AM2RLauncher.Mac.Properties {
using System; using System;
using System.Reflection;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]

@ -120,7 +120,7 @@
<data name="log4netContents" xml:space="preserve"> <data name="log4netContents" xml:space="preserve">
<value>&lt;log4net&gt; <value>&lt;log4net&gt;
&lt;root&gt; &lt;root&gt;
&lt;level value="ALL" /&gt; &lt;level value="INFO" /&gt;
&lt;appender-ref ref="file" /&gt; &lt;appender-ref ref="file" /&gt;
&lt;/root&gt; &lt;/root&gt;
&lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt; &lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt;

@ -4,6 +4,7 @@ using log4net.Config;
using System; using System;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using log4net.Repository.Hierarchy;
namespace AM2RLauncher.Wpf; namespace AM2RLauncher.Wpf;
@ -35,6 +36,11 @@ internal static class MainClass
// Configure logger // Configure logger
XmlConfigurator.Configure(new FileInfo(launcherDataPath + "/log4net.config")); 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 //Log Wine
if (Core.Core.IsThisRunningFromWine) if (Core.Core.IsThisRunningFromWine)
log.Info("Currently running from WINE!"); log.Info("Currently running from WINE!");

@ -1,10 +1,9 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// Dieser Code wurde von einem Tool generiert. // This code was generated by a tool.
// Laufzeitversion:4.0.30319.42000
// //
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn // Changes to this file may cause incorrect behavior and will be lost if
// der Code erneut generiert wird. // the code is regenerated.
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -12,46 +11,32 @@ namespace AM2RLauncher.Wpf.Properties {
using System; using System;
/// <summary> [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. [System.Diagnostics.DebuggerNonUserCodeAttribute()]
/// </summary> [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
// 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()]
internal class Resources { 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() { internal Resources() {
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. internal static System.Resources.ResourceManager ResourceManager {
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.Equals(null, resourceMan)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Wpf.Properties.Resources", typeof(Resources).Assembly); System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Wpf.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
} }
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle internal static System.Globalization.CultureInfo Culture {
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get { get {
return resourceCulture; return resourceCulture;
} }
@ -60,22 +45,6 @@ namespace AM2RLauncher.Wpf.Properties {
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die &lt;log4net&gt;
/// &lt;root&gt;
/// &lt;level value=&quot;ALL&quot; /&gt;
/// &lt;appender-ref ref=&quot;file&quot; /&gt;
/// &lt;/root&gt;
/// &lt;appender name=&quot;file&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;&gt;
/// &lt;file value=&quot;${DATADIR}/Logs/AM2RLauncher.log&quot; /&gt;
/// &lt;appendToFile value=&quot;true&quot; /&gt;
/// &lt;rollingStyle value=&quot;Once&quot; /&gt;
/// &lt;maxSizeRollBackups value=&quot;7&quot; /&gt;
/// &lt;maximumFileSize value=&quot;3MB&quot; /&gt;
/// &lt;staticLogFileName value=&quot;true&quot; /&gt;
/// &lt;layout type=&quot;log4net.Layout.PatternLayout&quot;&gt;
/// &lt;conversionPattern value=&quot;%date [%thread] %level %logg [Rest der Zeichenfolge wurde abgeschnitten]&quot;; ähnelt.
/// </summary>
internal static string log4netContents { internal static string log4netContents {
get { get {
return ResourceManager.GetString("log4netContents", resourceCulture); return ResourceManager.GetString("log4netContents", resourceCulture);

@ -120,7 +120,7 @@
<data name="log4netContents" xml:space="preserve"> <data name="log4netContents" xml:space="preserve">
<value>&lt;log4net&gt; <value>&lt;log4net&gt;
&lt;root&gt; &lt;root&gt;
&lt;level value="ALL" /&gt; &lt;level value="INFO" /&gt;
&lt;appender-ref ref="file" /&gt; &lt;appender-ref ref="file" /&gt;
&lt;/root&gt; &lt;/root&gt;
&lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt; &lt;appender name="file" type="log4net.Appender.RollingFileAppender"&gt;

@ -1,10 +1,9 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// Dieser Code wurde von einem Tool generiert. // This code was generated by a tool.
// Laufzeitversion:4.0.30319.42000
// //
// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn // Changes to this file may cause incorrect behavior and will be lost if
// der Code erneut generiert wird. // the code is regenerated.
// </auto-generated> // </auto-generated>
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@ -12,46 +11,32 @@ namespace AM2RLauncher.Language {
using System; using System;
/// <summary> [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. [System.Diagnostics.DebuggerNonUserCodeAttribute()]
/// </summary> [System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
// 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 { 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() { internal Text() {
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. public static System.Resources.ResourceManager ResourceManager {
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Resources.ResourceManager ResourceManager {
get { get {
if (object.ReferenceEquals(resourceMan, null)) { if (object.Equals(null, resourceMan)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly); System.Resources.ResourceManager temp = new System.Resources.ResourceManager("AM2RLauncher.Language.Text", typeof(Text).Assembly);
resourceMan = temp; resourceMan = temp;
} }
return resourceMan; return resourceMan;
} }
} }
/// <summary> [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle public static System.Globalization.CultureInfo Culture {
/// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
public static global::System.Globalization.CultureInfo Culture {
get { get {
return resourceCulture; return resourceCulture;
} }
@ -60,791 +45,538 @@ namespace AM2RLauncher.Language {
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die ABORT ähnelt.
/// </summary>
public static string Abort { public static string Abort {
get { get {
return ResourceManager.GetString("Abort", resourceCulture); return ResourceManager.GetString("Abort", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die ADD NEW MOD ähnelt.
/// </summary>
public static string AddNewMod { public static string AddNewMod {
get { get {
return ResourceManager.GetString("AddNewMod", resourceCulture); return ResourceManager.GetString("AddNewMod", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select a mod to be installed. ähnelt.
/// </summary>
public static string AddNewModToolTip { public static string AddNewModToolTip {
get { get {
return ResourceManager.GetString("AddNewModToolTip", resourceCulture); return ResourceManager.GetString("AddNewModToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Can&apos;t create an APK. ähnelt.
/// </summary>
public static string ApkButtonDisabledToolTip { public static string ApkButtonDisabledToolTip {
get { get {
return ResourceManager.GetString("ApkButtonDisabledToolTip", resourceCulture); return ResourceManager.GetString("ApkButtonDisabledToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Create an APK for $NAME ähnelt.
/// </summary>
public static string ApkButtonEnabledToolTip { public static string ApkButtonEnabledToolTip {
get { get {
return ResourceManager.GetString("ApkButtonEnabledToolTip", resourceCulture); return ResourceManager.GetString("ApkButtonEnabledToolTip", resourceCulture);
} }
} }
/// <summary> public static string ArchiveNotesCommunityUpdates {
/// 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.
/// </summary>
public static string ArchiveNotes {
get { get {
return ResourceManager.GetString("ArchiveNotes", resourceCulture); return ResourceManager.GetString("ArchiveNotesCommunityUpdates", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Author(s): ähnelt.
/// </summary>
public static string Author { public static string Author {
get { get {
return ResourceManager.GetString("Author", resourceCulture); return ResourceManager.GetString("Author", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Automatically update AM2R ähnelt.
/// </summary>
public static string AutoUpdateAM2R { public static string AutoUpdateAM2R {
get { get {
return ResourceManager.GetString("AutoUpdateAM2R", resourceCulture); return ResourceManager.GetString("AutoUpdateAM2R", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Automatically update the AM2RLauncher ähnelt.
/// </summary>
public static string AutoUpdateLauncher { public static string AutoUpdateLauncher {
get { get {
return ResourceManager.GetString("AutoUpdateLauncher", resourceCulture); return ResourceManager.GetString("AutoUpdateLauncher", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Changelog ähnelt.
/// </summary>
public static string ChangelogTab { public static string ChangelogTab {
get { get {
return ResourceManager.GetString("ChangelogTab", resourceCulture); return ResourceManager.GetString("ChangelogTab", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Are you sure you want to cancel this now? This will delete all your progress! ähnelt.
/// </summary>
public static string CloseOnCloningText { public static string CloseOnCloningText {
get { get {
return ResourceManager.GetString("CloseOnCloningText", resourceCulture); return ResourceManager.GetString("CloseOnCloningText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Sorry, you can&apos;t close this while it&apos;s installing! Please wait until it&apos;s finished. ähnelt.
/// </summary>
public static string CloseOnInstallingText { public static string CloseOnInstallingText {
get { get {
return ResourceManager.GetString("CloseOnInstallingText", resourceCulture); return ResourceManager.GetString("CloseOnInstallingText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die There was a problem with your Patchdata folder. It has been deleted, please download it again. ähnelt.
/// </summary>
public static string CorruptPatchData { public static string CorruptPatchData {
get { get {
return ResourceManager.GetString("CorruptPatchData", resourceCulture); return ResourceManager.GetString("CorruptPatchData", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die CREATE APK ähnelt.
/// </summary>
public static string CreateAPK { public static string CreateAPK {
get { get {
return ResourceManager.GetString("CreateAPK", resourceCulture); return ResourceManager.GetString("CreateAPK", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die CREATING APK ähnelt.
/// </summary>
public static string CreatingAPK { public static string CreatingAPK {
get { get {
return ResourceManager.GetString("CreatingAPK", resourceCulture); return ResourceManager.GetString("CreatingAPK", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Current profile: ähnelt.
/// </summary>
public static string CurrentProfile { public static string CurrentProfile {
get { get {
return ResourceManager.GetString("CurrentProfile", resourceCulture); return ResourceManager.GetString("CurrentProfile", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Enter custom game environment variables: ähnelt.
/// </summary>
public static string CustomEnvVarLabel { public static string CustomEnvVarLabel {
get { get {
return ResourceManager.GetString("CustomEnvVarLabel", resourceCulture); return ResourceManager.GetString("CustomEnvVarLabel", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Use custom download mirror ähnelt.
/// </summary>
public static string CustomMirrorCheck { public static string CustomMirrorCheck {
get { get {
return ResourceManager.GetString("CustomMirrorCheck", resourceCulture); return ResourceManager.GetString("CustomMirrorCheck", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME couldn&apos;t be deleted. ähnelt.
/// </summary>
public static string DeleteModButtonCantDelete { public static string DeleteModButtonCantDelete {
get { get {
return ResourceManager.GetString("DeleteModButtonCantDelete", resourceCulture); return ResourceManager.GetString("DeleteModButtonCantDelete", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME was successfully deleted! ähnelt.
/// </summary>
public static string DeleteModButtonSuccess { public static string DeleteModButtonSuccess {
get { get {
return ResourceManager.GetString("DeleteModButtonSuccess", resourceCulture); return ResourceManager.GetString("DeleteModButtonSuccess", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die DELETE MOD ähnelt.
/// </summary>
public static string DeleteModButtonText { public static string DeleteModButtonText {
get { get {
return ResourceManager.GetString("DeleteModButtonText", resourceCulture); return ResourceManager.GetString("DeleteModButtonText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Delete $NAME. ähnelt.
/// </summary>
public static string DeleteModButtonToolTip { public static string DeleteModButtonToolTip {
get { get {
return ResourceManager.GetString("DeleteModButtonToolTip", resourceCulture); return ResourceManager.GetString("DeleteModButtonToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die This will delete all files for $NAME. Are you sure you want to continue? ähnelt.
/// </summary>
public static string DeleteModWarning { public static string DeleteModWarning {
get { get {
return ResourceManager.GetString("DeleteModWarning", resourceCulture); return ResourceManager.GetString("DeleteModWarning", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die The Official AM2R Discord ähnelt.
/// </summary>
public static string DiscordToolTip { public static string DiscordToolTip {
get { get {
return ResourceManager.GetString("DiscordToolTip", resourceCulture); return ResourceManager.GetString("DiscordToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die DOWNLOAD ähnelt.
/// </summary>
public static string Download { public static string Download {
get { get {
return ResourceManager.GetString("Download", resourceCulture); return ResourceManager.GetString("Download", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die DOWNLOADING ähnelt.
/// </summary>
public static string Downloading { public static string Downloading {
get { get {
return ResourceManager.GetString("Downloading", resourceCulture); return ResourceManager.GetString("Downloading", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Download source: ähnelt.
/// </summary>
public static string DownloadSource { public static string DownloadSource {
get { get {
return ResourceManager.GetString("DownloadSource", resourceCulture); return ResourceManager.GetString("DownloadSource", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Error ähnelt.
/// </summary>
public static string ErrorWindowTitle { public static string ErrorWindowTitle {
get { get {
return ResourceManager.GetString("ErrorWindowTitle", resourceCulture); return ResourceManager.GetString("ErrorWindowTitle", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die The Community-Developers Github Page ähnelt.
/// </summary>
public static string GithubToolTip { public static string GithubToolTip {
get { get {
return ResourceManager.GetString("GithubToolTip", resourceCulture); return ResourceManager.GetString("GithubToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Use high quality music when patching to Android ähnelt.
/// </summary>
public static string HighQualityAndroid { public static string HighQualityAndroid {
get { get {
return ResourceManager.GetString("HighQualityAndroid", resourceCulture); return ResourceManager.GetString("HighQualityAndroid", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Use high quality music when patching to PC ähnelt.
/// </summary>
public static string HighQualityPC { public static string HighQualityPC {
get { get {
return ResourceManager.GetString("HighQualityPC", resourceCulture); return ResourceManager.GetString("HighQualityPC", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die INSTALL ähnelt.
/// </summary>
public static string Install { public static string Install {
get { get {
return ResourceManager.GetString("Install", resourceCulture); return ResourceManager.GetString("Install", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die INSTALLING ähnelt.
/// </summary>
public static string Installing { public static string Installing {
get { get {
return ResourceManager.GetString("Installing", resourceCulture); return ResourceManager.GetString("Installing", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Couldn&apos;t establish an internet connection! Try again later! ähnelt.
/// </summary>
public static string InternetConnectionDrop { public static string InternetConnectionDrop {
get { get {
return ResourceManager.GetString("InternetConnectionDrop", resourceCulture); return ResourceManager.GetString("InternetConnectionDrop", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME is an invalid git URL! ähnelt.
/// </summary>
public static string InvalidGitURL { public static string InvalidGitURL {
get { get {
return ResourceManager.GetString("InvalidGitURL", resourceCulture); return ResourceManager.GetString("InvalidGitURL", resourceCulture);
} }
} }
/// <summary>
/// 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.
/// </summary>
public static string JavaNotFound { public static string JavaNotFound {
get { get {
return ResourceManager.GetString("JavaNotFound", resourceCulture); return ResourceManager.GetString("JavaNotFound", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Launcher Language: (requires restart to take effect) ähnelt.
/// </summary>
public static string LanguageNotice { public static string LanguageNotice {
get { get {
return ResourceManager.GetString("LanguageNotice", resourceCulture); return ResourceManager.GetString("LanguageNotice", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Settings ähnelt.
/// </summary>
public static string LauncherSettingsTab { public static string LauncherSettingsTab {
get { get {
return ResourceManager.GetString("LauncherSettingsTab", resourceCulture); return ResourceManager.GetString("LauncherSettingsTab", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die GitHub (Primary) ähnelt.
/// </summary>
public static string MirrorGithubText { public static string MirrorGithubText {
get { get {
return ResourceManager.GetString("MirrorGithubText", resourceCulture); return ResourceManager.GetString("MirrorGithubText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die GitLab (Mirror) ähnelt.
/// </summary>
public static string MirrorGitlabText { public static string MirrorGitlabText {
get { get {
return ResourceManager.GetString("MirrorGitlabText", resourceCulture); return ResourceManager.GetString("MirrorGitlabText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME is already installed! ähnelt.
/// </summary>
public static string ModIsAlreadyInstalledMessage { public static string ModIsAlreadyInstalledMessage {
get { get {
return ResourceManager.GetString("ModIsAlreadyInstalledMessage", resourceCulture); return ResourceManager.GetString("ModIsAlreadyInstalledMessage", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME cannot be installed! It&apos;s for $OS. Download the $CURRENTOS version instead if it exists, or ask the mod authors to make one. ähnelt.
/// </summary>
public static string ModIsForWrongOS { public static string ModIsForWrongOS {
get { get {
return ResourceManager.GetString("ModIsForWrongOS", resourceCulture); return ResourceManager.GetString("ModIsForWrongOS", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME is an invalid AM2R mod! ähnelt.
/// </summary>
public static string ModIsInvalidMessage { public static string ModIsInvalidMessage {
get { get {
return ResourceManager.GetString("ModIsInvalidMessage", resourceCulture); return ResourceManager.GetString("ModIsInvalidMessage", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die $NAME was successfully added! Go to the Play Tab in order to install it! ähnelt.
/// </summary>
public static string ModSuccessfullyInstalledMessage { public static string ModSuccessfullyInstalledMessage {
get { get {
return ResourceManager.GetString("ModSuccessfullyInstalledMessage", resourceCulture); return ResourceManager.GetString("ModSuccessfullyInstalledMessage", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die News ähnelt.
/// </summary>
public static string NewsTab { public static string NewsTab {
get { get {
return ResourceManager.GetString("NewsTab", resourceCulture); return ResourceManager.GetString("NewsTab", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Couldn&apos;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.
/// </summary>
public static string NoInternetConnection { public static string NoInternetConnection {
get { get {
return ResourceManager.GetString("NoInternetConnection", resourceCulture); return ResourceManager.GetString("NoInternetConnection", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die OPEN PROFILE FOLDER ähnelt.
/// </summary>
public static string OpenProfileFolder { public static string OpenProfileFolder {
get { get {
return ResourceManager.GetString("OpenProfileFolder", resourceCulture); return ResourceManager.GetString("OpenProfileFolder", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Opens the folder where game files are located for $NAME. ähnelt.
/// </summary>
public static string OpenProfileFolderToolTip { public static string OpenProfileFolderToolTip {
get { get {
return ResourceManager.GetString("OpenProfileFolderToolTip", resourceCulture); return ResourceManager.GetString("OpenProfileFolderToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die OPEN PROFILE SAVE FOLDER ähnelt.
/// </summary>
public static string OpenSaveFolder { public static string OpenSaveFolder {
get { get {
return ResourceManager.GetString("OpenSaveFolder", resourceCulture); return ResourceManager.GetString("OpenSaveFolder", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Opens the folder where save files are located for $NAME. ähnelt.
/// </summary>
public static string OpenSaveFolderToolTip { public static string OpenSaveFolderToolTip {
get { get {
return ResourceManager.GetString("OpenSaveFolderToolTip", resourceCulture); return ResourceManager.GetString("OpenSaveFolderToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die PLAY ähnelt.
/// </summary>
public static string Play { public static string Play {
get { get {
return ResourceManager.GetString("Play", resourceCulture); return ResourceManager.GetString("Play", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Currently downloading . . . ähnelt.
/// </summary>
public static string PlayButtonDownladingToolTip { public static string PlayButtonDownladingToolTip {
get { get {
return ResourceManager.GetString("PlayButtonDownladingToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonDownladingToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Download the necessary patch files. ähnelt.
/// </summary>
public static string PlayButtonDownloadToolTip { public static string PlayButtonDownloadToolTip {
get { get {
return ResourceManager.GetString("PlayButtonDownloadToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonDownloadToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Currently installing. . . ähnelt.
/// </summary>
public static string PlayButtonInstallingToolTip { public static string PlayButtonInstallingToolTip {
get { get {
return ResourceManager.GetString("PlayButtonInstallingToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonInstallingToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Install $NAME ähnelt.
/// </summary>
public static string PlayButtonInstallToolTip { public static string PlayButtonInstallToolTip {
get { get {
return ResourceManager.GetString("PlayButtonInstallToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonInstallToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Currently already playing! ähnelt.
/// </summary>
public static string PlayButtonPlayingToolTip { public static string PlayButtonPlayingToolTip {
get { get {
return ResourceManager.GetString("PlayButtonPlayingToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonPlayingToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Play ähnelt.
/// </summary>
public static string PlayButtonPlayToolTip { public static string PlayButtonPlayToolTip {
get { get {
return ResourceManager.GetString("PlayButtonPlayToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonPlayToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select your AM2R_1.1.zip ähnelt.
/// </summary>
public static string PlayButtonSelect11ToolTip { public static string PlayButtonSelect11ToolTip {
get { get {
return ResourceManager.GetString("PlayButtonSelect11ToolTip", resourceCulture); return ResourceManager.GetString("PlayButtonSelect11ToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die PLAYING ähnelt.
/// </summary>
public static string Playing { public static string Playing {
get { get {
return ResourceManager.GetString("Playing", resourceCulture); return ResourceManager.GetString("Playing", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Play ähnelt.
/// </summary>
public static string PlayTab { public static string PlayTab {
get { get {
return ResourceManager.GetString("PlayTab", resourceCulture); return ResourceManager.GetString("PlayTab", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Create game debug logs ähnelt.
/// </summary>
public static string ProfileDebugCheckBox { public static string ProfileDebugCheckBox {
get { get {
return ResourceManager.GetString("ProfileDebugCheckBox", resourceCulture); return ResourceManager.GetString("ProfileDebugCheckBox", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Profile notes: ähnelt.
/// </summary>
public static string ProfileNotes { public static string ProfileNotes {
get { get {
return ResourceManager.GetString("ProfileNotes", resourceCulture); return ResourceManager.GetString("ProfileNotes", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Mod Settings ähnelt.
/// </summary>
public static string ProfileSettingsTab { public static string ProfileSettingsTab {
get { get {
return ResourceManager.GetString("ProfileSettingsTab", resourceCulture); return ResourceManager.GetString("ProfileSettingsTab", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Progress: ähnelt.
/// </summary>
public static string ProgressbarProgress { public static string ProgressbarProgress {
get { get {
return ResourceManager.GetString("ProgressbarProgress", resourceCulture); return ResourceManager.GetString("ProgressbarProgress", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die The Official AM2R Subreddit ähnelt.
/// </summary>
public static string RedditToolTip { public static string RedditToolTip {
get { get {
return ResourceManager.GetString("RedditToolTip", resourceCulture); return ResourceManager.GetString("RedditToolTip", resourceCulture);
} }
} }
/// <summary>
/// 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.
/// </summary>
public static string SaveLocationWarning { public static string SaveLocationWarning {
get { get {
return ResourceManager.GetString("SaveLocationWarning", resourceCulture); return ResourceManager.GetString("SaveLocationWarning", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die SELECT AM2R_1.1.zip ähnelt.
/// </summary>
public static string Select11 { public static string Select11 {
get { get {
return ResourceManager.GetString("Select11", resourceCulture); return ResourceManager.GetString("Select11", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select AM2R_1.1.zip ähnelt.
/// </summary>
public static string Select11FileDialog { public static string Select11FileDialog {
get { get {
return ResourceManager.GetString("Select11FileDialog", resourceCulture); return ResourceManager.GetString("Select11FileDialog", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select your Mod ähnelt.
/// </summary>
public static string SelectModFileDialog { public static string SelectModFileDialog {
get { get {
return ResourceManager.GetString("SelectModFileDialog", resourceCulture); return ResourceManager.GetString("SelectModFileDialog", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Success ähnelt.
/// </summary>
public static string SuccessWindowTitle { public static string SuccessWindowTitle {
get { get {
return ResourceManager.GetString("SuccessWindowTitle", resourceCulture); return ResourceManager.GetString("SuccessWindowTitle", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die System Language ähnelt.
/// </summary>
public static string SystemLanguage { public static string SystemLanguage {
get { get {
return ResourceManager.GetString("SystemLanguage", resourceCulture); return ResourceManager.GetString("SystemLanguage", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Show Launcher ähnelt.
/// </summary>
public static string TrayButtonShow { public static string TrayButtonShow {
get { get {
return ResourceManager.GetString("TrayButtonShow", resourceCulture); return ResourceManager.GetString("TrayButtonShow", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Can&apos;t access the Folder in order to download the update! Consider moving the program, or disabling auto-updates. ähnelt.
/// </summary>
public static string UnauthorizedAccessMessage { public static string UnauthorizedAccessMessage {
get { get {
return ResourceManager.GetString("UnauthorizedAccessMessage", resourceCulture); return ResourceManager.GetString("UnauthorizedAccessMessage", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Unhandled Exception has occured in your Application. ähnelt.
/// </summary>
public static string UnhandledException { public static string UnhandledException {
get { get {
return ResourceManager.GetString("UnhandledException", resourceCulture); return ResourceManager.GetString("UnhandledException", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select Mod Update ähnelt.
/// </summary>
public static string UpdateMod { public static string UpdateMod {
get { get {
return ResourceManager.GetString("UpdateMod", resourceCulture); return ResourceManager.GetString("UpdateMod", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die UPDATE MOD ähnelt.
/// </summary>
public static string UpdateModButtonText { public static string UpdateModButtonText {
get { get {
return ResourceManager.GetString("UpdateModButtonText", resourceCulture); return ResourceManager.GetString("UpdateModButtonText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Select a zip to update $NAME. ähnelt.
/// </summary>
public static string UpdateModButtonToolTip { public static string UpdateModButtonToolTip {
get { get {
return ResourceManager.GetString("UpdateModButtonToolTip", resourceCulture); return ResourceManager.GetString("UpdateModButtonToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Can&apos;t update $NAME with $SELECT. Add $SELECT as a new mod instead! ähnelt.
/// </summary>
public static string UpdateModButtonWrongMod { public static string UpdateModButtonWrongMod {
get { get {
return ResourceManager.GetString("UpdateModButtonWrongMod", resourceCulture); return ResourceManager.GetString("UpdateModButtonWrongMod", resourceCulture);
} }
} }
/// <summary>
/// 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.
/// </summary>
public static string UpdateModWarning { public static string UpdateModWarning {
get { get {
return ResourceManager.GetString("UpdateModWarning", resourceCulture); return ResourceManager.GetString("UpdateModWarning", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Version: ähnelt.
/// </summary>
public static string VersionLabel { public static string VersionLabel {
get { get {
return ResourceManager.GetString("VersionLabel", resourceCulture); return ResourceManager.GetString("VersionLabel", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt.
/// </summary>
public static string WarningWindowOk { public static string WarningWindowOk {
get { get {
return ResourceManager.GetString("WarningWindowOk", resourceCulture); return ResourceManager.GetString("WarningWindowOk", resourceCulture);
} }
} }
/// <summary>
/// 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.
/// </summary>
public static string WarningWindowText { public static string WarningWindowText {
get { get {
return ResourceManager.GetString("WarningWindowText", resourceCulture); return ResourceManager.GetString("WarningWindowText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die WARNING ähnelt.
/// </summary>
public static string WarningWindowTitle { public static string WarningWindowTitle {
get { get {
return ResourceManager.GetString("WarningWindowTitle", resourceCulture); return ResourceManager.GetString("WarningWindowTitle", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Xdelta not found! Cannot install Profiles without it. Please install xdelta3 from your local package manager. ähnelt.
/// </summary>
public static string XdeltaNotFound { public static string XdeltaNotFound {
get { get {
return ResourceManager.GetString("XdeltaNotFound", resourceCulture); return ResourceManager.GetString("XdeltaNotFound", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die The Community-Developers YouTube Channel ähnelt.
/// </summary>
public static string YoutubeToolTip { public static string YoutubeToolTip {
get { get {
return ResourceManager.GetString("YoutubeToolTip", resourceCulture); return ResourceManager.GetString("YoutubeToolTip", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die Zip Archives (*.zip) ähnelt.
/// </summary>
public static string ZipArchiveText { public static string ZipArchiveText {
get { get {
return ResourceManager.GetString("ZipArchiveText", resourceCulture); return ResourceManager.GetString("ZipArchiveText", resourceCulture);
} }
} }
/// <summary>
/// Sucht eine lokalisierte Zeichenfolge, die The selected Zip is not AM2R 1.1! Please choose another Zip file. ähnelt.
/// </summary>
public static string ZipIsNotAM2R11 { public static string ZipIsNotAM2R11 {
get { get {
return ResourceManager.GetString("ZipIsNotAM2R11", resourceCulture); 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);
}
}
} }
} }

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>APK erstellen für $NAME</value> <value>APK erstellen für $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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!</value> <value>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!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@ Bitte äußerste Vorsicht walten lassen.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>Das ausgewählte Zip-Archiv ist nicht AM2R 1.1 oder falsch geformt! Bitte ein anderes Archiv auswählen.</value> <value>Das ausgewählte Zip-Archiv ist nicht AM2R 1.1 oder falsch geformt! Bitte ein anderes Archiv auswählen.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>$NAME archivieren?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Crear un APK para $NAME</value> <value>Crear un APK para $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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!</value> <value>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!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@ Procede con cautela.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>¡El Zip seleccionado no es AM2R_1.1! Por favor elige otro archivo Zip.</value> <value>¡El Zip seleccionado no es AM2R_1.1! Por favor elige otro archivo Zip.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>¿Deseas archivar $NAME?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Créer un APK pour $NAME</value> <value>Créer un APK pour $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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, <value>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 donc assurez-vous de faire une sauvegarde de celles-ci avant de lancer
ce profil !</value> ce profil !</value>
@ -382,4 +382,10 @@ Soyez prudent.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>Le Zip sélectionné n'est pas AM2R 1.1 ! Veuillez choisir un autre fichier Zip.</value> <value>Le Zip sélectionné n'est pas AM2R 1.1 ! Veuillez choisir un autre fichier Zip.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>Archive $NAME ?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Crea un APK per $NAME</value> <value>Crea un APK per $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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!</value> <value>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!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@ Procedi con cautela.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>Il Zip selezionato non è AM2R 1.1! Perfavore scegli un altro file Zip.</value> <value>Il Zip selezionato non è AM2R 1.1! Perfavore scegli un altro file Zip.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>Vuoi archiviare $NAME?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>次のAPKを作成します $NAME</value> <value>次のAPKを作成します $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>これは以前インストールされたCommunity Updateのアーカイブです。再インストールはできませんし、ゲームファイルが削除されると自動的に削除されます。現在インストールされているCommunity Updateとセーブデータを共有しているため、このプロファイルを実行する前に必ずセーブデータのバックアップを作成してください</value> <value>これは以前インストールされたCommunity Updateのアーカイブです。再インストールはできませんし、ゲームファイルが削除されると自動的に削除されます。現在インストールされているCommunity Updateとセーブデータを共有しているため、このプロファイルを実行する前に必ずセーブデータのバックアップを作成してください</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>そのZIPファイルはAM2R v1.1ではありません! 別のZIPファイルを選んで下さい</value> <value>そのZIPファイルはAM2R v1.1ではありません! 別のZIPファイルを選んで下さい</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>$NAMEをアーカイブ化しますか</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>これは既にインストールされているMODです。再インストールはできず、またゲームファイルを削除すると自動的に削除されます。</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Criar um APK para $NAME</value> <value>Criar um APK para $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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!</value> <value>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!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@ Prossiga com cuidado.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>O arquivo Zip selecionado não contém o AM2R 1.1! Por favor, selecione outro arquivo Zip</value> <value>O arquivo Zip selecionado não contém o AM2R 1.1! Por favor, selecione outro arquivo Zip</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>Deseja arquivar $NAME?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>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.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Create an APK for $NAME</value> <value>Create an APK for $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>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!</value> <value>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!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -382,4 +382,10 @@ Proceed with caution.</value>
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>The selected Zip is not AM2R 1.1! Please choose another Zip file.</value> <value>The selected Zip is not AM2R 1.1! Please choose another Zip file.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>Do you want to archive $NAME?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>This is an archive of a previously installed Mod. It cannot be re-installed and will remove itself if its game files are deleted.</value>
</data>
</root> </root>

@ -132,7 +132,7 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>Создать APK-файл для $NAME</value> <value>Создать APK-файл для $NAME</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>Этот архив содержит ранее установленное обновление сообщества. Оно не может быть переустановлено и автоматически удалится при удалении файлов игры. Оно имеет общие файлы сохранения с текущим обновлением сообщества, поэтому не забудьте создать копию сохранений перед запуском!</value> <value>Этот архив содержит ранее установленное обновление сообщества. Оно не может быть переустановлено и автоматически удалится при удалении файлов игры. Оно имеет общие файлы сохранения с текущим обновлением сообщества, поэтому не забудьте создать копию сохранений перед запуском!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
@ -380,4 +380,10 @@
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>Указанный zip-файл не является файлом AM2R 1.1! Пожалуйста, выберите другой zip-файл.</value> <value>Указанный zip-файл не является файлом AM2R 1.1! Пожалуйста, выберите другой zip-файл.</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>Архивировать $NAME?</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>Это архив, содержащий ранее установленный мод. Он не может быть переустановлен, и, при удалении файлов игры, так же будет удалён.</value>
</data>
</root> </root>

@ -132,8 +132,8 @@
<data name="ApkButtonEnabledToolTip" xml:space="preserve"> <data name="ApkButtonEnabledToolTip" xml:space="preserve">
<value>为 $NAME 创建 APK</value> <value>为 $NAME 创建 APK</value>
</data> </data>
<data name="ArchiveNotes" xml:space="preserve"> <data name="ArchiveNotesCommunityUpdates" xml:space="preserve">
<value>这是先前安装过的社区更新版本的压缩文件,因此无法再重新安装一遍,并且在游戏文件被删除后也会自行删除。由于与当前安装的社区更新版本共用保存数据,所以请在运行该游戏实例前备份好保存数据!</value> <value>此为以前安装过的社区更新版本的归档,无法重新安装,若对应的游戏文件被删除,该归档也会自行删除。由于和当前安装的社区更新版本共用保存数据,所以请在运行该游戏实例前备份好保存数据!</value>
</data> </data>
<data name="Author" xml:space="preserve"> <data name="Author" xml:space="preserve">
<value>作者:</value> <value>作者:</value>
@ -382,4 +382,10 @@
<data name="ZipIsNotAM2R11" xml:space="preserve"> <data name="ZipIsNotAM2R11" xml:space="preserve">
<value>选定的文件不是 AM2R_1.1 !请选择其他 Zip 文件</value> <value>选定的文件不是 AM2R_1.1 !请选择其他 Zip 文件</value>
</data> </data>
<data name="ArchiveMod" xml:space="preserve">
<value>是否要归档 $NAME</value>
</data>
<data name="ArchiveNotesMods" xml:space="preserve">
<value>此为以前安装过的 Mod 的归档,无法重新安装,若对应的游戏文件被删除,该归档也会自行删除。</value>
</data>
</root> </root>

@ -14,7 +14,7 @@ namespace AM2RLauncher
//TODO: Mac support for autoupdater in general //TODO: Mac support for autoupdater in general
public static class LauncherUpdater public static class LauncherUpdater
{ {
// How often this was broken count: 6 // How often this was broken count: 7
// Auto updating is fun! // Auto updating is fun!
/// <summary>The Version that identifies this current release.</summary> /// <summary>The Version that identifies this current release.</summary>
@ -131,6 +131,15 @@ namespace AM2RLauncher
// No new update, exiting // No new update, exiting
if (!isCurrentVersionOutdated) if (!isCurrentVersionOutdated)
return; 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 + "."); log.Info("Current version (" + VERSION + ") is outdated! Initiating update for version " + onlineVersion + ".");
@ -207,8 +216,7 @@ namespace AM2RLauncher
CrossPlatformOperations.CopyOldConfigToNewConfig(); CrossPlatformOperations.CopyOldConfigToNewConfig();
log.Info("Files extracted. Preparing to restart executable..."); log.Info("Files extracted. Preparing to restart executable...");
if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x " + updatePath + "./AM2RLauncher.Gtk");
if (OS.IsLinux) System.Diagnostics.Process.Start("chmod", "+x ./AM2RLauncher.Gtk");
System.Diagnostics.Process.Start(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME); System.Diagnostics.Process.Start(updatePath + "/" + CrossPlatformOperations.LAUNCHERNAME);
Environment.Exit(0); Environment.Exit(0);

@ -31,7 +31,7 @@ namespace AM2RLauncher
/// </summary> /// </summary>
private async void PlayButtonLoadComplete(object sender, EventArgs e) private async void PlayButtonLoadComplete(object sender, EventArgs e)
{ {
LoadProfiles(); LoadProfilesAndAdjustLists();
if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked) if (!Profile.IsPatchDataCloned() || !(bool)autoUpdateAM2RCheck.Checked)
return; return;
@ -92,7 +92,7 @@ namespace AM2RLauncher
{ {
progressBar.Visible = false; progressBar.Visible = false;
progressLabel.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! // 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) if (currentXML.Version != profileList[0].Version)
{ {
log.Info("New game version (" + profileList[0].Version + ") detected! Beginning archival of version " + currentXML.Version + "..."); log.Info("New game version (" + profileList[0].Version + ") detected! Beginning archival of version " + currentXML.Version + "...");
Profile.ArchiveProfile(currentXML);
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<ProfileXML>(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.");
}
profileDropDown.SelectedIndex = 0; profileDropDown.SelectedIndex = 0;
LoadProfilesAndAdjustLists();
LoadProfiles();
} }
} }
@ -160,6 +122,9 @@ namespace AM2RLauncher
// State Check // State Check
UpdateStateMachine(); UpdateStateMachine();
// Check if 1.1 is installed by forcing invalidation
Profile.Is11Installed(true);
switch (updateState) switch (updateState)
{ {
#region Download #region Download
@ -240,7 +205,7 @@ namespace AM2RLauncher
SetPlayButtonState(UpdateState.Install); SetPlayButtonState(UpdateState.Install);
// This needs to be run BEFORE the state check so that the Mod Settings tab doesn't weird out // 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 // Do a state check
UpdateStateMachine(); UpdateStateMachine();
@ -438,7 +403,7 @@ namespace AM2RLauncher
progressBar.MaxValue = transferProgress.TotalObjects; progressBar.MaxValue = transferProgress.TotalObjects;
if (currentGitObject >= transferProgress.ReceivedObjects) if (currentGitObject >= transferProgress.ReceivedObjects)
return; 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; currentGitObject = transferProgress.ReceivedObjects;
progressBar.Value = transferProgress.ReceivedObjects; progressBar.Value = transferProgress.ReceivedObjects;
}); });
@ -461,7 +426,7 @@ namespace AM2RLauncher
return; return;
} }
// Check if xdelta is installed on linux // 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); MessageBox.Show(Language.Text.XdeltaNotFound, Language.Text.WarningWindowTitle, MessageBoxButtons.OK);
SetApkButtonState(ApkButtonState.Create); SetApkButtonState(ApkButtonState.Create);
@ -537,8 +502,6 @@ namespace AM2RLauncher
{ {
log.Info("User requested to add mod. Requesting user input for new mod .zip..."); log.Info("User requested to add mod. Requesting user input for new mod .zip...");
ProfileXML addedProfile;
OpenFileDialog fileFinder = new OpenFileDialog OpenFileDialog fileFinder = new OpenFileDialog
{ {
Directory = new Uri(CrossPlatformOperations.CURRENTPATH), Directory = new Uri(CrossPlatformOperations.CURRENTPATH),
@ -554,84 +517,81 @@ namespace AM2RLauncher
return; return;
} }
if (!String.IsNullOrWhiteSpace(fileFinder.FileName)) // This is default if (String.IsNullOrWhiteSpace(fileFinder.FileName))
{ {
log.Info("User selected \"" + fileFinder.FileName + "\""); log.Error("User did not supply valid input. Cancelling import.");
LoadProfilesAndAdjustLists();
// If either a directory was selected or the file somehow went missing, cancel return;
if (!File.Exists(fileFinder.FileName)) }
{
log.Error("Selected mod .zip file not found! Cancelling import.");
return;
}
FileInfo modFile = new FileInfo(fileFinder.FileName); log.Info("User selected \"" + fileFinder.FileName + "\"");
string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName; // If either a directory was selected or the file somehow went missing, cancel
string extractedName = modFile.Name.Replace(".zip", ""); 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 string modsDir = new DirectoryInfo(CrossPlatformOperations.CURRENTPATH + "/Mods").FullName;
if (Directory.Exists(modsDir + "/" + extractedName)) string extractedName = modFile.Name.Replace(".zip", "");
{
ProfileXML profile2 = Serializer.Deserialize<ProfileXML>(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); // Extract it and see if it contains a profile.xml. If not, this is invalid
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); // Check first, if the directory is already there, if yes, throw a message
Directory.Delete(modsDir + "/" + extractedName, true); if (Directory.Exists(modsDir + "/" + extractedName))
File.Delete(CrossPlatformOperations.CURRENTPATH + "/Mods/" + modFile.Name); {
return; ProfileXML profile2 = Serializer.Deserialize<ProfileXML>(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml"));
} log.Error("Mod is already imported as " + extractedName + "! Cancelling mod import.");
ProfileXML profile = Serializer.Deserialize<ProfileXML>(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 // Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup
if (OS.Name != profile.OperatingSystem) if (!File.Exists(modsDir + "/" + extractedName + "/profile.xml"))
{ {
log.Error("Mod is for " + profile.OperatingSystem + " while current OS is " + OS.Name + ". Cancelling mod import."); 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), MessageBox.Show(Language.Text.ModIsInvalidMessage.Replace("$NAME", extractedName), Language.Text.ErrorWindowTitle, MessageBoxType.Error);
Language.Text.ErrorWindowTitle, MessageBoxType.Error); Directory.Delete(modsDir + "/" + extractedName, true);
HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); File.Delete(CrossPlatformOperations.CURRENTPATH + "/Mods/" + modFile.Name);
return; return;
} }
// Check by *name*, if the mod was installed already ProfileXML profile = Serializer.Deserialize<ProfileXML>(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml"));
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;
}
addedProfile = profile; // Check if the OS versions match
log.Info(profile.Name + " successfully installed."); if (OS.Name != profile.OperatingSystem)
MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); {
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."); log.Error(profile.Name + " is already installed.");
LoadProfiles(); MessageBox.Show(Language.Text.ModIsAlreadyInstalledMessage.Replace("$NAME", profile.Name), Language.Text.WarningWindowTitle, MessageBoxType.Warning);
HelperMethods.DeleteDirectory(modsDir + "/" + extractedName);
return; return;
} }
LoadProfiles(); log.Info(profile.Name + " successfully installed.");
settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == addedProfile.Name); 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) if (settingsProfileDropDown.SelectedIndex == -1)
settingsProfileDropDown.SelectedIndex = 0; settingsProfileDropDown.SelectedIndex = 0;
} }
@ -653,11 +613,10 @@ namespace AM2RLauncher
/// </summary> /// </summary>
private void SaveButtonClickEvent(object sender, EventArgs e) private void SaveButtonClickEvent(object sender, EventArgs e)
{ {
if (IsProfileIndexValid()) if (!IsProfileIndexValid())
{ return;
log.Info("User opened the save directory for profile " + profileList[settingsProfileDropDown.SelectedIndex].Name + ", which is " + profileList[settingsProfileDropDown.SelectedIndex].SaveLocation); 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); CrossPlatformOperations.OpenFolder(profileList[settingsProfileDropDown.SelectedIndex].SaveLocation);
}
} }
/// <summary> /// <summary>
@ -680,7 +639,8 @@ namespace AM2RLauncher
{ {
deleteModButton.Enabled = true; deleteModButton.Enabled = true;
deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); 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); 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; if (profileDropDown.SelectedIndex == -1 && profileDropDown.Items.Count == 0) return;
profileIndex = profileDropDown.SelectedIndex; 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; profileAuthorLabel.Text = Language.Text.Author + " " + profileList[profileDropDown.SelectedIndex].Author;
profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version;
CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString());
if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" || if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" ||
profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) profileList[profileDropDown.SelectedIndex].SaveLocation == "default"))
saveWarningLabel.Visible = true; saveWarningLabel.Visible = true;
else else
saveWarningLabel.Visible = false; saveWarningLabel.Visible = false;
UpdateStateMachine(); UpdateStateMachine();
} }
/// <summary>Gets called when user selects a different item from <see cref="languageDropDown"/> and writes that to the config.</summary> /// <summary>Gets called when user selects a different item from <see cref="languageDropDown"/> and writes that to the config.</summary>
@ -940,7 +898,7 @@ namespace AM2RLauncher
if (result == DialogResult.Ok) if (result == DialogResult.Ok)
{ {
log.Info("User did not cancel. Proceeding to delete " + profile); log.Info("User did not cancel. Proceeding to delete " + profile);
DeleteProfile(profile); DeleteProfileAndAdjustLists(profile);
log.Info(profile + " has been deleted"); log.Info(profile + " has been deleted");
MessageBox.Show(Language.Text.DeleteModButtonSuccess.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle); MessageBox.Show(Language.Text.DeleteModButtonSuccess.Replace("$NAME", profile.Name), Language.Text.SuccessWindowTitle);
} }
@ -977,88 +935,107 @@ namespace AM2RLauncher
return; 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 log.Info("User selected \"" + fileFinder.FileName + "\"");
if (!File.Exists(fileFinder.FileName))
{
log.Error("Selected mod .zip file not found! Cancelling mod update.");
return;
}
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; FileInfo modFile = new FileInfo(fileFinder.FileName);
string extractedName = modFile.Name.Replace(".zip", "_new");
// 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! // Extract it and see if it contains a profile.xml. If not, this is invalid
ZipFile.ExtractToDirectory(fileFinder.FileName, modsDir + "/" + extractedName);
// Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup // If for some reason old files remain, delete them
if (!File.Exists(modsDir + "/" + extractedName + "/profile.xml")) if (Directory.Exists(extractedFolder))
{ Directory.Delete(extractedFolder, true);
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;
}
// Check by *name*, if the mod was installed already // Directory doesn't exist -> extract!
ProfileXML profile = Serializer.Deserialize<ProfileXML>(File.ReadAllText(modsDir + "/" + extractedName + "/profile.xml")); ZipFile.ExtractToDirectory(fileFinder.FileName, extractedFolder);
if (profileList.FirstOrDefault(p => p.Name == profile.Name) != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) // Let's check if profile.xml exists in there! If it doesn't throw an error and cleanup
{ if (!File.Exists(extractedFolder + "/profile.xml"))
// Mod is already installed, so we can update! {
DialogResult result = MessageBox.Show(Language.Text.UpdateModWarning.Replace("$NAME", currentProfile.Name), Language.Text.WarningWindowTitle, log.Error(fileFinder.FileName + " does not contain profile.xml! Cancelling mod update.");
MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); 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) // Check by *name*, if the mod was installed already
{ ProfileXML profile = Serializer.Deserialize<ProfileXML>(File.ReadAllText(extractedFolder + "/profile.xml"));
// Delete profile
DeleteProfile(currentProfile);
// Rename directory to take the old one's place if (profileList.FirstOrDefault(p => p.Name == profile.Name) != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name))
string originalFolder = modsDir + "/" + extractedName.Replace("_new", ""); {
Directory.Move(modsDir + "/" + extractedName, originalFolder); // 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);
} if (updateResult == DialogResult.Ok)
else // Cancel the operation! {
// If the profile isn't installed, don't ask about archiving it
if (Profile.IsProfileInstalled(currentProfile))
{ {
log.Error("User has cancelled mod update!"); //TODO: localize
abort = true; 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! log.Error("User has cancelled mod update!");
// 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; 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) if (abort)
{ {
// File cleanup // File cleanup
HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); HelperMethods.DeleteDirectory(extractedFolder);
LoadProfiles(); LoadProfilesAndAdjustLists();
return; return;
}
log.Info("Successfully updated mod profile " + profile.Name + ".");
MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", currentProfile.Name), Language.Text.SuccessWindowTitle);
UpdateStateMachine();
} }
ProfileXML currentSelectedProfile = profileList[settingsProfileDropDown.SelectedIndex]; log.Info("Successfully updated mod profile " + profile.Name + ".");
LoadProfiles(); MessageBox.Show(Language.Text.ModSuccessfullyInstalledMessage.Replace("$NAME", currentProfile.Name), Language.Text.SuccessWindowTitle);
settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentSelectedProfile.Name); UpdateStateMachine();
LoadProfilesAndAdjustLists();
settingsProfileDropDown.SelectedIndex = profileList.FindIndex(p => p.Name == currentProfile.Name);
if (settingsProfileDropDown.SelectedIndex == -1) if (settingsProfileDropDown.SelectedIndex == -1)
settingsProfileDropDown.SelectedIndex = 0; settingsProfileDropDown.SelectedIndex = 0;
} }
@ -1075,6 +1052,7 @@ namespace AM2RLauncher
CrossPlatformOperations.WriteToConfig("Width", ClientSize.Width); CrossPlatformOperations.WriteToConfig("Width", ClientSize.Width);
CrossPlatformOperations.WriteToConfig("Height", ClientSize.Height); CrossPlatformOperations.WriteToConfig("Height", ClientSize.Height);
CrossPlatformOperations.WriteToConfig("IsMaximized", this.WindowState == WindowState.Maximized); CrossPlatformOperations.WriteToConfig("IsMaximized", this.WindowState == WindowState.Maximized);
CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex.ToString());
switch (updateState) switch (updateState)
{ {

@ -1,6 +1,5 @@
using Eto.Drawing; using Eto.Drawing;
using System; using System;
using System.IO;
using AM2RLauncher.Core; using AM2RLauncher.Core;
using AM2RLauncher.Core.XML; using AM2RLauncher.Core.XML;
@ -52,7 +51,7 @@ namespace AM2RLauncher
else if (isProfileValid && profileList[profileIndex.Value].Installable == false) else if (isProfileValid && profileList[profileIndex.Value].Installable == false)
{ {
// We delete the profile, because we can't install it and it therefore holds no value! // 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. // Otherwise, we still need to install.
else else
@ -176,7 +175,7 @@ namespace AM2RLauncher
// Only enable these, when we're not on the community updates // Only enable these, when we're not on the community updates
if (settingsProfileDropDown.SelectedIndex > 0) 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); updateModButton.ToolTip = Language.Text.UpdateModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text);
deleteModButton.Enabled = enabled; deleteModButton.Enabled = enabled;
deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text); deleteModButton.ToolTip = Language.Text.DeleteModButtonToolTip.Replace("$NAME", settingsProfileDropDown.Items[settingsProfileDropDown.SelectedIndex].Text);
@ -269,91 +268,30 @@ namespace AM2RLauncher
} }
/// <summary> /// <summary>
/// Deletes the given <paramref name="profile"/>. Reloads the <see cref="profileList"/> if <paramref name="reloadProfileList"/> is true. /// Loads valid profile entries and reloads the necessary UI components.
/// </summary> /// </summary>
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 + ".");
}
/// <summary>
/// Scans the PatchData and Mods folders for valid profile entries, and loads them.
/// </summary>
//TODO: Seperate this (and by extension, deleteProfile) from UI and backend
private void LoadProfiles()
{
log.Info("Loading profiles...");
// Reset loaded profiles // Reset loaded profiles
profileDropDown.Items.Clear(); profileDropDown.Items.Clear();
profileList.Clear(); profileList.Clear();
profileIndex = null; profileIndex = null;
// Check for and add the Community Updates profile // Load the profileList
if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml")) profileList = Profile.LoadProfiles();
{
profileList.Add(Serializer.Deserialize<ProfileXML>(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<ProfileXML>(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);
}
}
}
// Add profile names to the profileDropDown // Add profile names to the profileDropDown
foreach (ProfileXML profile in profileList) foreach (ProfileXML profile in profileList)
{ {
// Archive version notes // Archive version notes
if (!profile.Installable) 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); profileDropDown.Items.Add(profile.Name);
} }
@ -383,8 +321,6 @@ namespace AM2RLauncher
settingsProfileDropDown.Items.AddRange(profileDropDown.Items); settingsProfileDropDown.Items.AddRange(profileDropDown.Items);
settingsProfileDropDown.SelectedIndex = profileDropDown.Items.Count != 0 ? 0 : -1; 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 // Refresh the author and version label on the main tab
if (profileList.Count > 0) if (profileList.Count > 0)
{ {
@ -392,7 +328,26 @@ namespace AM2RLauncher
profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version;
} }
log.Info("Reloading UI components after loading successful.");
UpdateStateMachine(); UpdateStateMachine();
} }
/// <summary>
/// Deletes a profile and reloads the necessary UI components.
/// </summary>
/// <param name="profile">The profile to delete.</param>
private void DeleteProfileAndAdjustLists(ProfileXML profile)
{
Profile.DeleteProfile(profile);
LoadProfilesAndAdjustLists();
}
private void ArchiveProfileAndAdjustLists(ProfileXML profile)
{
Profile.ArchiveProfile(profile);
LoadProfilesAndAdjustLists();
}
} }
} }

@ -10,7 +10,6 @@ using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
namespace AM2RLauncher namespace AM2RLauncher

@ -7,6 +7,8 @@ namespace AM2RLauncher.Core;
/// <summary> /// <summary>
/// Class that has core stuff that doesn't fit anywhere else /// Class that has core stuff that doesn't fit anywhere else
/// </summary> /// </summary>
//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 public static class Core
{ {
/// <summary> /// <summary>

@ -2,6 +2,7 @@
using LibGit2Sharp; using LibGit2Sharp;
using log4net; using log4net;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.IO.Compression; using System.IO.Compression;
@ -47,10 +48,12 @@ public static class Profile
/// <summary> /// <summary>
/// Checks if AM2R 1.1 has been installed already, aka if a valid AM2R 1.1 Zip exists. /// Checks if AM2R 1.1 has been installed already, aka if a valid AM2R 1.1 Zip exists.
/// </summary> /// </summary>
/// <returns><see langword="true"/> if yes, <see langword="false"/> if not.</returns> /// <param name="invalidateCache">Determines if the AM2R_11 Cache should be invalidated</param>
public static bool Is11Installed() /// <returns></returns>
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 we have a cache, return that instead
if (isAM2R11InstalledCache != null) return isAM2R11InstalledCache.Value; if (isAM2R11InstalledCache != null) return isAM2R11InstalledCache.Value;
@ -73,9 +76,9 @@ public static class Profile
} }
/// <summary> /// <summary>
/// Invalidates <see cref="isAM2R11InstalledCache"/>. /// Invalidates <see cref="isAM2R11InstalledCache"/> if necessary.
/// </summary> /// </summary>
private static void InvalidateAM2R11InstallCache() private static void InvalidateAM2R11InstallCacheIfNecessary()
{ {
// If the file exists, and its hash matches with ours, don't invalidate // If the file exists, and its hash matches with ours, don't invalidate
if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") && if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/AM2R_11.zip") &&
@ -123,6 +126,141 @@ public static class Profile
log.Info("Repository pulled successfully."); log.Info("Repository pulled successfully.");
} }
/// <summary>
/// Scans the PatchData and Mods folders for valid profile entries, creates and returns a list of them.
/// </summary>
/// <returns>A <see cref="List{ProfileXML}"/> containing all valid profile entries.</returns>
public static List<ProfileXML> LoadProfiles()
{
log.Info("Loading profiles...");
List<ProfileXML> profileList = new List<ProfileXML>();
// Check for and add the Community Updates profile
if (File.Exists(CrossPlatformOperations.CURRENTPATH + "/PatchData/profile.xml"))
{
ProfileXML profile = Serializer.Deserialize<ProfileXML>(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<ProfileXML>(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;
}
/// <summary>
/// Archives a given Profile by making a copy with "Name (version)". Does silently nothing if user archives already exist
/// </summary>
/// <param name="profile">The profile to archive</param>
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<ProfileXML>(profile));
profile = Serializer.Deserialize<ProfileXML>(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<ProfileXML>(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.");
}
}
/// <summary>
/// Deletes a profile from the Mods and Profiles folder.
/// </summary>
/// <param name="profile">The profile to delete.</param>
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 + ".");
}
/// <summary> /// <summary>
/// Installs <paramref name="profile"/>. /// Installs <paramref name="profile"/>.
/// </summary> /// </summary>
@ -308,8 +446,9 @@ public static class Profile
foreach (var file in new DirectoryInfo(profilePath).GetFiles()) foreach (var file in new DirectoryInfo(profilePath).GetFiles())
if (file.Name.EndsWith(".ogg") && !File.Exists(file.DirectoryName + "/" + file.Name.ToLower())) if (file.Name.EndsWith(".ogg") && !File.Exists(file.DirectoryName + "/" + file.Name.ToLower()))
File.Move(file.FullName, file.DirectoryName + "/" + file.Name.ToLower()); File.Move(file.FullName, file.DirectoryName + "/" + file.Name.ToLower());
// Loading custom fonts crashes on Mac, so we delete those // Loading custom fonts crashes on Mac, so we delete those if they exist
Directory.Delete(profilePath + "/lang/fonts", true); if (Directory.Exists(profilePath + "/lang/fonts"))
Directory.Delete(profilePath + "/lang/fonts", true);
// Move Frameworks, Info.plist and PkgInfo over // Move Frameworks, Info.plist and PkgInfo over
HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/Frameworks", profilePath.Replace("Resources", "Frameworks")); HelperMethods.DirectoryCopy(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/Frameworks", profilePath.Replace("Resources", "Frameworks"));
File.Copy(dataPath + "/Info.plist", profilePath.Replace("Resources", "") + "/Info.plist", true); File.Copy(dataPath + "/Info.plist", profilePath.Replace("Resources", "") + "/Info.plist", true);
@ -491,7 +630,7 @@ public static class Profile
{ {
ProcessStartInfo startInfo = new ProcessStartInfo(); 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 //TODO: make this more readable at one day
if (!String.IsNullOrWhiteSpace(envVars)) if (!String.IsNullOrWhiteSpace(envVars))
@ -523,7 +662,7 @@ public static class Profile
string value = envVars.Substring(0, valueSubstringLength); string value = envVars.Substring(0, valueSubstringLength);
envVars = envVars.Substring(value.Length); envVars = envVars.Substring(value.Length);
log.Info("Adding variable \"" + variable + "\" with value \"" + value + "\""); log.Info("Adding user variable \"" + variable + "\" with value \"" + value + "\"");
startInfo.EnvironmentVariables[variable] = value; startInfo.EnvironmentVariables[variable] = value;
} }
} }
@ -537,10 +676,10 @@ public static class Profile
log.Info("CWD of Profile is " + startInfo.WorkingDirectory); 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) 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()) using (Process p = new Process())

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
namespace AM2RLauncher.Core; namespace AM2RLauncher.Core;
@ -18,10 +18,12 @@ public static class Splash
"Now with 100% more Blob Throwers!", "Now with 100% more Blob Throwers!",
"Speedrun THIS, I dare you.", "Speedrun THIS, I dare you.",
"The broken pipe is a lie.", "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.", "Overcommitting to April Fool's since 2018.",
"Also try Metroid II: Return of Samus!", "Also try Metroid II: Return of Samus!",
"Also try Metroid: Samus Returns!", "Also try Metroid: Samus Returns!",
"Also try Prime 2D!", "Also try Prime 2D!",
"Also try Skippy the Bot!",
"Trust me, it's an 'unintentional feature.'", "Trust me, it's an 'unintentional feature.'",
"Coming soon to a PC near you!", "Coming soon to a PC near you!",
"This ain't your parents' Metroid 2!", "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", "S P I D E R B A L L",
"Fun is infinite with Community-Developers Inc.", "Fun is infinite with Community-Developers Inc.",
"You may only proceed if you wear baggy pants.", "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."
}; };
/// <summary> /// <summary>
@ -127,4 +130,4 @@ public static class Splash
totalSplashes = generalSplash; totalSplashes = generalSplash;
return totalSplashes; return totalSplashes;
} }
} }

@ -39,7 +39,7 @@ On Arch Linux you can install them by running this:
### Fedora ### Fedora
On Fedora you can install them by running this command: 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 ### Other distros
For other distros refer to your local package manager for instructions. For other distros refer to your local package manager for instructions.

Loading…
Cancel
Save