一般用Ghost主機(jī)游戲名字XXXXX #2,當(dāng)此我想顯示當(dāng)前加入游戲中的人數(shù),例如Dota,XXXXX #2(2/10),表示當(dāng)前有2個(gè)人加入.
首先對(duì)于戰(zhàn)網(wǎng)PVPGN不支持修改游戲名字,因此我還修改pvpgn,使得支持修改游戲名字,閑話少說(shuō),先看一下我的效果。

(在http://cid-4b5bdf2f7fd33dee.office.live.com/browse.aspx/pvpgn,可以下載我win32 x86環(huán)境下編譯好的ghostcb,pvpgn1.99)
下面開(kāi)始開(kāi)工了
修改ghost
(1)下載ghost源碼了http://www.codelain.com/forum/index.php?topic=13083.0
(2)bnet.h中,修改函數(shù)QueueGameRefresh,這個(gè)方法用于游戲創(chuàng)建,游戲更新的,我在這方法加入一個(gè)參數(shù),player_num:游戲人數(shù)
void QueueGameRefresh( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *saveGame, uint32_t upTime, uint32_t hostCounter ,uint32_t player_num=0);
bnet.cpp修改QueueGameRefresh

void CBNET :: QueueGameRefresh( unsigned char state, string gameName, string hostName, CMap *map, CSaveGame *saveGame, uint32_t upTime, uint32_t hostCounter ,uint32_t player_num/**//*=0*/)


{
if( hostName.empty( ) )

{
BYTEARRAY UniqueName = m_Protocol->GetUniqueName( );
hostName = string( UniqueName.begin( ), UniqueName.end( ) );
}
//moidfy gameName with player_num
gameName=gameName+"("+UTIL_ToString(player_num)+"/10)";//在游戲名字中顯示人數(shù)
//下面的就不用改了
(3)game_base.cpp中,修改函數(shù) function CBaseGame :: Update( void *fd, void *send_fd )
for( vector<CBNET *> :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ )

{
// don't queue a game refresh message if the queue contains more than 1 packet because they're very low priority

if( (*i)->GetOutPacketsQueued( ) <= 1 )

{

//add m_players.size() in parmeter list 傳入?yún)?shù)當(dāng)前加入游戲的人數(shù)
(*i)->QueueGameRefresh( m_GameState, m_GameName, string( ), m_Map, m_SaveGame, GetTime( ) - m_CreationTime, m_HostCounter ,m_Players.size());

Refreshed = true;
}
}
4 在game_base.cpp中,函數(shù)CBaseGame :: EventPlayerJoined和函數(shù)CBaseGame :: EventPlayerLeft的末尾添加以下代碼,即當(dāng)有玩家加入或者退出游戲時(shí),更新游戲名字
for( vector<CBNET *> :: iterator i = m_GHost->m_BNETs.begin( ); i != m_GHost->m_BNETs.end( ); i++ )

{
// don't queue a game refresh message if the queue contains more than 1 packet because they're very low priority

if( (*i)->GetOutPacketsQueued( ) <= 1 )

{

(*i)->QueueGameRefresh( m_GameState, m_GameName, string( ), m_Map, m_SaveGame, GetTime( ) - m_CreationTime, m_HostCounter ,m_Players.size());
}
}
ghost就修改好了,下面則是要改pvpgn,支持游戲名字的修改。
(1)還是去下載pvpgn的源碼包
http://pvpgn.berlios.de/index.php?page=files至于pvpgn的編譯,我用的vs平臺(tái),在pvpgn包內(nèi)doc文件夾下有個(gè)編譯方法,還是比較麻煩的,在這里我就不多說(shuō)了,網(wǎng)上也有文章說(shuō)編譯1.99的
http://yjfyy.spaces.live.com/blog/cns!B6AD95965E3A9326!550.entry()
(2)在game.h里添加一個(gè)修改游戲名字的方法申明,
void game_set_name(t_game * game,const char * name);
如下
extern t_game_flag game_get_flag(t_game const * game);
extern int game_get_count_by_clienttag(t_clienttag ct);
extern int game_is_ladder(t_game *game);
extern int game_discisloss(t_game *game);
extern int game_set_channel(t_game * game, t_channel * channel);
extern t_channel * game_get_channel(t_game * game);
//add function game_set_name
extern void game_set_name(t_game * game,const char * name);
添加一個(gè)CRITICAL_SECTION 臨界區(qū)變量(注這個(gè)只是在windows下的,對(duì)于linux可以linux下互斥變量替換),用于多線程game_list的互斥訪問(wèn)。在這里只是申明,至于定義和初始化,我把它放在winmain.cpp中,這個(gè)在后面我再細(xì)講
#ifndef INCLUDED_GAME_TYPES
#define INCLUDED_GAME_TYPES
//add a CRITICAL_SECTION
#ifdef _USE_SECTION
#include <Windows.h>
extern CRITICAL_SECTION gamelist_section;
#endif
(3) game.cpp中,在#inlcude "game.h",前定義_USE_SECTION
#define _USE_SECTION
#include "game.h"
#undef _USE_SECTION
在這里說(shuō)明一下,為什么 要用_USE_SECTION。
若直接在game.h不用#ifdef _USE_SECTION,那不就省事了。
事實(shí)上這么弄會(huì)出很多編譯錯(cuò)誤,主要就是 windows.h惹的禍,因?yàn)檫@樣別的地方#include "game.h",把windows.h也包含去了,會(huì)發(fā)生很多編譯錯(cuò)誤。
添加 game_set_name函數(shù)的定義
extern void game_set_name(t_game * game,const char * name)


{
EnterCriticalSection(&gamelist_section);//臨界區(qū),互斥訪問(wèn),以免產(chǎn)生讀寫沖突
if(stricmp(game->name,name)!=0)

{
xfree((void *)game->name);
game->name=xstrdup(name);
}
LeaveCriticalSection(&gamelist_section);
}
(4)CRITICAL_SECTION gamelist_section變量的定義及初始化(注在game.h只是申明,extern)
在winmain.cpp中 添加#include "bnet/game.h"
#define _USE_SECTION
#include "bnetd/game.h"
#ifdef _USE_SECTION
CRITICAL_SECTION gamelist_section;
#endif


在int CALLBACK WinMain函數(shù)中添加 gamelist_section的初始化
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE reserved, LPSTR lpCmdLine, int nCmdShow)


