--- sidebar_label: Getting Started sidebar_position: 2 --- # Getting Started This guide walks through building a minimal plugin from an empty project to a working drop-in that the launcher loads at startup. If you'd rather read finished code, the repository ships a complete reference plugin under `LANCommander.SamplePlugin` that exercises every extension point described here. ## Prerequisites - The .NET 10 SDK. - A local checkout of the LANCommander source, or a package/binary reference to the contract assemblies listed below. The framework binds plugins against the host's already-loaded assemblies, so you build against the same contract assemblies the host ships. ## 1. Create a class library A plugin is an ordinary class library targeting `net10.0`: ```bash dotnet new classlib -n MyCompany.MyPlugin -f net10.0 ``` ## 2. Reference the contract assemblies Reference the LANCommander assemblies that expose the extension points you need. Reference them with `Private=false` so your plugin binds against the host's already-loaded copies at runtime rather than shipping (and loading) its own duplicates: ```xml ``` :::note `Private=false` keeps the contract assemblies out of your plugin's output folder. This is important: the framework preserves type identity across the plugin's load context by deferring these shared assemblies to the host. Your plugin's *own* private dependencies (NuGet packages, helper libraries) should ship normally so they land next to your plugin's DLL. ::: ## 3. Implement the entry point Every plugin has a single entry point that implements [`IPlugin`](/Plugins/API%20Reference#iplugin). The two lifecycle methods map directly onto the host's "build the DI container once" model: - **`ConfigureServices`** runs while the host is still populating its service collection, *before* the provider is built. Only register services here — do not resolve them. - **`InitializeAsync`** runs *after* the provider is built. Resolve services, subscribe to events, and do any asynchronous startup work here. You receive a [`PluginContext`](/Plugins/API%20Reference#plugincontext) with the host identity, a scoped service provider, the plugin's directory, and a scoped logger. ```csharp using LANCommander.SDK.Plugins; using LANCommander.SDK.Plugins.Events; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace MyCompany.MyPlugin; public sealed class MyPlugin : IPlugin { public string Id => "com.mycompany.myplugin"; public string Name => "My Plugin"; public string Version => "1.0.0"; public string Author => "My Company"; private IDisposable? _launchSubscription; public void ConfigureServices(IServiceCollection services) { // Register anything you'll resolve later, or any extension point implementations. // e.g. services.AddSingleton(); } public Task InitializeAsync(PluginContext context, CancellationToken cancellationToken) { var events = context.Services.GetRequiredService(); _launchSubscription = events.Subscribe((evt, ct) => { context.Logger.LogInformation("Game {GameId} is about to launch", evt.GameId); return Task.CompletedTask; }); context.Logger.LogInformation("{Name} initialized on host {Host}", Name, context.Host); return Task.CompletedTask; } } ``` ## 4. Mark the assembly as a plugin Discovery is driven by an assembly-level [`[LANCommanderPlugin]`](/Plugins/API%20Reference#lancommanderpluginattribute) attribute. It names the entry point and declares compatibility metadata. Place it anywhere in your project (a common choice is above the `namespace` declaration in your entry point file): ```csharp using LANCommander.SDK.Plugins; [assembly: LANCommanderPlugin( typeof(MyCompany.MyPlugin.MyPlugin), Id = "com.mycompany.myplugin", MinHostVersion = "1.1.0", Hosts = PluginHost.Server | PluginHost.Launcher)] ``` - **`Id`** is optional; when omitted the loader falls back to the entry point's `IPlugin.Id`. - **`MinHostVersion` / `MaxHostVersion`** are optional SemVer bounds (inclusive). A plugin outside the host's version range is skipped. - **`Hosts`** declares which hosts the plugin supports. Defaults to both server and launcher. ## 5. Build and deploy Build your plugin and copy its output into a subfolder of LANCommander's `Plugins` directory. That directory lives inside LANCommander's data folder — `Data/Plugins` next to the executable, or under your user profile's application data if the install directory is not writable: ``` Data/ └── Plugins/ └── MyCompany.MyPlugin/ ├── MyCompany.MyPlugin.dll ├── MyCompany.MyPlugin.deps.json └── (your private dependencies) ``` The loader prefers an assembly named after the folder (`MyCompany.MyPlugin.dll` in the example above), so naming the folder after your main assembly is the most reliable convention. ## 6. Verify it loaded Start the host and check the logs. A successful load emits an entry like: ``` Loaded plugin 'My Plugin' (com.mycompany.myplugin) v1.0.0 by My Company ``` If your plugin does not appear, the logs will explain why — a missing `[LANCommanderPlugin]` attribute, an incompatible host version, a host it does not target, or an exception thrown during `ConfigureServices`. Every failure is isolated and logged rather than crashing the host. ## Next steps Now that your plugin loads, head to [Extension Points](/Plugins/Extension%20Points) to add real functionality, or browse the [API Reference](/Plugins/API%20Reference) for the complete surface.