Getting Started
Install the Plugin Template
With the .NET 10.0 SDK installed and dotnet on your PATH, install the plugin template, then run it with your plugin's details:
dotnet new install SwiftlyS2.CS2.PluginTemplate
dotnet new swplugin -n MyPlugin --PluginName "My Plugin" --PluginVersion "1.0.0" --PluginAuthor "Author" --PluginDescription "My first SwiftlyS2 plugin"-n becomes the plugin's Id, namespace, class name, assembly name and
output folder. The other flags only fill in APIPluginMetadata
and can be edited afterwards.
Generated project layout:
MyPlugin/
├── examples/
│ ├── Commands.example.cs
│ ├── Events.example.cs
│ ├── GameEvents.example.cs
│ ├── HookAndCallNativeFunctions.example.cs
│ ├── NetMessage.example.cs
│ └── SoundEvent.example.cs
├── resources/
│ ├── gamedata/
│ │ ├── offsets.jsonc
│ │ ├── patches.jsonc
│ │ └── signatures.jsonc
│ ├── templates/
│ └── translations/
│ └── en.jsonc
├── MyPlugin.cs
├── MyPlugin.csproj
└── README.md
examples/ is excluded from compilation by default (<Compile Remove="examples\**\*.cs" />) - it's reference material, not part of your plugin.
Main plugin class:
using SwiftlyS2.Shared.Plugins;
using SwiftlyS2.Shared;
namespace MyPlugin;
[PluginMetadata(Id = "MyPlugin", Version = "1.0.0", Name = "My Plugin", Author = "Author", Description = "My first SwiftlyS2 plugin")]
public partial class MyPlugin : BasePlugin
{
public MyPlugin(ISwiftlyCore core) : base(core)
{
}
public override void Load(bool hotReload)
{
}
public override void Unload()
{
}
}ConfigureSharedInterface/UseSharedInterface on APIBasePlugin (see Shared API) can be overridden the same way once you need them.
resources/gamedata, resources/templates and resources/translations
copy to the output directory on build. Each plugin manages its own
resources/gamedata, independently from others.
A freshly generated project may not reference the latest release - bump it in your .csproj if needed: <PackageReference Include="SwiftlyS2.CS2" Version="*" ExcludeAssets="runtime" PrivateAssets="all" />. * tracks latest stable; pin a version (e.g. 1.0.3) for reproducible builds, or use *-* for preview releases.
Publishing
dotnet publishThis outputs the packaged plugin to build/publish/<PluginId>/ and a ready-to-share build/<AssemblyName>.zip alongside it.
To test locally, copy build/publish/<PluginId>/ into your server's addons/swiftlys2/plugins/<PluginId>/. Use the .zip for releases.
Next Steps
The template's examples/ folder covers commands, core events, game events, native function hooking, net messages and sound events - the rest of this Development section covers each system in more depth. Read the Dependency Injection guide before writing logic, since SwiftlyS2 plugins favor constructor-based DI over static/global state.