diff --git a/docs/release-notes.md b/docs/release-notes.md
index aa9b488c..8c2b6a9e 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -4,7 +4,7 @@
## Upcoming version
* For players:
* You no longer need .NET 5 installed to run SMAPI or the installer.
- * The installer now detects when the game folder contains an incompatible older game version.
+ * The installer now detects when the game folder contains an incompatible legacy game version.
* Updated for the latest Stardew Valley 1.5.5 hotfix.
* For SMAPI maintainers:
diff --git a/src/SMAPI.Installer/Framework/InstallerContext.cs b/src/SMAPI.Installer/Framework/InstallerContext.cs
index 68df2001..bb973230 100644
--- a/src/SMAPI.Installer/Framework/InstallerContext.cs
+++ b/src/SMAPI.Installer/Framework/InstallerContext.cs
@@ -55,11 +55,11 @@ namespace StardewModdingAPI.Installer.Framework
return this.GameScanner.LooksLikeGameFolder(dir);
}
- /// Get whether a folder seems to contain Stardew Valley 1.5.4 or earlier.
+ /// Get whether a folder seems to contain the game, and which version it contains if so.
/// The folder to check.
- public bool LooksLikeStardewValley154(DirectoryInfo dir)
+ public GameFolderType GetGameFolderType(DirectoryInfo dir)
{
- return this.GameScanner.LooksLikeStardewValley154(dir);
+ return this.GameScanner.GetGameFolderType(dir);
}
}
}
diff --git a/src/SMAPI.Installer/InteractiveInstaller.cs b/src/SMAPI.Installer/InteractiveInstaller.cs
index 424fe42b..6694c257 100644
--- a/src/SMAPI.Installer/InteractiveInstaller.cs
+++ b/src/SMAPI.Installer/InteractiveInstaller.cs
@@ -10,6 +10,7 @@ using StardewModdingAPI.Installer.Framework;
using StardewModdingAPI.Internal.ConsoleWriting;
using StardewModdingAPI.Toolkit;
using StardewModdingAPI.Toolkit.Framework;
+using StardewModdingAPI.Toolkit.Framework.GameScanning;
using StardewModdingAPI.Toolkit.Framework.ModScanning;
using StardewModdingAPI.Toolkit.Utilities;
@@ -633,18 +634,39 @@ namespace StardewModdingApi.Installer
// use specified path
if (specifiedPath != null)
{
+ string errorPrefix = $"You specified --game-path \"{specifiedPath}\", but";
+
var dir = new DirectoryInfo(specifiedPath);
if (!dir.Exists)
{
- this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't exist.");
+ this.PrintError($"{errorPrefix} that folder doesn't exist.");
return null;
}
- if (!context.LooksLikeGameFolder(dir))
+
+ switch (context.GetGameFolderType(dir))
{
- this.PrintError($"You specified --game-path \"{specifiedPath}\", but that folder doesn't contain the Stardew Valley executable.");
- return null;
+ case GameFolderType.Valid:
+ return dir;
+
+ case GameFolderType.Legacy154OrEarlier:
+ this.PrintWarning($"{errorPrefix} that directory seems to have Stardew Valley 1.5.4 or earlier.");
+ this.PrintWarning("Please update your game to the latest version to use SMAPI.");
+ return null;
+
+ case GameFolderType.LegacyCompatibilityBranch:
+ this.PrintWarning($"{errorPrefix} that directory seems to have the Stardew Valley legacy 'compatibility' branch.");
+ this.PrintWarning("Unfortunately SMAPI is only compatible with the full main version of the game.");
+ this.PrintWarning("Please update your game to the main branch to use SMAPI.");
+ return null;
+
+ case GameFolderType.NoGameFound:
+ this.PrintWarning($"{errorPrefix} that directory doesn't contain a Stardew Valley executable.");
+ return null;
+
+ default:
+ this.PrintWarning($"{errorPrefix} that directory doesn't seem to contain a valid game install.");
+ return null;
}
- return dir;
}
// let user choose detected path
@@ -702,23 +724,32 @@ namespace StardewModdingApi.Installer
this.PrintWarning("That directory doesn't seem to exist.");
continue;
}
- if (!context.LooksLikeGameFolder(directory))
+
+ switch (context.GetGameFolderType(directory))
{
- if (context.LooksLikeStardewValley154(directory))
- {
+ case GameFolderType.Valid:
+ this.PrintInfo(" OK!");
+ return directory;
+
+ case GameFolderType.Legacy154OrEarlier:
this.PrintWarning("That directory seems to have Stardew Valley 1.5.4 or earlier.");
this.PrintWarning("Please update your game to the latest version to use SMAPI.");
- }
- else
- {
- this.PrintWarning("That directory doesn't contain a Stardew Valley executable.");
- }
- continue;
- }
+ continue;
- // looks OK
- this.PrintInfo(" OK!");
- return directory;
+ case GameFolderType.LegacyCompatibilityBranch:
+ this.PrintWarning("That directory seems to have the Stardew Valley legacy 'compatibility' branch.");
+ this.PrintWarning("Unfortunately SMAPI is only compatible with the full main version of the game.");
+ this.PrintWarning("Please update your game to the main branch to use SMAPI.");
+ continue;
+
+ case GameFolderType.NoGameFound:
+ this.PrintWarning("That directory doesn't contain a Stardew Valley executable.");
+ continue;
+
+ default:
+ this.PrintWarning("That directory doesn't seem to contain a valid game install.");
+ continue;
+ }
}
}
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameFolderType.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameFolderType.cs
new file mode 100644
index 00000000..d18af59b
--- /dev/null
+++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameFolderType.cs
@@ -0,0 +1,21 @@
+namespace StardewModdingAPI.Toolkit.Framework.GameScanning
+{
+ /// The detected validity for a Stardew Valley game folder based on file structure heuristics.
+ public enum GameFolderType
+ {
+ /// The folder seems to contain a valid Stardew Valley 1.5.5+ install.
+ Valid,
+
+ /// The folder doesn't contain Stardew Valley.
+ NoGameFound,
+
+ /// The folder contains Stardew Valley 1.5.4 or earlier. This version uses XNA Framework and 32-bit .NET Framework 4.5.2 on Windows and Mono on Linux/macOS, and isn't compatible with current versions of SMAPI.
+ Legacy154OrEarlier,
+
+ /// The folder contains Stardew Valley from the game's legacy compatibility branch, which backports newer changes to the format.
+ LegacyCompatibilityBranch,
+
+ /// The folder seems to contain Stardew Valley files, but they failed to load for unknown reasons (e.g. corrupted executable).
+ InvalidUnknown
+ }
+}
diff --git a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
index c7ebe6e0..37e4f263 100644
--- a/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
+++ b/src/SMAPI.Toolkit/Framework/GameScanning/GameScanner.cs
@@ -55,36 +55,58 @@ namespace StardewModdingAPI.Toolkit.Framework.GameScanning
/// The folder to check.
public bool LooksLikeGameFolder(DirectoryInfo dir)
{
- return
- dir.Exists
- && dir.EnumerateFiles("Stardew Valley.dll").Any();
+ return this.GetGameFolderType(dir) == GameFolderType.Valid;
}
- /// Get whether a folder seems to contain Stardew Valley 1.5.4 or earlier.
+ /// Detect the validity of a game folder based on file structure heuristics.
/// The folder to check.
- public bool LooksLikeStardewValley154(DirectoryInfo dir)
+ public GameFolderType GetGameFolderType(DirectoryInfo dir)
{
- if (!dir.Exists || this.LooksLikeGameFolder(dir))
- return false;
+ // no such folder
+ if (!dir.Exists)
+ return GameFolderType.NoGameFound;
- // get legacy executable
- FileInfo executable = new FileInfo(Path.Combine(dir.FullName, "Stardew Valley.exe"));
- if (!executable.Exists)
- executable = new FileInfo(Path.Combine(dir.FullName, "StardewValley.exe"));
- if (!executable.Exists)
- return false;
+ // apparently valid
+ if (dir.EnumerateFiles("Stardew Valley.dll").Any())
+ return GameFolderType.Valid;
- // check if it's a standard .NET assembly
- // This will fail in Stardew Valley 1.5.5+, where it's a binary wrapper around Stardew Valley.dll.
+ // doesn't contain any version of Stardew Valley
+ FileInfo executable = new(Path.Combine(dir.FullName, "Stardew Valley.exe"));
+ if (!executable.Exists)
+ executable = new(Path.Combine(dir.FullName, "StardewValley.exe")); // pre-1.5.5 Linux/macOS executable
+ if (!executable.Exists)
+ return GameFolderType.NoGameFound;
+
+ // get assembly version
+ Version version;
try
{
- Version version = AssemblyName.GetAssemblyName(executable.FullName).Version;
- return true;
+ version = AssemblyName.GetAssemblyName(executable.FullName).Version;
}
catch
{
- return false;
+ // The executable exists but it doesn't seem to be a valid assembly. This would
+ // happen with Stardew Valley 1.5.5+, but that should have been flagged as a valid
+ // folder before this point.
+ return GameFolderType.InvalidUnknown;
}
+
+ // ignore Stardew Valley 1.5.5+ at this point
+ if (version.Major == 1 && version.Minor == 3 && version.Build == 37)
+ return GameFolderType.InvalidUnknown;
+
+ // incompatible version
+ if (version.Major == 1 && version.Minor < 4)
+ {
+ // Stardew Valley 1.5.4 and earlier have assembly versions <= 1.3.7853.31734
+ if (version.Minor < 3 || version.Build <= 7853)
+ return GameFolderType.Legacy154OrEarlier;
+
+ // Stardew Valley 1.5.5+ legacy compatibility branch
+ return GameFolderType.LegacyCompatibilityBranch;
+ }
+
+ return GameFolderType.InvalidUnknown;
}
/*********