add support for casting mod-provided API to an interface without a direct assembly reference (#409)

This commit is contained in:
Jesse Plamondon-Willard 2017-12-12 01:00:32 -05:00
parent d04cacbdd0
commit 0e43041777
6 changed files with 36 additions and 0 deletions

View File

@ -86,6 +86,7 @@
<Copy SourceFiles="$(TargetDir)\StardewModdingAPI.AssemblyRewriters.dll" DestinationFolder="$(GamePath)" /> <Copy SourceFiles="$(TargetDir)\StardewModdingAPI.AssemblyRewriters.dll" DestinationFolder="$(GamePath)" />
<Copy SourceFiles="$(TargetDir)\$(TargetName).pdb" DestinationFolder="$(GamePath)" /> <Copy SourceFiles="$(TargetDir)\$(TargetName).pdb" DestinationFolder="$(GamePath)" />
<Copy SourceFiles="$(TargetDir)\$(TargetName).xml" DestinationFolder="$(GamePath)" /> <Copy SourceFiles="$(TargetDir)\$(TargetName).xml" DestinationFolder="$(GamePath)" />
<Copy SourceFiles="$(TargetDir)\ImpromptuInterface.dll" DestinationFolder="$(GamePath)" />
<Copy SourceFiles="$(TargetDir)\Newtonsoft.Json.dll" DestinationFolder="$(GamePath)" /> <Copy SourceFiles="$(TargetDir)\Newtonsoft.Json.dll" DestinationFolder="$(GamePath)" />
<Copy SourceFiles="$(TargetDir)\Mono.Cecil.dll" DestinationFolder="$(GamePath)" /> <Copy SourceFiles="$(TargetDir)\Mono.Cecil.dll" DestinationFolder="$(GamePath)" />
</Target> </Target>

View File

@ -22,6 +22,7 @@
<Copy SourceFiles="$(TargetDir)\readme.txt" DestinationFiles="$(PackagePath)\README.txt" /> <Copy SourceFiles="$(TargetDir)\readme.txt" DestinationFiles="$(PackagePath)\README.txt" />
<!-- copy SMAPI files for Mono --> <!-- copy SMAPI files for Mono -->
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\ImpromptuInterface.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Mono.Cecil.dll" DestinationFolder="$(PackageInternalPath)\Mono" /> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Mono.Cecil.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Newtonsoft.Json.dll" DestinationFolder="$(PackageInternalPath)\Mono" /> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Newtonsoft.Json.dll" DestinationFolder="$(PackageInternalPath)\Mono" />
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.exe" DestinationFolder="$(PackageInternalPath)\Mono" /> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.exe" DestinationFolder="$(PackageInternalPath)\Mono" />
@ -36,6 +37,7 @@
<Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="@(CompiledMods)" DestinationFolder="$(PackageInternalPath)\Mono\Mods\%(RecursiveDir)" /> <Copy Condition="$(OS) != 'Windows_NT'" SourceFiles="@(CompiledMods)" DestinationFolder="$(PackageInternalPath)\Mono\Mods\%(RecursiveDir)" />
<!-- copy SMAPI files for Windows --> <!-- copy SMAPI files for Windows -->
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\ImpromptuInterface.dll" DestinationFolder="$(PackageInternalPath)\Windows" />
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Mono.Cecil.dll" DestinationFolder="$(PackageInternalPath)\Windows" /> <Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Mono.Cecil.dll" DestinationFolder="$(PackageInternalPath)\Windows" />
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Newtonsoft.Json.dll" DestinationFolder="$(PackageInternalPath)\Windows" /> <Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\Newtonsoft.Json.dll" DestinationFolder="$(PackageInternalPath)\Windows" />
<Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.exe" DestinationFolder="$(PackageInternalPath)\Windows" /> <Copy Condition="$(OS) == 'Windows_NT'" SourceFiles="$(CompiledSmapiPath)\StardewModdingAPI.exe" DestinationFolder="$(PackageInternalPath)\Windows" />

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ImpromptuInterface;
namespace StardewModdingAPI.Framework.ModHelpers namespace StardewModdingAPI.Framework.ModHelpers
{ {
@ -62,5 +63,28 @@ namespace StardewModdingAPI.Framework.ModHelpers
this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.", LogLevel.Trace); this.Monitor.Log($"Accessed mod-provided API for {mod.DisplayName}.", LogLevel.Trace);
return mod?.Api; return mod?.Api;
} }
/// <summary>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 <c>null</c>.</summary>
/// <typeparam name="TInterface">The interface which matches the properties and methods you intend to access.</typeparam>
/// <param name="uniqueID">The mod's unique ID.</param>
public TInterface GetApi<TInterface>(string uniqueID) where TInterface : class
{
// validate
if (!typeof(TInterface).IsInterface)
{
this.Monitor.Log("Tried to map a mod-provided API into a class; must be an interface.");
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 api.ActLike<TInterface>();
}
} }
} }

View File

@ -20,5 +20,10 @@ namespace StardewModdingAPI
/// <summary>Get the API provided by a mod, or <c>null</c> if it has none. This signature requires using the <see cref="IModHelper.Reflection"/> API to access the API's properties and methods.</summary> /// <summary>Get the API provided by a mod, or <c>null</c> if it has none. This signature requires using the <see cref="IModHelper.Reflection"/> API to access the API's properties and methods.</summary>
/// <param name="uniqueID">The mod's unique ID.</param> /// <param name="uniqueID">The mod's unique ID.</param>
object GetApi(string uniqueID); object GetApi(string uniqueID);
/// <summary>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 <c>null</c>.</summary>
/// <typeparam name="TInterface">The interface which matches the properties and methods you intend to access.</typeparam>
/// <param name="uniqueID">The mod's unique ID.</param>
TInterface GetApi<TInterface>(string uniqueID) where TInterface : class;
} }
} }

View File

@ -53,6 +53,9 @@
<ApplicationIcon>icon.ico</ApplicationIcon> <ApplicationIcon>icon.ico</ApplicationIcon>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="ImpromptuInterface, Version=6.2.2.0, Culture=neutral, PublicKeyToken=0b1781c923b2975b, processorArchitecture=MSIL">
<HintPath>..\packages\ImpromptuInterface.6.2.2\lib\net40\ImpromptuInterface.dll</HintPath>
</Reference>
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL"> <Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
<HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath> <HintPath>..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
<Private>True</Private> <Private>True</Private>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="ImpromptuInterface" version="6.2.2" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" /> <package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" /> <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net45" />
</packages> </packages>