1. 项目概述:为什么BepInEx能让你的Unity游戏“活”起来?
如果你是一名Unity游戏开发者,或者是一位热衷于修改、增强PC端Unity游戏的玩家,那么你一定遇到过这样的困境:面对一个已经发布的游戏,你想添加一个新功能、修复一个烦人的Bug,或者仅仅是调整一下游戏参数,却发现无从下手。直接修改游戏原文件?风险极高,一次更新就可能让你的心血付诸东流。自己从头写一个Mod加载器?技术门槛和时间成本又让人望而却步。
这时,BepInEx(Bepis Injector Extensible)就登场了。它不是一个具体的Mod,而是一个强大、通用且开源的插件框架。简单来说,它就是为Unity游戏(尤其是使用Mono或IL2CPP后端编译的游戏)量身打造的“Mod运行环境”。你可以把它想象成游戏的一个“扩展坞”,所有第三方插件(Mod)都通过这个“扩展坞”安全、有序地加载到游戏中,而不会直接“污染”游戏本体。
我最初接触BepInEx是为了给一款喜欢的独立游戏添加中文翻译和UI优化。当时游戏本身不支持,社区Mod又需要一个稳定的运行基础。在尝试了多种注入方案后,BepInEx以其近乎完美的兼容性、清晰的日志系统和活跃的社区支持脱颖而出。它彻底改变了我和许多Mod开发者与Unity游戏的互动方式——从被动的玩家,变成了能主动塑造游戏体验的创造者。
本指南将带你从零开始,彻底掌握BepInEx。无论你是想为自己喜欢的游戏制作第一个Mod的爱好者,还是寻求为自家产品建立Mod生态的开发者,这篇文章都将提供从原理到实践、从安装到排错的全套“工具箱”。我们会避开那些晦涩难懂的理论堆砌,聚焦于“如何让它工作”以及“为什么这么操作”,并结合我踩过的无数个坑,分享那些官方文档里不会写的实战经验。
2. BepInEx核心原理与架构拆解
在动手之前,理解BepInEx是如何“嵌入”并“运作”于一个Unity游戏中的,至关重要。这不仅能帮助你在遇到问题时快速定位,也能让你在设计自己的插件时做出更明智的选择。
2.1 Unity游戏Mod的难点与BepInEx的解决方案
一个编译好的Unity游戏(通常是.exe和Data文件夹),其核心代码和逻辑已经被打包成托管程序集(如Assembly-CSharp.dll)。传统修改方式是直接反编译、修改、再重新编译这个DLL,俗称“打补丁”。这种方法有几个致命缺点:
- 易失效:游戏每次更新,对应的DLL可能变化,补丁立即失效。
- 冲突:多个Mod修改同一文件时,后安装的会覆盖前者,无法共存。
- 高风险:操作失误极易导致游戏崩溃,且难以恢复。
- 门槛高:需要较强的逆向工程和汇编知识。
BepInEx采用了更优雅的“运行时注入”方案。它不直接修改游戏原文件,而是在游戏启动时,将自己“插入”到游戏进程和Unity引擎之间。其核心流程可以概括为以下几步:
- 引导启动:通过修改游戏启动参数或利用Unity自身的插件机制,让游戏首先加载BepInEx的核心引导程序(
BepInEx.dll)。 - 环境准备:引导程序初始化一个独立的、受控的.NET运行时环境(对于Mono游戏)或准备好Hook框架(对于IL2CPP游戏)。
- 程序集修补:这是BepInEx的魔法所在。它会在游戏原有的程序集(如
Assembly-CSharp.dll)被加载到内存后、但尚未被执行前,通过Harmony等库对其中特定的方法(Method)进行“打补丁”(Patching)。这些补丁可以在方法执行前、后或完全替换原方法,从而实现功能修改。 - 插件加载:在稳定的修补环境建立后,BepInEx会扫描
BepInEx/plugins目录,加载所有符合规范的插件DLL。每个插件都可以独立声明自己的补丁、配置和依赖关系。
注意:BepInEx 5.x版本对IL2CPP的支持已经非常成熟,其原理是通过
BepInEx.IL2CPP组件和MonoMod.RuntimeDetour等工具,在本地/本地模拟的运行时中实现类似的钩子功能,架构上与Mono版本有所不同但最终效果一致。
2.2 BepInEx核心目录结构解析
安装完BepInEx后,游戏根目录下会生成一个BepInEx文件夹,它的结构是你管理所有Mod的司令部:
游戏根目录/ ├── BepInEx/ │ ├── core/ # BepInEx核心运行库,切勿随意修改或删除 │ ├── plugins/ # 【核心】所有插件的存放目录。每个插件一个子文件夹 │ │ └── YourPlugin/ │ │ ├── YourPlugin.dll │ │ └── manifest.json # 插件元数据文件 │ ├── patchers/ # 高级用法,用于放置“修补器”(Patcher),在插件加载前对游戏程序集进行更底层的修改 │ ├── config/ # 【重要】所有插件的配置文件(.cfg)默认存放于此 │ └── LogOutput.log # 【排错神器】BepInEx的运行日志,遇到问题首先查看它plugins目录:这是你接触最多的地方。一个合格的插件应该将自己的所有文件(主要是DLL和依赖项)放在一个以插件名命名的独立子文件夹内。这样做的好处是清晰、易于管理,卸载时直接删除整个文件夹即可。config目录:BepInEx内置了强大的配置管理功能。插件开发者可以通过代码定义配置项,用户则可以在游戏内通过按F1键(默认)调出的配置管理器实时修改,所有设置会自动保存到config目录下的.cfg文件。这实现了Mod设置的“热重载”,无需重启游戏。LogOutput.log文件:这是诊断一切问题的起点。BepInEx的日志系统非常详细,从加载进度、遇到的异常到每个插件的初始化信息都会记录在此。任何情况下游戏崩溃或Mod不生效,请第一时间打开这个文件。
2.3 与同类框架的对比:为什么是BepInEx?
在Unity游戏Mod领域,除了BepInEx,你可能还听说过UnityModManager(UMM)或MelonLoader。它们各有优劣:
| 特性 | BepInEx | UnityModManager (UMM) | MelonLoader |
|---|---|---|---|
| 核心架构 | 通用注入器,侧重底层Hook和运行时修补 | 针对特定游戏(如模拟经营类)的Mod管理器,提供GUI | 新兴的通用加载器,设计现代,对IL2CPP支持早 |
| 兼容性 | 极广,支持Mono和IL2CPP,适用于绝大多数Unity游戏 | 较窄,通常需要为每个游戏适配 | 较广,尤其早期在IL2CPP游戏上表现突出 |
| 配置管理 | 内置强大配置系统,支持热重载 | 依赖Mod自身实现,不统一 | 内置配置系统,功能类似BepInEx |
| 社区与生态 | 最大、最活跃,插件、教程资源海量 | 集中在特定游戏社群 | 增长迅速,尤其在特定游戏社区 |
| 上手难度 | 中等,概念较多但文档齐全 | 简单,图形化安装 | 中等,概念清晰 |
| 适用场景 | 通用性Mod开发、深度游戏修改、建立Mod生态 | 特定游戏的轻量级Mod管理 | 追求新特性的Mod开发,尤其是IL2CPP游戏 |
选择BepInEx的理由:
- 通用性与稳定性:它的设计目标就是成为Unity游戏的“标准模组接口”,经过多年迭代,稳定性和兼容性久经考验。
- 强大的基础设施:内置的配置、日志、依赖管理、补丁系统,让开发者能专注于功能本身,而不是重复造轮子。
- 庞大的社区:遇到问题几乎总能找到解决方案或讨论,插件共享格式也基本成为社区标准。
- 对开发者友好:清晰的API和丰富的示例,降低了开发门槛。
实操心得:对于一款全新的、不确定支持哪种框架的游戏,我通常会先尝试BepInEx。因为即使游戏使用IL2CPP,BepInEx 5.x的兼容层也大概率能工作。它的“非侵入式”设计理念,意味着即使安装失败,也几乎不会对游戏原文件造成损害,安全系数最高。
3. 手把手安装与配置BepInEx
理论说得再多,不如动手一试。我们以一款假设的、使用Mono后端编译的Windows PC版Unity游戏《MyDemoGame》为例,演示完整的安装流程。IL2CPP版本的安装流程在核心步骤上一致,只是需要下载对应的BepInEx_il2cpp_版本号.zip包。
3.1 环境准备与版本选择
- 定位游戏根目录:找到你的游戏安装位置。通常是通过Steam等平台安装后,在库中右键游戏 -> “管理” -> “浏览本地文件”。这个包含
游戏名.exe和游戏名_Data文件夹的路径就是根目录。 - 下载BepInEx:访问BepInEx的GitHub发布页。对于大多数Mono游戏,下载
BepInEx_x64_版本号.zip(64位系统)或BepInEx_x86_版本号.zip(32位游戏)。如果不确定,可以查看游戏主exe文件的属性。关键点:务必下载与游戏位数匹配的版本。 - 备份游戏(可选但强烈建议):复制整个游戏文件夹到另一个位置。这是避免意外发生的最佳保险。
3.2 标准安装流程详解
安装过程其实就是解压与替换,但细节决定成败。
- 解压压缩包:将下载的ZIP文件中的所有内容解压出来。
- 复制文件:将解压出的所有文件和文件夹(主要是
BepInEx文件夹、doorstop_config.ini、winhttp.dll等)直接复制到游戏根目录。 - 处理冲突:如果提示有文件已存在(通常不会,除非是重装),选择覆盖。
winhttp.dll和doorstop_config.ini是注入的关键,必须存在。 - 首次运行与验证:
- 双击游戏主exe启动游戏。此时,游戏窗口可能会黑屏或停留一段时间(控制台窗口可能出现),这是BepInEx在初始化、扫描插件和打补丁,属于正常现象。
- 进入游戏主菜单后,观察游戏根目录下是否生成了完整的
BepInEx文件夹结构,特别是LogOutput.log文件。 - 按
F1键(默认快捷键),屏幕左上角或中央应该会弹出一个半透明的配置管理器窗口。如果能弹出,恭喜你,BepInEx安装成功!
注意:有些游戏的反作弊或加密可能会阻止BepInEx注入。如果游戏完全无法启动,或启动后无任何BepInEx痕迹(无日志文件),就需要尝试“兼容性安装”或查阅该游戏特定的Mod社区寻求帮助。
3.3 关键配置文件解析:doorstop_config.ini与BepInEx.cfg
安装后有两个配置文件至关重要,理解它们能解决很多疑难杂症。
doorstop_config.ini- 注入器门神这个文件控制BepInEx如何被加载。用记事本打开它,你会看到类似以下内容:
[General] # 是否启用Doorstop。如果设为false,BepInEx将不会被加载。 enabled=true # 目标程序集(BepInEx核心)的路径,相对于游戏根目录。 targetAssembly=BepInEx/core/BepInEx.Preloader.dll # 要重定向的DLL名称。当游戏尝试加载这个DLL时,会被重定向到BepInEx。 doorstopType=DOORSTOP_DLL_NAMEenabled=true:这是总开关。如果你暂时想以纯净模式运行游戏(比如联机时),可以将其改为false。targetAssembly:一般不需要改动,除非你自定义了BepInEx的安装路径。doorstopType:这个值(默认是winhttp.dll)必须与游戏根目录下那个用于“劫持”的DLL文件名一致。这是注入的核心原理:游戏会尝试加载一个系统DLL,Doorstop通过同名DLL“冒充”它,从而获得控制权。
BepInEx.cfg- 框架核心配置位于BepInEx/config目录下。它控制BepInEx自身的行为:
[Logging] # 控制台窗口是否启用。开启后可以看到实时日志,对调试非常有帮助。 Enabled = true # 日志输出级别。Debug信息最全,但日志文件会很大。 LogLevel = Info [Chainloader] # 加载插件时是否检查其依赖项。保持启用可以避免因缺失依赖导致的崩溃。 LoadDependencies = true [Preloader] # 控制台窗口的标题。你可以改成自己喜欢的名字。 ConsoleTitle = MyDemoGame - BepInExEnabled = true:强烈建议在调试Mod时开启控制台窗口,所有日志信息会实时打印,比查看日志文件更直观。LogLevel:默认Info即可。如果遇到诡异问题,可以临时改为Debug来获取海量信息,但记得问题解决后改回去,否则日志文件会迅速膨胀。
实操心得:我习惯在安装完BepInEx后,第一时间将doorstop_config.ini中的enabled设为true,并打开BepInEx.cfg中的控制台输出。这样,从第一次运行开始,我就能亲眼看到整个加载过程,心里有底。如果游戏启动失败,控制台最后几行红色的错误信息就是最好的线索。
4. 插件(Mod)的开发、安装与管理实战
BepInEx安装好了,现在它是空的,我们需要用插件来填充它,赋予游戏新的能力。
4.1 如何为你的游戏寻找和安装现成插件
对于大多数玩家来说,开发插件不是第一步,安装他人制作好的插件才是。社区插件主要发布在GitHub、游戏对应的Nexus Mods、ModDB页面或专门的Discord频道。
标准安装步骤:
下载插件:通常是一个.zip或.rar压缩包。
解压查看:解压后,查看文件结构。一个规范的BepInEx插件包应该包含:
插件名.dll(核心文件)manifest.json(描述文件,包含插件名、版本、作者、依赖等)- 可能还有
README.md说明文档、图标、或其他资源文件。
放置到正确位置:将整个插件文件夹(或者至少是.dll和manifest.json)复制到
BepInEx/plugins/目录下。- 正确示例:
BepInEx/plugins/MyAwesomeMod/MyAwesomeMod.dll - 错误示例:
BepInEx/plugins/MyAwesomeMod.dll(直接扔在plugins根目录,不推荐,难以管理)
- 正确示例:
处理依赖:有些插件需要其他库才能运行,例如
BepInEx.Harmony(用于打补丁)或UnityEngine.UI(用于修改UI)。这些依赖通常需要你手动下载并放入BepInEx/plugins目录,或者放在BepInEx/core目录(如果是核心扩展)。仔细阅读插件的安装说明。启动游戏验证:启动游戏,进入主菜单后按
F1打开配置管理器。你应该能在插件列表里看到新安装的插件,并且可以对其进行配置(如果开发者提供了配置项)。
4.2 开发你的第一个BepInEx插件:从“Hello World”开始
如果你想从消费者变为创造者,那么亲手写一个插件是最好的开始。你需要准备:
- 开发环境:Visual Studio 2022 或 JetBrains Rider。
- .NET SDK:根据游戏和BepInEx版本,通常需要.NET Framework 4.7.2或.NET 6.0/8.0。在Visual Studio安装器中勾选对应版本即可。
- 引用库:你需要引用游戏本身的程序集(如
Assembly-CSharp.dll,位于游戏名_Data/Managed目录)和BepInEx的核心库(位于你安装的BepInEx/core目录)。
步骤一:创建项目并设置引用
- 在Visual Studio中新建一个“类库(.NET Framework)”项目,命名为
MyFirstPlugin。 - 在解决方案资源管理器中,右键“引用” -> “添加引用”。
- 点击“浏览”,找到游戏目录下的
游戏名_Data/Managed文件夹,添加Assembly-CSharp.dll(这是游戏逻辑的核心)。同时添加UnityEngine.dll、UnityEngine.CoreModule.dll等你可能需要的Unity基础库。 - 再次“浏览”,找到
BepInEx/core目录,添加BepInEx.dll和0Harmony.dll(如果你打算使用Harmony打补丁)。
步骤二:编写插件基础代码一个最简单的BepInEx插件包含以下要素:
using BepInEx; using BepInEx.Logging; using HarmonyLib; // 1. 定义插件元数据 [BepInPlugin(PluginGUID, PluginName, PluginVersion)] public class MyFirstPlugin : BaseUnityPlugin // 2. 继承BaseUnityPlugin { // 3. 定义插件的唯一标识符、名称和版本 public const string PluginGUID = "com.yourname.mydemogame.myfirstplugin"; public const string PluginName = "My First Plugin"; public const string PluginVersion = "1.0.0"; // 4. 内部日志记录器,用于输出信息到BepInEx控制台和日志文件 internal static ManualLogSource Log; // 5. Awake方法是插件的入口点,在插件加载时自动调用 private void Awake() { // 初始化日志记录器 Log = Logger; // 输出一条日志,证明插件已加载 Log.LogInfo($"Plugin {PluginName} is loaded!"); // 6. 应用Harmony补丁(示例,下一节详细讲) Harmony.CreateAndPatchAll(typeof(MyFirstPlugin).Assembly); } }[BepInPlugin]属性:这是插件的“身份证”,BepInEx通过它来识别和管理插件。PluginGUID必须是全局唯一的,通常使用“作者.游戏.插件名”的格式。BaseUnityPlugin:所有BepInEx插件的基类,提供了日志记录器(Logger)、配置(Config)等实用工具。Awake()方法:相当于Unity脚本的Start,是插件逻辑开始的地方。
步骤三:编译与部署
- 在Visual Studio中按
F6生成项目。成功后在项目的bin/Debug或bin/Release目录下找到MyFirstPlugin.dll。 - 在游戏目录的
BepInEx/plugins下创建一个新文件夹,例如MyFirstPlugin。 - 将编译好的
MyFirstPlugin.dll复制到这个新文件夹里。 - 启动游戏。如果一切正常,你将在BepInEx的控制台或
LogOutput.log中看到“Plugin My First Plugin is loaded!”这条信息。恭喜,你的第一个插件工作了!
4.3 使用Harmony库进行游戏代码“打补丁”
仅仅加载插件还不够,我们要修改游戏行为。Harmony库是实现这一点的利器。它允许你在运行时修改其他方法(包括游戏本身的方法)的IL代码。
场景:假设《MyDemoGame》中有一个Player类,里面有一个Heal方法,我们想每次治疗时额外多回复5点生命。
找到目标方法:你需要使用dnSpy、ILSpy或JetBrains dotPeek等反编译工具打开游戏的
Assembly-CSharp.dll,找到Player类和Heal方法,记下它的完整签名(包括命名空间、参数和返回类型)。假设它是public void Heal(int amount)。创建补丁类:
using HarmonyLib; [HarmonyPatch(typeof(Player))] // 指定要修补的类 [HarmonyPatch(nameof(Player.Heal))] // 指定要修补的方法 class PlayerHealPatch { // Prefix补丁:在原方法执行前运行 static void Prefix(ref int amount) { // 修改传入的amount参数,额外增加5点治疗量 amount += 5; MyFirstPlugin.Log.LogInfo($"前缀补丁生效!治疗量被修改为:{amount}"); } // Postfix补丁:在原方法执行后运行 static void Postfix(Player __instance, int amount) { // __instance是原方法的this对象,即当前的Player实例 // 可以在这里做一些后续操作,例如播放一个特效音 MyFirstPlugin.Log.LogInfo($"{__instance.name} 接受了 {amount} 点治疗。"); } }[HarmonyPatch]属性:用于标记这个类是一个补丁类,并指定目标类和方法。Prefix:前缀补丁。在原方法之前执行。你可以修改传入的参数(ref关键字),甚至通过返回false来阻止原方法执行。Postfix:后缀补丁。在原方法之后执行。你可以访问方法的返回值(如果有,用__result参数)、this实例(__instance)和所有参数。- Transpiler:更高级的补丁,直接修改方法的IL指令,用于实现更复杂的修改,初学者可暂不深入。
应用补丁:在你的插件主类
Awake方法中,确保调用了Harmony.CreateAndPatchAll。这行代码会扫描当前程序集(你的插件DLL)中所有带有[HarmonyPatch]属性的类,并自动应用补丁。测试:编译并部署插件,进入游戏触发治疗行为。你会在日志中看到补丁输出的信息,并且玩家的治疗量确实增加了5点。
实操心得:使用Harmony时,最大的挑战是准确找到你要修改的方法。反编译工具是你的眼睛。务必仔细核对方法的签名(包括参数类型和返回类型),一个字母的错误都会导致补丁失败。另外,慎用Prefix返回false来完全阻止原方法,除非你完全清楚原方法的作用,否则可能导致游戏状态异常。在Postfix中读取和修改__instance的状态通常是更安全的选择。
5. 高级技巧、配置管理与性能优化
当你能熟练制作基础插件后,以下高级技巧将让你的Mod更加专业和强大。
5.1 为你的插件添加可配置项
一个优秀的插件应该允许用户自定义其行为。BepInEx内置的ConfigurationManager(通常按F1唤出)让这变得非常简单。
在你的插件类中:
private void Awake() { Log = Logger; // 1. 绑定配置项 // 创建一个新的配置绑定,当配置文件中没有对应项时,使用默认值。 EnableExtraHealing = Config.Bind( "General", // 配置节(Section)名称,在配置管理器中会分组显示 "EnableExtraHealing", // 配置项的键(Key) true, // 默认值 "是否启用额外治疗效果" // 描述信息,会显示在配置管理器中 ); ExtraHealingAmount = Config.Bind( "General", "ExtraHealingAmount", 5, new ConfigDescription("额外治疗量", new AcceptableValueRange<int>(1, 20)) // 定义可接受的值范围(1-20) ); // 2. 在补丁中使用配置项 Harmony.CreateAndPatchAll(typeof(MyFirstPlugin).Assembly); } // 3. 声明配置绑定对象 private static ConfigEntry<bool> EnableExtraHealing; private static ConfigEntry<int> ExtraHealingAmount; // 4. 修改Harmony补丁,使用配置值 [HarmonyPatch(typeof(Player))] [HarmonyPatch(nameof(Player.Heal))] class PlayerHealPatch { static void Prefix(ref int amount) { if (EnableExtraHealing.Value) // 读取配置值 { amount += ExtraHealingAmount.Value; Log.LogInfo($"前缀补丁生效!启用额外治疗,治疗量+{ExtraHealingAmount.Value}"); } } }现在,用户可以在游戏中按F1,找到你的插件“My First Plugin”,在“General”分组下看到两个滑块/复选框,并可以实时修改它们。修改会立即生效(热重载),无需重启游戏。配置文件会自动保存在BepInEx/config/com.yourname.mydemogame.myfirstplugin.cfg。
5.2 插件依赖管理与版本控制
当你的插件需要其他插件或库才能运行时,需要声明依赖。
在插件主类上添加[BepInDependency]属性:
[BepInPlugin(PluginGUID, PluginName, PluginVersion)] [BepInDependency("com.someauthor.anotherplugin", BepInDependency.DependencyFlags.SoftDependency)] // 软依赖,没有也能运行,但有则功能增强 [BepInDependency("BepInEx.Harmony", BepInDependency.DependencyFlags.HardDependency)] // 硬依赖,没有则插件加载失败 public class MyFirstPlugin : BaseUnityPlugin { // ... }HardDependency:必须依赖。如果指定的插件(通过其GUID识别)未加载,你的插件将不会加载。SoftDependency:可选依赖。你的插件会检查该插件是否存在,并据此调整自身行为(例如,如果某个UI框架存在,则使用更高级的UI)。
版本控制:在[BepInPlugin]中定义的PluginVersion字符串,以及通过[BepInProcess]属性指定兼容的游戏进程名和版本,都是管理兼容性的好习惯。
5.3 性能考量与最佳实践
- 避免昂贵的操作:在
Update、FixedUpdate或频繁调用的Harmony补丁中,避免进行复杂的计算、字符串拼接(特别是Log.LogInfo)、或实例化大量Unity对象(GameObject.Instantiate)。这些操作每帧执行会迅速拖慢游戏。 - 善用缓存:如果需要反复访问某个组件或计算结果,将其缓存到字段中。
- 谨慎使用
GameObject.Find:这是一个相对昂贵的操作。尽量在Start或Awake中查找一次并缓存引用。 - 及时清理:如果你创建了新的GameObject或订阅了事件,记得在适当的时机(如
OnDestroy)销毁对象或取消订阅,防止内存泄漏。 - 日志分级:使用
Log.LogDebug输出调试信息,在发布版本中通过配置文件将日志级别设为Info或更高,可以减少日志输出对性能的影响。
6. 故障排除与调试指南
即使按照指南操作,也难免会遇到问题。这里是一份常见问题速查表。
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 游戏无法启动,或启动后立即崩溃 | 1. BepInEx版本与游戏不兼容(如x86/x64错误)。 2. 游戏有反作弊或加密。 3. 某个插件或依赖损坏。 | 1. 检查LogOutput.log的最后几行错误信息。2. 暂时移除 doorstop_config.ini或将其enabled设为false,确认游戏本身能运行。3. 清空 plugins文件夹,逐一重新安装插件,定位问题插件。 |
游戏能运行,但按F1没反应 | 1. 配置管理器快捷键被修改或禁用。 2. BepInEx未成功加载插件。 | 1. 检查BepInEx/config/BepInEx.cfg中[Keyboard]下的ToggleConfigWindow键位设置。2. 查看 LogOutput.log,确认你的插件是否出现在加载列表中。 |
| 插件已安装,但游戏内无效果 | 1. 插件DLL放置位置错误(未放在独立文件夹)。 2. 插件依赖缺失。 3. Harmony补丁的目标方法签名错误。 4. 插件代码有逻辑错误或异常被捕获。 | 1. 确认DLL在BepInEx/plugins/插件名/下。2. 查看日志中是否有“Missing dependency”错误。 3. 使用反编译工具仔细核对目标方法签名(命名空间、类名、方法名、参数类型)。 4. 查看日志中是否有来自你插件的异常堆栈跟踪。在代码中增加更多 Log.LogDebug语句进行跟踪。 |
| 配置管理器中看不到我的插件选项 | 1. 插件没有使用Config.Bind创建配置项。2. 配置项的Section和Key名称有误。 | 1. 确保在Awake方法中正确调用了Config.Bind。2. 检查配置文件 BepInEx/config/你的插件GUID.cfg是否生成。 |
| 游戏运行一段时间后卡顿或崩溃 | 1. 插件存在内存泄漏(未销毁对象、未取消事件订阅)。 2. 某个补丁或循环逻辑性能开销过大。 | 1. 使用性能分析工具(如Unity Profiler,如果游戏支持)或任务管理器观察内存增长。 2. 禁用部分插件,定位问题插件。检查插件中是否有在 Update中执行重负载操作。 |
调试利器:日志系统再次强调,LogOutput.log是你最好的朋友。学会阅读它:
[Info]:一般信息,如插件加载成功。[Warning]:警告,可能有问题但不致命。[Error]:错误,需要关注。[Fatal]:致命错误,通常导致崩溃。- 搜索你的插件名或GUID,快速定位相关日志。
- 开启
Debug级别日志可以获得最详细的信息流。
一个真实的排错案例:我曾为一个游戏制作Mod,补丁始终不生效。日志显示插件已加载,但无错误。最后发现,我反编译看到的方法签名是public void Heal(int),但实际游戏更新后,方法内部实现变了,虽然签名没变,但我补丁中访问的某个私有字段名已更改,导致补丁被静默跳过。解决方案是:使用Harmony的Debug模式编译我的插件,并在日志中看到“未找到方法”的警告,从而意识到问题所在。教训是:游戏更新后,即使Mod还能加载,也需重新验证补丁的目标。