399 lines
14 KiB
C#
399 lines
14 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using Microsoft.Win32;
|
|
using Mono.Unix;
|
|
|
|
namespace Saradomin.Utilities
|
|
{
|
|
public static class CrossPlatform
|
|
{
|
|
public static void LaunchURL(string url)
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
url = url.Replace("&", "^&");
|
|
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
{
|
|
Process.Start("xdg-open", url);
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
{
|
|
Process.Start("open", url);
|
|
}
|
|
}
|
|
|
|
public static void OpenFolder(string path)
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
{
|
|
Process.Start("xdg-open", path);
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
{
|
|
Process.Start("open", path);
|
|
}
|
|
}
|
|
|
|
public static bool IsJavaExecutableValid(string location)
|
|
{
|
|
try
|
|
{
|
|
if (!File.Exists(location))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using (var fileStream = File.OpenRead(location))
|
|
{
|
|
var bytes = new byte[4];
|
|
fileStream.Read(bytes, 0, 4);
|
|
|
|
if (bytes[0] == 0x7F
|
|
&& bytes[1] == 0x45
|
|
&& bytes[2] == 0x4C
|
|
&& bytes[3] == 0x46)
|
|
{
|
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
|
}
|
|
|
|
if (bytes[0] == 'M'
|
|
&& bytes[1] == 'Z')
|
|
{
|
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
|
}
|
|
|
|
if ((bytes[0] == 0xCF
|
|
&& bytes[1] == 0xFA)
|
|
|| (bytes[0] == 0xCA
|
|
&& bytes[1] == 0xFE))
|
|
{
|
|
return RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
|
|
}
|
|
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Ignore
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public static string LocateJavaExecutable()
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
var envPath = Environment.GetEnvironmentVariable("JAVA_HOME");
|
|
|
|
if (!string.IsNullOrEmpty(envPath))
|
|
return Path.Combine(envPath, "bin/java.exe");
|
|
|
|
using (var rk = Registry.LocalMachine.OpenSubKey("SOFTWARE\\JavaSoft\\Java Runtime Environment\\"))
|
|
{
|
|
if (rk == null)
|
|
return null;
|
|
|
|
var currentVersion = rk.GetValue("CurrentVersion")?.ToString();
|
|
|
|
if (currentVersion == null)
|
|
return null;
|
|
|
|
using (var key = rk.OpenSubKey(currentVersion))
|
|
{
|
|
if (key == null)
|
|
return null;
|
|
|
|
envPath = key.GetValue("JavaHome")?.ToString();
|
|
}
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(envPath))
|
|
return Path.Combine(envPath, "bin/java.exe");
|
|
|
|
throw new FileNotFoundException("Failed to find Java. Make sure it's installed!");
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
|
|| RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
|
|
{
|
|
var proc = new Process
|
|
{
|
|
StartInfo = new("/bin/which")
|
|
{
|
|
Arguments = "java",
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false
|
|
}
|
|
};
|
|
|
|
proc.Start();
|
|
proc.WaitForExit();
|
|
var data = proc.StandardOutput.ReadToEnd();
|
|
|
|
if (!string.IsNullOrEmpty(data))
|
|
return UnixPath.GetCompleteRealPath(data.Trim());
|
|
|
|
throw new FileNotFoundException("Failed to find Java. Make sure it's installed!");
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
{
|
|
var proc = new Process
|
|
{
|
|
StartInfo = new("/usr/bin/which")
|
|
{
|
|
Arguments = "java",
|
|
RedirectStandardOutput = true,
|
|
UseShellExecute = false
|
|
}
|
|
};
|
|
|
|
proc.Start();
|
|
proc.WaitForExit();
|
|
var data = proc.StandardOutput.ReadToEnd();
|
|
|
|
if (!string.IsNullOrEmpty(data))
|
|
return Path.Combine(UnixPath.GetCompleteRealPath(data.Trim()));
|
|
|
|
throw new FileNotFoundException("Failed to find Java. Make sure it's installed!");
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("Your platform is not supported.");
|
|
}
|
|
}
|
|
|
|
public static string LocateUnixUserHome()
|
|
{
|
|
return Environment.GetEnvironmentVariable("XDG_DATA_HOME")
|
|
?? Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
|
".local",
|
|
"share"
|
|
);
|
|
}
|
|
|
|
public static string Get2009scapeHome()
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
|
|| RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
|
|
{
|
|
return Path.Combine(
|
|
LocateUnixUserHome(),
|
|
"EmoScape"
|
|
);
|
|
}
|
|
else
|
|
{
|
|
var userProfile = Path.Combine (
|
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
|
"EmoScape"
|
|
);
|
|
var appData = Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
"EmoScape"
|
|
);
|
|
return Directory.Exists(userProfile) ? userProfile : appData;
|
|
}
|
|
}
|
|
|
|
public static string GetSaradominHome()
|
|
{
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
|
|| RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD))
|
|
{
|
|
return Path.Combine(
|
|
// Get the XDG_DATA_HOME environment variable, or if it doesn't exist, use the default ~/.local/share
|
|
LocateUnixUserHome(),
|
|
"EmoScape",
|
|
"saradomin"
|
|
);
|
|
}
|
|
|
|
return Path.Combine(
|
|
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
|
"EmoScape",
|
|
"saradomin"
|
|
);
|
|
}
|
|
|
|
public static string GetSingleplayerBackupsHome()
|
|
{
|
|
return Path.Combine(Get2009scapeHome(), "singleplayer_backups");
|
|
}
|
|
|
|
public static string GetSingleplayerHome()
|
|
{
|
|
return Path.Combine(Get2009scapeHome(), "singleplayer");
|
|
}
|
|
|
|
public static string LocateSingleplayerExecutable()
|
|
{
|
|
return Path.Combine(GetSingleplayerHome(), RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "launch.bat" : "launch.sh");
|
|
}
|
|
|
|
public static string Get2009scapeExecutable()
|
|
{
|
|
return Path.Combine(Get2009scapeHome(), "2009scape.jar");
|
|
}
|
|
|
|
public static string GetServerProfilePath(string baseDirectory)
|
|
{
|
|
baseDirectory ??= Get2009scapeHome();
|
|
return Path.Combine(baseDirectory, "server_profiles.json");
|
|
}
|
|
|
|
public static string RunCommandAndGetOutput(string command, Action<string> onOutputReceived = null, Action<string> onErrorReceived = null)
|
|
{
|
|
Process process = new Process();
|
|
StringBuilder output = new StringBuilder();
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
process.StartInfo = new ProcessStartInfo("cmd.exe", "/c " + command)
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
};
|
|
}
|
|
else if (
|
|
RuntimeInformation.IsOSPlatform(OSPlatform.Linux)
|
|
|| RuntimeInformation.IsOSPlatform(OSPlatform.OSX)
|
|
)
|
|
{
|
|
process.StartInfo = new ProcessStartInfo("bash", "-c \"" + command + "\"")
|
|
{
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
};
|
|
}
|
|
|
|
process.OutputDataReceived += (_, e) =>
|
|
{
|
|
if (e.Data == null) return;
|
|
output.AppendLine(e.Data);
|
|
onOutputReceived?.Invoke(e.Data);
|
|
};
|
|
|
|
process.ErrorDataReceived += (_, e) =>
|
|
{
|
|
if (e.Data == null) return;
|
|
output.AppendLine(e.Data);
|
|
onErrorReceived?.Invoke(e.Data);
|
|
};
|
|
|
|
process.Start();
|
|
|
|
process.BeginOutputReadLine();
|
|
process.BeginErrorReadLine();
|
|
|
|
process.WaitForExit();
|
|
|
|
return output.ToString();
|
|
}
|
|
|
|
public static string GetJava11DownloadUrl()
|
|
{
|
|
string architecture = GetSystemArchitecture();
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
{
|
|
return "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20%2B8/OpenJDK11U-jre_x64_windows_hotspot_11.0.20_8.zip";
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
{
|
|
return architecture == "x64"
|
|
? "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20%2B8/OpenJDK11U-jre_x64_linux_hotspot_11.0.20_8.tar.gz"
|
|
: "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20%2B8/OpenJDK11U-jre_aarch64_linux_hotspot_11.0.20_8.tar.gz";
|
|
}
|
|
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
{
|
|
return architecture == "x64"
|
|
? "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20%2B8/OpenJDK11U-jre_x64_mac_hotspot_11.0.20_8.tar.gz"
|
|
: "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.20%2B8/OpenJDK11U-jre_aarch64_mac_hotspot_11.0.20_8.tar.gz";
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("Your platform is not supported.");
|
|
}
|
|
}
|
|
|
|
private static string GetSystemArchitecture()
|
|
{
|
|
if (RuntimeInformation.OSArchitecture == Architecture.X64)
|
|
{
|
|
return "x64";
|
|
}
|
|
else if (RuntimeInformation.OSArchitecture == Architecture.Arm64)
|
|
{
|
|
return "aarch64";
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException("Your architecture is not supported.");
|
|
}
|
|
}
|
|
public static bool IsDirectoryWritable(string directoryPath)
|
|
{
|
|
var testFilePath = Path.Combine(directoryPath, "test");
|
|
|
|
try
|
|
{
|
|
File.Create(testFilePath).Dispose();
|
|
File.Delete(testFilePath);
|
|
|
|
return true;
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static Process StartJavaProcess(string javaExecutable, string jarPath, string memoryAllocation, Action<string> outputHandler, Action onExit)
|
|
{
|
|
Process process = new Process();
|
|
process.StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = javaExecutable,
|
|
Arguments = $"-Xmx{memoryAllocation} -Xms{memoryAllocation} -jar \"{jarPath}\"",
|
|
UseShellExecute = false,
|
|
CreateNoWindow = true,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
WorkingDirectory = Path.Combine(CrossPlatform.GetSingleplayerHome(), "game")
|
|
};
|
|
|
|
process.OutputDataReceived += (_, args) =>
|
|
{
|
|
if (string.IsNullOrEmpty(args.Data)) return;
|
|
outputHandler?.Invoke(args.Data);
|
|
};
|
|
|
|
process.ErrorDataReceived += (_, args) =>
|
|
{
|
|
if (string.IsNullOrEmpty(args.Data)) return;
|
|
outputHandler?.Invoke(args.Data);
|
|
};
|
|
|
|
process.EnableRaisingEvents = true;
|
|
process.Exited += (_, _) => onExit?.Invoke();
|
|
|
|
process.Start();
|
|
|
|
process.BeginOutputReadLine();
|
|
process.BeginErrorReadLine();
|
|
return process;
|
|
}
|
|
}
|
|
} |