Skip to content

Getting started

You are embedding Hosihikari.PluginManager in a process you control. The manager gives you discovery, dependency ordering, isolation, and lifecycle; you supply the carrier services and decide when to start and stop.

If you only want to run plugins on a Bedrock server, use a carrier instead — the carriers are hosts that already do this.

Terminal window
dotnet add package Hosihikari.PluginManager

The manager targets .NET 10 and depends on Hosihikari.Plugin.Abstractions for the plugin contract.

using Hosihikari;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Information);
builder.AddSimpleConsole(options => options.SingleLine = true);
});
var services = new ServiceCollection()
.AddSingleton(loggerFactory)
.BuildServiceProvider();
var manager = new PluginManager(
pluginsRoot: Path.Combine(root, "plugins"),
dataRoot: Path.Combine(root, "data", "hosihikari"),
configRoot: Path.Combine(root, "config", "hosihikari"),
reportFault: entry => loggerFactory.CreateLogger("Hosihikari").LogError("Load problem: {Entry}", entry),
carrierServices: services,
onRemoved: name => { /* the plugin is gone; drop your own record of it */ });

The three roots are directories you own. The manager creates data/ and config/ subdirectories as needed; it does not create plugins/ for you, and a missing plugins/ means an empty plugin set.

  • reportFault receives problems that happen outside a plugin hook — a process that died, a protocol error, a package refused before load.
  • carrierServices is the IServiceProvider plugins reach through IPluginContext.CarrierServices. Put an ILoggerFactory in it: without one, plugins get a null logger and every line they write disappears silently.
  • onRemoved fires after a failed plugin has been unloaded, so you can remove it from your own registry.

The manager does not know how to load anything by itself. A loader is a plugin package that registers itself on load, and the built-in assembly loader handles precompiled DLLs:

manager.RegisterLoader(new AssemblyPluginLoader());
manager.LoadAll();

To support source plugins, install the loader package alongside the others and let it register itself; see Carrier services.

Pass PluginManagerOptions to the seven-argument constructor:

var options = new PluginManagerOptions
{
UnloadVerificationTimeout = TimeSpan.FromSeconds(60),
};
var manager = new PluginManager(pluginsRoot, dataRoot, configRoot, reportFault, carrierServices, onRemoved, options);

UnloadVerificationTimeout is the budget for confirming that a detached plugin was actually reclaimed. It defaults to 30 seconds. A finite value must be positive and no more than about 49.7 days; use Timeout.InfiniteTimeSpan for no timer. The timeout is one of the failure modes described in Lifecycle.

  • Carrier services — what the host must supply, and how loaders are registered.
  • Lifecycle — Load, Enable, Disable, Unload, and the status snapshot.
  • Events and callbacks — the event bus and the two callbacks back into your host.

Writing the plugins themselves is in Writing plugins.