add descriptive error for PathTooLongException which crashes SMAPI or the installer

This commit is contained in:
Jesse Plamondon-Willard 2021-03-07 18:04:48 -05:00
parent 36cb8e8fcb
commit 0ed46c0910
No known key found for this signature in database
GPG Key ID: CF8B1456B3E29F49
5 changed files with 52 additions and 2 deletions

View File

@ -9,8 +9,9 @@
## Upcoming release ## Upcoming release
* For players: * For players:
* Fixed console showing _found 1 mod with warnings_ with no mods listed.
* If the installer crashes, the window now stays open if possible so you can read the error and ask for help. * If the installer crashes, the window now stays open if possible so you can read the error and ask for help.
* Added descriptive error if possible when a `PathTooLongException` crashes SMAPI or the installer.
* Fixed console showing _found 1 mod with warnings_ with no mods listed.
* For mod authors: * For mod authors:
* Added three stages to the `LoadStageChanged` event: `CreatedInitialLocations`/`SaveAddedLocations` (raised immediately after the game adds locations but before they're initialized), and `ReturningToTitle` (raised before exiting to the title screen). * Added three stages to the `LoadStageChanged` event: `CreatedInitialLocations`/`SaveAddedLocations` (raised immediately after the game adds locations but before they're initialized), and `ReturningToTitle` (raised before exiting to the title screen).

View File

@ -279,6 +279,7 @@ namespace StardewModdingApi.Installer
/********* /*********
** Step 4: validate assumptions ** Step 4: validate assumptions
*********/ *********/
// executable exists
if (!File.Exists(paths.ExecutablePath)) if (!File.Exists(paths.ExecutablePath))
{ {
this.PrintError("The detected game install path doesn't contain a Stardew Valley executable."); this.PrintError("The detected game install path doesn't contain a Stardew Valley executable.");
@ -286,6 +287,17 @@ namespace StardewModdingApi.Installer
return; 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;
}
}
/********* /*********
** Step 5: ask what to do ** Step 5: ask what to do

View File

@ -1,4 +1,5 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("StardewModdingAPI")] [assembly: InternalsVisibleTo("StardewModdingAPI")]
[assembly: InternalsVisibleTo("SMAPI.Installer")]
[assembly: InternalsVisibleTo("SMAPI.Web")] [assembly: InternalsVisibleTo("SMAPI.Web")]

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts; using System.Diagnostics.Contracts;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -133,5 +134,29 @@ namespace StardewModdingAPI.Toolkit.Utilities
{ {
return !Regex.IsMatch(str, "[^a-z0-9_.-]", RegexOptions.IgnoreCase); return !Regex.IsMatch(str, "[^a-z0-9_.-]", RegexOptions.IgnoreCase);
} }
/// <summary>Get the paths which exceed the OS length limit.</summary>
/// <param name="rootPath">The root path to search.</param>
internal static IEnumerable<string> GetTooLongPaths(string rootPath)
{
return Directory
.EnumerateFileSystemEntries(rootPath, "*.*", SearchOption.AllDirectories)
.Where(PathUtilities.IsPathTooLong);
}
/// <summary>Get whether a file or directory path exceeds the OS path length limit.</summary>
/// <param name="path">The path to test.</param>
internal static bool IsPathTooLong(string path)
{
try
{
_ = Path.GetFullPath(path);
return false;
}
catch (PathTooLongException)
{
return true;
}
}
} }
} }

View File

@ -252,11 +252,22 @@ namespace StardewModdingAPI.Framework.Logging
break; break;
// missing content folder exception // missing content folder exception
case FileNotFoundException ex when ex.Message == "Could not find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.": // path in error is hardcoded regardless of install path case FileNotFoundException ex when ex.Message == "Couldn't find file 'C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Stardew Valley\\Content\\XACT\\FarmerSounds.xgs'.": // path in error is hardcoded regardless of install path
this.Monitor.Log("The game can't find its Content\\XACT\\FarmerSounds.xgs file. You can usually fix this by resetting your content files (see https://smapi.io/troubleshoot#reset-content ), or by uninstalling and reinstalling the game.", LogLevel.Error); this.Monitor.Log("The game can't find its Content\\XACT\\FarmerSounds.xgs file. You can usually fix this by resetting your content files (see https://smapi.io/troubleshoot#reset-content ), or by uninstalling and reinstalling the game.", LogLevel.Error);
this.Monitor.Log($"Technical details: {ex.GetLogSummary()}"); this.Monitor.Log($"Technical details: {ex.GetLogSummary()}");
break; break;
// path too long exception
case PathTooLongException:
{
string[] affectedPaths = PathUtilities.GetTooLongPaths(Constants.ModsPath).ToArray();
string message = affectedPaths.Any()
? $"SMAPI can't launch because some of your mod files exceed the maximum path length on {Constants.Platform}.\nIf you need help fixing this error, see https://smapi.io/help\n\nAffected paths:\n {string.Join("\n ", affectedPaths)}"
: $"The game failed to launch: {exception.GetLogSummary()}";
this.MonitorForGame.Log(message, LogLevel.Error);
}
break;
// generic exception // generic exception
default: default:
this.MonitorForGame.Log($"The game failed to launch: {exception.GetLogSummary()}", LogLevel.Error); this.MonitorForGame.Log($"The game failed to launch: {exception.GetLogSummary()}", LogLevel.Error);