diff --git a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
index 93ea6028..95eb03f3 100644
--- a/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
+++ b/src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using Nanoray.Pintail;
using StardewModdingAPI.Framework.Reflection;
namespace StardewModdingAPI.Framework.ModHelpers
@@ -17,10 +16,10 @@ namespace StardewModdingAPI.Framework.ModHelpers
private readonly IMonitor Monitor;
/// The mod IDs for APIs accessed by this instanced.
- private readonly HashSet AccessedModApis = new HashSet();
+ private readonly HashSet AccessedModApis = new();
/// Generates proxy classes to access mod APIs through an arbitrary interface.
- private readonly IProxyManager ProxyManager;
+ private readonly InterfaceProxyFactory ProxyFactory;
/*********
@@ -29,13 +28,13 @@ namespace StardewModdingAPI.Framework.ModHelpers
/// 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.
+ /// Generates proxy classes to access mod APIs through an arbitrary interface.
/// Encapsulates monitoring and logging for the mod.
- public ModRegistryHelper(string modID, ModRegistry registry, IProxyManager proxyManager, IMonitor monitor)
+ public ModRegistryHelper(string modID, ModRegistry registry, InterfaceProxyFactory proxyFactory, IMonitor monitor)
: base(modID)
{
this.Registry = registry;
- this.ProxyManager = proxyManager;
+ this.ProxyFactory = proxyFactory;
this.Monitor = monitor;
}
@@ -95,9 +94,9 @@ namespace StardewModdingAPI.Framework.ModHelpers
}
// get API of type
- if (api is TInterface castApi)
- return castApi;
- return this.ProxyManager.ObtainProxy(api, this.ModID, uniqueID);
+ return api is TInterface castApi
+ ? castApi
+ : this.ProxyFactory.CreateProxy(api, sourceModID: this.ModID, targetModID: uniqueID);
}
}
}
diff --git a/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
new file mode 100644
index 00000000..40adde8e
--- /dev/null
+++ b/src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs
@@ -0,0 +1,42 @@
+using System.Reflection;
+using System.Reflection.Emit;
+using Nanoray.Pintail;
+
+namespace StardewModdingAPI.Framework.Reflection
+{
+ /// Generates proxy classes to access mod APIs through an arbitrary interface.
+ internal class InterfaceProxyFactory
+ {
+ /*********
+ ** Fields
+ *********/
+ /// The underlying proxy type builder.
+ private readonly IProxyManager ProxyManager;
+
+
+ /*********
+ ** Public methods
+ *********/
+ /// Construct an instance.
+ public InterfaceProxyFactory()
+ {
+ AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"StardewModdingAPI.Proxies, Version={this.GetType().Assembly.GetName().Version}, Culture=neutral"), AssemblyBuilderAccess.Run);
+ ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("StardewModdingAPI.Proxies");
+ this.ProxyManager = new ProxyManager(moduleBuilder, new ProxyManagerConfiguration(
+ proxyPrepareBehavior: ProxyManagerProxyPrepareBehavior.Eager,
+ proxyObjectInterfaceMarking: ProxyObjectInterfaceMarking.Disabled
+ ));
+ }
+
+ /// Create an API proxy.
+ /// The interface through which to access the API.
+ /// The API instance to access.
+ /// The unique ID of the mod consuming the API.
+ /// The unique ID of the mod providing the API.
+ public TInterface CreateProxy(object instance, string sourceModID, string targetModID)
+ where TInterface : class
+ {
+ return this.ProxyManager.ObtainProxy(instance, targetContext: targetModID, proxyContext: sourceModID);
+ }
+ }
+}
diff --git a/src/SMAPI/Framework/SCore.cs b/src/SMAPI/Framework/SCore.cs
index 8f810644..342d6415 100644
--- a/src/SMAPI/Framework/SCore.cs
+++ b/src/SMAPI/Framework/SCore.cs
@@ -48,8 +48,6 @@ using xTile.Display;
using MiniMonoModHotfix = MonoMod.Utils.MiniMonoModHotfix;
using PathUtilities = StardewModdingAPI.Toolkit.Utilities.PathUtilities;
using SObject = StardewValley.Object;
-using Nanoray.Pintail;
-using System.Reflection.Emit;
namespace StardewModdingAPI.Framework
{
@@ -1490,17 +1488,12 @@ namespace StardewModdingAPI.Framework
{
// init
HashSet suppressUpdateChecks = new HashSet(this.Settings.SuppressUpdateChecks, StringComparer.OrdinalIgnoreCase);
- AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"StardewModdingAPI.Proxies, Version={this.GetType().Assembly.GetName().Version}, Culture=neutral"), AssemblyBuilderAccess.Run);
- ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("StardewModdingAPI.Proxies");
- IProxyManager proxyManager = new ProxyManager(moduleBuilder, new ProxyManagerConfiguration(
- proxyPrepareBehavior: ProxyManagerProxyPrepareBehavior.Eager,
- proxyObjectInterfaceMarking: ProxyObjectInterfaceMarking.Disabled
- ));
+ InterfaceProxyFactory proxyFactory = new();
// load mods
foreach (IModMetadata mod in mods)
{
- if (!this.TryLoadMod(mod, mods, modAssemblyLoader, proxyManager, jsonHelper, contentCore, modDatabase, suppressUpdateChecks, out ModFailReason? failReason, out string errorPhrase, out string errorDetails))
+ if (!this.TryLoadMod(mod, mods, modAssemblyLoader, proxyFactory, jsonHelper, contentCore, modDatabase, suppressUpdateChecks, out ModFailReason? failReason, out string errorPhrase, out string errorDetails))
{
failReason ??= ModFailReason.LoadFailed;
mod.SetStatus(ModMetadataStatus.Failed, failReason.Value, errorPhrase, errorDetails);
@@ -1603,7 +1596,7 @@ namespace StardewModdingAPI.Framework
/// The mod to load.
/// The mods being loaded.
/// Preprocesses and loads mod assemblies.
- /// Generates proxy classes to access mod APIs through an arbitrary interface.
+ /// Generates proxy classes to access mod APIs through an arbitrary interface.
/// The JSON helper with which to read mods' JSON files.
/// The content manager to use for mod content.
/// Handles access to SMAPI's internal mod metadata list.
@@ -1612,7 +1605,7 @@ namespace StardewModdingAPI.Framework
/// The user-facing reason phrase explaining why the mod couldn't be loaded (if applicable).
/// More detailed details about the error intended for developers (if any).
/// Returns whether the mod was successfully loaded.
- private bool TryLoadMod(IModMetadata mod, IModMetadata[] mods, AssemblyLoader assemblyLoader, IProxyManager proxyManager, JsonHelper jsonHelper, ContentCoordinator contentCore, ModDatabase modDatabase, HashSet suppressUpdateChecks, out ModFailReason? failReason, out string errorReasonPhrase, out string errorDetails)
+ private bool TryLoadMod(IModMetadata mod, IModMetadata[] mods, AssemblyLoader assemblyLoader, InterfaceProxyFactory proxyFactory, JsonHelper jsonHelper, ContentCoordinator contentCore, ModDatabase modDatabase, HashSet suppressUpdateChecks, out ModFailReason? failReason, out string errorReasonPhrase, out string errorDetails)
{
errorDetails = null;
@@ -1755,7 +1748,7 @@ namespace StardewModdingAPI.Framework
IContentPackHelper contentPackHelper = new ContentPackHelper(manifest.UniqueID, new Lazy(GetContentPacks), CreateFakeContentPack);
IDataHelper dataHelper = new DataHelper(manifest.UniqueID, mod.DirectoryPath, jsonHelper);
IReflectionHelper reflectionHelper = new ReflectionHelper(manifest.UniqueID, mod.DisplayName, this.Reflection);
- IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry, proxyManager, monitor);
+ IModRegistry modRegistryHelper = new ModRegistryHelper(manifest.UniqueID, this.ModRegistry, proxyFactory, monitor);
IMultiplayerHelper multiplayerHelper = new MultiplayerHelper(manifest.UniqueID, this.Multiplayer);
modHelper = new ModHelper(manifest.UniqueID, mod.DirectoryPath, () => this.GetCurrentGameInstance().Input, events, contentHelper, contentPackHelper, commandHelper, dataHelper, modRegistryHelper, reflectionHelper, multiplayerHelper, translationHelper);