home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Game Programming for Teens / VBGPFT.cdr / DirectX8 / dx8a_sdk.exe / samples / multimedia / directplay / simpleclientserver / simpleserver / simpleserver.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-11-04  |  24.6 KB  |  684 lines

  1. //----------------------------------------------------------------------------
  2. // File: SimpleServer.cpp
  3. //
  4. // Desc: 
  5. //
  6. // Copyright (c) 1999-2000 Microsoft Corp. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #define STRICT
  9. #include <windows.h>
  10. #include <basetsd.h>
  11. #include <dplay8.h>
  12. #include <dpaddr.h>
  13. #include <dxerr8.h>
  14. #include "SimpleClientServer.h"
  15. #include "DXUtil.h"
  16. #include "resource.h"
  17.  
  18.  
  19.  
  20.  
  21. //-----------------------------------------------------------------------------
  22. // Player context locking defines
  23. //-----------------------------------------------------------------------------
  24. CRITICAL_SECTION g_csPlayerContext;
  25. #define PLAYER_LOCK()                   EnterCriticalSection( &g_csPlayerContext ); 
  26. #define PLAYER_ADDREF( pPlayerInfo )    if( pPlayerInfo ) pPlayerInfo->lRefCount++;
  27. #define PLAYER_RELEASE( pPlayerInfo )   if( pPlayerInfo ) { pPlayerInfo->lRefCount--; if( pPlayerInfo->lRefCount <= 0 ) SAFE_DELETE( pPlayerInfo ); } pPlayerInfo = NULL;
  28. #define PLAYER_UNLOCK()                 LeaveCriticalSection( &g_csPlayerContext );
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // Defines, and constants
  33. //-----------------------------------------------------------------------------
  34. #define SIMPLESERVER_DEFAULT_PORT           0x6501 // arbitrary port number for this app
  35.  
  36. struct APP_PLAYER_INFO
  37. {
  38.     LONG  lRefCount;                        // Ref count so we can cleanup when all threads 
  39.                                             // are done w/ this object
  40.     DPNID dpnidPlayer;                      // DPNID of player
  41.     TCHAR strPlayerName[MAX_PLAYER_NAME];   // Player name
  42. };
  43.  
  44.  
  45.  
  46.  
  47. //-----------------------------------------------------------------------------
  48. // Global variables
  49. //-----------------------------------------------------------------------------
  50. IDirectPlay8Server* g_pDPServer                  = NULL;    // DirectPlay server object
  51. HINSTANCE          g_hInst                       = NULL;    // HINST of app
  52. HWND               g_hDlg                        = NULL;    // HWND of main dialog
  53. LONG               g_lNumberOfActivePlayers      = 0;       // Number of players currently in game
  54. TCHAR              g_strAppName[256]             = TEXT("SimpleServer");
  55. TCHAR              g_strSessionName[MAX_PATH];              // Session name
  56. DWORD              g_dwPort;                                // Port
  57. HRESULT            g_hrDialog;                              // Exit code for app 
  58. BOOL               g_bServerStarted              = FALSE;   // TRUE if the server has started
  59.  
  60.  
  61.  
  62.  
  63. //-----------------------------------------------------------------------------
  64. // Function-prototypes
  65. //-----------------------------------------------------------------------------
  66. HRESULT WINAPI   DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
  67. INT_PTR CALLBACK ServerDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  68. HRESULT  StartServer( HWND hDlg );
  69. VOID     StopServer( HWND hDlg );
  70. VOID     DisplayPlayers( HWND hDlg );
  71. HRESULT  SendCreatePlayerMsg( APP_PLAYER_INFO* pPlayerInfo, DPNID dpnidTarget );
  72. HRESULT  SendWorldStateToNewPlayer( DPNID dpnidPlayer );
  73. HRESULT  SendDestroyPlayerMsgToAll( APP_PLAYER_INFO* pPlayerInfo );
  74. HRESULT  SendWaveMessageToAll( DPNID dpnidFrom );
  75.  
  76.  
  77.  
  78.  
  79.  
  80. //-----------------------------------------------------------------------------
  81. // Name: WinMain()
  82. // Desc: Entry point for the application.  Since we use a simple dialog for 
  83. //       user interaction we don't need to pump messages.
  84. //-----------------------------------------------------------------------------
  85. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, 
  86.                       LPSTR pCmdLine, INT nCmdShow )
  87. {
  88.     HKEY    hDPlaySampleRegKey;
  89.     BOOL    bConnectSuccess = FALSE;
  90.  
  91.     g_hInst = hInst; 
  92.     InitializeCriticalSection( &g_csPlayerContext );
  93.  
  94.     // Read persistent state information from registry
  95.     RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
  96.                     REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, 
  97.                     &hDPlaySampleRegKey, NULL );
  98.     DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), 
  99.                              g_strSessionName, MAX_PATH, TEXT("TestGame") );
  100.     DXUtil_ReadIntRegKey( hDPlaySampleRegKey, TEXT("SimpleServer Port"), 
  101.                           &g_dwPort, SIMPLESERVER_DEFAULT_PORT );
  102.  
  103.     // Init COM so we can use CoCreateInstance
  104.     CoInitializeEx( NULL, COINIT_MULTITHREADED );
  105.  
  106.     // For this sample, we just start a simple dialog box server
  107.     g_hrDialog = S_OK;
  108.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, (DLGPROC) ServerDlgProc );
  109.  
  110.     if( FAILED( g_hrDialog ) )
  111.     {
  112.         if( g_hrDialog == DPNERR_CONNECTIONLOST )
  113.         {
  114.             MessageBox( NULL, TEXT("The DirectPlay session was lost. ")
  115.                         TEXT("The server will now quit."),
  116.                         g_strAppName, MB_OK | MB_ICONERROR );
  117.         }
  118.         else
  119.         {
  120.             DXTRACE_ERR( TEXT("DialogBox"), g_hrDialog );
  121.             MessageBox( NULL, TEXT("An error occured. ")
  122.                         TEXT("The server will now quit."),
  123.                         g_strAppName, MB_OK | MB_ICONERROR );
  124.         }
  125.     }
  126.  
  127.     DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
  128.     DXUtil_WriteIntRegKey( hDPlaySampleRegKey, TEXT("SimpleServer Port"), g_dwPort );
  129.  
  130.     StopServer( NULL );
  131.  
  132.     RegCloseKey( hDPlaySampleRegKey );
  133.     DeleteCriticalSection( &g_csPlayerContext );
  134.     CoUninitialize();
  135.  
  136.     return TRUE;
  137. }
  138.  
  139.  
  140.  
  141.  
  142. //-----------------------------------------------------------------------------
  143. // Name: ServerDlgProc()
  144. // Desc: Handles dialog messages
  145. //-----------------------------------------------------------------------------
  146. INT_PTR CALLBACK ServerDlgProc( HWND hDlg, UINT msg, 
  147.                                 WPARAM wParam, LPARAM lParam )
  148. {
  149.     switch( msg ) 
  150.     {
  151.         case WM_INITDIALOG:
  152.         {
  153.             g_hDlg = hDlg;
  154.  
  155.             // Load and set the icon
  156.             HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
  157.             SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  158.             SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  159.  
  160.             SetWindowText( hDlg, TEXT("SimpleServer") );
  161.             SetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName );
  162.  
  163.             // Set the port to either a number or blank
  164.             if( g_dwPort != 0 )
  165.                 SetDlgItemInt( hDlg, IDC_PORT, g_dwPort, FALSE );
  166.             else
  167.                 SetDlgItemText( hDlg, IDC_PORT, TEXT("") );
  168.  
  169.             SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server stoped.") );
  170.  
  171.             PostMessage( hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  172.             break;
  173.         }
  174.  
  175.         case WM_APP_UPDATE_STATS:
  176.         {
  177.             // Update the number of players in the game
  178.             TCHAR strNumberPlayers[32];
  179.  
  180.             wsprintf( strNumberPlayers, TEXT("%d"), g_lNumberOfActivePlayers );
  181.             SetDlgItemText( hDlg, IDC_NUM_PLAYERS, strNumberPlayers );
  182.             DisplayPlayers( hDlg );
  183.             break;
  184.         }
  185.  
  186.         case WM_COMMAND:
  187.         {
  188.             switch( LOWORD(wParam) )
  189.             {
  190.                 case IDC_START:
  191.                     if( !g_bServerStarted )
  192.                     {
  193.                         if( FAILED( g_hrDialog = StartServer( hDlg ) ) )
  194.                         {
  195.                             DXTRACE_ERR( TEXT("StartServer"), g_hrDialog );
  196.                             EndDialog( hDlg, 0 );
  197.                         }
  198.                     }
  199.                     else
  200.                     {
  201.                         StopServer( hDlg );
  202.                     }
  203.  
  204.                     if( g_bServerStarted )
  205.                     {
  206.                         SetDlgItemText( hDlg, IDC_START, TEXT("Stop Server") );
  207.                         EnableWindow( GetDlgItem( hDlg, IDC_SESSION_NAME ), FALSE );
  208.                         EnableWindow( GetDlgItem( hDlg, IDC_PORT ), FALSE );
  209.                     }
  210.                     else
  211.                     {
  212.                         SetDlgItemText( hDlg, IDC_START, TEXT("Start Server") );
  213.                         EnableWindow( GetDlgItem( hDlg, IDC_SESSION_NAME ), TRUE );
  214.                         EnableWindow( GetDlgItem( hDlg, IDC_PORT ), TRUE );
  215.                     }
  216.  
  217.                     break;
  218.  
  219.                 case IDCANCEL:
  220.                     StopServer( hDlg );
  221.                     EndDialog( hDlg, 0 );
  222.                     return TRUE;
  223.             }
  224.             break;
  225.         }
  226.     }
  227.  
  228.     return FALSE; // Didn't handle message
  229. }
  230.  
  231.  
  232.  
  233.  
  234. //-----------------------------------------------------------------------------
  235. // Name: DirectPlayMessageHandler
  236. // Desc: Handler for DirectPlay messages.  This function is called by
  237. //       the DirectPlay message handler pool of threads, so be careful of thread
  238. //       synchronization problems with shared memory
  239. //-----------------------------------------------------------------------------
  240. HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, 
  241.                                          DWORD dwMessageId, 
  242.                                          PVOID pMsgBuffer )
  243. {
  244.     // Try not to stay in this message handler for too long, otherwise
  245.     // there will be a backlog of data.  The best solution is to 
  246.     // queue data as it comes in, and then handle it on other threads.
  247.     
  248.     // This function is called by the DirectPlay message handler pool of 
  249.     // threads, so be careful of thread synchronization problems with shared memory
  250.  
  251.     switch( dwMessageId )
  252.     {
  253.         case DPN_MSGID_CREATE_PLAYER:
  254.         {
  255.             HRESULT hr;
  256.             PDPNMSG_CREATE_PLAYER pCreatePlayerMsg;
  257.             pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer;
  258.  
  259.             // Get the peer info and extract its name
  260.             DWORD dwSize = 0;
  261.             DPN_PLAYER_INFO* pdpPlayerInfo = NULL;
  262.             hr = g_pDPServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, 
  263.                                              pdpPlayerInfo, &dwSize, 0 );
  264.             if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  265.             {
  266.                 if( hr == DPNERR_INVALIDPLAYER )
  267.                 {
  268.                     // Ignore this message if this is for the host
  269.                     break;
  270.                 }
  271.  
  272.                 return DXTRACE_ERR( TEXT("GetClientInfo"), hr );
  273.             }
  274.             pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ];
  275.             ZeroMemory( pdpPlayerInfo, dwSize );
  276.             pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO);
  277.             hr = g_pDPServer->GetClientInfo( pCreatePlayerMsg->dpnidPlayer, 
  278.                                        pdpPlayerInfo, &dwSize, 0 );
  279.             if( FAILED(hr) )
  280.                 return DXTRACE_ERR( TEXT("GetClientInfo"), hr );
  281.  
  282.             // Create a new and fill in a APP_PLAYER_INFO
  283.             APP_PLAYER_INFO* pPlayerInfo = new APP_PLAYER_INFO;
  284.             ZeroMemory( pPlayerInfo, sizeof(APP_PLAYER_INFO) );
  285.             pPlayerInfo->lRefCount   = 1;
  286.             pPlayerInfo->dpnidPlayer = pCreatePlayerMsg->dpnidPlayer;
  287.  
  288.             // This stores a extra TCHAR copy of the player name for 
  289.             // easier access.  This will be redundent copy since DPlay 
  290.             // also keeps a copy of the player name in GetClientInfo()
  291.             DXUtil_ConvertWideStringToGeneric( pPlayerInfo->strPlayerName, 
  292.                                                pdpPlayerInfo->pwszName, MAX_PLAYER_NAME );
  293.  
  294.             SAFE_DELETE_ARRAY( pdpPlayerInfo );
  295.  
  296.             // Tell DirectPlay to store this pPlayerInfo 
  297.             // pointer in the pvPlayerContext.
  298.             pCreatePlayerMsg->pvPlayerContext = pPlayerInfo;
  299.  
  300.             // Send all connected players a message telling about this new player
  301.             SendCreatePlayerMsg( pPlayerInfo, DPNID_ALL_PLAYERS_GROUP );
  302.  
  303.             // Tell this new player about the world state
  304.             SendWorldStateToNewPlayer( pCreatePlayerMsg->dpnidPlayer );
  305.  
  306.             // Update the number of active players, and 
  307.             // post a message to the dialog thread to update the 
  308.             // UI.  This keeps the DirectPlay message handler 
  309.             // from blocking
  310.             InterlockedIncrement( &g_lNumberOfActivePlayers );
  311.             if( g_hDlg != NULL )
  312.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  313.  
  314.             break;
  315.         }
  316.  
  317.         case DPN_MSGID_DESTROY_PLAYER:
  318.         {
  319.             PDPNMSG_DESTROY_PLAYER pDestroyPlayerMsg;
  320.             pDestroyPlayerMsg = (PDPNMSG_DESTROY_PLAYER)pMsgBuffer;
  321.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pDestroyPlayerMsg->pvPlayerContext;
  322.  
  323.             // Ignore this message if this is the host player
  324.             if( pPlayerInfo == NULL )
  325.                 break; 
  326.  
  327.             // Send all connected players a message telling about this destroyed player
  328.             SendDestroyPlayerMsgToAll( pPlayerInfo );
  329.  
  330.             PLAYER_LOCK();                  // enter player context CS
  331.             PLAYER_RELEASE( pPlayerInfo );  // Release player and cleanup if needed
  332.             PLAYER_UNLOCK();                // leave player context CS
  333.  
  334.             // Update the number of active players, and 
  335.             // post a message to the dialog thread to update the 
  336.             // UI.  This keeps the DirectPlay message handler 
  337.             // from blocking
  338.             InterlockedDecrement( &g_lNumberOfActivePlayers );
  339.             if( g_hDlg != NULL )
  340.                 PostMessage( g_hDlg, WM_APP_UPDATE_STATS, 0, 0 );
  341.  
  342.             break;
  343.         }
  344.  
  345.         case DPN_MSGID_TERMINATE_SESSION:
  346.         {
  347.             PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg;
  348.             pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer;
  349.  
  350.             g_hrDialog = DPNERR_CONNECTIONLOST;
  351.             EndDialog( g_hDlg, 0 );
  352.             break;
  353.         }
  354.  
  355.         case DPN_MSGID_RECEIVE:
  356.         {
  357.             PDPNMSG_RECEIVE pReceiveMsg;
  358.             pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer;
  359.             APP_PLAYER_INFO* pPlayerInfo = (APP_PLAYER_INFO*) pReceiveMsg->pvPlayerContext;
  360.  
  361.             GAMEMSG_GENERIC* pMsg = (GAMEMSG_GENERIC*) pReceiveMsg->pReceiveData;
  362.             if( pMsg->dwType == GAME_MSGID_WAVE )
  363.                 SendWaveMessageToAll( pPlayerInfo->dpnidPlayer );
  364.             break;
  365.         }
  366.     }
  367.  
  368.     return S_OK;
  369. }
  370.  
  371.  
  372.  
  373.  
  374. //-----------------------------------------------------------------------------
  375. // Name: StartServer
  376. // Desc: 
  377. //-----------------------------------------------------------------------------
  378. HRESULT StartServer( HWND hDlg )
  379. {
  380.     HRESULT hr;
  381.     PDIRECTPLAY8ADDRESS pDP8AddrLocal = NULL;
  382.  
  383.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Starting server...") );
  384.     SetCursor( LoadCursor(NULL, IDC_WAIT) );
  385.  
  386.     WCHAR wstrSessionName[MAX_PATH];
  387.     GetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName, MAX_PATH );
  388.     DXUtil_ConvertGenericStringToWide( wstrSessionName, g_strSessionName );
  389.  
  390.     BOOL bPortTranslated;
  391.     g_dwPort = GetDlgItemInt( hDlg, IDC_PORT, &bPortTranslated, FALSE );
  392.     if( !bPortTranslated )
  393.         g_dwPort = 0;
  394.  
  395.     // Create IDirectPlay8Server
  396.     if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Server, NULL, 
  397.                                        CLSCTX_INPROC_SERVER,
  398.                                        IID_IDirectPlay8Server, 
  399.                                        (LPVOID*) &g_pDPServer ) ) )
  400.         return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  401.  
  402.     // Init IDirectPlay8Server
  403.     if( FAILED( hr = g_pDPServer->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
  404.         return DXTRACE_ERR( TEXT("Initialize"), hr );
  405.  
  406.     hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, 
  407.                            CLSCTX_ALL, IID_IDirectPlay8Address, 
  408.                            (LPVOID*) &pDP8AddrLocal );
  409.     if( FAILED(hr) )
  410.     {
  411.         DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
  412.         goto LCleanup;
  413.     }
  414.  
  415.     hr = pDP8AddrLocal->SetSP( &CLSID_DP8SP_TCPIP );
  416.     if( FAILED(hr) )
  417.     {
  418.         DXTRACE_ERR( TEXT("SetSP"), hr );
  419.         goto LCleanup;
  420.     }
  421.  
  422.     // Add the port to pDP8AddrLocal, if the port is non-zero.
  423.     // If the port is 0, then DirectPlay will pick a port, 
  424.     // Games will typically hard code the port so the 
  425.     // user need not know it
  426.     if( g_dwPort != 0 )
  427.     {
  428.         if( FAILED( hr = pDP8AddrLocal->AddComponent( DPNA_KEY_PORT, 
  429.                                                       &g_dwPort, sizeof(g_dwPort),
  430.                                                       DPNA_DATATYPE_DWORD ) ) )
  431.             return DXTRACE_ERR( TEXT("AddComponent"), hr );
  432.     }
  433.  
  434.     DPN_APPLICATION_DESC dpnAppDesc;
  435.     ZeroMemory( &dpnAppDesc, sizeof(DPN_APPLICATION_DESC) );
  436.     dpnAppDesc.dwSize           = sizeof( DPN_APPLICATION_DESC );
  437.     dpnAppDesc.dwFlags          = DPNSESSION_CLIENT_SERVER;
  438.     dpnAppDesc.guidApplication  = g_guidApp;
  439.     dpnAppDesc.pwszSessionName  = wstrSessionName;
  440.  
  441.     hr = g_pDPServer->Host( &dpnAppDesc, &pDP8AddrLocal, 1, NULL, NULL, NULL, 0  );
  442.     if( FAILED(hr) )
  443.     {
  444.         DXTRACE_ERR( TEXT("Host"), hr );
  445.         goto LCleanup;
  446.     }
  447.  
  448.     SetCursor( LoadCursor(NULL, IDC_ARROW) );
  449.     g_bServerStarted = TRUE;
  450.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server started.") );
  451.  
  452. LCleanup:
  453.     SAFE_RELEASE( pDP8AddrLocal );
  454.  
  455.     return hr;
  456. }
  457.  
  458.  
  459.  
  460.  
  461. //-----------------------------------------------------------------------------
  462. // Name: StopServer
  463. // Desc: 
  464. //-----------------------------------------------------------------------------
  465. VOID StopServer( HWND hDlg )
  466. {
  467.     if( hDlg )
  468.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Stopping server...") );
  469.     SetCursor( LoadCursor(NULL, IDC_WAIT) );
  470.  
  471.     if( g_pDPServer )
  472.     {
  473.         g_pDPServer->Close(0);
  474.         SAFE_RELEASE( g_pDPServer );
  475.     }
  476.     g_bServerStarted = FALSE;
  477.  
  478.     SetCursor( LoadCursor(NULL, IDC_ARROW) );
  479.     if( hDlg )
  480.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Server stoped.") );
  481. }
  482.  
  483.  
  484.  
  485.     
  486. //-----------------------------------------------------------------------------
  487. // Name: DisplayPlayers
  488. // Desc: 
  489. //-----------------------------------------------------------------------------
  490. VOID DisplayPlayers( HWND hDlg )
  491. {
  492.     HRESULT hr;
  493.     DWORD dwNumPlayers = 0;
  494.     DPNID* aPlayers = NULL;
  495.  
  496.     SendMessage( GetDlgItem(hDlg, IDC_PLAYER_LIST), LB_RESETCONTENT, 0, 0 );
  497.  
  498.     if( NULL == g_pDPServer )
  499.         return;
  500.  
  501.     // Enumerate all the connected players
  502.     while( TRUE )
  503.     {
  504.         hr = g_pDPServer->EnumPlayersAndGroups( aPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  505.         if( SUCCEEDED(hr) )
  506.             break;
  507.  
  508.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  509.             return;
  510.  
  511.         SAFE_DELETE_ARRAY( aPlayers );
  512.         aPlayers = new DPNID[ dwNumPlayers ];
  513.     }
  514.  
  515.     // For each player, send a "create player" message to the new player
  516.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  517.     {
  518.         APP_PLAYER_INFO* pPlayerInfo = NULL;
  519.  
  520.         hr = g_pDPServer->GetPlayerContext( aPlayers[i], (LPVOID*) &pPlayerInfo, 0 );
  521.  
  522.         // Ignore this player if we can't get the context
  523.         if( pPlayerInfo == NULL || FAILED(hr) )
  524.             continue; 
  525.  
  526.         TCHAR strTemp[MAX_PATH];
  527.         wsprintf( strTemp, "DPNID: 0x%0.8x (%s)", pPlayerInfo->dpnidPlayer, pPlayerInfo->strPlayerName );
  528.         int nIndex = (int)SendMessage( GetDlgItem(hDlg, IDC_PLAYER_LIST), LB_ADDSTRING, 
  529.                                        0, (LPARAM)strTemp );
  530.     }
  531.  
  532.     SAFE_DELETE_ARRAY( aPlayers );
  533. }
  534.  
  535.  
  536.  
  537.     
  538. //-----------------------------------------------------------------------------
  539. // Name: SendCreatePlayerMsg
  540. // Desc: Send the target player a creation message about the player identified
  541. //       in the APP_PLAYER_INFO struct.
  542. //-----------------------------------------------------------------------------
  543. HRESULT SendCreatePlayerMsg( APP_PLAYER_INFO* pPlayerAbout, DPNID dpnidTarget )
  544. {
  545.     GAMEMSG_CREATE_PLAYER msgCreatePlayer;
  546.     msgCreatePlayer.dwType = GAME_MSGID_CREATE_PLAYER;
  547.     msgCreatePlayer.dpnidPlayer = pPlayerAbout->dpnidPlayer;
  548.     strcpy( msgCreatePlayer.strPlayerName, pPlayerAbout->strPlayerName );
  549.  
  550.     DPN_BUFFER_DESC bufferDesc;
  551.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_CREATE_PLAYER);
  552.     bufferDesc.pBufferData  = (BYTE*) &msgCreatePlayer;
  553.  
  554.     // DirectPlay will tell via the message handler 
  555.     // if there are any severe errors, so ignore any errors 
  556.     DPNHANDLE hAsync;
  557.     g_pDPServer->SendTo( dpnidTarget, &bufferDesc, 1,
  558.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  559.  
  560.     return S_OK;
  561. }
  562.  
  563.  
  564.  
  565.     
  566. //-----------------------------------------------------------------------------
  567. // Name: SendWorldStateToNewPlayer
  568. // Desc: Send the world state to the new player.  For this sample, it is just
  569. //       "create player" message for every connected player
  570. //-----------------------------------------------------------------------------
  571. HRESULT SendWorldStateToNewPlayer( DPNID dpnidNewPlayer )
  572. {
  573.     HRESULT hr;
  574.     DWORD dwNumPlayers = 0;
  575.     DPNID* aPlayers = NULL;
  576.  
  577.     // Tell this player the dpnid of itself
  578.     GAMEMSG_SET_ID msgSetID;
  579.     msgSetID.dwType      = GAME_MSGID_SET_ID;
  580.     msgSetID.dpnidPlayer = dpnidNewPlayer;
  581.  
  582.     DPN_BUFFER_DESC bufferDesc;
  583.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_SET_ID);
  584.     bufferDesc.pBufferData  = (BYTE*) &msgSetID;
  585.  
  586.     // DirectPlay will tell via the message handler 
  587.     // if there are any severe errors, so ignore any errors 
  588.     DPNHANDLE hAsync;
  589.     g_pDPServer->SendTo( dpnidNewPlayer, &bufferDesc, 1,
  590.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  591.  
  592.     // Enumerate all the connected players
  593.     while( TRUE )
  594.     {
  595.         hr = g_pDPServer->EnumPlayersAndGroups( aPlayers, &dwNumPlayers, DPNENUM_PLAYERS );
  596.         if( SUCCEEDED(hr) )
  597.             break;
  598.  
  599.         if( FAILED(hr) && hr != DPNERR_BUFFERTOOSMALL )
  600.             return DXTRACE_ERR( TEXT("EnumPlayersAndGroups"), hr );
  601.  
  602.         SAFE_DELETE_ARRAY( aPlayers );
  603.         aPlayers = new DPNID[ dwNumPlayers ];
  604.     }
  605.  
  606.     // For each player, send a "create player" message to the new player
  607.     for( DWORD i = 0; i<dwNumPlayers; i++ )
  608.     {
  609.         APP_PLAYER_INFO* pPlayerInfo = NULL;
  610.  
  611.         // Don't send a create msg to the new player about itself.  This will 
  612.         // be already done when we sent one to DPNID_ALL_PLAYERS_GROUP
  613.         if( aPlayers[i] == dpnidNewPlayer )
  614.             continue;  
  615.  
  616.         hr = g_pDPServer->GetPlayerContext( aPlayers[i], (LPVOID*) &pPlayerInfo, 0 );
  617.  
  618.         // Ignore this player if we can't get the context
  619.         if( pPlayerInfo == NULL || FAILED(hr) )
  620.             continue; 
  621.  
  622.         SendCreatePlayerMsg( pPlayerInfo, dpnidNewPlayer );
  623.     }
  624.  
  625.     SAFE_DELETE_ARRAY( aPlayers );
  626.  
  627.     return S_OK;
  628. }
  629.  
  630.  
  631.  
  632.  
  633. //-----------------------------------------------------------------------------
  634. // Name: SendDestroyPlayerMsgToAll
  635. // Desc: 
  636. //-----------------------------------------------------------------------------
  637. HRESULT SendDestroyPlayerMsgToAll( APP_PLAYER_INFO* pPlayerInfo )
  638. {
  639.     GAMEMSG_DESTROY_PLAYER msgDestroyPlayer;
  640.     msgDestroyPlayer.dwType = GAME_MSGID_DESTROY_PLAYER;
  641.     msgDestroyPlayer.dpnidPlayer = pPlayerInfo->dpnidPlayer;
  642.  
  643.     DPN_BUFFER_DESC bufferDesc;
  644.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_CREATE_PLAYER);
  645.     bufferDesc.pBufferData  = (BYTE*) &msgDestroyPlayer;
  646.  
  647.     // DirectPlay will tell via the message handler 
  648.     // if there are any severe errors, so ignore any errors 
  649.     DPNHANDLE hAsync;
  650.     g_pDPServer->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  651.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  652.  
  653.     return S_OK;
  654. }
  655.  
  656.  
  657.  
  658.  
  659. //-----------------------------------------------------------------------------
  660. // Name: SendWaveMessageToAll
  661. // Desc: 
  662. //-----------------------------------------------------------------------------
  663. HRESULT SendWaveMessageToAll( DPNID dpnidFrom )
  664. {
  665.     GAMEMSG_WAVE msgWave;
  666.     msgWave.dwType = GAME_MSGID_WAVE;
  667.     msgWave.dpnidPlayer = dpnidFrom;
  668.  
  669.     DPN_BUFFER_DESC bufferDesc;
  670.     bufferDesc.dwBufferSize = sizeof(GAMEMSG_WAVE);
  671.     bufferDesc.pBufferData  = (BYTE*) &msgWave;
  672.  
  673.     // DirectPlay will tell via the message handler 
  674.     // if there are any severe errors, so ignore any errors 
  675.     DPNHANDLE hAsync;
  676.     g_pDPServer->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1,
  677.                          0, NULL, &hAsync, DPNSEND_NOLOOPBACK );
  678.  
  679.     return S_OK;
  680. }
  681.  
  682.  
  683.  
  684.