📄 commmanager.cpp
字号:
throw CString("Cannot join session");
return;
}
}
/* The remarked code was used to check if its a TCP/IP connection.
// Check the session is supporting guarentied delivery:
ZeroMemory(&m_SessionCaps, sizeof(DPCAPS));
m_SessionCaps.dwSize = sizeof(DPCAPS);
hr = m_pIDP->GetCaps(&m_SessionCaps, DPGETCAPS_GUARANTEED);
if (FAILED(hr) ||
! (m_SessionCaps.dwFlags & DPCAPS_GUARANTEEDSUPPORTED)) {
// We don't support the connection chosen by user:
m_pIDP->Close();
throw CString("The connection selected isn't supported.\n"
"Select another connection\nand try again");
return;
}
*/
m_fIsConnected = TRUE;
SET_SESSION_START_TIME (GetTickCount());
}
void
CCommManager::CloseSession()
{
HRESULT hr;
if (m_fIsConnected) {
m_fIsConnected = FALSE;
if (m_fIsHost) {
m_pIDP->DestroyPlayer(m_idHost);
ASSERT (m_pHost);
m_CSHost.Lock();
delete m_pHost;
m_pHost = NULL;
m_CSHost.Unlock();
}
m_idHost = INVALID_PLAYER_ID;
hr = m_pIDP->Close();
if FAILED(hr)
{
TRACE("DirectPlay Close() session failed HR=%ul\n", hr);
throw CString("Communication failure.\nFailed to close session");
return;
}
TRACE_NETWORK_STATS;
}
}
void
CCommManager::CreatePlayer()
{
HRESULT hr;
DPNAME dpName;
ASSERT (! m_fIsPlaying); // We shouldn't be here if we are playing!!
// Check the RecvEvent handle:
if (! m_hRecvEvent) {
throw CString("Cannot create player:\nReceive event is null");
return;
}
// Create host's player object:
if (m_fIsHost) {
ZeroMemory (&dpName, sizeof(DPNAME));
dpName.dwSize = sizeof(DPNAME);
dpName.lpszShortNameA = "Host";
hr = m_pIDP->CreatePlayer(&m_idHost, &dpName, m_hRecvEvent, NULL, 0, 0);
if FAILED(hr) {
TRACE ("CreatePlayer failed HR=%ul\n", hr);
throw CString("Communication failure.\nCannot create host player");
return;
}
}
// Get user name:
CString strPlayerName = TANKS_APP->GetStoredPlayerName();
ZeroMemory (&dpName, sizeof(DPNAME));
dpName.dwSize = sizeof(DPNAME);
dpName.lpszLongNameA =
dpName.lpszShortNameA = const_cast<char*>((LPCSTR)strPlayerName);
// Try to create player object:
hr = m_pIDP->CreatePlayer(&m_idPlayer, &dpName, m_hRecvEvent, NULL, 0, 0);
if FAILED(hr) {
TRACE ("CreatePlayer failed HR=%ul\n", hr);
throw CString("Communication failure.\n"
"Cannot create client player");
return;
}
m_pIDP->SetPlayerData (
m_idPlayer,
dpName.lpszLongNameA,
strPlayerName.GetLength() + 1,
DPSET_REMOTE | DPSET_GUARANTEED);
m_fIsPlaying = TRUE;
}
void
CCommManager::DestroyPlayer()
{
if (m_fIsPlaying) {
m_fIsPlaying = FALSE;
m_pIDP->DestroyPlayer(m_idPlayer);
m_idPlayer = INVALID_PLAYER_ID;
}
}
/*------------------------------------------------------------------------------
Function: ThreadEntry
Purpose: Main message loop. Thread is waiting for signals from outgoing and
incoming queues and when signaled delivers messages to their destination.
Input: None.
Output: None.
Remarks: Incoming messages are dispatched to host or client objects to be
processed.
All outgoing messages are sent to the host machine.
------------------------------------------------------------------------------*/
UINT
CCommManager::ThreadEntry (LPVOID /*pParam*/)
{
#define WAIT_OBJECT_1 (WAIT_OBJECT_0 + 1)
#define WAIT_OBJECT_2 (WAIT_OBJECT_1 + 1)
HRESULT hr;
HANDLE aHandles[3];
// Check the QuitEvent handle:
if (! m_hQuitEvent) {
ASSERT(m_hQuitEvent);
return 1;
}
// Attempt to create the enqueue event:
HANDLE hEnqueueEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
if (! hEnqueueEvent) {
ASSERT(hEnqueueEvent);
return 1;
}
// Ask the incoming message queue to set the enqueue event on every enqueue.
m_OutgoingMsgQ.SetNotificationEvent (hEnqueueEvent);
aHandles[0] = m_hRecvEvent;
aHandles[1] = hEnqueueEvent;
aHandles[2] = m_hQuitEvent;
SetPriority (COMM_MANAGER_THREAD_PRIORITY);
while (! m_bEndThread) {
DWORD nResult = WaitForMultipleObjects(3, aHandles, FALSE, INFINITE);
switch (nResult) {
case WAIT_OBJECT_0: // new message arrived (from the network):
{
DWORD dwMsgCount = 0;
DWORD dwHostMsgCount = 0;
// Get messages for both players:
hr = m_pIDP->GetMessageCount(m_idPlayer, &dwMsgCount);
if FAILED(hr)
break;
if (m_fIsHost)
{ // Also host message may exist
hr = m_pIDP->GetMessageCount(m_idHost, &dwHostMsgCount);
if FAILED(hr)
break;
}
for (UINT i = 0; i < dwHostMsgCount + dwMsgCount; i++) {
m_Message.m_dwLength = CCommMessage::MAX_BUFFER_LENGTH;
hr = m_pIDP->Receive(&m_idFrom, &m_idTo, DPRECEIVE_ALL,
m_Message.m_aBuffer, &m_Message.m_dwLength);
if SUCCEEDED(hr)
{
if (m_idTo == m_idPlayer)
{ // New message for the player (client)
HandleClientMessage ();
INC_TOTAL_CLIENT_MESSAGES_RECEIVED;
}
else if (m_fIsHost && m_idTo == m_idHost)
{ // New message for the host
HandleHostMessage();
INC_TOTAL_HOST_MESSAGES_RECEIVED;
}
else
ASSERT (FALSE);
INC_TOTAL_BYTES_RECEIVED (m_Message.m_dwLength);
UPDATE_BIGGEST_PACKET_RECEIVED (m_Message.m_dwLength);
UPDATE_SMALLEST_PACKET_RECEIVED(m_Message.m_dwLength);
UPDATE_RECEIVE;
} // End of successful message received
else
{
INC_RECEIVE_ERRORS;
}
}
}
break;
case WAIT_OBJECT_1: // new message to send (from the outgoing queue):
{
CMessage msg;
// Empty outgoing queue:
for (int count = m_OutgoingMsgQ.GetQueueSize(); count > 0; count--)
{
// Get uncompressed message:
if (! m_OutgoingMsgQ.Dequeue(msg))
// TODO: although we were signaled after enqueue, we still encounter
// empty Q occasionly.
break;
// Send message over net to game host:
m_Message.m_dwLength = msg.GetBuffer(m_Message.m_aBuffer);
#if defined (NET_MON_SYNC) || defined (NET_MON_GAME)
if (msg.GetType() != CMessage::CHECK_SUM) // Not checksum message
{
NET_GAME_TRACE (("Client sending to host %s, size=%d (msg time = %d), game time = %d",
msg.GetName(), m_Message.m_dwLength, msg.GetTime(),
TANKS_APP->m_gTimer.GetLocalTime()))
}
else
{
NET_SYNC_TRACE (("Client sending checksum to host, size=%d (game time = %d)",
m_Message.m_dwLength, msg.GetTime()));
}
#endif // defined (NET_MON_SYNC) || defined (NET_MON_GAME)
HRESULT hr = m_pIDP->Send( m_idPlayer,
m_idHost,
DPSEND_GUARANTEED,
m_Message.m_aBuffer,
m_Message.m_dwLength);
if (!SUCCEEDED(hr))
{ // Can't send message
TRACE ("\tERROR: Client cannot send message to host !!!\n");
INC_CLIENT_SEND_ERRORS;
}
else
{ // Message sent successfully
INC_TOTAL_BYTES_SENT (m_Message.m_dwLength);
INC_TOTAL_CLIENT_MESSAGES_SENT;
UPDATE_BIGGEST_PACKET_SENT (m_Message.m_dwLength);
UPDATE_SMALLEST_PACKET_SENT (m_Message.m_dwLength);
UPDATE_SEND;
}
} // End while
} // End case block
break;
case WAIT_OBJECT_2: // we should quit thread:
m_bEndThread = TRUE;
break;
case WAIT_FAILED: {
CString strErr;
strErr.Format("CommManager thread failed with error code: %08X",
GetLastError());
AfxMessageBox(strErr);
}
default:
m_bEndThread = TRUE;
}
} // end of major comm. manager loop
// Ask the incoming message queue to stop setting the enqueue event on every enqueue.
m_OutgoingMsgQ.SetNotificationEvent (NULL);
// Terminate the enqueue event
CloseHandle (hEnqueueEvent);
return 0;
}
void
CCommManager::HandleClientMessage()
{
// First lets take care of system msgs, such as NEWPLAYER..
if (DPID_SYSMSG==m_idFrom)
{
switch (((DPMSG_GENERIC*)&m_Message.m_aBuffer[0])->dwType)
{
case DPSYS_CREATEPLAYERORGROUP: // a new player is joining
// Store player name in the array (where ?)
NET_SYS_TRACE (("Client got Create player or group (player ID = %d)",
((DPMSG_CREATEPLAYERORGROUP*)m_Message.m_aBuffer)->dpId));
break;
case DPSYS_DESTROYPLAYERORGROUP:
if (((DPMSG_DESTROYPLAYERORGROUP*)&m_Message.m_aBuffer[0])->dpId == m_idHost)
{ // this means the host closed the session
DisplayMessageAndEndGame (IDS_LOST_SEVER_CONNECTION);
}
NET_SYS_TRACE (("Client got Destroy player or group (player id = %d",
((DPMSG_DESTROYPLAYERORGROUP*)&m_Message.m_aBuffer[0])->dpId));
break;
case DPSYS_SESSIONLOST: // We can't proceed playing - stop game:
DisplayMessageAndEndGame (IDS_LOST_SEVER_CONNECTION);
NET_SYS_TRACE (("Client got session lost"));
break;
default:
// Disregard other DirectPlay system messages
NET_SYS_TRACE (("Client got unhandled message (Msg ID = %d)",
((DPMSG_GENERIC*)&m_Message.m_aBuffer[0])->dwType));
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -