Shared API
Shared API lets plugins expose typed interfaces that other plugins can consume at runtime.
Shared Interface Lifecycle
Shared API integration usually happens in three plugin callbacks:
ConfigureSharedInterface(IInterfaceManager): register interfaces your plugin providesUseSharedInterface(IInterfaceManager): retrieve interfaces from other pluginsOnSharedInterfaceInjected(IInterfaceManager): react after shared interfaces are injected
public override void ConfigureSharedInterface(IInterfaceManager interfaceManager)
{
// Register provider interfaces here.
}
public override void UseSharedInterface(IInterfaceManager interfaceManager)
{
// Resolve dependencies from other plugins here.
}
public override void OnSharedInterfaceInjected(IInterfaceManager interfaceManager)
{
// Optional: react when shared interfaces are re-injected.
}Providing Shared Interfaces
Use AddSharedInterface<TInterface, TImpl> in ConfigureSharedInterface.
public override void ConfigureSharedInterface(IInterfaceManager interfaceManager)
{
var economyApi = new EconomyApi();
interfaceManager.AddSharedInterface<IEconomyApi, EconomyApi>(
"Economy.Api.v1",
economyApi
);
}The provider plugin will provide to users a Contract assembly which will be used by consumer plugins as regular packages for the plugin.
The provider plugin will also need to add the Contract assembly file to the resources/exports.
Consuming Shared Interfaces
Preferred: TryGetSharedInterface
Use TryGetSharedInterface<TInterface> for optional dependencies.
private IEconomyApi? _economyApi;
public override void UseSharedInterface(IInterfaceManager interfaceManager)
{
if (!interfaceManager.TryGetSharedInterface<IEconomyApi>("Economy.Api.v1", out var economyApi))
{
Console.WriteLine("Economy API not available. Economy features disabled.");
_economyApi = null;
return;
}
_economyApi = economyApi;
}Required Dependency
If the dependency is mandatory, you can use GetSharedInterface<TInterface> directly.
IEconomyApi economyApi = interfaceManager.GetSharedInterface<IEconomyApi>("Economy.Api.v1");Availability Check
HasSharedInterface is useful when you only need a quick presence check.
bool hasEconomy = interfaceManager.HasSharedInterface("Economy.Api.v1");Complete Example
Shared Contract
namespace MyPlugin.Contracts;
public interface IEconomyApi
{
int GetBalance(ulong steamId);
bool TrySpend(ulong steamId, int amount);
}Provider Plugin
using MyPlugin.Contracts;
public sealed class EconomyApi : IEconomyApi
{
private readonly Dictionary<ulong, int> _balances = new();
public int GetBalance(ulong steamId)
{
return _balances.TryGetValue(steamId, out int balance) ? balance : 0;
}
public bool TrySpend(ulong steamId, int amount)
{
int current = GetBalance(steamId);
if (current < amount)
{
return false;
}
_balances[steamId] = current - amount;
return true;
}
}
public class EconomyPlugin : BasePlugin
{
private readonly EconomyApi _api = new();
public override void ConfigureSharedInterface(IInterfaceManager interfaceManager)
{
interfaceManager.AddSharedInterface<IEconomyApi, EconomyApi>("Economy.Api.v1", _api);
}
}Consumer Plugin
using MyPlugin.Contracts;
public class ShopPlugin : BasePlugin
{
private IEconomyApi? _economyApi;
public override void UseSharedInterface(IInterfaceManager interfaceManager)
{
interfaceManager.TryGetSharedInterface<IEconomyApi>("Economy.Api.v1", out _economyApi);
}
public void TryBuy(IPlayer player, int cost)
{
if (_economyApi == null)
{
player.PrintToChat("Economy service is unavailable.");
return;
}
if (!_economyApi.TrySpend(player.SteamID, cost))
{
player.PrintToChat("Not enough balance.");
return;
}
player.PrintToChat("Purchase successful.");
}
}Best Practices
- Use stable, descriptive keys such as
PluginName.ServiceName.v1. - Version keys for breaking changes, for example
Economy.Api.v1->Economy.Api.v2. - Prefer
TryGetSharedInterfacefor optional dependencies. - Keep shared contracts small and implementation-agnostic.
- If your shared API exposes events, reset or recreate provider instances on reconfiguration to avoid duplicate subscriptions.
Reference
See IInterfaceManager for shared interface manager methods.
See IPlugin and BasePlugin for plugin lifecycle callbacks.