Something went wrong. Try again.
the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
Something went wrong. Try again.
18 kB · 611 lines
C++
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612#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
//#define PRINT_ACK_STATS
#ifdef __PS3__static const int sc_wouldBlockFlag = CELL_RUDP_ERROR_WOULDBLOCK;#else // __ORBIS__static const int sc_wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK;#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; m_acksOutstanding = 0; m_totalBytesInSendQueue = 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); InitializeCriticalSection(&m_csAcks);#ifdef __ORBIS__ if(IsLocal()) { SonyVoiceChat_Orbis::initLocalPlayer(m_localPlayerIdx); }#endif
#ifndef _CONTENT_PACKAGE m_minAckTime = INT_MAX; m_maxAckTime = 0; m_totalAcks = 0; m_totalAckTime = 0; m_averageAckTime = 0;#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(){ SendInternal(&m_ISD, sizeof(InitSendData), e_flag_AckNotRequested);
// 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, bool ack ){ AckFlags ackFlags = ack ? e_flag_AckRequested : e_flag_AckNotRequested; // 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, ackFlags); } 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, ackFlags); } 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, AckFlags ackFlags){ EnterCriticalSection(&m_csQueue); bool bOutstandingPackets = (m_sendQueue.size() > 0); // check if there are still packets in the queue, we won't be calling SendMoreInternal here if there are QueuedSendBlock sendBlock;
unsigned char *dataCurrent = (unsigned char *)data; unsigned int dataRemaining = dataSize;
if(ackFlags == e_flag_AckReturning) { // no data, just the flag assert(dataSize == 0); assert(data == NULL); int dataSize = dataRemaining; if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD; sendBlock.start = NULL; sendBlock.end = NULL; sendBlock.current = NULL; sendBlock.ack = ackFlags; m_sendQueue.push(sendBlock); } else { 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; sendBlock.ack = ackFlags; memcpy( sendBlock.start, dataCurrent, dataSize); m_sendQueue.push(sendBlock); dataRemaining -= dataSize; dataCurrent += dataSize; }
} m_totalBytesInSendQueue += dataSize;
// if the queue had something in it already, then the UDP callback will fire and call SendMoreInternal // so we don't call it here, to avoid a deadlock if(!bOutstandingPackets) { // Now try and send as much as we can SendMoreInternal(); }
LeaveCriticalSection(&m_csQueue);}
int SQRNetworkPlayer::WriteDataPacket(const void* data, int dataSize, AckFlags ackFlags) { DataPacketHeader header(dataSize, ackFlags); int headerSize = sizeof(header); int packetSize = dataSize+headerSize; unsigned char* packetData = new unsigned char[packetSize]; *((DataPacketHeader*)packetData) = header; memcpy(&packetData[headerSize], data, dataSize);
#ifndef _CONTENT_PACKAGE if(ackFlags == e_flag_AckRequested) m_ackStats.push_back(System::currentTimeMillis());#endif
#ifdef __PS3__ int ret = cellRudpWrite( m_rudpCtx, packetData, packetSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );#else // __ORBIS__ && __PSVITA__ int ret = sceRudpWrite( m_rudpCtx, packetData, packetSize, 0);//SCE_RUDP_MSG_LATENCY_CRITICAL );#endif if(ret == sc_wouldBlockFlag) { // nothing was sent! } else { assert(ret==packetSize || ret > headerSize); // we must make sure we've sent the entire packet or the header and some data at least ret -= headerSize; if(ackFlags == e_flag_AckRequested) { EnterCriticalSection(&m_csAcks); m_acksOutstanding++; LeaveCriticalSection(&m_csAcks); } } delete packetData;
return ret;}
int SQRNetworkPlayer::GetPacketDataSize(){ unsigned int ackFlag; int headerSize = sizeof(ackFlag);#ifdef __PS3__ unsigned int packetSize = cellRudpGetSizeReadable(m_rudpCtx);#else unsigned int packetSize = sceRudpGetSizeReadable(m_rudpCtx);#endif if(packetSize == 0) return 0;
unsigned int dataSize = packetSize - headerSize; assert(dataSize >= 0); if(dataSize == 0) { // header only, must just be an ack returning ReadAck(); } return dataSize;}
int SQRNetworkPlayer::ReadDataPacket(void* data, int dataSize){ int headerSize = sizeof(DataPacketHeader); int packetSize = dataSize+headerSize;
unsigned char* packetData = new unsigned char[packetSize];#ifdef __PS3__ int bytesRead = cellRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );#else // __ORBIS__ && __PSVITA__ int bytesRead = sceRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );#endif if(bytesRead == sc_wouldBlockFlag) { delete packetData; return 0; } // check the header, and see if we need to send back an ack DataPacketHeader header = *((DataPacketHeader*)packetData); if(header.GetAckFlags() == e_flag_AckRequested) { // Don't send the ack back directly from here, as this is called from a rudp event callback, and we end up in a thread lock situation between the lock librudp uses // internally (which is locked already here since we are being called in the event handler), and our own lock that we do for processing our write queue m_manager->RequestWriteAck(GetSmallId()); } else { assert(header.GetAckFlags() == e_flag_AckNotRequested); } if(bytesRead > 0) { bytesRead -= headerSize; memcpy(data, &packetData[headerSize], bytesRead); } assert(header.GetDataSize() == bytesRead);
delete packetData;
return bytesRead;}
void SQRNetworkPlayer::ReadAck(){ DataPacketHeader header;#ifdef __PS3__ int bytesRead = cellRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );#else // __ORBIS__ && __PSVITA__ int bytesRead = sceRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );#endif if(bytesRead == sc_wouldBlockFlag) { return; }
assert(header.GetAckFlags() == e_flag_AckReturning); EnterCriticalSection(&m_csAcks); m_acksOutstanding--; assert(m_acksOutstanding >=0); LeaveCriticalSection(&m_csAcks);
#ifndef _CONTENT_PACKAGE#ifdef PRINT_ACK_STATS __int64 timeTaken = System::currentTimeMillis() - m_ackStats[0]; if(timeTaken < m_minAckTime) m_minAckTime = timeTaken; if(timeTaken > m_maxAckTime) m_maxAckTime = timeTaken; m_totalAcks++; m_totalAckTime += timeTaken; m_averageAckTime = m_totalAckTime / m_totalAcks; app.DebugPrintf("RUDP ctx : %d : Time taken for ack - %4d ms : min - %4d : max %4d : avg %4d\n", m_rudpCtx, timeTaken, m_minAckTime, m_maxAckTime, m_averageAckTime); m_ackStats.erase(m_ackStats.begin());#endif#endif}
void SQRNetworkPlayer::WriteAck(){ SendInternal(NULL, 0, e_flag_AckReturning);}
int SQRNetworkPlayer::GetOutstandingAckCount(){ return m_manager->GetOutstandingAckCount(this);}
int SQRNetworkPlayer::GetTotalOutstandingAckCount(){ return m_acksOutstanding;}
int SQRNetworkPlayer::GetTotalSendQueueBytes(){ return m_totalBytesInSendQueue;}
int SQRNetworkPlayer::GetTotalSendQueueMessages(){ CriticalSectionScopeLock lock(&m_csQueue); return m_sendQueue.size();
}
int SQRNetworkPlayer::GetSendQueueSizeBytes(){ return m_manager->GetSendQueueSizeBytes();}
int SQRNetworkPlayer::GetSendQueueSizeMessages(){ return m_manager->GetSendQueueSizeMessages();}
// 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); assert(m_sendQueue.size() > 0); // this should never be called with an empty queue.
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; int ret = WriteDataPacket(data, dataSize, m_sendQueue.front().ack);
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 m_totalBytesInSendQueue -= ret; delete [] m_sendQueue.front().start; m_sendQueue.pop(); if( m_sendQueue.size() ) { keepSending = true; } } else if( ( ret >= 0 ) || ( ret == sc_wouldBlockFlag ) ) {
// Things left to send - adjust this element in the queue int remainingBytes; if( ret >= 0 ) { // Only ret bytes sent so far m_totalBytesInSendQueue -= ret; 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}