The Multiplayer Games Dialog Box

[Previous] [Next]

Once the user has chosen a connection type, the next dialog box is shown. In this dialog box, you can either create a new game session or enumerate the existing game sessions and join one of them. This dialog box is controlled by the DPConnect_SessionsDlgProc function.

If the user indicates that he wants to see the available sessions (by clicking the Start Search button), DPConnect_SessionsDlgProc uses the function DPConnect_SessionsDlgShowGames to enumerate the available sessions (via IDirectPlay4::EnumSessions) and to add their names to the list box in the Multiplayer Games dialog box. The list is recomputed continuously to account for sessions being created, so a timer is used to periodically call DPConnect_SessionsDlgShowGames and update the list. Here's the declaration for EnumSessions:

 HRESULT EnumSessions (     LPDPSESSIONDESC2 lpsd,     DWORD dwTimeout,      LPDPENUMSESSIONSCALLBACK2 lpEnumSessionsCallback2,      LPVOID lpContext,      DWORD dwFlags  ); 

ParameterDescription
lpsd Pointer to the DPSESSIONDESC2 structure describing the sessions to be enumerated. Only sessions that meet the criteria set in this structure will be enumerated. You can set the guidApplication member to the GUID of an application that interests you if you know it, or you can set this member to GUID_NULL to obtain all sessions. You need the lpszPassword member only if you want private sessions. All data members other than guidApplication and lpszPassword are ignored.
dwTimeout In the asynchronous case, dwTimeout is the interval (in milliseconds) by which DirectPlay will broadcast enumeration requests to update the internal sessions list. If the time-out is set to 0, a default time-out appropriate for the service provider and connection type will be used. I recommend that you set this value to 0. The application can determine this time-out by calling IDirectPlay4::GetCaps and examining the dwTimeout data member of the DPCAPS structure.
lpEnumSessionsCallback2 Pointer to the application-supplied EnumSessionsCallback2 function to be called for each DirectPlay session that's responding.
lpContext Pointer to a user-defined context that's passed to each enumeration callback.
dwFlags The default is 0, which is equivalent to DPENUMSESSIONS_AVAILABLE. When enumerating sessions with DPENUMSESSIONS_ALL or DPENUMSESSIONS_PASSWORDREQUIRED, the application must know which sessions cannot be joined and which sessions are password protected so that it can warn the user or prompt for a password.

The possible values for the dwFlags parameter are:

DPENUMSESSIONS_ALL Enumerates all active sessions, whether or not they're accepting new players. Sessions in which the player limit has been reached, new players have been disabled, or joining has been disabled will be enumerated. Password-protected sessions won't be enumerated unless the DPENUMSESSIONS_PASSWORDREQUIRED flag is also specified. If DPENUMSESSIONS_ALL isn't specified, DPENUMSESSIONS_AVAILABLE is assumed.

DPENUMSESSIONS_ASYNC Enumerates the current sessions in the session cache and returns immediately. Starts the asynchronous enumeration process if it hasn't already begun. Updates to the session list continue until canceled by calling EnumSessions with the DPENUMSESSIONS_STOPASYNC flag, or by calling Open or Release. If this flag isn't specified, the enumeration is performed synchronously.

DPENUMSESSIONS_AVAILABLE Enumerates all sessions that are accepting new players to join. Sessions that have reached their maximum number of players, have disabled new players, or have disabled joining won't be enumerated. Password-protected sessions won't be enumerated unless the DPENUMSESSIONS_PASSWORDREQUIRED flag is also specified.

DPENUMSESSIONS_PASSWORDREQUIRED When combined with either the DPENUMSESSIONS_AVAILABLE or DPENUMSESSIONS_ALL flag, this flag allows password-protected sessions as well as sessions without password protection to be enumerated. If this flag isn't specified, no password-protected sessions will be returned.

DPENUMSESSIONS_RETURNSTATUS If this flag is specified, the enumeration won't display any dialog boxes showing the connection progress status. If the connection cannot be made immediately, the method will return with the DPERR_CONNECTING error. The application must keep calling EnumSessions until DP_OK returns, indicating successful completion, or until another error code returns, indicating an error.

