the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1#include "stdafx.h"
2#include "SQRNetworkPlayer.h"
3
4#ifdef __PS3__
5#include <cell/rudp.h>
6#include "PS3/Network/SonyVoiceChat.h"
7
8#elif defined __ORBIS__
9#include <rudp.h>
10#include "Orbis/Network/SonyVoiceChat_Orbis.h"
11
12#else // __PSVITA__
13#include <rudp.h>
14#include <adhoc_matching.h>
15#include "PSVita/Network/SonyVoiceChat_Vita.h"
16
17#endif
18
19//#define PRINT_ACK_STATS
20
21#ifdef __PS3__
22static const int sc_wouldBlockFlag = CELL_RUDP_ERROR_WOULDBLOCK;
23#else // __ORBIS__
24static const int sc_wouldBlockFlag = SCE_RUDP_ERROR_WOULDBLOCK;
25#endif
26
27
28
29static const bool sc_verbose = false;
30
31int SQRNetworkPlayer::GetSmallId()
32{
33 return m_ISD.m_smallId;
34}
35
36wchar_t *SQRNetworkPlayer::GetName()
37{
38 return m_name;
39}
40
41bool SQRNetworkPlayer::IsRemote()
42{
43 return !IsLocal();
44}
45
46bool SQRNetworkPlayer::IsHost()
47{
48 return (m_type == SNP_TYPE_HOST);
49}
50
51bool SQRNetworkPlayer::IsLocal()
52{
53 // m_host determines whether this *machine* is hosting the game, not this player (which is determined by m_type)
54 if( m_host )
55 {
56 // If we are the hosting machine, then both the host & local players are local to this machine
57 return (m_type == SNP_TYPE_HOST) || (m_type == SNP_TYPE_LOCAL);
58 }
59 else
60 {
61 // Not hosting, just local players are actually physically local
62 return (m_type == SNP_TYPE_LOCAL) ;
63 }
64}
65
66int SQRNetworkPlayer::GetLocalPlayerIndex()
67{
68 return m_localPlayerIdx;
69}
70
71bool SQRNetworkPlayer::IsSameSystem(SQRNetworkPlayer *other)
72{
73 return (m_roomMemberId == other->m_roomMemberId);
74}
75
76uintptr_t SQRNetworkPlayer::GetCustomDataValue()
77{
78 return m_customData;
79}
80
81void SQRNetworkPlayer::SetCustomDataValue(uintptr_t data)
82{
83 m_customData = data;
84}
85
86SQRNetworkPlayer::SQRNetworkPlayer(SQRNetworkManager *manager, eSQRNetworkPlayerType playerType, bool onHost, SceNpMatching2RoomMemberId roomMemberId, int localPlayerIdx, int rudpCtx, PlayerUID *pUID)
87{
88 m_roomMemberId = roomMemberId;
89 m_localPlayerIdx = localPlayerIdx;
90 m_rudpCtx = rudpCtx;
91 m_flags = 0;
92 m_type = playerType;
93 m_host = onHost;
94 m_manager = manager;
95 m_customData = 0;
96 m_acksOutstanding = 0;
97 m_totalBytesInSendQueue = 0;
98 if( pUID )
99 {
100 memcpy(&m_ISD.m_UID,pUID,sizeof(PlayerUID));
101#ifdef __PSVITA__
102 if(CGameNetworkManager::usingAdhocMode() && pUID->getOnlineID()[0] == 0)
103 {
104 assert(localPlayerIdx == 0);
105 // player doesn't have an online UID, set it from the player name
106 m_ISD.m_UID.setForAdhoc();
107 }
108#endif // __PSVITA__
109 }
110 else
111 {
112 memset(&m_ISD.m_UID,0,sizeof(PlayerUID));
113 }
114 SetNameFromUID();
115 InitializeCriticalSection(&m_csQueue);
116 InitializeCriticalSection(&m_csAcks);
117#ifdef __ORBIS__
118 if(IsLocal())
119 {
120 SonyVoiceChat_Orbis::initLocalPlayer(m_localPlayerIdx);
121 }
122#endif
123
124#ifndef _CONTENT_PACKAGE
125 m_minAckTime = INT_MAX;
126 m_maxAckTime = 0;
127 m_totalAcks = 0;
128 m_totalAckTime = 0;
129 m_averageAckTime = 0;
130#endif
131
132}
133
134SQRNetworkPlayer::~SQRNetworkPlayer()
135{
136#ifdef __ORBIS__
137 SQRNetworkManager_Orbis* pMan = (SQRNetworkManager_Orbis*)m_manager;
138// pMan->removePlayerFromVoiceChat(this);
139// m_roomMemberId = -1;
140#endif
141 DeleteCriticalSection(&m_csQueue);
142}
143
144bool SQRNetworkPlayer::IsReady()
145{
146 return ( ( m_flags & SNP_FLAG_READY_MASK ) == SNP_FLAG_READY_MASK );
147}
148
149PlayerUID SQRNetworkPlayer::GetUID()
150{
151 return m_ISD.m_UID;
152}
153
154void SQRNetworkPlayer::SetUID(PlayerUID UID)
155{
156 m_ISD.m_UID = UID;
157 SetNameFromUID();
158}
159
160bool SQRNetworkPlayer::HasConnectionAndSmallId()
161{
162 const int reqFlags = ( SNP_FLAG_CONNECTION_COMPLETE | SNP_FLAG_SMALLID_ALLOCATED );
163 return (( m_flags & reqFlags) == reqFlags);
164}
165
166void SQRNetworkPlayer::ConnectionComplete()
167{
168 m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
169 app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ConnectionComplete\n");
170 m_flags |= SNP_FLAG_CONNECTION_COMPLETE;
171}
172
173void SQRNetworkPlayer::SmallIdAllocated(unsigned char smallId)
174{
175 m_ISD.m_smallId = smallId;
176 m_flags |= SNP_FLAG_SMALLID_ALLOCATED;
177 m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
178 app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID allocated\n");
179
180
181 // If this is a non-network sort of player then flag now as having its small id confirmed
182 if( ( m_type == SNP_TYPE_HOST ) ||
183 ( m_host && ( m_type == SNP_TYPE_LOCAL ) ) ||
184 ( !m_host && ( m_type == SNP_TYPE_REMOTE ) ) )
185 {
186 m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
187 app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n");
188
189 m_flags |= SNP_FLAG_SMALLID_CONFIRMED;
190 }
191}
192
193void SQRNetworkPlayer::InitialDataReceived(SQRNetworkPlayer::InitSendData *ISD)
194{
195 assert(m_ISD.m_smallId == ISD->m_smallId);
196 memcpy(&m_ISD, ISD, sizeof(InitSendData) );
197#ifdef __PSVITA__
198 SetNameFromUID();
199#endif
200 m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
201 app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n");
202 m_flags |= SNP_FLAG_SMALLID_CONFIRMED;
203}
204
205bool SQRNetworkPlayer::HasSmallIdConfirmed()
206{
207 return ( m_flags & SNP_FLAG_SMALLID_CONFIRMED );
208}
209
210// To confirm to the host that we are ready, send a single byte with our small id.
211void SQRNetworkPlayer::ConfirmReady()
212{
213 SendInternal(&m_ISD, sizeof(InitSendData), e_flag_AckNotRequested);
214
215 // Final flag for a local player on the client, as we are now safe to send data on to the host
216 m_host ? app.DebugPrintf(sc_verbose, "host : ") : app.DebugPrintf(sc_verbose, "client:");
217 app.DebugPrintf(sc_verbose, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Small ID confirmed\n");
218 m_flags |= SNP_FLAG_SMALLID_CONFIRMED;
219}
220
221// 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
222// 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.
223void SQRNetworkPlayer::SendData( SQRNetworkPlayer *pPlayerTarget, const void *data, unsigned int dataSize, bool ack )
224{
225 AckFlags ackFlags = ack ? e_flag_AckRequested : e_flag_AckNotRequested;
226 // 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.
227 // The host can also send to other local players, but this doesn't need to go through Rudp.
228 if( m_host )
229 {
230 if( ( m_type == SNP_TYPE_HOST ) && ( pPlayerTarget->m_type == SNP_TYPE_LOCAL ) )
231 {
232 // Special internal communication from host to local player
233 m_manager->LocalDataSend( this, pPlayerTarget, data, dataSize );
234 }
235 else if( ( m_type == SNP_TYPE_LOCAL ) && ( pPlayerTarget->m_type == SNP_TYPE_HOST ) )
236 {
237 // Special internal communication from local player to host
238 m_manager->LocalDataSend( this, pPlayerTarget, data, dataSize );
239 }
240 else if( ( m_type == SNP_TYPE_HOST ) && ( pPlayerTarget->m_type == SNP_TYPE_REMOTE ) )
241 {
242 // Rudp communication from host to remote player - handled by remote player instance
243 pPlayerTarget->SendInternal(data,dataSize, ackFlags);
244 }
245 else
246 {
247 // Can't do any other types of communications
248 assert(false);
249 }
250 }
251 else
252 {
253 if( ( m_type == SNP_TYPE_LOCAL ) && ( pPlayerTarget->m_type == SNP_TYPE_HOST ) )
254 {
255 // Rudp communication from client to host - handled by this player instace
256 SendInternal(data, dataSize, ackFlags);
257 }
258 else
259 {
260 // Can't do any other types of communications
261 assert(false);
262 }
263 }
264}
265
266// 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,
267// 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
268// into internal buffers.
269void SQRNetworkPlayer::SendInternal(const void *data, unsigned int dataSize, AckFlags ackFlags)
270{
271 EnterCriticalSection(&m_csQueue);
272 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
273 QueuedSendBlock sendBlock;
274
275 unsigned char *dataCurrent = (unsigned char *)data;
276 unsigned int dataRemaining = dataSize;
277
278 if(ackFlags == e_flag_AckReturning)
279 {
280 // no data, just the flag
281 assert(dataSize == 0);
282 assert(data == NULL);
283 int dataSize = dataRemaining;
284 if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD;
285 sendBlock.start = NULL;
286 sendBlock.end = NULL;
287 sendBlock.current = NULL;
288 sendBlock.ack = ackFlags;
289 m_sendQueue.push(sendBlock);
290 }
291 else
292 {
293 while( dataRemaining )
294 {
295 int dataSize = dataRemaining;
296 if( dataSize > SNP_MAX_PAYLOAD ) dataSize = SNP_MAX_PAYLOAD;
297 sendBlock.start = new unsigned char [dataSize];
298 sendBlock.end = sendBlock.start + dataSize;
299 sendBlock.current = sendBlock.start;
300 sendBlock.ack = ackFlags;
301 memcpy( sendBlock.start, dataCurrent, dataSize);
302 m_sendQueue.push(sendBlock);
303 dataRemaining -= dataSize;
304 dataCurrent += dataSize;
305 }
306
307 }
308 m_totalBytesInSendQueue += dataSize;
309
310 // if the queue had something in it already, then the UDP callback will fire and call SendMoreInternal
311 // so we don't call it here, to avoid a deadlock
312 if(!bOutstandingPackets)
313 {
314 // Now try and send as much as we can
315 SendMoreInternal();
316 }
317
318 LeaveCriticalSection(&m_csQueue);
319}
320
321
322int SQRNetworkPlayer::WriteDataPacket(const void* data, int dataSize, AckFlags ackFlags)
323 {
324 DataPacketHeader header(dataSize, ackFlags);
325 int headerSize = sizeof(header);
326 int packetSize = dataSize+headerSize;
327 unsigned char* packetData = new unsigned char[packetSize];
328 *((DataPacketHeader*)packetData) = header;
329 memcpy(&packetData[headerSize], data, dataSize);
330
331#ifndef _CONTENT_PACKAGE
332 if(ackFlags == e_flag_AckRequested)
333 m_ackStats.push_back(System::currentTimeMillis());
334#endif
335
336#ifdef __PS3__
337 int ret = cellRudpWrite( m_rudpCtx, packetData, packetSize, 0);//CELL_RUDP_MSG_LATENCY_CRITICAL );
338#else // __ORBIS__ && __PSVITA__
339 int ret = sceRudpWrite( m_rudpCtx, packetData, packetSize, 0);//SCE_RUDP_MSG_LATENCY_CRITICAL );
340#endif
341 if(ret == sc_wouldBlockFlag)
342 {
343 // nothing was sent!
344 }
345 else
346 {
347 assert(ret==packetSize || ret > headerSize); // we must make sure we've sent the entire packet or the header and some data at least
348 ret -= headerSize;
349 if(ackFlags == e_flag_AckRequested)
350 {
351 EnterCriticalSection(&m_csAcks);
352 m_acksOutstanding++;
353 LeaveCriticalSection(&m_csAcks);
354 }
355 }
356 delete packetData;
357
358 return ret;
359}
360
361int SQRNetworkPlayer::GetPacketDataSize()
362{
363 unsigned int ackFlag;
364 int headerSize = sizeof(ackFlag);
365#ifdef __PS3__
366 unsigned int packetSize = cellRudpGetSizeReadable(m_rudpCtx);
367#else
368 unsigned int packetSize = sceRudpGetSizeReadable(m_rudpCtx);
369#endif
370 if(packetSize == 0)
371 return 0;
372
373 unsigned int dataSize = packetSize - headerSize;
374 assert(dataSize >= 0);
375 if(dataSize == 0)
376 {
377 // header only, must just be an ack returning
378 ReadAck();
379 }
380 return dataSize;
381}
382
383int SQRNetworkPlayer::ReadDataPacket(void* data, int dataSize)
384{
385 int headerSize = sizeof(DataPacketHeader);
386 int packetSize = dataSize+headerSize;
387
388 unsigned char* packetData = new unsigned char[packetSize];
389#ifdef __PS3__
390 int bytesRead = cellRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );
391#else // __ORBIS__ && __PSVITA__
392 int bytesRead = sceRudpRead( m_rudpCtx, packetData, packetSize, 0, NULL );
393#endif
394 if(bytesRead == sc_wouldBlockFlag)
395 {
396 delete packetData;
397 return 0;
398 }
399 // check the header, and see if we need to send back an ack
400 DataPacketHeader header = *((DataPacketHeader*)packetData);
401 if(header.GetAckFlags() == e_flag_AckRequested)
402 {
403 // 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
404 // 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
405 m_manager->RequestWriteAck(GetSmallId());
406 }
407 else
408 {
409 assert(header.GetAckFlags() == e_flag_AckNotRequested);
410 }
411 if(bytesRead > 0)
412 {
413 bytesRead -= headerSize;
414 memcpy(data, &packetData[headerSize], bytesRead);
415 }
416 assert(header.GetDataSize() == bytesRead);
417
418 delete packetData;
419
420 return bytesRead;
421}
422
423
424
425void SQRNetworkPlayer::ReadAck()
426{
427 DataPacketHeader header;
428#ifdef __PS3__
429 int bytesRead = cellRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );
430#else // __ORBIS__ && __PSVITA__
431 int bytesRead = sceRudpRead( m_rudpCtx, &header, sizeof(header), 0, NULL );
432#endif
433 if(bytesRead == sc_wouldBlockFlag)
434 {
435 return;
436 }
437
438 assert(header.GetAckFlags() == e_flag_AckReturning);
439 EnterCriticalSection(&m_csAcks);
440 m_acksOutstanding--;
441 assert(m_acksOutstanding >=0);
442 LeaveCriticalSection(&m_csAcks);
443
444#ifndef _CONTENT_PACKAGE
445#ifdef PRINT_ACK_STATS
446 __int64 timeTaken = System::currentTimeMillis() - m_ackStats[0];
447 if(timeTaken < m_minAckTime)
448 m_minAckTime = timeTaken;
449 if(timeTaken > m_maxAckTime)
450 m_maxAckTime = timeTaken;
451 m_totalAcks++;
452 m_totalAckTime += timeTaken;
453 m_averageAckTime = m_totalAckTime / m_totalAcks;
454 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);
455 m_ackStats.erase(m_ackStats.begin());
456#endif
457#endif
458}
459
460void SQRNetworkPlayer::WriteAck()
461{
462 SendInternal(NULL, 0, e_flag_AckReturning);
463}
464
465int SQRNetworkPlayer::GetOutstandingAckCount()
466{
467 return m_manager->GetOutstandingAckCount(this);
468}
469
470int SQRNetworkPlayer::GetTotalOutstandingAckCount()
471{
472 return m_acksOutstanding;
473}
474
475int SQRNetworkPlayer::GetTotalSendQueueBytes()
476{
477 return m_totalBytesInSendQueue;
478}
479
480int SQRNetworkPlayer::GetTotalSendQueueMessages()
481{
482 CriticalSectionScopeLock lock(&m_csQueue);
483 return m_sendQueue.size();
484
485}
486
487int SQRNetworkPlayer::GetSendQueueSizeBytes()
488{
489 return m_manager->GetSendQueueSizeBytes();
490}
491
492int SQRNetworkPlayer::GetSendQueueSizeMessages()
493{
494 return m_manager->GetSendQueueSizeMessages();
495}
496
497
498
499// 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,
500// 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
501// send here is complete, and can continue on.
502void SQRNetworkPlayer::SendMoreInternal()
503{
504 EnterCriticalSection(&m_csQueue);
505 assert(m_sendQueue.size() > 0); // this should never be called with an empty queue.
506
507 bool keepSending;
508 do
509 {
510 keepSending = false;
511 if( m_sendQueue.size() > 0)
512 {
513 // Attempt to send the full data in the first element in our queue
514 unsigned char *data= m_sendQueue.front().current;
515 int dataSize = m_sendQueue.front().end - m_sendQueue.front().current;
516 int ret = WriteDataPacket(data, dataSize, m_sendQueue.front().ack);
517
518 if( ret == dataSize )
519 {
520 // Fully sent, remove from queue - will loop in the while loop to see if there's anything else in the queue we could send
521 m_totalBytesInSendQueue -= ret;
522 delete [] m_sendQueue.front().start;
523 m_sendQueue.pop();
524 if( m_sendQueue.size() )
525 {
526 keepSending = true;
527 }
528 }
529 else if( ( ret >= 0 ) || ( ret == sc_wouldBlockFlag ) )
530 {
531
532 // Things left to send - adjust this element in the queue
533 int remainingBytes;
534 if( ret >= 0 )
535 {
536 // Only ret bytes sent so far
537 m_totalBytesInSendQueue -= ret;
538 remainingBytes = dataSize - ret;
539 assert(remainingBytes > 0 );
540 }
541 else
542 {
543 // Is CELL_RUDP_ERROR_WOULDBLOCK, nothing has yet been sent
544 remainingBytes = dataSize;
545 }
546 m_sendQueue.front().current = m_sendQueue.front().end - remainingBytes;
547 }
548 }
549 } while (keepSending);
550 LeaveCriticalSection(&m_csQueue);
551}
552
553void SQRNetworkPlayer::SetNameFromUID()
554{
555 mbstowcs(m_name, m_ISD.m_UID.getOnlineID(), 16);
556 m_name[16] = 0;
557#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
558 // Not an online player? Add a suffix with the controller ID on
559 if( m_ISD.m_UID.isSignedIntoPSN() == 0)
560 {
561 int pos = wcslen(m_name);
562 swprintf(&m_name[pos], 5, L" (%d)", m_ISD.m_UID.getQuadrant() + 1 );
563 }
564#endif
565}
566
567void SQRNetworkPlayer::SetName(char *name)
568{
569 mbstowcs(m_name, name, 20);
570 m_name[20] = 0;
571}
572
573int SQRNetworkPlayer::GetSessionIndex()
574{
575 return m_manager->GetSessionIndex(this);
576}
577
578bool SQRNetworkPlayer::HasVoice()
579{
580#ifdef __ORBIS__
581 return SonyVoiceChat_Orbis::hasMicConnected(this);
582#elif defined __PSVITA__
583 return SonyVoiceChat_Vita::hasMicConnected(this);
584#else
585 return SonyVoiceChat::hasMicConnected(&m_roomMemberId);
586#endif
587}
588
589bool SQRNetworkPlayer::IsTalking()
590{
591#ifdef __ORBIS__
592 return SonyVoiceChat_Orbis::isTalking(this);
593#elif defined __PSVITA__
594 return SonyVoiceChat_Vita::isTalking(this);
595#else
596 return SonyVoiceChat::isTalking(&m_roomMemberId);
597#endif
598}
599
600bool SQRNetworkPlayer::IsMutedByLocalUser(int userIndex)
601{
602#ifdef __ORBIS__
603// assert(0); // this is never called, so isn't implemented in the PS4 voice stuff at the moment
604 return false;
605#elif defined __PSVITA__
606 return false;// this is never called, so isn't implemented in the Vita voice stuff at the moment
607#else
608 SQRNetworkManager_PS3* pMan = (SQRNetworkManager_PS3*)m_manager;
609 return SonyVoiceChat::isMutedPlayer(pMan->m_roomSyncData.players[userIndex].m_roomMemberId);
610#endif
611}