client.cpp
上传用户:royluo
上传日期:2007-01-05
资源大小:1584k
文件大小:9k
源码类别:

游戏

开发平台:

Visual C++

  1. /*****************************************************************************
  2. *                                                                             
  3. *   Client.cpp                                                            
  4. *                                                                             
  5. *   Electrical Engineering Faculty - Software Lab                             
  6. *   Spring semester 1998                                                      
  7. *                                                                             
  8. *   Tanks game                                                                
  9. *                                                                             
  10. *   Module description: Implements the client handling of network messages.
  11. *                       
  12. *                                                                             
  13. *   Authors: Eran Yariv - 28484475                                           
  14. *            Moshe Zur  - 24070856                                           
  15. *                                                                            
  16. *                                                                            
  17. *   Date: 23/09/98                                                           
  18. *                                                                            
  19. ******************************************************************************/
  20. #include "stdafx.h"
  21. #include "Tanks.h"
  22. #include "Client.h"
  23. #include "TanksDlg.h"
  24. CClient::CClient (CCommManager &CommManager) : 
  25.     m_CommManager(CommManager),
  26.     m_IncomingMsgQ(TANKS_APP->m_gIncomingMsgQueue),
  27.     m_GameManager(TANKS_APP->m_gGameManager),
  28.     m_Message(CommManager.ExposeMessage())
  29. {
  30.     m_hHostIDEvent          = CreateEvent (NULL, FALSE, FALSE, NULL);
  31.     m_hAddLocalTankEvent    = CreateEvent (NULL, FALSE, FALSE, NULL);
  32.     m_hAddBoardEvent        = CreateEvent (NULL, FALSE, FALSE, NULL);
  33. }
  34. CClient::~CClient ()
  35. {
  36.     CloseHandle (m_hHostIDEvent);
  37.     CloseHandle (m_hAddLocalTankEvent);
  38.     CloseHandle (m_hAddBoardEvent);
  39. }
  40. /*------------------------------------------------------------------------------
  41.   Function: WaitForGameProperties
  42.   Purpose:  Called when the client begins a new game, to negotiate with the game
  43.             host and retrieve the game properties - player's tank ID and game 
  44.             board properties.
  45.   Input:    None.
  46.   Output:   Return TRUE on success.
  47.   Remarks:  The DirectPlay::CreatePlayer method is send to the game host w/o 
  48.             knowing it's DirectPlay player ID. The "protocol" we are using to 
  49.             negotiate w/ the host for the game properties is also responsible
  50.             for generating the host player ID (to be used when sending messages)
  51. ------------------------------------------------------------------------------*/
  52. BOOL
  53. CClient::WaitForGameProperties()
  54. {
  55.     // Wait for Host ID to arrive as response to our CreatePlayer msg:
  56.     int nResponse = WaitForSingleObject(m_hHostIDEvent, COMM_TIME_OUT);
  57.     if (WAIT_OBJECT_0 != nResponse)
  58.         return FALSE;
  59.         // At this stage we know that m_idHost is valid.
  60.     // Send Request for Tank ID
  61.     CMessage::MessageData Params;
  62.         // Request new tank:
  63.     UINT uTankID = TANKS_APP->GetStoredPreferedTankID();
  64.     Params.TankRequestParam.bID = BYTE(uTankID);
  65.     TANKS_APP->m_gOutgoingMsgQueue.Enqueue (CMessage::REQUEST_TANK, Params);
  66.     // Wait for AddTank and AddBoard to arrive
  67.     HANDLE aHandles[2] = { m_hAddLocalTankEvent, m_hAddBoardEvent };
  68.     nResponse = WaitForMultipleObjects (2, aHandles, TRUE, COMM_TIME_OUT);
  69.     return (WAIT_TIMEOUT != nResponse);
  70. }
  71. /*------------------------------------------------------------------------------
  72.   Function: HandleMessage
  73.   Purpose:  Handles the messages send from the game host to our client.
  74.   Input:    None.
  75.   Output:   None.
  76.   Remarks:  1. The message is stored in the CommManager to reduce stack 
  77.                operations.
  78.             2. We treat a client on the host machine the same as a remote 
  79.                client (thanks to the help of DirectPlay abstraction...)
  80. ------------------------------------------------------------------------------*/
  81. void
  82. CClient::HandleMessage()
  83. {
  84.     // Check if that's our host saying ACK:
  85.     if ((1==m_Message.m_dwLength) && (CCommManager::ACK==m_Message.m_aBuffer[0])) 
  86.     {   // Notify our CommManager of the Host ID (current m_idFrom):
  87.         m_CommManager.SetHostID();
  88.         // We can release the WaitForGameProperties method from it's wait:
  89.         SetEvent(m_hHostIDEvent);
  90.         NET_GAME_TRACE (("Client got ping from host"));
  91.         // Nothing else left to do here, the rest is done in GetGameProperties:
  92.         return;
  93.     }
  94.     if (CMessage::SET_MINES == m_Message.m_aBuffer[0])
  95.     {   // Special case: host sending mines per sector information - variable
  96.         // lenght message that may be very big !!!
  97.         DWORD AllMinesInSector[MAX_MINES_PER_SECTOR];
  98.         int iSector;
  99.         // Retrieve array of positions with the data of all the existing mines 
  100.         // in the given sector:
  101.         DWORD dwMinesFound = CMessage::DecodeSectorMines (&(m_Message.m_aBuffer[1]),
  102.                                                           m_Message.m_dwLength - 1,
  103.                                                           iSector, 
  104.                                                           AllMinesInSector);
  105.         // Tell the local game manager the correct mines setting in the sector.
  106.         // Do it now - don't use any queue: this message if it was put in a queue,
  107.         // would get very big - we don't want to waste that space.
  108.         m_GameManager.SetMinesInSector (iSector, dwMinesFound, AllMinesInSector);
  109.         return;
  110.     }
  111.     CMessage *pMsg =  new CMessage(m_Message.m_aBuffer, 
  112.                         (BYTE)m_Message.m_dwLength, PLAYER_MSG);
  113.     ASSERT(pMsg);
  114.     if (!pMsg)
  115.     {
  116.         AfxMessageBox(IDS_OUTOFMEMORY_ERR, MB_ICONSTOP | MB_OK, 0);
  117.         abort();
  118.     }
  119.     switch (pMsg->GetType())
  120.     {   // Catch special messages and handle accordingly:
  121.         case CMessage::ADD_BOARD:
  122.             // We should catch the 2 initializing messages, 
  123.             // to end GetGameProperties:
  124.             NET_GAME_TRACE (("Client got ADD_BOARD from host (game time = %d)",
  125.                 pMsg->GetTime ()));
  126.             SetEvent(m_hAddBoardEvent);
  127.             break;
  128.         case CMessage::ADD_TANK:
  129.             NET_GAME_TRACE (("Client got ADD_TANK (%s) from host "
  130.                 "(game time = %d)",
  131.                 pMsg->m_UnionData.TankParam.Local ? "local" : "remote", 
  132.                 pMsg->GetTime ()));
  133.             if (pMsg->m_UnionData.TankParam.Local)
  134.                 SetEvent(m_hAddLocalTankEvent);
  135.             break;
  136.         case CMessage::MANOUVER_SET:
  137.             NET_GAME_TRACE (("Client got MANOUVER_SET from host"
  138.                 "(game time = %d)", pMsg->GetTime ()));
  139.             // We should copy the manouver set of the sending tank to the 
  140.             // global array:
  141.             CopyManouverSet();
  142.             // We don't enqueue the message, so we have delete the 
  143.             // message manually:
  144.             delete pMsg;
  145.             // This message isn't handled by the game manager - 
  146.             // we should return before the enqueue:
  147.             return;
  148.         case CMessage::CHAT:
  149.             // Update chat dialog
  150.             ((CTanksDlg*)TANKS_APP->m_pMainWnd)->MarshalChatMsg(
  151.                 pMsg->m_UnionData.ChatParam.idFrom,
  152.                 pMsg->m_UnionData.ChatParam.TankID,
  153.                 pMsg->m_UnionData.ChatParam.Msg);
  154.             delete pMsg;
  155.             // This message isn't handled by the game manager - 
  156.             // we should return before the enqueue:
  157.             return;
  158.         default:
  159.             NET_GAME_TRACE (("Client got message %s from host "
  160.                             "(game time = %d)", 
  161.                             pMsg->GetName(), pMsg->GetTime ()));
  162.             break;
  163.     }
  164.     // At last, we put the message (as is) in the queue towards the 
  165.     // game manager:
  166.     m_IncomingMsgQ.Enqueue(pMsg, TRUE);
  167. }
  168. void
  169. CClient::CopyManouverSet()
  170. {
  171.     // Copy the manouver set from message to global manouver set array
  172.     CMessage Msg (m_Message.m_aBuffer, (BYTE)m_Message.m_dwLength, PLAYER_MSG);
  173.     // Set manouver set:
  174.     TANKS_APP->m_gManouverSets[Msg.m_UnionData.ManouverSetParam.TankID].SetAll(
  175.         Msg.m_UnionData.ManouverSetParam.ManouverSet);
  176.     // Set last direction:
  177.     TANKS_APP->m_guRemoteTanksDirs[Msg.m_UnionData.ManouverSetParam.TankID] =
  178.         Msg.m_UnionData.ManouverSetParam.Direction;
  179. }