《许愿三秒,验收三天》系列这个系列记录我和 Claude 一起折腾 MC 铁路服务器的两个月:升级模组、做报站器、自动建造、自动排图。这是第一篇。
我一直想在服务器上用上 Distant Horizons(遥远的地平线)。这是一个能在 MC 里实现超远视距的模组,快三年前就支持和光影一起运行了。可我实测下来,能和光影一起跑的版本要求 Iris 1.7,Iris 1.7 只支持 MC 1.20 以上,而 MTR3 的最后一个版本 3.2.2 只支持到 1.19【虽然实验性地支持了 1.20,但全是 bug,也没人维护,附属模组也大多不支持】。
MTR(Minecraft Transit Railway)是一个能在 MC 里修铁路、开列车的模组。我的服务器几年下来攒了 206 个车站、二三十条线路,全靠它。想上 1.20,就只能升到 MTR4。可 MTR4 几乎是推倒重写,带着一堆破坏性变更:许多基于 MTR3 和 NTE 的自定义车辆资源包基本都用不了了;闭塞从固定闭塞强制改成了移动闭塞,以前按固定闭塞排好的图得全部重排;还多了几个我不喜欢的改动,比如不能再靠窗、不能坐下。
MTR4 出来的这两年里,我试着升级过好几次,每次都发现这些问题一个也没解决,官方也没留任何向下兼容的口子【比如,能不能让某条线路继续用原来的区间闭塞,而不是强制用移动闭塞?】。升级意味着体验变差,自定义车用不了了;还意味着一大堆额外的活,所有快车都得重排。一个人干这些,耗时太久了。于是懒癌发作:3.2.2 也能用,不就是一个 Distant Horizons 嘛,我不用不就行了,将就着玩吧。
转机来自工作。这一年写代码用 Claude 越来越顺手,自己和身边人的 vibe coding 体验也越来越好。某天我偶然想起这件搁置了快两年的事,灵光一现:是不是能让它帮我完成?
说实话,我挺有把握的。一来工作里已经见识过它的能力;二来,这是软件。我从小就喜欢软件,原因很简单:玩软件零成本,能备份,能回滚,失败了几乎没有代价。不像硬件,一旦坏了,前功尽弃不说,还可能要花一大笔钱修,或者干脆换新。所以初高中那会儿,我把各种 Windows 在自己的笔记本上装了一遍又一遍,后来是 Linux,甚至黑苹果……存档也一样,复制一份让它随便折腾,最坏也就是回滚。
8 月 22 日上午,我把服务器存档丢给 Claude,第一句话是这么写的:
mtr3到mtr4的升级很大,堪比重构的破坏性变更,为了更好的升级,你先帮我找一下3.2.2的mtr源码
那时候我只是想找一双手,帮我把这件搁置了两年的苦差事干完。没想到这一干,就是两个月。
动手之前
我原本的目标是 1.20.4。Claude 先把服务器上的 22 个 mod 挨个查了一遍:1.20.4 只有 9 个能用,1.20.1 有 20 个,少掉的两个我本来就打算放弃。目标遂改成 1.20.1。
它也没急着升级,而是先在存档副本上把 MTR4 自带的转换器模拟跑了一遍,挖出一个坑:我以前用别的模组铺过一条 450 km/h 的高速线,那几段轨道的类型 MTR4 不认识,转换时会被悄悄当成木轨道,限速变成 20 km/h,一句警告都没有,跑一趟要从一分半变成半个多小时。提前把这 12 段改掉再转换,206 个车站、121 条交路(MTR 里同一条线路的不同方向、快慢车、区间车都算单独的交路)一个不少,和事先模拟的数字分毫不差。
一节黑车厢
本体升完,进游戏,问题就一个接一个冒出来了。最难缠的是重庆 5 号线的车:一到它附近,游戏先卡死半分钟,然后车只渲染出一节,壳还是黑的。
这其实在意料之中。社群早就说过 MTR4 不支持这类车,显示得奇奇怪怪很正常。甚至还有点超出预期:那节黑车厢的形状是对的。能认出形状,说明已经有了初步的支持,剩下的大不了就是让它适配 MTR4 的识别方式。说白了,就是把一种数据结构转换成另一种,这活 AI 可太擅长了。
Claude 先后猜了四个原因:材质切换太多、模型面数太大、光影、预加载配置。它猜一个,我进游戏测一个,四次都是“问题依旧”。那时的 Opus 5 确实还有点不足,连续四次全是在猜。还好我终于忍不住了,打断它:“要不先看看mtr3+nte源码呢?”
它去读了这个车原本依赖的 NTE 模组的源码,才找到真因:资源包里的部件名都带着 NTE 的前缀,MTR4 却按不带前缀的名字去查,28 个部件里 24 个查不到。
这也是我觉得这件事“完成的可能性比较大”的地方:MTR、Fabric、NTE、JCM,全都是开源的。狠狠地钻研源码,总能看出点什么。Attention Is All You Need。
剥掉前缀,车出来了,接着是车门的毛病:开着开着就再也打不开。查门的时候,我在游戏里注意到一个细节:
车门虽然打不开,但是站台屏蔽门是能打开的,这个能否佐证你的判断
这句话直接排除了它两个候选原因中的一个:屏蔽门的开门信号是从车门那一层发出来的,屏蔽门能开,说明车门的数据还在,问题只能出在模型重建以后,车门没认出自己是门。顺着这条路又改了一轮,晚上八点二十五:
终于!门都能打开了!也没有卡顿了!


