ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

IL2CPP 游戏上 BepInEx 6 为什么时好时坏:5 个高频故障的排查路径

IL2CPP 游戏上 BepInEx 6 为什么时好时坏:5 个高频故障的排查路径 IL2CPP 游戏上 BepInEx 6 为什么时好时坏5 个高频故障的排查路径【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx这篇文章写给给 Unity IL2CPP 游戏写插件、模组的开发者。你要解决的问题很具体BepInEx 6 在 IL2CPP 环境下启动慢得离谱、插件凭空消失、游戏直接闪退。下面 5 个问题按真实排障顺序排列每个结论都对应一条可验证的日志行或一个配置文件项你可以照着逐条查。先记住这条启动链后面 5 个问题都在它上面BepInEx 在 IL2CPP 游戏里的完整启动顺序是Doorstop在游戏进程最早期把入口劫持到预加载程序集Il2CppInteropManager生成互操作程序集把 C 侧的类型翻译成 CoreCLR 能加载的托管类型IL2CPPChainloader钩住il2cpp_runtime_invoke等 Unity 首个场景切换后才真正跑插件BaseChainloader做插件发现、依赖解析、按序加载。IL2CPP 环境的所有怪事基本都能定位到这 4 步中的某一步。IL2CPP 链加载器源码见 Runtimes/Unity/BepInEx.Unity.IL2CPP/通用加载逻辑在 BepInEx.Core/Bootstrap/。启动卡 10 分钟BepInEx 多半在后台重新生成互操作程序集结论先说你看到的首次启动长等待绝大多数情况不是卡死而是互操作程序集在重新生成。原理BepInEx 会把GameAssemblyWindows 上是 GameAssembly.dllLinux 上是 libil2cpp.so与全局元数据的 MD5 哈希和 Unity base 库、重命名映射一起打包计算结果写在互操作目录下的assembly-hash.txt。只要下列任一条件成立就触发重新生成互操作目录默认BepInEx/interop不存在assembly-hash.txt缺失或内容与当前哈希不一致游戏更新、改过UnhollowerDeobfuscationRegex都会变。重新生成的流程是删除interop里所有旧 dll → 下载解压对应 Unity 版本的 base 库unity-libs目录→ Cpp2IL 生成 dummy assemblies → Il2CppInterop 生成互操作程序集 → 写入新哈希。源码在 Il2CppInteropManager.cs。排查时盯三条日志日志关键字含义Detected outdated interop assemblies, will regenerate them now哈希不匹配进入重新生成Running Cpp2IL to generate dummy assemblies from ...开始逆向 GameAssembly这一步最耗时Cpp2IL finished in 00:00:1x.xxx直接读耗时作为你的基线数字两个常用开关[IL2CPP] UpdateInteropAssemblies false不自动重新生成。副作用是哈希变化时只打一条Interop assemblies are possibly out of date警告并提示你手动创建assembly-hash.txt塞入指定哈希来闭嘴。适合锁定游戏版本、批量打包的场景。[IL2CPP] ScanMethodRefs true默认跟随 64 位进程扫描方法引用给被 IL2CPP 标记为未使用的方法生成 CallerCount 标记插件能引用到更多方法代价是生成变慢。日志显示 0 个插件加载BepInEx 在 4 个检查点会静默跳过硬编码的插件结论先说插件消失不是加载失败而是根本没进加载队列。BaseChainloader 的ToPluginInfoBaseChainloader.cs用 Cecil 静态解析每个 dll逐个检查任一不过就跳过并打 Warning。四个跳过的检查点按出现频率排序GUID 不合法。BepInPlugin特性的 GUID 不匹配^[a-zA-Z0-9._-]$就被拒日志原文Skipping type ... because its GUID ... is of an illegal format。带空格的 GUID、中文 GUID 都是典型。进程名过滤。插件声明了[BepInProcess]但当前进程名不在列表里日志Skipping ... because of process filters。版本冲突。同一个 GUID 装了多份只留版本最高的一份其余Skipping ... because a newer version exists。不兼容声明。[BepInIncompatibility]声明的插件也存在时本插件整包移除日志级别是 ErrorCould not load ... because it is incompatible with。另外还有一条 WarningPlugin [...] targets a wrong BepInEx (...) and might not work until you update——插件编译时引用的 BepInEx.Core 比你当前版本新说明 dll 和框架版本不匹配。可复现的验证方法把BepInEx.cfg里[Logging.Disk] LogLevels调低到包含 Warning重启游戏后 grepLogOutput.log里的Skipping每一跳都会写明插件全名和原因不用猜。Doorstop 没生效怎么判断doorstop_config_il2cpp.ini 这 4 行是关键结论先说注入器问题先看配置文件仓库模板在 Runtimes/Unity/Doorstop/。IL2CPP 版和 Mono 版的模板差在两段最容易踩的 4 个配置项配置项模板默认值控制什么[General] enabledtrueDoorstop 总开关[General] target_assemblyBepInEx\core\BepInEx.Unity.IL2CPP.dll要执行的入口程序集入口方法必须是static void Doorstop.Entrypoint.Start()Mono 版指向BepInEx.Unity.Mono.Preloader.dll[Il2Cpp] coreclr_pathdotnet\coreclr.dllCoreCLR 运行时位置指错就是注入了但没动静[UnityMono] dll_search_path_override空Mono 模板为BepInEx\core游戏裁掉 mscorlib 时告诉 Mono 去哪个目录找核心库验证是否真的是 Doorstop 的问题临时把enabled改成false再启动游戏行为应当回退到完全干净的原游戏。如果禁用前后现象一模一样说明 Doorstop 根本没参与问题在更上层安装方式、游戏启动器绕过了 exe。反过来设环境变量DOORSTOP_DISABLE也是官方留的旁路除非你清楚[General] ignore_disable_switch的作用否则别动它。游戏更新后插件大面积失效BepInEx 的自动重建流程和离线做法结论先说游戏更新 →GameAssembly变化 → 哈希变化 → 重新生成这是预期行为不是故障。真正需要处理的只有两种情况生成过程本身失败或者你的机器离线导致 base 库下载失败。生成流水线里每一环都有独立报错Failed to generate Il2Cpp interop assemblies: {e}是总出口具体异常看它前面几行。下载失败时异常信息会直接告诉你怎么办把匹配版本的 base-libs zip 放进unity-libs目录或改UnityBaseLibrariesSource指向可用地址。离线场景的标准做法配置项说明文字里明确支持把UnityBaseLibrariesSource只填一个 zip 文件名不带 URL然后手动把该文件放进unity-libs目录。BepInEx 发现本地已有同名 zip 就不会发起任何网络连接。两个进阶项UnhollowerDeobfuscationRegex对混淆过的游戏匹配到的类型/成员会改用基于签名的稳定命名游戏更新后名字不变插件的硬编码引用不会碎。DumpDummyAssemblies true把 Cpp2IL 的 dummy assemblies 落到BepInEx/dummy排查某个类型为什么没被生成时直接翻这个目录。一个插件崩了会带崩游戏吗链加载器的隔离与级联跳过机制结论先说不会。两层 try-catch 把插件错误锁死在单插件范围但依赖链会级联跳过——你看到的一堆插件一起消失往往只有一颗坏蛋引起。隔离机制看 BaseChainloader.cs 的LoadPlugins每个插件单独包在 try-catch 里抛异常后该 GUID 被标记为 invalid错误写进DependencyErrors列表并打 Error 日志循环继续下一个插件。外层Execute还有一层兜底任何漏网异常会弹出控制台窗口并记录Error occurred loading plugins游戏进程继续跑。级联跳过长这样日志原文可直接 grepCould not load [AAA] because it has missing dependencies: BBB. Install the listed plugin(s) and restart the game. Skipping [CCC] because it has a dependency that was not loaded. See previous errors for details.CCC 自己没问题是它硬依赖的 BBB 没加载成功。排查时从Could not load根因Error 级开始看Skipping ... because it has a dependency that was not loaded连带Warning 级只是下游。磁盘日志的 4 个实用开关[Logging.Disk]段Enabled true默认写LogOutput.logLogLevels默认 Fatal|Error|Warning|Message|Info排障时把 Info 加进去InstantFlushing true每条日志立刻落盘注释里明说性能代价大但崩溃现场排障时是保命项ConcurrentFileLimit 5默认同时开 5 个以上游戏实例调试时调大。常见报错对照表看到日志先查这里日志关键字原文片段触发位置排查动作Detected outdated interop assemblies哈希校验首次/更新后正常频繁出现查游戏是否被反复替换文件Interop assemblies are possibly out of date关闭了自动更新按提示建assembly-hash.txt或重新打开UpdateInteropAssembliesCpp2IL finished in ...Cpp2IL记录耗时基线异常变慢时对比 GameAssembly 体积Failed to generate Il2Cpp interop assemblies生成总出口看前几行具体异常下载、磁盘、版本支持Failed to preload ... interop assemblies预加载阶段单个互操作 dll 加载失败记录文件名Skipping type ... illegal format插件发现修插件 GUID 字符集Skipping ... newer version exists版本冲突删掉旧版本 dlltargets a wrong version of BepInEx版本匹配用对应 BepInEx 重新编译插件Could not locate Il2Cpp game assembly原生库加载游戏改名/混淆过 GameAssembly确认游戏支持情况Unable to execute IL2CPP chainloader, no plugins will be loaded链加载执行前置所有日志的最后一条异常才是根因要点回顾与行动建议回顾一下 5 个问题的核心启动慢先找Detected outdated interop assemblies用Cpp2IL finished in量化耗时锁定版本时用UpdateInteropAssemblies false插件消失grepSkipping四个检查点GUID 格式、进程过滤、版本冲突、不兼容都有明确的日志原文Doorstop 问题先改enabled false做对照实验再查target_assembly与coreclr_path更新后重建是设计行为离线环境用本地 zip 替代下载崩溃隔离是单插件粒度根因看Could not load下游Skipping跟着就好。动手清单把LogOutput.log的LogLevels调到含 Info作为你的日常排障基线记下当前游戏版本的Cpp2IL finished耗时数字下次异常有对比基准游戏更新后第一次启动完整盯一遍Failed to generate/Failed to preload两类关键字再进游戏崩溃现场调试时临时打开InstantFlushing查完记得关回。照着这个顺序走绝大多数 IL2CPP 环境下的 BepInEx 稳定性问题都能在日志里找到确切的落点而不是靠猜。祝排障顺利 【免费下载链接】BepInExUnity / XNA game patcher and plugin framework项目地址: https://gitcode.com/GitHub_Trending/be/BepInEx创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表