diff options
Diffstat (limited to 'src/SMAPI.Toolkit/Utilities')
-rw-r--r-- | src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs | 157 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Utilities/PathUtilities.cs | 20 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Utilities/Platform.cs | 18 |
3 files changed, 185 insertions, 10 deletions
diff --git a/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs new file mode 100644 index 00000000..6dce5da5 --- /dev/null +++ b/src/SMAPI.Toolkit/Utilities/EnvironmentUtility.cs @@ -0,0 +1,157 @@ +using System; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +#if SMAPI_FOR_WINDOWS +using System.Management; +#endif +using System.Runtime.InteropServices; + +namespace StardewModdingAPI.Toolkit.Utilities +{ + /// <summary>Provides methods for fetching environment information.</summary> + public static class EnvironmentUtility + { + /********* + ** Fields + *********/ + /// <summary>The cached platform.</summary> + private static Platform? CachedPlatform; + + /// <summary>Get the OS name from the system uname command.</summary> + /// <param name="buffer">The buffer to fill with the resulting string.</param> + [DllImport("libc")] + static extern int uname(IntPtr buffer); + + + /********* + ** Public methods + *********/ + /// <summary>Detect the current OS.</summary> + public static Platform DetectPlatform() + { + if (EnvironmentUtility.CachedPlatform == null) + EnvironmentUtility.CachedPlatform = EnvironmentUtility.DetectPlatformImpl(); + + return EnvironmentUtility.CachedPlatform.Value; + } + + + /// <summary>Get the human-readable OS name and version.</summary> + /// <param name="platform">The current platform.</param> + [SuppressMessage("ReSharper", "EmptyGeneralCatchClause", Justification = "Error suppressed deliberately to fallback to default behaviour.")] + public static string GetFriendlyPlatformName(Platform platform) + { +#if SMAPI_FOR_WINDOWS + try + { + return new ManagementObjectSearcher("SELECT Caption FROM Win32_OperatingSystem") + .Get() + .Cast<ManagementObject>() + .Select(entry => entry.GetPropertyValue("Caption").ToString()) + .FirstOrDefault(); + } + catch { } +#endif + return (platform == Platform.Mac ? "MacOS " : "") + Environment.OSVersion; + } + + /// <summary>Get the name of the Stardew Valley executable.</summary> + /// <param name="platform">The current platform.</param> + public static string GetExecutableName(Platform platform) + { + return platform == Platform.Windows + ? "Stardew Valley.exe" + : "StardewValley.exe"; + } + + /// <summary>Get whether the platform uses Mono.</summary> + /// <param name="platform">The current platform.</param> + public static bool IsMono(this Platform platform) + { + return platform == Platform.Linux || platform == Platform.Mac; + } + + + /********* + ** Private methods + *********/ + /// <summary>Detect the current OS.</summary> + private static Platform DetectPlatformImpl() + { + switch (Environment.OSVersion.Platform) + { + case PlatformID.MacOSX: + return Platform.Mac; + + case PlatformID.Unix when EnvironmentUtility.IsRunningAndroid(): + return Platform.Android; + + case PlatformID.Unix when EnvironmentUtility.IsRunningMac(): + return Platform.Mac; + + case PlatformID.Unix: + return Platform.Linux; + + default: + return Platform.Windows; + } + } + + /// <summary>Detect whether the code is running on Android.</summary> + /// <remarks> + /// This code is derived from https://stackoverflow.com/a/47521647/262123. It detects Android by calling the + /// <c>getprop</c> system command to check for an Android-specific property. + /// </remarks> + private static bool IsRunningAndroid() + { + using (Process process = new Process()) + { + process.StartInfo.FileName = "getprop"; + process.StartInfo.Arguments = "ro.build.user"; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.UseShellExecute = false; + process.StartInfo.CreateNoWindow = true; + try + { + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + return !string.IsNullOrEmpty(output); + } + catch + { + return false; + } + } + } + + /// <summary>Detect whether the code is running on Mac.</summary> + /// <remarks> + /// This code is derived from the Mono project (see System.Windows.Forms/System.Windows.Forms/XplatUI.cs). It detects Mac by calling the + /// <c>uname</c> system command and checking the response, which is always 'Darwin' for MacOS. + /// </remarks> + private static bool IsRunningMac() + { + IntPtr buffer = IntPtr.Zero; + try + { + buffer = Marshal.AllocHGlobal(8192); + if (EnvironmentUtility.uname(buffer) == 0) + { + string os = Marshal.PtrToStringAnsi(buffer); + return os == "Darwin"; + } + return false; + } + catch + { + return false; // default to Linux + } + finally + { + if (buffer != IntPtr.Zero) + Marshal.FreeHGlobal(buffer); + } + } + } +} diff --git a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs index 8a3c2b03..40a59d87 100644 --- a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs +++ b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs @@ -6,7 +6,7 @@ using System.Text.RegularExpressions; namespace StardewModdingAPI.Toolkit.Utilities { - /// <summary>Provides utilities for normalising file paths.</summary> + /// <summary>Provides utilities for normalizing file paths.</summary> public static class PathUtilities { /********* @@ -15,14 +15,14 @@ namespace StardewModdingAPI.Toolkit.Utilities /// <summary>The possible directory separator characters in a file path.</summary> private static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray(); - /// <summary>The preferred directory separator chaeacter in an asset key.</summary> + /// <summary>The preferred directory separator character in an asset key.</summary> private static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString(); /********* ** Public methods *********/ - /// <summary>Get the segments from a path (e.g. <c>/usr/bin/boop</c> => <c>usr</c>, <c>bin</c>, and <c>boop</c>).</summary> + /// <summary>Get the segments from a path (e.g. <c>/usr/bin/example</c> => <c>usr</c>, <c>bin</c>, and <c>example</c>).</summary> /// <param name="path">The path to split.</param> /// <param name="limit">The number of segments to match. Any additional segments will be merged into the last returned part.</param> public static string[] GetSegments(string path, int? limit = null) @@ -32,16 +32,16 @@ namespace StardewModdingAPI.Toolkit.Utilities : path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); } - /// <summary>Normalise path separators in a file path.</summary> - /// <param name="path">The file path to normalise.</param> + /// <summary>Normalize path separators in a file path.</summary> + /// <param name="path">The file path to normalize.</param> [Pure] - public static string NormalisePathSeparators(string path) + public static string NormalizePathSeparators(string path) { string[] parts = PathUtilities.GetSegments(path); - string normalised = string.Join(PathUtilities.PreferredPathSeparator, parts); + string normalized = string.Join(PathUtilities.PreferredPathSeparator, parts); if (path.StartsWith(PathUtilities.PreferredPathSeparator)) - normalised = PathUtilities.PreferredPathSeparator + normalised; // keep root slash - return normalised; + normalized = PathUtilities.PreferredPathSeparator + normalized; // keep root slash + return normalized; } /// <summary>Get a directory or file path relative to a given source path.</summary> @@ -57,7 +57,7 @@ namespace StardewModdingAPI.Toolkit.Utilities throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'."); // get relative path - string relative = PathUtilities.NormalisePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); + string relative = PathUtilities.NormalizePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); if (relative == "") relative = "./"; return relative; diff --git a/src/SMAPI.Toolkit/Utilities/Platform.cs b/src/SMAPI.Toolkit/Utilities/Platform.cs new file mode 100644 index 00000000..f780e812 --- /dev/null +++ b/src/SMAPI.Toolkit/Utilities/Platform.cs @@ -0,0 +1,18 @@ +namespace StardewModdingAPI.Toolkit.Utilities +{ + /// <summary>The game's platform version.</summary> + public enum Platform + { + /// <summary>The Android version of the game.</summary> + Android, + + /// <summary>The Linux version of the game.</summary> + Linux, + + /// <summary>The Mac version of the game.</summary> + Mac, + + /// <summary>The Windows version of the game.</summary> + Windows + } +} |