一个属于我的 mod
MTR4 那两个改动(不能坐下、不能靠窗)我一直耿耿于怀,另外还急需一个功能:给同一个站台的不同交路设不同的停站时间。这是排缓急接续的前提,快车在站里越行慢车,慢车得多停一会儿让路。MTR4 没有,配置也改不出来。于是当天下午,Claude 搭起了一个 mod 的骨架,我给它起名叫“yuzi的mtr扩展”。
做停站时间时,它原本打算另存一份数据,再自己做服务端和客户端之间的同步。我记得它早上读代码时提过,MTR4 已经给每个交路存了停站时长,就问它:
那我们直接改这个文件不就好了?改动小,数据也不用另存一份
最后数据直接存进了 MTR 自己的站台里。这个 mod 后来越长越大,到现在已经有 81 个提交,版本号走到了 1.7.0。

空洞
所谓空洞,就是线路上突然少了好几班车:起点站的 PIDS 显示下一班还要很久,从海之角坐 10 号线到海傍,后面的车只剩一辆。

第一次看到时刻表上的空洞时,我没当回事,以为是重启了服务器,车还没发出来。直到在线上跑了几天,它还时不时冒出来,我才知道这是个麻烦的 bug,而且是偶发的,排查起来比修还难。后来的事实也确实如我所料……
我把观察到的规律整理了一下发给它:
- 所有按真实时间发车的线路都不会有空洞,其余线路都出现过。
- 空洞不总是存在,有时整条线间隔都正常,有时又会出现。
- 我的猜想:空洞的出现,好像和玩家登录、或者到整点有关。
Opus 5 很快给出一个解释:服务器卡顿时,真实时间和游戏时间走岔,发车表跟着平移,正好滑过某个班次,就丢了一班。三条线索全都对得上。
我总觉得哪里不对:
真的是这样吗?……而且是连续跳过了好几次发车才出现的空洞……而且空洞出现时,起点站的pids上都会显示很长的发车时间,就像是发车系统自己知道会有空洞,而不是在要发车那一刻发生的。这样吧,你把你的大哥fable叫出来……
Fable 5.1 一通雷霆大思考,叽里呱啦翻了一大堆文件,一个回合就把原因、触发它的命令,连修法都列了出来。触发它的,是我平时为了看风景把游戏调成白天的 /time set 0,那天晚上我敲了四次。Opus 5 没有直接转述,先自己去日志里核了一遍,分秒不差。
我当时心里就一句话:我草,这 Fable 5.1 真的太牛逼了。我和 Opus 5 原地打转了好久的问题,它一个回合就破了案。又是一个瘫坐时刻。
原理其实不复杂:MTR4 里按游戏时间发车的车厂,发车表是跟着游戏时间走的。/time set 把游戏时间拨回去,整张发车表就往后挪了九分多钟,刚发过的几班又一次“到点”,可它们的车还在路上,撞上“同一个班次不能有两辆车”的检查,被悄悄吞掉。那晚连吞了五班,11 分钟没有车。PIDS 提前就知道,是因为发车表本身已经挪过去了。MTR3 判断发车用的是真实时钟,只会往前走,所以以前怎么 /time set 都没事。修法也简单:游戏时钟一下子跳得太多时,发车表不跟着跳。
这版修复由 Fable 来写,Opus 5 来审,还真审出一个问题:拒绝过一次跳变以后,锚点就被永久冻死,再也不会跟着正常的漂移走。后来这成了我的固定做法:一个写,另一个审。审查也不总是同一个方向,做“只能从车门上车”的隐形墙时,列车跑起来出现了重影,Opus 5 以为是墙的问题,Fable 一查,是 Opus 5 自己前面那个光影修复留下的回归。
我好像成了产品经理
升级做完那天,我吃完饭回来,脑子里想的是:科技改变生活啊,AI 改变生活啊。这些事我一个人肯定做不完。真要自己做,首先得精通 Java,用空闲时间学半年;再把这几个仓库的源码吃透,又得大半年;然后再修这些 bug,那我真是完全无法想象了……
我也深刻地意识到,自己已经成了一个产品加测试,尤其是产品。我觉得我真的挺适合当产品的……额,不过现在想来,我当产品,那也是完美契合我自己的需求。我的需求挺小众的,还爱在常人注意不到的地方钻牛角尖、做到极致【实际上可能对涨各种 KPI 没什么用】【悲】。所以,我还是不知道自己适合干什么。
那天夜里一点多,我装上了 Distant Horizons。从早上十点半发出第一句话算起,前后不到 15 个小时。搁置了两年的事,一天就做完了。远处的山和桥、夜里的城市,终于都看得见了。


至于这位产品经理的下一个需求,已经来了:让列车开口说话。
