⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 commmanager.cpp

📁 分布式坦克游戏
💻 CPP
📖 第 1 页 / 共 3 页
字号:
            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 + -