Initial work on a way for mods to return specific API instances to specific mods.
This commit is contained in:
parent
e7d29a2f7d
commit
e8da8fff51
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using StardewModdingAPI.Framework.Reflection;
|
||||
using StardewModdingAPI.Internal;
|
||||
|
||||
namespace StardewModdingAPI.Framework.ModHelpers
|
||||
{
|
||||
|
@ -15,8 +17,8 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
|||
/// <summary>Encapsulates monitoring and logging for the mod.</summary>
|
||||
private readonly IMonitor Monitor;
|
||||
|
||||
/// <summary>The mod IDs for APIs accessed by this instanced.</summary>
|
||||
private readonly HashSet<string> AccessedModApis = new();
|
||||
/// <summary>The APIs accessed by this instance.</summary>
|
||||
private readonly Dictionary<string, object?> AccessedModApis = new();
|
||||
|
||||
/// <summary>Generates proxy classes to access mod APIs through an arbitrary interface.</summary>
|
||||
private readonly IInterfaceProxyFactory ProxyFactory;
|
||||
|
@ -66,11 +68,50 @@ namespace StardewModdingAPI.Framework.ModHelpers
|
|||
return null;
|
||||
}
|
||||
|
||||
// get raw API
|
||||
// get our cached API if one is available
|
||||
IModMetadata? mod = this.Registry.Get(uniqueID);
|
||||
if (mod?.Api != null && this.AccessedModApis.Add(mod.Manifest.UniqueID))
|
||||
this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.");
|
||||
return mod?.Api;
|
||||
if (mod == null)
|
||||
return null;
|
||||
|
||||
if (this.AccessedModApis.ContainsKey(mod.Manifest.UniqueID))
|
||||
{
|
||||
return this.AccessedModApis[mod.Manifest.UniqueID];
|
||||
}
|
||||
|
||||
object? api;
|
||||
|
||||
// safely request a specific API instance
|
||||
try
|
||||
{
|
||||
api = mod.Mod?.GetApi(this.Mod.Manifest);
|
||||
if (api != null && !api.GetType().IsPublic)
|
||||
{
|
||||
api = null;
|
||||
this.Monitor.Log($"{mod.DisplayName} provided a specific API instance with a non-public type. This isn't currently supported, so the specific API won't be available to the requesting mod.", LogLevel.Warn);
|
||||
}
|
||||
|
||||
if (api != null)
|
||||
this.Monitor.Log($"Accessed specific mod-provided API ({api.GetType().FullName}) for {mod.DisplayName}.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Monitor.Log($"Failed loading specific mod-provided API for {mod.DisplayName}. Integrations with other mods may not work. Error: {ex.GetLogSummary()}", LogLevel.Error);
|
||||
api = null;
|
||||
}
|
||||
|
||||
// fall back to the generic API instance
|
||||
if (api == null)
|
||||
{
|
||||
api = mod.Api;
|
||||
if (api != null)
|
||||
{
|
||||
this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.");
|
||||
}
|
||||
}
|
||||
|
||||
// cache the API instance and return it
|
||||
this.AccessedModApis[mod.Manifest.UniqueID] = api;
|
||||
return api;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
|
|
@ -25,5 +25,11 @@ namespace StardewModdingAPI
|
|||
|
||||
/// <summary>Get an API that other mods can access. This is always called after <see cref="Entry"/>.</summary>
|
||||
object? GetApi();
|
||||
|
||||
/// <summary>Get an API that a specific other mod can access. This method is called the first time the other mod calls <see cref="IModRegistry.GetApi(string)"/> for this mod.</summary>
|
||||
/// <param name="manifest">The other mod's manifest.</param>
|
||||
/// <returns>Returns an API for another mod, or <c>null</c> if the other mod should use the general API returned from <see cref="GetApi()"/>.</returns>
|
||||
object? GetApi(IManifest manifest);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,12 @@ namespace StardewModdingAPI
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual object? GetApi(IManifest manifest)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>Release or reset unmanaged resources.</summary>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue