summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-03 21:17:40 -0400
committerJesse Plamondon-Willard <Pathoschild@users.noreply.github.com>2022-04-03 21:17:40 -0400
commita20413664bcf073f88bb37bc225e6f0bf7756495 (patch)
treeb26b017e642e5d155ef9112f79adf9bbd677fb4d
parentc9af1c452aeab89aa39e6e1521154a7fcc648f5a (diff)
downloadSMAPI-a20413664bcf073f88bb37bc225e6f0bf7756495.tar.gz
SMAPI-a20413664bcf073f88bb37bc225e6f0bf7756495.tar.bz2
SMAPI-a20413664bcf073f88bb37bc225e6f0bf7756495.zip
split mod content load method, make error-handling more consistent
-rw-r--r--src/SMAPI/Framework/ContentManagers/ModContentManager.cs187
1 files changed, 112 insertions, 75 deletions
diff --git a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
index a451fd7c..b3de273a 100644
--- a/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
+++ b/src/SMAPI/Framework/ContentManagers/ModContentManager.cs
@@ -93,97 +93,34 @@ namespace StardewModdingAPI.Framework.ContentManagers
if (this.Coordinator.TryParseManagedAssetKey(assetName.Name, out string contentManagerID, out IAssetName relativePath))
{
if (contentManagerID != this.Name)
- throw new SContentLoadException($"Can't load managed asset key '{assetName}' through content manager '{this.Name}' for a different mod.");
+ throw this.GetLoadError(assetName, "can't load a different mod's managed asset key through this mod content manager.");
assetName = relativePath;
}
}
// get local asset
- SContentLoadException GetContentError(string reasonPhrase) => new($"Failed loading asset '{assetName}' from {this.Name}: {reasonPhrase}");
T asset;
try
{
// get file
FileInfo file = this.GetModFile(assetName.Name);
if (!file.Exists)
- throw GetContentError("the specified path doesn't exist.");
+ throw this.GetLoadError(assetName, "the specified path doesn't exist.");
// load content
- switch (file.Extension.ToLower())
+ asset = file.Extension.ToLower() switch
{
- // XNB file
- case ".xnb":
- {
- // the underlying content manager adds a .xnb extension implicitly, so
- // we need to strip it here to avoid trying to load a '.xnb.xnb' file.
- IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length], allowLocales: false);
-
- // load asset
- asset = this.RawLoad<T>(loadName, useCache: false);
- if (asset is Map map)
- {
- map.assetPath = loadName.Name;
- this.FixTilesheetPaths(map, relativeMapPath: loadName.Name, fixEagerPathPrefixes: true);
- }
- }
- break;
-
- // unpacked Bitmap font
- case ".fnt":
- {
- string source = File.ReadAllText(file.FullName);
- asset = (T)(object)new XmlSource(source);
- }
- break;
-
- // unpacked data
- case ".json":
- {
- if (!this.JsonHelper.ReadJsonFileIfExists(file.FullName, out asset))
- throw GetContentError("the JSON file is invalid."); // should never happen since we check for file existence above
- }
- break;
-
- // unpacked image
- case ".png":
- {
- // validate
- if (typeof(T) != typeof(Texture2D))
- throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'.");
-
- // fetch & cache
- using FileStream stream = File.OpenRead(file.FullName);
-
- Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream);
- texture = this.PremultiplyTransparency(texture);
- asset = (T)(object)texture;
- }
- break;
-
- // unpacked map
- case ".tbin":
- case ".tmx":
- {
- // validate
- if (typeof(T) != typeof(Map))
- throw GetContentError($"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'.");
-
- // fetch & cache
- FormatManager formatManager = FormatManager.Instance;
- Map map = formatManager.LoadMap(file.FullName);
- map.assetPath = assetName.Name;
- this.FixTilesheetPaths(map, relativeMapPath: assetName.Name, fixEagerPathPrefixes: false);
- asset = (T)(object)map;
- }
- break;
-
- default:
- throw GetContentError($"unknown file extension '{file.Extension}'; must be one of '.fnt', '.json', '.png', '.tbin', or '.xnb'.");
- }
+ ".fnt" => this.LoadFont<T>(assetName, file),
+ ".json" => this.LoadDataFile<T>(assetName, file),
+ ".png" => this.LoadImageFile<T>(assetName, file),
+ ".tbin" or ".tmx" => this.LoadMapFile<T>(assetName, file),
+ ".xnb" => this.LoadXnbFile<T>(assetName),
+ _ => this.HandleUnknownFileType<T>(assetName, file)
+ };
}
- catch (Exception ex) when (!(ex is SContentLoadException))
+ catch (Exception ex) when (ex is not SContentLoadException)
{
- throw new SContentLoadException($"The content manager failed loading content asset '{assetName}' from {this.Name}.", ex);
+ throw this.GetLoadError(assetName, "an unexpected occurred.", ex);
}
// track & return asset
@@ -213,6 +150,106 @@ namespace StardewModdingAPI.Framework.ContentManagers
/*********
** Private methods
*********/
+ /// <summary>Load an unpacked font file (<c>.fnt</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadFont<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (!typeof(T).IsAssignableFrom(typeof(XmlSource)))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(XmlSource)}'.");
+
+ // load
+ string source = File.ReadAllText(file.FullName);
+ return (T)(object)new XmlSource(source);
+ }
+
+ /// <summary>Load an unpacked data file (<c>.json</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadDataFile<T>(IAssetName assetName, FileInfo file)
+ {
+ if (!this.JsonHelper.ReadJsonFileIfExists(file.FullName, out T asset))
+ throw this.GetLoadError(assetName, "the JSON file is invalid."); // should never happen since we check for file existence before calling this method
+
+ return asset;
+ }
+
+ /// <summary>Load an unpacked image file (<c>.json</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadImageFile<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (typeof(T) != typeof(Texture2D))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Texture2D)}'.");
+
+ // load
+ using FileStream stream = File.OpenRead(file.FullName);
+ Texture2D texture = Texture2D.FromStream(Game1.graphics.GraphicsDevice, stream);
+ texture = this.PremultiplyTransparency(texture);
+ return (T)(object)texture;
+ }
+
+ /// <summary>Load an unpacked image file (<c>.tbin</c> or <c>.tmx</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T LoadMapFile<T>(IAssetName assetName, FileInfo file)
+ {
+ // validate
+ if (typeof(T) != typeof(Map))
+ throw this.GetLoadError(assetName, $"can't read file with extension '{file.Extension}' as type '{typeof(T)}'; must be type '{typeof(Map)}'.");
+
+ // load
+ FormatManager formatManager = FormatManager.Instance;
+ Map map = formatManager.LoadMap(file.FullName);
+ map.assetPath = assetName.Name;
+ this.FixTilesheetPaths(map, relativeMapPath: assetName.Name, fixEagerPathPrefixes: false);
+ return (T)(object)map;
+ }
+
+ /// <summary>Load a packed file (<c>.xnb</c>).</summary>
+ /// <typeparam name="T">The type of asset to load.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ private T LoadXnbFile<T>(IAssetName assetName)
+ {
+ // the underlying content manager adds a .xnb extension implicitly, so
+ // we need to strip it here to avoid trying to load a '.xnb.xnb' file.
+ IAssetName loadName = this.Coordinator.ParseAssetName(assetName.Name[..^".xnb".Length], allowLocales: false);
+
+ // load asset
+ T asset = this.RawLoad<T>(loadName, useCache: false);
+ if (asset is Map map)
+ {
+ map.assetPath = loadName.Name;
+ this.FixTilesheetPaths(map, relativeMapPath: loadName.Name, fixEagerPathPrefixes: true);
+ }
+
+ return asset;
+ }
+
+ /// <summary>Handle a request to load a file type that isn't supported by SMAPI.</summary>
+ /// <typeparam name="T">The expected file type.</typeparam>
+ /// <param name="assetName">The asset name relative to the loader root directory.</param>
+ /// <param name="file">The file to load.</param>
+ private T HandleUnknownFileType<T>(IAssetName assetName, FileInfo file)
+ {
+ throw this.GetLoadError(assetName, $"unknown file extension '{file.Extension}'; must be one of '.fnt', '.json', '.png', '.tbin', '.tmx', or '.xnb'.");
+ }
+
+ /// <summary>Get an error which indicates that an asset couldn't be loaded.</summary>
+ /// <param name="assetName">The asset name that failed to load.</param>
+ /// <param name="reasonPhrase">The reason the file couldn't be loaded.</param>
+ /// <param name="exception">The underlying exception, if applicable.</param>
+ private SContentLoadException GetLoadError(IAssetName assetName, string reasonPhrase, Exception exception = null)
+ {
+ return new($"Failed loading asset '{assetName}' from {this.Name}: {reasonPhrase}", exception);
+ }
+
/// <summary>Get a file from the mod folder.</summary>
/// <param name="path">The asset path relative to the content folder.</param>
private FileInfo GetModFile(string path)