/**This should get called every time a new byte is availible from the UART.
 * @param byte the new byte that just arrived.
 */
void OnByteRecieved(const unsigned char byte)
{
  //Check the interframe spacing.
  //If it has been more than that time it is either an error or a new packet.
  //also check if we arent recieving a message at all.
  //Either of these conditions indicate that this byte could be the start of a new character.
  if (((TimeSinceLastByteWasRecieved() >= CurrentTimeOut)) | !(RecievingMessage))

  {
    //A byte time of silence or more always delimits packets
    //So reset the recieve pointer to clear any garbage and reset the hash state.
    RecievePointer = 0;
    HashState = 0;


    //Consider this the start of a new packet ONLY if it matches the valid start code
    //And ONLY if the required interframe distance has been met or exceeded.
    //This lets us send one byte messages outside of a full packet
    if (byte == 0x55)
    {
      RecievingMessage = 1;
    }
    else
    {
      //If we don't see the valid start code we stay idle
      RecievingMessage = 0;
    }
    return;
  }

  //Only if a valid start code was detected at the start should we enter the byte in the buffer.
  else
  {
    RecieveBuffer[RecievePointer] = byte;
    RecievePointer++;
    //Update the checksum as we go so we don't have to do one huge batch of calculations
    //At the end, which would suck for realtime performance.

    //Also dont CRC the CRC because that would
    //not make sense unless we did that weird crc(message +crc)=0 thing
    if (!((RecievePointer >= (RecieveBuffer[LENGTH_OFFSET]-1)) &(RecievePointer>LENGTH_OFFSET)))
    {

      HashUpdate(byte);
    }



    //Not only check and see if we have as mny bytes as the length field says,
    //But also check that we even have the length field.
    if ((RecievePointer >= RecieveBuffer[LENGTH_OFFSET]) &(RecievePointer>LENGTH_OFFSET))
    {
      //If we have recieved a complete message, Check the checksum.
      //	DisableReciever(); //We must re enable this to be ready for the next packet.
      RecievingMessage = 0;
      //Do nothing with the packet if we have just been waiting for the end of it.

      if (CheckAddress(RecieveBuffer))
      {
        //Don't do anything with incorrect packets, they are bad.

        if (GetByteOf(0,HashState ) == RecieveBuffer[RecievePointer-1])
        {
          if(GetByteOf(1,HashState) == RecieveBuffer[RecievePointer-2])
          {
            HandleNewPacket(RecieveBuffer);
          }
        }
      }

    }
  }
}
Beispiel #2
0
//======================================================================================
// MessageHandler()
//
// Handles messages from DirectPlay.
//======================================================================================
HRESULT CDarkPeer::MessageHandler(void* pContext, DWORD messageType, void* pMessage)
{
	switch (messageType)
	{
	case DPN_MSGID_CREATE_PLAYER:
		{
			HandleCreatePlayerMsg((DPNMSG_CREATE_PLAYER*)pMessage);
			break;
		}

      case DPN_MSGID_DESTROY_PLAYER:
		{
			// Translate DPlay8's destroy player message to DPlay4
			PDPNMSG_DESTROY_PLAYER pDestroyPlayer = (PDPNMSG_DESTROY_PLAYER) pMessage;
			DPNID dpnidPlayer = pDestroyPlayer->dpnidPlayer;
			DPMSG_DESTROYPLAYERORGROUP* pDP4DestroyPlayer = new DPMSG_DESTROYPLAYERORGROUP;

			if (dpnidPlayer != m_dpnidLocal && g_pNetMan)
			{
#if (GAME == GAME_THIEF)
#if 1
				DPN_PLAYER_INFO* pPeerInfo = GetPeerInfo(pDestroyPlayer->dpnidPlayer);
				if (pPeerInfo)
				{
					char playerName[kMaxPlayerName];
					WideToAnsi(playerName, pPeerInfo->pwszName, sizeof(playerName));
					const char* str = "%s has left the game.";
					MessageMgr::Get()->AddLineFormat(true, str, playerName);
					ConPrintF(str, playerName);

					SAFE_DELETE_ARRAY(pPeerInfo);
				}
#else
				const char* playerName = Players.NameFromDPNID(pDestroyPlayer->dpnidPlayer);
				const char* msg = "%s has left the game.";
				MessageMgr::Get()->AddLineFormat(true, msg, playerName);
				ConPrintF(msg, playerName);
#endif
#endif
				ZeroMemory(pDP4DestroyPlayer, sizeof(DPMSG_DESTROYPLAYERORGROUP));
				pDP4DestroyPlayer->lpLocalData = m_DP4PlayerData[dpnidPlayer];
				pDP4DestroyPlayer->dpId = dpnidPlayer;
				pDP4DestroyPlayer->dwType = DPSYS_DESTROYPLAYERORGROUP;
				pDP4DestroyPlayer->dwPlayerType = DPPLAYERTYPE_PLAYER;

				// send Thief the destroy player notification in the form it expects from DPlay 4
				NetMessage* pMsg = new NetMessage;
				pMsg->m_pMsgData = (BYTE*)pDP4DestroyPlayer;
				pMsg->m_size = sizeof(DPMSG_DESTROYPLAYERORGROUP);
				pMsg->m_dpnidSender = DPID_SYSMSG;

				m_DarkQueue.Push(pMsg);
				// find the player's index and destroy the player data
			}
			break;
		}

		case DPN_MSGID_INDICATE_CONNECT:
			{
				if (g_Net == STATE_Host)
				{
#ifndef _RELEASE
					if (Client.MissionStarted() && !Cfg.GetBool("AllowJoinsInProgress"))
#else
					if (Client.MissionStarted())
#endif
						return DPNERR_HOSTREJECTEDCONNECTION;
				}
				break;
			}

		case DPN_MSGID_CONNECT_COMPLETE:
			{
				PDPNMSG_CONNECT_COMPLETE pConnComplete = (PDPNMSG_CONNECT_COMPLETE)pMessage;

				if (pConnComplete->hResultCode == DPN_OK)
				{
#if (GAME == GAME_THIEF || GAME == GAME_DROMED)
					m_dpnidLocal = (pConnComplete->dpnidLocal);

					ConPrintF("Connected to session.");
					_SFX_Play_Raw(1, 0, "pickloot.wav");
#endif

					SetEvent(m_ConnectedEvent);
				}
				break;
			}

		case DPN_MSGID_ENUM_HOSTS_RESPONSE:
			{
				m_csEnumResponse.Lock();

				DPNMSG_ENUM_HOSTS_RESPONSE* pResponse = (DPNMSG_ENUM_HOSTS_RESPONSE*)pMessage;

				OnEnumerationResponse(pResponse);

				m_csEnumResponse.Unlock();
				break;
			}

      case DPN_MSGID_RECEIVE:
			{
				PDPNMSG_RECEIVE pRecvData = (PDPNMSG_RECEIVE)pMessage;
				Packet* packet = (Packet*)pRecvData->pReceiveData;

				csReceive.Lock();

				// this may not be a good idea... some original packets are very close to these numbers
				if (packet->type > NewPacketStart && packet->type < NewPacketEnd)
				{
					HandleNewPacket(pRecvData->pReceiveData, pRecvData->dwReceiveDataSize, pRecvData->dpnidSender);
					csReceive.Unlock();
					return DPN_OK;
				}

				NetMessage* pMsg = new NetMessage;

				pMsg->m_pMsgData = pRecvData->pReceiveData;
				pMsg->m_size = pRecvData->dwReceiveDataSize;
				pMsg->m_bufferHandle = pRecvData->hBufferHandle; // Save buffer handle so we can return it to DirectPlay with ReturnBuffer() later
				pMsg->m_dpnidSender = pRecvData->dpnidSender;

				m_DarkQueue.Push(pMsg);

				csReceive.Unlock();

				return DPNSUCCESS_PENDING;
			}

		case DPN_MSGID_TERMINATE_SESSION:
			{
				// Translate DPlay8's terminate session message to DPlay4
				PDPNMSG_TERMINATE_SESSION pTerminateSession = (PDPNMSG_TERMINATE_SESSION)pMessage;
				DPMSG_SESSIONLOST* pDP4SessLost = new DPMSG_SESSIONLOST;
				NetMessage* pMsg = new NetMessage;

				ZeroMemory(pDP4SessLost, sizeof(DPMSG_SESSIONLOST));
				pDP4SessLost->dwType = DPSYS_SESSIONLOST;

				pMsg->m_pMsgData = (BYTE*)pDP4SessLost;
				pMsg->m_size = sizeof(DPMSG_SESSIONLOST);
				pMsg->m_dpnidSender = DPID_SYSMSG;

				m_DarkQueue.Push(pMsg);

#if (GAME == GAME_THIEF || GAME == GAME_DROMED)
				if (pTerminateSession->pvTerminateData)
				{
					SDestroyReason* pMsg = (SDestroyReason*)pTerminateSession->pvTerminateData;

					switch (pMsg->reason)
					{
						case DReason_CrcFailed:
							Client.StartEndGameTimer(EndGameTime, ER_KickedCrc); break;
						default:
						case DReason_Kicked:
							Client.StartEndGameTimer(EndGameTime, ER_Kicked); break;
					}
				}
				else
					Client.StartEndGameTimer(EndGameTime, ER_HostLeft);
#endif
				break;
			}
	}

	return DPN_OK;
}