introduce am2rlauncherdata env var, use xdg env vars, minor cleanup

- Config file on linux is not hardcoded to `~/.config/AM2RLauncher` anymore, and will now respect `$XDG_CONFIG_HOME`
- Data folder on linux is not hardcoded to `~/.local/share/AM2RLauncher` anymore. Instead it will now listen for `$AM2RLAUNCHERDATA` (on win too!) and respect `$XDG_DATA_HOME`

Profile Logging has been kept as is, until I figure out if AM2R on linux respects `$XDG_CONFIG_HOME`.
pull/30/head
Miepee 5 years ago
parent 6cf7cbf2d5
commit a14589baaf

@ -8,6 +8,7 @@ using System.IO;
using System.Text; using System.Text;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using log4net;
namespace AM2RLauncher namespace AM2RLauncher
{ {
@ -16,15 +17,20 @@ namespace AM2RLauncher
/// </summary> /// </summary>
class CrossPlatformOperations class CrossPlatformOperations
{ {
/// <summary>
/// The logger for <see cref="MainForm"/>, used to write any caught exceptions.
/// </summary>
private static readonly ILog log = LogManager.GetLogger(typeof(MainForm));
/// <summary> /// <summary>
/// Gets the current platform. /// Gets the current platform.
/// </summary> /// </summary>
readonly private static Platform currentPlatform = Platform.Instance; readonly private static Platform currentPlatform = Platform.Instance;
/// <summary> /// <summary>
/// Current Path where the Launcher is located. For Linux this is redirected to ~/.local/share/AM2RLauncher, in order to be more compliant to the XDG Base Directory Specification. /// Current Path where the Launcher is located. For more info, check <see cref="GenerateCurrentPath"/>.
/// </summary> /// </summary>
static readonly public string CURRENTPATH = currentPlatform.IsWinForms ? Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) : Environment.GetEnvironmentVariable("HOME") + "/.local/share/AM2RLauncher"; static readonly public string CURRENTPATH = GenerateCurrentPath();
/// <summary> /// <summary>
/// Name of the Launcher executable. /// Name of the Launcher executable.
@ -75,10 +81,11 @@ namespace AM2RLauncher
} }
if (currentPlatform.IsGtk) if (currentPlatform.IsGtk)
{ {
//config for nix systems will be saved in .config/AM2RLauncher //config for nix systems will be saved in XDG_CONFIG_HOME/AM2RLauncher (or if empty, ~/.config)
string homePath = Environment.GetEnvironmentVariable("HOME"); string homePath = Environment.GetEnvironmentVariable("HOME");
string launcherConfigPath = homePath + "/.config/AM2RLauncher/"; string xdgConfigHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
string launcherConfigFilePath = launcherConfigPath + "config.xml"; string launcherConfigPath = (String.IsNullOrWhiteSpace(xdgConfigHome) ? (homePath + "/.config") : xdgConfigHome) + "/AM2RLauncher";
string launcherConfigFilePath = launcherConfigPath + "/config.xml";
XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML(); XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML();
//if folder doesn't exist, create it and the config file //if folder doesn't exist, create it and the config file
@ -122,10 +129,11 @@ namespace AM2RLauncher
} }
else if (currentPlatform.IsGtk) else if (currentPlatform.IsGtk)
{ {
//config for nix systems will be saved in .config/AM2RLauncher //config for nix systems will be saved in XDG_CONFIG_HOME/AM2RLauncher (or if empty, ~/.config)
string homePath = Environment.GetEnvironmentVariable("HOME"); string homePath = Environment.GetEnvironmentVariable("HOME");
string launcherConfigPath = homePath + "/.config/AM2RLauncher/"; string xdgConfigHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
string launcherConfigFilePath = launcherConfigPath + "config.xml"; string launcherConfigPath = (String.IsNullOrWhiteSpace(xdgConfigHome) ? (homePath + "/.config") : xdgConfigHome) + "/AM2RLauncher";
string launcherConfigFilePath = launcherConfigPath + "/config.xml";
XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML(); XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML();
//if folder doesn't exist, create it and the config file //if folder doesn't exist, create it and the config file
@ -170,9 +178,11 @@ namespace AM2RLauncher
} }
else if(currentPlatform.IsGtk) else if(currentPlatform.IsGtk)
{ {
//config for nix systems will be saved in XDG_CONFIG_HOME/AM2RLauncher (or if empty, ~/.config)
string homePath = Environment.GetEnvironmentVariable("HOME"); string homePath = Environment.GetEnvironmentVariable("HOME");
string launcherConfigPath = homePath + "/.config/AM2RLauncher/"; string xdgConfigHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
string launcherConfigFilePath = launcherConfigPath + "config.xml"; string launcherConfigPath = (String.IsNullOrWhiteSpace(xdgConfigHome) ? (homePath + "/.config") : xdgConfigHome) + "/AM2RLauncher";
string launcherConfigFilePath = launcherConfigPath + "/config.xml";
XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML(); XML.LauncherConfigXML launcherConfig = new XML.LauncherConfigXML();
//for some reason deserializing and saving back again works, not exactly sure why, but I'll take it //for some reason deserializing and saving back again works, not exactly sure why, but I'll take it
@ -200,9 +210,14 @@ namespace AM2RLauncher
public static void OpenFolder(string path) public static void OpenFolder(string path)
{ {
// We have to replace forward slashes with backslashes here on windows because explorer.exe is picky... // We have to replace forward slashes with backslashes here on windows because explorer.exe is picky...
string realPath = currentPlatform.IsWinForms ? Environment.ExpandEnvironmentVariables(path).Replace("/", "\\") : path.Replace("~", Environment.GetEnvironmentVariable("HOME")); // And on Nix systems, we want to replace ~ with its corresponding env var
string realPath = currentPlatform.IsWinForms ? Environment.ExpandEnvironmentVariables(path).Replace("/", "\\")
: path.Replace("~", Environment.GetEnvironmentVariable("HOME"));
if (!Directory.Exists(realPath)) if (!Directory.Exists(realPath))
{
log.Info(realPath + " did not exist and was created");
Directory.CreateDirectory(realPath); Directory.CreateDirectory(realPath);
}
//needs quotes otherwise paths with space wont open //needs quotes otherwise paths with space wont open
if (currentPlatform.IsWinForms) if (currentPlatform.IsWinForms)
@ -215,14 +230,20 @@ namespace AM2RLauncher
/// <summary> /// <summary>
/// Opens <paramref name="path"/> and selects it in a file explorer. /// Opens <paramref name="path"/> and selects it in a file explorer.
/// Only selects on Windows, on Linux it just opens the folder. Does nothing if file doesn't exist.
/// </summary> /// </summary>
/// <param name="path">Path to open.</param> /// <param name="path">Path to open.</param>
public static void OpenFolderAndSelectFile(string path) public static void OpenFolderAndSelectFile(string path)
{ {
// We have to replace forward slashes with backslashes here on windows because explorer.exe is picky... // We have to replace forward slashes with backslashes here on windows because explorer.exe is picky...
string realPath = currentPlatform.IsWinForms ? Environment.ExpandEnvironmentVariables(path).Replace("/", "\\") : path.Replace("~", Environment.GetEnvironmentVariable("HOME")); // And on nix systems, we want to replace ~ with its corresponding env var
string realPath = currentPlatform.IsWinForms ? Environment.ExpandEnvironmentVariables(path).Replace("/", "\\")
: path.Replace("~", Environment.GetEnvironmentVariable("HOME"));
if (!File.Exists(realPath)) if (!File.Exists(realPath))
{
log.Error(realPath + "did not exist, operation to open its folder was cancelled!");
return; return;
}
//needs quotes otherwise paths with spaces wont open //needs quotes otherwise paths with spaces wont open
if (currentPlatform.IsWinForms) if (currentPlatform.IsWinForms)
@ -326,7 +347,8 @@ namespace AM2RLauncher
if (original == output) if (original == output)
output = output += "_"; output = output += "_";
string arguments = "-f -d -s \"" + original.Replace(CURRENTPATH + "/","") + "\" \"" + patch.Replace(CURRENTPATH + "/", "") + "\" \"" + output.Replace(CURRENTPATH + "/", "") + "\""; string arguments = "-f -d -s \"" + original.Replace(CURRENTPATH + "/","") + "\" \"" + patch.Replace(CURRENTPATH + "/", "")
+ "\" \"" + output.Replace(CURRENTPATH + "/", "") + "\"";
if (currentPlatform.IsWinForms) if (currentPlatform.IsWinForms)
{ {
@ -368,5 +390,77 @@ namespace AM2RLauncher
File.Move(output, originalOutput); File.Move(output, originalOutput);
} }
} }
/// <summary>
/// Figures out what the AM2RLauncher's <see cref="CURRENTPATH"/> should be.<br/>
/// Determination is as follows:
/// <list type="number">
/// <item><b>AM2RLAUNCHERDATA</b> environment variable is read and folders are recursively generated.</item>
/// <item>The current OS is checked. For Windows, the path where the executable is located will be returned.<br/>
/// For Linux, <b>$XDG_DATA_HOME/AM2RLauncher</b> will be returned.
/// Should <b>$XDG_DATA_HOME</b> be empty, it will default to <b>$HOME/.local/share</b>.</item>
/// <item>The path where the executable is located will be returned.</item>
/// </list>
/// Should any errors occur, it falls down to the next step.
/// </summary>
/// <returns></returns>
private static string GenerateCurrentPath()
{
// First, we check if the user has a custom AM2RLAUNCHERDATA env var
string am2rLauncherDataEnvVar = Environment.GetEnvironmentVariable("AM2RLAUNCHERDATA");
if (!String.IsNullOrWhiteSpace(am2rLauncherDataEnvVar))
{
try
{
// This will create the directories recursively if they don't exist
Directory.CreateDirectory(am2rLauncherDataEnvVar);
// Our env var is now set and directories exist
log.Info("CurrentPath is set to " + am2rLauncherDataEnvVar);
return am2rLauncherDataEnvVar;
}
catch (Exception ex)
{
log.Error($"There was an error with '{am2rLauncherDataEnvVar}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults.");
}
}
if (currentPlatform.IsWinForms)
{
log.Info("Using default Windows CurrentPath.");
// Windows has the path where the exe is located as default
return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
}
else if (currentPlatform.IsGtk)
{
// First check if XDG_DATA_HOME is set, if not we'll use ~/.local/share
string xdgDataHome = Environment.GetEnvironmentVariable("XDG_DATA_HOME");
if (string.IsNullOrWhiteSpace(xdgDataHome))
{
log.Info("Using default Linux CurrentPath.");
xdgDataHome = Environment.GetEnvironmentVariable("HOME") + "/.local/share";
}
// Add AM2RLauncher to the end of the dataPath
xdgDataHome += "/AM2RLauncher";
try
{
// This will create the directories recursively if they don't exist
Directory.CreateDirectory(xdgDataHome);
// Our env var is now set and directories exist
log.Info("CurrentPath is set to " + xdgDataHome);
return xdgDataHome;
}
catch (Exception ex)
{
log.Error($"There was an error with '{xdgDataHome}'!\n{ex.Message} {ex.StackTrace}. Falling back to defaults.");
}
}
log.Info("Something went wrong, falling back to the default CurrentPath.");
return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
}
} }
} }

@ -180,7 +180,6 @@ namespace AM2RLauncher
// for windows, the actual application is in "AM2RLauncher.dll". Which means, we need to update the lib folder as well. // for windows, the actual application is in "AM2RLauncher.dll". Which means, we need to update the lib folder as well.
if (currentPlatform.IsWinForms && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib")) if (currentPlatform.IsWinForms && Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/lib"))
{ {
// Directory.Move(CrossPlatformOperations.CURRENTPATH + "/lib", CrossPlatformOperations.CURRENTPATH + "/oldLib");
// So, because Windows behavior is dumb... // So, because Windows behavior is dumb...
// Rename all files in lib to *.bak // Rename all files in lib to *.bak

@ -577,12 +577,13 @@ namespace AM2RLauncher
{ {
string currentOS = ""; string currentOS = "";
if (Platform.IsWinForms) currentOS = "Windows"; if (Platform.IsWinForms) currentOS = "Windows";
else if (Platform.IsGtk) currentOS = "Linux"; ///teeeeechnically, windows users and macos users could run GTK applications as well, so this would prolly need clarification. else if (Platform.IsGtk) currentOS = "Linux"; ///teeeeechnically, any OS could run GTK applications as well but it'd break a lot and is thus unsupported.
log.Error("Mod is for " + profile.OperatingSystem + " while current OS is " + Platform + ". Cancelling mod import."); log.Error("Mod is for " + profile.OperatingSystem + " while current OS is " + Platform + ". Cancelling mod import.");
MessageBox.Show(Language.Text.ModIsForWrongOS.Replace("$NAME",profile.Name).Replace("$OS",profile.OperatingSystem).Replace("$CURRENTOS",currentOS), Language.Text.ErrorWindowTitle, MessageBoxType.Error); MessageBox.Show(Language.Text.ModIsForWrongOS.Replace("$NAME",profile.Name).Replace("$OS",profile.OperatingSystem).Replace("$CURRENTOS",currentOS),
Language.Text.ErrorWindowTitle, MessageBoxType.Error);
HelperMethods.DeleteDirectory(modsDir + "/" + extractedName); HelperMethods.DeleteDirectory(modsDir + "/" + extractedName);
return; return;
} }
@ -621,7 +622,8 @@ namespace AM2RLauncher
{ {
if (IsProfileIndexValid()) if (IsProfileIndexValid())
{ {
log.Info("User opened the profile directory for profile " + profileList[settingsProfileDropDown.SelectedIndex].Name + ", which is " + profileList[settingsProfileDropDown.SelectedIndex].SaveLocation); log.Info("User opened the profile directory for profile " + profileList[settingsProfileDropDown.SelectedIndex].Name +
", which is " + profileList[settingsProfileDropDown.SelectedIndex].SaveLocation);
CrossPlatformOperations.OpenFolder(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileList[settingsProfileDropDown.SelectedIndex].Name); CrossPlatformOperations.OpenFolder(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profileList[settingsProfileDropDown.SelectedIndex].Name);
} }
} }
@ -758,7 +760,8 @@ namespace AM2RLauncher
profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version; profileVersionLabel.Text = Language.Text.VersionLabel + " " + profileList[profileDropDown.SelectedIndex].Version;
CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex + ""); //Loj, tell me a better way to do this CrossPlatformOperations.WriteToConfig("ProfileIndex", profileIndex + ""); //Loj, tell me a better way to do this
if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" || profileList[profileDropDown.SelectedIndex].SaveLocation == "default")) if (profileDropDown.SelectedIndex != 0 && (profileList[profileDropDown.SelectedIndex].SaveLocation == "%localappdata%/AM2R" ||
profileList[profileDropDown.SelectedIndex].SaveLocation == "default"))
saveWarningLabel.Visible = true; saveWarningLabel.Visible = true;
else else
saveWarningLabel.Visible = false; saveWarningLabel.Visible = false;
@ -798,8 +801,9 @@ namespace AM2RLauncher
bool enabled = (bool)customMirrorCheck.Checked; bool enabled = (bool)customMirrorCheck.Checked;
customMirrorTextBox.Enabled = enabled; customMirrorTextBox.Enabled = enabled;
mirrorDropDown.Enabled = !enabled; mirrorDropDown.Enabled = !enabled;
// Not sure why the dropdown menu needs this hack, but the textBox does not.
if (Platform.IsWinForms) if (Platform.IsWinForms)
mirrorDropDown.TextColor = mirrorDropDown.Enabled ? colGreen : colInactive; // Not sure why the dropdown menu needs this hack, but the textBox does not. mirrorDropDown.TextColor = mirrorDropDown.Enabled ? colGreen : colInactive;
mirrorLabel.TextColor = !enabled ? colGreen : colInactive; mirrorLabel.TextColor = !enabled ? colGreen : colInactive;
// Create warning dialog when enabling // Create warning dialog when enabling
@ -901,7 +905,8 @@ namespace AM2RLauncher
ProfileXML profile = profileList[settingsProfileDropDown.SelectedIndex]; ProfileXML profile = profileList[settingsProfileDropDown.SelectedIndex];
log.Info("User is attempting to delete profile " + profile.Name + "."); log.Info("User is attempting to delete profile " + profile.Name + ".");
DialogResult result = MessageBox.Show(Language.Text.DeleteModWarning.Replace("$NAME", profile.Name), Language.Text.WarningWindowTitle, MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); DialogResult result = MessageBox.Show(Language.Text.DeleteModWarning.Replace("$NAME", profile.Name), Language.Text.WarningWindowTitle,
MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel);
if (result == DialogResult.Ok) if (result == DialogResult.Ok)
{ {
@ -980,7 +985,8 @@ namespace AM2RLauncher
if (profileList.Where(p => p.Name == profile.Name).FirstOrDefault() != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name)) if (profileList.Where(p => p.Name == profile.Name).FirstOrDefault() != null || Directory.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name))
{ {
// Mod is already installed, so we can update! // Mod is already installed, so we can update!
DialogResult result = MessageBox.Show(Language.Text.UpdateModWarning.Replace("$NAME", currentProfile.Name), Language.Text.WarningWindowTitle, MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel); DialogResult result = MessageBox.Show(Language.Text.UpdateModWarning.Replace("$NAME", currentProfile.Name), Language.Text.WarningWindowTitle,
MessageBoxButtons.OKCancel, MessageBoxType.Warning, MessageBoxDefaultButton.Cancel);
if (result == DialogResult.Ok) if (result == DialogResult.Ok)
{ {
@ -1003,7 +1009,8 @@ namespace AM2RLauncher
// Cancel the operation! // Cancel the operation!
// Show message to tell user that mod could not be found, install this separately // Show message to tell user that mod could not be found, install this separately
log.Error("Mod is not installed! Cancelling mod update."); 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); MessageBox.Show(Language.Text.UpdateModButtonWrongMod.Replace("$NAME", currentProfile.Name).Replace("$SELECT", profile.Name),
Language.Text.WarningWindowTitle, MessageBoxButtons.OK);
abort = true; abort = true;
} }
@ -1042,7 +1049,8 @@ namespace AM2RLauncher
if (updateState == UpdateState.Downloading) if (updateState == UpdateState.Downloading)
{ {
var result = MessageBox.Show(Language.Text.CloseOnCloningText, Language.Text.WarningWindowTitle, MessageBoxButtons.YesNo, MessageBoxType.Warning, MessageBoxDefaultButton.No); var result = MessageBox.Show(Language.Text.CloseOnCloningText, Language.Text.WarningWindowTitle, MessageBoxButtons.YesNo,
MessageBoxType.Warning, MessageBoxDefaultButton.No);
if (result == DialogResult.No) if (result == DialogResult.No)
{ {
e.Cancel = true; e.Cancel = true;

@ -58,7 +58,7 @@ namespace AM2RLauncher
private bool IsProfileInstalled(ProfileXML profile) private bool IsProfileInstalled(ProfileXML profile)
{ {
if (Platform.IsWinForms) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.exe"); if (Platform.IsWinForms) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.exe");
if (Platform.IsGtk) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.AppImage"); //should we check for .AppRun as well? if (Platform.IsGtk) return File.Exists(CrossPlatformOperations.CURRENTPATH + "/Profiles/" + profile.Name + "/AM2R.AppImage");
return false; return false;
} }
@ -315,7 +315,7 @@ namespace AM2RLauncher
// use the exe name based on the desktop file in the appimage, rather than hardcoding it. // use the exe name based on the desktop file in the appimage, rather than hardcoding it.
string desktopContents = File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir/AM2R.desktop"); string desktopContents = File.ReadAllText(CrossPlatformOperations.CURRENTPATH + "/PatchData/data/AM2R.AppDir/AM2R.desktop");
exe = Regex.Match(desktopContents, @"(?<=Exec=).*").Value; exe = Regex.Match(desktopContents, @"(?<=Exec=).*").Value;
log.Info("According to AppImage desktop file, use \"" + exe + "\" as game name."); log.Info("According to AppImage desktop file, using \"" + exe + "\" as game name.");
} }
log.Info("Attempting to patch in " + profilePath); log.Info("Attempting to patch in " + profilePath);
@ -644,7 +644,8 @@ namespace AM2RLauncher
ProfileXML profile = profileList[profileIndex.Value]; ProfileXML profile = profileList[profileIndex.Value];
// These are used on both windows and linux for game logging // These are used on both windows and linux for game logging
string savePath = Platform.IsWinForms ? profile.SaveLocation.Replace("%localappdata%", Environment.GetEnvironmentVariable("LOCALAPPDATA")) : profile.SaveLocation.Replace("~", Environment.GetEnvironmentVariable("HOME")); string savePath = Platform.IsWinForms ? profile.SaveLocation.Replace("%localappdata%", Environment.GetEnvironmentVariable("LOCALAPPDATA"))
: profile.SaveLocation.Replace("~", Environment.GetEnvironmentVariable("HOME"));
DirectoryInfo logDir = new DirectoryInfo(savePath + "/logs"); DirectoryInfo logDir = new DirectoryInfo(savePath + "/logs");
string date = string.Join("-", DateTime.Now.ToString().Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries)); string date = string.Join("-", DateTime.Now.ToString().Split(Path.GetInvalidFileNameChars(), StringSplitOptions.RemoveEmptyEntries));

@ -16,12 +16,15 @@ Linux needs the following dependencies installed:
- `openssl` - `openssl`
- `fuse2` - `fuse2`
As well as these dependencies to run AM2R:
- libopenal1:i386
- libpulse0:i386
Optionally, for APK creation any Java runtime is needed. Optionally, for APK creation any Java runtime is needed.
### Arch Linux ### Arch Linux
On Arch Linux, you can install these by running this: On Arch Linux, you can install these by running this:
(Multilib repositories are required, instructions on how to enable them can be found [here](https://wiki.archlinux.org/title/Official_repositories#Enabling_multilib)) (Multilib repositories are required, instructions on how to enable them can be found [here](https://wiki.archlinux.org/title/Official_repositories#Enabling_multilib))
`sudo pacman -S --needed dotnet-runtime fuse2 gtk3 libappindicator-gtk3 openssl webkit2gtk xdelta3 lib32-openal lib32-libpulse jre-openjdk` `sudo pacman -S --needed dotnet-runtime fuse2 gtk3 libappindicator-gtk3 openssl webkit2gtk xdelta3 lib32-openal lib32-libpulse jre-openjdk`
For other distros, refer to your local package manager for instructions. For other distros, refer to your local package manager for instructions.
@ -31,6 +34,12 @@ Downloads can be found at the [Release Page](https://github.com/AM2R-Community-D
Alternatively, for Arch Linux users an [AUR Package](https://aur.archlinux.org/packages/am2rlauncher/) also exist. Install it with `makepkg -si` or use your favourite AUR helper. Alternatively, for Arch Linux users an [AUR Package](https://aur.archlinux.org/packages/am2rlauncher/) also exist. Install it with `makepkg -si` or use your favourite AUR helper.
## Configuration and Data Files
The AM2RLauncher stores its files in the following places:
- On Windows, it stores the config file to the `AM2RLauncher.exe.config` next to the binary, and its data files in the same folder as the binary.
- On Linux, it stores the config file to `$XDG_CONFIG_HOME/AM2RLauncher` and its data files to `$XDG_DATA_HOME/AM2RLauncher` (which are defaulting back to `~/.config` and `~/.local/share` respectively).
The AM2RLauncher data can get quite big, so if you wish to change where it stores it, you can do so with the `AM2RLAUNCHERDATA` environment variable (i.e `AM2RLAUNCHERDATA="D:\MyLauncherData"` or `AM2RLAUNCHERDATA="/mnt/bigDrive/launcherData"`).
# Compiling Instructions: # Compiling Instructions:
## Dependencies ## Dependencies
For compiling for Windows .Net Framework 4.8 SDK is needed. For Linux .Net Core 5.0 SDK is needed. For compiling for Windows .Net Framework 4.8 SDK is needed. For Linux .Net Core 5.0 SDK is needed.

Loading…
Cancel
Save