summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-09-18 13:08:38 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2021-09-18 13:08:38 -0400
commitebe41180c41f544919c03fb3bf6029437a7d65a4 (patch)
tree0c5c0602bbee1fc96a024f3be1cd225d72d37fa0 /src
parentc5b8cd626489dad6210fe629658314dfc85f4d08 (diff)
parent6643da4574bec2d71ac9c25a2c9ab15b8c855e2b (diff)
downloadSMAPI-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.projitems2
-rw-r--r--src/SMAPI.Mods.ConsoleCommands/manifest.json4
-rw-r--r--src/SMAPI.Mods.ErrorHandler/manifest.json4
-rw-r--r--src/SMAPI.Mods.SaveBackup/manifest.json4
-rw-r--r--src/SMAPI.Toolkit/Serialization/Converters/SimpleReadOnlyConverter.cs7
-rw-r--r--src/SMAPI.Web/Controllers/JsonValidatorController.cs26
-rw-r--r--src/SMAPI.Web/Views/Mods/Index.cshtml4
-rw-r--r--src/SMAPI/Constants.cs2
-rw-r--r--src/SMAPI/Framework/ContentManagers/GameContentManager.cs44
-rw-r--r--src/SMAPI/Framework/Logging/LogManager.cs4
-rw-r--r--src/SMAPI/Framework/SCore.cs13
-rw-r--r--src/SMAPI/Metadata/CoreAssetPropagator.cs4
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;