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

📄 host.cpp

📁 分布式坦克游戏
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    // Pack message to buffer:
    m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
    // Send to last reporter:
    ReplyToSender();
}

void
CHost::SendRemoveTank(int iTankID)
{
    CMessage::MessageData MsgData;

    MsgData.TankRemoveParam.ID = BYTE(iTankID);
    MsgData.TankRemoveParam.Explode = TRUE;
    // Compose message from data:
    CMessage Msg(CMessage::REMOVE_TANK, MsgData, SERVER_MSG);
    // Pack message to buffer:
    m_Message.m_dwLength = Msg.GetBuffer(m_Message.m_aBuffer);
    // Send to last reporter:
    ReplyToSender();
}

void CHost::SendMinesStatus(int iSector)
{
    /*  NOTICE: This is a special case. Since the information on all the mines in
        a given sector is of variable length and may get very big, we don't construct
        a structure for it in the MessageData union like we do for all the other
        message type.
        Instead, we make the encoding in-place directly to the DPlay output buffer
        (using a static member function of CMessage) and don't keep any message structure.
    */
    DWORD AllMinesInSector[MAX_MINES_PER_SECTOR];

    // Fill array of positions with the data of all the existing mines in the given sector
    DWORD dwMinesFound = m_GameManager.GetMinesInSector (iSector, AllMinesInSector);

    m_Message.m_aBuffer[0] = CMessage::SET_MINES;   // Set message type in 1st byte
 
    m_Message.m_dwLength = 1 +  // The message type takes 1 byte
        CMessage::EncodeSectorMines (&m_Message.m_aBuffer[1],  
                                     iSector, 
                                     dwMinesFound, 
                                     AllMinesInSector);
    // Send to last reporter:
    ReplyToSender();
}


void
CHost::PlayerJoinsGame (UINT uID)
{
    memset (&m_PlayersRTT[uID], 0, sizeof (PlayerRTT));
    m_PlayersRTT[uID].dwPlayerJoinTime  = 
    m_PlayersRTT[uID].dwLastMsgTime     = GetTickCount();
    m_PlayersRTT[uID].dwPlayerMinRTT = MAX_DWORD; 
    ZERO_TANK_SYNC_STATS (uID);
}

/*------------------------------------------------------------------------------

  Function: UpdatePlayerRTT

  Purpose:  Calculates the round trip time from our host to the reporting player.
            Check if the zombie status should be updated.

  Input:    dwMsgTime - the time stamp of the message

  Output:   None.

  Remarks:  A tank becomes zombie if 5 sequential messages have RTT larger then
            the maximal allowed (this parameter is configurable via the 
            registry, and is set to 1.5 sec. by default).


------------------------------------------------------------------------------*/
void 
CHost::UpdatePlayerRTT (DWORD dwMsgTime)
{
    int i = LookupTankID (m_idFrom);
    if (0 > i)
        // Tank ID not associated yet   
        return;

    DWORD dwNow = m_Timer.GetLocalTime();
    DWORD dwCurLat = (dwNow >= dwMsgTime) ?
        (dwNow - dwMsgTime) : (dwMsgTime - dwNow);

    m_PlayersRTT[i].dwLastMsgTime = dwNow;
    m_PlayersRTT[i].dwPlayerCurRTT = dwCurLat;
    
    // TRACE ("          Now = %d, MsgTime = %d,  RTT = %d\n", dwNow, dwMsgTime, dwCurLat);

#ifdef GATHER_SYNC_STATS
    m_PlayersRTT[i].dwPlayerMaxRTT = max (
        m_PlayersRTT[i].dwPlayerMaxRTT, dwCurLat);
    m_PlayersRTT[i].dwPlayerMinRTT = min (
        m_PlayersRTT[i].dwPlayerMinRTT, dwCurLat);
    m_PlayersRTT[i].dwPlayerTotalRTTs += dwCurLat;
    m_PlayersRTT[i].dwTotMsgs++;
    m_PlayersRTT[i].adwPlayerRTTCounts[min (7, dwCurLat >> 7)]++;
    m_PlayersRTT[i].adwPlayerRTTTotals[min (7, dwCurLat >> 7)] += dwCurLat;
#endif // GATHER_SYNC_STATS

    //
    // Check for zombies:
    //
    BOOL bZombie = m_JudgeViewOfTanks[i].Zombie;    // Store current state

    if (m_JudgeViewOfTanks[i].Zombie)
    {   // Check if zombie's condition is improving:
        if (dwCurLat < TANKS_APP->GetMaxRTT())                   // RTT is valid again
        {
            if (m_JudgeViewOfTanks[i].LastRTTWasGood)   // if the former one was too -
                m_JudgeViewOfTanks[i].BadRTTCount--;    // dec. counter, or else
            else                                        // reset counter as we begin a new series
                m_JudgeViewOfTanks[i].BadRTTCount = MAX_BAD_RTT_COUNT - 1;
        }
        // If there were MAX_BAD_RTT_COUNT good RTTs in a row - 
        // tank is back in business:
        if (m_JudgeViewOfTanks[i].BadRTTCount <= 0)
        {
            m_JudgeViewOfTanks[i].BadRTTCount = 0;
            bZombie = FALSE;
        }
    } else
    {   // Check if tank needs to become zombie:
        if (dwCurLat > TANKS_APP->GetMaxRTT())                       // RTT is too big
        {
            if (! m_JudgeViewOfTanks[i].LastRTTWasGood)     // if the former one was too
                m_JudgeViewOfTanks[i].BadRTTCount++;        // inc. counter, or else
            else                                            // reset counter as a new series starts
                m_JudgeViewOfTanks[i].BadRTTCount = 1;
        }
        // If there were MAX_BAD_RTT_COUNT bad RTTs in a row - 
        // tank is out of business:
        if (m_JudgeViewOfTanks[i].BadRTTCount >= MAX_BAD_RTT_COUNT)
        {
            bZombie = TRUE;
        }
    }
    // Update last RTT evaluation:
    m_JudgeViewOfTanks[i].LastRTTWasGood = (dwCurLat < TANKS_APP->GetMaxRTT());
    
    if (bZombie != m_JudgeViewOfTanks[i].Zombie)    // There is a status change:
    {
        m_JudgeViewOfTanks[i].Zombie = bZombie;

        if (bZombie)
        {
            INC_ZOMBIE_IN (i)
        }
        else
        {
            INC_ZOMBIE_OUT (i)
        }
        NET_SYNC_TRACE (("Tank %d is %s zombie: "
                         "current latency = %d (max = %d),"
                         " bad RTT count = %d\n",
                         i, 
                         bZombie ? "becoming" : "stopping being", 
                         dwCurLat, 
                         m_PlayersRTT[i].dwPlayerMaxRTT,
                         m_JudgeViewOfTanks[i].BadRTTCount));
        SendTankZombie (i, bZombie, TRUE /* Send to all */);
    }

}

/*------------------------------------------------------------------------------

  Function: ChkForZombies

  Purpose:  Another zombie check - this method is called by the game manager 
            every iteration, to check for tanks that have stopped reporting for
            a long period of time (MAX_COMM_MUTE_PERIOD)

  Input:    None.

  Output:   None.

  Remarks:  
------------------------------------------------------------------------------*/
void
CHost::ChkForZombies()
{
    DWORD dwNow = m_Timer.GetLocalTime();

    for (int i = 0; i < MAX_TANKS; i++)
    {
        if (CCommManager::INVALID_PLAYER_ID == m_aPlayersID[i])
            continue;
        // Check if time of last message from tank[i] arrived in reasonable time:
        if (((dwNow - m_PlayersRTT[i].dwLastMsgTime) > MAX_COMM_MUTE_PERIOD) &&
            !m_JudgeViewOfTanks[i].Zombie)
        {   // This player wasn't heard for too long time:
            m_JudgeViewOfTanks[i].Zombie = TRUE;
            INC_ZOMBIE_IN (i)

            NET_SYNC_TRACE (("Tank %d is becoming zombie"
                             " - last message arrived %d millisecs ago.\n",
                             i, dwNow - m_PlayersRTT[i].dwLastMsgTime));
                    
            SendTankZombie (i, TRUE, TRUE /* Send to all */);
        }
    }
}


BOOL 
CHost::GetPlayerInfo (UINT ind, DWORD &dwDuration, DWORD &dwRTT)
{
    ASSERT (ind < MAX_TANKS);
    if (CCommManager::INVALID_PLAYER_ID == m_aPlayersID[ind])
        return FALSE;   // Player not playing now
    dwDuration = GetTickCount() - m_PlayersRTT[ind].dwPlayerJoinTime;
    dwRTT = m_PlayersRTT[ind].dwPlayerCurRTT;
    return TRUE;
}

DPID
CHost::GetDirectPlayID (UINT uPlayerID)
{
    ASSERT (uPlayerID < MAX_TANKS);
    return m_aPlayersID[uPlayerID];
}


#ifdef GATHER_SYNC_STATS

void 
CHost::ZeroTankSyncStats (UINT uTankID)
{
    TRACE ("\tTank #%d is joining session, starting sync statistics for it.\n", uTankID);
    memset (&m_TanksSyncStats[uTankID], 0, sizeof (TankSyncStats));
    m_TanksSyncStats[uTankID].dwSmallestTimeGap = MAX_DWORD;
    m_TanksSyncStats[uTankID].dwStartTime = GetTickCount();
}

