#include "stdafx.h" #include "SQRNetworkPlayer.h" #ifdef __PS3__ #include #include "PS3/Network/SonyVoiceChat.h" #elif defined __ORBIS__ #include #include "Orbis/Network/SonyVoiceChat_Orbis.h" #else // __PSVITA__ #include #include #include "PSVita/Network/SonyVoiceChat_Vita.h" #endif static const bool sc_verbose = false; int SQRNetworkPlayer::GetSmallId() { return m_ISD.m_smallId; } wchar_t *SQRNetworkPlayer::GetName() { return m_name; } bool SQRNetworkPlayer::IsRemote() { return !IsLocal(); } bool SQRNetworkPlayer::IsHost() { return (m_type == SNP_TYPE_HOST); } bool SQRNetworkPlayer::IsLocal() { // m_host determines whether this *machine* is hosting the game, not this player (which is determined by m_type) if( m_host ) { // If we are the hosting machine, then both the host & local players are local to this machine return (m_type == SNP_TYPE_HOST) || (m_type == SNP_TYPE_LOCAL); } else { // Not hosting, just local players are actually physically local return (m_type == SNP_TYPE_LOCAL) ; } } int SQRNetworkPlayer::GetLocalPlayerIndex() { return m_localPlayerIdx; } bool SQRNetworkPlayer::IsSameSystem(SQRNetworkPlayer *other) { return (m_roomMemberId == other->m_roomMemberId); } uintptr_t SQRNetworkPlayer::GetCustomDataValue() { return m_customData; } void SQRNetworkPlayer::SetCustomDataValue(uintptr_t data) { m_customData = data; } SQRNetworkPlayer::SQRNetworkPlayer(SQRNetworkManager *manager, eSQRNetworkPlayerType playerType, bool onHost, SceNpMatching2RoomMemberId roomMemberId, int localPlayerIdx, int rudpCtx, PlayerUID *pUID) { m_roomMemberId = roomMemberId; m_localPlayerIdx = localPlayerIdx; m_rudpCtx = rudpCtx; m_flags = 0; m_type = playerType; m_host = onHost; m_manager = manager; m_customData = 0; if( pUID ) { memcpy(&m_ISD.m_UID,pUID,sizeof(PlayerUID)); #ifdef __PSVITA__ if(CGameNetworkManager::usingAdhocMode() && pUID->getOnlineID()[0] == 0) { assert(localPlayerIdx == 0); // player doesn't have an online UID, set it from the player name m_ISD.m_UID.setForAdhoc(); } #endif // __PSVITA__ } else { memset(&m_ISD.m_UID,0,sizeof(PlayerUID)); } SetNameFromUID(); InitializeCriticalSection(&m_csQueue); #ifdef __ORBIS__ if(IsLocal()) { SonyVoiceChat_Orbis::initLocalPlayer(m_localPlayerIdx); } #endif } SQRNetworkPlayer::~SQRNetworkPlayer() { #ifdef __ORBIS__ SQRNetworkManager_Orbis* pMan = (SQRNetworkManager_Orbis*)m_manager; // pMan->removePlayerFromVoiceChat(this); // m_roomMemberId = -1; #endif DeleteCriticalSection(&m_csQueue); } bool SQRNetworkPlayer::IsReady() { return ( ( m_flags & SNP_FLAG_READY_MASK ) == SNP_FLAG_READY_MASK ); } PlayerUID SQRNetworkPlayer::GetUID() { return m_ISD.m_UID; } void SQRNetworkPlayer::SetUID(PlayerUID UID) { m_ISD.m_UID = UID; SetNameFromUID(); } bool SQRNetworkPlayer::HasConnectionAndSmallId() { const int reqFlags = ( SNP_FLAG_CONNECTION_COMPLETE | SNP_FLAG_SMALLID_ALLOCATED ); return (( m_flags & reqFlags) == reqFlags); } void SQRNetworkPlayer::ConnectionComplete() { m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:"); app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ConnectionComplete\n"); m_flags |= SNP_FLAG_CONNECTION_COMPLETE; } void SQRNetworkPlayer::SmallIdAllocated(unsigned char smallId) { m_ISD.m_smallId = smallId; m_flags |= SNP_FLAG_SMALLID_ALLOCATED; m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:"); app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID allocated\n"); // If this is a non-network sort of player then flag now as having its small id confirmed if( ( m_type == SNP_TYPE_HOST ) || ( m_host && ( m_type == SNP_TYPE_LOCAL ) ) || ( !m_host && ( m_type == SNP_TYPE_REMOTE ) ) ) { m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:"); app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n"); m_flags |= SNP_FLAG_SMALLID_CONFIRMED; } } void SQRNetworkPlayer::InitialDataReceived(SQRNetworkPlayer::InitSendData *ISD) { assert(m_ISD.m_smallId == ISD->m_smallId); memcpy(&m_ISD, ISD, sizeof(InitSendData) ); #ifdef __PSVITA__ SetNameFromUID(); #endif m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:"); app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n"); m_flags |= SNP_FLAG_SMALLID_CONFIRMED; } bool SQRNetworkPlayer::HasSmallIdConfirmed() { return ( m_flags & SNP_FLAG_SMALLID_CONFIRMED ); } // To confirm to the host that we are ready, send a single byte with our small id. void SQRNetworkPlayer::ConfirmReady() { #ifdef __PS3__ int ret = cellRudpWrite( m_rudpCtx, &m_ISD, sizeof(InitSendData), CELL_RUDP_MSG_LATENCY_CRITICAL ); #else //__ORBIS__ int ret = sceRudpWrite( m_rudpCtx, &m_ISD, sizeof(InitSendData), SCE_RUDP_MSG_LATENCY_CRITICAL ); #endif // TODO - error handling here? assert ( ret == sizeof(InitSendData) ); // Final flag for a local player on the client, as we are now safe to send data on to the host m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:"); app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n"); m_flags |= SNP_FLAG_SMALLID_CONFIRMED; } // Attempt to send data, of any size, from this player to that specified by pPlayerTarget. This may not be possible depending on the two players, due to // our star shaped network connectivity. Data may be any size, and is copied so on returning from this method it does not need to be preserved. void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize ) { // Our network is connected as a star. If we are the host, then we can send to any remote player. If we're a client, we can send only to the host. // The host can also send to other local players, but this doesn't need to go through Rudp. if( m_host ) { if( ( m_type == SNP_TYPE_HOST ) && ( pPlayerTarget->m_type == SNP_TYPE_LOCAL ) ) { // Special internal communication from host to local player m_manager->LocalDataSend( this, pPlayerTarget, data, dataSize ); } else if( ( m_type == SNP_TYPE_LOCAL ) && ( pPlayerTarget->m_type == SNP_TYPE_HOST ) ) { // Special internal communication from local player to host m_manager->LocalDataSend( this, pPlayerTarget, data, dataSize ); } else if( ( m_type == SNP_TYPE_HOST ) && ( pPlayerTarget->m_type == SNP_TYPE_REMOTE ) ) { // Rudp communication from host to remote player - handled by remote player instance pPlayerTarget->SendInternal(data,dataSize); } else { // Can't do any other types of communications assert(false); } } else { if( ( m_type == SNP_TYPE_LOCAL ) && ( pPlayerTarget->m_type == SNP_TYPE_HOST ) ) { // Rudp communication from client to host - handled by this player instace SendInternal(data, dataSize); } else { // Can't do any other types of communications assert(false); } } } // Internal send function - to simplify the number of mechanisms we have for sending data, this method just adds the data to be send to the player's internal queue, // and then calls SendMoreInternal. This method can take any size of data, which it will split up into payload size chunks before sending. All input data is copied // into internal buffers. void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize) { EnterCriticalSection(&m_csQueue); QueuedSendBlock sendBlock; unsigned char *dataCurrent = (unsigned char *)data; unsigned int dataRemaining = dataSize; while( dataRemaining ) { int dataSize = dataRemaining; if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD; sendBlock.start = new unsigned char [dataSize]; sendBlock.end = sendBlock.start + dataSize; sendBlock.current = sendBlock.start; memcpy( sendBlock.start, dataCurrent, dataSize); m_sendQueue.push(sendBlock); dataRemaining -= dataSize; dataCurrent += dataSize; } // Now try and send as much as we can SendMoreInternal(); LeaveCriticalSection(&m_csQueue); } // Internal send function. This attempts to send as many elements in the queue as possible until the write function tells us that we can't send any more. This way, // we are guaranteed that if there *is* anything more in the queue left to send, we'll get a CELL_RUDP_CONTEXT_EVENT_WRITABLE event when whatever we've managed to // send here is complete, and can continue on. void SQRNetworkPlayer::SendMoreInternal() { EnterCriticalSection(&m_csQueue); bool keepSending; do { keepSending = false; if( m_sendQueue.size() > 0) { // Attempt to send the full data in the first element in our queue unsigned char *data= m_sendQueue.front().current; int dataSize = m_sendQueue.front().end - m_sendQueue.front().current; #ifdef __PS3__ int ret = cellRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL ); int wouldBlockFlag = CELL_RUDP_ERROR_WOULDBLOCK; #else // __ORBIS__ int ret = sceRudpWrite( m_rudpCtx, data, dataSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL ); int wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK; #endif if( ret == dataSize ) { // Fully sent, remove from queue - will loop in the while loop to see if there's anything else in the queue we could send delete [] m_sendQueue.front().start; m_sendQueue.pop(); if( m_sendQueue.size() ) { keepSending = true; } } else if( ( ret >= 0 ) || ( ret == wouldBlockFlag ) ) { // Things left to send - adjust this element in the queue int remainingBytes; if( ret >= 0 ) { // Only ret bytes sent so far remainingBytes = dataSize - ret; assert(remainingBytes > 0 ); } else { // Is CELL_RUDP_ERROR_WOULDBLOCK, nothing has yet been sent remainingBytes = dataSize; } m_sendQueue.front().current = m_sendQueue.front().end - remainingBytes; } } } while (keepSending); LeaveCriticalSection(&m_csQueue); } void SQRNetworkPlayer::SetNameFromUID() { mbstowcs(m_name, m_ISD.m_UID.getOnlineID(), 16); m_name[16] = 0; #ifdef __PS3__ // only 1 player on vita, and they have to be online (or adhoc), and with PS4 all local players need to be signed in // Not an online player? Add a suffix with the controller ID on if( m_ISD.m_UID.isSignedIntoPSN() == 0) { int pos = wcslen(m_name); swprintf(&m_name[pos], 5, L" (%d)", m_ISD.m_UID.getQuadrant() + 1 ); } #endif } void SQRNetworkPlayer::SetName(char *name) { mbstowcs(m_name, name, 20); m_name[20] = 0; } int SQRNetworkPlayer::GetSessionIndex() { return m_manager->GetSessionIndex(this); } bool SQRNetworkPlayer::HasVoice() { #ifdef __ORBIS__ return SonyVoiceChat_Orbis::hasMicConnected(this); #elif defined __PSVITA__ return SonyVoiceChat_Vita::hasMicConnected(this); #else return SonyVoiceChat::hasMicConnected(&m_roomMemberId); #endif } bool SQRNetworkPlayer::IsTalking() { #ifdef __ORBIS__ return SonyVoiceChat_Orbis::isTalking(this); #elif defined __PSVITA__ return SonyVoiceChat_Vita::isTalking(this); #else return SonyVoiceChat::isTalking(&m_roomMemberId); #endif } bool SQRNetworkPlayer::IsMutedByLocalUser(int userIndex) { #ifdef __ORBIS__ // assert(0); // this is never called, so isn't implemented in the PS4 voice stuff at the moment return false; #elif defined __PSVITA__ return false;// this is never called, so isn't implemented in the Vita voice stuff at the moment #else SQRNetworkManager_PS3* pMan = (SQRNetworkManager_PS3*)m_manager; return SonyVoiceChat::isMutedPlayer(pMan->m_roomSyncData.players[userIndex].m_roomMemberId); #endif }