DPENUMSESSIONS_STOPASYNC Enumerates all the current sessions in the session cache and cancels the asynchronous enumeration process.

When IDirectPlay4::EnumSessions is called for the first time, the Locate Session dialog box (shown in Figure 15-3) appears. The appearance of this dialog box varies based on the connection type. For the TCP/IP connection type, users can type the computer name or the IP address of the session host they want in the Locate Session dialog box; otherwise, they can leave this dialog box blank and search for other sessions to join.

Figure 15-3 The Locate Session dialog box

If the user selects a session in the list box, the code attempts to keep the session selected (if one was selected previously) unless it ends and therefore disappears.

If the user selects a session and clicks the Join button, the DPConnect_SessionsDlgJoinGame function is called. Here's the definition of this routine:

 //------------------------------------------------------------------- // Name: DPConnect_SessionsDlgJoinGame // Desc: Joins the selected DirectPlay session //------------------------------------------------------------------- HRESULT DPConnect_SessionsDlgJoinGame( HWND hDlg ) {     DPSESSIONDESC2 dpsd;     DPNAME         dpname;     HRESULT        hr;     HWND           hWndListBox = GetDlgItem( hDlg, IDC_GAMES_LIST );     DPSessionInfo* pDPSISelected = NULL;     int            nItemSelected;     char           buffer[256];     nItemSelected = SendMessage( hWndListBox, LB_GETCURSEL, 0, 0 );          // Add status text in the list box.     pDPSISelected = (DPSessionInfo*) SendMessage( hWndListBox,                                                    LB_GETITEMDATA,                                                    nItemSelected, 0 );     if( NULL == pDPSISelected )     {         MessageBox( hDlg, TEXT("There are no games to join."),                     TEXT("DirectPlay Sample"), MB_OK );         return S_OK;     }     // Set up the DPSESSIONDESC2 and get the session GUID from      // the selected list box item.     ZeroMemory( &dpsd, sizeof(dpsd) );     dpsd.dwSize          = sizeof(dpsd);     dpsd.guidInstance    = pDPSISelected->guidSession;     dpsd.guidApplication = g_AppGUID;     // Join the session.     g_bHostPlayer = FALSE;     if( FAILED( hr = g_pDP->Open( &dpsd, DPOPEN_JOIN ) ) )         return hr;     // Create player based on g_strLocalPlayerName.       // Store the player's DPID in g_LocalPlayerDPID.     // All DirectPlay messages for this player will signal      // g_hDPMessageEvent.     ZeroMemory( &dpname, sizeof(DPNAME) );     dpname.dwSize         = sizeof(DPNAME);     dpname.lpszShortNameA = g_strLocalPlayerName;          if( FAILED( hr = g_pDP->CreatePlayer( &g_LocalPlayerDPID,                                           &dpname,                                            g_hDPMessageEvent, NULL,                                           0, 0)))         return hr;     pCMyApp->MyRRnetID = g_LocalPlayerDPID;     itoa((int)pCMyApp->MyRRnetID, buffer, 10);     PrintMessage(NULL, "Direct Play : Joined game", NULL, NULL);     PrintMessage(NULL, "Player's dpid : ",                  dpname.lpszShortNameA, NULL);     PrintMessage(NULL, "MyRRnetID     : ", buffer, NULL);     pCMyApp->multiplay_flag = TRUE;     // DirectPlay connect successful, so end dialog.     EndDialog( hDlg, EXITCODE_FORWARD );     return S_OK; } 

In this routine, as long as there's a game to join, you can set up a DPSESSIONDESC2 structure and get the session GUID the user selected from the list. You can then call the IDirectPlay4::Open method with the DPOPEN_JOIN flag to join a session that was enumerated by your previous call to IDirectPlay4::EnumSessions. Here's the declaration for the IDirectPlay4::Open method:

 HRESULT  Open(     LPDPSESSIONDESC2 lpsd     DWORD dwFlags ); 

The Open method has the following parameters.

lpsd Pointer to the DPSESSIONDESC2 structure that describes the session the user is creating or joining. If the user is joining a session, you need to specify only the dwSize, guidInstance, and lpszPassword data members. You need to supply a password only if the enumerated session had the DPSESSION_PASSWORD flag set.

