diff --git a/src/SMAPI/Framework/IModMetadata.cs b/src/SMAPI/Framework/IModMetadata.cs
index c4be7daf..a36994fd 100644
--- a/src/SMAPI/Framework/IModMetadata.cs
+++ b/src/SMAPI/Framework/IModMetadata.cs
@@ -31,7 +31,7 @@ namespace StardewModdingAPI.Framework
IMod Mod { get; }
/// The mod-provided API (if any).
- IModProvidedApi Api { get; }
+ object Api { get; }
/*********
@@ -45,7 +45,10 @@ namespace StardewModdingAPI.Framework
/// Set the mod instance.
/// The mod instance to set.
- /// The mod-provided API (if any).
- IModMetadata SetMod(IMod mod, IModProvidedApi api);
+ IModMetadata SetMod(IMod mod);
+
+ /// Set the mod-provided API instance.
+ /// The mod-provided API.
+ IModMetadata SetApi(object api);
}
}
diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
index 340205f3..949d986a 100644
--- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
@@ -47,7 +47,7 @@ namespace StardewModdingAPI.Framework.ModHelpers
}
/// Get the API provided by a mod, or null if it has none. This signature requires using the API to access the API's properties and methods.
- public IModProvidedApi GetApi(string uniqueID)
+ public object GetApi(string uniqueID)
{
return this.Registry.Get(uniqueID)?.Api;
}
diff --git a/src/SMAPI/Framework/ModLoading/ModMetadata.cs b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
index 2e5c27be..30fe211b 100644
--- a/src/SMAPI/Framework/ModLoading/ModMetadata.cs
+++ b/src/SMAPI/Framework/ModLoading/ModMetadata.cs
@@ -30,7 +30,7 @@ namespace StardewModdingAPI.Framework.ModLoading
public IMod Mod { get; private set; }
/// The mod-provided API (if any).
- public IModProvidedApi Api { get; private set; }
+ public object Api { get; private set; }
/*********
@@ -62,10 +62,16 @@ namespace StardewModdingAPI.Framework.ModLoading
/// Set the mod instance.
/// The mod instance to set.
- /// The mod-provided API (if any).
- public IModMetadata SetMod(IMod mod, IModProvidedApi api)
+ public IModMetadata SetMod(IMod mod)
{
this.Mod = mod;
+ return this;
+ }
+
+ /// Set the mod-provided API instance.
+ /// The mod-provided API.
+ public IModMetadata SetApi(object api)
+ {
this.Api = api;
return this;
}
diff --git a/src/SMAPI/IMod.cs b/src/SMAPI/IMod.cs
index 35ac7c0f..44ef32c9 100644
--- a/src/SMAPI/IMod.cs
+++ b/src/SMAPI/IMod.cs
@@ -1,4 +1,4 @@
-namespace StardewModdingAPI
+namespace StardewModdingAPI
{
/// The implementation for a Stardew Valley mod.
public interface IMod
@@ -22,5 +22,8 @@
/// The mod entry point, called after the mod is first loaded.
/// Provides simplified APIs for writing mods.
void Entry(IModHelper helper);
+
+ /// Get an API that other mods can access. This is always called after .
+ object GetApi();
}
-}
\ No newline at end of file
+}
diff --git a/src/SMAPI/IModProvidedApi.cs b/src/SMAPI/IModProvidedApi.cs
deleted file mode 100644
index 9884ca78..00000000
--- a/src/SMAPI/IModProvidedApi.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace StardewModdingAPI
-{
- /// An API provided by a mod for other mods to use.
- /// This is a marker interface. Each mod can only have one implementation of .
- public interface IModProvidedApi { }
-}
diff --git a/src/SMAPI/IModRegistry.cs b/src/SMAPI/IModRegistry.cs
index fd71d72a..f84cfcfb 100644
--- a/src/SMAPI/IModRegistry.cs
+++ b/src/SMAPI/IModRegistry.cs
@@ -19,6 +19,6 @@ namespace StardewModdingAPI
/// Get the API provided by a mod, or null if it has none. This signature requires using the API to access the API's properties and methods.
/// The mod's unique ID.
- IModProvidedApi GetApi(string uniqueID);
+ object GetApi(string uniqueID);
}
}
diff --git a/src/SMAPI/Mod.cs b/src/SMAPI/Mod.cs
index ee75ba54..3a753afc 100644
--- a/src/SMAPI/Mod.cs
+++ b/src/SMAPI/Mod.cs
@@ -25,6 +25,9 @@ namespace StardewModdingAPI
/// Provides simplified APIs for writing mods.
public abstract void Entry(IModHelper helper);
+ /// Get an API that other mods can access. This is always called after .
+ public virtual object GetApi() => null;
+
/// Release or reset unmanaged resources.
public void Dispose()
{
diff --git a/src/SMAPI/Program.cs b/src/SMAPI/Program.cs
index 6330cc1a..e7552630 100644
--- a/src/SMAPI/Program.cs
+++ b/src/SMAPI/Program.cs
@@ -711,11 +711,9 @@ namespace StardewModdingAPI
modHelper = new ModHelper(manifest.UniqueID, metadata.DirectoryPath, jsonHelper, contentHelper, commandHelper, modRegistryHelper, reflectionHelper, translationHelper);
}
- // get mod instances
+ // get mod instance
if (!this.TryLoadModEntry(modAssembly, error => TrackSkip(metadata, error), out Mod mod))
continue;
- if (this.TryLoadModProvidedApi(modAssembly, modHelper, monitor, error => this.Monitor.Log($"Failed loading {metadata.DisplayName}'s mod-provided API. Integrations may not work correctly. Error: {error}", LogLevel.Warn), out IModProvidedApi api))
- this.Monitor.Log($" Found mod-provided API ({api.GetType().FullName}).", LogLevel.Trace);
// init mod
mod.ModManifest = manifest;
@@ -723,7 +721,7 @@ namespace StardewModdingAPI
mod.Monitor = monitor;
// track mod
- metadata.SetMod(mod, api);
+ metadata.SetMod(mod);
this.ModRegistry.Add(metadata);
}
catch (Exception ex)
@@ -796,6 +794,19 @@ namespace StardewModdingAPI
{
this.Monitor.Log($"{metadata.DisplayName} failed on entry and might not work correctly. Technical details:\n{ex.GetLogSummary()}", LogLevel.Error);
}
+
+ // get mod API
+ try
+ {
+ object api = metadata.Mod.GetApi();
+ if (api != null)
+ this.Monitor.Log($" Found mod-provided API ({api.GetType().FullName}).", LogLevel.Trace);
+ metadata.SetApi(api);
+ }
+ catch (Exception ex)
+ {
+ this.Monitor.Log($"Failed loading mod-provided API for {metadata.DisplayName}. Integrations with other mods may not work. Error: {ex.GetLogSummary()}", LogLevel.Error);
+ }
}
// invalidate cache entries when needed
@@ -865,73 +876,6 @@ namespace StardewModdingAPI
return true;
}
- /// Load a mod's implementation.
- /// The mod assembly.
- /// The mod's helper instance.
- /// The mod's monitor instance.
- /// A callback invoked when loading fails.
- /// The loaded instance.
- private bool TryLoadModProvidedApi(Assembly modAssembly, IModHelper modHelper, IMonitor monitor, Action onError, out IModProvidedApi api)
- {
- api = null;
-
- // find type
- TypeInfo[] apis = modAssembly.DefinedTypes.Where(type => typeof(IModProvidedApi).IsAssignableFrom(type) && !type.IsAbstract).Take(2).ToArray();
- if (apis.Length == 0)
- return false;
- if (apis.Length > 1)
- {
- onError($"its DLL contains multiple '{nameof(IModProvidedApi)}' implementations.");
- return false;
- }
-
- // get constructor
- ConstructorInfo constructor = (
- from constr in apis[0].GetConstructors()
- let args = constr.GetParameters()
- where
- !args.Any()
- || args.All(arg => typeof(IModHelper).IsAssignableFrom(arg.ParameterType) || typeof(IMonitor).IsAssignableFrom(arg.ParameterType))
- orderby args.Length descending
- select constr
- ).FirstOrDefault();
- if (constructor == null)
- {
- onError($"its {nameof(IModProvidedApi)} must have a constructor with zero arguments, or only arguments of type {nameof(IModHelper)} or {nameof(IMonitor)}.");
- return false;
- }
-
- // construct instance
- try
- {
- // prepare constructor args
- ParameterInfo[] args = constructor.GetParameters();
- object[] values = new object[args.Length];
- for (int i = 0; i < args.Length; i++)
- {
- if (typeof(IModHelper).IsAssignableFrom(args[i].ParameterType))
- values[i] = modHelper;
- else if (typeof(IMonitor).IsAssignableFrom(args[i].ParameterType))
- values[i] = monitor;
- else
- {
- // shouldn't happen
- onError($"its {nameof(IModProvidedApi)} instance's constructor has unexpected argument type {args[i].ParameterType.FullName}.");
- return false;
- }
- }
-
- // instantiate
- api = (IModProvidedApi)constructor.Invoke(values);
- return true;
- }
- catch (Exception ex)
- {
- onError($"its {nameof(IModProvidedApi)} couldn't be constructed: {ex.GetLogSummary()}");
- return false;
- }
- }
-
/// Reload translations for all mods.
private void ReloadTranslations()
{
diff --git a/src/SMAPI/StardewModdingAPI.csproj b/src/SMAPI/StardewModdingAPI.csproj
index 579ed487..0db94843 100644
--- a/src/SMAPI/StardewModdingAPI.csproj
+++ b/src/SMAPI/StardewModdingAPI.csproj
@@ -114,7 +114,6 @@
-