Line 810: |
Line 810: |
| | | |
| Note that game versions before 1.2.0 and some mod versions are non-standard (e.g. Stardew Valley 1.11 comes ''before'' 1.2). All SMAPI versions are standard. | | Note that game versions before 1.2.0 and some mod versions are non-standard (e.g. Stardew Valley 1.11 comes ''before'' 1.2). All SMAPI versions are standard. |
| + | |
| + | ==Mod-provided APIs== |
| + | {{SMAPI upcoming |
| + | |version = 2.3 |
| + | |content = Mods can provide their own APIs to other mods, even without a dependency or assembly reference. This can be used to integrate mods, provide custom information, or provide new framework APIs beyond those offered by SMAPI itself. |
| + | |
| + | ===Providing an API=== |
| + | To provide an API for other mods to use: |
| + | <ol> |
| + | <li>Add a normal class to your mod project with the methods and properties you want to expose. |
| + | <source lang="c#"> |
| + | internal class YourModApi |
| + | { |
| + | public string ExampleProperty { get; set; } = "Example value"; |
| + | |
| + | public bool GetThing(string example) |
| + | { |
| + | return true; |
| + | } |
| + | } |
| + | </source> |
| + | (You can use a [https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors constructor] to initialise the API if desired.)</li> |
| + | <li>Override <tt>GetApi</tt> in your mod's entry class and return an instance of your API: |
| + | <source lang="c#"> |
| + | public override object GetApi() |
| + | { |
| + | return new YourModApi(); |
| + | } |
| + | </source></li> |
| + | </ol> |
| + | |
| + | That's it! SMAPI will get one instance of your API and cache it. |
| + | |
| + | Notes: |
| + | * <tt>GetApi</tt> is always called after <tt>Entry</tt>, so it's safe to pass in your mod's initialised fields. |
| + | * Be careful when changing your API! If you make a breaking change, other mods may need an update before they can access your API again. |
| + | * You can optionally add a public [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface interface] to your API. If a mod directly references your mod DLL, they'll be able to use your interface instead of creating their own. |
| + | |
| + | ===Using an API=== |
| + | You can use a mod-provided API by mapping it to an [https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/interface interface]: |
| + | <ol> |
| + | <li>Create an interface with only the properties and methods you want to access. (If you directly reference the mod DLL and it provides a public API interface, you can use that instead.) |
| + | <source lang="C#"> |
| + | internal interface ISomeModApi |
| + | { |
| + | bool GetThing(string example); |
| + | } |
| + | </source></li> |
| + | <li>In your mod code (after <tt>Entry</tt>), you can get the API by specifying the interface you created in step 1, and the [[#Basic fields|mod's unique ID]]: |
| + | <source lang="c#"> |
| + | ISomeModApi api = helper.ModRegistry.GetApi<ISomeModApi>("other-mod-ID"); |
| + | if (api != null) |
| + | bool result = api.GetThing("boop"); |
| + | </source></li> |
| + | </ol> |
| + | |
| + | For a quick integration, you can also use reflection instead of creating an interface: |
| + | <source lang="c#"> |
| + | object api = helper.ModRegistry.GetApi("other-mod-id"); |
| + | if (api != null) |
| + | bool result = helper.Reflection.GetMethod(api, "GetThing").Invoke<bool>("boop"); |
| + | </source> |
| + | |
| + | Notes: |
| + | * You can't call <tt>GetApi</tt> until all mods are initialised and their <tt>Entry</tt> methods called. You can use the <tt>GameEvents.FirstUpdateTick</tt> [[#Events|event]] if you need to access mod APIs early; this is guaranteed to happen after all mods are initialised. |
| + | * You should always null-check APIs you consume. <tt>GetApi</tt> will return <tt>null</tt> if the API isn't available (e.g. because the mod isn't already installed or doesn't have one), or if an error occurs fetching the API. |
| + | }} |
| | | |
| [[Category:Modding]] | | [[Category:Modding]] |