Creating Your First RocketMod Plugin
RocketMod plugins are dynamic-link libraries written in C# that extend an Unturned™ dedicated server with custom commands, event handlers, and server-side logic. RocketMod is the legacy plugin framework for Unturned™, and it remains widely deployed on production servers. This article walks through creating a complete plugin from scratch — project setup, code structure, building, and deployment — with no prior plugin development experience assumed beyond basic C# familiarity.
The 57 Studios™ team has been writing RocketMod plugins for internally-managed servers since 2022. The patterns documented here reflect what actually works in production, not just what the API reference says.

Prerequisites
- A working Unturned™ dedicated server with RocketMod installed (see RocketMod and OpenMod Plugin Basics).
- Visual Studio 2022 Community Edition or later, with the .NET desktop development workload.
- Access to the server's
Unturned_Data/Managed/directory (or the server'sModules/Rocket.Unturned/directory) to extract reference DLLs. - Basic C# knowledge: classes, methods, interfaces, namespaces.
What you will learn
- How to set up a Visual Studio project targeting RocketMod.
- How RocketMod discovers and loads plugins at server startup.
- The minimum structure a RocketMod plugin needs to compile and load.
- How to add a configuration class and a command class.
- How to build and deploy the plugin to a live server.
- How to verify the plugin loaded correctly.
Understanding the plugin base class
RocketPlugin is the base class for all plugins. A plugin class inherits from RocketPlugin and implements the lifecycle methods that RocketMod calls at server startup, shutdown, and reload. Every plugin is a single assembly (.dll) placed in the Rocket/Plugins/ directory on the server.
When RocketMod starts, it scans Rocket/Plugins/ for assemblies that contain classes inheriting from RocketPlugin. It instantiates each one and calls its Load() method. If the class also implements a configuration type, RocketMod deserializes the configuration from an XML file before calling Load(). The base class provides Configuration and Translations instances that the plugin uses at runtime.
Why a generic parameter matters
RocketPlugin accepts a generic type parameter [TConfig] that tells RocketMod which configuration class to deserialize. Without it, the plugin has no configuration file and cannot persist settings across server restarts. Although it is technically possible to write RocketPlugin without the generic and do manual file I/O, doing so abandons RocketMod's built-in serialization, change-detection, and automatic file creation. Every production plugin uses RocketPlugin[TConfig].
csharp
using Rocket.API;
using Rocket.Core.Plugins;
namespace MyFirstPlugin
{
public class MyFirstPlugin : RocketPlugin<MyFirstPluginConfiguration>
{
protected override void Load()
{
Rocket.Core.Logging.Logger.Log("[MyFirstPlugin] Loaded successfully.");
}
protected override void Unload()
{
Rocket.Core.Logging.Logger.Log("[MyFirstPlugin] Unloaded.");
}
}
}Project structure
A RocketMod plugin project on disk has this layout:
MyFirstPlugin/
├── MyFirstPlugin.csproj
├── MyFirstPlugin.cs
├── MyFirstPluginConfiguration.cs
├── Commands/
│ └── HelloCommand.cs
└── libs/
├── Rocket.API.dll
├── Rocket.Core.dll
├── Rocket.Unturned.dll
└── Assembly-CSharp.dllThe libs/ folder is a local copy of the reference DLLs extracted from the server. You do not submit libs/ to source control — each developer copies the DLLs from their own server's installation.
Reference DLLs explained
| DLL | Source location on server | What it provides |
|---|---|---|
Rocket.API.dll | Modules/Rocket.Unturned/ or Rocket/Libraries/ | Interfaces: IRocketPlugin, IRocketCommand, IRocketPlayer, IRocketPluginConfiguration |
Rocket.Core.dll | Same location | Base classes: RocketPlugin<TConfig>, RocketPluginManager, logging, translation, permission checking |
Rocket.Unturned.dll | Same location | Unturned-specific wrappers: UnturnedPlayer, UnturnedChat, UnturnedPlayerEvents, UnturnedServer |
Assembly-CSharp.dll | Unturned_Data/Managed/ | Unturned's own game code; needed when your plugin accesses raw Unturned API types |
Always reference DLLs with <Private>false</Private> so they are not copied into the build output. The server already has them in its own directories.
Setting up the Visual Studio project
Step 1: Create a new Class Library project
Open Visual Studio and create a new project using the Class Library template targeting .NET Framework 4.7.2. Name it MyFirstPlugin. Visual Studio generates a Class1.cs that you can delete.
Step 2: Set the target framework
Edit MyFirstPlugin.csproj to match the RocketMod target:
xml
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net472</TargetFramework>
<AssemblyName>MyFirstPlugin</AssemblyName>
<RootNamespace>MyFirstPlugin</RootNamespace>
</PropertyGroup>
<ItemGroup>
<Reference Include="Rocket.API">
<HintPath>libs\Rocket.API.dll</HintPath>
[Private]false[/Private]
</Reference>
<Reference Include="Rocket.Core">
<HintPath>libs\Rocket.Core.dll</HintPath>
[Private]false[/Private]
</Reference>
<Reference Include="Rocket.Unturned">
<HintPath>libs\Rocket.Unturned.dll</HintPath>
[Private]false[/Private]
</Reference>
<Reference Include="Assembly-CSharp">
<HintPath>libs\Assembly-CSharp.dll</HintPath>
[Private]false[/Private]
</Reference>
</ItemGroup>
</Project>If your server runs on a different .NET Framework version (some older hosts use 4.6.1), verify the version by checking the Rocket.API.dll assembly metadata or asking the host provider.
Step 3: Extract reference DLLs from the server
On your server, copy these files from Modules/Rocket.Unturned/ into the project's libs/ folder:
Rocket.API.dllRocket.Core.dllRocket.Unturned.dll
Then copy Assembly-CSharp.dll from Unturned_Data/Managed/ into the same libs/ folder.
DLL version mismatch
The most common build failure in RocketMod plugin development happens when a developer builds against DLLs from their local Unturned installation and then deploys to a production server running a different Unturned version. Always extract the DLLs from the target server, not from your development machine. The Assembly-CSharp.dll version changes with every Unturned update, and mismatches produce MethodNotFoundException or MissingMethodException at runtime.
Writing the plugin class
The plugin class is the entry point that RocketMod instantiates when the plugin loads. Create MyFirstPlugin.cs:
Namespace note
RocketMod's API interfaces live in the Rocket.API.Commands namespace. The RocketPlugin<TConfig> base class is in Rocket.Core.Plugins. Add using directives for both, plus Rocket.Unturned.Events if you subscribe to Unturned events.
csharp
using Rocket.API.Commands;
using Rocket.Core.Plugins;
using Rocket.Unturned.Events;
using Rocket.Unturned.Player;
using UnityEngine;
namespace MyFirstPlugin
{
public class MyFirstPlugin : RocketPlugin<MyFirstPluginConfiguration>
{
public static MyFirstPlugin Instance { get; private set; }
protected override void Load()
{
Instance = this;
UnturnedPlayerEvents.OnPlayerConnected += OnPlayerConnected;
Rocket.Core.Logging.Logger.Log(
$"[MyFirstPlugin] Loaded. Greeting: {Configuration.Instance.GreetingMessage}");
}
protected override void Unload()
{
UnturnedPlayerEvents.OnPlayerConnected -= OnPlayerConnected;
Instance = null;
Rocket.Core.Logging.Logger.Log("[MyFirstPlugin] Unloaded.");
}
private void OnPlayerConnected(UnturnedPlayer player)
{
player.SendChat(
Configuration.Instance.GreetingMessage, Color.green);
}
}
}The Instance singleton
The public static MyFirstPlugin Instance property is the standard RocketMod pattern for exposing the plugin instance to other classes — especially command classes, which are separate classes that implement IRocketCommand. Without the singleton, command classes would have no way to access the plugin's configuration, event handlers, or shared state.
Set Instance = this at the end of Load() after all initialization is done so that command code never accesses a half-initialized singleton. Set Instance = null in Unload() so that any stale reference from a command that fires during unloading throws a clear NullReferenceException rather than silently operating on dead state.
Writing the configuration class
Configuration classes implement IRocketPluginConfiguration and declare public fields. RocketMod serializes them to XML automatically.
csharp
using Rocket.API;
namespace MyFirstPlugin
{
public class MyFirstPluginConfiguration : IRocketPluginConfiguration
{
public string GreetingMessage { get; set; }
public void LoadDefaults()
{
GreetingMessage = "Welcome to the server!";
}
}
}Configuration lifecycle
- On first load, RocketMod detects that no configuration file exists for the plugin.
- It calls
LoadDefaults()on a fresh instance. - It serializes the default values to
Rocket/Plugins/MyFirstPlugin/MyFirstPlugin.configuration.xml. - On subsequent loads, it deserializes the XML back into the class.
- The plugin reads the values through
Configuration.Instance.PropertyName.
The LoadDefaults() method must set every public field to a sensible default. If a field is left at its C# default (zero, null, false), the first-time user sees a null greeting message or a zero cooldown. Always set explicit defaults.
Configuration properties
| Data type | XML serialization | Example |
|---|---|---|
string | Element with text content | <GreetingMessage>Welcome!</GreetingMessage> |
int / float | Same pattern | <MaxPlayers>32</MaxPlayers> |
bool | Same pattern | <EnableLogging>true</EnableLogging> |
List<string> | Array of elements | <Items><Item>one</Item><Item>two</Item></Items> |
| Nested objects | Nested elements | <SubConfig><Field>value</Field></SubConfig> |
RocketMod's XML serializer expects public fields or public auto-properties with both getter and setter. Do not use read-only properties, private fields, or List<T> without a public setter — they will serialize but never deserialize, and the default values persist silently.
Editing the configuration file on the server
After the plugin has loaded once, the configuration file appears at:
Rocket/Plugins/MyFirstPlugin/MyFirstPlugin.configuration.xmlOpen it in Notepad++ to edit values:
xml
<?xml version="1.0" encoding="utf-8"?>
<MyFirstPluginConfiguration>
<GreetingMessage>Welcome to the server!</GreetingMessage>
</MyFirstPluginConfiguration>Changes take effect after a server restart or /rocket reload MyFirstPlugin. The plugin must call Configuration.Save() if it modifies values at runtime, or the changes are lost on the next reload.
Writing a command
Commands in RocketMod are separate classes that implement the IRocketCommand interface. Create Commands/HelloCommand.cs:
csharp
using Rocket.API.Commands;
using Rocket.Unturned.Chat;
using System.Collections.Generic;
namespace MyFirstPlugin.Commands
{
public class HelloCommand : IRocketCommand
{
public string Name => "hello";
public string Help => "Displays a greeting from the plugin.";
public string Syntax => "/hello";
public List<string> Aliases => new List<string> { "hi", "hey" };
public string[] Permissions => new string[] { };
public AllowedCaller AllowedCaller => AllowedCaller.Player;
public void Execute(IRocketPlayer caller, string[] command)
{
UnturnedChat.Say(
caller,
MyFirstPlugin.Instance.Configuration.Instance.GreetingMessage);
}
}
}The IRocketCommand interface
| Member | Type | Purpose |
|---|---|---|
Name | string | The primary command keyword. Players type /hello to invoke it. |
Help | string | Short description shown in /help listings. |
Syntax | string | Usage instructions shown in /help hello. |
Aliases | List<string> | Alternative keywords that also invoke the command. |
Permissions | List<string> | Required permissions. Empty list = anyone can use it. |
AllowedCaller | AllowedCaller | Who can run this command — Player, Console, or Both. |
Execute | void | The code that runs when the command is invoked. |
All commands in the plugin's assembly are automatically discovered by RocketMod's command manager. There is no manual registration step. The command discovery scans every class that implements IRocketCommand in the plugin's assembly and registers it with the command name taken from the Name property.
Command aliases
The Aliases list provides alternative names for the command. In the example above, /hi and /hey both trigger HelloCommand. Aliases share the same permissions, help text, and syntax as the primary name. If you need different behavior under a different name, write a separate command class.
AllowedCaller explained
The AllowedCaller property controls execution context:
Player— the command only runs when invoked by a connected player from in-game chat. Calling it from the server console produces an automatic "this command can only be used by players" error.Console— the command only runs from the server console. Calling it from in-game does nothing. This is useful for administrative commands that should not be exposed to players.Both— the command runs from both the in-game chat and the server console. Use this for commands that are safe in both contexts, but always null-check thecallerparameter becauseIRocketPlayerfrom the console is a different implementation than from a player.
Building and deploying
Build the project
In Visual Studio, build the solution in Release mode. The output is MyFirstPlugin.dll in bin/Release/net472/.
Deploy to the server
- Copy
MyFirstPlugin.dllto the server'sRocket/Plugins/directory. - If your plugin references external DLLs not already on the server, copy them to
Rocket/Libraries/. - Restart the server, or run
/rocket reload MyFirstPluginfrom the server console.
Verify the plugin loaded
Check the server console output for:
[MyFirstPlugin] Loaded. Greeting: Welcome to the server!If the plugin did not load, check Rocket/Rocket.log for errors. The log file records assembly resolution failures, missing dependencies, and exceptions thrown during Load(). Common failure modes:
| Log message | Likely cause |
|---|---|
Could not load file or assembly 'Rocket.API' | Missing reference DLL in Rocket/Libraries/ |
Method not found: 'Void RocketPlugin.Load()' | DLL compiled against a different RocketMod version |
Plugin MyFirstPlugin failed to load | Exception thrown in Load() before logging the success message |
No parameterless constructor defined for MyFirstPlugin | The plugin class is missing a public default constructor |
Hot-reloading
After the initial deployment, you can rebuild and recopy the DLL without restarting the server:
- Build the project in Release mode.
- Copy the new
MyFirstPlugin.dlltoRocket/Plugins/, overwriting the old one. - Run
/rocket reload MyFirstPluginfrom the server console.
RocketMod unloads the old plugin assembly, loads the new one, and calls Load(). This works for most plugins, but if the plugin allocates unmanaged resources or holds file handles, a full server restart after several reload cycles is recommended to release orphaned resources.
Testing the command
- Join the server as a player.
- Type
/helloin the chat. - The server responds with "Welcome to the server!" in green text.
If nothing happens, check these in order:
- Is the plugin listed in
/rocket plugins? If no, the DLL did not load. - Does the command name match the
Nameproperty? Typing/hellomatchesName = "hello". - Is
AllowedCallerset toPlayerorBoth? If it isConsole, the in-game chat ignores the command. - Are any required permissions set? An empty
Permissionslist means no restriction. If the list has entries, the calling player must have one of them assigned through the permission system.
Adding translations
RocketMod supports per-plugin translation files for messages that appear to players. Translations live in Rocket/Translations/MyFirstPlugin/English.xml:
xml
<?xml version="1.0" encoding="utf-8"?>
<Translations>
<Translation Id="command_hello">Hello, {0}! Welcome to the server.</Translation>
<Translation Id="player_joined">{0} joined the server.</Translation>
</Translations>Load translations in your plugin:
csharp
string message = Translate("command_hello", caller.DisplayName);
UnturnedChat.Say(caller, message);The Translate() method is inherited from RocketPlugin<TConfig>. It looks up the translation ID in the current language file and formats the string with the provided arguments. If the translation ID is not found, it returns the ID itself so you see the missing key in the console output.
Translation files are loaded when the plugin loads and cached in memory. A /rocket reload refreshes them from disk. There is no hot-reload for individual translation entries — if you edit the XML file on a live server, the plugin sees the old values until the next reload.
Common mistakes
Building against the wrong .NET version
RocketMod targets .NET Framework 4.7.2. If your project targets .NET 6.0, .NET Core, or .NET Standard, the assembly does not load. Check the TargetFramework in the .csproj file. The correct value is net472.
Forgetting to set Private to false
When reference DLLs have <Private>true</Private>, the build system copies them into the output directory. If you then copy the entire bin/Release/net472/ folder to the server, you overwrite the server's own DLLs with potentially different versions. Set <Private>false</Private> on every RocketMod reference.
Missing LoadDefaults in configuration
If LoadDefaults() is empty or omitted, every configuration field is null, 0, or false on first load. The configuration file is still created, but every value is the C# default. Always populate every field in LoadDefaults().
Case sensitivity in command names
RocketMod's command lookup is case-insensitive. /Hello, /HELLO, and /hello all match the same Name = "hello". This is intentional, but it means you cannot create two commands whose names differ only by case — the second one silently overwrites the first.
Complete reference: minimum working plugin
The shortest plugin that compiles, loads, and does something observable:
csharp
using Rocket.API.Commands;
using Rocket.Core.Plugins;
namespace MinimalPlugin
{
public class MinimalPlugin : RocketPlugin<MinimalPluginConfiguration>
{
protected override void Load()
{
Rocket.Core.Logging.Logger.Log("[MinimalPlugin] Alive.");
}
protected override void Unload()
{
Rocket.Core.Logging.Logger.Log("[MinimalPlugin] Dead.");
}
}
public class MinimalPluginConfiguration : IRocketPluginConfiguration
{
public void LoadDefaults() { }
}
}This plugin has no commands and no event subscriptions. It logs on load and unload. It validates that your project setup, DLL references, and deployment path are all working before you write real logic.
Next steps
Now that you have a working plugin, the next article covers the plugin lifecycle in detail — what happens between Load and Unload, how RocketMod manages plugin state, and the events that fire around lifecycle transitions.
- Plugin Lifecycle — deep dive into Load, Unload, Reload, and the events that surround them.
- RocketMod and OpenMod Plugin Basics — back to the framework overview if you need more context before continuing.
Debugging plugin load failures
When a plugin fails to load, the server's Rocket/Rocket.log is the primary diagnostic tool. The log records every assembly load attempt, every plugin initialization, and every exception thrown during the lifecycle.
Common load failure patterns
| Log entry | Cause | Fix |
|---|---|---|
Could not load file or assembly 'Rocket.API' or one of its dependencies | The reference DLLs | |
are missing from the server's Rocket/Libraries/ or the plugin was built with | ||
<Private>true</Private> and the local DLLs were copied to the server | Copy the correct DLLs | |
from Modules/Rocket.Unturned/ to the server and rebuild with <Private>false</Private> | ||
Method not found: 'Void RocketPlugin.Load()' | The plugin was compiled against a different | |
| RocketMod version than the server has | Rebuild against DLLs extracted from the production server | |
Plugin MyFirstPlugin failed to load: System.NullReferenceException | Something in | |
Load() threw a null reference — likely Configuration.Instance or U.Instance accessed | ||
| before initialization | Check Load() for operations that depend on not-yet-initialized services | |
No parameterless constructor defined for MyFirstPlugin | The plugin class is missing a | |
| public default constructor | Add public MyFirstPlugin() { } to the plugin class | |
FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json' | A NuGet | |
dependency was not copied to the server's Rocket/Libraries/ | Copy the dependency DLL | |
to Rocket/Libraries/ |
Using the Rocket.log effectively
The log file at Rocket/Rocket.log appends entries as they occur. The most recent entries are at the end. When diagnosing a load failure:
- Clear or truncate the log file before restarting the server so you only see fresh output.
- Search for your plugin's assembly name in the log to find the relevant section.
- Look for the
Plugin X failed to loadline, which includes the exception type and message. - Scroll up from that line to find the
Loading assembly Xentry for context. - Check for preceding plugin load entries — if an earlier plugin threw an unhandled exception in its constructor (not Load), RocketMod may stop processing remaining plugins.
Creating a log viewer command
For servers where you cannot access the log file directly (remote hosts, panel-only access), you can create a debug command that reads the log from in-game:
csharp
[RocketCommand("pluginlog", "Shows recent plugin log output.",
AllowedCaller = AllowedCaller.Console)]
[RocketCommandAlias("plog")]
public class PluginLogCommand : IRocketCommand
{
public void Execute(IRocketPlayer caller, string[] command)
{
string logPath = Path.Combine(
Environment.CurrentDirectory,
"Rocket",
"Rocket.log");
if (!File.Exists(logPath))
{
UnturnedChat.Say(caller, "Log file not found.", Color.red);
return;
}
string[] lines = File.ReadAllLines(logPath);
int start = Math.Max(0, lines.Length - 30);
for (int i = start; i < lines.Length; i++)
{
Rocket.Core.Logging.Logger.Log(lines[i]);
}
}
}This reads the last 30 lines of the log and prints them to the console. Adjust the line count based on how much output you need.
Working with multiple projects
As your plugin suite grows, you may want to share code between plugins. The recommended approach for RocketMod is a shared library project.
Shared library structure
MySharedLib/
├── MySharedLib.csproj
├── Extensions/
│ └── PlayerExtensions.cs
├── Models/
│ └── CooldownEntry.cs
└── Helpers/
└── PermissionHelper.csReferencing the shared library
xml
<!-- In each plugin's .csproj -->
<ItemGroup>
<ProjectReference Include="..\MySharedLib\MySharedLib.csproj" />
</ItemGroup>On the server, copy MySharedLib.dll to Rocket/Libraries/ so every plugin can find it. Shared libraries do not go in Rocket/Plugins/ — RocketMod only loads assemblies with plugin classes from the Plugins folder. Libraries go in Libraries.
What to put in a shared library
- Extension methods: adding utility methods to
UnturnedPlayer,IRocketPlayer,IRocketCommand. - Permission constants: defining permission strings in one place so all plugins use identical strings.
- Configuration helpers: base classes for configuration that all plugins share.
- Database abstraction: if multiple plugins access a database, the connection and query logic belongs in the shared library.
Avoid putting plugin lifecycle code in a shared library. Each plugin's Load() and Unload() should remain in its own assembly because RocketMod discovers plugins by scanning for RocketPlugin<TConfig> subclasses.
Plugin logging patterns
RocketMod's Rocket.Core.Logging.Logger provides three levels of logging:
csharp
// Information — normal operation, load/unload messages
Logger.Log("[MyPlugin] Plugin loaded.");
// Warning — recoverable issues, missing optional configuration
Logger.LogWarning("[MyPlugin] Configuration field 'ThemeColor' not set, using default.");
// Error — failures that degrade functionality but do not crash the plugin
Logger.LogError("[MyPlugin] Failed to load translation file: English.xml");Structured logging for diagnostics
For complex plugins, use a consistent log prefix format that makes log filtering easier:
csharp
Logger.Log($"[MyPlugin:Load] Configuration loaded. MaxPlayers={Configuration.Instance.MaxPlayers}");
Logger.Log($"[MyPlugin:PlayerConnected] Player {player.DisplayName} ({player.SteamId}) joined.");
Logger.Log($"[MyPlugin:Command:Heal] {caller.DisplayName} healed {target.DisplayName}");
Logger.Log($"[MyPlugin:Error:Permissions] Permission check failed for {player.DisplayName}: {ex.Message}");The prefix structure [PluginName:Category:SubCategory] makes grep filtering straightforward. When troubleshooting a specific feature, you can search for just the relevant category.
Log volume management
Avoid logging inside high-frequency event handlers like OnPlayerDamaged or OnVehicleUpdated. These events fire many times per second during normal gameplay, and logging every occurrence fills the log file rapidly. Use a rate-limited log:
csharp
private DateTime _lastDamageLog = DateTime.MinValue;
private void OnPlayerDamaged(UnturnedPlayer player, ref ushort amount,
ref bool shouldRaiseDamage)
{
// Log at most once every 30 seconds
if ((DateTime.UtcNow - _lastDamageLog).TotalSeconds > 30)
{
Logger.Log("[MyPlugin] Player damage event active.");
_lastDamageLog = DateTime.UtcNow;
}
}Frequently asked questions
Why does my plugin not appear in /rocket plugins?
The DLL did not load. Check that it is in Rocket/Plugins/ (not a subfolder), that the plugin class is public and inherits from RocketPlugin<TConfig>, and that the assembly targets net472. Check Rocket/Rocket.log for the specific error.
Do I need to restart the server every time I change the DLL?
No. Run /rocket reload MyFirstPlugin from the server console. RocketMod unloads and reloads the assembly in place. After several reloads, consider a full restart to release memory from orphaned assemblies.
Can I use NuGet packages in a RocketMod plugin?
Not directly. RocketMod targets .NET Framework and does not have a NuGet package manager. You must manually download any third-party dependency, reference the DLL in your project, set Private to true in the project file for that dependency, and copy it to Rocket/Libraries/ on the server. OpenMod plugins use NuGet natively, but that is a different framework.
What is the difference between RocketPlugin and RocketPlugin[TConfig]?
RocketPlugin (without the generic parameter) is the non-generic base class. It provides Load(), Unload(), Translate(), and Logger but does not create or manage a configuration file. RocketPlugin<TConfig> inherits from RocketPlugin and adds automatic XML serialization and deserialization of the configuration class. Always use the generic version in production plugins.
How do I see debug output from my plugin?
RocketMod writes log output to three places:
- The server console window (visible in the terminal or panel).
Rocket/Rocket.log— a rolling log file with full detail.Rocket/Rocket.<date>.log— daily logs if log rotation is enabled.
Use Rocket.Core.Logging.Logger.Log("message") for info-level messages and Logger.LogWarning("message") or Logger.LogError("message") for warnings and errors.
Why does my command not show up in /help?
RocketMod's /help command lists all registered commands. If your plugin loaded but the command is missing, check that the command class is public, implements IRocketCommand from Rocket.API.Commands, and is in the same assembly as the plugin. Commands in referenced DLLs are not automatically discovered.
Plugin assembly naming conventions
The DLL filename determines how RocketMod refers to your plugin in logs and commands. Choose a name that is unique, descriptive, and follows the community convention.
| Convention | Example | Notes |
|---|---|---|
| PascalCase with no prefix | MyPlugin.dll | Most common, clean |
| Author prefix | StudioNameMyPlugin.dll | Prevents collisions on shared servers |
| Number prefix for load order | 01_Core.dll | Controls load sequence (fragile) |
Avoid generic names like Commands.dll or Core.dll that another plugin might also use. If two plugins share the same assembly name, only one registers — RocketMod deduplicates by assembly name.
Document history
| Version | Date | Author | Notes |
|---|---|---|---|
| 1.0 | 2026-07-27 | 57 Studios | Initial publication. Full plugin creation walkthrough. |
