Ghost自动主机在游戏名字中显示当前加入游戏的人数!

Ghost自动主机在游戏名字中显示当前加入游戏的人数!

 

一般用Ghost主机游戏名字XXXXX #2,当此我想显示当前加入游戏中的人数,例如Dota,XXXXX #2(2/10),表示当前有2个人加入.

首先对于战网PVPGN不支持修改游戏名字,因此我还修改pvpgn,使得支持修改游戏名字,闲话少说,先看一下我的效果。
Ghost自动主机在游戏名字中显示当前加入游戏的人数!_第1张图片

(在http://cid-4b5bdf2f7fd33dee.office.live.com/browse.aspx/pvpgn,可以下载我win32 x86环境下编译好的ghostcb,pvpgn1.99)
下面开始开工了
修改ghost
(1)下载ghost源码了http://www.codelain.com/forum/index.php?topic=13083.0
(2)bnet.h中,修改函数QueueGameRefresh,这个方法用于游戏创建,游戏更新的,我在这方法加入一个参数,player_num:游戏人数
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)";//在游戏名字中显示人数
           //下面的就不用改了

(3)game_base.cpp中,修改函数   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 传入参数当前加入游戏的人数
                (*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中,函数CBaseGame :: EventPlayerJoined和函数CBaseGame :: EventPlayerLeft的末尾添加以下代码,即当有玩家加入或者退出游戏时,更新游戏名字

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的源码包

pvpgn-199.r577.tar.gz
http://pvpgn.berlios.de/index.php?page=files
至于pvpgn的编译,我用的vs平台,在pvpgn包内doc文件夹下有个编译方法,还是比较麻烦的,在这里我就不多说了,网上也有文章说编译1.99的 http://yjfyy.spaces.live.com/blog/cns!B6AD95965E3A9326!550.entry()
(2)在game.h里添加一个修改游戏名字的方法申明,
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);


         添加一个CRITICAL_SECTION 临界区变量(注这个只是在windows下的,对于linux可以linux下互斥变量替换),用于多线程game_list的互斥访问。在这里只是申明,至于定义和初始化,我把它放在winmain.cpp中,这个在后面我再细讲

#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

 在这里说明一下,为什么 要用_USE_SECTION。
若直接在game.h不用#ifdef _USE_SECTION,那不就省事了。
事实上这么弄会出很多编译错误,主要就是 windows.h惹的祸,因为这样别的地方#include  "game.h",把windows.h也包含去了,会发生很多编译错误。
      添加 game_set_name函数的定义
   

extern   void  game_set_name(t_game  *  game, const   char   *  name)
{
    EnterCriticalSection(
&gamelist_section);//临界区,互斥访问,以免产生读写冲突
    
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函数中添加 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)准备工作已经做好了,现在就可以更新游戏名字了
static int _client_startgame4(t_connection * c, t_packet const *const packet)这个方法用于处理游戏建立以及游戏更新,我们就在这个方法里面更新游戏名字
hanlde_bnet.cpp中static int _client_startgame4(t_connection * c, t_packet const *const packet)函数加入一行代码

 

if  ((currgame  =  conn_get_game(c)))  {
#ifdef _SLOTS
        
//update the game name  ########加入这行,要使得这个生效,在编译宏中加入_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) 至此因该基本完成,不过还有一个bug,处理pvpgan服务端与客户端游戏更新不一致的情况
例如服务端游戏名字是XXXXX #1(1/10),而客户端没有及时更新游戏列表,XXXXX #1(0/10),此时客户端加入游戏时,就会出错. 修改gamelist_find_game方法,修改游戏名字查找游戏方法,我只匹配'('前面的部分,XXXXX #1(1/10)与XXXXX #1(0/10)认为是同一个游戏。
  添加一个游戏名字匹配的辅助方法,这个只在game.cpp中添加就可以了,为内部函数。

     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;
    //临界区
    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
        
&& 
           //主要修改部分,游戏名字不一致时,只匹配(前面的部分
           (!
strcasecmp(name,game->name) || prefix_string(game->name,name))) 
        
{
            LeaveCriticalSection(
&gamelist_section);
            
return game;
        }

    }
     //退出临界区
    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;
}


   最后说明一下,pvpgn要使得显示游戏人数这一功能生效,需要在译编译宏中加入_SLOTS的定义,或者直接在在hanlde_bnet.cpp最前面,加上
#define _SLOTS。
    
   ok,完成


个人联系方式:
email :[email protected]
qq:370180103
如有问题请pm我.






 

你可能感兴趣的:(Ghost自动主机在游戏名字中显示当前加入游戏的人数!)