创建游戏内核(25)【完】

创建游戏内核(25)【完】

 

本篇是创建游戏内核(24)的续篇,涉及到的DirectPlay基础知识请参阅使用DirectPlay进行网络互联(4)

 

使用NETWORK_CLIENT处理客户端

可以使用NETWORK_CLIENT类来处理网络的客户端对象,它的使用方法同NETWORK_SERVER对象的使用方法相似,但有一点不同,那就是连接到网络的方法,必须使用NETWORK_CLIENT::connect来建立与服务器端的连接。

来看看类的定义:

typedef  class  NETWORK_CLIENT
{
public :
    NETWORK_CLIENT();
    
virtual  ~NETWORK_CLIENT();

    IDirectPlay8Client* get_client();

    BOOL init();
    BOOL shutdown();

    BOOL connnect(
const  GUID* guid_adapter, 
                  
const   char * server_ip,  long  server_port, 
                  
const   char * player_name,
                  
const   char * session_name,  const   char * session_pwd = NULL);

    BOOL disconnect();
    BOOL is_connected();

    BOOL send_data(
void * data,  ulong  size,  ulong  flags = 0);
    BOOL send_text(
char * text,  ulong  flags = 0);

    BOOL get_local_ip(
char * local_ip);
    
long  get_server_port();
    BOOL get_name(
char * name);
    BOOL get_session_name(
char * session_name);
    BOOL get_session_pwd(
char * session_pwd);

protected :
    
static  HRESULT WINAPI _network_msg_handler(PVOID user_context, DWORD msg_id, PVOID msg_buffer);

    
virtual  BOOL _add_player_to_group(DPNMSG_ADD_PLAYER_TO_GROUP* msg) {  return  TRUE; }
    
virtual  BOOL _async_op_complete(DPNMSG_ASYNC_OP_COMPLETE* msg) {  return  TRUE; }
    
virtual  BOOL _client_info(DPNMSG_CLIENT_INFO* msg) {  return  TRUE; }
    
virtual  BOOL _connect_complete(DPNMSG_CONNECT_COMPLETE* msg) {  return  TRUE; }
    
virtual  BOOL _create_group(DPNMSG_CREATE_GROUP* msg) {  return  TRUE; }
    
virtual  BOOL _create_player(DPNMSG_CREATE_PLAYER* msg) {  return  TRUE; }
    
virtual  BOOL _destroy_group(DPNMSG_DESTROY_GROUP* msg) {  return  TRUE; }
    
virtual  BOOL _destroy_player(DPNMSG_DESTROY_PLAYER* msg) {  return  TRUE; }
    
virtual  BOOL _enum_hosts_query(DPNMSG_ENUM_HOSTS_QUERY* msg) {  return  TRUE; }
    
virtual  BOOL _enum_hosts_response(DPNMSG_ENUM_HOSTS_RESPONSE* msg) {  return  TRUE; }
    
virtual  BOOL _group_info(DPNMSG_GROUP_INFO* msg) {  return  TRUE; }
    
virtual  BOOL _host_migrate(DPNMSG_HOST_MIGRATE* msg) {  return  TRUE; }
    
virtual  BOOL _indicate_connect(DPNMSG_INDICATE_CONNECT* msg) {  return  TRUE; }
    
virtual  BOOL _indicated_connect_aborted(DPNMSG_INDICATED_CONNECT_ABORTED* msg) {  return  TRUE; }
    
virtual  BOOL _peer_info(DPNMSG_PEER_INFO* msg) {  return  TRUE; }
    
virtual  BOOL _receive(DPNMSG_RECEIVE* msg) {  return  TRUE; }
    
virtual  BOOL _remove_player_from_group(DPNMSG_REMOVE_PLAYER_FROM_GROUP* msg) {  return  TRUE; }
    
virtual  BOOL _return_buffer(DPNMSG_RETURN_BUFFER* msg) {  return  TRUE; }
    
virtual  BOOL _send_complete(DPNMSG_SEND_COMPLETE* msg) {  return  TRUE; }
    
virtual  BOOL _server_info(DPNMSG_SERVER_INFO* msg) {  return  TRUE; }
    
virtual  BOOL _terminate_session(DPNMSG_TERMINATE_SESSION* msg) {  return  TRUE; }

protected :
    IDirectPlay8Client* _client;

    BOOL                _is_connected;

    
char                 _server_ip[MAX_PATH];
    
long                 _server_port;

    
char                 _name[MAX_PATH];

    
char                 _session_name[MAX_PATH];
    
char                 _session_pwd[MAX_PATH];    
} *NETWORK_CLIENT_PTR;

