SwiftlyS2
Development

Shared API

The Shared API allows plugins to expose interfaces that other plugins can consume, enabling inter-plugin communication and functionality sharing.

Overview

The Shared API system consists of two main methods in your plugin:

  • ConfigureSharedInterface: Register interfaces that your plugin provides to others
  • UseSharedInterface: Consume interfaces that other plugins have registered

Providing Shared Interfaces

To make your plugin's functionality available to other plugins, override the ConfigureSharedInterface method:

public override void ConfigureSharedInterface(IInterfaceManager interfaceManager) {
    // Register your shared interfaces here
}

Adding a Shared Interface

Use AddSharedInterface to register an interface implementation:

interfaceManager.AddSharedInterface<IMyService, MyServiceImpl>("MyPlugin.MyService", new MyServiceImpl());

Parameters:

  • TInterface: The interface type (must be defined in a contracts DLL)
  • TImpl: The implementation class
  • key: A unique string identifier for this interface
  • implInstance: The instance of your implementation

The interface must be defined in a separate contracts DLL that can be referenced by both the provider and consumer plugins.

Consuming Shared Interfaces

To use interfaces provided by other plugins, override the UseSharedInterface method:

public override void UseSharedInterface(IInterfaceManager interfaceManager) {
    // Get shared interfaces from other plugins here
}

Checking if an Interface Exists

Before consuming an interface, you can check if it's available:

if (interfaceManager.HasSharedInterface("MyPlugin.MyService")) {
    // Interface is available
}

Getting a Shared Interface

Use GetSharedInterface to retrieve an interface implementation:

var myService = interfaceManager.GetSharedInterface<IMyService>("MyPlugin.MyService");

Complete Example

Here's a complete example showing how two plugins can communicate via the Shared API.

1. Create a Contracts Project

First, create a shared contracts DLL that both plugins will reference:

// File: MyPlugin.Contracts/IEconomyService.cs
namespace MyPlugin.Contracts;

public interface IEconomyService {
    int GetPlayerBalance(int playerId);
    void AddPlayerBalance(int playerId, int amount);
    bool RemovePlayerBalance(int playerId, int amount);
}

The contract DLL must be put inside resources/exports folder of the plugin.

2. Provider Plugin (Economy Plugin)

The plugin that provides the functionality:

// File: EconomyPlugin/EconomyService.cs
using MyPlugin.Contracts;

namespace EconomyPlugin;

public class EconomyService : IEconomyService {
    private Dictionary<int, int> _balances = new();

    public int GetPlayerBalance(int playerId) {
        return _balances.TryGetValue(playerId, out var balance) ? balance : 0;
    }

    public void AddPlayerBalance(int playerId, int amount) {
        _balances[playerId] = GetPlayerBalance(playerId) + amount;
    }

    public bool RemovePlayerBalance(int playerId, int amount) {
        var currentBalance = GetPlayerBalance(playerId);
        if (currentBalance < amount) return false;

        _balances[playerId] = currentBalance - amount;
        return true;
    }
}

// File: EconomyPlugin/Plugin.cs
public class Plugin : SwiftlyPlugin {
    public override void ConfigureSharedInterface(IInterfaceManager interfaceManager) {
        var economyService = new EconomyService();
        interfaceManager.AddSharedInterface<IEconomyService, EconomyService>(
            "Economy.Service",
            economyService
        );
    }
}

3. Consumer Plugin (Shop Plugin)

The plugin that consumes the economy functionality:

// File: ShopPlugin/Plugin.cs
using MyPlugin.Contracts;

public class Plugin : SwiftlyPlugin {
    private IEconomyService? _economyService;

    public override void UseSharedInterface(IInterfaceManager interfaceManager) {
        if (interfaceManager.HasSharedInterface("Economy.Service")) {
            _economyService = interfaceManager.GetSharedInterface<IEconomyService>("Economy.Service");
            Console.WriteLine("Successfully connected to Economy service!");
        } else {
            Console.WriteLine("Warning: Economy plugin not found!");
        }
    }

    public void BuyItem(int playerId, int itemPrice) {
        if (_economyService == null) {
            Console.WriteLine("Economy service not available!");
            return;
        }

        var balance = _economyService.GetPlayerBalance(playerId);
        if (balance < itemPrice) {
            Console.WriteLine("Insufficient funds!");
            return;
        }

        if (_economyService.RemovePlayerBalance(playerId, itemPrice)) {
            Console.WriteLine("Item purchased successfully!");
        }
    }
}

Best Practices

Clear Events

If your API contains events that can be registered by other plugins, make sure to set them to null or create a new API object to provide to the interfaceManager each time ConfigureSharedInterface is called. Otherwise, events may be registered multiple times.

Ensure Your Interface Inherits IDisposable

In most cases, we recommend making your interface disposable and adding disposed checks. When a shared interface is unloaded, the framework will automatically call the dispose method of each shared interface (if it inherits IDisposable), which ensures that deprecated API objects are not used incorrectly.

Use Descriptive Keys

Use a consistent naming convention for interface keys:

// Good: Plugin name + service description
"EconomyPlugin.CurrencyService"
"PermissionsPlugin.AuthService"

// Avoid: Generic or ambiguous names
"Service"
"API"

Handle Missing Dependencies

Always check if an interface exists before using it:

public override void UseSharedInterface(IInterfaceManager interfaceManager) {
    if (!interfaceManager.HasSharedInterface("Economy.Service")) {
        Console.WriteLine("Warning: Economy plugin is not loaded!");
        // Provide fallback behavior or disable features
        return;
    }

    _economyService = interfaceManager.GetSharedInterface<IEconomyService>("Economy.Service");
}

Version Your Interfaces

Consider versioning your interface keys if you plan to make breaking changes:

interfaceManager.AddSharedInterface<IEconomyServiceV2, EconomyServiceV2>(
    "Economy.Service.v2",
    new EconomyServiceV2()
);

Store Shared Interfaces in Fields

Store retrieved interfaces in class fields for easy access throughout your plugin:

public class Plugin : SwiftlyPlugin {
    private IEconomyService? _economy;
    private IPermissionsService? _permissions;

    public override void UseSharedInterface(IInterfaceManager interfaceManager) {
        _economy = interfaceManager.GetSharedInterface<IEconomyService>("Economy.Service");
        _permissions = interfaceManager.GetSharedInterface<IPermissionsService>("Permissions.Service");
    }
}

Reference

See IInterfaceManager for more details.

On this page