点一下屏幕上北边那一格,客户端要先跑一次寻路,再写一个包发给服务器。这个包只有7个字节——56k拨号、Java Applet沙盒、600毫秒一次的服务器节拍,三条约束叠在一起,Jagex把一次多人3D世界的同步动作压缩到几个字节讲完。真正有意思的不是“老游戏真省”,而是这套省字节的克制后来变成了游戏本身没法改的规则。

一次点击,怎么变成所有人屏幕上的动作

走路请求包的结构很直白:1字节opcode,1字节说明包体长度,4字节起点坐标,路径拐点只发相对起点的偏移(一轴1字节,比绝对坐标省一半),最后1字节记录是否按住Ctrl。opcode本身还单独过一层ISAAC流密码加密,理由很实际——opcode决定后面怎么读这个包,不加密它,第三方客户端能直接把协议翻译出来。

  • 结论.直线上的中间格子根本不发,服务器自己按碰撞图补上,这才是真正的省法,不是省一两个字节的小聪明。

服务器600毫秒跑一次循环,这个频率刚好卡在客户端刷新和网络抖动之下——所以整篇设计谈的是省字节,不是省时间。同步走的是“位”而不是“字节”:玩家这一轮没变化,在更新包里只占1个比特;走一步,7个比特;传送,顶格也只要18个比特。按对该反编译客户端的示例分析,一次包含帧头的完整场景更新包最低能小到9字节左右——“没变化最便宜”这条原则被贯彻到了极致。

走路请求包:7个字节 opcode 1字节 长度标记 1字节 起点坐标 4字节 Ctrl键 1字节 合计 7字节
更新一个玩家的状态,要花几个比特 1 位·无变化 7 位·走一步 18 位·传送

“2004年”这个说法没那么精确

技术圈拿来做反编译分析的那份客户端,常被叫作“2004年的RuneScape”,但流传较广的317号客户端实际更接近2005年前后的修订版;连专门想还原原始版本的复刻项目2004Scape,自己承认手头的存档是当年5月18日那版,不是3月29日正式上线时的版本。“2004年”更像一个方便记忆的年代标签,不是精确版本号。考古式的技术写作最容易踩的坑,不是编数据,是把“大致对”当成“精确对”。


跟同年上线的魔兽世界比,两条相反的路

同一年11月,《魔兽世界》上线,走的是另一条路:连续世界、客户端插值和预测,靠“猜”和“补”把延迟藏起来,让画面看起来流畅。有对其流量的测量显示,那其实是一条很细的TCP流,单包负载均值在26字节左右——但这项测量未必对应2004年刚上线的客户端,只能当量级参考。RuneScape选的是反过来的做法:把延迟做成600毫秒一格的离散节奏,战斗、移动全部按格子走,延迟不用藏,它本来就是规则的一部分。

藏延迟,还是用延迟 RuneScape 离散600ms节拍 相对坐标增量 延迟=玩法节奏 WoW 连续世界渲染 客户端插值/预测 延迟要藏起来

这不是谁的架构更先进,是两种游戏类型对“流畅感”要不要的判断不同。魔兽世界需要连续的战场手感,不能露怯;RuneScape的乐趣本来就建立在慢一拍的策略节奏上,tick反而顺理成章。

省流从来不是免费的。update mask这套位打包机制效率极高,但也很脆:字段顺序、隐式状态全靠约定,私服和复刻项目里最常见的bug,就是某一块mask解析错了,后面所有玩家的数据全部错位。600毫秒的tick最初只是工程妥协,后来却变成了玩法本身的契约——战斗节奏、动画时长、寻路逻辑全部按tick对齐,想改tick时长,等于把整个内容体系推倒重来。

  • 风险.视距从来不是一个简单的半径参数,扩大视距意味着更多实体比较、更多掩码块、更多外观同步开销,成本落在服务器CPU和内存上,不只是带宽。
工程妥协撑得够久,就会长成没人敢动的游戏宪法。

那一次“向北走一格”,七个字节发出去,九个字节左右传回别人屏幕。这套精打细算撑住了拨号年代的多人世界,但真正留下来的不是省字节的技巧清单,而是一个更硬的判断:什么时候该把工程上的将就直接写进游戏规则,而不是想办法掩盖它。RuneScape把这道选择题做完了,做得足够彻底,以至于二十年后想改都改不动。