Code

显示标签为“Games”的博文。显示所有博文
显示标签为“Games”的博文。显示所有博文

2011年1月9日星期日

zt (bookofhook) : = The Quake3 Networking Model =

This article is a reprint/updated version of an e-mail I sent out to the mud-dev mailing list a few years ago, describing the Q3 networking model as described to me by John Carmack.  I did this partly out of my own curiousity (since I was firmly entrenched in the graphics side of things) and partly out of a desire to propagate information on the 100% unreliable networking model in Q3 which I felt (and still feel) was fairly groundbreaking due to its simplicity and ease of understanding.

== The First Attempt (QTEST/Quake2) ==

Carmack's first real networking implementation, back in 1995, used TCP for !QuakeTest (QTEST).  This was fine for LAN play, because the large packets (8K) wouldn't fragment on a LAN (by "fragment", I mean to the point where disassembly and reassembly induced significant overhead), but didn't work so well over the Internet due to fragmentation (where dis/reassembly and lost packets often resulted in very expensive resends).  His next iteration involved using UDP with both reliable and unreliable data, pretty much what many would consider a standard networking architecture.  However standard mixed reliabled/unreliable implementations tend to generate very hard to find bugs, e.g. sequencing errors where guaranteed messages referenced entities altered through unreliable messages.

== Quake3 ==