void 
CHost::PrintTankSyncStats (UINT uTankID)
{
    TRACE ( "\n\n\t\t\t**** Game sync statistics for tank %d ****\n",
                uTankID);
    TRACE ( "Total time player %d was active = %.3f secs\n",
                uTankID,
                double(GetTickCount() - m_TanksSyncStats[uTankID].dwStartTime) / 1000.0);
    TRACE ( "Sync messages arriving from tank %d = %d\n",
                uTankID, m_TanksSyncStats[uTankID].dwSyncMsgsArrived);
    TRACE ("Average size of sync message = %d\n",
                m_TanksSyncStats[uTankID].dwSyncMsgsArrived ?
                (uTankID, m_TanksSyncStats[uTankID].dwTotSyncMsgSize / 
                 m_TanksSyncStats[uTankID].dwSyncMsgsArrived) : 0);
    TRACE ( "Sync mismatches:\n");
    TRACE ( "\tBonus = %d, Mines = %d, Zombie = %d\n",
                m_TanksSyncStats[uTankID].dwBonusMismatch,
                m_TanksSyncStats[uTankID].dwMinesMismatch,
                m_TanksSyncStats[uTankID].dwZombieMismatch);
    TRACE ( "\tTanks status = %d\n",
                m_TanksSyncStats[uTankID].dwOtherTankStatusMismatch);
    TRACE ( "\tMissing tanks = %d, Extra tanks = %d\n",
                m_TanksSyncStats[uTankID].dwMissingTanks,
                m_TanksSyncStats[uTankID].dwExtraTanks);
    TRACE ( "Zombie:\n");
    TRACE ( "\tTank became zombie %d times, and came back alive %d times.\n",
                m_TanksSyncStats[uTankID].dwZombieIn,
                m_TanksSyncStats[uTankID].dwZombieOut);
    TRACE ( "Sync msgs timing:\n");
    TRACE ( "\tTime gap between reports: min = %d millisecs, max = %d, avg = %d\n",
                m_TanksSyncStats[uTankID].dwSmallestTimeGap,
                m_TanksSyncStats[uTankID].dwBiggestTimeGap,
                m_TanksSyncStats[uTankID].dwTotalGapsCnt ?
                    DWORD(double(m_TanksSyncStats[uTankID].dwTotalGaps) / 
                          double(m_TanksSyncStats[uTankID].dwTotalGapsCnt)) : 0);

    DWORD dwAvg = m_PlayersRTT[uTankID].dwPlayerTotalRTTs ? 
        DWORD(double(m_PlayersRTT[uTankID].dwPlayerTotalRTTs) /
              double(m_PlayersRTT[uTankID].dwTotMsgs)) : 0;

    TRACE ( "Round Trip Times:\n");
    TRACE ( "\tMax = %d msecs, Min = %d msecs , Avg = %d msecs\n",
                m_PlayersRTT[uTankID].dwPlayerMaxRTT,
                m_PlayersRTT[uTankID].dwPlayerMinRTT,
                dwAvg);
    TRACE ( "\tRTT histogram:\n" );
    for (int i = 0; i < sizeof(m_PlayersRTT[uTankID].adwPlayerRTTCounts) /
        sizeof (m_PlayersRTT[uTankID].adwPlayerRTTCounts[0]) - 1; i++)
    {
        TRACE ( "\tRTT between %d and %d was counted %d times (Avg = %d)\n",
            i << 7, 
            ((i + 1) << 7) - 1, 
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i],
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i] ?
            m_PlayersRTT[uTankID].adwPlayerRTTTotals[i] /
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i] : 0);
    }
    TRACE ( "\tRTT above %d was counted %d times (Avg = %d)\n\n",
            i << 7,
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i],
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i] ?
            m_PlayersRTT[uTankID].adwPlayerRTTTotals[i] /
            m_PlayersRTT[uTankID].adwPlayerRTTCounts[i] : 0);

    UNREFERENCED_PARAMETER(uTankID);
}

void 
CHost::UpdateSyncMsgTime (UINT uTankID)
{
    if (!m_TanksSyncStats[uTankID].dwLastReportTime)
    {   // First time around
        m_TanksSyncStats[uTankID].dwLastReportTime = GetTickCount();
        m_TanksSyncStats[uTankID].dwTotalGapsCnt = 0;
        m_TanksSyncStats[uTankID].dwTotalGaps = 0;
        return;
    }
    DWORD dwNow = GetTickCount();
    DWORD dwTimeGap = dwNow - m_TanksSyncStats[uTankID].dwLastReportTime;
    m_TanksSyncStats[uTankID].dwLastReportTime = dwNow;
    m_TanksSyncStats[uTankID].dwSmallestTimeGap = min (dwTimeGap,
        m_TanksSyncStats[uTankID].dwSmallestTimeGap);
    m_TanksSyncStats[uTankID].dwBiggestTimeGap = max (dwTimeGap,
        m_TanksSyncStats[uTankID].dwBiggestTimeGap);
    m_TanksSyncStats[uTankID].dwTotalGaps += dwTimeGap;
    m_TanksSyncStats[uTankID].dwTotalGapsCnt++;
}


#endif // defined GATHER_SYNC_STATS

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -