📄 commmanager.cpp
字号:
return;
}
m_pClient->HandleMessage();
}
void
CCommManager::HandleHostMessage()
{
// 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
DPID idFrom = ((DPMSG_CREATEPLAYERORGROUP*)m_Message.m_aBuffer)->dpId;
NET_SYS_TRACE (("Server got Create player or group (player ID = %d)",idFrom));
if (idFrom==m_idHost) // We received new player about our own object
return;
// Respond with ACK:
m_Message.m_aBuffer[0] = ACK;
m_Message.m_dwLength = 1;
SendAsHost(idFrom); // As host
}
break;
case DPSYS_DESTROYPLAYERORGROUP:
{ // a player just left the session:
DPID idFrom = ((DPMSG_CREATEPLAYERORGROUP*)m_Message.m_aBuffer)->dpId;
NET_SYS_TRACE (("Server got Destroy player or group (player ID = %d)",idFrom));
// Notify other players ?
// Remove the ID from the array:
m_CSHost.Lock();
m_pHost->RemovePlayerFromArray(idFrom);
m_CSHost.Unlock();
}
break;
case DPSYS_SESSIONLOST: // We can't proceed playing - stop game:
NET_SYS_TRACE (("Server got Session lost"));
DisplayMessageAndEndGame (IDS_LOST_SEVER_CONNECTION);
break;
default:
// Disregard other DirectPlay system messages
NET_SYS_TRACE (("Server got unhandled message (Msg ID = %d)",
((DPMSG_GENERIC*)&m_Message.m_aBuffer[0])->dwType));
break;
}
return;
}
m_CSHost.Lock();
m_pHost->HandleMessage( m_idFrom, // Send the player ID of the sender
m_idFrom == m_idPlayer);// If this is the local player, it's the judge
m_CSHost.Unlock();
}
void
CCommManager::SendAsHost(DPID idTo)
{
ASSERT (m_pIDP);
// Always called by host:
NET_GAME_TRACE (("Host sending %s to player ID %d (size=%d) at time %lu, msg.time=%lu",
CMessage::GetName (m_Message.m_aBuffer[0]),
idTo,
m_Message.m_dwLength,
TANKS_APP->m_gTimer.GetLocalTime(),
*((PDWORD)&m_Message.m_aBuffer[1])));
HRESULT hr = m_pIDP->Send( m_idHost,
idTo,
DPSEND_GUARANTEED,
m_Message.m_aBuffer,
m_Message.m_dwLength);
if (!SUCCEEDED(hr))
{ // Can't send message
TRACE ("\tERROR: Host cannot send message to client !!!\n");
INC_HOST_SEND_ERRORS;
}
else
{ // Message sent successfully
INC_TOTAL_BYTES_SENT (m_Message.m_dwLength);
INC_TOTAL_HOST_MESSAGES_SENT;
UPDATE_BIGGEST_PACKET_SENT (m_Message.m_dwLength);
UPDATE_SMALLEST_PACKET_SENT (m_Message.m_dwLength);
UPDATE_SEND;
}
}
void
CCommManager::NotifyBonusEaten (UINT uTankID)
{
// This function is called by a tank object in this machine.
// It is called only if we're the host machine => the prime judge of the game.
// A tank eats a bonus and wishes to notify all the players (including himself)
// of this happy event.
ASSERT (IsHost()); // Only a tank on a host machine can issue this call
CMessage::MessageData Params;
// Create bonus eating notification message:
Params.BonusParam.Type = BONUS_NONE; // Bonus is removed, not added
Params.BonusParam.LifeSpan = uTankID;
// Send it to the comm. managers outgoing queue - it'll spread to all from there.
// The host player will receive it and will spread it to all players.
TANKS_APP->m_gOutgoingMsgQueue.Enqueue (CMessage::ADD_BONUS, Params);
}
void
CCommManager::NotifyNewBonus (BonusType typ, DWORD ttl, CPoint &loc)
{
// This function is called by the game manager in the host machine.
// It is called only if we're the host machine => the prime judge of the game.
// It's time to tell all of the game managers (including the local one)
// that a new bonus is added.
ASSERT (IsHost()); // Only the game manager on a host machine can issue this call
CMessage::MessageData Params;
// Create bonus eating notification message:
Params.BonusParam.Type = typ;
Params.BonusParam.LifeSpan = ttl / 1000; // Convert ttl to seconds
Params.BonusParam.XPos = WORD(loc.x);
Params.BonusParam.YPos = WORD(loc.y);
// Send it to the comm. managers outgoing queue - it'll spread to all from there.
// The host player will receive it and will spread it to all players.
TANKS_APP->m_gOutgoingMsgQueue.Enqueue (CMessage::ADD_BONUS, Params);
}
void
CCommManager::NotifyExplodingTank (UINT uTankID)
{ // This function is called by a tank object in this machine.
// It is called only if we're the host machine => the prime judge of the game.
// A tank reaches the conclusion he's dying now wishes to notify all the
// players (including himself) of this sad event.
// ASSERT (IsHost()); // Only a tank on a host machine can issue this call
CMessage::MessageData Params;
// Create tank removal notification message:
Params.TankRemoveParam.ID = BYTE(uTankID);
Params.TankRemoveParam.Explode = TRUE;
// Send it to the comm. managers outgoing queue - it'll spread to all from there
// The host player will receive it and will spread it to all players.
TANKS_APP->m_gOutgoingMsgQueue.Enqueue (CMessage::REMOVE_TANK, Params);
}
void
CCommManager::NotifyCheckSum (CMessage::MessageData &msgdata)
{ // This function is called by a the game manager in this machine.
// It is called when the game manager wishes to send a game check sum
m_OutgoingMsgQ.Enqueue (CMessage::CHECK_SUM, msgdata);
// We take advantage of the fact that this method is called every sec.
// to trigger the zombie check:
if (m_pHost)
m_pHost->ChkForZombies();
}
void
CCommManager::NotifyChatMsg (LPCSTR szMsg)
{
CMessage::MessageData Params;
strcpy (Params.ChatParam.Msg, szMsg);
Params.ChatParam.TankID = BYTE(TANKS_APP->m_gGameManager.GetLocalTankID());
Params.ChatParam.idFrom = m_idPlayer;
m_OutgoingMsgQ.Enqueue (CMessage::CHAT, Params);
}
void
CCommManager::DisplayMessageAndEndGame (UINT uMsgID)
{
if (m_bLostServerConnection)
return;
m_bLostServerConnection = TRUE;
if (0 != uMsgID)
AfxMessageBox (uMsgID, MB_OK | MB_ICONHAND);
// Simulate a user menu selection of "Stop Game":
::PostMessage(TANKS_APP->m_pMainWnd->m_hWnd, WM_COMMAND, ID_STOP_GAME, 0);
}
BOOL
CCommManager::GetPlayerInfo (
UINT ind,
BOOL &bIsJudge,
CString &cstrName,
DWORD &dwDuration,
DWORD &dwRTT)
{
m_CSHost.Lock();
BOOL bRes = FALSE;
if (m_pHost)
{ // Server active
bRes = m_pHost->GetPlayerInfo (ind, dwDuration, dwRTT);
if (bRes)
{ // Successfully queried server
DWORD dwDPID = m_pHost->GetDirectPlayID (ind);
bIsJudge = (m_idPlayer == dwDPID);
char szBuf[1024];
DWORD dwSize = 1024;
HRESULT hres = m_pIDP->GetPlayerData (dwDPID, szBuf, &dwSize, 0);
cstrName = (DP_OK == hres) ? szBuf : "";
}
}
m_CSHost.Unlock();
return bRes;
}
void
CCommManager::GetPlayerName (DPID id, CString& cstrName)
{
m_CSHost.Lock();
char szBuf[256];
DWORD dwSize = 256;
HRESULT hres = m_pIDP->GetPlayerData (id, szBuf, &dwSize, 0);
cstrName = (DP_OK == hres && dwSize) ? szBuf : "Unknown";
m_CSHost.Unlock();
}
BOOL CCommManager::KillPlayer (UINT uTankID)
{
BOOL bRes = FALSE;
m_CSHost.Lock();
if (m_pHost)
{
ASSERT (uTankID < MAX_TANKS);
NotifyExplodingTank (uTankID);
bRes = TRUE;
}
m_CSHost.Unlock();
return bRes;
}
#ifdef GATHER_NETWORK_STATS
void
CCommManager::UpdateReceive ()
{
DWORD dwCurTime = GetTickCount();
DWORD dwWindowSize = dwCurTime - m_dwLastSecTimeRecv;
if (dwWindowSize < 1000)
return;
m_dwLastSecTimeRecv = dwCurTime;
DWORD dwAmountInWindow = m_dwTotalBytesReceived - m_dwLastRecvTotal;
m_dwLastRecvTotal = m_dwTotalBytesReceived;
DWORD dwBPS = DWORD(double(dwAmountInWindow) * double(1000.0) / double(dwWindowSize));
m_dwMaxBytesReceivedInLastSecond = max (m_dwMaxBytesReceivedInLastSecond, dwBPS);
}
void
CCommManager::UpdateSend ()
{
DWORD dwCurTime = GetTickCount();
DWORD dwWindowSize = dwCurTime - m_dwLastSecTimeSend;
if (dwWindowSize < 1000)
return;
m_dwLastSecTimeSend = dwCurTime;
DWORD dwAmountInWindow = m_dwTotalBytesSent - m_dwLastSentTotal;
m_dwLastSentTotal = m_dwTotalBytesSent;
DWORD dwBPS = DWORD(double(dwAmountInWindow) * double(1000.0) / double(dwWindowSize));
m_dwMaxBytesSentInLastSecond = max (m_dwMaxBytesSentInLastSecond, dwBPS);
}
void
CCommManager::TraceNetworkStats ()
{
TRACE ( "\n\n\t\t\t**** Network statistics ****\n");
DWORD dwNow = GetTickCount();
DWORD dwTotTime = dwNow - m_dwSessionStartTime;
TRACE ( "Session time = %.3f secs.\n",
double(dwTotTime) / 1000.0);
TRACE ( "Send:\n");
DWORD dwTotMsgs = m_dwTotalClientMsgsSent + m_dwTotalHostMsgsSent;
TRACE ( "\tTotal bytes sent = %d (biggest packet size = %d, smallest packet size = %d, avg size = %d)\n",
m_dwTotalBytesSent,
m_dwBiggestSentPacketSize,
m_dwSmallestSentPacketSize,
dwTotMsgs ? DWORD(double(m_dwTotalBytesSent) / double(dwTotMsgs)) : 0);
TRACE ( "\tTotal messages sent = %d (client messages = %d, host messages = %d)\n",
dwTotMsgs,
m_dwTotalClientMsgsSent,
m_dwTotalHostMsgsSent);
TRACE ( "\tTotal send errors = %d (client errors = %d, host errors = %d)\n",
m_dwClientSendErrors + m_dwHostSendErrors,
m_dwClientSendErrors,
m_dwHostSendErrors);
TRACE ( "\tMaximum bytes sent per second = %d (avg = %d)\n",
m_dwMaxBytesSentInLastSecond,
dwTotTime ? DWORD(double(m_dwTotalBytesSent) / (double(dwTotTime) / double(1000.0))) : 0);
TRACE ( "Receive:\n");
dwTotMsgs = m_dwTotalClientMsgsReceived + m_dwTotalHostMsgsReceived;
TRACE ( "\tTotal bytes received = %d (biggest packet size = %d, smallest packet size = %d, avg size = %d)\n",
m_dwTotalBytesReceived,
m_dwBiggestReceivedPacketSize,
m_dwSmallestReceivedPacketSize,
dwTotMsgs ? DWORD(double(m_dwTotalBytesReceived) / double(dwTotMsgs)) : 0);
TRACE ( "\tTotal messages received = %d (client messages = %d, host messages = %d)\n",
dwTotMsgs,
m_dwTotalClientMsgsReceived,
m_dwTotalHostMsgsReceived);
TRACE ( "\tTotal receive errors = %d\n",
m_dwReceiveErrors);
TRACE ( "\tMaximum bytes received per second = %d (avg = %d)\n\n",
m_dwMaxBytesReceivedInLastSecond,
dwTotTime ? DWORD(double(m_dwTotalBytesReceived) / (double(dwTotTime) / double(1000.0))) : 0);
}
#endif // GATHER_NETWORK_STATS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -