diff options
| author | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
|---|---|---|
| committer | daoge_cmd <3523206925@qq.com> | 2026-03-01 12:16:08 +0800 |
| commit | b691c43c44ff180d10e7d4a9afc83b98551ff586 (patch) | |
| tree | 3e9849222cbc6ba49f2f1fc6e5fe7179632c7390 /Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp | |
| parent | def8cb415354ac390b7e89052a50605285f1aca9 (diff) | |
Initial commit
Diffstat (limited to 'Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp')
| -rw-r--r-- | Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp b/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp new file mode 100644 index 00000000..e244b34c --- /dev/null +++ b/Minecraft.Client/Common/Network/Sony/SQRNetworkPlayer.cpp @@ -0,0 +1,399 @@ +#include "stdafx.h" +#include "SQRNetworkPlayer.h" + +#ifdef __PS3__ +#include <cell/rudp.h> +#include "PS3/Network/SonyVoiceChat.h" + +#elif defined __ORBIS__ +#include <rudp.h> +#include "Orbis/Network/SonyVoiceChat_Orbis.h" + +#else // __PSVITA__ +#include <rudp.h> +#include <adhoc_matching.h> +#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 +} |
