Loading...
Loading...
BepInEx-based multiplayer co-op mod for Subnautica 2 with synchronized gameplay, adaptive scaling, and decentralized peer-to-peer networking
npx skill4agent add aradotso/devtools-skills subnautica-ii-coop-modSkill by ara.so — Devtools Skills collection.
# 1. Install BepInEx 6.0.x for Subnautica 2
# Download from https://github.com/BepInEx/BepInEx/releases
# Extract to Subnautica 2 game directory
# 2. Download Deep Synergy Mod
# Extract the mod package
# 3. Copy plugin files
cp -r BepInEx/plugins/* <Subnautica2Directory>/BepInEx/plugins/
# 4. Create configuration directory
mkdir -p <Subnautica2Directory>/BepInEx/config/
# 5. Launch game to generate default configs
# BepInEx will create config files on first runSubnautica2/
├── BepInEx/
│ ├── core/
│ ├── plugins/
│ │ ├── DeepSynergy.dll
│ │ ├── SessionManager.dll
│ │ └── StateSynchronizer.dll
│ └── config/
│ ├── synergy_profile.json
│ └── session_config.xml
└── Subnautica2.exeBepInEx/config/synergy_profile.json{
"session_name": "DeepDive Squad",
"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": "all",
"voice_chat_integration": "discord_rpc",
"network": {
"use_nat_punchthrough": true,
"port": 7777,
"max_latency_ms": 200,
"sync_interval_ms": 50
},
"api_integration": {
"openai": {
"enabled": false,
"api_key_env": "OPENAI_API_KEY",
"role": "narrator",
"model": "gpt-4"
},
"claude": {
"enabled": false,
"api_key_env": "ANTHROPIC_API_KEY",
"role": "lore_engine",
"model": "claude-3-opus-20240229"
}
},
"locale": "en-US"
}| Field | Type | Description |
|---|---|---|
| string | Display name for your session |
| int | Maximum concurrent players (2-8) |
| string | |
| float | Resource spawn rate multiplier (0.5-2.0) |
| float | Oxygen drain rate (0.5-2.0, lower = slower drain) |
| int | Divides creature spawn counts |
| bool | Share unlocked blueprints across players |
| bool | Synchronize map pings |
| string | |
# Set API keys via environment variables
export OPENAI_API_KEY="your-openai-key-here"
export ANTHROPIC_API_KEY="your-anthropic-key-here"
# Enable in synergy_profile.json
# The mod will automatically use these keys when api_integration.enabled = true# Start a host session
/start_server
# Join existing session
/join_session <session-code>
# Example: /join_session 9B2A-4C7D-E8F1
# Leave current session
/leave_session
# Display session status
/synergy_status# Adjust difficulty scaling (temporary override)
/synergy_scale <multiplier>
# Example: /synergy_scale 1.5
# Override world seed
/seed_override <seed>
# Example: /seed_override 8251
# Force inventory sync
/force_sync inventory
# Teleport to player
/teleport_to <player_name># Trigger AI narration (requires OpenAI enabled)
/api_narrate "<context>"
# Example: /api_narrate "exploring the underwater caves"
# Generate creature lore (requires Claude enabled)
/api_lore <creature_id>
# Example: /api_lore reaper_leviathan
# Generate base name suggestions
/api_name_baseusing BepInEx;
using BepInEx.IL2CPP;
using DeepSynergy.API;
using UnityEngine;
namespace MyCustomPlugin
{
[BepInPlugin("com.myname.custommod", "Custom Mod", "1.0.0")]
[BepInDependency("com.deepsynergy.core", BepInDependency.DependencyFlags.HardDependency)]
public class CustomPlugin : BasePlugin
{
public override void Load()
{
// Get Deep Synergy session manager
var sessionManager = DeepSynergyAPI.GetSessionManager();
// Subscribe to session events
sessionManager.OnPlayerJoined += OnPlayerJoined;
sessionManager.OnPlayerLeft += OnPlayerLeft;
sessionManager.OnStateSync += OnStateSync;
Log.LogInfo("Custom plugin loaded with Deep Synergy integration");
}
private void OnPlayerJoined(PlayerInfo player)
{
Log.LogInfo($"Player joined: {player.Name} (ID: {player.PeerId})");
// Send custom data to all clients
DeepSynergyAPI.BroadcastCustomData("MyCustomPlugin", new {
message = $"{player.Name} joined!",
timestamp = System.DateTime.UtcNow
});
}
private void OnPlayerLeft(PlayerInfo player)
{
Log.LogInfo($"Player left: {player.Name}");
}
private void OnStateSync(SyncEvent syncEvent)
{
// Handle synchronized state updates
if (syncEvent.Type == SyncEventType.InventoryUpdate)
{
Log.LogInfo($"Inventory synced for player {syncEvent.PlayerId}");
}
}
}
}using DeepSynergy.Config;
using Newtonsoft.Json;
using System.IO;
public class ConfigManager
{
public static SynergyProfile LoadProfile(string path)
{
var json = File.ReadAllText(path);
return JsonConvert.DeserializeObject<SynergyProfile>(json);
}
public static void CreateDefaultProfile(string path)
{
var profile = new SynergyProfile
{
SessionName = "New Session",
MaxPlayers = 4,
DifficultyScale = "adaptive",
ResourceMultiplier = 1.0f,
OxygenConsumption = 1.0f,
CreatureSpawnDivider = 1,
EnablePvp = false,
SharedBlueprints = true,
Network = new NetworkConfig
{
UseNatPunchthrough = true,
Port = 7777,
MaxLatencyMs = 200,
SyncIntervalMs = 50
}
};
var json = JsonConvert.SerializeObject(profile, Formatting.Indented);
File.WriteAllText(path, json);
}
public static void UpdateScaling(float multiplier)
{
var api = DeepSynergyAPI.GetSessionManager();
api.SetDifficultyMultiplier(multiplier);
}
}using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
public class NarrativeEngine
{
private readonly string _openAiKey;
private readonly HttpClient _client;
public NarrativeEngine()
{
_openAiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
_client = new HttpClient();
_client.DefaultRequestHeaders.Add("Authorization", $"Bearer {_openAiKey}");
}
public async Task<string> GenerateNarration(string context)
{
var request = new
{
model = "gpt-4",
messages = new[]
{
new { role = "system", content = "You are a narrative engine for Subnautica 2, providing immersive journal entries." },
new { role = "user", content = $"Generate a brief journal entry about: {context}" }
},
max_tokens = 150,
temperature = 0.8
};
var json = JsonConvert.SerializeObject(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(
"https://api.openai.com/v1/chat/completions",
content
);
var responseJson = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<dynamic>(responseJson);
return result.choices[0].message.content.ToString();
}
}# 1. Configure your profile
# Edit BepInEx/config/synergy_profile.json
# 2. Launch game
# 3. Open BepInEx console (F1)
# 4. Start server
/start_server
# 5. Share the generated session code with friends
# Example output: "Server created: session code = 9B2A-4C7D-E8F1"# 1. Launch game
# 2. Open BepInEx console (F1)
# 3. Join using session code
/join_session 9B2A-4C7D-E8F1
# 4. Wait for sync to complete
/synergy_status
# Look for "State sync: 100% complete"# Check connected players and latency
/synergy_status
# Example output:
# Connected peers: 3
# State sync: 100% complete
# Average latency: 45ms
# Inventory hash: 0xFA342B1E# View current scaling
/synergy_status
# Temporarily increase difficulty
/synergy_scale 1.5
# Reset to profile defaults
/synergy_scale 1.0# 1. Check firewall rules
# Windows: Allow port 7777 (UDP) in Windows Firewall
# Linux: sudo ufw allow 7777/udp
# 2. Verify NAT settings in profile
# Edit synergy_profile.json:
"network": {
"use_nat_punchthrough": true,
"port": 7777
}
# 3. Check BepInEx logs
# Location: BepInEx/LogOutput.log
grep "SessionManager" BepInEx/LogOutput.log# Force inventory resync
/force_sync inventory
# Check for mod conflicts
# Disable other BepInEx plugins temporarily and test# 1. Reduce sync frequency in profile
"network": {
"sync_interval_ms": 100 # Increase from 50ms to 100ms
}
# 2. Lower creature spawn rates
"creature_spawn_divider": 2 # Half as many creatures
# 3. Check network stats
/synergy_status
# Look for "Average latency" > 200ms# 1. Check BepInEx version compatibility
# Ensure BepInEx 6.0.x or later is installed
# 2. Verify mod file integrity
# Re-download and reinstall DeepSynergy.dll
# 3. Clear cache
rm -rf BepInEx/cache/*
# Restart game
# 4. Check logs for IL2CPP errors
grep "IL2CPP" BepInEx/LogOutput.log# 1. Verify environment variables
echo $OPENAI_API_KEY
echo $ANTHROPIC_API_KEY
# 2. Check API integration settings in profile
"api_integration": {
"openai": {
"enabled": true,
"api_key_env": "OPENAI_API_KEY"
}
}
# 3. Test API connectivity
/api_narrate "test"
# Check BepInEx logs for API response errors# 1. Force inventory sync
/force_sync inventory
# 2. Check inventory hash consistency
/synergy_status
# All players should have matching "Inventory hash"
# 3. If persistent, restart session
/leave_session
# Host restarts with /start_server
# All players rejoin// Edit synergy_profile.json
{
"locale": "en-US" // Change to your preferred locale
}
// Supported: en-US, zh-CN, ja-JP, de-DE, fr-FR, pt-BR, ru-RU, es-LA, ko-KR# View recent errors
tail -n 100 BepInEx/LogOutput.log | grep ERROR
# Filter for Deep Synergy specific logs
grep "DeepSynergy" BepInEx/LogOutput.log
# Monitor logs in real-time
tail -f BepInEx/LogOutput.log/synergy_status// Register custom synchronization logic
DeepSynergyAPI.RegisterSyncHandler("CustomItemType", (data, playerId) => {
// Handle custom item sync
var item = JsonConvert.DeserializeObject<CustomItem>(data);
GameState.ApplyCustomItem(item, playerId);
});# If host disconnects, session migrates automatically
# Force migration to specific player
/migrate_host <player_name>// Enable verbose logging in synergy_profile.json
{
"debug": {
"enabled": true,
"log_sync_events": true,
"log_network_packets": true
}
}