subnautica-ii-coop-bepinex-mod

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Subnautica II Co-op BepInEx Mod

Subnautica 2 合作模式 BepInEx 模组

Skill by ara.so — Devtools Skills collection.
ara.so 开发的Skill — 属于Devtools Skills合集。

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
Deep Synergy多人游戏模组将Subnautica 2转变为同步合作体验。基于BepInEx构建,它实现了确定性会话同步、自适应难度缩放、基于Merkle树验证的共享库存,以及可选的基于OpenAI/Claude API的AI驱动叙事功能。
核心架构:
  • BepInEx 6.0.x 插件框架(IL2CPP钩子,无需修改游戏文件)
  • WebRTC P2P 用于去中心化多人游戏(NAT穿透)
  • Merkle树库存同步 确保分布式状态完整性
  • 基于玩家数量的自适应缩放
  • API集成 用于程序化叙事生成

Installation

安装

Prerequisites

前置条件

  1. Subnautica 2 (Steam/GOG version)
  2. BepInEx 6.0.x framework installed
  1. Subnautica 2(Steam/GOG版本)
  2. 已安装BepInEx 6.0.x框架

Setup Steps

设置步骤

bash
undefined
bash
undefined

1. Install BepInEx first (if not already installed)

1. 先安装BepInEx(如果尚未安装)

Extract to Subnautica 2 game directory

解压到Subnautica 2游戏目录

2. Download Deep Synergy mod

2. 下载Deep Synergy模组

Extract to: <Subnautica2>/BepInEx/plugins/DeepSynergy/

解压至:<Subnautica2>/BepInEx/plugins/DeepSynergy/

3. Verify directory structure:

3. 验证目录结构:

BepInEx/

BepInEx/

plugins/

plugins/

DeepSynergy/

DeepSynergy/

DeepSynergy.dll

DeepSynergy.dll

Newtonsoft.Json.dll

Newtonsoft.Json.dll

config/

config/

synergy_profile.json

synergy_profile.json

undefined
undefined

File Structure

文件结构

<Subnautica2>/
├── BepInEx/
│   ├── core/
│   ├── plugins/
│   │   └── DeepSynergy/
│   │       ├── DeepSynergy.dll
│   │       └── libs/
│   └── config/
│       ├── synergy_profile.json
│       └── session_config.xml
└── Subnautica2.exe
<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
)

会话配置文件(
BepInEx/config/synergy_profile.json

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
}
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

配置字段

FieldTypeDescription
session_name
stringDisplay name for session
max_players
int2-8 player limit
difficulty_scale
enum
fixed
,
adaptive
,
manual
resource_multiplier
floatMultiplies harvestable resources (0.5-2.0)
oxygen_consumption
floatOxygen drain rate (0.5-1.5)
creature_spawn_divider
intReduces creature count (1=normal, 2=half)
shared_blueprints
boolBlueprint unlocks sync across players
time_of_day_sync
enum
host
,
all
,
none
字段类型描述
session_name
string会话显示名称
max_players
int玩家数量限制(2-8人)
difficulty_scale
enum
fixed
(固定)、
adaptive
(自适应)、
manual
(手动)
resource_multiplier
float可采集资源倍数(0.5-2.0)
oxygen_consumption
float氧气消耗速率(0.5-1.5)
creature_spawn_divider
int减少生物生成数量(1=正常,2=减半)
shared_blueprints
bool蓝图解锁在玩家间同步
time_of_day_sync
enum
host
(跟随主机)、
all
(全员同步)、
none
(不同步)

Network Configuration

网络配置

