Getting Online with Multiplayer Gaming(17)

Getting Online with Multiplayer Gaming(17)

 

Message Handling

The client application uses the same message structures as the server, but the client
has no need for queuing messages. As Figure 19.16 demonstrates, incoming messages
are immediately parsed by the client.

Getting Online with Multiplayer Gaming(17)_第1张图片

Now that you’ve seen the receive function that handles incoming message, it’s time
to examine each message handling function.

 

cApp::create_player

As clients join the game, the server informs other connected clients of those new
arrivals. The purpose of the following create_player function is to find room in the
sPlayer structure and store the player data:

void  cApp::create_player( const  sMsg* msg)
{
    sCreatePlayerMsg* create_msg = (sCreatePlayerMsg*) msg;

    
// do not add local player to list
     if (create_msg->header.player_id == m_players[0].player_id)
        
return ;

    
long  player_index = -1;

    
for ( long  i = 1; i < MAX_PLAYERS; i++)
    {
        
if (m_players[i].connected)
        {
            
// makre sure player not already in list
             if (m_players[i].player_id == create_msg->header.player_id)
                
return ;
        }
        
else
            player_index = i;
    }

    
if (player_index == -1)   // no open slots
         return ;

    EnterCriticalSection(&m_update_cs);

    
// add player data
    m_players[player_index].connected  =  true ;
    m_players[player_index].player_id  = create_msg->header.player_id;
    m_players[player_index].x_pos      = create_msg->x_pos;
    m_players[player_index].y_pos      = create_msg->y_pos;
    m_players[player_index].z_pos      = create_msg->z_pos;
    m_players[player_index].direction  = create_msg->direction;
    m_players[player_index].speed      = 0.0f;
    m_players[player_index].last_state = STATE_IDLE;

    m_num_players++;

    LeaveCriticalSection(&m_update_cs);
}

 

cApp::destroy_player

The server notifies clients when a player is leaving a session. The clients, in turn,
signal the player as being disconnected and skips updating the player during the
update cycle. The following code determines which client is disconnected and
takes the appropriate steps:

void  cApp::destroy_player( const  sMsg* msg)
{
    sDestroyPlayerMsg* destroy_msg = (sDestroyPlayerMsg*) msg;

    
// do not remove local player from list
     if (destroy_msg->header.player_id == m_players[0].player_id)
        
return ;

    
long  player_index = get_player_index(destroy_msg->header.player_id);
    
if (player_index == -1)
        
return ;

    EnterCriticalSection(&m_update_cs);

    m_players[player_index].connected = 
false ;
    m_num_players--;

    LeaveCriticalSection(&m_update_cs);
}
 

cApp::change_player_state

The client processes changes of state in players by pulling out the message data and
putting it in the player’s structure. If a player isn’t found in the list of players, the
client requests that player’s information via a MSG_GET_PLAYER_INFO message and exits the
change_player_state function without further ado.

This is the only situation in which a player’s coordinates can be directly modified
by a state change—clients are not allowed to make direct changes to their coordinates
(to avoid cheating), so it’s up to the server to tell players just where they are
in the world during the updates:

void  cApp::change_player_state( const  sMsg* msg)
{
    sStateChangeMsg* change_msg = (sStateChangeMsg*) msg;

    
long  player_index = get_player_index(change_msg->header.player_id);

    
if (player_index == -1)   // unknown player - request information
    {
        sRequestPlayerInfoMsg request_msg;

        request_msg.header.type       = MSG_GET_PLAYER_INFO;
        request_msg.header.size       = 
sizeof (sRequestPlayerInfoMsg);
        request_msg.header.player_id  = m_players[0].player_id;
        request_msg.request_player_id = change_msg->header.player_id;

        send_network_msg(&request_msg, DPNSEND_NOLOOPBACK);
        
return ;
    }

    EnterCriticalSection(&m_update_cs);

    
// store new player state information
    m_players[player_index].last_state = change_msg->state;
    m_players[player_index].x_pos      = change_msg->x_pos;
    m_players[player_index].y_pos      = change_msg->y_pos;
    m_players[player_index].z_pos      = change_msg->z_pos;
    m_players[player_index].direction  = change_msg->direction;
    m_players[player_index].speed      = change_msg->speed;
    m_players[player_index].latency    = change_msg->latency;

    
// bounds latency to 1 second
     if (m_players[player_index].latency > 1000)
        m_players[player_index].latency = 1000;

    
// adjust time based on latency
    m_players[player_index].last_update_time = timeGetTime() - m_players[player_index].latency;

    LeaveCriticalSection(&m_update_cs);
}

///////////////////////////////////////////////////////////////////////////////////////////// /

bool  cApp::send_network_msg( void * msg,  long  send_flags)
{
    sMsgHeader* header = (sMsgHeader*) msg;

    
if (header->size == 0)
        
return   false ;

    
return  m_client.send_data(msg, header->size, send_flags);
}

Just like the server, the client has a send_network_msg to send the game-related
network messages to the server.

NOTE
The client also depends on the latency time to modify
the timing calculations.The server sends this latency
time to the client, but to make things safe, the client
application is allowed to cut the latency down to one
second if the server states that it is higher.


你可能感兴趣的:(Getting Online with Multiplayer Gaming(17))