Creating Your First Subnautica 2 Mod (C# / BepInEx)
This guide walks you through building a minimal working BepInEx plugin for Subnautica 2 from scratch. You'll need basic C# knowledge but no prior modding experience.
Tools You Need
- Visual Studio 2022 Community (free) or JetBrains Rider
- .NET 8.0 SDK
- BepInEx installed in your game (see BepInEx Setup Guide)
- dnSpy or ILSpy — to read the game's compiled code
Step 1 — Create a New Class Library Project
In Visual Studio:
- New Project → Class Library → target .NET Standard 2.1 (BepInEx compatibility).
- Name it something like
MyFirstSubMod. - Delete the auto-generated
Class1.cs.
Step 2 — Add NuGet References
In your .csproj, add the BepInEx package:
<ItemGroup>
<PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" />
<PackageReference Include="BepInEx.Core" Version="5.*" />
</ItemGroup>
Also add a reference to the game's assembly. Find Assembly-CSharp.dll inside:
Subnautica2\Subnautica2_Data\Managed\Assembly-CSharp.dll
Add it as a local reference in your .csproj:
<ItemGroup>
<Reference Include="Assembly-CSharp">
<HintPath>C:\Path\To\Subnautica2\Subnautica2_Data\Managed\Assembly-CSharp.dll</HintPath>
<Private>false</Private>
</Reference>
</ItemGroup>
Step 3 — Write Your Plugin Entry Point
Create Plugin.cs:
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
namespace MyFirstSubMod
{
[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
public class Plugin : BaseUnityPlugin
{
internal static new ManualLogSource Logger { get; private set; } = null!;
private static Harmony? _harmony;
private void Awake()
{
Logger = base.Logger;
_harmony = new Harmony(MyPluginInfo.PLUGIN_GUID);
_harmony.PatchAll();
Logger.LogInfo("MyFirstSubMod loaded successfully!");
}
}
}
Add MyPluginInfo.cs:
namespace MyFirstSubMod
{
internal static class MyPluginInfo
{
internal const string PLUGIN_GUID = "com.yourname.myfirstsubmod";
internal const string PLUGIN_NAME = "My First SubMod";
internal const string PLUGIN_VERSION = "1.0.0";
}
}
Step 4 — Add a Harmony Patch
Harmony lets you intercept game method calls without editing game files. Here's a simple example that logs every time the player takes damage:
using HarmonyLib;
namespace MyFirstSubMod
{
// Find the real class/method names using dnSpy or ILSpy on Assembly-CSharp.dll
[HarmonyPatch(typeof(PlayerHealth), nameof(PlayerHealth.TakeDamage))]
internal static class PlayerHealth_TakeDamage_Patch
{
// Runs BEFORE the original method
static void Prefix(float damage)
{
Plugin.Logger.LogInfo($"Player is taking {damage} damage!");
}
}
}
Use dnSpy to open
Assembly-CSharp.dlland browse the real class and method names for the game.
Step 5 — Build and Deploy
- Build the project (Ctrl+Shift+B).
- Copy
bin\Debug\netstandard2.1\MyFirstSubMod.dllto:Subnautica2\BepInEx\plugins\MyFirstSubMod\ - Launch the game and check
BepInEx\LogOutput.logfor your "loaded successfully!" message.
Step 6 — Iterate
- Edit → Build → Copy DLL → Relaunch game.
- Use
Logger.LogInfo()/LogWarning()/LogError()liberally — they all appear inLogOutput.log. - The BepInEx Configuration Manager mod lets you expose config options in-game without restarting.
Finding Game Classes with dnSpy
- Open dnSpy.
- File → Open → navigate to
Assembly-CSharp.dll. - Browse namespaces/classes in the left panel, or use Edit → Search (Ctrl+Shift+K) to find class names.
- Click any method to see its decompiled C# source.
Video Resources
Join the Forum to share your mod and get feedback from the community!