From f7eda265d9dd11af7bc9ce2540d45ba2668e2345 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Thu, 22 Dec 2016 10:48:05 -0500 Subject: track loaded mod instances & manifests via mod registry (#201) --- src/StardewModdingAPI/Framework/ModRegistry.cs | 18 ++++++-- src/StardewModdingAPI/IMod.cs | 26 +++++++++++ src/StardewModdingAPI/Mod.cs | 2 +- src/StardewModdingAPI/Program.cs | 60 ++++++++++++++++---------- src/StardewModdingAPI/StardewModdingAPI.csproj | 1 + 5 files changed, 80 insertions(+), 27 deletions(-) create mode 100644 src/StardewModdingAPI/IMod.cs (limited to 'src') diff --git a/src/StardewModdingAPI/Framework/ModRegistry.cs b/src/StardewModdingAPI/Framework/ModRegistry.cs index ba56a447..b593142d 100644 --- a/src/StardewModdingAPI/Framework/ModRegistry.cs +++ b/src/StardewModdingAPI/Framework/ModRegistry.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; namespace StardewModdingAPI.Framework @@ -11,6 +12,9 @@ namespace StardewModdingAPI.Framework /********* ** Properties *********/ + /// The registered mod data. + 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(); @@ -19,11 +23,17 @@ namespace StardewModdingAPI.Framework ** Public methods *********/ /// Register a mod as a possible source of deprecation warnings. - /// The mod manifest. - /// The mod assembly. - public void Add(Manifest manifest, Assembly assembly) + /// The mod instance. + public void Add(IMod mod) + { + this.Mods.Add(mod); + this.ModNamesByAssembly[mod.GetType().Assembly.FullName] = mod.ModManifest.Name; + } + + /// Get all enabled mods. + public IEnumerable GetMods() { - this.ModNamesByAssembly[assembly.FullName] = manifest.Name; + return (from mod in this.Mods select mod); } /// Get the friendly name for the closest assembly registered as a source of deprecation warnings. diff --git a/src/StardewModdingAPI/IMod.cs b/src/StardewModdingAPI/IMod.cs new file mode 100644 index 00000000..35ac7c0f --- /dev/null +++ b/src/StardewModdingAPI/IMod.cs @@ -0,0 +1,26 @@ +namespace StardewModdingAPI +{ + /// The implementation for a Stardew Valley mod. + public interface IMod + { + /********* + ** Accessors + *********/ + /// Provides simplified APIs for writing mods. + IModHelper Helper { get; } + + /// Writes messages to the console and log file. + IMonitor Monitor { get; } + + /// The mod's manifest. + IManifest ModManifest { get; } + + + /********* + ** Public methods + *********/ + /// The mod entry point, called after the mod is first loaded. + /// Provides simplified APIs for writing mods. + void Entry(IModHelper helper); + } +} \ No newline at end of file diff --git a/src/StardewModdingAPI/Mod.cs b/src/StardewModdingAPI/Mod.cs index f0f876fa..d12a7e05 100644 --- a/src/StardewModdingAPI/Mod.cs +++ b/src/StardewModdingAPI/Mod.cs @@ -5,7 +5,7 @@ using StardewModdingAPI.Framework; namespace StardewModdingAPI { /// The base class for a mod. - public class Mod + public class Mod : IMod { /********* ** Properties diff --git a/src/StardewModdingAPI/Program.cs b/src/StardewModdingAPI/Program.cs index 8a87c15d..f2d7faa8 100644 --- a/src/StardewModdingAPI/Program.cs +++ b/src/StardewModdingAPI/Program.cs @@ -462,37 +462,53 @@ namespace StardewModdingAPI continue; } - // hook up mod + // get mod instance + Mod mod; try { + // get implementation TypeInfo modEntryType = modAssembly.DefinedTypes.First(x => x.BaseType == typeof(Mod)); - Mod modEntry = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); - if (modEntry != null) + mod = (Mod)modAssembly.CreateInstance(modEntryType.ToString()); + if (mod == null) { - // track mod - Program.ModRegistry.Add(manifest, modAssembly); - - // hook up mod - modEntry.ModManifest = manifest; - modEntry.Helper = helper; - modEntry.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; - modEntry.PathOnDisk = directory; - Program.Monitor.Log($"Loaded mod: {modEntry.ModManifest.Name} by {modEntry.ModManifest.Author}, v{modEntry.ModManifest.Version} | {modEntry.ModManifest.Description}", LogLevel.Info); - Program.ModsLoaded += 1; - modEntry.Entry(); // deprecated since 1.0 - modEntry.Entry((ModHelper)modEntry.Helper); // deprecated since 1.1 - modEntry.Entry(modEntry.Helper); // deprecated since 1.1 - - // raise deprecation warning for old Entry() method - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); - if (Program.DeprecationManager.IsVirtualMethodImplemented(modEntryType, typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) - Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + Program.Monitor.Log($"{errorPrefix}: the mod's entry class could not be instantiated."); + continue; } + + // inject data + mod.ModManifest = manifest; + mod.Helper = helper; + mod.Monitor = new Monitor(manifest.Name, Program.LogFile) { ShowTraceInConsole = Program.DeveloperMode }; + mod.PathOnDisk = directory; + + // track mod + Program.ModRegistry.Add(mod); + Program.ModsLoaded += 1; + Program.Monitor.Log($"Loaded mod: {manifest.Name} by {manifest.Author}, v{manifest.Version} | {manifest.Description}", LogLevel.Info); } catch (Exception ex) { Program.Monitor.Log($"{errorPrefix}: an error occurred while loading the target DLL.\n{ex.GetLogSummary()}", LogLevel.Error); + continue; + } + + // call mod entry + try + { + // call entry methods + mod.Entry(); // deprecated since 1.0 + mod.Entry((ModHelper)mod.Helper); // deprecated since 1.1 + mod.Entry(mod.Helper); + + // raise deprecation warning for old Entry() methods + if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(object[]) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.0", DeprecationLevel.Notice); + if (Program.DeprecationManager.IsVirtualMethodImplemented(mod.GetType(), typeof(Mod), nameof(Mod.Entry), new[] { typeof(ModHelper) })) + Program.DeprecationManager.Warn(manifest.Name, $"an old version of {nameof(Mod)}.{nameof(Mod.Entry)}", "1.1", DeprecationLevel.Notice); + } + catch (Exception ex) + { + Program.Monitor.Log($"The {manifest.Name} 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 cbcd9964..9dec9881 100644 --- a/src/StardewModdingAPI/StardewModdingAPI.csproj +++ b/src/StardewModdingAPI/StardewModdingAPI.csproj @@ -167,6 +167,7 @@ + -- cgit