json
{
  "network": {
    "port": 25000,
    "max_latency_ms": 200,
    "reconnect_timeout_s": 30,
    "stun_server": "stun:stun.l.google.com:19302",
    "use_relay": false,
    "encryption": true
  }
}
json
{
  "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):
bash
undefined
通过BepInEx终端访问(默认按F1键):
bash
undefined

Host a new session

开启新会话

/start_server
/start_server

Join existing session

加入现有会话

/join_session <session-code>
/join_session <session-code>

Example: /join_session 9B2A-4C7D-E8F1

示例:/join_session 9B2A-4C7D-E8F1

Check connection status

检查连接状态

/synergy_status
/synergy_status

Adjust difficulty scaling mid-session

会话中调整难度缩放

/synergy_scale <multiplier>
/synergy_scale <multiplier>

Example: /synergy_scale 1.5

示例:/synergy_scale 1.5

Force world seed synchronization

强制世界种子同步

/seed_override <seed>
/seed_override <seed>

Example: /seed_override 8251

示例:/seed_override 8251

Trigger AI narration (requires API config)

触发AI叙事(需配置API)

/api_narrate "<context>"
/api_narrate "<context>"

Example: /api_narrate "exploring deep caves"

示例:/api_narrate "exploring deep caves"

Disconnect gracefully

优雅断开连接

/disconnect
/disconnect

Force inventory resync

强制库存同步

/sync_inventory
/sync_inventory

List connected peers

列出已连接的玩家

/list_peers
undefined
/list_peers
undefined

Code Examples

代码示例

Plugin Entry Point (C#)

Plugin Entry Point (C#)

csharp
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");
        }
    }
}
csharp
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

Session Creation Pattern

csharp
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()}";
        }
    }
}
csharp
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

Inventory Synchronization

csharp
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);
        }
    }
}
csharp
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

AI Narrative Integration

csharp
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();
        }
    }
}
csharp
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

Adaptive Scaling Implementation

csharp
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);
        }
    }
}
csharp
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

Common Patterns

Session Lifecycle

Session Lifecycle

csharp
// 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();
csharp
// 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

State Synchronization

csharp
// 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);
    }
};
csharp
// 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

Error Handling

csharp
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}");
}
csharp
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:
  1. Verify port forwarding (default 25000)
  2. Check firewall rules for Subnautica2.exe and BepInEx
  3. Confirm both players have identical mod versions
  4. Enable debug mode:
    "debug_mode": true
    in config
  5. Try changing STUN server in network config
bash
undefined
症状: 无法连接到会话
解决方案:
  1. 验证端口转发(默认25000)
  2. 检查Subnautica2.exe和BepInEx的防火墙规则
  3. 确认所有玩家使用相同版本的模组
  4. 启用调试模式:在配置中设置
    "debug_mode": true
  5. 尝试更改网络配置中的STUN服务器
bash
undefined

Check logs

查看日志

tail -f BepInEx/LogOutput.log | grep DeepSynergy
tail -f BepInEx/LogOutput.log | grep DeepSynergy

Common error patterns:

常见错误模式:

"WebRTC connection timeout" → NAT/firewall issue

"WebRTC connection timeout" → NAT/防火墙问题

"Version mismatch" → Update mod to matching version

"Version mismatch" → 更新模组至匹配版本

"Session not found" → Invalid session code

"Session not found" → 会话代码无效

undefined
undefined

Inventory Desync

库存不同步

Symptom: Players see different inventories
Solutions:
bash
undefined
症状: 玩家看到的库存不一致
解决方案:
bash
undefined

Force resync via console

通过控制台强制同步

/sync_inventory
/sync_inventory

Or programmatically

或通过代码实现

inventorySync.ForceFullSync();

Check for conflicting mods:
```bash
inventorySync.ForceFullSync();

检查冲突模组:
```bash

Disable other inventory mods temporarily

暂时禁用其他库存类模组

Verify DeepSynergy.dll is latest version

确认DeepSynergy.dll为最新版本

undefined
undefined

API Integration Not Working

API集成失效

Symptom: AI narration not generating
Solutions:
bash
undefined
症状: AI叙事无法生成内容
解决方案:
bash
undefined

Verify environment variables

验证环境变量

echo $OPENAI_API_KEY # Linux/Mac echo %OPENAI_API_KEY% # Windows
echo $OPENAI_API_KEY # Linux/Mac echo %OPENAI_API_KEY% # Windows

