using System.Collections.Generic;
using System.Linq;
using StardewModdingAPI.Framework.Reflection;
namespace StardewModdingAPI.Framework.ModHelpers
{
/// Provides metadata about installed mods.
internal class ModRegistryHelper : BaseHelper, IModRegistry
{
/*********
** Properties
*********/
/// The underlying mod registry.
private readonly ModRegistry Registry;
/// Encapsulates monitoring and logging for the mod.
private readonly IMonitor Monitor;
/// The mod IDs for APIs accessed by this instanced.
private readonly HashSet AccessedModApis = new HashSet();
/// Generates proxy classes to access mod APIs through an arbitrary interface.
private readonly InterfaceProxyFactory ProxyFactory;
/*********
** Public methods
*********/
/// Construct an instance.
/// The unique ID of the relevant mod.
/// The underlying mod registry.
/// Generates proxy classes to access mod APIs through an arbitrary interface.
/// Encapsulates monitoring and logging for the mod.
public ModRegistryHelper(string modID, ModRegistry registry, InterfaceProxyFactory proxyFactory, IMonitor monitor)
: base(modID)
{
this.Registry = registry;
this.ProxyFactory = proxyFactory;
this.Monitor = monitor;
}
/// Get metadata for all loaded mods.
public IEnumerable GetAll()
{
return this.Registry.GetAll().Select(p => p.Manifest);
}
/// Get metadata for a loaded mod.
/// The mod's unique ID.
/// Returns the matching mod's metadata, or null if not found.
public IManifest Get(string uniqueID)
{
return this.Registry.Get(uniqueID)?.Manifest;
}
/// Get whether a mod has been loaded.
/// The mod's unique ID.
public bool IsLoaded(string uniqueID)
{
return this.Registry.Get(uniqueID) != null;
}
/// 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 object GetApi(string uniqueID)
{
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}.", LogLevel.Trace);
return mod?.Api;
}
/// Get the API provided by a mod, mapped to a given interface which specifies the expected properties and methods. If the mod has no API or it's not compatible with the given interface, get null.
/// The interface which matches the properties and methods you intend to access.
/// The mod's unique ID.
public TInterface GetApi(string uniqueID) where TInterface : class
{
// validate
if (!this.Registry.AreAllModsInitialised)
{
this.Monitor.Log("Tried to access a mod-provided API before all mods were initialised.", LogLevel.Error);
return null;
}
if (!typeof(TInterface).IsInterface)
{
this.Monitor.Log($"Tried to map a mod-provided API to class '{typeof(TInterface).FullName}'; must be a public interface.", LogLevel.Error);
return null;
}
if (!typeof(TInterface).IsPublic)
{
this.Monitor.Log($"Tried to map a mod-provided API to non-public interface '{typeof(TInterface).FullName}'; must be a public interface.", LogLevel.Error);
return null;
}
// get raw API
object api = this.GetApi(uniqueID);
if (api == null)
return null;
// get API of type
if (api is TInterface castApi)
return castApi;
return this.ProxyFactory.CreateProxy(api, this.ModID, uniqueID);
}
}
}