实现:
//---------------------------------------------------------------------------------
// Constructor, zero member data.
//---------------------------------------------------------------------------------
NETWORK_CLIENT::NETWORK_CLIENT()
{
    memset(
this , 0,  sizeof (* this )-4);
}

//---------------------------------------------------------------------------------
// Destructor, shutdown this client connection.
//---------------------------------------------------------------------------------
NETWORK_CLIENT::~NETWORK_CLIENT()
{
    shutdown();
}

//---------------------------------------------------------------------------------
// Shutdown this client connection.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::shutdown()
{
    
if (! disconnect())
        
return  FALSE;

    _client = NULL;
    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Disconnet this client to any clients and servers.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::disconnect()
{
    
if (_client)
    {
        
if (FAILED(_client->Close(0)))
            
return  FALSE;
    }
    
    _is_connected    = FALSE;
    _server_port     = 0;
    _server_ip[0]    = 0;
    _name[0]         = 0;
    _session_name[0] = 0;
    _session_pwd[0]  = 0;

    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Return pointer to DirectPlay client object.
//---------------------------------------------------------------------------------
IDirectPlay8Client* NETWORK_CLIENT::get_client()
{
    
return  _client;
}

//---------------------------------------------------------------------------------
// Create DirectPlay client object.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::init()
{
    
// shutdown older connection first
    shutdown();

    
// create the client object
     if (FAILED(CoCreateInstance(CLSID_DirectPlay8Client, NULL, CLSCTX_INPROC, IID_IDirectPlay8Client,
                               (
void **) &_client)))
        
return  FALSE;

    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Connect to server.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::connnect( const  GUID* guid_adapter, 
                              
const   char * server_ip,  long  server_port, 
                              
const   char * player_name, 
                              
const   char * session_name,  const   char * session_pwd)
{
    
// disconnnect older connection first
    disconnect();

    
// error checking
     if (_client == NULL || session_name == NULL || player_name == NULL || server_ip == NULL)
        
return  FALSE;

    
if ((_server_port = server_port) == 0)
        
return  FALSE;

    
// initialize the client object
     if (FAILED(_client->Initialize((PVOID) this , _network_msg_handler, 0)))
        
return  FALSE;

    
// assign client information

    DPN_PLAYER_INFO player_info;
    WCHAR w_player_name[MAX_PATH];

    ZeroMemory(&player_info, 
sizeof (DPN_PLAYER_INFO));

    mbstowcs(w_player_name, player_name, strlen(player_name)+1);

    player_info.dwSize      = 
sizeof (DPN_PLAYER_INFO);
    player_info.dwInfoFlags = DPNINFO_NAME | DPNINFO_DATA;
    player_info.pwszName    = w_player_name;

    _client->SetClientInfo(&player_info, NULL, NULL, DPNSETCLIENTINFO_SYNC);

    
// create address objects

    IDirectPlay8Address* dp_address = NULL;
    IDirectPlay8Address* dp_device  = NULL;

    
if (FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC, IID_IDirectPlay8Address,
                               (
void **) &dp_address)))
        
return  FALSE;

    
if (FAILED(CoCreateInstance(CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC, IID_IDirectPlay8Address,
                               (
void **) &dp_device)))
    {
        dp_address->Release();
        
return  FALSE;
    }

    
// set protocols
    dp_address->SetSP(&CLSID_DP8SP_TCPIP);
    dp_device->SetSP(&CLSID_DP8SP_TCPIP);

    
// set the port - must not be 0
    dp_address->AddComponent(DPNA_KEY_PORT, &_server_port,  sizeof (DWORD), DPNA_DATATYPE_DWORD);    

    WCHAR w_server_ip[MAX_PATH];

    
// set the host ip address
    mbstowcs(w_server_ip, server_ip, strlen(server_ip)+1);
    dp_address->AddComponent(DPNA_KEY_HOSTNAME, w_server_ip, (DWORD) ((wcslen(w_server_ip) + 1) * 
sizeof (WCHAR)),
                             DPNA_DATATYPE_STRING);

    
// set the adapter
    dp_address->AddComponent(DPNA_KEY_DEVICE, guid_adapter,  sizeof (GUID), DPNA_DATATYPE_GUID);
    dp_device->AddComponent(DPNA_KEY_DEVICE, guid_adapter, 
sizeof (GUID), DPNA_DATATYPE_GUID);

    WCHAR w_session_name[MAX_PATH], w_session_pwd[MAX_PATH];

    
// record the session name and password
    strcpy(_session_name, session_name);
    mbstowcs(w_session_name, session_name, MAX_PATH);

    
if (session_pwd)
    {
        strcpy(_session_pwd, session_pwd);
        mbstowcs(w_session_pwd, session_pwd, MAX_PATH);
    }

    
// setup the application description structure

    DPN_APPLICATION_DESC app_desc;

    ZeroMemory(&app_desc, 
sizeof (DPN_APPLICATION_DESC));

    app_desc.dwSize          = 
sizeof (DPN_APPLICATION_DESC);
    app_desc.dwFlags         = DPNSESSION_CLIENT_SERVER;
    app_desc.guidApplication = g_app_guid;
    app_desc.pwszSessionName = w_session_name;

    
if (session_pwd)
    {
        app_desc.pwszPassword = w_session_pwd;
        app_desc.dwFlags |= DPNSESSION_REQUIREPASSWORD;
    }

    DPNHANDLE async_handle;

    BOOL ret_value = TRUE;

    
// connect to server    
    HRESULT rv = _client->Connect(&app_desc, dp_address, dp_device, NULL, NULL, NULL, 0, NULL, &async_handle, 0);

    
if (FAILED(rv))
    {
        ret_value = FALSE;

        
if (rv == DPNERR_HOSTREJECTEDCONNECTION)
            err_msg_box("Host reject connection.");
        
else   if (rv == DPNERR_INVALIDAPPLICATION)
            err_msg_box("The GUID supplied for the application is invalid.");
        
else   if (rv == DPNERR_INVALIDDEVICEADDRESS)
            err_msg_box("The address for the local computer or adapter is invalid.");
        
else   if (rv == DPNERR_INVALIDFLAGS)
            err_msg_box("The flags passed to this method are invalid.");
        
else   if (rv == DPNERR_INVALIDHOSTADDRESS)
            err_msg_box("The specified remote address is invalid.");
        
else   if (rv == DPNERR_INVALIDINSTANCE)
            err_msg_box("The GUID for the application instance is invalid.");
        
else   if (rv == DPNERR_INVALIDINTERFACE)
            err_msg_box("The interface parameter is invalid. This value will be returned in a connect request"
            " if the connecting player was not a client in a client/server game or a peer in a peer-to-peer game.");
        
else   if (rv == DPNERR_INVALIDPASSWORD)        
            err_msg_box("An invalid password was supplied when attempting to join a session that requires a password.");
        
else   if (rv == DPNERR_NOCONNECTION)
            err_msg_box("No communication link was established.");
        
else   if (rv == DPNERR_NOTHOST)
            err_msg_box("An attempt by the client to connect to a nonhost computer.");
        
else   if (rv == DPNERR_SESSIONFULL)
            err_msg_box("The maximum number of players allotted for the session has been reached.");
        
else   if (rv == DPNERR_ALREADYCONNECTED)
            err_msg_box("The object is already connected to the session.");
    }   
    
    dp_address->Release();
    dp_device->Release();
    
return  ret_value;
}

//---------------------------------------------------------------------------------
// Judge whether client has connected to server.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::is_connected()
{
    
return  _is_connected;
}

//---------------------------------------------------------------------------------
// Send data to server.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::send_data( void * data,  ulong  size,  ulong  flags)
{
    
// error checking
     if (_client == NULL)
        
return  FALSE;

    
// build a data structure

    DPN_BUFFER_DESC buffer_desc;

    buffer_desc.dwBufferSize = size;
    buffer_desc.pBufferData  = (BYTE*) data;

    DPNHANDLE async_handle;

    
if (FAILED(_client->Send(&buffer_desc, 1, 0, NULL, &async_handle, flags)))
        
return  FALSE;

    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Send text to server.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::send_text( char * text,  ulong  flags)
{
    
// error checking
     if (_client == NULL || text == NULL)
        
return  FALSE;

    
return  send_data(text, ( ulong )strlen(text) + 1, flags);
}

//---------------------------------------------------------------------------------
// Get local ip address.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::get_local_ip( char * local_ip)
{
    WSADATA wsa_data;

    
if (WSAStartup(MAKEWORD(1, 0), &wsa_data))
        
return  FALSE;

    
char  local_name[MAX_PATH];
    gethostname(local_name, MAX_PATH);

    HOSTENT* host_ent;

    
if ((host_ent = gethostbyname(local_name)) == NULL)
    {
        WSACleanup();
        
return  FALSE;
    }

    
char * ip_addr = inet_ntoa(*((in_addr*) host_ent->h_addr_list[0]));
    
    WSACleanup();

    
if (ip_addr == NULL)
        
return  FALSE;

    strcpy(local_ip, ip_addr);

    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Return port which used to connect to server.
//---------------------------------------------------------------------------------
long  NETWORK_CLIENT::get_server_port()
{
    
return  _server_port;
}


//---------------------------------------------------------------------------------
// Return name.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::get_name( char * name)
{
    
if (name == NULL)
        
return  FALSE;

    strcpy(name, _name);
    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Get session name.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::get_session_name( char * session_name)
{
    
if (session_name == NULL)
        
return  FALSE;

    strcpy(session_name, _session_name);
    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Get session password.
//---------------------------------------------------------------------------------
BOOL NETWORK_CLIENT::get_session_pwd( char * session_pwd)
{
    
if (session_pwd == NULL)
        
return  FALSE;

    strcpy(session_pwd, _session_pwd);
    
return  TRUE;
}

//---------------------------------------------------------------------------------
// Message handler.
//---------------------------------------------------------------------------------
HRESULT WINAPI NETWORK_CLIENT::_network_msg_handler(PVOID user_context, DWORD msg_id, PVOID msg_buffer)
{
    NETWORK_CLIENT_PTR client;
    DPNMSG_CONNECT_COMPLETE* msg_connect_complte;

    
if ((client = (NETWORK_CLIENT_PTR) user_context) == NULL)
        
return  E_FAIL;

    
switch (msg_id)
    {
    
case  DPN_MSGID_ADD_PLAYER_TO_GROUP:
      
if (client->_add_player_to_group((DPNMSG_ADD_PLAYER_TO_GROUP*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_ASYNC_OP_COMPLETE:
      
if (client->_async_op_complete((DPNMSG_ASYNC_OP_COMPLETE*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_CLIENT_INFO:
      
if (client->_client_info((DPNMSG_CLIENT_INFO*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_CONNECT_COMPLETE:
        
// update connection information

        msg_connect_complte = (DPNMSG_CONNECT_COMPLETE*) msg_buffer;

        
if (msg_connect_complte->hResultCode == S_OK)
            client->_is_connected = TRUE;

        
if (client->_connect_complete((DPNMSG_CONNECT_COMPLETE*) msg_buffer))
            
return  S_OK;

        
break ;

    
case  DPN_MSGID_CREATE_GROUP:
      
if (client->_create_group((DPNMSG_CREATE_GROUP*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_CREATE_PLAYER:
      
if (client->_create_player((DPNMSG_CREATE_PLAYER*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_DESTROY_GROUP:
      
if (client->_destroy_group((DPNMSG_DESTROY_GROUP*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_DESTROY_PLAYER:
      
if (client->_destroy_player((DPNMSG_DESTROY_PLAYER*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_ENUM_HOSTS_QUERY:
      
if (client->_enum_hosts_query((DPNMSG_ENUM_HOSTS_QUERY*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_ENUM_HOSTS_RESPONSE:
      
if (client->_enum_hosts_response((DPNMSG_ENUM_HOSTS_RESPONSE*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_GROUP_INFO:
      
if (client->_group_info((DPNMSG_GROUP_INFO*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_HOST_MIGRATE:
      
if (client->_host_migrate((DPNMSG_HOST_MIGRATE*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_INDICATE_CONNECT:
      
if (client->_indicate_connect((DPNMSG_INDICATE_CONNECT*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_INDICATED_CONNECT_ABORTED:
      
if (client->_indicated_connect_aborted((DPNMSG_INDICATED_CONNECT_ABORTED*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_PEER_INFO:
      
if (client->_peer_info((DPNMSG_PEER_INFO*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_RECEIVE:
      
if (client->_receive((DPNMSG_RECEIVE*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_REMOVE_PLAYER_FROM_GROUP:
      
if (client->_remove_player_from_group((DPNMSG_REMOVE_PLAYER_FROM_GROUP*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_RETURN_BUFFER:
      
if (client->_return_buffer((DPNMSG_RETURN_BUFFER*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_SEND_COMPLETE:
      
if (client->_send_complete((DPNMSG_SEND_COMPLETE*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_SERVER_INFO:
      
if (client->_server_info((DPNMSG_SERVER_INFO*) msg_buffer))
        
return  S_OK;
      
break ;

    
case  DPN_MSGID_TERMINATE_SESSION:
      client->_is_connected = FALSE;
      
if (client->_terminate_session((DPNMSG_TERMINATE_SESSION*) msg_buffer))
        
return  S_OK;
      
break ;
    }

    
return  E_FAIL;
}

测试代码:
/********************************************************************************
PURPOSE:
    Test for class NETWORK_CLIENT.
********************************************************************************/


#include "Core_Global.h"

#define  HOST_PORT   12345

class  CLIENT :  public  NETWORK_CLIENT
{
public :
    CLIENT()
    {
        _is_connect_complete = FALSE;
    }

    BOOL connect_complete()
    {
        
return  _is_connect_complete;
    }

private :
    
virtual  BOOL _receive(DPNMSG_RECEIVE* msg)
    {
        MessageBox(NULL, LPCSTR(msg->pReceiveData), "server message", MB_OK);
        
        
return  TRUE;
    }

    
virtual  BOOL _connect_complete(DPNMSG_CONNECT_COMPLETE* Msg)
    {
        _is_connect_complete = TRUE;

        
return  TRUE;
    }

private :
    BOOL _is_connect_complete;
};

class  APP :  public  APPLICATION
{
public :
    BOOL init()
    {
        
if (! _adapter.init())
            
return  FALSE;

        
// get first adapter guid
        GUID* guid_adapter = _adapter.get_guid(0);

        
if (! _client.init())
            
return  FALSE;

        
if (! _client.connnect(guid_adapter, "127.0.0.1", HOST_PORT, "lovedday", "test_session"))
            
return  FALSE;

        
while (! _client.connect_complete())
            ;

        
if (! _client.send_text("Hi, how are you?"))
            
return  FALSE;

        
return  TRUE;
    }

    BOOL frame()
    {
        Sleep(300);

        
return  TRUE;
    }

    BOOL shutdown()
    {
        
return  TRUE;
    }

private :
    CLIENT _client;
    NETWORK_ADAPTER _adapter;
};

int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line,  int  cmd_show)
{
    APP app;

    
return  app.run();
}

你可能感兴趣的:(创建游戏内核(25)【完】)