!?PCL2修复下载?!
不修改 exe,恢复 PCL2 的 Minecraft 下载入口
一次PCL2的修复记录
一、前言
PCL2 是很多 Minecraft 玩家熟悉的启动器。它启动快、界面清爽,整合包、Mod、光影资源的下载也一直很方便。但在 2.99 版本之后,不少人和我一样发现:下载页里找不到“原版游戏”了,Minecraft 区域只剩下一句提示——
为遵守相关法律法规,PCL 不再提供 MC 下载功能,非常抱歉 qwq……
我去网上查找为什么会变成这样子的时候发现有人把Minecraft的圈钱服务器举报了也顺便把PCL2举报了,我以为只有PCL2不能下载了,可我发现其他启动器也有被关掉下载的渠道...
二、解决问题
1. 为什么不能直接改 exe
最直接的想法是静态修改 IL:把 LoaderInit 的方法体重写,把左侧入口的 Collapsed 改成 Visible,再保存回 exe。
但这个方案很快被否掉了。
静态改 IL 不只是改几个字节。至少要处理:
- 方法体的重新计算和写入;
- 元数据 token 的修复;
- 异常表的调整;
- 强名称、资源、BAML 等潜在影响;
- PCL 更新后偏移和方法结构全部变化。
更重要的是,PCL 是一个会自动更新的启动器。今天按 2.99.0.1 的偏移改好,明天换个版本就可能全部失效。对普通用户来说,改坏 exe 的代价也太高。
所以我最后选择了运行时注入:不碰 exe,在 PCL 启动后从内存里修补目标方法。
2. 用 AppDomainManager 找到注入点
.NET Framework 允许通过应用程序配置文件注册 AppDomainManager。在 Plain Craft Launcher 2.exe.config 里加上:
1 | <runtime> |
CLR 会在 PCL 的 Main 执行之前创建这个 AppDomainManager。我在这时启动一个后台线程,等 PCL 的入口程序集和 WPF 环境准备得差不多了,再用 Harmony 给目标方法打补丁。
这里有一个细节:只加 appDomainManager* 会让 CLR 退回旧式路径处理,PCL 内部使用的 \\?\ 长路径会失效,启动时可能直接报“没有对当前文件夹的权限”。所以配置里还要同时关掉 UseLegacyPathHandling 和 BlockLongPaths。
3. 第一个补丁:把加载器换回来
第一个目标是 PCL.PageDownloadInstall.LoaderInit。
思路不复杂:在这个方法的 IL 里找到 ldstr "关闭下载",它后面跟着的是那个会抛异常的假 LoaderTask。把从这条字符串开始、到下一个 ldarg.0 之前的整段指令替换成:
1 | ldsfld PCL.ModDownload::DlClientListLoader |
这样,PageLoaderInit 收到的就是真正的版本列表加载器,而不是一个一执行就抛异常的替身。
用 Harmony transpiler 表达,大概是这样:
1 | int start = list.FindIndex(i => |
当然,实际代码还要处理标签、异常块和指令边界,但核心就是“找到假加载器,换成真加载器”。
4. 第二个补丁:恢复左侧入口
第二个目标是 PCL.PageDownloadLeft..ctor。
需要改三处:
- 把两处
ldc.i4.2(Visibility.Collapsed)改成ldc.i4.0(Visibility.Visible); - 把
PageID的初始值从DownloadMod改成DownloadInstall; - 把
ItemMod.Checked = true改成ItemInstall.Checked = true。
这样,下载页打开时左侧会重新出现“原版游戏”,并且默认停在这个页面。
5. 补丁成功,按钮却没出现
这是整个过程中最有意思、也最容易被忽略的一个坑。
第一次运行时,日志明确显示两个方法都 patch 成功了:
1 | patched PCL.PageDownloadInstall.LoaderInit |
但打开 PCL,左侧还是没有“原版游戏”。
原因不在补丁本身,而在对象的生命周期:PCL 在 Harmony 生效之前,就已经创建了 PageDownloadLeft 的实例。构造函数补丁只对“以后创建的对象”生效,救不了那个已经存在的实例。它的 ItemInstall.Visibility 仍然是 Collapsed。
解决方法是加一层“活动实例修复”:在 PCL 启动后,通过 WPF 的 Dispatcher 找到 ModMain.FrmDownloadLeft,把 ItemInstall 和 LabResource 强制设为 Visible。日志里会多出一行:
1 | sidebar repaired: ItemInstall Visible |
这件事给我的提醒是:补丁成功,不等于目标对象被修复。 做运行时修改时,除了方法有没有被替换,还要关心对象是什么时候创建的、当前实例在哪里。
6. 把补丁做成工具
补丁跑通之后,我开始把它做成普通用户能用的工具。
工具是一个 WinForms 单文件程序,内部嵌入了 PclRuntime.dll 和 0Harmony.dll。它的工作流程是:
- 找到 PCL 目录,校验 exe 的版本和 SHA-256;
- 备份原来的
.exe.config; - 写入注入配置;
- 释放
PclRuntime.dll和0Harmony.dll; - 启动 PCL 后由运行时补丁接管。
卸载时反向操作:恢复配置备份,删除两个 DLL 和标记文件。整个过程中,Plain Craft Launcher 2.exe 本体不被修改。
后来我又把界面重新做了一版:去掉多余说明和日志框,只保留路径、状态和三个按钮;日志改为关闭工具时写入工具目录下的 日志.txt。这样界面更干净,排查问题时也仍然有记录可看。
7. 验证
修复后的日志大致是这样:
1 | injected, base=... |
打开 PCL,下载页左侧出现了“原版游戏”,右侧能看到最新版本、正式版、预览版、远古版和愚人节版。选择版本后可以进入安装页,Forge、NeoForge、Fabric、OptiFine 等选项也都还在。
我还在测试副本里实际点击了 26.3 的“开始下载”,确认它开始拉取原版 libraries 和 assets,而不是只把 UI 显示出来。测试完成后我取消了下载并清理了测试目录。
最后核对了一下 exe 的哈希,确认没有变化:
1 | 0DB34E19D9EEB6D496D20FABE786EC16BBD36BA6B0CCDC8D29CB7E909C114397 |
这也是运行时补丁相对静态修改的一个好处:PCL 本体仍然是原来的文件,卸载时只需要删掉配置和两个 DLL。
四、结尾
这个工具几乎都是AI完成的,如果有什么BUG可以到评论区反馈
祝PCL和龙猫越来越好
下载源码及软件密码:PCL2



