diff options
author | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-09-18 13:08:38 -0400 |
---|---|---|
committer | Jesse Plamondon-Willard <Pathoschild@users.noreply.github.com> | 2021-09-18 13:08:38 -0400 |
commit | ebe41180c41f544919c03fb3bf6029437a7d65a4 (patch) | |
tree | 0c5c0602bbee1fc96a024f3be1cd225d72d37fa0 /src | |
parent | c5b8cd626489dad6210fe629658314dfc85f4d08 (diff) | |
parent | 6643da4574bec2d71ac9c25a2c9ab15b8c855e2b (diff) | |
download | SMAPI-ebe41180c41f544919c03fb3bf6029437a7d65a4.tar.gz SMAPI-ebe41180c41f544919c03fb3bf6029437a7d65a4.tar.bz2 SMAPI-ebe41180c41f544919c03fb3bf6029437a7d65a4.zip |
Merge branch 'develop' into stable
Diffstat (limited to 'src')
-rw-r--r-- | src/SMAPI.Internal/ExceptionHelper.cs (renamed from src/SMAPI.Internal/ExceptionExtensions.cs) | 36 | ||||
-rw-r--r-- | src/SMAPI.Internal/SMAPI.Internal.projitems | 2 | ||||
-rw-r--r-- | src/SMAPI.Mods.ConsoleCommands/manifest.json | 4 | ||||
-rw-r--r-- | src/SMAPI.Mods.ErrorHandler/manifest.json | 4 | ||||
-rw-r--r-- | src/SMAPI.Mods.SaveBackup/manifest.json | 4 | ||||
-rw-r--r-- | src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs | 7 | ||||
-rw-r--r-- | src/SMAPI.Web/Controllers/JsonValidatorController.cs | 26 | ||||
-rw-r--r-- | src/SMAPI.Web/Views/Mods/Index.cshtml | 4 | ||||
-rw-r--r-- | src/SMAPI/Constants.cs | 2 | ||||
-rw-r--r-- | src/SMAPI/Framework/ContentManagers/GameContentManager.cs | 44 | ||||
-rw-r--r-- | src/SMAPI/Framework/Logging/LogManager.cs | 4 | ||||
-rw-r--r-- | src/SMAPI/Framework/SCore.cs | 13 | ||||
-rw-r--r-- | src/SMAPI/Metadata/CoreAssetPropagator.cs | 4 |
13 files changed, 106 insertions, 48 deletions
diff --git a/src/SMAPI.Internal/ExceptionExtensions.cs b/src/SMAPI.Internal/ExceptionHelper.cs index d8189048..4bc55f95 100644 --- a/src/SMAPI.Internal/ExceptionExtensions.cs +++ b/src/SMAPI.Internal/ExceptionHelper.cs @@ -1,10 +1,11 @@ using System; using System.Reflection; +using System.Text.RegularExpressions; namespace StardewModdingAPI.Internal { /// <summary>Provides extension methods for handling exceptions.</summary> - internal static class ExceptionExtensions + internal static class ExceptionHelper { /********* ** Public methods @@ -15,20 +16,26 @@ namespace StardewModdingAPI.Internal { try { + string message; switch (exception) { case TypeLoadException ex: - return $"Failed loading type '{ex.TypeName}': {exception}"; + message = $"Failed loading type '{ex.TypeName}': {exception}"; + break; case ReflectionTypeLoadException ex: string summary = ex.ToString(); foreach (Exception childEx in ex.LoaderExceptions ?? new Exception[0]) summary += $"\n\n{childEx?.GetLogSummary()}"; - return summary; + message = summary; + break; default: - return exception?.ToString() ?? $"<null exception>\n{Environment.StackTrace}"; + message = exception?.ToString() ?? $"<null exception>\n{Environment.StackTrace}"; + break; } + + return ExceptionHelper.SimplifyExtensionMessage(message); } catch (Exception ex) { @@ -44,5 +51,26 @@ namespace StardewModdingAPI.Internal exception = exception.InnerException; return exception; } + + /// <summary>Simplify common patterns in exception log messages that don't convey useful info.</summary> + /// <param name="message">The log message to simplify.</param> + public static string SimplifyExtensionMessage(string message) + { + // remove namespace for core exception types + message = Regex.Replace( + message, + @"(?:StardewModdingAPI\.Framework\.Exceptions|Microsoft\.Xna\.Framework|System|System\.IO)\.([a-zA-Z]+Exception):", + "$1:" + ); + + // remove unneeded root build paths for SMAPI and Stardew Valley + message = message + .Replace(@"C:\source\_Stardew\SMAPI\src\", "") + .Replace(@"C:\GitlabRunner\builds\Gq5qA5P4\0\ConcernedApe\", ""); + + // remove placeholder info in Linux/macOS stack traces + return message + .Replace(@"<filename unknown>:0", ""); + } } } diff --git a/src/SMAPI.Internal/SMAPI.Internal.projitems b/src/SMAPI.Internal/SMAPI.Internal.projitems index 0ee94a5b..41d356c0 100644 --- a/src/SMAPI.Internal/SMAPI.Internal.projitems +++ b/src/SMAPI.Internal/SMAPI.Internal.projitems @@ -14,6 +14,6 @@ <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\ConsoleLogLevel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\IConsoleWriter.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ConsoleWriting\MonitorColorScheme.cs" /> - <Compile Include="$(MSBuildThisFileDirectory)ExceptionExtensions.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)ExceptionHelper.cs" /> </ItemGroup> </Project>
\ No newline at end of file diff --git a/src/SMAPI.Mods.ConsoleCommands/manifest.json b/src/SMAPI.Mods.ConsoleCommands/manifest.json index de223c01..e53bf991 100644 --- a/src/SMAPI.Mods.ConsoleCommands/manifest.json +++ b/src/SMAPI.Mods.ConsoleCommands/manifest.json @@ -1,9 +1,9 @@ { "Name": "Console Commands", "Author": "SMAPI", - "Version": "3.12.6", + "Version": "3.12.7", "Description": "Adds SMAPI console commands that let you manipulate the game.", "UniqueID": "SMAPI.ConsoleCommands", "EntryDll": "ConsoleCommands.dll", - "MinimumApiVersion": "3.12.6" + "MinimumApiVersion": "3.12.7" } diff --git a/src/SMAPI.Mods.ErrorHandler/manifest.json b/src/SMAPI.Mods.ErrorHandler/manifest.json index fcb6d7eb..37a7e9bf 100644 --- a/src/SMAPI.Mods.ErrorHandler/manifest.json +++ b/src/SMAPI.Mods.ErrorHandler/manifest.json @@ -1,9 +1,9 @@ { "Name": "Error Handler", "Author": "SMAPI", - "Version": "3.12.6", + "Version": "3.12.7", "Description": "Handles some common vanilla errors to log more useful info or avoid breaking the game.", "UniqueID": "SMAPI.ErrorHandler", "EntryDll": "ErrorHandler.dll", - "MinimumApiVersion": "3.12.6" + "MinimumApiVersion": "3.12.7" } diff --git a/src/SMAPI.Mods.SaveBackup/manifest.json b/src/SMAPI.Mods.SaveBackup/manifest.json index 1c84b5c2..28c7ec14 100644 --- a/src/SMAPI.Mods.SaveBackup/manifest.json +++ b/src/SMAPI.Mods.SaveBackup/manifest.json @@ -1,9 +1,9 @@ { "Name": "Save Backup", "Author": "SMAPI", - "Version": "3.12.6", + "Version": "3.12.7", "Description": "Automatically backs up all your saves once per day into its folder.", "UniqueID": "SMAPI.SaveBackup", "EntryDll": "SaveBackup.dll", - "MinimumApiVersion": "3.12.6" + "MinimumApiVersion": "3.12.7" } diff --git a/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs index 549f0c18..ccc5158b 100644 --- a/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs +++ b/src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs @@ -22,7 +22,7 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters /// <param name="objectType">The object type.</param> public override bool CanConvert(Type objectType) { - return objectType == typeof(T); + return objectType == typeof(T) || Nullable.GetUnderlyingType(objectType) == typeof(T); } /// <summary>Writes the JSON representation of the object.</summary> @@ -44,10 +44,15 @@ namespace StardewModdingAPI.Toolkit.Serialization.Converters string path = reader.Path; switch (reader.TokenType) { + case JsonToken.Null when Nullable.GetUnderlyingType(objectType) != null: + return null; + case JsonToken.StartObject: return this.ReadObject(JObject.Load(reader), path); + case JsonToken.String: return this.ReadString(JToken.Load(reader).Value<string>(), path); + default: throw new SParseException($"Can't parse {typeof(T).Name} from {reader.TokenType} node (path: {reader.Path})."); } diff --git a/src/SMAPI.Web/Controllers/JsonValidatorController.cs b/src/SMAPI.Web/Controllers/JsonValidatorController.cs index c77a3036..e06c1236 100644 --- a/src/SMAPI.Web/Controllers/JsonValidatorController.cs +++ b/src/SMAPI.Web/Controllers/JsonValidatorController.cs @@ -90,21 +90,27 @@ namespace StardewModdingAPI.Web.Controllers // parse JSON JToken parsed; - try { - parsed = JToken.Parse(file.Content, new JsonLoadSettings + // load raw JSON + var settings = new JsonLoadSettings { DuplicatePropertyNameHandling = DuplicatePropertyNameHandling.Error, CommentHandling = CommentHandling.Load - }); - } - catch (JsonReaderException ex) - { - return this.View("Index", result.AddErrors(new JsonValidatorErrorModel(ex.LineNumber, ex.Path, ex.Message, ErrorType.None))); - } + }; + try + { + parsed = JToken.Parse(file.Content, settings); + } + catch (JsonReaderException ex) + { + return this.View("Index", result.AddErrors(new JsonValidatorErrorModel(ex.LineNumber, ex.Path, ex.Message, ErrorType.None))); + } - // format JSON - result.SetContent(parsed.ToString(Formatting.Indented), expiry: file.Expiry, uploadWarning: file.Warning); + // format JSON + string formatted = parsed.ToString(Formatting.Indented); + result.SetContent(formatted, expiry: file.Expiry, uploadWarning: file.Warning); + parsed = JToken.Parse(formatted); // update line number references + } // skip if no schema selected if (schemaName == "none") diff --git a/src/SMAPI.Web/Views/Mods/Index.cshtml b/src/SMAPI.Web/Views/Mods/Index.cshtml index 7dcd0718..5df49afb 100644 --- a/src/SMAPI.Web/Views/Mods/Index.cshtml +++ b/src/SMAPI.Web/Views/Mods/Index.cshtml @@ -45,7 +45,7 @@ else @if (hasBeta) { - <p id="beta-blurb" v-show="showAdvanced"><strong>Note:</strong> "@betaLabel" lines are for an unreleased version of SMAPI, not the stable version most players have. If a mod doesn't have that line, the info applies to both versions of SMAPI.</p> + <p id="beta-blurb"><strong>Note:</strong> "@betaLabel" lines are for the beta version of Stardew Valley, not the stable version most players have. If a mod doesn't have that line, the info applies to both versions.</p> } </div> @@ -99,7 +99,7 @@ else </td> <td> <div v-html="mod.Compatibility.Summary"></div> - <div v-if="mod.BetaCompatibility" v-show="showAdvanced"> + <div v-if="mod.BetaCompatibility"> <strong v-if="mod.BetaCompatibility">@betaLabel:</strong> <span v-html="mod.BetaCompatibility.Summary"></span> </div> diff --git a/src/SMAPI/Constants.cs b/src/SMAPI/Constants.cs index d0c693bf..fbc00d1d 100644 --- a/src/SMAPI/Constants.cs +++ b/src/SMAPI/Constants.cs @@ -54,7 +54,7 @@ namespace StardewModdingAPI internal static int? LogScreenId { get; set; } /// <summary>SMAPI's current raw semantic version.</summary> - internal static string RawApiVersion = "3.12.6"; + internal static string RawApiVersion = "3.12.7"; } /// <summary>Contains SMAPI's constants and assumptions.</summary> diff --git a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs index 63cd1759..38bcf153 100644 --- a/src/SMAPI/Framework/ContentManagers/GameContentManager.cs +++ b/src/SMAPI/Framework/ContentManagers/GameContentManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using System.Reflection; using Microsoft.Xna.Framework.Content; @@ -205,28 +206,35 @@ namespace StardewModdingAPI.Framework.ContentManagers /// <remarks>Derived from <see cref="LocalizedContentManager.Load{T}(string, LocalizedContentManager.LanguageCode)"/>.</remarks> private T RawLoad<T>(string assetName, LanguageCode language, bool useCache) { - // use cached key - if (language == this.Language && this.LocalizedAssetNames.TryGetValue(assetName, out string cachedKey)) - return base.RawLoad<T>(cachedKey, useCache); - - // try translated key - if (language != LocalizedContentManager.LanguageCode.en) + try { - string translatedKey = $"{assetName}.{this.GetLocale(language)}"; - try - { - T obj = base.RawLoad<T>(translatedKey, useCache); - this.LocalizedAssetNames[assetName] = translatedKey; - return obj; - } - catch (ContentLoadException) + // use cached key + if (language == this.Language && this.LocalizedAssetNames.TryGetValue(assetName, out string cachedKey)) + return base.RawLoad<T>(cachedKey, useCache); + + // try translated key + if (language != LocalizedContentManager.LanguageCode.en) { - this.LocalizedAssetNames[assetName] = assetName; + string translatedKey = $"{assetName}.{this.GetLocale(language)}"; + try + { + T obj = base.RawLoad<T>(translatedKey, useCache); + this.LocalizedAssetNames[assetName] = translatedKey; + return obj; + } + catch (ContentLoadException) + { + this.LocalizedAssetNames[assetName] = assetName; + } } - } - // try base asset - return base.RawLoad<T>(assetName, useCache); + // try base asset + return base.RawLoad<T>(assetName, useCache); + } + catch (ContentLoadException ex) when (ex.InnerException is FileNotFoundException innerEx && innerEx.InnerException == null) + { + throw new SContentLoadException($"Error loading \"{assetName}\": it isn't in the Content folder and no mod provided it."); + } } /// <summary>Parse an asset key that contains an explicit language into its asset name and language, if applicable.</summary> diff --git a/src/SMAPI/Framework/Logging/LogManager.cs b/src/SMAPI/Framework/Logging/LogManager.cs index 6fe44d98..f2876146 100644 --- a/src/SMAPI/Framework/Logging/LogManager.cs +++ b/src/SMAPI/Framework/Logging/LogManager.cs @@ -406,6 +406,10 @@ namespace StardewModdingAPI.Framework.Logging } } + // simplify exception messages + if (level == LogLevel.Error) + message = ExceptionHelper.SimplifyExtensionMessage(message); + // forward to monitor gameMonitor.Log(message, level); } diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs index 5913430e..86b69239 100644 --- a/src/SMAPI/Framework/SCore.cs +++ b/src/SMAPI/Framework/SCore.cs @@ -289,7 +289,7 @@ namespace StardewModdingAPI.Framework this.UpdateWindowTitles(); // start game - this.Monitor.Log("Starting game...", LogLevel.Debug); + this.Monitor.Log("Waiting for game to launch...", LogLevel.Debug); try { this.IsGameRunning = true; @@ -377,7 +377,7 @@ namespace StardewModdingAPI.Framework // load mods { - this.Monitor.Log("Loading mod metadata..."); + this.Monitor.Log("Loading mod metadata...", LogLevel.Debug); ModResolver resolver = new ModResolver(); // log loose files @@ -1487,7 +1487,7 @@ namespace StardewModdingAPI.Framework /// <param name="modDatabase">Handles access to SMAPI's internal mod metadata list.</param> private void LoadMods(IModMetadata[] mods, JsonHelper jsonHelper, ContentCoordinator contentCore, ModDatabase modDatabase) { - this.Monitor.Log("Loading mods..."); + this.Monitor.Log("Loading mods...", LogLevel.Debug); // load mods IList<IModMetadata> skippedMods = new List<IModMetadata>(); @@ -1523,6 +1523,7 @@ namespace StardewModdingAPI.Framework this.ReloadTranslations(loaded); // initialize loaded non-content-pack mods + this.Monitor.Log("Launching mods...", LogLevel.Debug); foreach (IModMetadata metadata in loadedMods) { // add interceptors @@ -1572,6 +1573,8 @@ namespace StardewModdingAPI.Framework // unlock mod integrations this.ModRegistry.AreAllModsInitialized = true; + + this.Monitor.Log("Mods loaded and ready!", LogLevel.Debug); } /// <summary>Raised after a mod adds or removes asset interceptors.</summary> @@ -1891,9 +1894,9 @@ namespace StardewModdingAPI.Framework string locale = Path.GetFileNameWithoutExtension(file.Name.ToLower().Trim()); try { - if (!jsonHelper.ReadJsonFileIfExists(file.FullName, out IDictionary<string, string> data)) + if (!jsonHelper.ReadJsonFileIfExists(file.FullName, out IDictionary<string, string> data) || data == null) { - errors.Add($"{file.Name} file couldn't be read"); // should never happen, since we're iterating files that exist + errors.Add($"{file.Name} file couldn't be read"); // mainly happens when the file is corrupted or empty continue; } diff --git a/src/SMAPI/Metadata/CoreAssetPropagator.cs b/src/SMAPI/Metadata/CoreAssetPropagator.cs index 708673c3..35ae26b3 100644 --- a/src/SMAPI/Metadata/CoreAssetPropagator.cs +++ b/src/SMAPI/Metadata/CoreAssetPropagator.cs @@ -414,6 +414,10 @@ namespace StardewModdingAPI.Metadata SpriteText.coloredTexture = content.Load<Texture2D>(key); return true; + case "loosesprites\\giftbox": // Game1.LoadContent + Game1.giftboxTexture = content.Load<Texture2D>(key); + return true; + case "loosesprites\\nightbg": // Game1.LoadContent Game1.nightbg = content.Load<Texture2D>(key); return true; |