BepInEx 6 完整使用指南:安装配置、插件加载机制与常见报错解决
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
BepInEx 是 Unity Mono、Unity IL2CPP 与 .NET(XNA / FNA / MonoGame)游戏的插件加载框架,让第三方 Mod 以 dll 形式挂进游戏进程。本文覆盖 BepInEx 安装与 Doorstop 配置、插件加载机制、IL2CPP 互操作、日志调优和常见报错解决,按"装好 → 跑通 → 看懂 → 排错"的顺序走一遍。验收标准只有一条:游戏窗口能稳定看到 BepInEx 控制台,output_log.txt里出现Chainloader startup complete,且插件加载计数大于 0。
Doorstop 配置详解:BepInEx 6 安装后的第一个关键文件
BepInEx 装好之后游戏却"没反应",九成是 Doorstop 没配好——Doorstop 是 Unity 的引导机制:游戏启动时先加载你指定的 dll 并执行其入口方法,BepInEx 的 Preloader 就靠这条通道抢在 Unity 主逻辑之前跑起来。配置文件是游戏根目录的doorstop_config.ini,关键行如下:
[General] enabled = true target_assembly = BepInEx\core\BepInEx.Unity.Mono.Preloader.dll redirect_output_log = true [Il2Cpp] coreclr_path = dotnet\coreclr.dll corlib_dir = dotnetenabled = true是总开关;target_assembly指向 BepInEx 的预加载入口程序集,Mono 与 IL2CPP 构建指向不同的 dll,别照抄错行;redirect_output_log = true把 Unity 原始日志转写进output_log.txt——游戏窗口闪退时,这个文件就是唯一的诊断现场;[Il2Cpp]段两项指向 BepInEx 自带的 CoreCLR 运行时与托管核心库目录,IL2CPP 构建才需要。仓库里保留着 doorstop_config_mono.ini 和 doorstop_config_il2cpp.ini 两份模板,可直接对照检查本地配置。验证方式:启动游戏后output_log.txt出现,且 BepInEx 日志从Preloader前缀开始滚动,即配置生效。
BepInEx 插件加载机制:plugins 目录如何被扫描与排序
插件的加载规则由 BepInEx.Core/Bootstrap/ 下的BaseChainloader实现:初始化时自动创建plugins目录,扫描其中所有 dll,逐个解析元数据并按依赖顺序加载。插件类必须声明BepInPlugin特性:
[BepInPlugin("com.example.mymod", "MyMod", "1.0.0")] public class MyMod : BaseUnityPlugin { }特性里的三个参数依次是 GUID(全生命周期不变的唯一标识)、显示名和版本号。加载器对每个候选类做四道检查:特性缺失、GUID 含非法字符、版本号为空、名称为空——任何一道不过就跳过该类型并打警告。插件还能声明BepInDependency(依赖某 GUID,硬依赖缺失则本插件不加载)、BepInProcess(只允许在指定游戏进程名下加载)和BepInIncompatibility(与某插件互斥)。加载器会按依赖关系拓扑排序、跳过重复 GUID 中较旧的版本、核对进程名与互斥声明,最后输出加载计数。Mono 环境里插件被挂成BepInEx_ManagerGameObject 上的组件;IL2CPP 环境用对应的AddComponent扩展方法走同一套逻辑。验证方式:日志里出现N plugins to load,每个插件一行Loading [...],结尾Chainloader startup complete。
BepInEx IL2CPP 互操作程序集生成:IL2CPP 游戏的第一次启动为什么慢
IL2CPP 构建把全部 C# 代码编译成 C++ 打进原生库(GameAssembly.dll/UserAssembly.dll/libil2cpp.so),运行时只剩二进制与元数据,.NET 反射查类型、调方法整套机制直接失效。BepInEx 的做法是在启动时自动生成一套"替身"程序集补上反射能力,流程是:
GameAssembly + global-metadata.dat → Cpp2IL 逆向出类与方法信息 → Il2CppInterop 生成互操作程序集(默认 BepInEx/interop 目录) → 插件对着生成的类型编程,与 Mono 体验一致框架会记录游戏程序集的哈希,缓存失效才重新生成;游戏升过一次版本后重建一次互操作,之后启动速度接近 Mono。这套流程由BepInEx.cfg的[IL2CPP]段三个开关控制:
[IL2CPP] UpdateInteropAssemblies = true ScanMethodRefs = true PreloadIL2CPPInteropAssemblies = trueUpdateInteropAssemblies默认开,控制游戏更新后自动重建互操作程序集——关掉它的直接后果就是"升一次游戏、坏一批 Mod";ScanMethodRefs默认开,启用交叉引用扫描来标注方法引用计数、生成更完整的程序集;PreloadIL2CPPInteropAssemblies默认开,在加载插件前预载全部互操作程序集,个别游戏有兼容问题时才考虑关掉。互操作程序集默认存放在BepInEx/interop,这个目录是缓存不是垃圾,删了等于每次启动都重新生成一遍。IL2CPP 版的 Chainloader 通过 Hook 游戏运行时的il2cpp_runtime_invoke接管流程,等游戏加载完首个场景(回调Internal_ActiveSceneChanged)后才触发插件加载,所以插件生效时机天然晚于 Mono。
BepInEx 日志系统与调试开关:output_log.txt 和 LogOutput.log 怎么用
日志是 BepInEx 唯一的全知视角,由 BepInEx.Core/Logging/ 的多路监听器实现:控制台直出(ConsoleLogListener)与磁盘写入(DiskLogListener)。磁盘日志默认开启,落在BepInEx/LogOutput.log,受BepInEx.cfg的[Logging.Disk]段控制:
[Logging.Disk] Enabled = true LogLevels = "FATAL|ERROR|WARNING|MESSAGE|INFO" InstantFlushing = false ConcurrentFileLimit = 5ConcurrentFileLimit = 5表示最多同时保留 5 个日志文件(每个运行中的游戏实例占用一个)。Unity 引擎自身日志也能汇入 BepInEx 日志流(Logging.UnityLogListening默认开),但要写进磁盘文件需手动打开[Logging.Disk]的WriteUnityLog = true。排查崩溃时把InstantFlushing = true打开:日志逐条立即落盘,性能开销不小,但能保证崩溃发生前的最后几条记录不丢。日志源名称本身就是定位线索:Preloader前缀指向 Doorstop 引导阶段,Chainloader指插件加载,Il2CppInterop/InteropManager指互操作生成,Unity Log指引擎自身。
常见报错对照与解决方法 🛠️
以下对照表覆盖 BepInEx 6 里最常见的几类日志,比逐条读日志快得多。
| 日志关键行 | 含义 | 处理 |
|---|---|---|
Could not locate Il2Cpp game assembly (GameAssembly.dll, UserAssembly.dll or libil2cpp.so) | 找不到 IL2CPP 游戏程序集,文件被改名混淆或 Unity 版本暂不受支持 | 确认游戏未加壳/混淆,用环境变量BEPINEX_GAME_ASSEMBLY_PATH指向真实文件,核对 Unity 版本是否在 Cpp2IL 支持范围 |
Failed to generate Il2Cpp interop assemblies | Cpp2IL 逆向或 Il2CppInterop 生成环节失败 | 多为游戏混淆或 Unity 版本过新/过旧,升级 BepInEx 到最新 Bleeding Edge 构建 |
Skipping over type [...] as no metadata attribute is specified | 插件类没写BepInPlugin特性 | 加载器直接跳过,属于插件作者的问题,找作者修 |
Plugin [...] targets a wrong version of BepInEx (x.x.x) | 插件编译目标大版本高于当前框架 | 换匹配大版本的插件,或升级 BepInEx |
Skipping type [...] because its GUID [...] is of an illegal format | GUID 含字母数字之外的非法字符 | 作者侧修复,插件不会被加载 |
Skipping [...] because a newer version exists | 同一 GUID 存在多个版本 | 正常行为,只加载最新版 |
Skipping [...] because of process filters | 插件声明了BepInProcess且当前进程名不匹配 | 该插件本就不为这个游戏准备 |
Could not load [...] because it has missing dependencies: ... | 硬依赖的 GUID 未安装或版本不满足 | 安装缺失插件或把依赖更新到满足范围的版本后重启 |
Could not load [...] because it is incompatible with: ... | 插件声明了BepInIncompatibility且冲突插件已存在 | 二选一保留 |
排不动时的顺序:先用环境变量DOORSTOP_DISABLE禁用 BepInEx 启动一次,确认问题是否真的来自 BepInEx 这条链路;再把plugins目录里的 dll 逐个移出做二分定位;框架层问题回到前面各节核对配置与版本。另外升级游戏后先小范围验证一次互操作重建,确认无误再批量更新 Mod。
延伸阅读:BepInEx 源码构建方法与仓库文档位置
想深入或从源码构建,仓库自带的文档是首选。docs/BUILDING.md 说明编译方式:需要 .NET 6.0 或更高,用内置的build项目(基于 CakeBuild)执行--target Compile编译,MakeDist生成各平台发行包,Publish打成 zip 输出到bin/dist。docs/CONTRIBUTING.md 与 docs/CODE_OF_CONDUCT.md 分别是协作流程与社区规范。源码结构上:BepInEx.Core/Bootstrap/是链式加载器主逻辑,BepInEx.Core/Configuration/是BepInEx.cfg的读写与类型转换,BepInEx.Core/Contract/定义BepInPlugin特性和PluginInfo,各运行时的实现在 Runtimes/ 下按Unity/Mono、Unity/IL2CPP、NET分目录,Doorstop 配置模板在 Runtimes/Unity/Doorstop/。想本地构建时,先克隆仓库再执行:
git clone https://gitcode.com/GitHub_Trending/be/BepInEx cd BepInEx && ./build.sh --target Compile这组命令在 Linux 下完成依赖拉取与二进制编译,Windows 对应build.cmd或build.ps1。
收尾:三步行动清单 ✅
- 首次安装:核对
doorstop_config.ini三项(enabled、target_assembly、redirect_output_log),启动一次,确认output_log.txt生成且出现Chainloader startup complete。 - 验证加载链路:放入一个最小插件,日志确认
Loading [...]与Chainloader startup complete,加载计数大于 0。 - IL2CPP 环境升级游戏后:保留
BepInEx/interop缓存,小范围验证互操作重建成功,再批量更新 Mod。
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考