• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            教父的告白
            一切都是紙老虎
            posts - 82,  comments - 7,  trackbacks - 0
            原文:http://game.chinaitlab.com/freshmen/783449.html

                要想在修改游戲中做到百戰(zhàn)百勝,是需要相當(dāng)豐富的計(jì)算機(jī)知識(shí)的。有很多計(jì)算機(jī)高手就是從玩游戲,修改游戲中,逐步對(duì)計(jì)算機(jī)產(chǎn)生濃厚的興趣,逐步成長(zhǎng)起來 的。不要在羨慕別人能夠做到的,因?yàn)閯e人能夠做的你也能夠!我相信你們看了本教程后,會(huì)對(duì)游戲有一個(gè)全新的認(rèn)識(shí),呵呵,因?yàn)槲沂莻€(gè)好老師!(別拿雞蛋砸我 呀,救命啊!#¥%……*)

                不過要想從修改游戲中學(xué)到知識(shí),增加自己的計(jì)算機(jī)水平,可不能只是靠修改游戲呀! 要知道,修改游戲只是一個(gè)驗(yàn)證你對(duì)你所了解的某些計(jì)算機(jī)知識(shí)的理解程度的場(chǎng)所,只能給你一些發(fā)現(xiàn)問題、解決問題的機(jī)會(huì),只能起到幫助你提高學(xué)習(xí)計(jì)算機(jī)的興 趣的作用,而決不是學(xué)習(xí)計(jì)算機(jī)的捷徑。

                一:什么叫外掛?

                現(xiàn)在的網(wǎng)絡(luò)游戲多是基于Internet上客戶/服務(wù)器模式,服務(wù)端程序運(yùn)行在游戲服務(wù)器上,游戲的設(shè)計(jì)者在其中創(chuàng)造一個(gè)龐大的游戲空間,各地的玩家可以通過運(yùn)行客戶端程序同時(shí)登錄到游戲中。簡(jiǎn)單地說,網(wǎng)絡(luò)游戲?qū)嶋H上就是由游戲開發(fā)商 提供一個(gè)游戲環(huán)境,而玩家們就是在這個(gè)環(huán)境中相對(duì)自由和開放地進(jìn)行游戲操作。那么既然在網(wǎng)絡(luò)游戲中有了服務(wù)器這個(gè)概念,我們以前傳統(tǒng)的修改游戲方法就顯得 無能為力了。記得我們?cè)趩螜C(jī)版的游戲中,隨心所欲地通過內(nèi)存搜索來修改角色的各種屬性,這在網(wǎng)絡(luò)游戲中就沒有任何用處了。因?yàn)槲覀冊(cè)诰W(wǎng)絡(luò)游戲中所扮演角色 的各種屬性及各種重要資料都存放在服務(wù)器上,在我們自己機(jī)器上(客戶端)只是顯示角色的狀態(tài),所以通過修改客戶端內(nèi)存里有關(guān)角色的各種屬性是不切實(shí)際的。 那么是否我們就沒有辦法在網(wǎng)絡(luò)游戲中達(dá)到我們修改的目的?回答是"否".我們知道Internet客戶/服務(wù)器模式的通訊一般采用TCP/IP通信協(xié)議,數(shù)據(jù)交換是通過IP數(shù)據(jù)包的傳輸來實(shí)現(xiàn)的,一般來說我們客戶端向服務(wù)器發(fā)出某些請(qǐng)求,比如移動(dòng)、戰(zhàn)斗等指令都是通過封包的形式和服務(wù)器交換數(shù) 據(jù)。那么我們把本地發(fā)出消息稱為SEND,意思就是發(fā)送數(shù)據(jù),服務(wù)器收到我們SEND的消息后,會(huì)按照既定的程序把有關(guān)的信息反饋給客戶端,比如,移動(dòng)的 坐標(biāo),戰(zhàn)斗的類型。那么我們把客戶端收到服務(wù)器發(fā)來的有關(guān)消息稱為RECV.知道了這個(gè)道理,接下來我們要做的工作就是分析客戶端和服務(wù)器之間往來的數(shù)據(jù) (也就是封包),這樣我們就可以提取到對(duì)我們有用的數(shù)據(jù)進(jìn)行修改,然后模擬服務(wù)器發(fā)給客戶端,或者模擬客戶端發(fā)送給服務(wù)器,這樣就可以實(shí)現(xiàn)我們修改游戲的 目的了。

                目前除了修改游戲封包來實(shí)現(xiàn)修改游戲的目的,我們也可以修改客戶端的有關(guān)程序來達(dá)到我們的要求。我們知道目前各個(gè)服務(wù)器的運(yùn)算能力是有限的,特別在游戲 中,游戲服務(wù)器要計(jì)算游戲中所有玩家的狀況幾乎是不可能的,所以有一些運(yùn)算還是要依靠我們客戶端來完成,這樣又給了我們修改游戲提供了一些便利。比如我們 可以通過將客戶端程序脫殼來發(fā)現(xiàn)一些程序的判斷分支,通過跟蹤調(diào)試我們可以把一些對(duì)我們不利的判斷去掉,以此來滿足我們修改游戲的需求。 在下幾個(gè)章節(jié)中,我們將給大家講述封包的概念,和修改跟蹤客戶端的有關(guān)知識(shí)。大家準(zhǔn)備好了嗎?

                游戲數(shù)據(jù)格式和存儲(chǔ)

                在進(jìn)行我們的工作之前,我們需要掌握一些關(guān)于計(jì)算機(jī)中儲(chǔ)存數(shù)據(jù)方式的知識(shí)和游戲中儲(chǔ)存數(shù)據(jù)的特點(diǎn)。本章節(jié)是提供給菜鳥級(jí)的玩家看的,如果你是高手就可以跳 過了,如果,你想成為無堅(jiān)不摧的劍客,那么,這些東西就會(huì)花掉你一些時(shí)間;如果,你只想作個(gè)江湖的游客的話,那么這些東西,了解與否無關(guān)緊要。是作劍客, 還是作游客,你選擇吧!

                現(xiàn)在我們開始!首先,你要知道游戲中儲(chǔ)存數(shù)據(jù)的幾種格式,這幾種格式是:字節(jié)(BYTE)、字(WORD)和雙字(DOUBLE WORD),或者說是8位、16位和32位儲(chǔ)存方式。字節(jié)也就是8位方式能儲(chǔ)存0~255的數(shù)字;字或說是16位儲(chǔ)存方式能儲(chǔ)存0~65535的數(shù);雙字 即32位方式能儲(chǔ)存0~4294967295的數(shù)。

                為何要了解這些知識(shí)呢?在游戲中各種參數(shù)的最大值是不同的,有些可能100左右就夠了,比如,金庸群俠傳中的角色的等級(jí)、隨機(jī)遇敵個(gè)數(shù)等等。而有些卻需要 大于255甚至大于65535,象金庸群俠傳中角色的金錢值可達(dá)到數(shù)百萬。所以,在游戲中各種不同的數(shù)據(jù)的類型是不一樣的。在我們修改游戲時(shí)需要尋找準(zhǔn)備 修改的數(shù)據(jù)的封包,在這種時(shí)候,正確判斷數(shù)據(jù)的類型是迅速找到正確地址的重要條件。

                在計(jì)算機(jī)中數(shù)據(jù)以字節(jié)為基本的儲(chǔ)存單位,每個(gè)字節(jié)被賦予一個(gè)編號(hào),以確定各自的位置。這個(gè)編號(hào)我們就稱為地址。

                在需要用到字或雙字時(shí),計(jì)算機(jī)用連續(xù)的兩個(gè)字節(jié)來組成一個(gè)字,連續(xù)的兩個(gè)字組成一個(gè)雙字。而一個(gè)字或雙字的地址就是它們的低位字節(jié)的地址。 現(xiàn)在我們常用的Windows 9x操作系統(tǒng)中,地址是用一個(gè)32位的二進(jìn)制數(shù)表示的。而在平時(shí)我們用到內(nèi)存地址時(shí),總是用一個(gè)8位的16進(jìn)制數(shù)來表示它。

                二進(jìn)制和十六進(jìn)制又是怎樣一回事呢?

                簡(jiǎn)單說來,二進(jìn)制數(shù)就是一種只有0和1兩個(gè)數(shù)碼,每滿2則進(jìn)一位的計(jì)數(shù)進(jìn)位法。同樣,16進(jìn)制就是每滿十六就進(jìn)一位的計(jì)數(shù)進(jìn)位法。16進(jìn)制有0——F十六 個(gè)數(shù)字,它為表示十到十五的數(shù)字采用了A、B、C、D、E、F六個(gè)數(shù)字,它們和十進(jìn)制的對(duì)應(yīng)關(guān)系是:A對(duì)應(yīng)于10,B對(duì)應(yīng)于11,C對(duì)應(yīng)于12,D對(duì)應(yīng)于 13,E對(duì)應(yīng)于14,F(xiàn)對(duì)應(yīng)于15.而且,16進(jìn)制數(shù)和二進(jìn)制數(shù)間有一個(gè)簡(jiǎn)單的對(duì)應(yīng)關(guān)系,那就是;四位二進(jìn)制數(shù)相當(dāng)于一位16進(jìn)制數(shù)。比如,一個(gè)四位的二 進(jìn)制數(shù)1111就相當(dāng)于16進(jìn)制的F,1010就相當(dāng)于A.了解這些基礎(chǔ)知識(shí)對(duì)修改游戲有著很大的幫助,下面我就要談到這個(gè)問題。由于在計(jì)算機(jī)中數(shù)據(jù)是以 二進(jìn)制的方式儲(chǔ)存的,同時(shí)16進(jìn)制數(shù)和二進(jìn)制間的轉(zhuǎn)換關(guān)系十分簡(jiǎn)單,所以大部分的修改工具在顯示計(jì)算機(jī)中的數(shù)據(jù)時(shí)會(huì)顯示16進(jìn)制的代碼,而且在你修改時(shí)也 需要輸入16進(jìn)制的數(shù)字。你清楚了吧?

                在游戲中看到的數(shù)據(jù)可都是十進(jìn)制的,在要尋找并修改參數(shù)的值時(shí),可以使用Windows提供的計(jì)算器來進(jìn)行十進(jìn)制和16進(jìn)制的換算,我們可以在開始菜單里的程序組中的附件中找到它。

                現(xiàn)在要了解的知識(shí)也差不多了!不過,有個(gè)問題在游戲修改中是需要注意的。在計(jì)算機(jī)中數(shù)據(jù)的儲(chǔ)存方式一般是低位數(shù)儲(chǔ)存在低位字節(jié),高位數(shù)儲(chǔ)存在高位字節(jié)。比如,十進(jìn)制數(shù)41715轉(zhuǎn)換為16進(jìn)制的數(shù)為A2F3,但在計(jì)算機(jī)中這個(gè)數(shù)被存為F3A2.

                看了以上內(nèi)容大家對(duì)數(shù)據(jù)的存貯和數(shù)據(jù)的對(duì)應(yīng)關(guān)系都了解了嗎? 好了,接下來我們要告訴大家在游戲中,封包到底是怎么一回事了,來!大家把袖口卷起來,讓我們來干活吧!

                二:什么是封包?

                怎么截獲一個(gè)游戲的封包?怎么去檢查游戲服務(wù)器的ip地址和端口號(hào)? Internet用戶使用的各種信息服務(wù),其通訊的信息最終均可以歸結(jié)為以IP包為單位的信息傳送,IP包除了包括要傳送的數(shù)據(jù)信息外,還包含有信息要發(fā) 送到的目的IP地址、信息發(fā)送的源IP地址、以及一些相關(guān)的控制信息。當(dāng)一臺(tái)路由器收到一個(gè)IP數(shù)據(jù)包時(shí),它將根據(jù)數(shù)據(jù)包中的目的IP地址項(xiàng)查找路由表,根據(jù)查找的結(jié)果將此IP數(shù)據(jù)包送往對(duì)應(yīng)端口。下一臺(tái)IP路由器收到此數(shù)據(jù)包后繼續(xù)轉(zhuǎn)發(fā),直至發(fā)到目的地。路由器之間可以通過路由協(xié)議來進(jìn)行路由信息的交換,從而更新路由表。

                那么我們所關(guān)心的內(nèi)容只是IP包中的數(shù)據(jù)信息,我們可以使用許多監(jiān)聽網(wǎng)絡(luò)的工具來截獲客戶端與服務(wù)器之間的交換數(shù)據(jù),下面就向你介紹其中的一種工具:WPE. WPE使用方法:執(zhí)行WPE會(huì)有下列幾項(xiàng)功能可選擇:

                SELECT GAME選擇目前在記憶體中您想攔截的程式,您只需雙擊該程式名稱即可。

                TRACE追蹤功能。用來追蹤擷取程式送收的封包。WPE必須先完成點(diǎn)選欲追蹤的程式名稱,才可以使用此項(xiàng)目。 按下Play鍵開始擷取程式收送的封包。您可以隨時(shí)按下 | | 暫停追蹤,想繼續(xù)時(shí)請(qǐng)?jiān)侔聪?| | .按下正方形可以停止擷取封包并且顯示所有已擷取封包內(nèi)容。若您沒按下正方形停止鍵,追蹤的動(dòng)作將依照OPTION里的設(shè)定值自動(dòng)停止。如果您沒有擷取到 資料,試試將OPTION里調(diào)整為Winsock Version 2.WPE 及 Trainers 是設(shè)定在顯示至少16 bits 顏色下才可執(zhí)行。

                FILTER過濾功能。用來分析所擷取到的封包,并且予以修改。

                SEND PACKET送出封包功能。能夠讓您送出假造的封包。

                TRAINER MAKER制作修改器。

                OPTIONS設(shè)定功能。讓您調(diào)整WPE的一些設(shè)定值。

                FILTER的詳細(xì)教學(xué)

                - 當(dāng)FILTER在啟動(dòng)狀態(tài)時(shí) ,ON的按鈕會(huì)呈現(xiàn)紅色。- 當(dāng)您啟動(dòng)FILTER時(shí),您隨時(shí)可以關(guān)閉這個(gè)視窗。FILTER將會(huì)留在原來的狀態(tài),直到您再按一次 on / off 鈕。- 只有FILTER啟用鈕在OFF的狀態(tài)下,才可以勾選Filter前的方框來編輯修改。- 當(dāng)您想編輯某個(gè)Filter,只要雙擊該Filter的名字即可。

                NORMAL MODE:

                范例:

                當(dāng)您在 Street Fighter Online ﹝快打旋風(fēng)線上版﹞游戲中,您使用了兩次火球而且擊中了對(duì)方,這時(shí)您會(huì)擷取到以下的封包:SEND-> 0000 08 14 21 06 01 04 SEND-> 0000 02 09 87 00 67 FF A4 AA 11 22 00 00 00 00 SEND-> 0000 03 84 11 09 11 09 SEND-> 0000 0A 09 C1 10 00 00 FF 52 44 SEND-> 0000 0A 09 C1 10 00 00 66 52 44您的第一個(gè)火球讓對(duì)方減了16滴﹝16 = 10h﹞的生命值,而您觀察到第4跟第5個(gè)封包的位置4有10h的值出現(xiàn),應(yīng)該就是這里了。

                您觀察10h前的0A 09 C1在兩個(gè)封包中都沒改變,可見得這3個(gè)數(shù)值是發(fā)出火球的關(guān)鍵。

                因此您將0A 09 C1 10填在搜尋列﹝SEARCH﹞,然后在修改列﹝MODIFY﹞的位置4填上FF.如此一來,當(dāng)您再度發(fā)出火球時(shí),F(xiàn)F會(huì)取代之前的10,也就是攻擊力為255的火球了!

                ADVANCED MODE:范例: 當(dāng)您在一個(gè)游戲中,您不想要用真實(shí)姓名,您想用修改過的假名傳送給對(duì)方。在您使用TRACE后,您會(huì)發(fā)現(xiàn)有些封包里面有您的名字出現(xiàn)。假設(shè)您的名字是 Shadow,換算成16進(jìn)位則是﹝53 68 61 64 6F 77﹞;而您打算用moon﹝6D6F 6F 6E 20 20﹞來取代他。1) SEND-> 0000 08 14 21 06 01 042) SEND-> 0000 01 06 99 53 68 61 64 6F 77 00 01 05 3) SEND-> 0000 03 84 11 09 11 094) SEND-> 0000 0A 09 C1 10 00 53 68 61 64 6F 77 00 11 5) SEND-> 0000 0A 09 C1 10 00 00 66 52 44但是您仔細(xì)看,您的名字在每個(gè)封包中并不是出現(xiàn)在相同的位置上- 在第2個(gè)封包里,名字是出現(xiàn)在第4個(gè)位置上- 在第4個(gè)封包里,名字是出現(xiàn)在第6個(gè)位置上在這種情況下,您就需要使用ADVANCED MODE- 您在搜尋列﹝SEARCH﹞填上:53 68 61 64 6F 77 ﹝請(qǐng)務(wù)必從位置1開始填﹞- 您想要從原來名字Shadow的第一個(gè)字母開始置換新名字,因此您要選擇從數(shù)值被發(fā)現(xiàn)的位置開始替代連續(xù)數(shù)值﹝from the position of the chain found﹞.- 現(xiàn)在,在修改列﹝MODIFY﹞000的位置填上:6D 6F 6F 6E 20 20 ﹝此為相對(duì)應(yīng)位置,也就是從原來搜尋欄的+001位置開始遞換﹞- 如果您想從封包的第一個(gè)位置就修改數(shù)值,請(qǐng)選擇﹝from the beginning of the packet﹞了解一點(diǎn)TCP/IP協(xié)議常識(shí)的人都知道,互聯(lián)網(wǎng)是 將信息數(shù)據(jù)打包之后再傳送出去的。每個(gè)數(shù)據(jù)包分為頭部信息和數(shù)據(jù)信息兩部分。頭部信息包括數(shù)據(jù)包的發(fā)送地址和到達(dá)地址等。數(shù)據(jù)信息包括我們?cè)谟螒蛑邢嚓P(guān)操 作的各項(xiàng)信息。那么在做截獲封包的過程之前我們先要知道游戲服務(wù)器的IP地址和端口號(hào)等各種信息,實(shí)際上最簡(jiǎn)單的是看看我們游戲目錄下,是否有一個(gè) SERVER.INI的配置文件,這個(gè)文件里你可以查看到個(gè)游戲服務(wù)器的IP地址,比如金庸群俠傳就是如此,那么除了這個(gè)我們還可以在DOS下使用 NETSTAT這個(gè)命令, NETSTAT命令的功能是顯示網(wǎng)絡(luò)連接、路由表和網(wǎng)絡(luò)接口信息,可以讓用戶得知目前都有哪些網(wǎng)絡(luò)連接正在運(yùn)作。或者你可以使用木馬客星等工具來查看網(wǎng)絡(luò) 連接。工具是很多的,看你喜歡用哪一種了。

                NETSTAT命令的一般格式為:NETSTAT [選項(xiàng)]命令中各選項(xiàng)的含義如下:-a 顯示所有socket,包括正在監(jiān)聽的。-c 每隔1秒就重新顯示一遍,直到用戶中斷它。

                -i 顯示所有網(wǎng)絡(luò)接口的信息。-n 以網(wǎng)絡(luò)IP地址代替名稱,顯示出網(wǎng)絡(luò)連接情形。-r 顯示核心路由表,格式同"route -e".-t 顯示TCP協(xié)議的連接情況。-u 顯示UDP協(xié)議的連接情況。-v 顯示正在進(jìn)行的工作。

                三:怎么來分析我們截獲的封包?

                首先我們將WPE截獲的封包保存為文本文件,然后打開它,這時(shí)會(huì)看到如下的數(shù)據(jù)(這里我們以金庸群俠傳里PK店小二客戶端發(fā)送的數(shù)據(jù)為例來講解):第一個(gè) 文件:SEND-> 0000 E6 56 0D 22 7E 6B E4 17 13 13 12 13 12 13 67 1BSEND-> 0010 17 12 DD 34 12 12 12 12 17 12 0E 12 12 12 9BSEND-> 0000 E6 56 1E F1 29 06 17 12 3B 0E 17 1ASEND-> 0000 E6 56 1B C0 68 12 12 12 5ASEND-> 0000 E6 56 02 C8 13 C9 7E 6B E4 17 10 35 27 13 12 12SEND-> 0000 E6 56 17 C9 12第二個(gè)文件:SEND-> 0000 83 33 68 47 1B 0E 81 72 76 76 77 76 77 76 02 7ESEND-> 0010 72 77 07 1C 77 77 77 77 72 77 72 77 77 77 6DSEND-> 0000 83 33 7B 94 4C 63 72 77 5E 6B 72 F3SEND-> 0000 83 33 7E A5 21 77 77 77 3FSEND-> 0000 83 33 67 AD 76 CF 1B 0E 81 72 75 50 42 76 77 77SEND-> 0000 83 33 72 AC 77我們發(fā)現(xiàn)兩次PK店小二的數(shù)據(jù)格式一樣,但是內(nèi)容卻不相同,我們是PK的同一個(gè)NPC,為什么會(huì)不同呢? 原來金庸群俠傳的封包是經(jīng)過了加密運(yùn)算才在網(wǎng)路上傳輸?shù)模敲次覀兠媾R的問題就是如何將密文解密成明文再分析了。

                因?yàn)橐话愕臄?shù)據(jù)包加密都是異或運(yùn)算,所以這里先講一下什么是異或。 簡(jiǎn)單的說,異或就是"相同為0,不同為1"(這是針對(duì)二進(jìn)制按位來講的),舉個(gè)例子,0001和0010異或,我們按位對(duì)比,得到異或結(jié)果是0011,計(jì) 算的方法是:0001的第4位為0,0010的第4位為0,它們相同,則異或結(jié)果的第4位按照"相同為0,不同為1"的原則得到0,0001的第3位為 0,0010的第3位為0,則異或結(jié)果的第3位得到0,0001的第2位為0,0010的第2位為1,則異或結(jié)果的第2位得到1,0001的第1位為 1,0010的第1位為0,則異或結(jié)果的第1位得到1,組合起來就是0011.異或運(yùn)算今后會(huì)遇到很多,大家可以先熟悉熟悉,熟練了對(duì)分析很有幫助的。

                下面我們繼續(xù)看看上面的兩個(gè)文件,按照常理,數(shù)據(jù)包的數(shù)據(jù)不會(huì)全部都有值的,游戲開發(fā)時(shí)會(huì)預(yù)留一些字節(jié)空間來便于日后的擴(kuò)充,也就是說數(shù)據(jù)包里會(huì)存在一些"00"的字節(jié),觀察上面的文件,我們會(huì)發(fā)現(xiàn)文件一里很多"12",文件二里很多"77",那么這是不是代表我們說的"00"呢?推理到這里,我們就開始行動(dòng)吧!

                我們把文件一與"12"異或,文件二與"77"異或,當(dāng)然用手算很費(fèi)事,我們使用"M2M 1.0 加密封包分析工具"來計(jì)算就方便多了。得到下面的結(jié)果:第一個(gè)文件:1 SEND-> 0000 F4 44 1F 30 6C 79 F6 05 01 01 00 01 00 01 75 09SEND-> 0010 05 00 CF 26 00 00 00 00 05 00 1C 00 00 00 892 SEND-> 0000 F4 44 0C E3 3B 13 05 00 29 1C 05 083 SEND-> 0000 F4 44 09 D2 7A 00 00 00 484 SEND-> 0000 F4 44 10 DA 01 DB 6C 79 F6 05 02 27 35 01 00 005 SEND-> 0000 F4 44 05 DB 00第二個(gè)文件:1 SEND-> 0000 F4 44 1F 30 6C 79 F6 05 01 01 00 01 00 01 75 09SEND-> 0010 05 00 70 6B 00 00 00 00 05 00 05 00 00 00 1A2 SEND-> 0000 F4 44 0C E3 3B 13 05 00 29 1C 05 843 SEND-> 0000 F4 44 09 D2 56 00 00 00 484 SEND-> 0000 F4 44 10 DA 01 B8 6C 79 F6 05 02 27 35 01 00 005 SEND-> 0000 F4 44 05 DB 00哈,這一下兩個(gè)文件大部分都一樣啦,說明我們的推理是正確的,上面就是我們需要的明文!

                接下來就是搞清楚一些關(guān)鍵的字節(jié)所代表的含義,這就需要截獲大量的數(shù)據(jù)來分析。

                首先我們會(huì)發(fā)現(xiàn)每個(gè)數(shù)據(jù)包都是"F4 44"開頭,第3個(gè)字節(jié)是變化的,但是變化很有規(guī)律。我們來看看各個(gè)包的長(zhǎng)度,發(fā)現(xiàn)什么沒有?對(duì)了,第3個(gè)字節(jié)就是包的長(zhǎng)度! 通過截獲大量的數(shù)據(jù)包,我們判斷第4個(gè)字節(jié)代表指令,也就是說客戶端告訴服務(wù)器進(jìn)行的是什么操作。例如向服務(wù)器請(qǐng)求戰(zhàn)斗指令為"30",戰(zhàn)斗中移動(dòng)指令 為"D4"等。 接下來,我們就需要分析一下上面第一個(gè)包"F4 44 1F 30 6C 79 F6 05 01 01 00 01 00 01 75 09 05 00 CF 26 00 00 00 00 05 00 1C 00 00 00 89",在這個(gè)包里包含什么信息呢?應(yīng)該有通知服務(wù)器你PK的哪個(gè)NPC吧,我們就先來找找這個(gè)店小二的代碼在什么地方。 我們?cè)貾K一個(gè)小嘍羅(就是大理客棧外的那個(gè)咯):SEND-> 0000 F4 44 1F 30 D4 75 F6 05 01 01 00 01 00 01 75 09SEND-> 0010 05 00 8A 19 00 00 00 00 11 00 02 00 00 00 C0 我們根據(jù)常理分析,游戲里的NPC種類雖然不會(huì)超過65535(FFFF),但開發(fā)時(shí)不會(huì)把自己限制在字的范圍,那樣不利于游戲的擴(kuò)充,所以我們?cè)陔p字里 看看。通過"店小二"和"小嘍羅"兩個(gè)包的對(duì)比,我們把目標(biāo)放在"6C 79 F6 05"和"CF 26 00 00"上。(對(duì)比一下很容易的,但你不能太遲鈍咯,呵呵)我們?cè)倏纯春竺娴陌诤竺娴陌飸?yīng)該還會(huì)出現(xiàn)NPC的代碼,比如移動(dòng)的包,游戲允許觀戰(zhàn),服務(wù) 器必然需要知道NPC的移動(dòng)坐標(biāo),再廣播給觀戰(zhàn)的其他玩家。在后面第4個(gè)包"SEND-> 0000 F4 44 10 DA 01 DB 6C 79 F6 05 02 27 35 01 00 00"里我們又看到了"6C 79 F6 05",初步斷定店小二的代碼就是它了!(這分析里邊包含了很多工作的,大家可以用WPE截下數(shù)據(jù)來自己分析分析)

                第一個(gè)包的分析暫時(shí)就到這里(里面還有的信息我們暫時(shí)不需要完全清楚了)

                我們看看第4個(gè)包"SEND-> 0000 F4 44 10 DA 01 DB 6C 79 F6 05 02 27 35 01 00 00",再截獲PK黃狗的包,(狗會(huì)出來2只哦)看看包的格式:SEND-> 0000 F4 44 1A DA 02 0B 4B 7D F6 05 02 27 35 01 00 00SEND-> 0010 EB 03 F8 05 02 27 36 01 00 00根據(jù)上面的分析,黃狗的代碼為"4B 7D F6 05"(100040011),不過兩只黃狗服務(wù)器怎樣分辨呢?看看"EB 03 F8 05"(100140011),是上一個(gè)代碼加上100000,呵呵,這樣服務(wù)器就可以認(rèn)出兩只黃狗了。我們?cè)偻ㄟ^野外遇敵截獲的數(shù)據(jù)包來證實(shí),果然如 此。

                那么,這個(gè)包的格式應(yīng)該比較清楚了:第3個(gè)字節(jié)為包的長(zhǎng)度,"DA"為指令,第5個(gè)字節(jié)為NPC個(gè)數(shù),從第7個(gè)字節(jié)開始的10個(gè)字節(jié)代表一個(gè)NPC的信息,多一個(gè)NPC就多10個(gè)字節(jié)來表示。

                大家如果玩過網(wǎng)金,必然知道隨機(jī)遇敵有時(shí)會(huì)出現(xiàn)增援,我們就利用游戲這個(gè)增援來讓每次戰(zhàn)斗都會(huì)出現(xiàn)增援的NPC吧。

                通過在戰(zhàn)斗中出現(xiàn)增援截獲的數(shù)據(jù)包,我們會(huì)發(fā)現(xiàn)服務(wù)器端發(fā)送了這樣一個(gè)包:F4 44 12 E9 EB 03 F8 05 02 00 00 03 00 00 00 00 00 00 第5-第8個(gè)字節(jié)為增援NPC的代碼(這里我們就簡(jiǎn)單的以黃狗的代碼來舉例)。 那么,我們就利用單機(jī)代理技術(shù)來同時(shí)欺騙客戶端和服務(wù)器吧!

                好了,呼叫NPC的工作到這里算是完成了一小半,接下來的事情,怎樣修改封包和發(fā)送封包,我們下節(jié)繼續(xù)講解吧。

                四:怎么冒充"客戶端"向"服務(wù)器"發(fā)我們需要的封包?

                這里我們需要使用一個(gè)工具,它位于客戶端和服務(wù)器端之間,它的工作就是進(jìn)行數(shù)據(jù)包的接收和轉(zhuǎn)發(fā),這個(gè)工具我們稱為代理。如果代理的工作單純就是接收和轉(zhuǎn)發(fā) 的話,這就毫無意義了,但是請(qǐng)注意:所有的數(shù)據(jù)包都要通過它來傳輸,這里的意義就重大了。我們可以分析接收到的數(shù)據(jù)包,或者直接轉(zhuǎn)發(fā),或者修改后轉(zhuǎn)發(fā),或 者壓住不轉(zhuǎn)發(fā),甚至偽造我們需要的封包來發(fā)送。

                下面我們繼續(xù)講怎樣來同時(shí)欺騙服務(wù)器和客戶端,也就是修改封包和偽造封包。 通過我們上節(jié)的分析,我們已經(jīng)知道了打多個(gè)NPC的封包格式,那么我們就動(dòng)手吧!

                首先我們要查找客戶端發(fā)送的包,找到戰(zhàn)斗的特征,就是請(qǐng)求戰(zhàn)斗的第1個(gè)包,我們找"F4 44 1F 30"這個(gè)特征,這是不會(huì)改變的,當(dāng)然是要解密后來查找哦。 找到后,表示客戶端在向服務(wù)器請(qǐng)求戰(zhàn)斗,我們不動(dòng)這個(gè)包,轉(zhuǎn)發(fā)。 繼續(xù)向下查找,這時(shí)需要查找的特征碼不太好辦,我們先查找"DA",這是客戶端發(fā)送NPC信息的數(shù)據(jù)包的指令,那么可能其他包也有"DA",沒關(guān)系,我們 看前3個(gè)字節(jié)有沒有"F4 44"就行了。找到后,我們的工作就開始了!

                我們確定要打的NPC數(shù)量。這個(gè)數(shù)量不能很大,原因在于網(wǎng)金的封包長(zhǎng)度用一個(gè)字節(jié)表示,那么一個(gè)包可以有255個(gè)字節(jié),我們上面分析過,增加一個(gè)NPC要增加10個(gè)字節(jié),所以大家算算就知道,打20個(gè)NPC比較合適。

                然后我們要把客戶端原來的NPC代碼分析計(jì)算出來,因?yàn)樵黾拥腘PC代碼要加上100000哦。再把我們?cè)黾拥腘PC代碼計(jì)算出來,并且組合成新的封包,注意代表包長(zhǎng)度的字節(jié)要修改啊,然后轉(zhuǎn)發(fā)到服務(wù)器,這一步在編寫程序的時(shí)候要注意算法,不要造成較大延遲。

                上面我們欺騙服務(wù)器端完成了,欺騙客戶端就簡(jiǎn)單了。

                發(fā)送了上面的封包后,我們根據(jù)新增NPC代碼構(gòu)造封包馬上發(fā)給客戶端,格式就是"F4 44 12 E9 NPC代碼 02 00 00 03 00 00 00 00 00 00",把每個(gè)新增的NPC都構(gòu)造這樣一個(gè)包,按順序連在一起發(fā)送給客戶端,客戶端也就被我們騙過了,很簡(jiǎn)單吧。

                以后戰(zhàn)斗中其他的事我們就不管了,盡情地開打吧。

                游戲外掛基本原理及實(shí)現(xiàn)

                解釋游戲外掛的基本原理和實(shí)現(xiàn)方法

                游戲外掛已經(jīng)深深地影響著眾多網(wǎng)絡(luò)游戲玩家,今天在網(wǎng)上看到了一些關(guān)于游戲外掛編寫的技術(shù),于是轉(zhuǎn)載上供大家參考

                1、游戲外掛的原理

                外掛現(xiàn)在分為好多種,比如模擬鍵盤的,鼠標(biāo)的,修改數(shù)據(jù)包的,還有修改本地內(nèi)存的,但好像沒有修改服務(wù)器內(nèi)存的哦,呵呵。其實(shí)修改服務(wù)器也是有辦法的,只是技術(shù)太高一般人沒有辦法入手而已。(比如請(qǐng)GM去夜總會(huì)、送禮、收黑錢等等辦法都可以修改服務(wù)器數(shù)據(jù),哈哈)

                修改游戲無非是修改一下本地內(nèi)存的數(shù)據(jù),或者截獲API函數(shù)等等。這里我把所能想到的方法都作一個(gè)介紹,希望大家能做出很好的外掛來使游戲廠商更好的完善 自己的技術(shù)。我見到一篇文章是講魔力寶貝的理論分析,寫得不錯(cuò),大概是那個(gè)樣子。下來我就講解一下技術(shù)方面的東西,以作引玉之用。


               2 技術(shù)分析部分

                2.1 模擬鍵盤或鼠標(biāo)的響應(yīng)

                我們一般使用:

            UINT SendInput(
                UINT nInputs,   // count of input events
               PINPUT pInputs, // array of input events
                int cbSize    // size of structure
              );
                API函數(shù)。第一個(gè)參數(shù)是說明第二個(gè)參數(shù)的矩陣的維數(shù)的,第二個(gè)參數(shù)包含了響應(yīng)事件,這個(gè)自己填充就可以,最后是這個(gè)結(jié)構(gòu)的大小,非常簡(jiǎn)單,這是最簡(jiǎn)單的方法模擬鍵盤鼠標(biāo)了,呵呵。注意,這個(gè)函數(shù)還有個(gè)替代函數(shù):

            VOID keybd_event(
                BYTE bVk,       // 虛擬鍵碼
                BYTE bScan,      // 掃描碼
                DWORD dwFlags,
                ULONG_PTR dwExtraInfo // 附加鍵狀態(tài)
              );
              與
              VOID mouse_event(
                DWORD dwFlags,      // motion and click options
                DWORD dx,         // horizontal position or change
                DWORD dy,        // vertical position or change
                DWORD dwData,      // wheel movement
                ULONG_PTR dwExtraInfo  // application-defined information
              );
                這兩個(gè)函數(shù)非常簡(jiǎn)單了,我想那些按鍵精靈就是用的這個(gè)吧。上面的是模擬鍵盤,下面的是模擬鼠標(biāo)的。這個(gè)僅僅是模擬部分,要和游戲聯(lián)系起來我們還需要找到游 戲的窗口才行,或者包含快捷鍵,就象按鍵精靈的那個(gè)激活鍵一樣,我們可以用GetWindow函數(shù)來枚舉窗口,也可以用Findwindow函數(shù)來查找制 定的窗口(注意,還有一個(gè)FindWindowEx),F(xiàn)indwindowEx可以找到窗口的子窗口,比如按鈕,等什么東西。當(dāng)游戲切換場(chǎng)景的時(shí)候我們 可以用FindWindowEx來確定一些當(dāng)前窗口的特征,從而判斷是否還在這個(gè)場(chǎng)景,方法很多了,比如可以GetWindowInfo來確定一些東西, 比如當(dāng)查找不到某個(gè)按鈕的時(shí)候就說明游戲場(chǎng)景已經(jīng)切換了,等等辦法。有的游戲沒有控件在里面,這是對(duì)圖像做坐標(biāo)變換的話,這種方法就要受到限制了。這就需 要我們用別的辦法來輔助分析了。

                至于快捷鍵我們要用動(dòng)態(tài)連接庫實(shí)現(xiàn)了,里面要用到hook技術(shù)了,這個(gè)也非常簡(jiǎn)單。大家可能都會(huì)了,其實(shí)就是一個(gè)全局的hook對(duì)象然后 SetWindowHook就可以了,回調(diào)函數(shù)都是現(xiàn)成的,而且現(xiàn)在網(wǎng)上的例子多如牛毛。這個(gè)實(shí)現(xiàn)在外掛中已經(jīng)很普遍了。如果還有誰不明白,那就去看看 MSDN查找SetWindowHook就可以了。

                不要低估了這個(gè)動(dòng)態(tài)連接庫的作用,它可以切入所有的進(jìn)程空間,也就是可以加載到所有的游戲里面哦,只要用對(duì),你會(huì)發(fā)現(xiàn)很有用途的。這個(gè)需要你復(fù)習(xí)一下Win32編程的基礎(chǔ)知識(shí)了。呵呵,趕快去看書吧。

                2.2 截獲消息

                有些游戲的響應(yīng)機(jī)制比較簡(jiǎn)單,是基于消息的,或者用什么定時(shí)器的東西。這個(gè)時(shí)候你就可以用攔截消息來實(shí)現(xiàn)一些有趣的功能了。

                我們攔截消息使用的也是hook技術(shù),里面包括了鍵盤消息,鼠標(biāo)消息,系統(tǒng)消息,日志等,別的對(duì)我們沒有什么大的用處,我們只用攔截消息的回調(diào)函數(shù)就可以 了,這個(gè)不會(huì)讓我寫例子吧。其實(shí)這個(gè)和上面的一樣,都是用SetWindowHook來寫的,看看就明白了很簡(jiǎn)單的。

                至于攔截了以后做什么就是你的事情了,比如在每個(gè)定時(shí)器消息里面處理一些我們的數(shù)據(jù)判斷,或者在定時(shí)器里面在模擬一次定時(shí)器,那么有些數(shù)據(jù)就會(huì)處理兩次, 呵呵。后果嘛,不一定是好事情哦,呵呵,不過如果數(shù)據(jù)計(jì)算放在客戶端的游戲就可以真的改變數(shù)據(jù)了,呵呵,試試看吧。用途還有很多,自己想也可以想出來的, 呵呵。

                2.3 攔截Socket包

                這個(gè)技術(shù)難度要比原來的高很多。

                首先我們要替換WinSock.DLL或者WinSock32.DLL,我們寫的替換函數(shù)要和原來的函數(shù)一致才行,就是說它的函數(shù)輸出什么樣的,我們也要 輸出什么樣子的函數(shù),而且參數(shù),參數(shù)順序都要一樣才行,然后在我們的函數(shù)里面調(diào)用真正的WinSock32.DLL里面的函數(shù)就可以了。

                首先:我們可以替換動(dòng)態(tài)庫到系統(tǒng)路徑。

                其次:我們應(yīng)用程序啟動(dòng)的時(shí)候可以加載原有的動(dòng)態(tài)庫,用這個(gè)函數(shù)LoadLibary然后定位函數(shù)入口用GetProcAddress函數(shù)獲得每個(gè)真正Socket函數(shù)的入口地址。

                當(dāng)游戲進(jìn)行的時(shí)候它會(huì)調(diào)用我們的動(dòng)態(tài)庫,然后從我們的動(dòng)態(tài)庫中處理完畢后才跳轉(zhuǎn)到真正動(dòng)態(tài)庫的函數(shù)地址,這樣我們就可以在里面處理自己的數(shù)據(jù)了,應(yīng)該是一 切數(shù)據(jù)。呵呵,興奮吧,攔截了數(shù)據(jù)包我們還要分析之后才能進(jìn)行正確的應(yīng)答,不要以為這樣工作就完成了,還早呢。等分析完畢以后我們還要仿真應(yīng)答機(jī)制來和服 務(wù)器通信,一個(gè)不小心就會(huì)被封號(hào)。

                分析數(shù)據(jù)才是工作量的來源呢,游戲每次升級(jí)有可能加密方式會(huì)有所改變,因此我們寫外掛的人都是亡命之徒啊,被人愚弄了還不知道。

                2.4 截獲API

                上面的技術(shù)如果可以靈活運(yùn)用的話我們就不用截獲API函數(shù)了,其實(shí)這種技術(shù)是一種補(bǔ)充技術(shù)。比如我們需要截獲Socket以外的函數(shù)作為我們的用途,我們就要用這個(gè)技術(shù)了,其實(shí)我們也可以用它直接攔截在Socket中的函數(shù),這樣更直接。

                現(xiàn)在攔截API的教程到處都是,我就不列舉了,我用的比較習(xí)慣的方法是根據(jù)輸入節(jié)進(jìn)行攔截的,這個(gè)方法可以用到任何一種操作系統(tǒng)上,比如Windows 98/2000等,有些方法不是跨平臺(tái)的,我不建議使用。這個(gè)技術(shù)大家可以參考《Windows核心編程》里面的545頁開始的內(nèi)容來學(xué)習(xí),如果是 Win98系統(tǒng)可以用“Windows系統(tǒng)奧秘”那個(gè)最后一章來學(xué)習(xí)。

                網(wǎng)絡(luò)游戲通訊模型初探

                [文章導(dǎo)讀]本文就將圍繞三個(gè)主題來給大家講述一下網(wǎng)絡(luò)游戲的網(wǎng)絡(luò)互連實(shí)現(xiàn)方法

                序言

                網(wǎng)絡(luò)游戲,作為游戲與網(wǎng)絡(luò)有機(jī)結(jié)合的產(chǎn)物,把玩家?guī)肓诵碌膴蕵奉I(lǐng)域。網(wǎng)絡(luò)游戲在中國開始發(fā)展至今也僅有3,4年的歷史,跟已經(jīng)擁有幾十年開發(fā)歷史的單機(jī)游戲相比,網(wǎng)絡(luò)游戲還是非常年輕的。當(dāng)然,它的形成也是根據(jù)歷史變化而產(chǎn)生的可以說沒有互聯(lián)網(wǎng)的 興起,也就沒有網(wǎng)絡(luò)游戲的誕生。作為新興產(chǎn)物,網(wǎng)絡(luò)游戲的開發(fā)對(duì)廣大開發(fā)者來說更加神秘,對(duì)于一個(gè)未知領(lǐng)域,開發(fā)者可能更需要了解的是網(wǎng)絡(luò)游戲與普通單機(jī) 游戲有何區(qū)別,網(wǎng)絡(luò)游戲如何將玩家們連接起來,以及如何為玩家提供一個(gè)互動(dòng)的娛樂環(huán)境。本文就將圍繞這三個(gè)主題來給大家講述一下網(wǎng)絡(luò)游戲的網(wǎng)絡(luò)互連實(shí)現(xiàn)方 法。

                網(wǎng)絡(luò)游戲與單機(jī)游戲

                說到網(wǎng)絡(luò)游戲,不得不讓人聯(lián)想到單機(jī)游戲,實(shí)際上網(wǎng)絡(luò)游戲的實(shí)質(zhì)脫離不了單機(jī)游戲的制作思想,網(wǎng)絡(luò)游戲和單機(jī)游戲的差別大家可以很直接的想到:不就是可以 多人連線嗎?沒錯(cuò),但如何實(shí)現(xiàn)這些功能,如何把網(wǎng)絡(luò)連線合理的融合進(jìn)單機(jī)游戲,就是我們下面要討論的內(nèi)容。在了解網(wǎng)絡(luò)互連具體實(shí)現(xiàn)之前,我們先來了解一下 單機(jī)與網(wǎng)絡(luò)它們各自的運(yùn)行流程,只有了解這些,你才能深入網(wǎng)絡(luò)游戲開發(fā)的核心。

                現(xiàn)在先讓我們來看一下普通單機(jī)游戲的簡(jiǎn)化執(zhí)行流程:

            Initialize() // 初始化模塊
            {
             初始化游戲數(shù)據(jù);
            }
            Game() // 游戲循環(huán)部分
            {
             繪制游戲場(chǎng)景、人物以及其它元素;
             獲取用戶操作輸入;
             switch( 用戶輸入數(shù)據(jù))
             {
              case 移動(dòng):
              {
               處理人物移動(dòng);
              }
              break;
              case 攻擊:
              {
               處理攻擊邏輯:
              }
              break;
              ...
              其它處理響應(yīng);
              ...
              default:
               break;
             }
             游戲的NPC等邏輯AI處理;
            }
            Exit() // 游戲結(jié)束
            {
             釋放游戲數(shù)據(jù);
             離開游戲;
            }

                我們來說明一下上面單機(jī)游戲的流程。首先,不管是游戲軟件還是其他應(yīng)用軟件,初始化部分必不可少,這里需要對(duì)游戲的數(shù)據(jù)進(jìn)行初始化,包括圖像、聲音以及一 些必備的數(shù)據(jù)。接下來,我們的游戲?qū)?chǎng)景、人物以及其他元素進(jìn)行循環(huán)繪制,把游戲世界展現(xiàn)給玩家,同時(shí)接收玩家的輸入操作,并根據(jù)操作來做出響應(yīng),此外, 游戲還需要對(duì)NPC以及一些邏輯AI進(jìn)行處理。最后,游戲數(shù)據(jù)被釋放,游戲結(jié)束。

                網(wǎng)絡(luò)游戲與單機(jī)游戲有一個(gè)很顯著的差別,就是網(wǎng)絡(luò)游戲除了一個(gè)供操作游戲的用戶界面平臺(tái)(如單機(jī)游戲)外,還需要一個(gè)用于連接所有用戶,并為所有用戶提供數(shù)據(jù)服務(wù)的服務(wù)器,從某些角度來看,游戲服務(wù)器就像一個(gè)大型的數(shù)據(jù)庫,

                提供數(shù)據(jù)以及數(shù)據(jù)邏輯交互的功能。讓我們來看看一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)游戲模型執(zhí)行流程:

                客戶機(jī):

            Login()// 登入模塊
            {
             初始化游戲數(shù)據(jù);
             獲取用戶輸入的用戶和密碼;
             與服務(wù)器創(chuàng)建網(wǎng)絡(luò)連接;
             發(fā)送至服務(wù)器進(jìn)行用戶驗(yàn)證;
             ...
             等待服務(wù)器確認(rèn)消息;
             ...
             獲得服務(wù)器反饋的登入消息;
             if( 成立 )
              進(jìn)入游戲;
             else
              提示用戶登入錯(cuò)誤并重新接受用戶登入;
            }
            Game()// 游戲循環(huán)部分
            {
             繪制游戲場(chǎng)景、人物以及其它元素;
             獲取用戶操作輸入;
             將用戶的操作發(fā)送至服務(wù)器;
             ...
             等待服務(wù)器的消息;
             ...
             接收服務(wù)器的反饋信息;
             switch( 服務(wù)器反饋的消息數(shù)據(jù) )
             {
              case 本地玩家移動(dòng)的消息:
              {
               if( 允許本地玩家移動(dòng) )
                客戶機(jī)處理人物移動(dòng);
               else
                客戶機(jī)保持原有狀態(tài);
              }
               break;
              case 其他玩家/NPC的移動(dòng)消息:
              {
               根據(jù)服務(wù)器的反饋信息進(jìn)行其他玩家或者NPC的移動(dòng)處理;
              }
              break;
              case 新玩家加入游戲:
              {
               在客戶機(jī)中添加顯示此玩家;
              }
               break;
              case 玩家離開游戲:
              {
               在客戶機(jī)中銷毀此玩家數(shù)據(jù);
              }
               break;
              ...
              其它消息類型處理;
              ... 
              default:
               break;
             }
            }
            Exit()// 游戲結(jié)束
            {
             發(fā)送離開消息給服務(wù)器;
             ...
             等待服務(wù)器確認(rèn);
             ...
             得到服務(wù)器確認(rèn)消息;
             與服務(wù)器斷開連接;
             釋放游戲數(shù)據(jù);
             離開游戲;
            }


              服務(wù)器:

            Listen()  // 游戲服務(wù)器等待玩家連接模塊
            {
             ...
             等待用戶的登入信息;
             ...
             接收到用戶登入信息;
             分析用戶名和密碼是否符合;
             if( 符合 )
             {
              發(fā)送確認(rèn)允許進(jìn)入游戲消息給客戶機(jī); 
              把此玩家進(jìn)入游戲的消息發(fā)布給場(chǎng)景中所有玩家;
              把此玩家添加到服務(wù)器場(chǎng)景中;
             }
             else
             {
              斷開與客戶機(jī)的連接;
             }
            }
            Game() // 游戲服務(wù)器循環(huán)部分
            {
             ...
             等待場(chǎng)景中玩家的操作輸入;
             ...
             接收到某玩家的移動(dòng)輸入或NPC的移動(dòng)邏輯輸入;
             // 此處只以移動(dòng)為例
             進(jìn)行此玩家/NPC在地圖場(chǎng)景是否可移動(dòng)的邏輯判斷;

             if( 可移動(dòng) )
             {
              對(duì)此玩家/NPC進(jìn)行服務(wù)器移動(dòng)處理;
              發(fā)送移動(dòng)消息給客戶機(jī);
              發(fā)送此玩家的移動(dòng)消息給場(chǎng)景上所有玩家;
             }
             else
              發(fā)送不可移動(dòng)消息給客戶機(jī);
            }
            Exit()  // 游戲服務(wù)=器結(jié)束
            {
             接收到玩家離開消息;
             將此消息發(fā)送給場(chǎng)景中所有玩家;
             發(fā)送允許離開的信息;
             將玩家數(shù)據(jù)存入數(shù)據(jù)庫;
             注銷此玩家在服務(wù)器內(nèi)存中的數(shù)據(jù);
            }
            }


                讓我們來說明一下上面簡(jiǎn)單網(wǎng)絡(luò)游戲模型的運(yùn)行機(jī)制。先來講講服務(wù)器端,這里服務(wù)器端分為三個(gè)部分(實(shí)際上一個(gè)完整的網(wǎng)絡(luò)游戲遠(yuǎn)不止這些):登入模塊、游戲 模塊和登出模塊。登入模塊用于監(jiān)聽網(wǎng)絡(luò)游戲客戶端發(fā)送過來的網(wǎng)絡(luò)連接消息,并且驗(yàn)證其合法性,然后在服務(wù)器中創(chuàng)建這個(gè)玩家并且把玩家?guī)ьI(lǐng)到游戲模塊中; 游戲模塊則提供給玩家用戶實(shí)際的應(yīng)用服務(wù),我們?cè)诤竺鏁?huì)詳細(xì)介紹這個(gè)部分; 在得到玩家要離開游戲的消息后,登出模塊則會(huì)把玩家從服務(wù)器中刪除,并且把玩家的屬性數(shù)據(jù)保存到服務(wù)器數(shù)據(jù)庫中,如: 經(jīng)驗(yàn)值、等級(jí)、生命值等。

                接下來讓我們看看網(wǎng)絡(luò)游戲的客戶端。這時(shí)候,客戶端不再像單機(jī)游戲一樣,初始化數(shù)據(jù)后直接進(jìn)入游戲,而是在與服務(wù)器創(chuàng)建連接,并且獲得許可的前提下才進(jìn)入 游戲。除此之外,網(wǎng)絡(luò)游戲的客戶端游戲進(jìn)程需要不斷與服務(wù)器進(jìn)行通訊,通過與服務(wù)器交換數(shù)據(jù)來確定當(dāng)前游戲的狀態(tài),例如其他玩家的位置變化、物品掉落情 況。同樣,在離開游戲時(shí),客戶端會(huì)向服務(wù)器告知此玩家用戶離開,以便于服務(wù)器做出相應(yīng)處理。

                以上用簡(jiǎn)單的偽代碼給大家闡述了單機(jī)游戲與網(wǎng)絡(luò)游戲的執(zhí)行流程,大家應(yīng)該可以清楚看出兩者的差別,以及兩者間相互的關(guān)系。我們可以換個(gè)角度考慮,網(wǎng)絡(luò)游戲 就是把單機(jī)游戲的邏輯運(yùn)算部分搬移到游戲服務(wù)器中進(jìn)行處理,然后把處理結(jié)果(包括其他玩家數(shù)據(jù))通過游戲服務(wù)器返回給連接的玩家。

                網(wǎng)絡(luò)互連

                在了解了網(wǎng)絡(luò)游戲基本形態(tài)之后,讓我們進(jìn)入真正的實(shí)際應(yīng)用部分。首先,作為網(wǎng)絡(luò)游戲,除了常規(guī)的單機(jī)游戲所必需的東西之外,我們還需要增加一個(gè)網(wǎng)絡(luò)通訊模塊,當(dāng)然,這也是網(wǎng)絡(luò)游戲較為主要的部分,我們來討論一下如何實(shí)現(xiàn)網(wǎng)絡(luò)的通訊模塊。

                一個(gè)完善的網(wǎng)絡(luò)通訊模塊涉及面相當(dāng)廣,本文僅對(duì)較為基本的處理方式進(jìn)行討論。網(wǎng)絡(luò)游戲是由客戶端和服務(wù)器組成,相應(yīng)也需要兩種不同的網(wǎng)絡(luò)通訊處理方式,不 過也有相同之處,我們先就它們的共同點(diǎn)來進(jìn)行介紹。我們這里以Microsoft Windows 2000 [2000 Server]作為開發(fā)平臺(tái),并且使用Winsock作為網(wǎng)絡(luò)接口(可能一些朋友會(huì)考慮使用DirectPlay來進(jìn)行網(wǎng)絡(luò)通訊,不過對(duì)于當(dāng)前在線游 戲,DirectPlay并不適合,具體原因這里就不做討論了)。

                確定好平臺(tái)與接口后,我們開始進(jìn)行網(wǎng)絡(luò)連接創(chuàng)建之前的一些必要的初始化工作,這部分無論是客戶端或者服務(wù)器都需要進(jìn)行。讓我們看看下面的代碼片段:

            WORD wVersionRequested;
            WSADATAwsaData;
            wVersionRequested MAKEWORD(1, 1);
            if( WSAStartup( wVersionRequested, &wsaData ) !0 )
            {
             Failed( WinSock Version Error!" );
            }
              上面通過調(diào)用Windows的socket API函數(shù)來初始化網(wǎng)絡(luò)設(shè)備,接下來進(jìn)行網(wǎng)絡(luò)Socket的創(chuàng)建,代碼片段如下:

            SOCKET sSocket socket( AF_INET, m_lProtocol, 0 );
            if( sSocket == INVALID_SOCKET )
            {
             Failed( "WinSocket Create Error!" );
            }

                這里需要說明,客戶端和服務(wù)端所需要的Socket連接數(shù)量是不同的,客戶端只需要一個(gè)Socket連接足以滿足游戲的需要,而服務(wù)端必須為每個(gè)玩家用戶 創(chuàng)建一個(gè)用于通訊的Socket連接。當(dāng)然,并不是說如果服務(wù)器上沒有玩家那就不需要?jiǎng)?chuàng)建Socket連接,服務(wù)器端在啟動(dòng)之時(shí)會(huì)生成一個(gè)特殊的 Socket用來對(duì)玩家創(chuàng)建與服務(wù)器連接的請(qǐng)求進(jìn)行響應(yīng),等介紹網(wǎng)絡(luò)監(jiān)聽部分后會(huì)有更詳細(xì)說明。

                有初始化與創(chuàng)建必然就有釋放與刪除,讓我們看看下面的釋放部分:

            if( sSocket != INVALID_SOCKET )
            {
             closesocket( sSocket );
            }
            if( WSACleanup() != 0 )
            {
             Warning( "Can't release Winsocket" );
            }

                這里兩個(gè)步驟分別對(duì)前面所作的創(chuàng)建初始化進(jìn)行了相應(yīng)釋放。

                接下來看看服務(wù)器端的一個(gè)網(wǎng)絡(luò)執(zhí)行處理,這里我們假設(shè)服務(wù)器端已經(jīng)創(chuàng)建好一個(gè)Socket供使用,我們要做的就是讓這個(gè)Socket變成監(jiān)聽網(wǎng)絡(luò)連接請(qǐng)求的專用接口,看看下面代碼片段:

            SOCKADDR_IN addr;
            memset( &addr, 0, sizeof(addr) );
            addr.sin_family = AF_INET;
            addr.sin_addr.s_addr = htonl( INADDR_ANY );
            addr.sin_port = htons( Port );  // Port為要監(jiān)聽的端口號(hào)
            // 綁定socket
            if( bind( sSocket, (SOCKADDR*)&addr, sizeof(addr) ) == SOCKET_ERROR )
            {
             Failed( "WinSocket Bind Error!");
            }
            // 進(jìn)行監(jiān)聽
            if( listen( sSocket, SOMAXCONN ) == SOCKET_ERROR )
            {
             Failed( "WinSocket Listen Error!");
            }

                這里使用的是阻塞式通訊處理,此時(shí)程序?qū)⑻幱诘却婕矣脩暨B接的狀態(tài),倘若這時(shí)候有客戶端連接進(jìn)來,則通過accept()來創(chuàng)建針對(duì)此玩家用戶的Socket連接,代碼片段如下:

            sockaddraddrServer;
            int nLen sizeof( addrServer );
            SOCKET sPlayerSocket accept( sSocket, &addrServer, &nLen );
            if( sPlayerSocket == INVALID_SOCKET )
            {
             Failed( WinSocket Accept Error!");
            }

                這里我們創(chuàng)建了sPlayerSocket連接,此后游戲服務(wù)器與這個(gè)玩家用戶的通訊全部通過此Socket進(jìn)行,到這里為止,我們服務(wù)器已經(jīng)有了接受玩家用戶連接的功能,現(xiàn)在讓我們來看看游戲客戶端是如何連接到游戲服務(wù)器上,代碼片段如下:

            SOCKADDR_IN addr;
            memset( &addr, 0, sizeof(addr) );
            addr.sin_family = AF_INET;// 要連接的游戲服務(wù)器端口號(hào)
            addr.sin_addr.s_addr = inet_addr( IP );// 要連接的游戲服務(wù)器IP地址,
            addr.sin_port = htons( Port );//到此,客戶端和服務(wù)器已經(jīng)有了通訊的橋梁,
            //接下來就是進(jìn)行數(shù)據(jù)的發(fā)送和接收:
            connect( sSocket, (SOCKADDR*)&addr, sizeof(addr) );
            if( send( sSocket, pBuffer, lLength, 0 ) == SOCKET_ERROR )
            {
             Failed( "WinSocket Send Error!");
            }


                這里的pBuffer為要發(fā)送的數(shù)據(jù)緩沖指針,lLength為需要發(fā)送的數(shù)據(jù)長(zhǎng)度,通過這支Socket API函數(shù),我們無論在客戶端或者服務(wù)端都可以進(jìn)行數(shù)據(jù)的發(fā)送工作,同時(shí),我們可以通過recv()這支Socket API函數(shù)來進(jìn)行數(shù)據(jù)接收:

            lLength, 0 ) == SOCKET_ERROR )
            {
             Failed( "WinSocket Recv Error!");
            }

                其中pBuffer用來存儲(chǔ)獲取的網(wǎng)絡(luò)數(shù)據(jù)緩沖,lLength則為需要獲取的數(shù)據(jù)長(zhǎng)度。


                現(xiàn)在,我們已經(jīng)了解了一些網(wǎng)絡(luò)互連的基本知識(shí),但作為網(wǎng)絡(luò)游戲,如此簡(jiǎn)單的連接方式是無法滿足網(wǎng)絡(luò)游戲中百人千人同時(shí)在線的,我們需要更合理容錯(cuò)性更強(qiáng)的網(wǎng)絡(luò)通訊處理方式,當(dāng)然,我們需要先了解一下網(wǎng)絡(luò)游戲?qū)W(wǎng)絡(luò)通訊的需求是怎樣的。

                大家知道,游戲需要不斷循環(huán)處理游戲中的邏輯并進(jìn)行游戲世界的繪制,上面所介紹的Winsock處理方式均是以阻塞方式進(jìn)行,這樣就違背了游戲的執(zhí)行本 質(zhì),可以想象,在客戶端連接到服務(wù)器的過程中,你的游戲不能得到控制,這時(shí)如果玩家想取消連接或者做其他處理,甚至顯示一個(gè)最基本的動(dòng)態(tài)連接提示都不行。

                所以我們需要用其他方式來處理網(wǎng)絡(luò)通訊,使其不會(huì)與游戲主線相沖突,可能大家都會(huì)想到: 創(chuàng)建一個(gè)網(wǎng)絡(luò)線程來處理不就可以了?沒錯(cuò),我們可以創(chuàng)建一個(gè)專門用于網(wǎng)絡(luò)通訊的子線程來解決這個(gè)問題。當(dāng)然,我們游戲中多了一個(gè)線程,我們就需要做更多的 考慮,讓我們來看看如何創(chuàng)建網(wǎng)絡(luò)通訊線程。

                在Windows系統(tǒng)中,我們可以通過CreateThread()函數(shù)來進(jìn)行線程的創(chuàng)建,看看下面的代碼片段:

            DWORD dwThreadID;
            HANDLE hThread = CreateThread( NULL, 0, NetThread/*網(wǎng)絡(luò)線程函式*/, sSocket, 0, &dwThreadID );
            if( hThread == NULL )
            {
             Failed( "WinSocket Thread Create Error!");
            }
              這里我們創(chuàng)建了一個(gè)線程,同時(shí)將我們的Socket傳入線程函數(shù):

            DWORD WINAPINetThread(LPVOID lParam)

            {
             SOCKET sSocket (SOCKET)lParam;
             ...
             return 0;
            }

                NetThread就是我們將來用于處理網(wǎng)絡(luò)通訊的網(wǎng)絡(luò)線程。那么,我們又如何把Socket的處理引入線程中?

                看看下面的代碼片段:

            HANDLE hEvent;
            hEvent = CreateEvent(NULL,0,0,0);
            // 設(shè)置異步通訊
            if( WSAEventSelect( sSocket, hEvent,
            FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE ) ==SOCKET_ERROR )
            {
             Failed( "WinSocket EventSelect Error!");
            }

                通過上面的設(shè)置之后,WinSock API函數(shù)均會(huì)以非阻塞方式運(yùn)行,也就是函數(shù)執(zhí)行后會(huì)立即返回,這時(shí)網(wǎng)絡(luò)通訊會(huì)以事件方式存儲(chǔ)于hEvent,而不會(huì)停頓整支程式。

                完成了上面的步驟之后,我們需要對(duì)事件進(jìn)行響應(yīng)與處理,讓我們看看如何在網(wǎng)絡(luò)線程中獲得網(wǎng)絡(luò)通訊所產(chǎn)生的事件消息:

            WSAEnumNetworkEvents( sSocket, hEvent, &SocketEvents );
            if( SocketEvents.lNetworkEvents != 0 )
            {
             switch( SocketEvents.lNetworkEvents )
             {
              case FD_ACCEPT:
               WSANETWORKEVENTS SocketEvents;
               break;
              case FD_CONNECT:
              {
               if( SocketEvents.iErrorCode[FD_CONNECT_BIT] == 0)
               // 連接成功  
               {
               // 連接成功后通知主線程(游戲線程)進(jìn)行處理
               }
              }
               break;
              case FD_READ:
              // 獲取網(wǎng)絡(luò)數(shù)據(jù)
              {
               if( recv( sSocket, pBuffer, lLength, 0) == SOCKET_ERROR )
               {
                Failed( "WinSocket Recv Error!");
               }
              }
               break;
              case FD_WRITE:
               break;
              case FD_CLOSE:
               // 通知主線程(游戲線程), 網(wǎng)絡(luò)已經(jīng)斷開
               break;
              default:
            }
            }


                這里僅對(duì)網(wǎng)絡(luò)連接(FD_CONNECT) 和讀取數(shù)據(jù)(FD_READ) 進(jìn)行了簡(jiǎn)單模擬操作,但實(shí)際中網(wǎng)絡(luò)線程接收到事件消息后,會(huì)對(duì)數(shù)據(jù)進(jìn)行組織整理,然后再將數(shù)據(jù)回傳給我們的游戲主線程使用,游戲主線程再將處理過的數(shù)據(jù)發(fā) 送出去,這樣一個(gè)往返就構(gòu)成了我們網(wǎng)絡(luò)游戲中的數(shù)據(jù)通訊,是讓網(wǎng)絡(luò)游戲動(dòng)起來的最基本要素。

                最后,我們來談?wù)勱P(guān)于網(wǎng)絡(luò)數(shù)據(jù)包(數(shù)據(jù)封包)的組織,網(wǎng)絡(luò)游戲的數(shù)據(jù)包是游戲數(shù)據(jù)通訊的最基本單位,網(wǎng)絡(luò)游戲一般不會(huì)用字節(jié)流的方式來進(jìn)行數(shù)據(jù)傳輸,一個(gè) 數(shù)據(jù)封包也可以看作是一條消息指令,在游戲進(jìn)行中,服務(wù)器和客戶端會(huì)不停的發(fā)送和接收這些消息包,然后將消息包解析轉(zhuǎn)換為真正所要表達(dá)的指令意義并執(zhí)行。

                互動(dòng)與管理

                說到互動(dòng),對(duì)于玩家來說是與其他玩家的交流,但對(duì)于計(jì)算機(jī)而言,實(shí)現(xiàn)互動(dòng)也就是實(shí)現(xiàn)數(shù)據(jù)消息的相互傳遞。前面我們已經(jīng)了解過網(wǎng)絡(luò)通訊的基本概念,它構(gòu)成了 互動(dòng)的最基本條件,接下來我們需要在這個(gè)網(wǎng)絡(luò)層面上進(jìn)行數(shù)據(jù)的通訊。遺憾的是,計(jì)算機(jī)并不懂得如何表達(dá)玩家之間的交流,因此我們需要提供一套可讓計(jì)算機(jī)了 解的指令組織和解析機(jī)制,也就是對(duì)我們上面簡(jiǎn)單提到的網(wǎng)絡(luò)數(shù)據(jù)包(數(shù)據(jù)封包)的處理機(jī)制。

                為了能夠更簡(jiǎn)單的給大家闡述網(wǎng)絡(luò)數(shù)據(jù)包的組織形式,我們以一個(gè)聊天處理模塊來進(jìn)行討論,看看下面的代碼結(jié)構(gòu):

            struct tagMessage{
             long lType;
             long lPlayerID;
            };
            // 消息指令
            // 指令相關(guān)的玩家標(biāo)識(shí)
            char strTalk[256]; // 消息內(nèi)容

                上面是抽象出來的一個(gè)極為簡(jiǎn)單的消息包結(jié)構(gòu),我們先來談?wù)勂涓鱾€(gè)數(shù)據(jù)域的用途:首先,lType 是消息指令的類型,這是最為基本的消息標(biāo)識(shí),這個(gè)標(biāo)識(shí)用來告訴服務(wù)器或客戶端這條指令的具體用途,以便于服務(wù)器或客戶端做出相應(yīng)處理。lPlayerID 被作為玩家的標(biāo)識(shí)。大家知道,一個(gè)玩家在機(jī)器內(nèi)部實(shí)際上也就是一堆數(shù)據(jù),特別是在游戲服務(wù)器中,可能有成千上萬個(gè)玩家,這時(shí)候我們需要一個(gè)標(biāo)記來區(qū)分玩 家,這樣就可以迅速找到特定玩家,并將通訊數(shù)據(jù)應(yīng)用于其上。

                strTalk 是我們要傳遞的聊天數(shù)據(jù),這部分才是真正的數(shù)據(jù)實(shí)體,前面的參數(shù)只是數(shù)據(jù)實(shí)體應(yīng)用范圍的限定。

                在組織完數(shù)據(jù)之后,緊接著就是把這個(gè)結(jié)構(gòu)體數(shù)據(jù)通過Socket 連接發(fā)送出去和接收進(jìn)來。這里我們要了解,網(wǎng)絡(luò)在進(jìn)行數(shù)據(jù)傳輸過程中,它并不關(guān)心數(shù)據(jù)采用的數(shù)據(jù)結(jié)構(gòu),這就需要我們把數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換為二進(jìn)制數(shù)據(jù)碼進(jìn)行發(fā) 送,在接收方,我們?cè)賹⑦@些二進(jìn)制數(shù)據(jù)碼轉(zhuǎn)換回程序使用的相應(yīng)數(shù)據(jù)結(jié)構(gòu)。讓我們來看看如何實(shí)現(xiàn):

            tagMessageMsg;
            Msg.lTypeMSG_CHAT;
            Msg.lPlayerID 1000;
            strcpy( &Msg.strTalk, "聊天信息" );

                首先,我們假設(shè)已經(jīng)組織好一個(gè)數(shù)據(jù)包,這里MSG_CHAT 是我們自行定義的標(biāo)識(shí)符,當(dāng)然,這個(gè)標(biāo)識(shí)符在服務(wù)器和客戶端要統(tǒng)一。玩家的ID 則根據(jù)游戲需要來進(jìn)行設(shè)置,這里1000 只作為假設(shè),現(xiàn)在繼續(xù):

            char* p = (char*)&Msg;
            long lLength = sizeof( tagMessage );
            send( sSocket, p, lLength );
            // 獲取數(shù)據(jù)結(jié)構(gòu)的長(zhǎng)度

                我們通過強(qiáng)行轉(zhuǎn)換把結(jié)構(gòu)體轉(zhuǎn)變?yōu)閏har 類型的數(shù)據(jù)指針,這樣就可以通過這個(gè)指針來進(jìn)行流式數(shù)據(jù)處理,這里通過

                sizeof() 獲得結(jié)構(gòu)體長(zhǎng)度,然后用WinSock 的Send() 函數(shù)將數(shù)據(jù)發(fā)送出去。

                接下來看看如何接收數(shù)據(jù):

            long lLength = sizeof( tagMessage );
            char* Buffer = new char[lLength];
            recv( sSocket, Buffer, lLength );
            tagMessage* p = (tagMessage*)Buffer;
            // 獲取數(shù)據(jù)

                在通過WinSock 的recv() 函數(shù)獲取網(wǎng)絡(luò)數(shù)據(jù)之后,我們同樣通過強(qiáng)行轉(zhuǎn)換把獲取出來的緩沖數(shù)據(jù)轉(zhuǎn)換為相應(yīng)結(jié)構(gòu)體,這樣就可以方便地對(duì)數(shù)據(jù)進(jìn)行訪問。(注:強(qiáng)行轉(zhuǎn)換僅僅作為數(shù)據(jù)轉(zhuǎn)換的 一種手段,實(shí)際應(yīng)用中有更多可選方式,這里只為簡(jiǎn)潔地說明邏輯)談到此處,不得不提到服務(wù)器/ 客戶端如何去篩選處理各種消息以及如何對(duì)通訊數(shù)據(jù)包進(jìn)行管理。無論是服務(wù)器還是客戶端,在收到網(wǎng)絡(luò)消息的時(shí)候,通過上面的數(shù)據(jù)解析之后,還必須對(duì)消息類型 進(jìn)行一次篩選和派分,簡(jiǎn)單來說就是類似Windows 的消息循環(huán),不同消息進(jìn)行不同處理。這可以通過一個(gè)switch 語句(熟悉Windows 消息循環(huán)的朋友相信已經(jīng)明白此意),基于消

                息封包里的lType 信息,對(duì)消息進(jìn)行區(qū)分處理,考慮如下代碼片段:

            switch( p->lType ) // 這里的p->lType為我們解析出來的消息類型標(biāo)識(shí)
            {
             case MSG_CHAT: // 聊天消息
              break;
             case MSG_MOVE: // 玩家移動(dòng)消息
              break;
             case MSG_EXIT: // 玩家離開消息
              break;
             default:
              break;
            }

                面片段中的MSG_MOVE 和MSG_EXIT 都是我們虛擬的消息標(biāo)識(shí)(一個(gè)真實(shí)游戲中的標(biāo)識(shí)可能會(huì)有上百個(gè),這就需要考慮優(yōu)化和優(yōu)先消息處理問題)。此外,一個(gè)網(wǎng)絡(luò)游戲服務(wù)器面對(duì)的是成百上千的連接 用戶,我們還需要一些合理的數(shù)據(jù)組織管理方式來進(jìn)行相關(guān)處理。普通的單體游戲服務(wù)器,可能會(huì)因?yàn)楫?dāng)機(jī)或者用戶過多而導(dǎo)致整個(gè)游戲網(wǎng)絡(luò)癱瘓,而這也就引入分 組服務(wù)器機(jī)制,我們把服務(wù)器分開進(jìn)行數(shù)據(jù)的分布式處理。

                我們把每個(gè)模塊提取出來,做成專用的服務(wù)器系統(tǒng),然后建立一個(gè)連接所有服務(wù)器的數(shù)據(jù)中心來進(jìn)行數(shù)據(jù)交互,這里每個(gè)模塊均與數(shù)據(jù)中心創(chuàng)建了連接,保證了每個(gè) 模塊的相關(guān)性,同時(shí)玩家轉(zhuǎn)變?yōu)榕c當(dāng)前提供服務(wù)的服務(wù)器進(jìn)行連接通訊,這樣就可以緩解單獨(dú)一臺(tái)服務(wù)器所承受的負(fù)擔(dān),把壓力分散到多臺(tái)服務(wù)器上,同時(shí)保證了數(shù) 據(jù)的統(tǒng)一,而且就算某臺(tái)服務(wù)因?yàn)楫惓6?dāng)機(jī)也不會(huì)影響其他模塊的游戲玩家,從而提高了整體穩(wěn)定性。分組式服務(wù)器緩解了服務(wù)器的壓力,但也帶來了服務(wù)器調(diào)度 問題,分組式服務(wù)器需要對(duì)服務(wù)器跳轉(zhuǎn)進(jìn)行處理,就以一個(gè)玩家進(jìn)行游戲場(chǎng)景跳轉(zhuǎn)作為討論基礎(chǔ):假設(shè)有一玩家處于游戲場(chǎng)景A,他想從場(chǎng)景A 跳轉(zhuǎn)到場(chǎng)景B,在游戲中,我們稱之場(chǎng)景切換,這時(shí)玩家就會(huì)觸發(fā)跳轉(zhuǎn)需求,比如走到了場(chǎng)景中的切換點(diǎn),這樣服務(wù)器就把玩家數(shù)據(jù)從"游戲場(chǎng)景A 服務(wù)器"刪除,同時(shí)在"游戲場(chǎng)景B 服務(wù)器"中把玩家建立起來。

                這里描述了場(chǎng)景切換的簡(jiǎn)單模型,當(dāng)中處理還有很多步驟,不過通過這樣的思考相信大家可以派生出很多應(yīng)用技巧。

                不過需要注意的是,在場(chǎng)景切換或者說模塊間切換的時(shí)候,需要切實(shí)考慮好數(shù)據(jù)的傳輸安全以及邏輯合理性,否則切換很可能會(huì)成為將來玩家復(fù)制物品的橋梁。

                總結(jié)

                本篇講述的都是通過一些簡(jiǎn)單的過程來進(jìn)行網(wǎng)絡(luò)游戲通訊,提供了一個(gè)制作的思路,雖然具體實(shí)現(xiàn)起來還有許多要做 ,但只要順著這個(gè)思路去擴(kuò)展、去完善,相信大家很快就能夠編寫出自己的網(wǎng)絡(luò)通訊模塊。由于時(shí)間倉促,本文在很多細(xì)節(jié)方面都有省略,文中若有錯(cuò)誤之處也望大 家見諒



            posted on 2009-09-23 23:39 暗夜教父 閱讀(1453) 評(píng)論(0)  編輯 收藏 引用 所屬分類: Game Development

            <2009年9月>
            303112345
            6789101112
            13141516171819
            20212223242526
            27282930123
            45678910

            常用鏈接

            留言簿(2)

            隨筆分類

            隨筆檔案

            文章分類

            文章檔案

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            国产精品岛国久久久久| 国产福利电影一区二区三区,免费久久久久久久精 | 久久国产精品免费一区二区三区| 伊人久久精品无码二区麻豆| 色狠狠久久综合网| 色8激情欧美成人久久综合电| 久久久久国产视频电影| 精品久久国产一区二区三区香蕉 | 日本精品久久久中文字幕| 国产91色综合久久免费| 69久久精品无码一区二区| 国产精品久久久久9999| 久久99精品久久久久久动态图| 久久久久久午夜成人影院 | 97久久综合精品久久久综合| 久久99精品久久久久久久不卡| 国内精品伊人久久久久av一坑| 国产精品青草久久久久婷婷| 国产精品美女久久久久网| 热99re久久国超精品首页| 国产精品激情综合久久| 欧美午夜精品久久久久久浪潮| 亚洲综合久久久| 97久久天天综合色天天综合色hd| 久久久久免费精品国产| 久久精品亚洲乱码伦伦中文| 性高朝久久久久久久久久| 97精品依人久久久大香线蕉97| 国产成人精品久久免费动漫| 久久福利片| 浪潮AV色综合久久天堂| 99久久精品这里只有精品| 欧美久久亚洲精品| 蜜臀久久99精品久久久久久小说| 日本精品久久久久中文字幕| 婷婷久久五月天| 国产91色综合久久免费分享| 亚洲国产日韩欧美久久| 97久久超碰成人精品网站| 亚洲国产成人精品久久久国产成人一区二区三区综| 久久久黄色大片|