diff options
-rw-r--r-- | src/SMAPI/Framework/ModHelpers/ModRegistryHelper.cs | 17 | ||||
-rw-r--r-- | src/SMAPI/Framework/Reflection/InterfaceProxyFactory.cs | 42 | ||||
-rw-r--r-- | src/SMAPI/Framework/SCore.cs | 17 |
3 files changed, 55 insertions, 21 deletions
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; /// <summary>The mod IDs for APIs accessed by this instanced.</summary> - private readonly HashSet<string> AccessedModApis = new HashSet<string>(); + private readonly HashSet<string> AccessedModApis = new(); /// <summary>Generates proxy classes to access mod APIs through an arbitrary interface.</summary> - private readonly IProxyManager<string> ProxyManager; + private readonly InterfaceProxyFactory ProxyFactory; /********* @@ -29,13 +28,13 @@ namespace StardewModdingAPI.Framework.ModHelpers /// <summary>Construct an instance.</summary> /// <param name="modID">The unique ID of the relevant mod.</param> /// <param name="registry">The underlying mod registry.</param> - /// <param name="proxyManager">Generates proxy classes to access mod APIs through an arbitrary interface.</param> + /// <param name="proxyFactory">Generates proxy classes to access mod APIs through an arbitrary interface.</param> /// <param name="monitor">Encapsulates monitoring and logging for the mod.</param> - public ModRegistryHelper(string modID, ModRegistry registry, IProxyManager<string> 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<string, TInterface>(api, this.ModID, uniqueID); + return api is TInterface castApi + ? castApi + : this.ProxyFactory.CreateProxy<TInterface>(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 +{ + /// <summary>Generates proxy classes to access mod APIs through an arbitrary interface.</summary> + internal class InterfaceProxyFactory + { + /********* + ** Fields + *********/ + /// <summary>The underlying proxy type builder.</summary> + private readonly IProxyManager<string> ProxyManager; + + + /********* + ** Public methods + *********/ + /// <summary>Construct an instance.</summary> + 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<string>(moduleBuilder, new ProxyManagerConfiguration<string>( + proxyPrepareBehavior: ProxyManagerProxyPrepareBehavior.Eager, + proxyObjectInterfaceMarking: ProxyObjectInterfaceMarking.Disabled + )); + } + + /// <summary>Create an API proxy.</summary> + /// <typeparam name="TInterface">The interface through which to access the API.</typeparam> + /// <param name="instance">The API instance to access.</param> + /// <param name="sourceModID">The unique ID of the mod consuming the API.</param> + /// <param name="targetModID">The unique ID of the mod providing the API.</param> + public TInterface CreateProxy<TInterface>(object instance, string sourceModID, string targetModID) + where TInterface : class + { + return this.ProxyManager.ObtainProxy<string, TInterface>(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<string> suppressUpdateChecks = new HashSet<string>(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<string> proxyManager = new ProxyManager<string>(moduleBuilder, new ProxyManagerConfiguration<string>( - 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 /// <param name="mod">The mod to load.</param> /// <param name="mods">The mods being loaded.</param> /// <param name="assemblyLoader">Preprocesses and loads mod assemblies.</param> - /// <param name="proxyManager">Generates proxy classes to access mod APIs through an arbitrary interface.</param> + /// <param name="proxyFactory">Generates proxy classes to access mod APIs through an arbitrary interface.</param> /// <param name="jsonHelper">The JSON helper with which to read mods' JSON files.</param> /// <param name="contentCore">The content manager to use for mod content.</param> /// <param name="modDatabase">Handles access to SMAPI's internal mod metadata list.</param> @@ -1612,7 +1605,7 @@ namespace StardewModdingAPI.Framework /// <param name="errorReasonPhrase">The user-facing reason phrase explaining why the mod couldn't be loaded (if applicable).</param> /// <param name="errorDetails">More detailed details about the error intended for developers (if any).</param> /// <returns>Returns whether the mod was successfully loaded.</returns> - private bool TryLoadMod(IModMetadata mod, IModMetadata[] mods, AssemblyLoader assemblyLoader, IProxyManager<string> proxyManager, JsonHelper jsonHelper, ContentCoordinator contentCore, ModDatabase modDatabase, HashSet<string> 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<string> 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<IContentPack[]>(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); |