Skip to content

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.

Visual Studio project window showing a new RocketMod plugin class file

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's Modules/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.dll

The 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

DLLSource location on serverWhat it provides
Rocket.API.dllModules/Rocket.Unturned/ or Rocket/Libraries/Interfaces: IRocketPlugin, IRocketCommand, IRocketPlayer, IRocketPluginConfiguration
Rocket.Core.dllSame locationBase classes: RocketPlugin<TConfig>, RocketPluginManager, logging, translation, permission checking
Rocket.Unturned.dllSame locationUnturned-specific wrappers: UnturnedPlayer, UnturnedChat, UnturnedPlayerEvents, UnturnedServer
Assembly-CSharp.dllUnturned_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.dll
  • Rocket.Core.dll
  • Rocket.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

  1. On first load, RocketMod detects that no configuration file exists for the plugin.
  2. It calls LoadDefaults() on a fresh instance.
  3. It serializes the default values to Rocket/Plugins/MyFirstPlugin/MyFirstPlugin.configuration.xml.
  4. On subsequent loads, it deserializes the XML back into the class.
  5. 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 typeXML serializationExample
stringElement with text content<GreetingMessage>Welcome!</GreetingMessage>
int / floatSame pattern<MaxPlayers>32</MaxPlayers>
boolSame pattern<EnableLogging>true</EnableLogging>
List<string>Array of elements<Items><Item>one</Item><Item>two</Item></Items>
Nested objectsNested 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.xml

Open 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

MemberTypePurpose
NamestringThe primary command keyword. Players type /hello to invoke it.
HelpstringShort description shown in /help listings.
SyntaxstringUsage instructions shown in /help hello.
AliasesList<string>Alternative keywords that also invoke the command.
PermissionsList<string>Required permissions. Empty list = anyone can use it.
AllowedCallerAllowedCallerWho can run this command — Player, Console, or Both.
ExecutevoidThe 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 the caller parameter because IRocketPlayer from 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

  1. Copy MyFirstPlugin.dll to the server's Rocket/Plugins/ directory.
  2. If your plugin references external DLLs not already on the server, copy them to Rocket/Libraries/.
  3. Restart the server, or run /rocket reload MyFirstPlugin from 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 messageLikely 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 loadException thrown in Load() before logging the success message
No parameterless constructor defined for MyFirstPluginThe 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:

  1. Build the project in Release mode.
  2. Copy the new MyFirstPlugin.dll to Rocket/Plugins/, overwriting the old one.
  3. Run /rocket reload MyFirstPlugin from 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

  1. Join the server as a player.
  2. Type /hello in the chat.
  3. 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 Name property? Typing /hello matches Name = "hello".
  • Is AllowedCaller set to Player or Both? If it is Console, the in-game chat ignores the command.
  • Are any required permissions set? An empty Permissions list 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.

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 entryCauseFix
Could not load file or assembly 'Rocket.API' or one of its dependenciesThe 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 serverCopy 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 hasRebuild against DLLs extracted from the production server
Plugin MyFirstPlugin failed to load: System.NullReferenceExceptionSomething in
Load() threw a null reference — likely Configuration.Instance or U.Instance accessed
before initializationCheck Load() for operations that depend on not-yet-initialized services
No parameterless constructor defined for MyFirstPluginThe plugin class is missing a
public default constructorAdd 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:

  1. Clear or truncate the log file before restarting the server so you only see fresh output.
  2. Search for your plugin's assembly name in the log to find the relevant section.
  3. Look for the Plugin X failed to load line, which includes the exception type and message.
  4. Scroll up from that line to find the Loading assembly X entry for context.
  5. 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.cs

Referencing 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.

ConventionExampleNotes
PascalCase with no prefixMyPlugin.dllMost common, clean
Author prefixStudioNameMyPlugin.dllPrevents collisions on shared servers
Number prefix for load order01_Core.dllControls 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

VersionDateAuthorNotes
1.02026-07-2757 StudiosInitial publication. Full plugin creation walkthrough.