1 / 53

Creating a DirectX Project

Creating a DirectX Project. A DirectPLay Chat Program. Setting up your Compiler for DirectX. Install DirectX SDK Make sure your compiler has path to directx8/include Directx8/lib Directx8/samples/multimedia/common/src Directx8/samples/multimedia/common/include.

stasia
Download Presentation

Creating a DirectX Project

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Creating a DirectX Project A DirectPLay Chat Program

  2. Setting up your Compiler for DirectX • Install DirectX SDK • Make sure your compiler has path to • directx8/include • Directx8/lib • Directx8/samples/multimedia/common/src • Directx8/samples/multimedia/common/include

  3. Create a new win 32 application with Visual C++ • Under the Project Settings menu, select Link • In the Object/Libraries edit box, enter winmm.lib and dplay.lib • Select C/C++ tab • From the Category drop down menu, select Code Generation • In the Use Run-Time Library drop-down menu, select Multi-Threaded

  4. Select OK • Under the Project Menu, select Add To Project and then select Files. Browse to where you installed DirectX. Under Directx8/samples/multimedia/common/src, you will find dxutil.cpp. Select this file and then select OK. • Repeat the step to add dxutil.h from Directx8/samples/multimedia/common/include

  5. Now, create DpChat.cpp • The add new header file called DPChat.h • The files will contain global vars declaration, function prototypes, and preprocessor definitions

  6. Initialize all GUID, must be defined at the beginning of all DirectX application Needs for DirectPlay Button used to join the session List box output text Button used to host the session Edit box to input host name Edit box to input host port Edit box to input player’s name The DPChat Header File • #define INITGUID • #include <windows.h> • #include <dplay8.h> • #include <stdio.h> • #include "DXUtil.h" • //----------------------------------------------------------------------------------- • // Windows Globals • //----------------------------------------------------------------------------------- • // Icon Resource • #define IDI_ICON1 101 • // ID's for child windows • #define IDC_hBU_Join 40001 • #define IDC_hLB_Output 40002 • #define IDC_hBU_Host 40004 • #define IDC_hEB_InputServerIP 40005 • #define IDC_hEB_InputServerPort 40006 • #define IDC_hEB_InputName 40007

  7. Static text Edit box to accept chat text Set Windows timer (see later) Run guidgen from command prompt • #define IDC_hST_TextServerIP 40008 • #define IDC_hST_TextServerPort 40009 • #define IDC_hST_TextName 40010 • #define IDC_hEB_InputField 40011 • // Handles to child windows • HWND hBU_Join = NULL; • HWND hBU_Host = NULL; • HWND hLB_Output = NULL; • HWND hEB_InputServerIP = NULL; • HWND hEB_InputServerPort = NULL; • HWND hEB_InputName = NULL; • HWND hEB_InputField = NULL; • HWND hST_TextServerIP = NULL; • HWND hST_TextServerPort = NULL; • HWND hST_TextName = NULL; • // Timer Ids • #define TIMERID_CONNECT_COMPLETE 1 • // set the GUID, Needed to identify application • GUID DP_CHAT = { 0x2ae835d, 0x9179, 0x485f, { 0x83, 0x43, 0x90, 0x1d, 0x32, 0x7c, 0xe7, 0x94 } }; • // Class name & app name • LPCTSTR lpszApplicationName = "DPChat"; • LPCTSTR lpszTitle = "DPChat";

  8. Used for both join and host Is this slot being used? Player’s unique DirectPlay identifier • //----------------------------------------------------------------------------------- • // Direct Play Objects • //----------------------------------------------------------------------------------- • IDirectPlay8Peer* g_pDP; • IDirectPlay8Address* g_pDeviceAddress; • IDirectPlay8Address* g_pHostAddress; • DPNHANDLE g_hConnectAsyncOp; • DPNID g_dpnidLocalPlayer = 0; • #define MAX_PLAYERS 4 • struct PLAYER_INFORMATION • { • bool bActive; • DPNID dpnidPlayer; • char szPlayerName[32]; • }; • PLAYER_INFORMATION PlayerInfo[MAX_PLAYERS]; • //----------------------------------------------------------------------------------- • // Multi-Threading Variables • //----------------------------------------------------------------------------------- • HANDLE g_hConnectCompleteEvent; • HRESULT g_hrConnectComplete; • CRITICAL_SECTION g_csModifyPlayer;

  9. //-----------------------------------------------------------------------------------//----------------------------------------------------------------------------------- • // Miscellaneous Variables • //----------------------------------------------------------------------------------- • LONG g_lNumberOfActivePlayers = 0; • BOOL bHost = 0; • //----------------------------------------------------------------------------------- • // Packet Structures • //----------------------------------------------------------------------------------- • struct PACKET_CHAT • { • char szText[256]; • }; • //----------------------------------------------------------------------------------- • // Functions for our Windows Interface • //----------------------------------------------------------------------------------- • // Message Loop CallBack Function prototype ( REQUIRED FOR ALL WINDOWS PROGRAMS ) • LRESULT CALLBACK fnMessageProcessor (HWND, UINT, WPARAM, LPARAM); • // Function to display text in the output box • void vShowText(HWND hChildHandle, char *szText); • // Function to setup display of GUI • void vCreateInterface(HWND hWnd,HINSTANCE hInstance);

  10. // Function called when program exits, cleans up allocated objects • void vCleanup(void); • //----------------------------------------------------------------------------------- • // DirectPlay Functions • //----------------------------------------------------------------------------------- • // Function to initialize direct play system • HRESULT hrInitializeDirectPlay( HWND hWindow ); • // Function to send chat message • HRESULT hrSendChatMessage(int player, char *szmessage); • // Function to handle all incoming Dplay messages • HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer ); • // Function to host a game • HRESULT hrHostGame( HWND hwnd ); • // Function to join a game • HRESULT hrJoinGame( HWND hWnd ); • // Function called when a player joins the game • HRESULT hrCreatePlayer( PVOID pvUserContext, PVOID pMsgBuffer ); • // Function called when a player leaves the game • HRESULT hrDestroyPlayer( PVOID pvUserContext, PVOID pMsgBuffer );

  11. DPChat.cpp(main()) • #include "dpchat.h" • // • // Function to Create the Window and Display it ( REQUIRED FOR ALL WINDOWS PROGRAMS ) • // • int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) • { • MSG msg; • WNDCLASSEX wndclass; • HWND hWnd; • HRESULT hReturn; • // Set up window attributes • wndclass.cbSize = sizeof(wndclass); • wndclass.style = CS_HREDRAW | CS_VREDRAW; • wndclass.lpfnWndProc = fnMessageProcessor; • wndclass.cbClsExtra = 0; • wndclass.cbWndExtra = 0;

  12. wndclass.hInstance = hInstance; • wndclass.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON1) ); • wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ); • wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW); • wndclass.lpszMenuName = NULL; • wndclass.lpszClassName = lpszApplicationName; // Registered Class Name • wndclass.hIconSm = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON1) ); • if( RegisterClassEx( &wndclass ) == 0 ) { • // Do error logic here • exit(1); • }

  13. // Create the main window • hWnd = CreateWindow( lpszApplicationName,// Application Name • lpszTitle, // Name Displayed on Title Bar • WS_OVERLAPPEDWINDOW, • 100, • 100, • 400, • 340, • NULL, • NULL, • hInstance, • NULL ); • // Create Child Objects • vCreateInterface(hWnd,hInstance); • ShowWindow(hWnd, nCmdShow); • UpdateWindow(hWnd);

  14. // Initialize Direct Play • hReturn = hrInitializeDirectPlay( hWnd ); • if( FAILED(hReturn) ) { • vCleanup(); • exit(1); • } • // Process messages until the program is terminated • while( GetMessage ( &msg, NULL, 0, 0 ) ) • { • TranslateMessage( &msg ); • DispatchMessage( &msg ); • } • return(msg.wParam); • } Not using PeekMessage() in this example

  15. vCreateInterface(hWnd,hInstance) • void vCreateInterface(HWND hWnd,HINSTANCE hInstance) • { • // Server IP Text • hST_TextServerIP = CreateWindow( • "static","Server IP", • WS_CHILD | SS_CENTER | WS_VISIBLE, • 5, • 5, • 120, • 28, • hWnd,(HMENU)IDC_hST_TextServerIP,hInstance,NULL);

  16. // Port Text • hST_TextServerPort = CreateWindow( • "static","Port", • WS_CHILD | SS_CENTER | WS_VISIBLE, • 125, • 5, • 50, • 28, • hWnd,(HMENU)IDC_hST_TextServerPort,hInstance,NULL); • // Name Text • hST_TextName = CreateWindow( • "static","Player Name", • WS_CHILD | SS_CENTER | WS_VISIBLE, • 250, • 5, • 135, • 28, • hWnd,(HMENU)IDC_hST_TextName,hInstance,NULL);

  17. // Join Button • hBU_Join = CreateWindow( • "BUTTON", • "Join", • WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, • 325, • 280, • 60, • 28, • hWnd,(HMENU)IDC_hBU_Join,hInstance,NULL); • // Host Button • hBU_Host = CreateWindow( • "BUTTON", • "Host", • WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, • 325, • 240, • 60, • 28, • hWnd,(HMENU)IDC_hBU_Host,hInstance,NULL);

  18. // Output Window • hLB_Output = CreateWindowEx( • WS_EX_CLIENTEDGE, • "LISTBOX", • NULL, • WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | WS_BORDER, • 5, • 50, • 315, • 230, • hWnd,(HMENU)IDC_hLB_Output,hInstance,NULL); • // Name • hEB_InputName = CreateWindowEx( • WS_EX_CLIENTEDGE, • "EDIT","Unnamed", • WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, • 250, • 20, • 135, • 28, • hWnd,(HMENU)IDC_hEB_InputName,hInstance,NULL);

  19. // Server IP • hEB_InputServerIP = CreateWindowEx( • WS_EX_CLIENTEDGE, • "EDIT","192.168.0.2", • WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, • 5, • 20, • 120, • 28, • hWnd,(HMENU)IDC_hEB_InputServerIP,hInstance,NULL); • // Server Port • hEB_InputServerPort = CreateWindowEx( • WS_EX_CLIENTEDGE, • "EDIT","6000", • WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT, • 125, • 20, • 50, • 28, • hWnd,(HMENU)IDC_hEB_InputServerPort,hInstance,NULL);

  20. // Edit field to enter chat messages into • hEB_InputField = CreateWindowEx( • WS_EX_CLIENTEDGE, • "EDIT",NULL, • WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL | ES_MULTILINE, • 5, • 280, • 315, • 28, • hWnd,(HMENU)IDC_hEB_InputField,hInstance,NULL); • }

  21. Screen shot hST_TextServerPort hST_TextName hST_TextServerIP hEB_InputServerIP hEB_InputName hEB_InputServerPort hLB_Output hBU_Host hEB_InputField hBU_Join

  22. Output to list box • void vShowText(HWND hChildHandle, char *szText) • { • int Line; • // add string to the listbox • SendMessage(hChildHandle,LB_ADDSTRING,0,(LPARAM)szText); • // determine number of items in listbox • Line = SendMessage(hChildHandle,LB_GETCOUNT,0,0); • // flag last item as the selected item, to scroll listbox down • SendMessage(hChildHandle,LB_SETCURSEL,Line-1,0); • // unflag all items to eliminate negative highlite • SendMessage(hChildHandle,LB_SETCURSEL,-1,0); • }

  23. fnMessageProcessor() • LRESULT CALLBACK fnMessageProcessor ( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) • { • char szMessage[256]; • char szCompMessage[256]; • HRESULT hReturn; • switch (iMsg) • { • case WM_COMMAND: • { • // Check for child window messages • switch(LOWORD(wParam)) • { • // Check if the user clicked the button • case IDC_hBU_Join: • hrJoinGame( hWnd ); • break; • case IDC_hBU_Host: • hrHostGame( hWnd ); • break; • }

  24. switch(HIWORD(wParam)) • { • case EN_UPDATE: • // Get the text from the edit box • GetWindowText(hEB_InputField,szMessage,256); • // Check if they pressed enter • if( szMessage[strlen(szMessage)-1] == 10 ) { • // Get rid of trailing garbage • szMessage[strlen(szMessage)-2] = '\0'; • sprintf(szCompMessage,"<%s> %s", PlayerInfo[0].szPlayerName, szMessage); • hReturn = hrSendChatMessage(-1,szCompMessage); • // clear input field • SetWindowText(hEB_InputField,""); • } • } • break; • } • case WM_DESTROY: • // Cleanup System • vCleanup(); • // Exit out of Windows • PostQuitMessage(0); • break;

  25. We set it earlier • case WM_TIMER: • if( wParam == TIMERID_CONNECT_COMPLETE ) { • // Check if the message is telling us our connection is complete • if( WAIT_OBJECT_0 == WaitForSingleObject( g_hConnectCompleteEvent, 0 ) ) { • if( FAILED( g_hrConnectComplete ) ) { • vShowText(hLB_Output,"<<---CONNECTION IN-COMPLETE---->>"); • } • else { • vShowText(hLB_Output,"<<----CONNECTION COMPLETE---->>"); • } • KillTimer( hWnd, TIMERID_CONNECT_COMPLETE ); • } • } • break; • default: • return(DefWindowProc(hWnd, iMsg, wParam, lParam)); • } • return(0L); } So far, it’s all Windows GUI

  26. When players join sessions or leave sessions at the same time, the list of players won’t be corrupted hrInitializeDirectPlay() in WinMain • HRESULT hrInitializeDirectPlay( HWND hWindow ) • { • HRESULT hReturn; • int i; • // Initialize COM • hReturn = CoInitialize( NULL ); • if( FAILED(hReturn) ) { • MessageBox( hWindow, "Error Initializing COM", "DirectPlay Error", MB_ICONERROR ); • return hReturn; • } • // Initialize critical sections for multi-threading • InitializeCriticalSection( &g_csModifyPlayer );

  27. // Create IDirectPlay8Peer Object • if( FAILED( hReturn = CoCreateInstance( CLSID_DirectPlay8Peer, • NULL, • CLSCTX_INPROC_SERVER, • IID_IDirectPlay8Peer, • (LPVOID*) &g_pDP ) ) ) • MessageBox( hWindow, "Can't Create DPlayPeer", "DirectPlay Error", MB_ICONERROR ); • // Init IDirectPlay8Peer Message Handler • if( FAILED( hReturn = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) ) { • MessageBox( hWindow, "Failed to Message Handler", "DirectPlay Error", MB_ICONERROR ); • return -1; • } • // Create a device address • hReturn = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*) &g_pDeviceAddress ); • if( FAILED(hReturn) ) { • MessageBox( hWindow, "Failed to Create Device", "CoCreateInstance()", MB_ICONERROR ); • return -1; • }

  28. See next page • // Set our service provider to TCP/IP • if( FAILED( hReturn = g_pDeviceAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { • MessageBox( hWindow, "Failed to SetSP() for Device Address", "Invalid Param", MB_ICONERROR ); • return -1; • } • // Create a host address • hReturn = CoCreateInstance( CLSID_DirectPlay8Address, NULL,CLSCTX_INPROC_SERVER, IID_IDirectPlay8Address, (LPVOID*) &g_pHostAddress ); • if( FAILED(hReturn) ) { • MessageBox( hWindow, "Failed to Create Host Address()", "Invalid Param", MB_ICONERROR ); • return -1; • } • // Set the host address to TCP/IP • if( FAILED( hReturn = g_pHostAddress->SetSP( &CLSID_DP8SP_TCPIP ) ) ) { • MessageBox( hWindow, "Failed to SetSP() for Host Address", "Invalid Param", MB_ICONERROR ); • return -1; • } • // Create connection complete event for later use • g_hConnectCompleteEvent = CreateEvent( NULL, FALSE, FALSE, NULL );

  29. vShowText(hLB_Output,"<<--TCP INITED-->>"); • // Init miscellaneous variables • for( i = 0 ; i < MAX_PLAYERS ; i++ ) { • PlayerInfo[i].bActive = 0; • } • return S_OK; • } HANDLE CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes, //security attributes that can be inherited BOOL bManualReset, //or auto reset, depending on the boolean BOOL bInitialState, //event should start out signaled or not LPCTSTR lpName //name the event with this string );

  30. DirectPlayMessageHandler() • HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer ) • { • HRESULT hReturn = S_OK; • switch( dwMessageId ) • { • case DPN_MSGID_CREATE_PLAYER: • { • vShowText(hLB_Output,"Creating Player"); • hrCreatePlayer(pvUserContext,pMsgBuffer); • break; • } • case DPN_MSGID_DESTROY_PLAYER: • { • hrDestroyPlayer(pvUserContext,pMsgBuffer); • break; • }

  31. Received by the one who will take over at hosting. DirectPlay handles host change automatically If migration is not active and the host terminates the session, everyone gets disconnected • case DPN_MSGID_HOST_MIGRATE: • { • vShowText(hLB_Output,"Migrate Host"); • PDPNMSG_HOST_MIGRATE pHostMigrateMsg; • pHostMigrateMsg = (PDPNMSG_HOST_MIGRATE)pMsgBuffer; • // Check to see if we are the new host • if( pHostMigrateMsg->dpnidNewHost == g_dpnidLocalPlayer ) { • vShowText(hLB_Output,"(HOSTING)"); • } • break; • } • case DPN_MSGID_TERMINATE_SESSION: • { • vShowText(hLB_Output,"<-Terminating Session->"); • PDPNMSG_TERMINATE_SESSION pTerminateSessionMsg; • pTerminateSessionMsg = (PDPNMSG_TERMINATE_SESSION)pMsgBuffer; • break; • }

  32. Received whenever a chat message is sent. This msg type is used by all games to send custom messages Any player who joins a session successfully receives this message Put the event into a signaled state • case DPN_MSGID_RECEIVE: • { • PDPNMSG_RECEIVE pReceiveMsg; • pReceiveMsg = (PDPNMSG_RECEIVE)pMsgBuffer; • vShowText(hLB_Output,(char*)pReceiveMsg->pReceiveData); • break; • } • case DPN_MSGID_CONNECT_COMPLETE: • { • PDPNMSG_CONNECT_COMPLETE pConnectCompleteMsg; • pConnectCompleteMsg = (PDPNMSG_CONNECT_COMPLETE)pMsgBuffer; • g_hrConnectComplete = pConnectCompleteMsg->hResultCode; • SetEvent( g_hConnectCompleteEvent ); • break; • } • } • return hReturn; • }

  33. Used for player info hrHostGame() in fnMessageProcessor() • HRESULT hrHostGame( HWND hWindow) • { • HRESULT hReturn; • char szPeerName[256]; • char szSessionName[256]; • WCHAR wszPeerName[256]; • WCHAR wszSessionName[256]; • DPN_APPLICATION_DESC dnAppDesc; • char szPort[6]; • DWORD dwLength = 256; • DPN_PLAYER_INFO dpPlayerInfo; • DWORD dwPort = 9000;

  34. Host can migrate Host is a player too, don’t forget • // Setup our player information • GetWindowText(hEB_InputName,szPeerName,36); // Get name from Window Edit Box • DXUtil_ConvertGenericStringToWide( wszPeerName, szPeerName ); • ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) ); • dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); • dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; //tell it to get info from pwszName • dpPlayerInfo.pwszName = wszPeerName; • // Set us up to be non-asynchronous • if( FAILED( hReturn = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC ) ) ) { • MessageBox( hWindow, "Failed to SetPeerInfo()", "DirectPlay Error", MB_ICONERROR ); • return -1; • } • // Setup the application description • sprintf(szSessionName,"%s's Game",szPeerName); • DXUtil_ConvertGenericStringToWide( wszSessionName, szSessionName ); • ZeroMemory( &dnAppDesc, sizeof(DPN_APPLICATION_DESC) ); • dnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC); • dnAppDesc.guidApplication = DP_CHAT; • dnAppDesc.pwszSessionName = wszSessionName; • dnAppDesc.dwMaxPlayers = MAX_PLAYERS; • dnAppDesc.dwFlags = DPNSESSION_MIGRATE_HOST;

  35. A host needs port number to accept connection Application description address Host address Number of host address in &g_pDeviceAddress Player context Optional flags • // Get Port from edit box • GetWindowText(hEB_InputServerPort,szPort,6); • // Convert the port string to a DWORD • dwPort = atol(szPort); • // Add port number to address • hReturn = g_pDeviceAddress->AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),DPNA_DATATYPE_DWORD); • if( hReturn != S_OK ) { • MessageBox( hWindow, "Failed to AddComponent()", "hrHostGame()", MB_ICONERROR ); • return -1; • } • // Host the game • hReturn = g_pDP->Host( &dnAppDesc, • &g_pDeviceAddress, • 1, • NULL, • NULL, • NULL, • NULL );

  36. if( FAILED( hReturn ) ) { • if( hReturn == DPNERR_INVALIDPARAM ) • MessageBox( hWindow, "Failed to Host()", "Invalid Param", MB_ICONERROR ); • else if( hReturn == DPNERR_INVALIDDEVICEADDRESS ) • MessageBox( hWindow, "Failed to Host()", "Invalid Device Address", MB_ICONERROR ); • else • MessageBox( hWindow, "Failed to Host()", "DirectPlay Error", MB_ICONERROR ); • return -1; • } • // Let us know we are the host • bHost = 1; • vShowText(hLB_Output,"<- Hosting ->"); • return hReturn; • }

  37. hrCreatePlayer() • As soon as we finish the Host() function, the program receives a create player message. • This function is actually called from DirectPlayMessageHandler() • The message type is DPN_MSGID_CREATE_PLAYER

  38. Typedef struct _DPNMSGH_CREATE_PLAYER{ DWORD dwSize;//size of this structure DPNID dpnidPlayer;//DPNID of new player PVOID pvPlayerContext } DPNMSGH_CREATE_PLAYER, * PDPNMSGH_CREATE_PLAYER; • HRESULT hrCreatePlayer( PVOID pvUserContext, PVOID pMsgBuffer ) • { • HRESULT hReturn = S_OK; • PDPNMSG_CREATE_PLAYER pCreatePlayerMsg; • char strName[256]; • char szOutput[256]; • DWORD dwSize = 0; • DPN_PLAYER_INFO *pdpPlayerInfo = NULL; • int i; • // Get a Create Message pointer to the buffer • pCreatePlayerMsg = (PDPNMSG_CREATE_PLAYER)pMsgBuffer; • // Get the peer info and extract its name • hReturn = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 ); • if( FAILED(hReturn) && hReturn != DPNERR_BUFFERTOOSMALL ) { • hReturn = -1; • } • else { • // Allocate memory for the player info • pdpPlayerInfo = (DPN_PLAYER_INFO*) new BYTE[ dwSize ]; • ZeroMemory( pdpPlayerInfo, dwSize ); • pdpPlayerInfo->dwSize = sizeof(DPN_PLAYER_INFO); • // Load the player info into the newly allocated data • hReturn = g_pDP->GetPeerInfo( pCreatePlayerMsg->dpnidPlayer, pdpPlayerInfo, &dwSize, 0 ); HRESULT GetPeerInfo( const DPNID dpnid, //peer id of the one we want to get info DPN_PLAYER_INFO *const pdpnPlayerInfo, //info will be stored here DWORD *const pdwSize, //size of the returned data const DWORD dwFlags // reserved data, always zero );

  39. if( FAILED(hReturn) ) { • hReturn = -1; • } • else { • EnterCriticalSection( &g_csModifyPlayer ); • // Convert player name to ANSI • DXUtil_ConvertWideStringToGeneric( strName, pdpPlayerInfo->pwszName ); • // Add player to list • for( i = 0 ; i < MAX_PLAYERS ; i++ ) { • if( !PlayerInfo[i].bActive ) { • PlayerInfo[i].bActive = 1; • PlayerInfo[i].dpnidPlayer = pCreatePlayerMsg->dpnidPlayer; • strcpy(PlayerInfo[i].szPlayerName,strName); • break; • } • }

  40. // Check if no free slot found • if( i == MAX_PLAYERS ) { • vShowText(hLB_Output,"No free slots in game!"); • } • // Check if we are adding ourselves • else if( pdpPlayerInfo->dwPlayerFlags & DPNPLAYER_LOCAL ) { • g_dpnidLocalPlayer = pCreatePlayerMsg->dpnidPlayer; • sprintf(szOutput,"<Slot%d> Added Ourselves",i); • vShowText(hLB_Output,szOutput); • } • else { • sprintf(szOutput,"<Slot%d><%s> Is In The Game",i,strName); • vShowText(hLB_Output,szOutput); • // Send them a welcoming message if we are the host • sprintf(szOutput,"Welcome to the game, %s!",strName); • if( bHost ) { • hrSendChatMessage(i,szOutput); • } • }

  41. Clean memory Increment global var in a thread-safe way • SAFE_DELETE_ARRAY( pdpPlayerInfo ); • // Update the number of active players in a thread safe way • InterlockedIncrement( &g_lNumberOfActivePlayers ); • LeaveCriticalSection( &g_csModifyPlayer ); • } • } • return hReturn; • }

  42. hrJoinGame() in fnMessageProcessor() • HRESULT hrJoinGame( HWND hWnd ) • { • HRESULT hReturn = S_OK; • WCHAR wszHostName[256]; • WCHAR wszPeerName[256]; • char szPeerName[256]; • char szIP[256]; • char szPort[256]; • DWORD dwPort; • DWORD dwLength = 256; • DPN_APPLICATION_DESC dpnAppDesc; • DPN_PLAYER_INFO dpPlayerInfo; • vShowText(hLB_Output,"Attempting Connection..."); • // Set the peer info • GetWindowText(hEB_InputName,szPeerName,36); // Get name from Window Edit Box • DXUtil_ConvertGenericStringToWide( wszPeerName, szPeerName );

  43. ZeroMemory( &dpPlayerInfo, sizeof(DPN_PLAYER_INFO) ); • dpPlayerInfo.dwSize = sizeof(DPN_PLAYER_INFO); • dpPlayerInfo.dwInfoFlags = DPNINFO_NAME; • dpPlayerInfo.pwszName = wszPeerName; • // Make this a synchronous call • if( FAILED( hReturn = g_pDP->SetPeerInfo( &dpPlayerInfo, NULL, NULL, DPNSETPEERINFO_SYNC ) ) ) { • vShowText(hLB_Output,"Failed to set peer info"); • return -1; • } • // Prepare the application description • ZeroMemory( &dpnAppDesc, sizeof( DPN_APPLICATION_DESC ) ); • dpnAppDesc.dwSize = sizeof( DPN_APPLICATION_DESC ); • dpnAppDesc.guidApplication = DP_CHAT; • // Get IP from edit box • GetWindowText(hEB_InputServerIP,szIP,32); • // Get Port from edit box • GetWindowText(hEB_InputServerPort,szPort,6); • // Convert the IP to a wide string • DXUtil_ConvertGenericStringToWide( wszHostName, szIP ); • // Convert the port string to a DWORD • dwPort = atol(szPort);

  44. // Add host name to address • hReturn = g_pHostAddress->AddComponent(DPNA_KEY_HOSTNAME,wszHostName,(wcslen(wszHostName)+1)*sizeof(WCHAR),DPNA_DATATYPE_STRING); • if( hReturn != S_OK ) { • MessageBox( hWnd, "Failed to AddComponent()", "hrJoinGame()", MB_ICONERROR ); • return -1; • } • // Add port number to address • hReturn = g_pHostAddress->AddComponent(DPNA_KEY_PORT,&dwPort,sizeof(DWORD),DPNA_DATATYPE_DWORD); • if( hReturn != S_OK ) { • MessageBox( hWnd, "Failed to AddComponent()", "hrJoinGame()", MB_ICONERROR ); • return -1; • }

  45. 100 milliseconds timer, to signal program to check for a connection complete indicator-> so we don’t have to only loop waiting for connection • // Connect to the session • hReturn = g_pDP->Connect( &dpnAppDesc, • g_pHostAddress, • g_pDeviceAddress, • NULL, //reserved • NULL, //reserved • NULL, //optional user connect data • 0, // size of optional connect data • NULL, //optional context • NULL, //optional user-supplied context • &g_hConnectAsyncOp, //asynchronous handle • NULL); // flags • if( hReturn != E_PENDING && FAILED(hReturn) ) { • vShowText(hLB_Output,"Failed to Connect"); • return -1; • } • SetTimer( hWnd, TIMERID_CONNECT_COMPLETE, 100, NULL ); • return(hReturn); • }

  46. Joiner.. • Gets at least 2 create messages, one for the host and one for the joiner • If any other players are present, then you also get creation messages for them

  47. Player to send, -1 for all players Called in fnMessageProcessor() hrSendChatMessage() HRESULT hrSendChatMessage(int player, char *szmessage) { PACKET_CHAT msgChat; DPNHANDLE hAsync; DWORD dwLength = strlen(szmessage); DPN_BUFFER_DESC bufferDesc; // If no message to send, then just return if( dwLength == 0 ) return S_OK; // Copy the message to send into our packet strcpy(msgChat.szText,szmessage); // Set the size of the packet to send bufferDesc.dwBufferSize = sizeof(PACKET_CHAT) + dwLength; // Copy our packet into the send buffer bufferDesc.pBufferData = (BYTE*) &msgChat; // Send message to everyone including ourselves if -1 passed if( player == -1 ) g_pDP->SendTo( DPNID_ALL_PLAYERS_GROUP, &bufferDesc, 1, 0, NULL, &hAsync, 0 ); // Send to specific player otherwise else g_pDP->SendTo( PlayerInfo[player].dpnidPlayer, &bufferDesc, 1, 0, NULL, &hAsync, 0 ); return S_OK; }

  48. SendTo() HRESULT SendTo( const DPNID dpnid, //player to send to, use DPNIN_ALL_PLAYERS_GROUP // for all players DPN_BUFFER_DESC *const pBufferDesc, //the one loaded with message info const DWORD cBufferDesc, //no.of buffer you are sending DWORD dwTimeOut, // 0 for no time out void *const pvAsyncContext, //optional async context DPNHANDLE *const pAsyncHandle, //async handle const DWORD dwFlags );

  49. Flags for SendTo() • DPN_SEND_SYNC • tells the program to process the send synchronously • DPN_SEND_NOCOPY • Keeps from making an internal copy • DPN_SEND_NOCOMPLETE • Prevent DPN_MSGID_SEND_NOCOMPLETE message from being received when a message is complete • DPN_SEND_COMPLETEONPROCESS • Sends a DPN_MSGID_SEND_NOCOMPLETE message to a message handler when the message is received and processed by the target. This can greatly slow down transmission. You must use DPN_GUARANTEED with this flag • DPN_SEND_GUARANTEED • Guarantees delivery of the message. Can slow down transmission

  50. Flags for SendTo() cont… • DPN_SEND_PRIORITY_HIGH • DPN_SEND_PRIORITY_LOW • DPN_SEND_NONSEQUENTIAL • Target receives the message in order they arrive and not in order they were sent • DPN_SEND_NOLOOPBACK • Keeps you from sending a broadcast message back to yourself

More Related