那些日子(十三)
这几天,许多同事 popo 上跟我聊天,谈及这段时间写的这个系列。老同事一刀(从大话一开始到现在一直在写游戏服务器),那是感慨万千,还帮我纠正了一处人名的错误;同样的有许多人,督促我修正一些小地方,我都一一改过了。有人聊起来,夸我记的好清楚,如同昨天才发生的一样。
真是不敢当,我的记性其实不好。记不清的人和事远比记下来的多,尤其容易忘记别人的名字,很惭愧啊。我只是写下那些能记住,可以理清前后因果脉络的故事;更多的人和事情,由于记忆残缺,分不清时间,不知道该放到故事的哪个角落。
我记得麻雀当年陪我选手机;记得美术部的一群长发帅哥集体去剃光头;记得给乌鸦夫妻参谋买房子;甚至记得牙牙来报道的那一天情景……
记得一刀他们在公司地板上过夜;记得 Mario 半夜里陪着 mm 在办公室里看流星花园;记得我们大家常去的大排档;记得凌晨两点干完活,一起打车去石牌东吃烤蚝,萝卜还一个劲的说没有他们家乡的好……
我只是记下自己的历程,但我不只是为自己写。我也为大家写,尽可能帮一起共事过的大家留下过去快乐的点点滴滴。美好的记忆不是什么可耻的事情 :) ,可耻的只是永远停留在回忆里的人,我想我们都不是这样的人。如果再有同行的朋友读过来,尽可以在留言中留下你的故事,或是提醒我一些被我遗漏的重大事件。
对于新加入网易的同事,据说有许多人是这个系列的读者,如果我写的能让迷茫的人看到一条模糊的路,那没有什么比这更能让我高兴的了。让我觉得在繁忙的工作之后,从每个晚上划出三个小时写这些很有价值。
网易之所以是一个好公司,正是因为不断的有同样信念的人聚集在一起。那些尚且不足的地方,需要大家一同努力。
以下是今天的正文:
说起国内自主研发的第一款商业上成功运营的 MMORPG,不应该算给《大话西游2》。
2000 年底,另一款网游悄然上线,并在 2001 年初成功收费,同时在线人数一度攀升到好几万,远超过当时失败的《大话西游》,它就是天晴数码的《幻灵游侠》。
我下载了一份《幻灵游侠》的 client ,发现居然是用 C++ Builder 做的,不由自主的想起了姚晓光。他 QQ 上的名字是 npc6 ,这个网名可能更多人熟悉一些。
2000 年在北京鹰翔的时候,我经常给林广利推荐一些写程序的网友过去工作,林广利不懂程序,也时常让我帮忙和一些来应聘的程序员谈,算是面试了。姚晓光和他的哥们陈晨就是那个时候进入的鹰翔。
加上在大学最后一年辍学的小蓝,和我的一个老朋友彭乐,他们一起做《碧雪情天》。一个单机游戏,后来也制作了同名的网络版。
姚晓光喜欢用 RAD 的工具做开发,所以尤喜 BCB 。我那时维护了一个风魂的 BCB 版,但之后由于 BCB 的一些 bug 把我弄的痛苦不堪,就放弃维护了。姚晓光就是给我 report 那些 BCB 版风魂 bug 的人。
他和陈晨不久后离开鹰翔,我没有打听去了哪里。直到《幻灵游侠》上线,好奇的网上一问,他还真的在天晴。
《幻灵游侠》运营的情况我不甚了解,但是半年后我和姚重逢在林广利的办公室里聊天时。我意识到这款游戏还是很成功的。姚晓光说他后来一个月能拿到三万的月奖金,让我心里暗暗惊叹。倒不是羡慕,只是觉得,网络游戏还真的能赚钱哪。
《大话西游一》的最后那几个月,公司给大家发了一次奖金,算是犒劳辛苦了快一年的兄弟们。我领到奖金时,古越和果子都走了,micro 还在,但没多少事做。那一次,似乎有几千块(或是一万?)的奖金。我总觉得我能拿这么多,是因为做 client 的人只剩下我一个。
两者一对比,足可见成功的项目与失败的项目之差别了。
不久以后,姚晓光和彭乐去了盛大制作《神迹》,小蓝来到了网易加入 3d 组(即以后的天下二),此是后话。
当《幻灵游侠》如火如荼之时,我们还在紧张制作这《大话西游 2.0》。当时国内市场上还有几款更为火暴的游戏,其中首推《传奇》。几乎占据了大半壁江山。《石器时代》的后续产品《魔力宝贝》也崭露头角。我几乎觉得形势已定,根本没想过产品日后要在商业上超过这些,但我单纯的想把大话2.0 做好。内心里,我把大话一的失败看成自己的一种耻辱。
前一次说了不少大话2 项目的好话,现在可以谈谈一些不足了。
其实大话2 的制作时间很短,主要是在程序上重来。美术则增加了不少素材,让游戏更加完备,这些工作并行进行,跟程序不起冲突。策划方面随着月心的离开,交到了黄华的手上,对我大话2 策划方面的制作流程几乎没有关心过,只记得黄华担任了最早的主策划一职,别的就没有印象了。
今天的眼光来看,大话二的 client 程序也存在许多的问题。尤其是在我经手的一些地方,如果能再一次重新设计,会做的更好一些,这个想法促成了后来与郭伟合作为《梦幻西游》重写 client 。
client 对网络包的解析模块做的很生硬,这部分是由詹东设计的,被 kyo 抱怨了很久。因为他把解析数据流的底层接口放到了脚本层。甚至需要程序员去数字节数,一旦数错,逻辑就会出错。这种过于底层的接口暴露,放到今天来看是绝对不合格的。
服务器逻辑和客户端逻辑都需要维护一些对象和 id 的对应关系表。我们起初的一个疏忽,希望可以利用 某种逻辑一致性,省略了中间的 id 转换过程,结果导致了后期无穷尽的麻烦。客户端的对象系统中,还包括许多界面元素和一些与服务器逻辑无关的对象,为了回避和服务器对象的 id 冲突,我们使用了许多极其丑陋的方法。
不过,也有一些灵机一动的有趣想法。有一天,有个美术(刘祺?)找到我,说能不能在聊天中插入一些包子符号?我想他们老是混 mop ,受了那些 874 、253 的影响。这倒是一个新鲜玩意,我已不记得当时 msn 可不可以发表情符号聊天了,至少 qq 还没有加上,我们的 popo 也不可以。当时我立刻联想到的就是猫扑论坛里那些可爱的包子(不过我是不喜欢 mop 的那种感觉,从来没泡过)。我想了下说,让我试试吧。
在 UI 控件里增添动画图片的支持花了我一个多月的时间。没有人告诉我该怎么做,应该做成怎样。我只是凭直觉写着。我想可以更丰富一些,让玩家可以方便的改变颜色,插入表情,甚至做出一些特别的效果(文字闪烁等)。按程序员习惯,通用的转义符号是 / 。但这个被服务器程序员用来扩展 GM 指令去了。我觉得其它很多符号对程序员来说有特别含义,最终选择了 # ,这个符合我觉得顺眼。
关于插入图片,原本跟策划聊天时,有人想用传统的 :) :( 这些。我表示反对,一则实现稍微麻烦,二则美术提供了几十个符号,以后维护这些转义符太烦琐。所以我自作主张的改成了简单的 # 加数字的形式。
这里另一个小插曲足以见得我们当时的仓促:第一批表情图片只有 64 个。据写服务器 ten 的经验,在以前的 mud 中,一旦用户拥有自己发送彩色文字的权利,总有玩家恶意去模拟系统公告来行骗。所以最好的方案是使用图片来标识频道。顺理成章的 65 号到 73 号表情就被频道图片占用了。
为了不让玩家可以输入这些频道图片,kyo 用了个简单有效但野蛮的办法,在显示聊天信息时,严格过滤掉 #65 到 #73 ,这也就是为什么网易游戏中一段游戏表情符号号码断层的原因。很傻,不是么?其实完全没有必要把玩家输入的表情符号与系统内部使用的图片混杂在一起。在 UI 上实现图文混排模块时,设计的稍微好一点,就可以回避这个问题。
这段代码写的太仓促了,也由于当时偏执的追求效率,一大堆词法分析和文字排版的代码拥挤在一起,留下不少隐患。后来大话2 client 许多 bug 都出在这里。是个深刻教训。无论是写程序还是设计,在经验不足的时候,还是要三思而后行。很久很久没有人愿意重写我那堆烂程序也是意料之中的事。实际工程中,几个人做的小项目,就不要指望自己犯下的错误会有后人来擦。我自己每次去改别人的 bug 时都郁闷的想吐血,自己不愿意做的事情,想必他人也不想去碰的。可见二进制复用还是满重要的,呵呵。接口清晰,出了问题换人重写即可。
莫小瞧这一点点东西,自己做过了才知道烦。后来许多人抄袭网易的产品,抄袭聊天这一块,却总也做不好。技术门槛虽然不高,也还是有那么一丁点。等到网易泡泡的项目需要加入图文混排的聊天框时,他们组专门拨了一个程序员专职写这样一个模块,弄了好久。
大话一到了后期,client 的问题显得不那么严重了。除了古越在后期维护修正了不少 bug 这个因素外;似乎玩家也习惯了 client 出错,反正我们的 client 重启飞快,几乎没有 loading 的时间。但还有一个让人哭笑不得的原因 —— 外挂横行。
大话一的通讯管道是明文的,随便用一个截包工具拦下网络包,做一个简单的黑盒分析就能看的一清二楚。有玩家用 MFC 写了个简单的程序就可以模拟我们的游戏通讯。因为不需要显示图象,又不用处理一些复杂逻辑,所以可以做的很稳定,甚至允许同时开几个帐号同时游戏。
在和 dingdang 聊这事时,他无奈的说,现在风巢(大话的一个高等级区域)里几乎已经没有活人了。机器人玩家对游戏的危害性,从 mud 时代开始,大家就深有体会。我想,这个问题一定要想办法解决。
当时最火暴的游戏之一《金庸群侠传》也深受外挂困扰,一度外挂可以做到官方 client 做不到的事情,比如可以远距离和 npc 对话。我想那是因为服务器未做限制的缘故。这些距离校验以往都是在 client 做的,而非法 client 可以轻易直达目的。当时业内传闻,为《金庸群侠传》写外挂的人都有百万级的收入了,真是令人乍舌。
dingdang 认为外挂问题很难解决,毕竟 client 在玩家手上,理论上无法阻止玩家分析通讯协议,并制作模拟程序。而 server 不可能分辨出究竟网络包是由怎样的程序发出。我们能做的只是把关键运算全部由服务器校验而已,让玩家做不出违反规则的事情。
我说,至少我们把通讯管道加密吧,别让人家那么容易的分析出来。要分析也得让他们分析我们的 client 程序本身(即做白盒分析),而不能仅仅靠截取网络包就够了(只做黑盒分析)。dingdang 表示通讯加密可能会加大服务器的负担,目前的硬件不一定承担的起。况且开发日程比较紧,新增加一个模块需要额外的测试,我们承担不起降低服务器稳定性的风险。离大话新版内测上线的日子不到一周了,从项目管理者的角度看,dingdang 是对的。我了解他,dingdang 和 kyo 都是在技术上很保守的人,这其实是一大优点,我们用一个褒义词来形容,那就是稳重。这份稳重保证了大话二程序的稳定,以及它的持久发展。但也可能让我们失去了一些东西,历史不能假设,谁又说的清呢?
我是一个技术上很激进的人,至少比现在的我激进多了。当时我认定,做通讯加密是至关重要的,而且得不惜一切代价在大话的新 client 对外发布的第一版之前完成。一旦流失了一个可以工作在明文环境下的 client ,都可能造成损失。加密和解密,外挂和反外挂,永远不会出现最强的矛和盾。这门技术总是游历于正统软件技术之外,属于旁门左道。我们争取的并不是一个完美的解决方案,只是延长时间而已。在过去的年代,加密技术延长的是软件被破解的时间,现在反外挂也只是拖延一个可用的外挂被制作出来而已。流出一个不设防的程序,无疑会大大减少外挂制作者的精力消耗了。
《应用密码学》这本书,在北京时就开始读了,一直觉得很有趣。到这个时候我已经读过两遍。我想,设计一个即简单,运行速度快,又少占内存的加密算法并不难。问题只在于留给我去实现的时间不多,还要保留一些时间说服 dingdang 整合进服务器里去。
大话西游 2.0 ClosedBeta 是在 2002 年 5 月 1 日对外开放的。我在一个古老的留言本上记录下了这一时刻。
看到当时自己的留言:
今天熬夜上传大话西游2.0 ClosedBeta 版中.... 明天就有人可以玩到我们这个新游戏了. 自己感觉马马乎乎. 还过得去. 总算搞完了啊.
(90) 云风 | 主页 | (2002-04-30 05:49:40)
仿佛回到了那一天。
我的加解密模块是两天前完成的,同时给 dingdang 讲解分析了 cpu 消耗,以及额外的内存占用情况。接口也设计的很简单。我想他很容易就被说服了,在最后两天全力把这些加入服务器。
上面这条留言是 4 月 30 日早上凌晨提交的,记得我那一夜我没有睡。同上一次大话西游一发布前夜一样,更多的是在打杂。检查各种数据是否完备。为了让压缩包更小一些。这次甚至又修改了动画的格式。
一个是在动画中插入控制信息,让动画的停顿可以直接用控制信息描述出来,而不用浪费资源去重复储存相同的帧。
另一点是将大面积的魔法光效做抽线处理,这样数据量就只有原来的二分之一。在渲染时,再把这些抽掉的线条用程序实时填补上。
做这些不仅是为了玩家的硬盘空间,减少下载的 client 的体积,更重要的还是想节省内存。以及提高运行时资料的加载速度。
这些工作也是在最后那几天做的。本以为大话二已足够顺利不需要赶在发行前熬夜了,没想到事都临头还是逃不过。不过已经比之前好的多了。至少我们是在 5 月 1 日的前一晚熬夜,而不是当晚。
其实一般来说,我很少通宵通宵不睡觉,那段时间许多同事都比我辛苦,我从没有在公司打过地铺。晚上不睡觉时,比谁都精神。只是有时候情绪不太好,大家也知道缺少睡眠容易发怒,所以在我提高自己的音量时,都很能容忍。我还记得那晚,交代给黄华一些临时写的一些工具,让他按我指定的次序转换图象资源文件,而他不小心做错,不得不忍受我在旁边大声嚷嚷,呵呵,还真是情绪失控呀 :) 。事后想想,我的责任更大一些。如果写那些工具时,多加一些检查,就不会有人无谓的犯错了。不过这个事情影响还是挺大,最后大话二的资源里有好些地方出了纰漏,至少到一年之后才完全找清楚修改干净。
等到五月一日前的那个晚上,dingdang 终于把服务器那边的通讯加密全部搞定。我终于松了一口气,居然准时完成了任务。
那晚,tarcy 老兄打电话让我出去喝酒,我一口答应,心情非常愉快。
ps. 关于外挂的问题,前几年我写过一个帖子。应该还能 google 到。今天我对这些没什么兴趣,倒是有不少同事再接再厉的做了许多。所以这里就不详细描述了。
谢绝转载
Comments
Posted by: tianqing | (22) December 14, 2012 06:57 PM
Posted by: leeonix | (21) October 2, 2009 05:35 PM
Posted by: 离别 | (20) June 27, 2008 09:27 AM
Posted by: du | (19) May 13, 2008 09:48 PM
Posted by: 小聪 | (18) May 13, 2008 08:31 PM
Posted by: jackyfire | (17) May 13, 2008 07:03 PM
Posted by: rockcarry | (16) May 13, 2008 05:14 PM
Posted by: zen_yue | (15) May 13, 2008 04:27 PM
Posted by: 江心 | (14) May 13, 2008 04:05 PM
Posted by: kai | (13) May 13, 2008 02:23 PM
Posted by: GAMEWING | (12) May 13, 2008 01:47 PM
Posted by: Cloud | (11) May 13, 2008 01:03 PM
Posted by: Spe | (10) May 13, 2008 11:41 AM
Posted by: tigerdx | (9) May 13, 2008 09:54 AM
Posted by: rockcarry | (8) May 13, 2008 09:45 AM
Posted by: chinetman | (7) May 13, 2008 08:58 AM
Posted by: ttt | (6) May 13, 2008 08:34 AM
Posted by: Anonymous | (5) May 13, 2008 07:53 AM
Posted by: Alex | (4) May 13, 2008 01:34 AM
Posted by: Alex | (3) May 13, 2008 01:30 AM
Posted by: joe wulf | (2) May 13, 2008 01:12 AM
Posted by: srdrm | (1) May 13, 2008 12:59 AM