diff --git a/release-notes.md b/release-notes.md
index ce91c693..b7f5f1f7 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -14,7 +14,8 @@ For mod developers:
See [log](https://github.com/Pathoschild/SMAPI/compare/1.13...1.13.1).
For players:
-* Fixed error when loading a mod with no version.
+* Fixed errors when loading a mod with no name or version.
+* Fixed mods with no manifest `Name` field having no name (SMAPI will now shows their filename).
## 1.13
See [log](https://github.com/Pathoschild/SMAPI/compare/1.12...1.13).
diff --git a/src/StardewModdingAPI.Tests/ModResolverTests.cs b/src/StardewModdingAPI.Tests/ModResolverTests.cs
index efa6fa06..8cf5a29e 100644
--- a/src/StardewModdingAPI.Tests/ModResolverTests.cs
+++ b/src/StardewModdingAPI.Tests/ModResolverTests.cs
@@ -5,6 +5,7 @@ using System.Linq;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
+using StardewModdingAPI.Framework;
using StardewModdingAPI.Framework.Models;
using StardewModdingAPI.Framework.ModLoading;
using StardewModdingAPI.Framework.Serialisation;
diff --git a/src/StardewModdingAPI/Framework/ModLoading/IModMetadata.cs b/src/StardewModdingAPI/Framework/IModMetadata.cs
similarity index 79%
rename from src/StardewModdingAPI/Framework/ModLoading/IModMetadata.cs
rename to src/StardewModdingAPI/Framework/IModMetadata.cs
index 3771ffdd..56ac25f1 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/IModMetadata.cs
+++ b/src/StardewModdingAPI/Framework/IModMetadata.cs
@@ -1,6 +1,7 @@
using StardewModdingAPI.Framework.Models;
+using StardewModdingAPI.Framework.ModLoading;
-namespace StardewModdingAPI.Framework.ModLoading
+namespace StardewModdingAPI.Framework
{
/// Metadata for a mod.
internal interface IModMetadata
@@ -26,6 +27,9 @@ namespace StardewModdingAPI.Framework.ModLoading
/// The reason the metadata is invalid, if any.
string Error { get; }
+ /// The mod instance (if it was loaded).
+ IMod Mod { get; }
+
/*********
** Public methods
@@ -35,5 +39,9 @@ namespace StardewModdingAPI.Framework.ModLoading
/// The reason the metadata is invalid, if any.
/// Return the instance for chaining.
IModMetadata SetStatus(ModMetadataStatus status, string error = null);
+
+ /// Set the mod instance.
+ /// The mod instance to set.
+ IModMetadata SetMod(IMod mod);
}
}
diff --git a/src/StardewModdingAPI/Framework/ModHelper.cs b/src/StardewModdingAPI/Framework/ModHelper.cs
index 7810148c..f939b83c 100644
--- a/src/StardewModdingAPI/Framework/ModHelper.cs
+++ b/src/StardewModdingAPI/Framework/ModHelper.cs
@@ -37,6 +37,7 @@ namespace StardewModdingAPI.Framework
** Public methods
*********/
/// Construct an instance.
+ /// The mod's display name.
/// The manifest for the associated mod.
/// The full path to the mod's folder.
/// Encapsulate SMAPI's JSON parsing.
@@ -46,7 +47,7 @@ namespace StardewModdingAPI.Framework
/// Simplifies access to private game code.
/// An argument is null or empty.
/// The path does not exist on disk.
- public ModHelper(IManifest manifest, string modDirectory, JsonHelper jsonHelper, IModRegistry modRegistry, CommandManager commandManager, SContentManager contentManager, IReflectionHelper reflection)
+ public ModHelper(string displayName, IManifest manifest, string modDirectory, JsonHelper jsonHelper, IModRegistry modRegistry, CommandManager commandManager, SContentManager contentManager, IReflectionHelper reflection)
{
// validate
if (string.IsNullOrWhiteSpace(modDirectory))
@@ -61,9 +62,9 @@ namespace StardewModdingAPI.Framework
// initialise
this.DirectoryPath = modDirectory;
this.JsonHelper = jsonHelper;
- this.Content = new ContentHelper(contentManager, modDirectory, manifest.Name);
+ this.Content = new ContentHelper(contentManager, modDirectory, displayName);
this.ModRegistry = modRegistry;
- this.ConsoleCommands = new CommandHelper(manifest.Name, commandManager);
+ this.ConsoleCommands = new CommandHelper(displayName, commandManager);
this.Reflection = reflection;
}
diff --git a/src/StardewModdingAPI/Framework/ModLoading/ModMetadata.cs b/src/StardewModdingAPI/Framework/ModLoading/ModMetadata.cs
index 7b25e090..ab590e10 100644
--- a/src/StardewModdingAPI/Framework/ModLoading/ModMetadata.cs
+++ b/src/StardewModdingAPI/Framework/ModLoading/ModMetadata.cs
@@ -26,6 +26,9 @@ namespace StardewModdingAPI.Framework.ModLoading
/// The reason the metadata is invalid, if any.
public string Error { get; private set; }
+ /// The mod instance (if it was loaded).
+ public IMod Mod { get; private set; }
+
/*********
** Public methods
@@ -53,5 +56,13 @@ namespace StardewModdingAPI.Framework.ModLoading
this.Error = error;
return this;
}
+
+ /// Set the mod instance.
+ /// The mod instance to set.
+ public IModMetadata SetMod(IMod mod)
+ {
+ this.Mod = mod;
+ return this;
+ }
}
}
diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs
index 3899aa3f..62063fbd 100644
--- a/src/StardewModdingAPI/Framework/ModRegistry.cs
+++ b/src/StardewModdingAPI/Framework/ModRegistry.cs
@@ -13,7 +13,7 @@ namespace StardewModdingAPI.Framework
** Properties
*********/
/// The registered mod data.
- private readonly List Mods = new List();
+ private readonly List Mods = new List();
/// The friendly mod names treated as deprecation warning sources (assembly full name => mod name).
private readonly IDictionary ModNamesByAssembly = new Dictionary();
@@ -28,7 +28,7 @@ namespace StardewModdingAPI.Framework
/// Get metadata for all loaded mods.
public IEnumerable GetAll()
{
- return this.Mods.Select(p => p.ModManifest);
+ return this.Mods.Select(p => p.Manifest);
}
/// Get metadata for a loaded mod.
@@ -50,15 +50,15 @@ namespace StardewModdingAPI.Framework
** Internal methods
****/
/// Register a mod as a possible source of deprecation warnings.
- /// The mod instance.
- public void Add(IMod mod)
+ /// The mod metadata.
+ public void Add(IModMetadata metadata)
{
- this.Mods.Add(mod);
- this.ModNamesByAssembly[mod.GetType().Assembly.FullName] = mod.ModManifest.Name;
+ this.Mods.Add(metadata);
+ this.ModNamesByAssembly[metadata.Mod.GetType().Assembly.FullName] = metadata.DisplayName;
}
/// Get all enabled mods.
- public IEnumerable GetMods()
+ public IEnumerable GetMods()
{
return (from mod in this.Mods select mod);
}
diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs
index ada05320..06523144 100644
--- a/src/StardewModdingAPI/Program.cs
+++ b/src/StardewModdingAPI/Program.cs
@@ -237,15 +237,15 @@ namespace StardewModdingAPI
this.IsDisposed = true;
// dispose mod data
- foreach (IMod mod in this.ModRegistry.GetMods())
+ foreach (IModMetadata mod in this.ModRegistry.GetMods())
{
try
{
- (mod as IDisposable)?.Dispose();
+ (mod.Mod as IDisposable)?.Dispose();
}
catch (Exception ex)
{
- this.Monitor.Log($"The {mod.ModManifest.Name} mod failed during disposal: {ex.GetLogSummary()}.", LogLevel.Warn);
+ this.Monitor.Log($"The {mod.DisplayName} mod failed during disposal: {ex.GetLogSummary()}.", LogLevel.Warn);
}
}
@@ -580,14 +580,15 @@ namespace StardewModdingAPI
// inject data
mod.ModManifest = manifest;
- mod.Helper = new ModHelper(manifest, metadata.DirectoryPath, jsonHelper, this.ModRegistry, this.CommandManager, contentManager, this.Reflection);
- mod.Monitor = this.GetSecondaryMonitor(manifest.Name);
+ mod.Helper = new ModHelper(metadata.DisplayName, manifest, metadata.DirectoryPath, jsonHelper, this.ModRegistry, this.CommandManager, contentManager, this.Reflection);
+ mod.Monitor = this.GetSecondaryMonitor(metadata.DisplayName);
mod.PathOnDisk = metadata.DirectoryPath;
// track mod
- this.ModRegistry.Add(mod);
+ metadata.SetMod(mod);
+ this.ModRegistry.Add(metadata);
modsLoaded += 1;
- this.Monitor.Log($"Loaded {manifest.Name} by {manifest.Author}, v{manifest.Version} | {manifest.Description}", LogLevel.Info);
+ this.Monitor.Log($"Loaded {metadata.DisplayName} by {manifest.Author}, v{manifest.Version} | {manifest.Description}", LogLevel.Info);
}
catch (Exception ex)
{
@@ -596,21 +597,23 @@ namespace StardewModdingAPI
}
// initialise loaded mods
- foreach (IMod mod in this.ModRegistry.GetMods())
+ foreach (IModMetadata metadata in this.ModRegistry.GetMods())
{
try
{
+ IMod mod = metadata.Mod;
+
// call entry methods
(mod as Mod)?.Entry(); // deprecated since 1.0
mod.Entry(mod.Helper);
// raise deprecation warning for old Entry() methods
if (this.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) }))
- deprecationWarnings.Add(() => this.DeprecationManager.Warn(mod.ModManifest.Name, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.Info));
+ deprecationWarnings.Add(() => this.DeprecationManager.Warn(metadata.DisplayName, $"{nameof(Mod)}.{nameof(Mod.Entry)}(object[]) instead of {nameof(Mod)}.{nameof(Mod.Entry)}({nameof(IModHelper)})", "1.0", DeprecationLevel.Info));
}
catch (Exception ex)
{
- this.Monitor.Log($"The {mod.ModManifest.Name} mod failed on entry initialisation. It will still be loaded, but may not function correctly.\n{ex.GetLogSummary()}", LogLevel.Warn);
+ this.Monitor.Log($"The {metadata.DisplayName} mod failed on entry initialisation. It will still be loaded, but may not function correctly.\n{ex.GetLogSummary()}", LogLevel.Warn);
}
}
diff --git a/src/StardewModdingAPI/StardewModdingAPI.csproj b/src/StardewModdingAPI/StardewModdingAPI.csproj
index 60171493..d8bfd473 100644
--- a/src/StardewModdingAPI/StardewModdingAPI.csproj
+++ b/src/StardewModdingAPI/StardewModdingAPI.csproj
@@ -122,7 +122,7 @@
-
+