新闻详情

新闻详情

首页 / 资讯中心 / 详情

从零到一:BepInEx插件开发与Unity Mod制作完整指南

发布时间:2026/9/19 11:33:14来源:尧图网络
从零到一:BepInEx插件开发与Unity Mod制作完整指南
前两天有个群友在群里发了一张截图游戏目录里 BepInEx 文件夹、plugins 文件夹都建好了他自己照着网上的模板用 Visual Studio 写了一个插件扔进去之后日志里却什么都没有。这个问题我太熟了。BepInEx 插件开发这件事大部分人第一道坎根本不是 C# 代码本身而是版本选型、工程配置和运行机制没对齐。BepInEx 是目前 Unity 游戏 Mod 圈子里事实标准的前置框架Visual Studio 是写 C# 插件最顺手的 IDE两者组合起来一条完整的 Mod 开发流水线并没有想象中复杂。这篇文章会把这条流水线完整拆开讲一遍从 BepInEx 版本怎么选、VS 工程怎么建到插件入口怎么写、Harmony 补丁怎么打再到调试怎么挂、乱码和加载失败怎么排查。适合手里已经有一款 Unity 单机游戏、想从单纯的玩家进一步变成 Mod 开发者的朋友也适合刚入行想做游戏扩展的 .NET 开发者。1. 动手前的准备版本选型与前置安装1.1 先搞清楚BepInEx 5和BepInEx 6的差别进入正题前先说一个绕不开的问题下载 BepInEx 时你会在 GitHub Releases 和各大整合包站点看到两种版本5.4.22 和 6.x 预览版。很多新手直接下载了标题里带 6 的最新版然后拿着 5 的教程写代码最后各种加载失败。稳妥起见2024 年做常规 Unity Mod 开发我的建议依然是先用 BepInEx 5.4.22 起步。原因很简单BepInEx 5 是基于 Mono 运行时设计的生态最成熟社区教程、现成模板、老游戏兼容性几乎都围绕它展开BepInEx 6 是官方在推进的新一代底层换成了 .NET方向没问题但配套工具链和第三方插件生态还没完全跟上遇到的很多问题你可能连搜都搜不到答案。除非你明确知道自己要打交道的游戏必须用 6一般是较新的 IL2CPP 游戏否则别让最新版成为你的第一课。像英灵神殿这类老牌 Unity 单机游戏社区里的 Mod 至今还是以 BepInEx 5 为底座在运行这也从侧面说明 5 的稳定性经过了大量实战验证。这一块的选型逻辑我做了个简单的对照表对比项BepInEx 5.4.xBepInEx 6.x主流程度高绝大多数单机 Unity Mod 都用它预发布状态生态还没完全迁移插件目标框架.NET Framework 3.5~4.8.NET 6IL2CPP 支持不支持传统版有 IL2CPP 实验支持新手友好度高教程最多中等需要排查更多环境问题如果你手里的游戏是两年内比较大众的 Unity 单机作品默认选 5.4.22 基本不会错。这里也顺便纠正一个很常见的误区BepInEx 的 x64 和 x86 两个压缩包不能互换下载前先确认游戏主程序是多少位的否则注入阶段就直接失败。怎么看在任务管理器里找到游戏进程看“平台”列或者用 Dependency Walker 一类的工具打开游戏主程序看架构。1.2 Visual Studio需要安装哪些组件写 BepInEx 插件本质上是用 C# 编写一个类库所以 Visual Studio 这边只需要一个工作负载就够在 VS Installer 里勾选“.NET 桌面开发”。它会帮你把 .NET Framework 4.8 的 Targeting Pack、MSBuild、C# 编译器一起装好。社区版就完全够用不需要 Enterprise。这里有一个特别容易混淆的点VS 的扩展市场里有一个官方出品的“Unity 工具”扩展很多人以为写 BepInEx 插件开发也需要它。那个扩展是给“开发 Unity 引擎本身”的人用的用来在 VS 里调试 Unity 编辑器、查看场景和资源。而我们做 Mod 开发是在游戏运行时做扩展根本走不到 Unity 编辑器那一步所以这个扩展可以完全忽略装不装都不影响。另外一个细节如果你在创建项目的时候发现模板里找不到“.NET Framework 类库”说明你的 VS 工作负载没装全。用 VS Installer 修改安装在“.NET 桌面开发”下面把 .NET Framework 4.8 开发工具包勾上然后重启 VS 就能看到了。不要为了省空间跳过这个组件后面所有工程配置都依赖它。1.3 正确把BepInEx解压进游戏目录前置安装这个环节看着简单实际踩坑率很高。正确做法是从 Releases 页面下载对应架构的压缩包解压后把压缩包里的所有文件BepInEx 文件夹、doorstop_config.ini、winhttp.dll原样释放到游戏根目录也就是游戏主程序 exe 所在的那个目录而不是释放到游戏目录下的某个子文件夹里。很多人的第一个问题就出在这里只复制了 BepInEx 文件夹漏掉了 winhttp.dll。这个 DLL 是 BepInEx 的启动注入器它必须和游戏 exe 同级BepInEx 才能通过 Unity 的 Doorstop 机制在游戏启动早期把自己挂载进去。少了它你后续写再多代码都是白搭游戏日志里一点痕迹都不会有。装好之后第一次启动游戏BepInEx 会生成自己的目录结构包括 config、plugins、logs 这些子目录同时根目录可能出现一条控制台窗口。看到这个窗口基本就说明注入成功了。Steam 游戏的话记得先在库里面右键游戏 - 属性 - 已安装文件 - 浏览打开本地目录不要手动瞎猜路径。如果游戏原本就整合过 Mod 环境先检查根目录里是不是已经存在 BepInEx存在的话要先确认版本避免新旧文件互相覆盖。1.4 快速判断游戏是Mono还是IL2CPP这个判断很关键直接决定你能不能按这篇文章的流程做下去。Unity 游戏有两种脚本后端Mono 和 IL2CPP。Mono 构建的游戏会保留一个名为 Assembly-CSharp.dll 的托管程序集通常放在游戏目录下带 _Data 后缀的文件夹里的 Managed 子目录中IL2CPP 构建的游戏则是把 C# 代码全部转成 C 再编译产物叫 GameAssembly.dll体积通常比较大。BepInEx 5 的常规插件只能针对 Mono 游戏工作因为它的核心是直接托管注入如果你面对的是 IL2CPP 版本就必须使用 BepInEx 6 的 IL2CPP 路线而且里面涉及的 API 和调试方式差异很大。判断方法很简单先在根目录找有没有 GameAssembly.dll有大概率是 IL2CPP再找 _Data/Managed/Assembly-CSharp.dll有就是 Mono。新手第一次练手一定要选 Mono 版本的游戏这个选择能帮你绕开后续一半以上的坑。这里顺便提一下热搜里面经常出现“gameassembly.dll的作用”“bepinex压缩包”这些词很多人其实是被 IL2CPP 游戏卡住了。如果你手里的游戏只有 IL2CPP 版我的建议是先换一个 Mono 版的老游戏练手把基础流程跑通再去研究 IL2CPP 的特殊方案。顺序不要反。2. 搭建插件工程类库项目与程序集引用2.1 为什么建“类库”而不是“控制台应用”我第一次写 BepInEx 插件的时候习惯性地建了控制台项目结果编译出一堆带 Main 入口的 exe扔到 plugins 里毫无反应。你要理解BepInEx 插件不是一个独立程序它是一段被 BepInEx 进程加载并执行的托管代码所以工程类型必须选 C# 的“类库”最终产物是一个 DLL由 BepInEx 的插件加载器在合适的时机创建实例。类库工程没有固定的入口方法这一点对很多刚从 WinForms 或控制台转过来的人不太习惯。BepInEx 是通过约定来找插件的找到继承 BaseUnityPlugin 的类让 Unity 的 MonoBehaviour 生命周期接管它所以你的插件本质上是一个被动态实例化的 MonoBehaviour。想通这一点后面写代码就不会觉得“我明明什么都没调用Awake 怎么自己就跑了”。创建项目的时候在 VS 里搜“类库”就能看到模板注意选择带(.NET Framework)后缀的那个而不是默认的“.NET 类库”。如果看不到这个模板回到上一节说的补装 .NET Framework 开发工具包。2.2 目标框架选.NET Framework还是.NET 8这一步是新手最容易踩的坑。VS 2022 默认新建的类库项目通常面向 .NET 8 或 .NET 6这种项目编译出来的 DLL 拿到 BepInEx 5 里基本没法用因为 BepInEx 5 的运行时是基于 Mono 的它不认识较新 .NET 运行时要求的那一堆依赖。正确做法是把目标框架改成 .NET Framework 4.7.2 或 4.8。为什么是 4.x 而不是 3.5Unity 2018 之后的版本内置 Mono 对 .NET Framework 4.x 的支持已经比较完整BepInEx 5 官方插件模板也是基于 4.x 编写的。如果选太老的 3.5有些 C# 语法和基础库特性用不了如果选太新的 .NET 8游戏里的 Mono 运行时又缺失相关组件。项目创建后右键项目 - 属性 - 目标框架把它改成 .NET Framework 4.8 即可。语言版本这一项就不用太保守了只要编译器支持C# 9、10 甚至更新的语法都可以用因为最终编译出来的仍是 .NET Framework 程序集不依赖运行时的语法特性。所以字符串插值、switch 表达式这类现代写法放心用。2.3 添加BepInEx.dll和0Harmony.dll引用接下来进入第一个真正的“连接”动作把 BepInEx 的核心程序集引用到项目里。在解决方案资源管理器里右键项目的“引用” - 添加引用 - 浏览先去游戏目录下的 BepInEx\core 文件夹选中 BepInEx.dll 添加进来。如果你后面要用 Harmony 打补丁再选择 0Harmony.dll 一并添加这两个 DLL 的引用是基础。这里有一个必须记住的细节添加完引用后把两个 DLL 的“复制本地”属性改成 False。默认情况下编译器会把引用的程序集复制到输出目录也就是你的项目 bin 文件夹甚至 plugins 目录这会让 BepInEx 在加载时出现重复程序集、版本冲突一类问题。BepInEx 本身会在运行期从 core 目录加载这些程序集你把 DLL 复制到 plugins 目录反而帮倒忙。怎么改在解决方案资源管理器里展开“引用”选中 BepInEx.dll 和 0Harmony.dll看属性面板把“复制本地”切换成 False。改完之后项目运行时才能安心地引用 core 目录里的版本。2.4 把输出路径直接指向游戏的plugins目录开发体验在这个环节会有一个明显提升。右键项目 - 属性 - 生成在“输出路径”一栏填入游戏目录的完整路径比如 D:\SteamLibrary\steamapps\common\MyGame\BepInEx\plugins\。设置之后每次编译完的 DLL 都会自动出现在游戏插件目录省去手动复制的步骤。这个路径填绝对路径最省事。如果有同事协作或者换电脑可以改成相对路径但绝对路径在个人开发时完全够用。唯一要注意的是编译时如果游戏还在运行生成的 DLL 会被游戏进程锁定VS 会报“文件正在被另一进程使用”导致生成失败。所以开发期要么先把游戏关掉再编译要么养成“先改后跑”的习惯。plugins 目录放插件时直接放在根目录最稳妥。BepInEx 对子目录的扫描支持在不同版本上表现不一没必要为了整洁把 DLL 塞进嵌套目录里去找不痛快。项目名可以随便起但输出 DLL 的文件名最好保持和项目名一致方便出错时定位是哪个插件出了问题。3. 核心代码从空插件到能用的Mod3.1 插件入口类与BepInPlugin特性代码部分从最基础的入口类开始。BepInEx 通过一个标记了 BepInPlugin 特性的类来识别插件这个类必须继承 BaseUnityPlugin。BepInPlugin 特性有三个参数GUID、名称、版本号。GUID 是全局唯一标识约定用反域名格式比如 com.yourname.myfirstmod不要直接抄别人的 GUID否则两个插件会因为标识冲突而无法同时加载。看一下最简入口的样子using BepInEx; using BepInEx.Logging; namespace MyFirstMod { [BepInPlugin(com.yourname.myfirstmod, My First Mod, 1.0.0)] public class Plugin : BaseUnityPlugin { private void Awake() { Logger.LogInfo(My First Mod 加载成功); } } }Logger属性是 BaseUnityPlugin 自带的 ManualLogSource 实例直接用就好不需要自己 new。这行日志虽然简单但它是判断插件有没有被 BepInEx 识别的最快方式。这里再多说一句命名空间的习惯。建议用你的作者名或工作室名做前缀不要用默认的 namespace Project1一旦插件多了重名和混淆是大概率事件。养成一开始就起好名字的习惯后来能省掉不少排查时间。3.2 生命周期方法Awake、Update与OnGUI因为插件类继承了 BaseUnityPlugin而 BaseUnityPlugin 又继承自 UnityEngine.MonoBehaviour所以 Unity 的生命周期方法在这里全都有效。最常见的三个是 Awake、Update 和 OnGUI。Awake 在插件被加载时执行一次适合做初始化Update 每帧执行适合监听按键和轮询状态OnGUI 在 UI 绘制阶段执行适合绘制调试信息或简单弹窗。很多从普通 C# 转过来的朋友会困惑我没人 new 这个类Awake 怎么会被调用答案就是 MonoBehaviour 的生命周期不由你自己的代码控制而是由 UnityEngine 的游戏循环机制在合适的时机调用。BepInEx 在加载插件时创建了实例然后把后续流程完全交给 Unity 调度。想通了这一点你会发现插件开发其实就是“写一个特殊的 MonoBehaviour”门槛瞬间低了很多。生命周期方法里最容易踩的坑是性能。Update 每帧都会跑如果里面做了字符串拼接、日志输出、查找对象这类操作游戏帧率很快就会被拖下来。我一般习惯把高频输出用计数器限制住要么只输出状态变化要么每 60 帧输出一次测试阶段跑起来流畅得多。3.3 实战做一个按键提示Mod现在写一个真正能跑起来的示例按 F 键在游戏画面左上角显示一条“按键触发”的提示。这个例子不依赖任何具体游戏的内部类几乎可以在所有 Mono 版 Unity 游戏上直接验证。[BepInPlugin(com.yourname.myfirstmod, My First Mod, 1.0.0)] public class Plugin : BaseUnityPlugin { private bool _showTip; private float _tipTimer; private void Awake() { Logger.LogInfo(My First Mod 加载成功); } private void Update() { if (Input.GetKeyDown(KeyCode.F)) { _showTip true; _tipTimer 3f; Logger.LogInfo(玩家按下了 F 键); } if (_showTip) { _tipTimer - Time.deltaTime; if (_tipTimer 0f) { _showTip false; } } } private void OnGUI() { if (_showTip) { GUI.Label(new Rect(20f, 20f, 400f, 60f), Hotkey F triggered by My First Mod); } } }这段代码演示了三件事Input 检测、GUI 绘制、定时清除。你可以把 LogInfo 换成任何调试输出把 GUI.Label 里的文字换成你自己的内容。编译通过后启动游戏按 F 键应该能看到日志和左上角的提示。如果按键没反应先确认目标游戏用的是旧版输入系统。Unity 2019 之后有些新项目默认开启了新版 Input System旧的 Input.GetKeyDown 可能被禁用。判断方法是在游戏里能不能通过 UnityEngine.Input 相关 API 读到输入读不到就需要找输入系统的其他入口不过大多数 BepInEx 支持的 Mono 老游戏仍然是旧输入系统。OnGUI 里的 GUI.Label 性能一般只在测试阶段用不要真拿来做正式 UI。3.4 再进一步用Harmony打补丁改游戏逻辑按键提示只是验证环境真正让 Mod 具备“改变游戏规则”能力的是 Harmony。Harmony 是一个专门用来在运行时修改 .NET 方法逻辑的库BepInEx 5 的 core 目录里已经带了兼容版本。为什么 Mod 几乎都用 Harmony 而不是直接改游戏的 Assembly-CSharp.dll因为直接改原文件一更新就没了二无法分发三容易把游戏搞坏。Harmony 的特点是“运行时补丁”游戏文件保持原样补丁逻辑由你的插件动态加载。Harmony 最常用的两种补丁是 Prefix 和 Postfix。Prefix 在原方法执行前运行可以拦截参数、跳过原方法Postfix 在原方法执行后运行可以读取返回值、修改 ref 参数。下面是一个 Postfix 示例假设你在 dnSpy 里看到了某个游戏类 PlayerInventory 有一个 AddItem 方法using HarmonyLib; [HarmonyPatch(typeof(PlayerInventory), nameof(PlayerInventory.AddItem))] public static class Patch_AddItem { private static readonly ManualLogSource Log BepInEx.Logging.Logger.CreateLogSource(Patch_AddItem); [HarmonyPostfix] static void Postfix(int itemId, int count) { Log.LogInfo($AddItem called: itemId{itemId}, count{count}); } }注意一句PlayerInventory 和 AddItem 只是示例真实类名、方法名必须以你反编译出来的为准。方法参数也是一样参数名和类型都要从反编译结果里抄。正式使用前需要在插件 Awake 里调用一个 PatchAllvar harmony new Harmony(com.yourname.myfirstmod.harmony); harmony.PatchAll();PatchAll 会自动扫描当前程序集里所有打了 HarmonyPatch 特性的类并应用补丁。补丁写完后不要在 Awake 里反复 PatchAll只调用一次否则会打重复补丁同一方法被挂载多次可能造成诡异重复执行。Harmony 的威力在 Prefix 里更明显你可以在原方法执行前修改参数、改变返回值甚至直接 return false 跳过原方法。但能力越大责任越大乱改核心逻辑很容易导致存档损坏或任务卡死。开发阶段建议只加日志不改行为验证流程通了再逐步扩大修改面。3.5 调试输出Logger与Unity Debug的配合插件开发中日志是排查问题的第一生产力。BepInEx 的 Logger 分四个级别LogInfo、LogWarning、LogError、LogFatal分别对应普通信息、警告、错误和致命错误。日常开发我会在 Awake 里输出加载成功、在关键逻辑处输出参数、在 catch 里输出异常堆栈基本靠这三类日志就能解决大部分问题。Unity 自己的 UnityEngine.Debug.Log 输出也会被 BepInEx 捕获到 LogOutput.log 里所以两种日志都行。不过我个人的习惯是插件内部统一用 BepInEx 的 Logger原因是日志行会带上插件标签出问题的时候能快速定位是哪个插件在说话。比如用 CreateLogSource 创建的日志源输出样例是这样的[Patch_AddItem] AddItem called: itemId5, count1一眼就能看到来源。还有一个小技巧加入临时调试日志时用#if DEBUG包起来编译 Debug 配置时输出Release 配置时不输出。这样你正式发布 Mod 的时候不用一个个删日志代码改一下编译配置就干净了。开发阶段日志可以多用户到手后日志要克制这是 Mod 分发的一个基本素养。4. 调试与验证附加进程、看日志、断点4.1 附加到正在运行的游戏进程开发到这一步最爽的时刻来了当游戏在你眼前跑起来而你的断点精准命中了某一行代码。操作路径是先启动游戏确保插件已经被 BepInEx 加载然后在 VS 里点“调试”菜单 - “附加到进程”在进程列表里选中目标游戏进程点击附加再打开插件源码在你想暂停的地方打上断点触发对应逻辑即可。附加调试只对 Mono 版游戏有效IL2CPP 版本的托管代码已经被编译成 C 和二进制无法用传统托管调试器挂断点。这也是我一直强调新手先找 Mono 游戏的原因调试体验完全不是一个量级。附加之后如果发现插件代码里的断点一直不命中先检查一下是不是插件没有真正加载再看 VS 的“调试”窗口里代码类型是否包含了“托管(v4.6等)”这一项。附加完成以后游戏进程里的异常多数会在 VS 里直接中断局部变量、调用堆栈都可以正常看。这一套流程顺畅的话Mod 开发效率和“盲写 纯日志”相比是几何级提升。4.2 游戏启动太快插件断点跟不上怎么办附加调试最大的麻烦在于插件 Awake 往往在游戏启动最早期就执行了等你打开 VS、附加进程Awake 早就跑完了。应对办法有几种最简单粗暴的是在 Awake 里加 System.Diagnostics.Debugger.Launch()也就是调用一个程序化的调试器启动#if DEBUG System.Diagnostics.Debugger.Launch(); #endif当插件执行到这一行时系统通常会让调试器挂起并弹出选择窗口你选择当前 VS 进程就能接上断点。Mono 运行时对这个方法的支持并不是百分百稳定所以如果发现弹不出来不要死磕。更通用的办法是把想在 Awake 阶段验证的逻辑改成由按键触发比如在 Update 里按 F5 输出状态游戏加载完成后再人工触发这样就不需要抓住启动窗口期了。再给一个极端场景的备选方案真的需要断在 Awake就把 Awake 里的逻辑拆一部分到 Start 或者延迟协程里给附加留出时间窗口。踩过几次坑之后你就会发现调试这个事最靠谱的路径往往不是“越复杂越高级”而是“能不用断点就别用断点日志先行”。4.3 日志文件是排查问题的第一现场如果断点挂了半天都不稳定放弃断点转向日志是更务实的选择。BepInEx 的日志默认写在游戏目录 BepInEx\LogOutput.log。每次运行游戏这个文件都会重新生成记录插件加载链、异常、普通输出。开发时我习惯用 VS Code 或者 Notepad 直接打开这个文件开着自动刷新游戏操作一遍后回来一拉就能看到最新输出。LogOutput.log 的开头部分其实信息量很大。正常加载时你会看到 BepInEx 版本、游戏版本、Gatekeeper 状态然后就是所有插件的加载链路类似[Info : BepInEx] Loading [My First Mod 1.0.0]。如果你的插件名出现在这里说明加载成功如果只出现了其他插件而你就是找不到自己的插件那问题大概率出在插件放置位置、GUID 冲突、依赖缺失这三件事上。日志文件也会把异常堆栈打出来这是排查 MissingMethodException 和 TypeLoadException 的关键现场。看到异常先别急着换方案复制堆栈搜索关键异常类型很多问题其实在日志里已经写得明明白白。4.4 重新加载与热更新改完代码怎么最快生效BepInEx 社区目前没有特别成熟稳定的插件热重载方案常规操作就是“改完代码 - 重新编译 - 重启游戏”。因为游戏在运行时会锁定已加载的 DLL你会发现不退出游戏时编译会报文件占用错误。所以开发节奏往往是改代码、编译、退出游戏、重新开始游戏、看日志、再改。这个流程看起来麻烦但如果把前面 2.4 的输出路径配置做好了实际耗时几乎可以忽略。编译完的产物直接落到 plugins 目录重启游戏就是一次验证。我见过有些人为了省事硬塞一个独立线程去加载插件 DLL 实现“伪热重载”最终出了各种状态残留问题反而浪费更多时间。一个提升效率的小习惯把“启动游戏”这个动作固定成一条命令或脚本游戏路径和插件目录都写死这样每次改完代码只需要点一次编译和一次启动脚本。开发工具链的自动化程度决定了你能把注意力放在写逻辑上而不是放在点鼠标上。5. 常见问题与避坑实录5.1 插件没有加载先查这几个地方“插件没有加载”是出现频率最高的问题。按下面的顺序排查绝大多数情况几分钟内能定位。第一打开 BepInEx\LogOutput.log搜你自己的 GUID 或插件名没有出现就说明 BepInEx 根本没扫描到你的 DLL。第二确认 DLL 确实在 BepInEx\plugins 根目录不要放进子文件夹不要改成奇怪的文件名后缀。第三确认你编译的是 Debug 或 Release 配置里正确的目标别把旧的缓存文件误当成新产物。第四检查 GUID 是否和其他插件重复重复 GUID 会让 BepInEx 直接拒绝加载其中之一。还有一个很容易被忽略的问题程序集版本号格式。BepInPlugin 版本号要用三段数字如 “1.0.0”有些新写代码的人习惯写成 “1.0” 或 “v1.0.0”虽然不一定报错但会导致部分解析工具异常。尽量保持标准三段式少给自己挖坑。如果日志里插件名出现了但没有任何后续输出说明插件的 Awake 可能抛了异常。去日志里找Error级别的行通常伴随完整堆栈。我见过的大部分案例都是引用缺失比如插件引用了某个其他 DLL但该 DLL 没有被放在 plugins 或 BepInEx 的加载路径里。5.2 中文乱码四种场景四种解法“bepinex乱码”这个热搜词说明被中文乱码折磨的人不止一个。乱码分四种场景解决方式完全不同别一看乱码就以为是编码问题先定位是哪个环节。第一种BepInEx 控制台窗口中文乱码。这是 Windows 控制台代码页的问题。在游戏启动前或系统终端里执行chcp 65001把活动代码页切成 UTF-8控制台里的中文通常就正常了。第二种LogOutput.log 文件本身用记事本打开乱码。记事本对 UTF-8 无 BOM 的识别有历史问题用 VS Code 或 Notepad 打开一般直接正常显示。第三种插件源码里的中文字符串在代码里看着正常但日志输出到控制台乱码。检查一下源码文件编码是不是 UTF-8 with BOMVS 里通过“文件 - 高级保存选项”改成“Unicode (UTF-8 with signature) - 代码页 65001”。第四种游戏界面内的中文 UI 乱码或显示成方块。这不是字符串编码问题而是 Unity 默认字体不包含中文字形需要在 UI 层替换为带中文的字体资源。把上述情况整理成速查表现象本质原因处理方式控制台中文乱码Windows 控制台代码页不是 UTF-8执行 chcp 65001 或用 VS Code 查看日志文件用记事本打开乱码记事本对 UTF-8 无 BOM 识别差改用 VS Code / Notepad 打开源码字符串输出乱码源文件编码不是 UTF-8 with BOM高级保存选项改为 UTF-8 with BOM游戏 UI 中文变方块Unity 默认字体缺中文字形加载中文字体资源替换 UI 字体我之前在一个老游戏上做中文提示前三种都挨个踩了一遍最后发现最坑的是第四种字符串内容完全正确显示层字体没有中文字形看起来就像乱码。这种情况你改编码改到天亮都没用直接换字体才对路。5.3 MissingMethodException与程序集冲突你在开发时会碰到很多MissingMethodException或TypeLoadException这类报错十有八九和程序集版本冲突有关。最常见的原因是插件引用了 NuGet 上的 Harmony 2.x而 BepInEx 运行时加载的是它自带的核心 0Harmony.dll两个程序集版本不同方法签名或程序集标识对不上运行时找方法自然失败。解决办法很朴素引用的 0Harmony.dll 一定要从游戏目录 BepInEx\core 下添加而不是从 NuGet 下载并且把复制本地设为 False。BepInEx 自带的是兼容版本和插件环境匹配程度最高。Harmony 之外的第三方库引用也同理优先找“能在目标游戏 Mono 运行时里跑”的版本不要盲目追新。另一种情况是插件用了 .NET Standard 或 .NET Core 特有的基础类库方法比如 System.Text.Json 的某些 API在游戏的 Mono 运行时不支持。遇到这类问题替换成旧 API或者自己实现一个轻量解析别指望游戏运行时给你补齐新的 BCL。老 Mono 能带的东西有限写插件时要时刻想着“这段代码在五年前的 .NET Framework 环境里能不能跑”。5.4 IL2CPP游戏的GameAssembly.dll怎么处理GameAssembly.dll 是 IL2CPP 编译后的产物把原本的 IL 代码转化成了 C 再编译出的本地指令所以传统的 “引用 Assembly-CSharp.dll Harmony 托管注入” 方案天然失效。BepInEx 6 的 IL2CPP 分支提供了一套兼容层思路是在游戏早期初始化托管运行时再把 IL2CPP 的函数指针暴露给托管侧从而让 C# 插件能调用游戏内部逻辑。但 IL2CPP 路线对新手极其不友好。你不仅要做托管补丁还要懂 IL2CPP 的 Metadata 结构理解 il2cpp_api 的调用方式涉及的工具链也复杂得多。网上有一堆工具可以帮你从 GameAssembly.dll 和 global-metadata.dat 里还原大致的方法名和类结构但这类逆向分析只建议对你自己购买的正版单机游戏做学习研究不要用来做任何违规的事情。对绝大多数人来说第一直觉应该是绕开 IL2CPP 游戏而不是硬刚。如果非做不可路径大概是用 BepInEx 6 的 il2cpp build Il2CppDumper 一类的工具还原结构用 il2cpp 互操作 API 写插件。整个过程调试能力大打折扣断点几乎使不上劲基本靠日志和原生调试器配合。在没有底子之前别指望一个晚上就把 IL2CPP Mod 跑通。5.5 手机端Unity游戏能装BepInEx吗搜“bepinex 前置手机昨安装”的朋友多半是看到某个游戏的手游版想装 Mod。结论先说BepInEx 官方正式支持的平台主要是 Windows、Linux、macOS 桌面游戏的 Mono 或 IL2CPP 环境手机端尤其是 Android 和 iOS并没有官方版可用。Android 上有些社区维护的 BepInEx 移动端 fork但安装方式非常繁琐通常需要把文件写入到应用私有目录、修改 APK、设置环境变量还得处理签名校验很多游戏改完就闪退。iOS 因为沙盒和签名机制限制更严格基本没有公开可复现的方案。折腾小半天最后多半是白忙一场。想搞手机游戏的 Mod更现实的做法是去关注对应游戏社区的官方 Mod 接口或专用 Mod 加载器而不是硬套 BepInEx。如果只是想在手机上复现你写的桌面 Mod 效果我建议调整思路先在 PC 版把逻辑跑通再考虑平台适配而不是一上来就挑战移动端。这个顺序能帮你省下大量验证时间也更容易定位问题到底是“插件逻辑”还是“移动端环境”。6. 三件小事开发体验升级最后分享三个开发习惯都是我自己从反复踩坑里沉淀下来的。第一备份一份“干净的游戏根目录”。新手期改配置、删文件、乱放 DLL 是家常便饭如果把原目录备份好出问题直接还原比对着报错慢慢猜快得多。Steam 游戏的验证文件完整性也能救场但整体还原一个目录是最无脑的方案。第二写改动前先查日志写完后立刻看日志。BepInEx 的 LogOutput.log 基本能反映一切加载链、异常、警告你的思路要围绕日志文件展开而不是围绕“我觉得应该没问题”。很多时候你觉得代码没问题日志里却早就把原因写得明明白白。养成“日志优先”的调试习惯之后超过七成的插件问题都能在展开编辑器前解决。第三开发期插件里多写点用#if DEBUG包起来的调试输出发布前统一关闭。这样做既不影响用户运行时的性能又能让调试期间的线索不丢失。Mod 开发到了一定程度真正难的不是写代码而是“如何快速定位自己代码和陌生游戏环境之间的断层”日志在这里就是你的探照灯。希望这篇从零到一的长文能帮你把第一条 BepInEx 插件顺利跑起来后面就靠你拿着 Harmony 到处探索了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