If the user is creating a session, the application must completely fill the DPSESSIONDESC2 structure with the properties of the sessions to be created. DirectPlay will generate the guidInstance data member.

dwFlags You can use only one of the following flags:

  • DPOPEN_CREATE Create a new instance of an application session. The local computer will be the name server and host of the session.
  • DPOPEN_JOIN Join an existing instance of an application session for the purpose of participating. The application will be able to create players and send and receive messages.
  • DPOPEN_RETURNSTATUS If this flag is specified, the method won't display any dialog boxes showing the connection progress status. If the connection cannot be made immediately, the method will return with the DPERR_CONNECTING error. The application must keep calling Open until either DP_OK returns, indicating successful completion, or an error code returns.

Finally, DPConnect_SessionsDlgJoinGame creates a local player for the current session based on the name in the g_strLocalPlayerName variable. By passing the g_hDPMessageEvent value as the third argument to IDirectPlay::CreatePlayer, it indicates that all the DirectPlay messages for this player will signal g_hDPMessageEvent. Here's the declaration for the IDirectPlay4::CreatePlayer routine:

 HRESULT  CreatePlayer(     LPDPID lpidPlayer,     LPDPNAME lpPlayerName,     HANDLE hEvent,     LPVOID lpData,     DWORD dwDataSize,     DWORD dwFlags ); 

ParameterDescription
lpidPlayer Pointer to a variable that the DirectPlay player ID will fill. DirectPlay defines this value.
lpPlayerName Pointer to a DPNAME structure that holds the name of the player. NULL indicates that the player has no initial name information. The name in lpPlayerName is provided for the player's use only; it isn't used internally and doesn't need to be unique.
hEvent An event object created by the application that DirectPlay will signal when it receives a message addressed to the player.
lpData Pointer to a block of application-defined data to associate with the player ID. NULL indicates that the player has no initial data. The data specified in this parameter is assumed to be remote data that will be propagated to all the other applications in the session, as if IDirectPlay4::SetPlayerData had been called.
dwDataSize Size, in bytes, of the data block that lpData points to.
dwFlags Flags indicating what type of player is currently using the game. The default (0) is a nonspectator, nonserver player. These flags are available:

DPPLAYER_SERVERPLAYER The player is a server player for client/server communications. Only the host can create a server player. Only one server player can exist in a session. If this flag is specified, CreatePlayer will always return a player ID of DPID_SERVERPLAYER.

DPPLAYER_SPECTATOR The player is created as a spectator. A spectator player behaves exactly as a normal player except that the player is flagged as a spectator. The application can then limit what a spectator player can do. The application completely defines the behavior of a spectator player. DirectPlay simply propagates this flag.