The final iteration (Quake3), which was the first time he really felt he "got it right" (whereas Carmack always felt a little uneasy with previous implementations' fragility), used a radically different approach.  With Quake3 he dropped the notion of a reliable packet altogether, replacing the previous network packet structure with a single packet type -- the client's necessary game state.  The server sends sequenced game state updates that are delta compressed from the last acknowledged game state the client received.  This "just works".  Dropped packets are handled implicitly, and specific commands are never acknowledged independently -- last known state acks are piggy backed on regular incoming/outgoing traffic.

The client's receive logic boils down to:
{
      if ( newState.sequence < lastState.sequence )
      {
        //discard packet
      }
      else if ( newState.sequence > lastState.sequence )
      {
         lastState = deltaUncompress( lastState, newState );

         ackServer( lastState.sequence );
      }
}

The client then extrapolates movement and whatever other information it needs based on the last game state it received.

It's even simpler on the server:
{
      deltaCompressState( client.lastAckState, newState, &compressedState );

      sendToClient( client, compressedState );
}

The server never sits around waiting for an acknowledgement. As a result, latencies are much lower than if you have code that sits there twiddling its thumbs waiting for a synchronous ACK.

There are two downsides to this implementation. The big one is that it soaks more bandwidth since the server is constantly pumping new state to the client instead of just sending new state when it doesn't get an ACK. Also, the amount of data sent grows with the number of dropped packets since the delta grows as a result.

The other downside is that the server must buffer a lot of data, specifically of the last acked state to the client (so it can delta compress) along with a list of all the previous states it has sent to the client (back to the last acked one). This is necessary so it can rebase its delta comparisons on any of the game states that the client has acked.

For example, let's say the client last acked sequence 14. The server is sending out new game states with incrementing sequences. It may be up to sequence 20 when it gets an ack from the client that it has received sequence 17. The server has to have the state that was sent as part of sequence 17 in order to rebase the delta compression, so if game states are large enough or the buffers are long enough, this can grow fairly high (to the tune of several hundred K per client).

All reliable data that another node needs is sent repeatedly until the sender receives an update for most-recent-ack (indicating that the packet has been received). For example, if a player sends a chat message (reliable) with update 6, he will continually send that chat message on subsequent state updates until he receives notification from the server that it has received an update >= 6.  Brute force, but it works.

== Port Allocation ==

A note about using multiple ports -- there is one significant advantage to using multiple ports, and that's that the OS buffers incoming data per port. So if you have a chance of a port buffer overflow, then multiple ports may not be a bad idea. If a port overflow is highly unlikely to occur, then multiple ports probably just complicate matters.

Speaking of port buffer overflows, John doesn't think this is a problem. People that spin a second thread just to block on incoming ports are probably just doing extra work that doesn't need to be done. Effectively a thread that pumps the data ports is duplicating the exact same work the network stack is doing in the OS. Instead, John just pumps the network stack at the top of the event loop. Goes to show that brute force sometimes "just works". On a listen server (i.e. you're hosting a server on your client), where frame times can be several dozen milliseconds, there is a chance that you'll get a buffer overrun. In that case there are some options in Q3 to minimize buffer sizes, etc. to reduce the likelihood of a buffer overrun.

One nice thing about Q3's networking architecture, however, is that even in the case of a buffer overrun it just keeps working. There is no effective difference to this system between a dropped packet and a buffer overrun; as a matter of fact, this may actually be masking some real buffer overruns, but so far Carmack's pretty sure that he's not even come close to hitting an overrun situation. Of course, the dynamics of a shooter are different than those of an MMOG (fewer clients, much higher bandwidth per client), but it's interesting nonetheless.

== NAT ==

One interesting note on NAT: apparently some older routers will randomly switch the client's port when behind a NAT. This is very rare, but causes lost connections "randomly" for many users. It took forever to track this down, but once it was discovered he solved it by having a client randomly generate a unique client-id (16-bits) at connection time that is appended to every incoming packet. That way multiple clients with the same IP can work just fine, even if their ports get re-assigned mid-session. Humorously enough, he never bothered handling the (so rare as to be insignificant) case where two clients behind the same firewall randomly generate the exact same ID (in the event this occurred one of the clients would be dropped due to badly out of sync state).

== Compression, Encryption, and Packets ==

Aside from application level delta compression, Q3 also does per-packet Huffman compression. Works great, simple to implement, and the upside to something more aggressive is very low.

He has done some half-hearted work on encryption, but basically app/stream-level encryption is pointless because of the sophistication of hackers. In the future he'll probably rely on higher level inspection (a la Punkbusters for Counter-Strike) instead of cute bit-twiddling.

Finally, I asked about packet size. He thinks the notion of a 512-byte optimal MTU is pretty much at least 5 years out of date. He sees almost no problems with a max packet size of 1400 bytes, and fragmentation just isn't an issue. During the course of typical activity, the actual payload size is often smaller than the UDP header size (!), and even
during hectic activity the packet size is on the order of several hundred bytes. The large packets (up to 1.4K) are typically when a large amount of game state must be sent at once, such as at connection time when there is no state to delta against and when there is a lot of startup initialization going on.

== Summary ==

The Q3 networking model obviates the need to even have a discussion about UDP vs. TCP, unreliable vs. reliable, and out-of-order vs. in-order. It's all unreliable UDP delta compressed against the last known state.

A very elegant and effective architecture, albeit one that is ideally suited to a subset of game types.

2010年8月20日星期五

不玩HoN了

玩了这么久的HoN感觉这类游戏非常不适合单个玩家玩。跟dota一样,HoN强调的是团队配合。一个人在没有朋友的情况下很少可以碰到愿意跟自己配合,而且水平又适当的人,所以很多情况下都是孤军奋战。最后输赢跟水平没太大关系,只要分的团队好赢的几率就很大。我有时候就可以连赢好多盘然后又连输好多盘。

其次HoN的积分系统很容易让人上瘾。我玩的时候会下意识的给自己制定一个目标,达到多少多少分。玩玩为了达到这个分数,我需要花上3,4个小时在这个游戏上,而且是不能被打断的小时。这样会让我感到很累,而且也很浪费时间。更重要的是,往往打了几盘之后,感觉自己就盲目了。随便选英雄,随便玩。纯粹是一种茫然的状态。游戏本身并不重要,重要的是我已经可以忘掉所有事情了。说不上这是种什么好的感觉。可能赢了,或者玩到三杀四杀的时候会有点快感,但输时,被别人骂noob, idiot的时候,那种感觉是很不好的。所以,最后我决定把HoN从电脑里删除掉,再不玩这个可恶的游戏了。

不玩HoN我还有很多选择,但总的来说我会prefer单机游戏,或者一些turn based然后一局又不会很长的网络游戏。这样可以一边游戏,一边处理一些另外的事情。

2010年7月24日星期六

urban terror

今天玩了一天的urban terror,颓废了一天。为了在小猫面前掩饰我的心虚,我把玩这个游戏跟FYP扯上关系,美其名曰熟悉游戏。。。
其实这个用quake 3引擎作成的仿CS游戏玩起来还是很不一样的。它加入了很多CS里没有的元素,比如说power slide,体力值,救治等等。这些都是游戏的节奏上有很多不同。刚开始玩的时候还很不适应,感觉怎么敌人速度那么快,自己队友也在天上跳来跳去的,追都追不上。自己当然也是经常拖后腿,K/D 比率低之又低。。今天之所以玩了一整天是因为发现了power slide原来是这么让人上瘾。在掌握了技巧之后,我也可以在屋顶上飞来飞去。边飞还可以边杀人。这个的确非常过瘾。不过,这种游戏如果小猫来玩肯定没完一下就晕了。。恩,节奏很快的一个游戏。
当然,这个游戏跟FYP还是有点关系的。它跟我所研究的ioquake的code base是一样的。所以说游戏里的很多machanism 都在ioquake里可以实现。除了这个之外,对于我找游戏省电的idea也有点帮助。至于有什么帮助,现在还没想出来。
现在脑袋里只有一阵阵枪声。。

2008年11月9日星期日

网络时代的氓流——我们游戏为了什么?

当一个游戏玩家长大了,自然要学着思考点严肃的问题,例如生活,社会,价值等,每个人都如此,我也不例外。

曾经,每天都在思考同样的一个问题:自己是否存在过,或者存在的状态是什么?生活方式的选择 总会使人感到困惑,自己在象牙塔中度过了太多太多的岁月,以至于某一天突然发现自己被迫要面对一些大人们的烦恼时,很多事情已经失去了控制,那种感觉很无 助,因为认知失调的产生几乎在我们出生的时候就已经注定,无论如何逃避,终有一天要面对现实,即便它复杂到只有上帝才可能给出答案。

后工业时代的文明,喧嚣的都市,充满诱惑与陷阱。第一次站在上海的南京路上时,终于明白为什 么《海上钢琴师》中的丹尼·布德曼站到船桥上见到高楼林立的纽约时选择了回头——魂归大海。相对于钢琴的键盘,纽约的街道让他感到恐惧,因为那不是人类能 够弹奏的钢琴,太多道路蔓延在你永远也看不到尽头的高楼间,对于任何人来说,都太过复杂。也难怪会有如此多的极端教派企图毁灭现代文明。走在繁华的南京路 上,突然发现自己似乎并不属于这个世界,任街道两旁的霓虹灯如何耀眼,商品陈列柜中的货物如何诱人,但脑中却还在回忆似乎还有一部游戏的冒险尚未完成,等 待着我——这个故事主角给冒险加上一个句号。

不得不承认,游戏与网络改变了我们这一代人,也许文化上是从现代主义到后现代主义的实践吧。 但不管怎样,突然发现自己已经成了一个时代的氓流,精神上的流亡者。在偶的愤青时代曾经天真的人为只要一个人/民族拥有了一个坚定的信仰,那么这个社会终 将会向我们所认为的那样发展。但现在发现,在一个消费主义成为主流的多元社会中,解构成了这个时代的主题。像Green Day 《American Idiot》中唱的那样,“媒体控制着大众,使他们都变成白痴,电视梦想着明天……。”任何主体包括权力在内都正在解构,慢慢地消解。所有东西似乎都成了 消费品,甚至包括感情、性或者信息与政治。一个主体消失的时代,人们被迫承认现实的复杂性,因为童真不再跟随我们。但是另一个问题:生活是什么?性、香 烟、啤酒+摇滚乐?主体的消失甚至让人对自己的存在产生质疑。很多时候似乎精神已经被放逐,留下一个没有灵魂的躯壳。梦想改变,梦想摆脱,可最终听到的却 只有一些卫道士般的教诲。

于是,我开始沉迷游戏,似乎这种沉迷一直持续了有八九年,又或者是最近两年才发现自己曾经沉 迷。选择游戏为一种生活方式似乎是一种天性使然,因为现实的压抑必然使人向往另一种生活方式。工业时代的物质辉煌,信息时代的速度奇迹,似乎都依赖于不断 的技术进步,而今天技术几乎掌握了人类生活的方方面面,“只有技术想不到的,没有技术做不到的”。(我也忘了这句话是谁说的了)于是网络和游戏的结合成为 历史的必然。拜技术所赐,游戏中人格的重构成为现实,即便是虚拟的。EQ里我是一个可爱的矮子牧师。SB里我还是个矮子牧师,最后到WOW,我依然是一个 矮子牧师(哎,谁知道矮牧最后能成为大爷中的大爷呢~?暴雪的眷顾吧,呵呵)。由于西方奇幻文化本身就是一种对人性的解构,将人类的天性分拆到几大种族 内,而矮人的种族特点是我最喜欢的了,古板、善良加上无时不刻的抱怨,冒险的路上,多了这种伙伴是一种可*与温馨。而5年来,我在虚拟中的“冒险”经历似 乎也可以著书了,只有当游戏时才能刹那间体验到存在的欢愉,一种个体自由的充分展现,内在的无私敞开。屏幕前会心的一笑,我知道,这是生命的激情。在不断 的解构与建构的过程中我能够意识到自我主体的存在性。至少不用像黑格尔说的那样需要拿刀子插到自己的心脏才能感觉到自我的存在^_^,用句哲学上的话来总 结就是“边缘状态下的生命意识喷发。”

近10年的游戏龄,过程中反对的声音总不绝于耳,不过总算已经熬到了大学(想想当初备考时期 的苦闷,寒心哦),回想足迹,发现那些视游戏如洪水猛兽的人依然如此顽固,在他们看来,一个人与其花那么多时间、精力浪费在虚拟世界中,不如多多用功在实 实在在的事情上。现在看来,只是两种消费观念的分歧,他们认为我们的消费是无价值的,而我们却因为这种消费而建构着自主认同。但是一种社会的压力,大家都 看到的,这种既成的规则企图将其的规则强行实施在每一个人身上,力图通过权威的话语霸权使每一个人都按照既定的模式塑造自己,而我们则是这种强权的反抗 者,通过更深的沉迷反抗&否定这种塑造,因为游戏给了我们一种选择不的机会,即便它是虚拟的。从此,规训和反抗、压抑和逃离、惯例和突破、陈规和 创新、禁忌和纵欲似乎成了生活中永恒的矛盾。不否认游戏中获得的这种违禁快感使人欲罢不能。最终通过一种个体选择获得了一种虚拟的主体性认同,从此生活便 不在迷茫。

游戏对于我意味着什么?引一段托马斯·莫尔在其《乌托邦》中的描述:

……晚饭后,他们有一个小时的娱乐时间,他们常玩的两种游戏与棋类颇为相似,一种称之为数学 竞赛,其中一个数字能够吞并另一个数字,另一种游戏是邪恶向美德发动进攻,在这个游戏中,可以充分展示一个人的机智,美德采用何种保护措施去一直邪恶的力 量,采用何种手段挫败邪恶的企图。最终,游戏的一方采用何种途径赢得整局的胜利……

这是一个生活在16世纪伟大思想家和人文主义者憧憬的理想国度中最为基本的生活方式的一项内 容。游戏——一种生活方式,是人性养成的重要内容。在今天,电子游戏似乎让这一切成了现实,不,比其中的表述更加清晰,更加丰满动人。游戏里,我们创造我 们喜欢的人生,体验成功的滋味,我们可以是一个邪恶的大法师,可以是一个愤怒中的战士,仁慈的牧师,甚至可以回到古代成为三国枭雄之一,也许还可以驾驶阿 帕奇直升机,M1主战坦克等等。世上还没有什么东西能够给一个个体如此大的自由性吧。即便这样还有有许多人藐视这种虚拟空间的主体自由性,但如果我们还没 有遗忘游戏对于童年的意义,我们就不会藐视游戏空间内的所有这些真正存在的感受。

于是乎,从大富翁的童真般笑声到CS的AWP那厚实而令人绝望的枪声,从《主题公园》那简陋 的花园到《过山车大亨》中轨道眩目的过山车。《星际争霸》中我们挥斥方秋,《三国无双》中我们万夫莫敌,《博得之门》中我们探索魔法与剑的奥秘……各种游 戏的足迹已经在记忆中深深印下。单机时代的我只为追求一种单纯的快乐。

进入网游时代,我为技术的进步而欢呼雀跃,儿时的梦想竟能够真真切切的摆在眼前,第一次进入 一个脱离了日常生活的秩序的世界,所谓当狗也风流啊,在这个世界,不管大狗小狗,都是能叫的。一个幻想的空间,足以让人释放已久的焦虑与压抑。不过结果是 更多像我一样的可怜鬼沉迷其中。

有人批判这是一种文化工业的圈套,我们“无所事事”地沉迷游戏,遗忘了真实生活的细节。但从 另一个方面看,我们是否随着理性主义、经验主义和笛卡儿怀疑论哲学的发展,把自己完全封闭在一个已知的或可知的世界中,我们被因果的必然性所制约?(引自 何学威、蓝爱国:《网络文学的民间视野》P65,中国文联出版社2004版)

凯恩(Keen)指出:

当我们把这个世界描绘成一个可以对之进行详尽无疑的解释的闭合系统的时候,我们实际上是在消 灭自己的好奇心并剥夺掉自己的自由,而这些全都反映了一种病态的生活取向(引自托马斯·古尔德、杰弗瑞·戈比:《人类思想史中的休闲》,成素梅等 译,P197,云南人民出版社2000版)

事实上,网络游戏对于一个个体来说,是一种虚拟的现实化,而非现实的虚拟化,将梦现实化,而不是将现实中的铜臭带入梦中(虽然不可避免的商业化也出现在了游戏中)

有些时候沉迷也是需要找理由的,人就是这样,总是会自然或者不自然地去合理化自己的行为。在 整理思想的碎片从而解构了一种话语权力后,我需要重构一种认同,网络时代的自我认同,从而远离已旧的飘零生活。人毕竟要学会去变得成熟一些,虽然这个过程 不是那样充满欢娱,没有狂欢节般的自由和奔放,但是,记得一句话,从一本摇滚期刊上看到的

“Music can not save you from anything but the silent”

音乐如此,游戏呢?除了空洞的灵魂,我想游戏也不能将我们从任何事物中拯救出来。还有一句关于音乐的话,我想用到这里来比喻更加恰当些

“People made music and music made them free.”

自由对于每个灵魂来说都是一种永恒的追求。在人类历史上的任何时期,都有人出来高唱自由赞 歌。但是在生活中其实每个人都面临着一种恐惧,也许是无知,也许是死亡,或许就是对死亡的无知吧^_^,它无时不可刻的在提醒我们它的存在。以至于很多人 强迫自己每天都按照惯例去做他认为自己应该做的每一件事情,努力使自己相信只要自己生活有了一种节奏,那么任何事情都可以成为永恒的,永远也不会改变。这 显然是自欺欺人,但是面对一种未知的恐惧,谁又敢保证他做得比别人更好呢?于是,为了摆脱这种恐惧,要么,如美国跨掉的一代那般,完成一段亚文化向主流文 化的回归过程,但也许还有其他选择,因为毕竟我们和他们不是一代人。那个时候的心情用Green Day的《Boulevard Of Broken Dreams》描述再适合不过了:

I walk a lonely road

The only one that I have ever known

Don't know where it goes

But it's home to me and I walk alone

…………

而这个时候我在中青网协举办的的《网络游戏辩论赛》中邂逅了珈蓝。

在此之前我漂流在EQ和SB间,留下了无数美好的回忆。诺拉斯大陆上,也许现在还有一个可爱 的矮子牧师在守望,公园笨龙这个ID就是从EQ诞生的,沿用到现在。EQ时代零零散散的加入了不少公会,都很小,因为当时感觉大公会没有太多人情味。还是 小公会惬意,但世上没有不散的筵席,分别的时刻从来都是不可避免,现实如此,网络依旧。而且一年内让偶经历了3次……555555~

第一次接触珈蓝是在04年辩论赛上。当时主要是因为珈蓝一辩血小板MM的声音太具杀伤力,后来了解到原来是中文系的硕士(难怪ing),之后是决赛前夕与叶子和大大胖子在UC上的聊天,反正只知道叶子的话是滔滔不绝ing,不知怎么的就把偶拉到珈蓝了。

一次8错的邂逅,现在回想,当初和胖子聊了很久,关于对网络的认识,关于公会的烦恼,关于生 活的种种抱怨,貌似一种老者诉说。第一次遇到一个能够将内在感受如此程度敞开的人,这在现实中几乎是不可想象的。决赛,KOK失利后和KOK的HKG36 同志哭(应该他是哭了)诉了一晚,说了很多胡话,当时还有游侠网的雨夜MM在场(魔剑小说《无尽的征程》作者之一),那一晚3个人侃侃而谈,畅快淋漓。那 次是偶第一次认识到网游公会对一个人的意义,对一个虚拟的游戏公会竟然有了一种家的憧憬。那时珈蓝因为被冠以文人公会的称号而且貌似MM也不少并且是第一 个提出建构公会文化的游戏玩家组织,所以当时就一个想法,“以后这就是俺的窝喽……”

真正把一个虚拟的公会组织当作心灵的“窝”可不是一个想当然的过程,中间偶也出走过两次,不 过最后还是忍不住回来看看曾经的老骨头,寻觅曾经的足迹,在虚拟的回忆中寻找生命的哲学。因为我们有着共同的理念,共同的爱好,我们喜欢游戏,喜欢奇幻、 了解AD&D,听摇滚,玩punk,这些本身就是一种文化;一种可选择的生活方式;一群我们可以互相认同的人。

当偶加入珈蓝的时候其实就被告知珈蓝内部不是一个理想化的地方,有明争也有暗斗。因为不论网 络如何虚拟,网络中的人依然如放风筝般,在自由的翱翔之时总会被现实中的一根线牵着,游离与现实与虚拟,解构与建构之间。所以网络依旧不是一个乌托邦,各 种分歧层出不穷,并不比现实中简单多少。但是,当你打开电脑,敲入bbs.jlsd.net的时候,以往的面孔依旧,回忆会不经意间的流露在眼前,进入游 戏,突然有个人喊道:“报告,发现千年古尸……”“我看到了石化了几百年的人物。”每每看到这些话语,屏幕前的我总忍不住会心一笑。这就是一种认同,一种 主体的认同,一种被承认的主体感。虽然不知道路通向何方,但我知道这是回家的路。因为,天堂2中我们曾是兄弟,星际online中我们都是VS的好战士, 我们拥有战友的情谊,WOW中,我们是利益的集合体为了紫色装备一遍一遍的蹂躏或者被蹂躏MC/BWL中的各大BOSS。我相信在未来EVE中,我们同样 能够拥有超越现实的情谊,而这种情谊是我们珈蓝人一生中都值得骄傲的资本。因为它是一段足迹,是值得我们每个人去珍惜,去共同回忆的一段经历。

from: http://www.yxglw.com/Onlinegames/qsly/118820.html