Test API key

测试API密钥

curl https://api.openai.com/v1/models
-H "Authorization: Bearer $OPENAI_API_KEY"

Check config:
```json
{
  "api_integration": {
    "openai": {
      "enabled": true,
      "api_key_env": "OPENAI_API_KEY",  // Must match env var name
      "model": "gpt-4"
    }
  }
}
curl https://api.openai.com/v1/models
-H "Authorization: Bearer $OPENAI_API_KEY"

检查配置:
```json
{
  "api_integration": {
    "openai": {
      "enabled": true,
      "api_key_env": "OPENAI_API_KEY",  // 必须与环境变量名称一致
      "model": "gpt-4"
    }
  }
}

Performance Issues

性能问题

Symptom: Lag/stuttering with 3+ players
Solutions:
  1. Reduce creature spawn rate:
json
{
  "creature_spawn_divider": 2  // Halves creature count
}
  1. Lower sync frequency (advanced):
csharp
StateSync.SetUpdateInterval(100);  // ms, default 50
  1. Disable API features:
json
{
  "api_integration": {
    "openai": { "enabled": false },
    "claude": { "enabled": false }
  }
}
症状: 3人及以上玩家时出现卡顿/延迟
解决方案:
  1. 降低生物生成速率:
json
{
  "creature_spawn_divider": 2  // 生物数量减半
}
  1. 降低同步频率(高级设置):
csharp
StateSync.SetUpdateInterval(100);  // 毫秒,默认50
  1. 禁用API功能:
json
{
  "api_integration": {
    "openai": { "enabled": false },
    "claude": { "enabled": false }
  }
}

Log Analysis

日志分析

bash
undefined
bash
undefined

Enable debug logging

启用调试日志

In synergy_profile.json:

在synergy_profile.json中设置:

"debug_mode": true
"debug_mode": true

Key log patterns:

关键日志模式:

"[StateSync] Merkle mismatch" → Inventory desync

"[StateSync] Merkle mismatch" → 库存不同步

"[Network] Peer disconnected" → Connection loss

"[Network] Peer disconnected" → 连接中断

"[API] Rate limit exceeded" → Reduce API calls

"[API] Rate limit exceeded" → 减少API调用次数

undefined
undefined

Advanced Configuration

高级配置

Custom Scaling Formula

自定义缩放公式

csharp
// 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);
    }
}
csharp
// 在插件中覆盖默认缩放逻辑
public class CustomScaler : DifficultyScaler
{
    protected override float CalculateCreatureMultiplier(int players)
    {
        // 自定义公式:指数级减少
        return Mathf.Pow(0.8f, players - 1);
    }
}

Session Migration

会话迁移

csharp
// 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();
}
csharp
// 实现主机断开时的会话迁移
_channel.OnHostDisconnected += () => {
    var survivingPeer = _peers.OrderBy(p => p.Latency).First();
    if (survivingPeer.Id == localPlayerId)
    {
        PromoteToHost();
    }
};

private void PromoteToHost()
{
    _channel.BecomeHost();
    BroadcastFullState();
}

Blueprint Sharing

蓝图共享

csharp
// 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());
    }
};
csharp
// 同步蓝图解锁
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

环境变量

bash
undefined
bash
undefined

API keys (never commit these)

API密钥(切勿提交到代码仓库)

export OPENAI_API_KEY="sk-..." export ANTHROPIC_API_KEY="sk-ant-..."
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"
undefined
export SYNERGY_PORT=25000 export SYNERGY_STUN_SERVER="stun:custom.server.com:3478"
undefined

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
  • 操作系统: Windows 10/11、macOS 11+、Linux(Ubuntu 20.04+、Steam Deck)
  • BepInEx版本: 6.0.x(IL2CPP)
  • 游戏版本: Subnautica 2(2026年发布版)
  • 冲突模组: 避免同时使用其他多人游戏/库存类模组