
subnautica-ii-coop-bepinex-mod
BepInEx multiplayer mod for Subnautica 2 with session sync, shared inventory, and API-driven narrative features
- Installs
- 229
- Last 24h
- —
- Trending rank
- —
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/reason-machines/devtools-skills --skill subnautica-ii-coop-bepinex-mod- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads subnautica-ii-coop-bepinex-mod automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
Subnautica II Co-op BepInEx Mod
Skill by ara.so — Devtools Skills collection.
Overview
The Deep Synergy Multiplayer Mod transforms Subnautica 2 into a synchronized cooperative experience. Built on BepInEx, it implements deterministic session synchronization, adaptive difficulty scaling, shared inventory via Merkle tree verification, and optional AI-driven narrative features using OpenAI/Claude APIs.
Core Architecture:
- BepInEx 6.0.x plugin framework (IL2CPP hooks, no game file modification)
- WebRTC P2P for decentralized multiplayer (NAT punch-through)
- Merkle tree inventory sync for distributed state integrity
- Adaptive scaling based on player count
- API integrations for procedural narrative generation
Installation
Prerequisites
- Subnautica 2 (Steam/GOG version)
- BepInEx 6.0.x framework installed
Setup Steps
# 1. Install BepInEx first (if not already installed)
# Download from https://github.com/BepInEx/BepInEx/releases
# Extract to Subnautica 2 game directory
# 2. Download Deep Synergy mod
# Extract to: <Subnautica2>/BepInEx/plugins/DeepSynergy/
# 3. Verify directory structure:
# BepInEx/
# plugins/
# DeepSynergy/
# DeepSynergy.dll
# Newtonsoft.Json.dll
# config/
# synergy_profile.json
File Structure
<Subnautica2>/
├── BepInEx/
│ ├── core/
│ ├── plugins/
│ │ └── DeepSynergy/
│ │ ├── DeepSynergy.dll
│ │ └── libs/
│ └── config/
│ ├── synergy_profile.json
│ └── session_config.xml
└── Subnautica2.exe
Configuration
Session Profile (BepInEx/config/synergy_profile.json)
{
"session_name": "Ocean Explorers",
"max_players": 4,
"difficulty_scale": "adaptive",
"resource_multiplier": 1.0,
"oxygen_consumption": 1.0,
"creature_spawn_divider": 1,
"enable_pvp": false,
"friendly_fire": false,
"shared_blueprints": true,
"ping_locations_shared": true,
"time_of_day_sync": "host",
"voice_chat_integration": "none",
"network": {
"port": 25000,
"max_latency_ms": 200,
"reconnect_timeout_s": 30,
"stun_server": "stun:stun.l.google.com:19302"
},
"api_integration": {
"openai": {
"enabled": false,
"api_key_env": "OPENAI_API_KEY",
"model": "gpt-4",
"role": "narrator"
},
"claude": {
"enabled": false,
"api_key_env": "ANTHROPIC_API_KEY",
"model": "claude-3-sonnet-20240229",
"role": "lore_engine"
}
},
"locale": "en-US",
"debug_mode": false
}
Configuration Fields
| Field | Type | Description |
|---|---|---|
session_name | string | Display name for session |
max_players | int | 2-8 player limit |
difficulty_scale | enum | fixed, adaptive, manual |
resource_multiplier | float | Multiplies harvestable resources (0.5-2.0) |
oxygen_consumption | float | Oxygen drain rate (0.5-1.5) |
creature_spawn_divider | int | Reduces creature count (1=normal, 2=half) |
shared_blueprints | bool | Blueprint unlocks sync across players |
time_of_day_sync | enum | host, all, none |
Network Configuration
{
"network": {
"port": 25000,
"max_latency_ms": 200,
"reconnect_timeout_s": 30,
"stun_server": "stun:stun.l.google.com:19302",
"use_relay": false,
"encryption": true
}
}
Console Commands
Access via BepInEx terminal (F1 key by default):
# Host a new session
/start_server
# Join existing session
/join_session <session-code>
# Example: /join_session 9B2A-4C7D-E8F1
# Check connection status
/synergy_status
# Adjust difficulty scaling mid-session
/synergy_scale <multiplier>
# Example: /synergy_scale 1.5
# Force world seed synchronization
/seed_override <seed>
# Example: /seed_override 8251
# Trigger AI narration (requires API config)
/api_narrate "<context>"
# Example: /api_narrate "exploring deep caves"
# Disconnect gracefully
/disconnect
# Force inventory resync
/sync_inventory
# List connected peers
/list_peers
Code Examples
Plugin Entry Point (C#)
using BepInEx;
using BepInEx.IL2CPP;
using HarmonyLib;
using UnityEngine;
namespace DeepSynergy
{
[BepInPlugin(GUID, Name, Version)]
public class DeepSynergyPlugin : BasePlugin
{
public const string GUID = "com.deepsynergy.subnautica2";
public const string Name = "Deep Synergy Multiplayer";
public const string Version = "1.0.0";
private SessionManager _sessionManager;
private StateSync _stateSync;
public override void Load()
{
Log.LogInfo("Loading Deep Synergy...");
// Load configuration
var config = ConfigLoader.LoadProfile();
// Initialize core systems
_sessionManager = new SessionManager(config);
_stateSync = new StateSync(config);
// Apply Harmony patches
var harmony = new Harmony(GUID);
harmony.PatchAll();
Log.LogInfo("Deep Synergy loaded successfully");
}
}
}
Session Creation Pattern
using DeepSynergy.Core;
using System;
namespace DeepSynergy.Session
{
public class SessionManager
{
private SynergyConfig _config;
private WebRTCChannel _channel;
public SessionManager(SynergyConfig config)
{
_config = config;
}
public string CreateSession()
{
var sessionCode = GenerateSessionCode();
_channel = new WebRTCChannel(_config.Network);
_channel.OnPeerConnected += HandlePeerConnect;
_channel.OnDataReceived += HandleStateUpdate;
_channel.StartHost(_config.Network.Port);
Console.WriteLine($"Session created: {sessionCode}");
return sessionCode;
}
public bool JoinSession(string sessionCode)
{
_channel = new WebRTCChannel(_config.Network);
_channel.OnConnected += () => {
Console.WriteLine("Connected to session");
SyncInitialState();
};
return _channel.Connect(sessionCode);
}
private void HandleStateUpdate(byte[] data)
{
var update = StateUpdate.Deserialize(data);
_stateSync.ApplyUpdate(update);
}
private string GenerateSessionCode()
{
var guid = Guid.NewGuid();
return $"{guid.ToString().Substring(0, 4).ToUpper()}-" +
$"{guid.ToString().Substring(4, 4).ToUpper()}-" +
$"{guid.ToString().Substring(8, 4).ToUpper()}";
}
}
}
Inventory Synchronization
using System.Security.Cryptography;
using System.Text;
namespace DeepSynergy.Sync
{
public class InventorySync
{
private Dictionary<string, InventoryState> _playerInventories;
public string ComputeMerkleRoot(InventoryState inventory)
{
var hashes = new List<string>();
foreach (var item in inventory.Items.OrderBy(i => i.Id))
{
var itemData = $"{item.Id}:{item.Quantity}:{item.Metadata}";
hashes.Add(ComputeHash(itemData));
}
return BuildMerkleTree(hashes);
}
public void SyncInventory(string playerId, InventoryState state)
{
var localHash = ComputeMerkleRoot(state);
var remoteHash = RequestRemoteHash(playerId);
if (localHash != remoteHash)
{
// Resolve conflict using timestamp authority
var resolvedState = ConflictResolver.Resolve(
state,
GetRemoteState(playerId)
);
ApplyInventoryState(playerId, resolvedState);
BroadcastUpdate(playerId, resolvedState);
}
}
private string ComputeHash(string data)
{
using (var sha256 = SHA256.Create())
{
var bytes = Encoding.UTF8.GetBytes(data);
var hash = sha256.ComputeHash(bytes);
return BitConverter.ToString(hash).Replace("-", "");
}
}
private string BuildMerkleTree(List<string> hashes)
{
if (hashes.Count == 1) return hashes[0];
var newLevel = new List<string>();
for (int i = 0; i < hashes.Count; i += 2)
{
var combined = i + 1 < hashes.Count
? hashes[i] + hashes[i + 1]
: hashes[i];
newLevel.Add(ComputeHash(combined));
}
return BuildMerkleTree(newLevel);
}
}
}
AI Narrative Integration
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace DeepSynergy.AI
{
public class NarrativeEngine
{
private readonly HttpClient _client;
private readonly string _apiKey;
private readonly string _model;
public NarrativeEngine(string apiKeyEnv, string model)
{
_apiKey = Environment.GetEnvironmentVariable(apiKeyEnv);
_model = model;
_client = new HttpClient();
}
public async Task<string> GenerateNarration(string context)
{
if (string.IsNullOrEmpty(_apiKey))
{
return "API key not configured";
}
var request = new
{
model = _model,
messages = new[]
{
new { role = "system", content = "You are a narrator for a co-op ocean survival game. Generate brief, atmospheric journal entries based on player actions." },
new { role = "user", content = $"Context: {context}" }
},
max_tokens = 150,
temperature = 0.7
};
_client.DefaultRequestHeaders.Clear();
_client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_apiKey}");
var response = await _client.PostAsJsonAsync(
"https://api.openai.com/v1/chat/completions",
request
);
var result = await response.Content.ReadAsStringAsync();
var json = JsonDocument.Parse(result);
return json.RootElement
.GetProperty("choices")[0]
.GetProperty("message")
.GetProperty("content")
.GetString();
}
}
}
Adaptive Scaling Implementation
namespace DeepSynergy.Scaling
{
public class DifficultyScaler
{
private SynergyConfig _config;
private int _playerCount;
public void UpdatePlayerCount(int count)
{
_playerCount = count;
if (_config.DifficultyScale == "adaptive")
{
AdjustGameParameters();
}
}
private void AdjustGameParameters()
{
// Scale creature spawns inversely with player count
var creatureMultiplier = 1.0f / (_playerCount * _config.CreatureSpawnDivider);
Game.CreatureSpawner.SetGlobalMultiplier(creatureMultiplier);
// Scale resource availability
var resourceMultiplier = _config.ResourceMultiplier *
Mathf.Lerp(1.0f, 1.5f, (_playerCount - 1) / 7f);
Game.ResourceManager.SetMultiplier(resourceMultiplier);
// Adjust oxygen consumption (more players = slightly more efficient)
var oxygenEfficiency = _config.OxygenConsumption *
Mathf.Lerp(1.0f, 0.85f, (_playerCount - 1) / 7f);
Game.Player.SetOxygenConsumption(oxygenEfficiency);
}
}
}
Common Patterns
Session Lifecycle
// Host workflow
var session = new SessionManager(config);
var sessionCode = session.CreateSession();
Console.WriteLine($"Share code: {sessionCode}");
// Client workflow
var session = new SessionManager(config);
session.JoinSession("9B2A-4C7D-E8F1");
// Graceful disconnect
session.Disconnect();
State Synchronization
// Send state update
var update = new StateUpdate
{
Timestamp = DateTime.UtcNow.Ticks,
PlayerId = localPlayerId,
Type = UpdateType.InventoryChange,
Data = SerializeInventory()
};
_channel.Broadcast(update.Serialize());
// Receive and apply update
_channel.OnDataReceived += (data) => {
var update = StateUpdate.Deserialize(data);
if (ConflictResolver.ShouldApply(update))
{
ApplyStateUpdate(update);
}
};
Error Handling
try
{
session.JoinSession(sessionCode);
}
catch (SessionNotFoundException)
{
Console.WriteLine("Session not found. Check code.");
}
catch (NetworkTimeoutException)
{
Console.WriteLine("Connection timeout. Check firewall/NAT.");
}
catch (VersionMismatchException ex)
{
Console.WriteLine($"Mod version mismatch: {ex.Message}");
}
Troubleshooting
Connection Issues
Symptom: Cannot connect to session
Solutions:
- Verify port forwarding (default 25000)
- Check firewall rules for Subnautica2.exe and BepInEx
- Confirm both players have identical mod versions
- Enable debug mode:
"debug_mode": truein config - Try changing STUN server in network config
# Check logs
tail -f BepInEx/LogOutput.log | grep DeepSynergy
# Common error patterns:
# "WebRTC connection timeout" → NAT/firewall issue
# "Version mismatch" → Update mod to matching version
# "Session not found" → Invalid session code
Inventory Desync
Symptom: Players see different inventories
Solutions:
# Force resync via console
/sync_inventory
# Or programmatically
inventorySync.ForceFullSync();
Check for conflicting mods:
# Disable other inventory mods temporarily
# Verify DeepSynergy.dll is latest version
API Integration Not Working
Symptom: AI narration not generating
Solutions:
# Verify environment variables
echo $OPENAI_API_KEY # Linux/Mac
echo %OPENAI_API_KEY% # Windows
# Test API key
curl https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY"
Check config:
{
"api_integration": {
"openai": {
"enabled": true,
"api_key_env": "OPENAI_API_KEY", // Must match env var name
"model": "gpt-4"
}
}
}
Performance Issues
Symptom: Lag/stuttering with 3+ players
Solutions:
- Reduce creature spawn rate:
{
"creature_spawn_divider": 2 // Halves creature count
}
- Lower sync frequency (advanced):
StateSync.SetUpdateInterval(100); // ms, default 50
- Disable API features:
{
"api_integration": {
"openai": { "enabled": false },
"claude": { "enabled": false }
}
}
Log Analysis
# Enable debug logging
# In synergy_profile.json:
"debug_mode": true
# Key log patterns:
# "[StateSync] Merkle mismatch" → Inventory desync
# "[Network] Peer disconnected" → Connection loss
# "[API] Rate limit exceeded" → Reduce API calls
Advanced Configuration
Custom Scaling Formula
// Override default scaling in plugin
public class CustomScaler : DifficultyScaler
{
protected override float CalculateCreatureMultiplier(int players)
{
// Custom formula: exponential reduction
return Mathf.Pow(0.8f, players - 1);
}
}
Session Migration
// Implement host migration on disconnect
_channel.OnHostDisconnected += () => {
var survivingPeer = _peers.OrderBy(p => p.Latency).First();
if (survivingPeer.Id == localPlayerId)
{
PromoteToHost();
}
};
private void PromoteToHost()
{
_channel.BecomeHost();
BroadcastFullState();
}
Blueprint Sharing
// Sync blueprint unlocks
Game.BlueprintManager.OnUnlock += (blueprint) => {
if (_config.SharedBlueprints)
{
var update = new StateUpdate
{
Type = UpdateType.BlueprintUnlock,
Data = Encoding.UTF8.GetBytes(blueprint.Id)
};
_channel.Broadcast(update.Serialize());
}
};
Environment Variables
# API keys (never commit these)
export OPENAI_API_KEY="sk-..."
export ANTHROPIC_API_KEY="sk-ant-..."
# Optional network overrides
export SYNERGY_PORT=25000
export SYNERGY_STUN_SERVER="stun:custom.server.com:3478"
Compatibility
- OS: Windows 10/11, macOS 11+, Linux (Ubuntu 20.04+, Steam Deck)
- BepInEx: 6.0.x (IL2CPP)
- Game Version: Subnautica 2 (2026 release)
- Conflicting Mods: Avoid other multiplayer/inventory mods
FAQ
What does the subnautica-ii-coop-bepinex-mod skill do?
BepInEx multiplayer mod for Subnautica 2 with session sync, shared inventory, and API-driven narrative features
How do I install subnautica-ii-coop-bepinex-mod?
Run npx skills add https://github.com/reason-machines/devtools-skills --skill subnautica-ii-coop-bepinex-mod in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/subnautica-ii-coop-bepinex-mod/ (personal) or .claude/skills/subnautica-ii-coop-bepinex-mod/ (project).
Which AI agents can use subnautica-ii-coop-bepinex-mod?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is subnautica-ii-coop-bepinex-mod safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains subnautica-ii-coop-bepinex-mod?
It is published by reason-machines in reason-machines/devtools-skills. It has 229 recorded installs.
More from reason-machines/devtools-skills
cc-switch-cli
reason-machines/devtools-skills
Cross-platform CLI tool for managing Claude Code, Codex, Gemini, OpenCode & OpenClaw providers, MCP servers, prompts, skills, and proxies.
wx-cli-wechat-local-data
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
chrome-devtools-mcp-automation
reason-machines/devtools-skills
Use Chrome DevTools MCP to control Chrome, debug web apps, analyze performance, and automate browser tasks via MCP tools
officecli-office-automation
reason-machines/devtools-skills
Use OfficeCLI to create, read, and edit Word, Excel, and PowerPoint files from the command line with AI-friendly commands.
cli-anything-agent-native-software
reason-machines/devtools-skills
Generate and use command-line interfaces that make any software controllable by AI agents with structured JSON output
autocli-web-scraping
reason-machines/devtools-skills
Open the skill to read its SKILL.md instructions.
Popular backend & apis skills
find-skills
vercel-labs/skills
Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
entra-app-registration
microsoft/azure-skills
Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.
google-agents-cli-adk-code
google/agents-cli
This skill should be used when the user wants to "write agent code", "build an agent with ADK", "add a tool", "create a callback", "define an agent", "use state management" — in a project that needs ADK (Agent Development Kit) API patterns and code examples. It provides a quick reference for agent types, tool definitions, orchestration patterns, callbacks, state management, the graph Workflow API, and reference recipes to study. Do NOT use for scaffolding (use google-agents-cli-scaffold) or deployment (use google-agents-cli-deploy).
embedded-captions
heygen-com/hyperframes
Add captions or subtitles to an existing single-subject talking-head video without editing the footage. Use for plain verbatim captions, cinematic captions embedded behind the subject, VFX captions, “炸/特效/酷炫字幕,” or a named identity from the 35-style catalog. Route by visual identity, not by backend engine. The quiet anchor rail is the default; embed every word only when the user explicitly wants a fully cinematic treatment. The workflow runs locally end to end, including transcription and subject matting; split multi-shot footage before applying it.
entra-agent-id
microsoft/azure-skills
Provision Microsoft Entra Agent Identity Blueprints, BlueprintPrincipals, and per-instance Agent Identities via Microsoft Graph, and configure OAuth 2.0 token exchange (fmipath, OBO, cross-tenant) including the Microsoft Entra SDK for AgentID sidecar. USE FOR: Agent Identity Blueprint, BlueprintPrincipal, agent OAuth, fmipath token exchange, agent OBO, Workload Identity Federation for agents, polyglot agent auth, Microsoft.Identity.Web.AgentIdentities. DO NOT USE FOR: standard Entra app registration (use entra-app-registration), Microsoft Foundry agent authoring (use microsoft-foundry).
neon
neondatabase/agent-skills
Overview of Neon, a complete set of cloud backend primitives around Lakebase Postgres: Auth, Object Storage, Functions, the AI Gateway, and Realtime. Start here to choose Neon for undecided login, files, APIs, and LLM calls, set up the CLI or MCP server, and follow the branch-first workflow. Use when building an app or backend on Neon, or when "Neon" or "Lakebase Postgres" is mentioned. Child skill neon-postgres wins for an existing DATABASEURL, SQL, schema, inspect, or search. Child skill neon-auth wins for login, users, sessions, identity routing, and Managed Better Auth setup. Child skill neon-realtime wins for live queries in reactive apps and agents. Also use for object storage, S3, buckets, serverless functions, function triggers, cron, AI gateway, LLM calls, realtime, logs, Loki, Grafana, observability, postgres, database, backend, Claimable Neon, neon.new, or a no-signup database.