📄 commmanager.cpp
字号:
/*****************************************************************************
*
* CommManager.cpp
*
* Electrical Engineering Faculty - Software Lab
* Spring semester 1998
*
* Tanks game
*
* Module description: The Communication Manager wraps the DPlay API, and
* manages the communication setting, initializing,
* termination, and messages traffic to and from the app.
*
* Authors: Eran Yariv - 28484475
* Moshe Zur - 24070856
*
*
* Date: 23/09/98
*
******************************************************************************/
#include "stdafx.h"
#include <objbase.h> // we need this or else initguid.h won't let us compile
#include <initguid.h> // including the header makes DEFINE_GUID define the GUID.
#include "Tanks.h"
#include "Client.h"
#include "Host.h"
#include "EnumSession.h"
#ifdef GATHER_NETWORK_STATS
#define SET_SESSION_START_TIME(t) {m_dwSessionStartTime=(t); \
m_dwLastSecTimeRecv = m_dwLastSecTimeSend = m_dwSessionStartTime;}
#define INC_TOTAL_BYTES_SENT(cb) m_dwTotalBytesSent+=(cb);
#define INC_TOTAL_BYTES_RECEIVED(cb) m_dwTotalBytesReceived+=(cb);
#define INC_TOTAL_CLIENT_MESSAGES_SENT m_dwTotalClientMsgsSent++;
#define INC_TOTAL_CLIENT_MESSAGES_RECEIVED m_dwTotalClientMsgsReceived++;
#define INC_TOTAL_HOST_MESSAGES_SENT m_dwTotalHostMsgsSent++;
#define INC_TOTAL_HOST_MESSAGES_RECEIVED m_dwTotalHostMsgsReceived++;
#define UPDATE_BIGGEST_PACKET_SENT(cb) m_dwBiggestSentPacketSize = max (m_dwBiggestSentPacketSize, (cb));
#define UPDATE_SMALLEST_PACKET_SENT(cb) m_dwSmallestSentPacketSize = min (m_dwSmallestSentPacketSize, (cb));
#define UPDATE_BIGGEST_PACKET_RECEIVED(cb) m_dwBiggestReceivedPacketSize = max (m_dwBiggestReceivedPacketSize, (cb));
#define UPDATE_SMALLEST_PACKET_RECEIVED(cb) m_dwSmallestReceivedPacketSize = min (m_dwSmallestReceivedPacketSize,(cb));
#define INC_CLIENT_SEND_ERRORS m_dwClientSendErrors++;
#define INC_HOST_SEND_ERRORS m_dwHostSendErrors++;
#define INC_RECEIVE_ERRORS m_dwReceiveErrors++;
#define UPDATE_RECEIVE UpdateReceive();
#define UPDATE_SEND UpdateSend();
#define TRACE_NETWORK_STATS TraceNetworkStats();
#else // !defined GATHER_NETWORK_STATS
#define SET_SESSION_START_TIME(t)
#define INC_TOTAL_BYTES_SENT(cb)
#define INC_TOTAL_BYTES_RECEIVED(cb)
#define INC_TOTAL_CLIENT_MESSAGES_SENT
#define INC_TOTAL_CLIENT_MESSAGES_RECEIVED
#define INC_TOTAL_HOST_MESSAGES_SENT
#define INC_TOTAL_HOST_MESSAGES_RECEIVED
#define UPDATE_BIGGEST_PACKET_SENT(cb)
#define UPDATE_SMALLEST_PACKET_SENT(cb)
#define UPDATE_BIGGEST_PACKET_RECEIVED(cb)
#define UPDATE_SMALLEST_PACKET_RECEIVED(cb)
#define INC_CLIENT_SEND_ERRORS
#define INC_HOST_SEND_ERRORS
#define INC_RECEIVE_ERRORS
#define UPDATE_RECEIVE
#define UPDATE_SEND
#define TRACE_NETWORK_STATS
#endif // defined GATHER_NETWORK_STATS
char TANKS_SESSION_NAME[] = "Tanks Game";
const BYTE CCommManager::ACK = 0xFF;
const DPID CCommManager::INVALID_PLAYER_ID = MAX_DWORD;
CCommManager::CCommManager() :
m_pIDP(NULL),
m_fIsConnected(FALSE),
m_fIsPlaying(FALSE),
m_fIsHost(TRUE),
m_IncomingMsgQ(TANKS_APP->m_gIncomingMsgQueue),
m_OutgoingMsgQ(TANKS_APP->m_gOutgoingMsgQueue),
m_idHost(INVALID_PLAYER_ID),
m_idPlayer(INVALID_PLAYER_ID),
m_pHost(NULL)
#ifdef GATHER_NETWORK_STATS
,
m_dwTotalBytesSent (0),
m_dwTotalBytesReceived (0),
m_dwBiggestSentPacketSize (0),
m_dwLastRecvTotal (0),
m_dwLastSentTotal (0),
m_dwSmallestSentPacketSize (MAX_DWORD),
m_dwBiggestReceivedPacketSize (0),
m_dwSmallestReceivedPacketSize (MAX_DWORD),
m_dwMaxBytesSentInLastSecond (0),
m_dwMaxBytesReceivedInLastSecond (0),
m_dwTotalClientMsgsSent (0),
m_dwTotalClientMsgsReceived (0),
m_dwClientSendErrors (0),
m_dwTotalHostMsgsSent (0),
m_dwTotalHostMsgsReceived (0),
m_dwHostSendErrors (0),
m_dwReceiveErrors (0)
#endif // GATHER_NETWORK_STATS
{
m_hRecvEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
m_hQuitEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
// Create client
m_pClient = new CClient(*this);
}
CCommManager::~CCommManager ()
{
if (m_pIDP)
m_pIDP->Release();
if (m_pClient)
delete m_pClient;
if (m_pHost)
delete m_pHost;
CloseHandle (m_hRecvEvent);
CloseHandle (m_hQuitEvent);
}
void
CCommManager::SetCommParams()
{
CCommSettingDlg dlg;
dlg.DoModal();
return;
}
/*------------------------------------------------------------------------------
Function: OnNewGame
Purpose: Initailizes the DPlay object, and starts the connection protocol w/
the server. In case this is a server machine, it also starts the
host object.
Input: None.
Output: Return TRUE if succeeded to connect to a game session.
------------------------------------------------------------------------------*/
BOOL
CCommManager::OnNewGame()
{
try {
// Create DirectPlay2 interface
CreateDPInterface();
// Start session
OpenSession();
// Create player
CreatePlayer();
} catch (CString &strErr) {
AfxMessageBox(strErr, MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//
// At last - all is well, start the message pumping:
//
// Empty both queues:
TANKS_APP->m_gOutgoingMsgQueue.Empty();
TANKS_APP->m_gOutgoingMsgQueue.Empty();
m_bLostServerConnection = FALSE;
TANKS_APP->SetMaxRTT(MAX_VALID_RTT); // Init the global max RTT param from the reg.
StartWorkerThread();
if (! m_pClient->WaitForGameProperties()) {
AfxMessageBox("Server timed out");
return FALSE;
}
return TRUE;
}
BOOL
CCommManager::OnStopGame()
{
if (m_fIsPlaying) {
// Stop the working thread:
EndThread(TRUE);
// Destroy the player object:
DestroyPlayer();
// Stop the session:
CloseSession();
}
return TRUE;
}
void
CCommManager::CreateDPInterface ()
{
LPDIRECTPLAY lpDirectPlay1 = NULL;
HRESULT hr;
//
// Get the GUID of the connection provider.
//
GUID guidCurr;
if (! TANKS_APP->GetStoredGUID(&guidCurr))
{ // Its the first run on this machine and no connection was selected.
throw CString ("No connection was selected.\n"
"Use Setting->Communication prefernces menu\n"
"to select a connection and try again.");
return;
}
//
// Release previous interface.
//
if (m_pIDP)
{
CloseSession(); // Just to make sure
m_pIDP->Release(); // Release the old interface
m_pIDP = NULL; // Prepare for a failure
}
//
// Get a new interface.
//
// Retrieve a DirectPlay 1.0 interface.
hr = DirectPlayCreate(&guidCurr, &lpDirectPlay1, NULL);
if FAILED(hr) {
TRACE("DirectPlayCreate failed HR=%ul\n", hr);
throw CString("Communication failure.\n(DirectPlayCreate failed)");
return;
}
// Query for an ANSI DirectPlay2 interface.
hr = lpDirectPlay1->QueryInterface(IID_IDirectPlay2A, (LPVOID *) &m_pIDP);
// Release DirectPlay 1.0 interface
if (lpDirectPlay1)
lpDirectPlay1->Release();
if FAILED(hr) {
TRACE("QueryInterface for IID_IDirectPlay2A failed HR=%ul\n", hr);
throw CString("Communication failure.\n"
"(QueryInterface failed)");
return;
}
}
void
CCommManager::OpenSession()
{
HRESULT hr;
DPSESSIONDESC2 SessionDesc;
// Close any exiting session.
if (m_fIsConnected)
CloseSession();
ZeroMemory(&SessionDesc, sizeof(DPSESSIONDESC2));
SessionDesc.dwSize = sizeof(DPSESSIONDESC2);
SessionDesc.guidApplication = TANKS_GUID;
// Get user choice from registry:
m_fIsHost = TANKS_APP->GetStoredIsHostFlag();
//
// Open session:
//
if (m_fIsHost)
{ // Create a new session
CString strName = TANKS_APP->GetStoredPlayerName();
SessionDesc.dwFlags = DPSESSION_KEEPALIVE |
DPSESSION_NODATAMESSAGES;
// We add one for our Host that occupies an additional player.
SessionDesc.dwMaxPlayers = MAX_TANKS + 1;
SessionDesc.lpszSessionNameA = const_cast<LPSTR>((LPCSTR)strName);
hr = m_pIDP->Open(&SessionDesc, DPOPEN_CREATE);
if FAILED(hr) {
throw CString("Cannot create new session");
return;
}
// Create the host object:
m_CSHost.Lock();
m_pHost = new CHost(*this);
if (! m_pHost)
{
m_CSHost.Unlock();
throw CString("Cannot create new session");
return;
}
m_CSHost.Unlock();
}
else
{
//
// Let user select a session.
//
DPSESSIONDESC2 dpDesc;
ZeroMemory(&dpDesc, sizeof(DPSESSIONDESC2));
dpDesc.dwSize = sizeof(DPSESSIONDESC2);
dpDesc.guidApplication = TANKS_GUID;
// Bring the select session dialog.
CEnumSession dlg(m_pIDP, &dpDesc.guidInstance);
if (IDOK != dlg.DoModal())
{ // User aborted or EnumSession failed.
throw CString("No session selected");
return;
}
// Join the session:
hr = m_pIDP->Open(&dpDesc, DPOPEN_JOIN);
if FAILED(hr) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -