diff options
Diffstat (limited to 'src')
74 files changed, 1145 insertions, 965 deletions
diff --git a/src/SMAPI.Installer/Framework/InstallerContext.cs b/src/SMAPI.Installer/Framework/InstallerContext.cs index 88e57760..95df32ca 100644 --- a/src/SMAPI.Installer/Framework/InstallerContext.cs +++ b/src/SMAPI.Installer/Framework/InstallerContext.cs @@ -1,6 +1,4 @@ -using System; using System.IO; -using Microsoft.Win32; using StardewModdingAPI.Toolkit; using StardewModdingAPI.Toolkit.Framework.GameScanning; using StardewModdingAPI.Toolkit.Utilities; @@ -13,9 +11,6 @@ namespace StardewModdingAPI.Installer.Framework /********* ** Fields *********/ - /// <summary>The <see cref="Environment.OSVersion"/> value that represents Windows 7.</summary> - private readonly Version Windows7Version = new Version(6, 1); - /// <summary>The underlying toolkit game scanner.</summary> private readonly GameScanner GameScanner = new GameScanner(); @@ -29,9 +24,6 @@ namespace StardewModdingAPI.Installer.Framework /// <summary>The human-readable OS name and version.</summary> public string PlatformName { get; } - /// <summary>The name of the Stardew Valley executable.</summary> - public string ExecutableName { get; } - /// <summary>Whether the installer is running on Windows.</summary> public bool IsWindows => this.Platform == Platform.Windows; @@ -47,7 +39,6 @@ namespace StardewModdingAPI.Installer.Framework { this.Platform = EnvironmentUtility.DetectPlatform(); this.PlatformName = EnvironmentUtility.GetFriendlyPlatformName(this.Platform); - this.ExecutableName = EnvironmentUtility.GetExecutableName(this.Platform); } /// <summary>Get the installer's version number.</summary> @@ -57,42 +48,6 @@ namespace StardewModdingAPI.Installer.Framework return new SemanticVersion(raw); } - /// <summary>Get whether the current system has .NET Framework 4.5 or later installed. This only applies on Windows.</summary> - /// <exception cref="NotSupportedException">The current platform is not Windows.</exception> - public bool HasNetFramework45() - { - switch (this.Platform) - { - case Platform.Windows: - using (RegistryKey versionKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full")) - return versionKey?.GetValue("Release") != null; // .NET Framework 4.5+ - - default: - throw new NotSupportedException("The installed .NET Framework version can only be checked on Windows."); - } - } - - /// <summary>Get whether the current system has XNA Framework installed. This only applies on Windows.</summary> - /// <exception cref="NotSupportedException">The current platform is not Windows.</exception> - public bool HasXna() - { - switch (this.Platform) - { - case Platform.Windows: - using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(@"SOFTWARE\Microsoft\XNA\Framework")) - return key != null; // XNA Framework 4.0+ - - default: - throw new NotSupportedException("The installed XNA Framework version can only be checked on Windows."); - } - } - - /// <summary>Whether the current OS supports newer versions of .NET Framework.</summary> - public bool CanInstallLatestNetFramework() - { - return Environment.OSVersion.Version >= this.Windows7Version; // Windows 7+ - } - /// <summary>Get whether a folder seems to contain the game files.</summary> /// <param name="dir">The folder to check.</param> public bool LooksLikeGameFolder(DirectoryInfo dir) diff --git a/src/SMAPI.Installer/Framework/InstallerPaths.cs b/src/SMAPI.Installer/Framework/InstallerPaths.cs index 6ba5fa5f..0976eceb 100644 --- a/src/SMAPI.Installer/Framework/InstallerPaths.cs +++ b/src/SMAPI.Installer/Framework/InstallerPaths.cs @@ -1,4 +1,5 @@ using System.IO; +using StardewModdingAPI.Toolkit.Framework; namespace StardewModdingAPI.Installer.Framework { @@ -44,17 +45,20 @@ namespace StardewModdingAPI.Installer.Framework /// <summary>The full path to the user's config overrides file.</summary> public string ApiUserConfigPath { get; } - /// <summary>The full path to the installed game executable file.</summary> - public string ExecutablePath { get; private set; } + /// <summary>The full path to the installed game DLL.</summary> + public string GameDllPath { get; } - /// <summary>The full path to the vanilla game launcher on Linux/macOS.</summary> - public string UnixLauncherPath { get; } + /// <summary>The full path to the installed SMAPI executable file.</summary> + public string UnixSmapiExecutablePath { get; } - /// <summary>The full path to the installed SMAPI launcher on Linux/macOS before it's renamed.</summary> - public string UnixSmapiLauncherPath { get; } + /// <summary>The full path to the vanilla game launch script on Linux/macOS.</summary> + public string VanillaLaunchScriptPath { get; } - /// <summary>The full path to the vanilla game launcher on Linux/macOS after SMAPI is installed.</summary> - public string UnixBackupLauncherPath { get; } + /// <summary>The full path to the installed SMAPI launch script on Linux/macOS before it's renamed.</summary> + public string NewLaunchScriptPath { get; } + + /// <summary>The full path to the backed up game launch script on Linux/macOS after SMAPI is installed.</summary> + public string BackupLaunchScriptPath { get; } /********* @@ -63,28 +67,24 @@ namespace StardewModdingAPI.Installer.Framework /// <summary>Construct an instance.</summary> /// <param name="bundleDir">The directory path containing the files to copy into the game folder.</param> /// <param name="gameDir">The directory path for the installed game.</param> - /// <param name="gameExecutableName">The name of the game's executable file for the current platform.</param> - public InstallerPaths(DirectoryInfo bundleDir, DirectoryInfo gameDir, string gameExecutableName) + public InstallerPaths(DirectoryInfo bundleDir, DirectoryInfo gameDir) { + // base paths this.BundleDir = bundleDir; this.GameDir = gameDir; this.ModsDir = new DirectoryInfo(Path.Combine(gameDir.FullName, "Mods")); + this.GameDllPath = Path.Combine(gameDir.FullName, Constants.GameDllName); - this.BundleApiUserConfigPath = Path.Combine(bundleDir.FullName, "smapi-internal", "config.user.json"); + // launch scripts + this.VanillaLaunchScriptPath = Path.Combine(gameDir.FullName, "StardewValley"); + this.NewLaunchScriptPath = Path.Combine(gameDir.FullName, "unix-launcher.sh"); + this.BackupLaunchScriptPath = Path.Combine(gameDir.FullName, "StardewValley-original"); + this.UnixSmapiExecutablePath = Path.Combine(gameDir.FullName, "StardewModdingAPI"); - this.ExecutablePath = Path.Combine(gameDir.FullName, gameExecutableName); - this.UnixLauncherPath = Path.Combine(gameDir.FullName, "StardewValley"); - this.UnixSmapiLauncherPath = Path.Combine(gameDir.FullName, "StardewModdingAPI"); - this.UnixBackupLauncherPath = Path.Combine(gameDir.FullName, "StardewValley-original"); + // internal files + this.BundleApiUserConfigPath = Path.Combine(bundleDir.FullName, "smapi-internal", "config.user.json"); this.ApiConfigPath = Path.Combine(gameDir.FullName, "smapi-internal", "config.json"); this.ApiUserConfigPath = Path.Combine(gameDir.FullName, "smapi-internal", "config.user.json"); } - - /// <summary>Override the filename for the <see cref="ExecutablePath"/>.</summary> - /// <param name="filename">the file name.</param> - public void SetExecutableFileName(string filename) - { - this.ExecutablePath = Path.Combine(this.GamePath, filename); - } } } diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs index 9f49137f..d8c27a2d 100644 --- a/src/SMAPI.Installer/InteractiveInstaller.cs +++ b/src/SMAPI.Installer/InteractiveInstaller.cs @@ -39,18 +39,19 @@ namespace StardewModdingApi.Installer string GetInstallPath(string path) => Path.Combine(installDir.FullName, path); // current files - yield return GetInstallPath("libgdiplus.dylib"); // Linux/macOS only yield return GetInstallPath("StardewModdingAPI"); // Linux/macOS only + yield return GetInstallPath("StardewModdingAPI.dll"); yield return GetInstallPath("StardewModdingAPI.exe"); yield return GetInstallPath("StardewModdingAPI.exe.config"); yield return GetInstallPath("StardewModdingAPI.exe.mdb"); // Linux/macOS only yield return GetInstallPath("StardewModdingAPI.pdb"); // Windows only + yield return GetInstallPath("StardewModdingAPI.runtimeconfig.json"); yield return GetInstallPath("StardewModdingAPI.xml"); - yield return GetInstallPath("StardewModdingAPI-x64.exe"); // not normally added to game folder, but may be mistakenly added by a manual install yield return GetInstallPath("smapi-internal"); yield return GetInstallPath("steam_appid.txt"); // obsolete + yield return GetInstallPath("libgdiplus.dylib"); // before 3.13 (macOS only) yield return GetInstallPath(Path.Combine("Mods", ".cache")); // 1.3-1.4 yield return GetInstallPath(Path.Combine("Mods", "TrainerMod")); // *–2.0 (renamed to ConsoleCommands) yield return GetInstallPath("Mono.Cecil.Rocks.dll"); // 1.3–1.8 @@ -70,9 +71,7 @@ namespace StardewModdingApi.Installer yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.dll"); // moved in 2.8 yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.pdb"); // moved in 2.8 yield return GetInstallPath("StardewModdingAPI.Toolkit.CoreInterfaces.xml"); // moved in 2.8 - yield return GetInstallPath("System.Numerics.dll"); // moved in 2.8 - yield return GetInstallPath("System.Runtime.Caching.dll"); // moved in 2.8 - yield return GetInstallPath("System.ValueTuple.dll"); // moved in 2.8 + yield return GetInstallPath("StardewModdingAPI-x64.exe"); // before 3.13 if (modsDir.Exists) { @@ -150,30 +149,6 @@ namespace StardewModdingApi.Installer #endif /**** - ** Check Windows dependencies - ****/ - if (context.IsWindows) - { - // .NET Framework 4.5+ - if (!context.HasNetFramework45()) - { - this.PrintError(context.CanInstallLatestNetFramework() - ? "Please install the latest version of .NET Framework before installing SMAPI." - : "Please install .NET Framework 4.5 before installing SMAPI." - ); - this.PrintError("See the download page at https://www.microsoft.com/net/download/framework for details."); - Console.ReadLine(); - return; - } - if (!context.HasXna()) - { - this.PrintError("You don't seem to have XNA Framework installed. Please run the game at least once before installing SMAPI, so it can perform its first-time setup."); - Console.ReadLine(); - return; - } - } - - /**** ** read command-line arguments ****/ // get action from CLI @@ -270,51 +245,20 @@ namespace StardewModdingApi.Installer // get folders DirectoryInfo bundleDir = new DirectoryInfo(this.BundlePath); - paths = new InstallerPaths(bundleDir, installDir, context.ExecutableName); + paths = new InstallerPaths(bundleDir, installDir); } /********* ** Step 4: validate assumptions *********/ - // not 64-bit on Windows - if (context.Platform == Platform.Windows) - { - FileInfo linuxExecutable = new FileInfo(Path.Combine(paths.GamePath, "StardewValley.exe")); - if (linuxExecutable.Exists && this.Is64Bit(linuxExecutable.FullName)) - { - this.PrintError("Oops! The detected game install path seems to be unofficial 64-bit mode, which is no longer supported. You can update to Stardew Valley 1.5.5 or later instead. See https://stardewvalleywiki.com/Modding:Migrate_to_64-bit_on_Windows for more info."); - Console.ReadLine(); - return; - } - } - // executable exists - if (!File.Exists(paths.ExecutablePath)) + if (!File.Exists(paths.GameDllPath)) { this.PrintError("The detected game install path doesn't contain a Stardew Valley executable."); Console.ReadLine(); return; } - - // not Stardew Valley 1.5.5+ - if (File.Exists(Path.Combine(paths.GamePath, "Stardew Valley.dll"))) - { - this.PrintError("Oops! The detected game install path seems to be Stardew Valley 1.5.5 or later, but this version of SMAPI is only compatible up to Stardew Valley 1.5.4. Please check for a newer version of SMAPI: https://smapi.io."); - Console.ReadLine(); - return; - } - - // game folder doesn't contain paths beyond the max limit - { - string[] tooLongPaths = PathUtilities.GetTooLongPaths(Path.Combine(paths.GamePath, "Mods")).ToArray(); - if (tooLongPaths.Any()) - { - this.PrintError($"SMAPI can't install to the detected game folder, because some of its files exceed the maximum {context.Platform} path length.\nIf you need help fixing this error, see https://smapi.io/help\n\nAffected paths:\n {string.Join("\n ", tooLongPaths)}"); - Console.ReadLine(); - return; - } - } Console.Clear(); @@ -387,11 +331,11 @@ namespace StardewModdingApi.Installer ** Always uninstall old files ****/ // restore game launcher - if (context.IsUnix && File.Exists(paths.UnixBackupLauncherPath)) + if (context.IsUnix && File.Exists(paths.BackupLaunchScriptPath)) { this.PrintDebug("Removing SMAPI launcher..."); - this.InteractivelyDelete(paths.UnixLauncherPath); - File.Move(paths.UnixBackupLauncherPath, paths.UnixLauncherPath); + this.InteractivelyDelete(paths.VanillaLaunchScriptPath); + File.Move(paths.BackupLaunchScriptPath, paths.VanillaLaunchScriptPath); } // remove old files @@ -439,30 +383,41 @@ namespace StardewModdingApi.Installer this.PrintDebug("Safely replacing game launcher..."); // back up & remove current launcher - if (File.Exists(paths.UnixLauncherPath)) + if (File.Exists(paths.VanillaLaunchScriptPath)) { - if (!File.Exists(paths.UnixBackupLauncherPath)) - File.Move(paths.UnixLauncherPath, paths.UnixBackupLauncherPath); + if (!File.Exists(paths.BackupLaunchScriptPath)) + File.Move(paths.VanillaLaunchScriptPath, paths.BackupLaunchScriptPath); else - this.InteractivelyDelete(paths.UnixLauncherPath); + this.InteractivelyDelete(paths.VanillaLaunchScriptPath); } // add new launcher - File.Move(paths.UnixSmapiLauncherPath, paths.UnixLauncherPath); + File.Move(paths.NewLaunchScriptPath, paths.VanillaLaunchScriptPath); - // mark file executable + // mark files executable // (MSBuild doesn't keep permission flags for files zipped in a build task.) - new Process + foreach (string path in new[] { paths.VanillaLaunchScriptPath, paths.UnixSmapiExecutablePath }) { - StartInfo = new ProcessStartInfo + new Process { - FileName = "chmod", - Arguments = $"755 \"{paths.UnixLauncherPath}\"", - CreateNoWindow = true - } - }.Start(); + StartInfo = new ProcessStartInfo + { + FileName = "chmod", + Arguments = $"755 \"{path}\"", + CreateNoWindow = true + } + }.Start(); + } } + // copy the game's deps.json file + // (This is needed to resolve native DLLs like libSkiaSharp.) + File.Copy( + sourceFileName: Path.Combine(paths.GamePath, "Stardew Valley.deps.json"), + destFileName: Path.Combine(paths.GamePath, "StardewModdingAPI.deps.json"), + overwrite: true + ); + // create mods directory (if needed) |
