BepInEx 游戏插件框架完整指南:从零安装到打造第一个 Unity 模组
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
装了一堆插件,游戏要么闪退要么没反应,还说不清到底是谁的锅——这是不少 Unity 游戏模组玩家的日常。BepInEx 游戏插件框架把插件加载、依赖排序、配置、日志这些脏活统一管起来,让你不用动游戏本体,也能稳定地加载、调试自己的模组。
一句话定位:BepInEx 是什么,给谁用
BepInEx(全称 Bepis Injector Extensible)是一个面向Unity Mono、Unity IL2CPP 和 .NET 框架游戏(XNA、FNA、MonoGame 等)的开源插件/模组框架。
一句话概括:你写一个带BepInPlugin标记的 C# 类,丢进BepInEx/plugins/,它负责在你不修改游戏原始文件的前提下把这个插件拉起来、按依赖顺序跑通、并给每个插件配好独立配置和日志。
它解决的核心问题:
- 非侵入式:插件全部运行时动态加载,出问题不会损坏游戏本体。
- 统一契约:所有插件实现同一套接口,依赖、不兼容、进程过滤都靠属性声明,框架自动处理。
- 多运行时覆盖:Mono 最稳,IL2CPP 与 .NET 也在持续完善。
| 运行时 | Windows | macOS | Linux | ARM |
|---|---|---|---|---|
| Unity Mono | ✔ | ✔ | ✔ | N/A |
| Unity IL2CPP | ✔ | ✘ | ✔ | ✘ |
| .NET / XNA | ✔ | Mono | Mono | N/A |
注意:目前只有 Unity Mono 有稳定发布版,IL2CPP 和 .NET 更偏尝鲜。如果你只是普通用户,优先选 Unity Mono 的游戏。
上手之前:环境要求、版本选择与前置依赖
先确认游戏属于哪种运行时
判断方法看游戏目录里的文件:
- 有
UnityPlayer.dll→Unity Mono - 有
GameAssembly.dll→Unity IL2CPP - 跑在 .NET Framework 上(XNA/FNA/MonoGame 一类)→.NET / XNA
版本怎么选
- 普通玩家 / 大多数 Unity 游戏:用官方发布的Unity Mono 稳定版,这是唯一有稳定发布的线。
- 尝鲜 / 跟进 IL2CPP、.NET:用 Bleeding Edge 版(BepInEx 6 线),功能新但兼容性需要自己验证。
- 插件开发者:本地从源码构建,见 docs/BUILDING.md。
前置依赖
- 运行时注入靠 UnityDoorstop:它负责在游戏启动时把 BepInEx 的入口程序集塞进去,对应仓库里的 Runtimes/Unity/Doorstop/ 配置。
- 本地开发构建需要 .NET 6.0 或更新(构建基于 CakeBuild 脚本)。
- 操作系统要求见上表;Linux/macOS 走
libdoorstop.so/libdoorstop.dylib,Windows 走winhttp.dll。
从零到一:三步装好 BepInEx 并跑通首次运行
第一步:部署框架文件
把 BepInEx 发行包解压/复制进游戏根目录,最终目录结构应该是:
游戏主目录/ ├─ BepInEx/ │ ├─ core/ # 核心运行库 │ ├─ patchers/ # 补丁加载器 │ ├─ plugins/ # 你的插件(.dll) │ ├─ config/ # 各插件的独立配置 │ └─ LogOutput.log # 运行日志(首启后生成) ├─ doorstop_config.ini ├─ winhttp.dll (Win) / libdoorstop.so (Linux) / libdoorstop.dylib (macOS) └─ 游戏可执行文件第二步:确认注入配置
doorstop_config.ini是关键。Unity Mono 的标准配置:
# doorstop_config.ini(Unity Mono 示例) [General] enabled = true target_assembly = BepInEx\core\BepInEx.Unity.Mono.Preloader.dll redirect_output_log = false [UnityMono] dll_search_path_override = "BepInEx\core"如果是 IL2CPP,入口和 CLR 路径不同:
[General] enabled = true target_assembly = BepInEx\core\BepInEx.Unity.IL2CPP.dll [Il2Cpp] coreclr_path = dotnet\coreclr.dll corlib_dir = dotnetLinux / macOS 下通常不改 ini,而是改启动脚本 run_bepinex_mono.sh,把可执行文件名填进去:
# run_bepinex_mono.sh(节选) executable_name="Game.x86_64" enabled="1" target_assembly="BepInEx/core/BepInEx.Unity.Mono.Preloader.dll" dll_search_path_override="BepInEx/core"然后直接./run_bepinex_mono.sh启动即可。
第三步:验证是否装好了
启动游戏,满足下面任意两条基本就成功了:
- 弹出一个命令行窗口,标题形如
BepInEx <版本> - <进程名>,滚动打印加载信息; - 游戏根目录自动生成了
BepInEx/目录结构; - 出现
BepInEx/LogOutput.log,里面能看到Chainloader initialized→N plugins to load→Chainloader startup complete的完整链路。
看到Chainloader startup complete就说明框架已接管,可以开始放插件了。
核心功能演示:用真实场景看它怎么工作
场景一:加载一个带依赖的插件
BepInEx 的核心是 BepInEx.Core/Bootstrap/ 里的 Chainloader。你往plugins/里扔一个 dll,它会自动:扫描程序集 → 解析BepInPlugin元数据 → 按 GUID 依赖做拓扑排序(保证依赖先加载)→ 逐个加载。
依赖和不兼容用属性声明,框架据此决定加载顺序和取舍:
[BepInPlugin("com.example.mymod", "MyFirstMod", "1.0.0")] [BepInProcess("MyGame")] // 只在指定进程跑 [BepInDependency("com.example.base", ">=1.2.0")] // 硬依赖 + 版本范围 public class MyFirstMod : BaseUnityPlugin { private void Awake() { var key = Config.Bind("General", "Enabled", true, "是否启用本模组"); Logger.LogInfo($"插件已加载,当前开关:{key.Value}"); } }三个属性各司其职:
[BepInPlugin(GUID, 名称, 版本)]:必填,定义插件身份,GUID 一旦定下就别再改。[BepInDependency]:可多挂;带版本范围时按SemVer 范围匹配(>=1.2.0、~1.2.0、^1.2.0等)。[BepInProcess("MyGame")]:让插件只在匹配的进程里运行,多开/多进程时很有用。
场景二:给插件配一套自己的配置
BaseUnityPlugin自带Config实例,文件落在BepInEx/config/<你的GUID>.cfg,每个插件互相隔离。绑定一行就够:
ConfigEntry<bool> enableKey = Config.Bind("General", "Enabled", true, "是否启用"); enableKey.Value = false; // SaveOnConfigSet 默认 true,改完立即落盘配置系统实现在 BepInEx.Core/Configuration/,线程安全,支持类型化默认值和描述信息。
场景三:用日志定位问题
框架自带控制台 + 磁盘双路日志,分级为Debug / Info / Message / Warning / Error / Fatal。插件里用Logger.LogInfo(...)等直接打;全局级别在核心配置里调:
# BepInEx.cfg [Logging.Console] Enabled = true PreventClose = false LogLevels = All [Logging.Disk] Enabled = true AppendLog = true LogLevels = All ConcurrentFileLimit = 5需要排查崩溃时,把Debug级别打开,再配合磁盘日志的InstantFlushing = true立刻落盘(有性能代价,排障完记得关)。
进阶玩法:高级配置与性能优化
启动速度:让二次启动更快
TypeLoader 内置程序集缓存:按 dll 哈希缓存插件元数据,程序集没变就复用解析结果,跳过重复扫描。插件多时二次启动能明显提速;插件一变,哈希对不上自动失效重建,无需手动清理。
插件越多越要管的加载顺序
Chainloader 的ModifyLoadOrder会:
- 对重复 GUID只保留版本号最高的那个,旧的记一条 Warning 跳过;
- 做拓扑排序,依赖缺失的插件排到最后,避免"先加载的挡住后加载的"。
所以同目录里塞两个同 GUID 不同版本的 dll,它会自动选新版,不用你手工删。
按进程拆分插件
多开或一个进程管多个游戏时,用[BepInProcess("进程名")]让不同插件只在该跑的进程里激活,进程名不匹配的会被静默跳过(日志里有记录)。
调试器直连(Unity Mono)
doorstop_config.ini里开了debug_enabled = true后,会起一个 Mono 调试服务器,debug_address指定地址(默认127.0.0.1:10000),再配合debug_suspend = true让游戏挂起等调试器接上——适合在线断点调试插件。
常见坑位:现象、原因与解法
1. 现象:游戏启动没反应 / 秒退。原因:Doorstop 没注入成功,或target_assembly指错了 dll。解法:确认enabled = true;核对入口路径——Mono 是BepInEx.core.BepInEx.Unity.Mono.Preloader.dll,IL2CPP 是BepInEx.core.BepInEx.Unity.IL2CPP.dll;确认对应平台的winhttp.dll/libdoorstop.so/libdoorstop.dylib都在且位数匹配。
2. 现象:插件没加载,日志里有 "missing dependencies" / "incompatible version"。原因:硬依赖没装,或装了的版本不满足范围。解法:翻BepInEx/LogOutput.log的DependencyErrors,装上缺失依赖。注意BepInEx 6 里裸版本号是精确匹配(1.2.0只认1.2.0),要表达"最低版本"请写成>=1.2.0,这是从 5 迁过来最常见的行为变化。
3. 现象:插件被跳过,日志提示 "targets a wrong version of BepInEx"。原因:插件编译时引用的 BepInEx 主版本号,和当前运行的主版本号对不上。解法:用对应版本的 BepInEx 重新编译插件,或把运行时升到匹配的版本。
4. 现象:Linux 上从 Steam 启动,脚本报 "The executable is a Windows executable file"。原因:检测到 PE 可执行文件,说明在 Linux 装了 Windows 版(或反之),或这是要走 Wine/Proton 的 Windows 游戏。解法:纯 Linux 游戏用 Linux 版 BepInEx;Windows 游戏在 Linux 上要走 Wine/Proton 并配 Windows 版,别混装。
5. 现象:插件 dll 在、但依赖的程序集解析失败。原因:Mono 的 DLL 搜索路径没覆盖到 BepInEx core。解法:在[UnityMono]里设置dll_search_path_override = "BepInEx\core",多个路径用;(脚本里用:)分隔。
生态与延伸:模组加载器、社区与继续探索
第三方插件加载器生态
BepInEx 常被当作统一底座,上面跑着各种"元加载器"(metaplayer),能加载原本属于别的框架的插件格式,包括BSIPA、IPA、MelonLoader、MonoMod、uMod、Partiality等。等于你装了 BepInEx,还能顺带兼容这些生态里的模组。
关键依赖库
框架站在几个成熟组件肩膀上:
- UnityDoorstop:启动注入;
- HarmonyX:运行时方法热补丁,插件改游戏逻辑主要靠它(BepInEx.Core/Logging/HarmonyLogSource.cs 还专门接了它的日志);
- MonoMod / Il2CppInterop:IL2CPP 与运行时补丁的基础;
- Mono.Cecil:程序集元数据解析。
本地资源与继续探索
- docs/BUILDING.md:从源码构建的完整说明与构建目标(
Compile/MakeDist/Publish)。 - docs/CONTRIBUTING.md:提 issue、提 PR 的规范,参与开发前建议先读。
- 想读懂加载流程,入口就两个文件:BepInEx.Core/Bootstrap/BaseChainloader.cs(发现 + 排序 + 加载)和 BepInEx.Core/Bootstrap/TypeLoader.cs(程序集扫描 + 缓存)。
- 需要本地构建时:
git clone https://gitcode.com/GitHub_Trending/be/BepInEx cd BepInEx # Windows (PowerShell) ./build.ps1 --target Compile # Linux / macOS ./build.sh --target Compile社区方面,BepInEx 有一个活跃的 Discord 服务器,安装、兼容、排障的问题在那里基本都能问到答案。
BepInEx 的价值不在某个单点功能,而在它把"发现—排序—加载—配置—日志—补丁"这条插件生命周期收敛成了一套稳定契约:你只管写插件,框架管剩下的。对玩家,它让改 Unity 游戏变得安全、可回退;对开发者,它给了一套从属性声明到日志排障的完整工具链。从"装好跑通第一个日志"到"按依赖顺序稳定加载几十个插件",这条路是清晰的。
核心关键词:BepInEx 游戏插件框架、Unity Mono 模组框架
长尾关键词:BepInEx 安装教程、如何给 Unity 游戏打模组、BepInEx 插件依赖与版本管理、BepInEx 日志与配置排障、IL2CPP 游戏插件框架、BepInEx 从源码构建、Unity 游戏 MOD 框架入门
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考