六月的晨光在落地窗上切成一道斜长的亮块,照得沈砚桌面上摊开的补丁日志边缘泛白。他昨晚没怎么睡,准确说是在那张折叠床上躺了大概三个小时,眼睛闭着但脑子里一直在转那行"exit code 0x3f7a"后面的注释。现在凌晨六点四十七分,他坐在工位上,保温杯里是昨晚剩的半杯凉透的红茶,茶渍在杯壁上凝固成一圈深褐的环。 他翻到第十六页,手指停在第三段的末尾。运维团队那次推送标号"P-1047"的补丁是在五月十二号凌晨两点执行的,操作人字段写着"zhao.yuan",时间戳与日志文件创建时间完全吻合。沈砚盯着那个名字看了十几秒,然后用指尖点了点显示屏边缘,把窗口切到运维系统的变更记录查询界面。他输入"zhao.yuan"和日期区间,回车后跳出来二十七条记录,大多是例行维护和服务器扩容操作,只有三条涉及游戏逻辑层的代码推送。其中两条有主策划张正的电子签名审批,第三条没有。 就是那条改了重试逻辑的。 沈砚从椅背上抓起那件藏青色的薄外套披上,拖着脚步往茶水间走。走廊里还空荡荡的,只有保洁阿姨在拐角处推着拖把车经过,轮子碾过地砖发出咕噜噜的声响。他用拳头砸了一下咖啡机的出液按钮,机器嗡鸣着吐出深褐色的液体,杯底聚起一层细密的油脂。他端起杯子凑到鼻尖,被烫了一下,然后把杯子搁在台面上等它凉。 手机震了一下,是微博的推送提示音。沈砚没有立刻看,先把杯子里的咖啡吹了吹喝了一口,才解锁屏幕。 那条推送来自一个他不关注的游戏资讯账号,标题是"神秘男子面馆怒怼黑粉?疑似'神陨之墟'主策划现身"。配图是一张模糊的侧脸照,角度显然是从面馆的角落里偷拍的,他当时背对门口坐着,扭过头跟那几个玩家说话的动作刚好被镜头捕捉下来,下巴线条和鼻梁的轮廓清清楚楚。底下的评论已经攒了三百多条,热评第一条写着"认出来了,这个人我在CJ展上见过,好像是星枢的游戏策划"。第二条是"笑死,自家副本没人打得过还要出来嘴硬"。第三条是个链接,点进去是某直播平台一位名叫"老K"的主播昨晚的录播回放,标题栏写着一行大红字:"神陨之墟·最终歼灭作战·死磕第十二小时·已崩溃"。 沈砚划掉了推送,把手机屏幕朝下扣在台面上。他靠在茶水间的墙边,后背抵着瓷砖的凉意,慢慢把那杯咖啡喝完了。杯子丢进垃圾桶的时候塑料壳撞上桶壁发出一声闷响,他站直身体,往工位走回去。 走到半路,赵元的工位已经亮了灯。那人侧对着过道坐着,正在戴耳机,桌面上放着一盒拆开的胃药铝箔包装,锡纸撕了一半露出两粒白色的药片。沈砚脚步顿了一下,没停,继续走到自己位置上坐下。椅子转过来的时候,他注意到赵元似乎也察觉到了他的动静,耳机摘了一只下来,但没有回头。 七点二十三分。沈砚打开一个空白的文档页面,开始整理昨天晚上在副本里录下来的数据。他按照时间轴把守门人·法尔斯的每一次技能施放都标注出来,旁边列上系统时间戳和角色血量波动曲线。到第七次落石的时候,他发现有两次的判定窗口比设计值宽了将近零点三秒——岩石碎块砸到地面的视觉特效比伤害判定早了三百毫秒左右,这意味着玩家的闪避动作如果在看到特效后才触发,实际上已经晚了。但如果是按音效来反应呢?他记得音效文件里有一层低频震动,混音师当初特意加进去作为警告信号。沈砚调出那次副本回放的文件,找到第七次落石发生的时间段,把音频轨单独提取出来,加载到波形编辑器里。波形图上,在视觉特效出现之前大约两百毫秒的位置,确实有一段幅度很低的次声波频段被压缩在了混响层下面。 这里有问题。沈砚用鼠标框住那段波形,右键标注:"次声波预警偏移?检查混音母带版本。" 他往椅背上靠了靠,目光从屏幕移到桌面那摞设计文档上。昨晚他在老赵面馆里跟那几个玩家说话的时候,嘴上是镇定的,心跳其实比平时快了将近二十下。他不太习惯被认出来,更不习惯在那种场合下面对一群情绪近乎沸腾的人。但他说的那些话——每一句——都是真的。每项机制都有破绽提示,问题在于这些提示的呈现方式在某个环节被人动过了。比如这个次声波偏移,如果是从混音阶段就出了问题,那它可以瞒过很多层面的审核,因为视觉和听觉对不上的时候人的直觉会归咎于"手感问题",而不是机制设计缺陷。 沈砚揉了揉眉心。他的目光再次落到赵元的名字上——不是他怀疑赵元动了什么手脚,而是那个"zhao.yuan"字段出现在补丁操作人栏里意味着很多种可能。可能是赵元执行了别人写好的脚本但他自己不知道里面包含了什么变更,可能是他被指派去推一个未经审批的紧急修复包,也可能是赵元本身发现了问题然后擅自改了代码想解决问题但搞砸了。沈砚需要排除其中几种,但直接去问赵元——现在就去——很可能会打草惊蛇或者导致对方心理防御收缩,什么都问不出来。 他保存了文档,站起身。隔壁部门的几个人陆续进来了,有人拎着塑料袋装的包子经过他工位旁边,油渍从袋底渗出来在桌面上印了一小圈。沈砚侧身让了一下,然后沿着过道往赵元的工位方向走。他在距离赵元还有三步远的地方停下来,因为赵元桌上的座机响了。 赵元接起来,声音很平:"运维,赵元。"对方说了什么,赵元嗯了一声,听了几秒,忽然抬手把耳机完全摘下来挂到脖子上,整张脸绷紧了。"你再说一遍,哪台服务器?"他问。电话那头的声音沈砚听不清楚,只能看见赵元握着话筒的指节泛白,停顿了大约两秒后,他低声说:"我马上看。" 挂了电话赵元就切到另一个屏幕的监控面板上,十指敲击键盘的动作又急又快。沈砚站在他侧后方,目光越过他的肩头落在那个不断刷新的错误日志窗口上——红字一行接一行地往上滚,开头全是同一个错误码。沈砚认得那个码,那是隐藏剧情线的触发条件校验失败时抛出的异常类型。 "出什么事了?"沈砚问。 赵元像是刚发现他站在那里,肩膀猛地缩了一下,转过头来的时候表情里混着意外和一种很淡的慌乱,但很快被压下去了。"测试服06区,"他说,语速比平时快,"副本实例在初始化阶段触发了某个条件分支,然后整个场景的交互状态机卡死了。现在是所有进入06区'神陨之墟'的玩家都会卡在进门前那块平台上,动不了,也退不出来。" 沈砚绕过桌子,站到赵元另一侧,盯着那个错误日志。异常堆栈的顶部指向一个函数名:CheckHiddenTrigger(),参数列表里传进来一个数值,那个数值在日志里被记录为"0x9E0007"。这个数字他记得——昨晚他在设计文档最底下的注释里看到过类似的一串十六进制标注,当时他用铅笔在旁边画了个问号。那个注释是他自己写的,写于去年十一月份的一个凌晨,内容大概是记录了一个未正式启用的交互校验方式,那套校验方式在开发阶段被搁置了,但因为它的底层接口已经跟主逻辑绑定,弃用的时候没有完全拆除干净,留下了几段条件判断像断掉的锁链一样挂在系统深处。 "我进去看看。"沈砚说。 赵元侧过头看他,嘴唇动了动像是要说什么,但又咽回去了。他点点头,让开了主控位置,沈砚坐下来登录了一个内部调试账号。加载画面切过去的时候,他看到那块平台确实是卡住的,角色静止在场景中,周围的环境粒子还在飘浮,但所有的交互按键全部失效。他调出控制台,输入了几条指令检查当前激活的状态机节点,然后发现触发这条异常分支的条件是一个非常具体的组合——玩家身上必须同时具备三个隐藏标识位,且当前游戏时间在某个特定区间内。这三个隐藏标识位正常玩家是不可能同时获得的,因为其中有一个需要在"神陨之墟"的某个前置副本里完成一个极其冷门的支线任务,那个任务的入口藏在一个可选对话的第三层分支里,官方攻略上从未收录过。 沈砚盯着控制台输出的那行状态列表,指腹无意识地摩挲着鼠标侧面的磨砂漆面。他脑子里在飞速往回翻——谁会在什么时候获得这三个标识位?除非是有测试人员特意用GM指令给自己刷了。他抬起头问赵元:"05区到08区这几个测试服的账号数据是从主服同步过来的还是单独建的?" 赵元从另一台机器上抬起头:"05和07是同步的主服快照,06和08是手工创建的测试账号池。" "那06区卡住的这个角色ID,你查一下它的创建方式和最近一周的操作记录。" 赵元敲了几下键盘,屏幕上弹出一张表格。沈砚侧着身子看过去,在那个角色ID的创建信息栏里看到"创建方式:批量生成",然后日志里有一条显眼的记录——五月十四号晚上十一点左右,有人在GM后台给这个角色添加了隐藏标识位,操作人的IP段是公司内网,但具体的操作人字段留空了。 "这东西是被人为加上的。"沈砚说。 赵元沉默了。他的视线落在那个空白的操作人字段上,喉结动了一下。沈砚没有看他,但能感觉到赵元的手停在键盘上方,没动。过了好一会儿,赵元开口,声音压得很低:"我可以查那个时间点的后台登录记录,看看是谁的token。" "查。"沈砚说。 赵元开始操作。沈砚坐在旁边的椅子上,目光落在监控屏幕跳动的数字上,脑子里同时在跑两条并行的线——一条是那个隐藏交互机制的问题,一条是赵元刚才接电话时的反应。赵元看起来对服务器出问题这件事是实打实地紧张,这意味着他至少不是故意制造这起事故的人。但他之前推的那个补丁呢?那个改了重试逻辑的补丁,操作人字段是他自己的名字,没有审批签名。沈砚在想等会儿要怎么开口问这件事才不会让对话变成审讯。 "查到了。"赵元的声音把沈砚拉回来。他盯着屏幕上的记录,眉头皱得很紧。"那天的登录记录显示,在那个时间点登录后台的账号是运维组的一个公共测试账号,使用人那一栏填的备注是……" 他停了一下。 "是'例行维护'。" 赵元说完这四个字之后,整个工位区安静了几秒。走廊里有人经过,脚底踩在地砖上的声音从远到近又到远,最后只剩下空调出风口的呼呼声。沈砚的右手食指在椅子扶手上轻轻敲了两下,节奏很慢。 "公共测试账号没有个人绑定?"他问。 "没有。"赵元说,"运维组四个人都知道密码。但这个备注……'例行维护'是这个账号的默认备注模板,用的人如果不手动改掉的话它就会自动填入这个。所以很难确定是谁。" 沈砚点了点头。他从椅子上站起来,走了两步到窗边,看着下面街道上逐渐密集起来的早高峰车流。阳光已经把整栋楼的侧面都照得发烫了,玻璃上贴着的那层半透明隔热膜在强光下显出细密的波纹状纹理。他把手插进外套口袋里,指腹碰到手机壳边角的位置,那上面有一条浅浅的裂纹,是上次被方睿拉着出去吃饭回来路上不小心摔出来的。 "赵元。"他背对着赵元说。 "嗯?" "五月十二号凌晨你推的那个补丁,P-1047号,改了副本的重试逻辑。那个是谁让你推的?" 身后安静了几秒。然后赵元说:"那个是张正张总给我发的邮件,让我第二天一早之前把那个包推上去。我收到邮件的时候是五月十一号下午六点,张总的邮箱发出来的,附件里带了一个修复包,压缩包备注说明写着'紧急修复副本实例化超时问题'。我当时看了一眼代码改动的地方,确实只涉及重试间隔调整,没有别的东西,就直接推了。" 沈砚转过身来。赵元坐在那里,两只手放在膝盖上,眼睛直视着他。他的目光很平稳,但嘴唇抿得有点紧——那种紧不是在掩饰什么,更像是一个被问到突然问题的人正在努力回忆细节时的表情。 "邮件你还有吗?"沈砚问。 "有。我一般不清除工作邮件。" 赵元打开邮箱界面,在搜索框里输入"P-1047",回车,第一条结果就弹出来了。沈砚走过去俯下身看屏幕,发件人确实是张正的内部邮箱地址,时间是五月十一号下午六点零三分,主题是"Re: 紧急补丁推送 P-1047"。正文没有多余的话,只有一行:"附件压缩包内容为已审核通过的修复包,请于5月12日早8点前完成06-09区推送。有问题及时联系。——张正。" 沈砚的视线在"已审核通过"那五个字上停留了一会儿。邮件没有附带任何审批单号,也没有抄送其他任何人。 "压缩包现在还找得到吗?"他问。 赵元摇了摇头:"推完我就按常规流程清掉了本地压缩副本。但运维系统里应该存了推送时上传的版本归档。" "调出来。"沈砚说,"对比一下归档包和邮件附件里的MD5值。" 赵元愣了一下,然后立刻反应过来这句话的意思——如果邮件里带的压缩包和实际推送到服务器的压缩包MD5不同,那说明有人在中间某个环节替换了文件。或者,更糟的情况是,邮件附件本身就和张正以为的"已审核通过的修复包"不同。 赵元的手在键盘上操作起来,动作比刚才更急了一些。沈砚退后一步站直身体,目光扫过整个办公区——现在已经有将近一半的工位坐了人,键盘声、电话铃声和同事之间交谈的低语渐渐汇成一片白噪音。他看到方睿从门口走进来,手里拎着一个纸袋,大概又是从楼下那家面包店买的早餐。方睿也看到了他,脚步转向这边走,但走到一半似乎察觉到了沈砚和赵元之间那种微妙的、绷着的气氛,停在半路,抬起手里的纸袋示意了一下,然后用口型问:"没事吧?" 沈砚摇了摇头,做了个"等一下"的手势。方睿点点头,往自己工位走过去了。 赵元敲完最后一个回车键,屏幕上弹出来两个MD5校验值并排显示。沈砚凑近去看——左边的值是邮件附件的哈希,右边是运维系统归档包的哈希。 两个值不一样。 赵元靠在椅背上,脸白了一层。他盯着那两行数字看了很久,然后把手从键盘上拿下来,搁在膝盖上。沈砚听到他用一种很轻、几乎被空调声盖过的声音说了一句话。 "那不是张总给我的东西。" 沈砚没有接话。他从口袋里摸出手机,看了一眼时间——八点十四分。季成蹊让他今天去办公室汇报情况,没说具体几点,但按往常的习惯,季成蹊一般九点之前就到公司了。 他把手机重新放回口袋里,低头对赵元说:"你把这个对比结果保存下来,截图,不要发给任何人。等我看完季总那边再决定接下来怎么处理。" 赵元点了点头。沈砚转身往自己工位走,经过方睿旁边的时候方睿正咬着一口可颂面包,腮帮子鼓着,含含糊糊地问:"去哪?" "季成蹊。"沈砚说。 方睿嚼了两下咽下去,用纸擦了擦手:"你昨晚没睡吧?黑眼圈都快掉到下巴了。你打算怎么说?" 沈砚拉开抽屉取出那本写满了笔记的活页本和昨晚在面馆被人拍下来之后一直没来得及仔细看的热搜截屏。他把东西装进一个帆布袋里,拉链拉上,然后直起身。 "照实说。"他回答。 方睿皱了一下眉,想说什么但沈砚已经往门口走了。到电梯口等梯的时候沈砚透过玻璃门看到外面走廊尽头的落地窗——阳光把整条走廊染成白金色,空气中的浮尘在光柱里缓慢翻卷。他想起昨晚在那间面馆里隔着雾气氤氲的玻璃窗看到夜雨顺着招牌边缘淌下来的样子,那时候他以为最难的部分是向一群愤怒的玩家解释一个他们不愿意接受的真相。 现在看来最难的部分才刚刚开始。 电梯到了,门打开时里面空无一人。沈砚走进去按下十七楼,金属门合拢的瞬间他注意到门板内侧有一道很浅的划痕,像是什么尖锐的东西从里面往外刮过留下的。电梯匀速上升,显示器上的数字跳过十五的时候他深吸了一口气,吐出去的时候吐得很慢。 帆布袋里的活页本边角硌着他的肋骨下方。他在心里把那几页要讲的内容重新过了一遍——副本数据异常、隐藏标识位的未授权添加、补丁包的MD5值不匹配、以及那条藏在他自己设计文档底部的、被遗忘的交互校验方式。所有这些东西串在一起形成一条线,而那条线的终点指向一个他暂时还没有把握说清楚的问题。 十七楼到了。门打开,面前是铺着浅灰色地毯的走廊,两侧的办公室门都关着。季成蹊的办公室在走廊尽头右侧第二间,门上的磨砂玻璃透出里面亮着的灯光。 沈砚走过去,在门前站定。他抬手,指节弯曲,在门上敲了三下。 里面传来季成蹊的声音,隔着门板听起来比平时低沉一些:"进。" 沈砚拧开门把手。