{
#ifdef _USE_SECTION
InitializeCriticalSection(&gamelist_section);//初始化....
#endif
int result;
Console console;


if (cmdline_load(__argc, __argv) != 1)
{
return -1;
}
(5)準(zhǔn)備工作已經(jīng)做好了,現(xiàn)在就可以更新游戲名字了
static int _client_startgame4(t_connection * c, t_packet const *const packet)這個(gè)方法用于處理游戲建立以及游戲更新,我們就在這個(gè)方法里面更新游戲名字
hanlde_bnet.cpp中static int _client_startgame4(t_connection * c, t_packet const *const packet)函數(shù)加入一行代碼

if ((currgame = conn_get_game(c)))
{
#ifdef _SLOTS
//update the game name ########加入這行,要使得這個(gè)生效,在編譯宏中加入_SLOTS,或者直接在game.cpp加入一行#define _SLOTS
game_set_name(currgame,gamename);
#endif

if ((status & CLIENT_STARTGAME4_STATUSMASK_OPEN_VALID) == status)
{
if (status & CLIENT_STARTGAME4_STATUS_START)
game_set_status(currgame, game_status_started);
else if (status & CLIENT_STARTGAME4_STATUS_FULL)
game_set_status(currgame, game_status_full);
else
game_set_status(currgame, game_status_open);

} else
{
eventlog(eventlog_level_error, __FUNCTION__, "[%d] unknown startgame4 status %d (clienttag: %s)", conn_get_socket(c), status, clienttag_uint_to_str(conn_get_clienttag(c)));
}
(6) 至此因該基本完成,不過(guò)還有一個(gè)bug,處理pvpgan服務(wù)端與客戶端游戲更新不一致的情況
例如服務(wù)端游戲名字是XXXXX #1(1/10),而客戶端沒(méi)有及時(shí)更新游戲列表,XXXXX #1(0/10),此時(shí)客戶端加入游戲時(shí),就會(huì)出錯(cuò). 修改gamelist_find_game方法,修改游戲名字查找游戲方法,我只匹配'('前面的部分,XXXXX #1(1/10)與XXXXX #1(0/10)認(rèn)為是同一個(gè)游戲。
添加一個(gè)游戲名字匹配的輔助方法,這個(gè)只在game.cpp中添加就可以了,為內(nèi)部函數(shù)。
bool prefix_string(const char * str,const char * prex)


{
int i=0;
if(strlen(str)<strlen(prex))

{
return false;
}
while(prex[i]!=0 && prex[i]!='(')

{
if(prex[i]!=str[i])
return false;
i++;
}
return true;

}
修改gamelist_find_game方法
extern t_game * gamelist_find_game(char const * name, t_clienttag ctag, t_game_type type)


{
t_elist *curr;
t_game *game;
//臨界區(qū)
EnterCriticalSection(&gamelist_section);
elist_for_each(curr,&gamelist_head)

{
game = elist_entry(curr,t_game,glist_link);
if ((type==game_type_all || game->type==type)
&& ctag == game->clienttag
&& game->name
&&
//主要修改部分,游戲名字不一致時(shí),只匹配(前面的部分
(!strcasecmp(name,game->name) || prefix_string(game->name,name)))

{
LeaveCriticalSection(&gamelist_section);
return game;
}
}
//退出臨界區(qū)
LeaveCriticalSection(&gamelist_section);

return NULL;
}
修改 gamelist_find_game_available方法,同上
extern t_game * gamelist_find_game_available(char const * name, t_clienttag ctag, t_game_type type)


{
t_elist *curr;
t_game *game;
t_game_status status;
EnterCriticalSection(&gamelist_section);
elist_for_each(curr,&gamelist_head)

{
game = elist_entry(curr,t_game,glist_link);
status = game->status;

if ((type==game_type_all || game->type==type) && (ctag == game->clienttag) && (game->name)
&& [color=red]
//主要修改部分
((!strcasecmp(name,game->name) || prefix_string(game->name,name))) [/color] && (game->status != game_status_started) &&
(game->status != game_status_done))

{
LeaveCriticalSection(&gamelist_section);
return game;
}
}
LeaveCriticalSection(&gamelist_section);

return NULL;
}
最后說(shuō)明一下,pvpgn要使得顯示游戲人數(shù)這一功能生效,需要在譯編譯宏中加入_SLOTS的定義,或者直接在在hanlde_bnet.cpp最前面,加上
#define _SLOTS。
ok,完成
個(gè)人聯(lián)系方式:
email :kuramawzw@163.com,
qq:370180103
如有問(wèn)題請(qǐng)pm我.