GitHub热榜月报:从数据归档到大模型实战,这些项目值得一试 2026/9/19 12:27:22

GitHub热榜月报:从数据归档到大模型实战,这些项目值得一试

每个月月初我都有个固定动作:把上一个月的 GitHub 热榜从头到尾扫一遍,挑几个感兴趣的项目 clone 到本地跑一跑。这个习惯保持了好几年,热榜一年比一年热闹,但真正能让我愿意花几个小时去读代码、试功能的项目,其实一直…

阅读更多 →
如何快速上手 Hoppscotch:开源 API 调试与构建工具完整指南 2026/9/19 12:27:22

如何快速上手 Hoppscotch:开源 API 调试与构建工具完整指南

如何快速上手 Hoppscotch:开源 API 调试与构建工具完整指南 【免费下载链接】hoppscotch Open-Source API Development Ecosystem • https://hoppscotch.io • Offline, On-Prem & Cloud • Web, Desktop & CLI • Open-Source Alternative to Postman, In…

阅读更多 →
RK3568手动构建Linux 4.19内核镜像与设备树优化实战 2026/9/19 12:27:22

RK3568手动构建Linux 4.19内核镜像与设备树优化实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
x64dbg 用户数据库函数标记命令 `functionadd/func` 全解析:用法、校验与底层实现 2026/9/19 12:27:22

