BepInEx:免费的 Unity 游戏 Mod 插件框架,5 分钟跑起来
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
BepInEx 是一个免费的 Unity 游戏 Mod 插件框架:把插件 DLL 丢进 plugins 文件夹,它就能在游戏启动前自动完成插件发现、依赖排序、配置与日志。你不用碰游戏一行代码,也不用自己写注入和加载逻辑。
先看看你的环境行不行
🎮 玩家视角:它决定了你能不能给手里的 Unity 游戏装 Mod,装好之后所有插件都挂在这套地基上。
👨💻 开发者视角:它是你写插件的运行时,配置绑定、日志、依赖声明这些脚手架全都内置,你只管写业务逻辑。
兼容范围(来自 README.md 的兼容性表):
| 运行时 | Windows | macOS | Linux |
|---|---|---|---|
| Unity Mono | ✔️ | ✔️ | ✔️ |
| Unity IL2CPP | ✔️ | ❌ | ✔️ |
| .NET / XNA(含 FNA、MonoGame) | ✔️ | 走 Mono | 走 Mono |
⚠️ 注意:目前只有 Unity Mono 有稳定发布版,IL2CPP 要走 Bleeding Edge 构建。和 MelonLoader 这类同类加载器相比,BepInEx 的差异在于它把插件发现、依赖图排序、统一配置和统一日志做成了标准件,第三方 Mod 基本都按它的契约来写。
三分钟大白话:它到底在干什么
📦 把它想成社区快递站的收货流程。每天早上快递车(游戏主程序)到场,但站里有个规矩:站长(Chainloader)会先拦下车,逐件核对包裹——有没有面单([BepInPlugin]属性里的 GUID、名称、版本号),面单格式对不对,是不是寄给这个站的([BepInProcess]进程过滤),有没有包裹声明"必须在我之前签收"([BepInDependency],站长按拓扑排序排出派送顺序)。核对完、排序完,包裹全部上架,才放行让站点开门营业(游戏真正初始化)。任何一步不合规则,这件包裹被拒收,理由写进台账(日志)。
整个流程在 BaseChainloader.cs 里能逐行对上:DiscoverPlugins是数包裹,ModifyLoadOrder是排派送顺序,LoadPlugins是真正签收。
东西都放在游戏根目录的BepInEx文件夹里,路径常量定义见 Paths.cs:
游戏根目录/ ├── BepInEx/ │ ├── core/ # 框架核心 DLL(Doorstop 的加载入口也在这) │ ├── plugins/ # 你的插件 DLL 放这里 │ ├── patchers/ # 预加载修补程序 │ ├── config/ # 各插件的 .cfg 配置文件(核心配置是 BepInEx.cfg) │ └── cache/ # 插件发现结果的缓存 └── LogOutput.log # 启动日志,排障第一现场5 分钟上手
使用版:装 Mod
- 下载 Unity Mono 稳定版压缩包(IL2CPP 游戏去 Bleeding Edge 构建页拿),解压。
- 把解压出来的
BepInEx整个文件夹拷到游戏 exe 所在目录。 - 把你的插件 DLL 放进
BepInEx/plugins。 - 启动游戏,打开根目录的
LogOutput.log,看到 "Chainloader startup complete" 就说明全链路通了。
自建版:从源码编译
克隆仓库:
git clone https://gitcode.com/GitHub_Trending/be/BepInEx装好 .NET 6.0 或更高(构建脚本基于 CakeBuild,硬性要求)。
Linux/macOS 在仓库目录运行
./build.sh --target Compile;Windows 运行build.cmd --target Compile。要可分发包就换
--target MakeDist(产物在bin/dist);要再打成压缩包用--target Publish。
各目标的具体说明见 docs/BUILDING.md。
关键配置与进阶技巧
target_assembly(doorstop_config_mono.ini)Doorstop 拦截后去加载哪个程序集。标准值是BepInEx/core/BepInEx.Unity.Mono.Preloader.dll。改了路径或手动挪过框架文件夹之后,这里没同步就是"什么都不会发生"的头号原因。
dll_search_path_override(同一文件)让 Mono 在找程序集前先查指定目录。默认值"BepInEx/core"专门救原游戏Managed目录被裁剪、找不到 mscorlib 的情况;要加多个目录用分号隔开。
Logging.Disk段(BepInEx/config/BepInEx.cfg)磁盘日志总开关和输出级别。排查崩溃时把InstantFlushing设为true,每条日志立即落盘(性能有代价);开多个游戏实例调试时调大ConcurrentFileLimit(默认 5),否则新实例的日志文件会被拒发。
[BepInDependency]和[BepInProcess](Attributes.cs)写插件时在类上声明。依赖可以是HardDependency(缺失直接拒载)或SoftDependency(缺了就降级跑);带版本范围时注意 BepInEx 6 里裸版本号按精确匹配处理,想要"最低版本"语义要写>=1.2.0。[BepInProcess("GameName")]限定插件只在指定进程名启动。插件骨架继承 BaseUnityPlugin.cs 即可,构造时自带Logger和Config两个开箱即用的成员。
出问题时:排障速查
| 现象 | 根因 | 解决 |
|---|---|---|
| 游戏能启动但插件一个没加载 | Doorstop 没生效,或target_assembly指向了不存在的程序集 | 检查 ini 里enabled = true且target_assembly指向BepInEx/core/BepInEx.Unity.Mono.Preloader.dll |
| 启动报找不到 mscorlib / 系统程序集 | 原游戏Managed目录被裁剪,Mono 缺核心库 | 保持dll_search_path_override = "BepInEx/core",让框架目录优先于 Managed 被搜索 |
| 同 GUID 插件放了两份,只加载了一份 | 同 GUID 去重时只保留版本号最高的,另一份被跳过 | 删掉旧 DLL,plugins 目录里只留一份 |
| 插件换个游戏就不加载 | 带[BepInProcess]的插件只在属性名匹配当前 exe 进程名时运行 | 核对属性里的进程名和实际 exe 文件名(去掉 .exe)是否一致 |
| 日志里提示 "targets a wrong version of BepInEx" | 插件是用旧大版本的 BepInEx 编译的,大版本不兼容 | 找该插件的新版本,或降级框架到对应大版本 |
| ⚠️ IL2CPP 游戏找不到稳定版下载 | 官方只有 Unity Mono 出稳定版,IL2CPP 属于实验性质 | 使用 Bleeding Edge 构建;macOS + IL2CPP 组合目前直接不支持 |
写在最后
一句话定位:BepInEx 就是把"插件放哪、谁先跑、坏了怎么查"这些脏活全收走的 Unity Mod 地基,你的插件只管写功能本身。下一步建议:先通读 docs/BUILDING.md 弄清三个构建目标的产物差异,再顺着 BepInEx.Core/Bootstrap/ 里 Chainloader 的源码走一遍加载流程,配合 BepInEx.Core/Contract/ 看属性契约,写插件时就不会被加载规则绊住。
【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考