If the user clicks the Create Game button, the code calls the DPConnect_SessionsDlgCreateGame routine to attempt to create a new game and initialize the player data. Here's the code for this routine:

 //------------------------------------------------------------------- // Name: DPConnect_SessionsDlgCreateGame // Desc: Asks the user the session name and creates a new DirectPlay //       session //------------------------------------------------------------------- HRESULT DPConnect_SessionsDlgCreateGame( HWND hDlg ) {     DPSESSIONDESC2 dpsd;     DPNAME         dpname;     HRESULT        hr;     int            nResult;      HINSTANCE      hInst;     FILE *fp;     hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );     // Display a modal Multiplayer Connect dialog box.     EnableWindow( hDlg, FALSE );      nResult = DialogBox( hInst,                          MAKEINTRESOURCE(IDD_MULTIPLAYER_CREATE),                           hDlg, DPConnect_CreateSessionDlgProc );     EnableWindow( hDlg, TRUE );      if( nResult == IDCANCEL )         return S_OK;     // Set up the DPSESSIONDESC2 based on g_AppGUID, and      // g_strSessionName. The DPSESSION_KEEPALIVE flag keeps      // the session alive if players exit abnormally.     ZeroMemory( &dpsd, sizeof(dpsd) );     dpsd.dwSize           = sizeof(dpsd);     dpsd.guidApplication  = g_AppGUID;     dpsd.lpszSessionNameA = g_strSessionName;     dpsd.dwMaxPlayers     = 10;     dpsd.dwFlags          = DPSESSION_KEEPALIVE |                             DPSESSION_MIGRATEHOST;     if( g_bUseProtocol )         dpsd.dwFlags |= DPSESSION_DIRECTPLAYPROTOCOL;     // Create a new session.     g_bHostPlayer = TRUE;     if( FAILED( hr = g_pDP->Open( &dpsd, DPOPEN_CREATE ) ) )         return hr;     // Create a player based on g_strLocalPlayerName.       // Store the player's DPID in g_LocalPlayerDPID.     // All DirectPlay messages for this player will signal      // g_hDPMessageEvent.     ZeroMemory( &dpname, sizeof(DPNAME) );     dpname.dwSize         = sizeof(DPNAME);     dpname.lpszShortNameA = g_strLocalPlayerName;      // Create the player.     if( FAILED( hr = g_pDP->CreatePlayer( &g_LocalPlayerDPID,                                           &dpname,                                           g_hDPMessageEvent, NULL, 0,                                           DPPLAYER_SERVERPLAYER ) ) )         return hr;     // Initialize the player data.     pCMyApp->num_players = 0;     pCMyApp->MyRRnetID = g_LocalPlayerDPID;     pCMyApp->player_list[pCMyApp->num_players].x = 600;     pCMyApp->player_list[pCMyApp->num_players].y = 12;     pCMyApp->player_list[pCMyApp->num_players].z = 500;     pCMyApp->player_list[pCMyApp->num_players].rot_angle = 0;     pCMyApp->player_list[pCMyApp->num_players].model_id = 0;     pCMyApp->player_list[pCMyApp->num_players].skin_tex_id = 0;     pCMyApp->player_list[pCMyApp->num_players].current_weapon = 0;     pCMyApp->player_list[pCMyApp->num_players].current_car = 0;     pCMyApp->player_list[pCMyApp->num_players].current_frame = 0;     pCMyApp->player_list[pCMyApp->num_players].current_sequence = 0;     pCMyApp->         player_list[pCMyApp->num_players].bIsPlayerInWalkMode = TRUE;     pCMyApp->         player_list[pCMyApp->num_players].RRnetID = g_LocalPlayerDPID;     pCMyApp->player_list[pCMyApp->num_players].bIsPlayerValid = TRUE;     pCMyApp->num_players++;          if(dpname.lpszShortNameA == NULL)         strcpy(pCMyApp->player_list[0].name, "no name");     else         strcpy(pCMyApp->player_list[0].name, dpname.lpszShortNameA);     // Enter information into the log file.     fp = fopen("rrlogfile.txt","a");     fprintf( fp, "Direct Play : Created game\n");     fprintf( fp, "Player's name  : %s\n",              pCMyApp->player_list[0].name);     fprintf( fp, "Player's dpid  : %d\n",              pCMyApp->player_list[0].RRnetID);     fprintf( fp, "MyRRnetID      : %d\n", pCMyApp->MyRRnetID);     fprintf( fp, "---------------\n\n");     fclose(fp);     pCMyApp->multiplay_flag = TRUE;     // DirectPlay connect successful, so end dialog.     EndDialog( hDlg, EXITCODE_FORWARD );     return S_OK; } 

This code presents a dialog box in which the user enters a name for the session and specifies whether or not to use the DirectPlay protocol, which provides guaranteed messaging even if the service provider is designed for unguaranteed messaging. The dialog box is shown in Figure 15-4.

Figure 15-4 The Create Game dialog box

Once this dialog box has been dismissed, IDirectPlay4::Open is called with the DPOPEN_CREATE flag to create the session. And finally, a player is created, just as it was in the DPConnect_SessionsDlgJoinGame function.

As you can see, getting into a DirectPlay session takes several steps and can involve a lot of interaction with the user. The code in dpconnect.cpp is great either to use in your program or just to study to understand how this process works.



Inside Direct3D
Inside Direct3D (Dv-Mps Inside)
ISBN: 0735606137
EAN: 2147483647
Year: 1999
Pages: 131

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net