Modding:Modder Guide/APIs/Integrations

From Stardew Valley Wiki
< Modding:Modder Guide‎ | APIs
Revision as of 00:10, 11 February 2020 by Pathoschild (talk | contribs) (correct intro)
Jump to navigation Jump to search

Creating SMAPI mods SMAPI mascot.png


Modding:Index

A mod integration refers to two mods communicating or cooperating in some way. SMAPI provides a few features to support this.

Dependencies

You can define dependencies in your manifest.json file, which are other mods that must be loaded before yours. If the dependency is required and missing, SMAPI will show a friendly error to the player. See the manifest page for more info.

Mod registry

Your mod can get information about loaded mods, or check if a particular mod is loaded. (All mods are loaded by the time your mod's Entry(…) method is called.)

// check if a mod is loaded
bool isLoaded = this.Helper.ModRegistry.IsLoaded("UniqueModID");

// get info for a mod
IModInfo mod = this.Helper.ModRegistry.Get("UniqueModID");
bool isContentPack = mod.IsContentPack;
IManifest manifest = mod.Manifest; // name, description, version, etc

// get info for all loaded mods
foreach(IModInfo mod in this.Helper.ModRegistry.GetAll()) {  }

Mod-provided APIs

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:

  1. Add a normal class to your mod project with the methods and properties you want to expose.
    public class YourModApi
    {
        public string ExampleProperty { get; set; } = "Example value";
    
        public bool GetThing(string example)
        {
           return true;
        }
    }
    
    (You can use a constructor to initialise the API if desired.)
  2. Override GetApi in your mod's entry class and return an instance of your API:
       public override object GetApi()
       {
          return new YourModApi();
       }
    

That's it! SMAPI will get one instance of your API and cache it.

Notes:

  • GetApi is always called after Entry, 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 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 interface:

  1. 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.)
    public interface ISomeModApi
    {
       bool GetThing(string example);
    }
    
  2. In your mod code (after Entry), you can get the API by specifying the interface you created in step 1, and the mod's unique ID:
    ISomeModApi api = helper.ModRegistry.GetApi<ISomeModApi>("other-mod-ID");
    if (api != null)
       bool result = api.GetThing("boop");
    

For a quick integration, you can also use reflection instead of creating an interface:

object api = helper.ModRegistry.GetApi("other-mod-id");
if (api != null)
   bool result = helper.Reflection.GetMethod(api, "GetThing").Invoke<bool>("boop");

Notes:

  • You can't call GetApi until all mods are initialised and their Entry methods called. You can use the GameLoop.GameLaunched 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. GetApi will return null 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.

Known limitations

  • When providing an API, the interface and implementation must be public.
  • When mapping an API to a custom interface using GetApi<T> (i.e. not using the mod's original interface), only the API interface itself can be proxied. Method return values and parameters must be types that both mods have access to (e.g. built-in types like bool, SMAPI types like IManifest, or game types like GameLocation).

Message sending

The following describes the upcoming SMAPI 3.3, and may change before release.

You can send messages using the multiplayer API, with a destination ranging from very narrow (e.g. one mod on one connected computer) to very broad (all mods on all computers). Messages can also be sent to the current computer, e.g. to communicate between two mods. This can be used for a variety of integrations.

For example:

  • Request something from a host mod. (Tractor Mod uses this to summon a tractor to the current player in multiplayer, even if the tractor isn't in a location synced to that player.)
  • Notify another mod about something. (Chests Anywhere uses this to notify Automate when a chest's automation options are edited.)