x64dbg 用户数据库函数标记命令 `functionadd/func` 全解析:用法、校验与底层实现

x64dbg 用户数据库函数标记命令 functionadd/func 全解析:用法、校验与底层实现 【免费下载链接】x64dbg An open-source user mode debugger for Windows. Optimized for reverse engineering and malware analysis. 项目地址: https://gitcode.com/gh_mirrors/x…

阅读更多 →
首件鉴定控制程序数字化落地:从.doc到可执行流程的关键解析 2026/9/19 12:27:22

首件鉴定控制程序数字化落地:从.doc到可执行流程的关键解析

简介:首件鉴定控制程序文件是一份面向制造业质量管理和生产现场的控制程序模板,主要适用于新产品、重大升级产品以及工艺发生变更后的首件检验需求。文件以企业标准为蓝本,系统给出了首件产品、首件检验(FAI)、公司内部…

阅读更多 →
Zephyr RTOS 在 NXP FRDM-KE15Z 开发板上的完整上手指南:硬件特性、系统时钟、串口控制台与 Linkserver/J-Link 烧录调试 2026/9/19 12:24:21

Zephyr RTOS 在 NXP FRDM-KE15Z 开发板上的完整上手指南:硬件特性、系统时钟、串口控制台与 Linkserver/J-Link 烧录调试

Zephyr RTOS 在 NXP FRDM-KE15Z 开发板上的完整上手指南:硬件特性、系统时钟、串口控制台与 Linkserver/J-Link 烧录调试 【免费下载链接】zephyr Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS f…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