the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at master 4132 lines 156 kB view raw
1#include "stdafx.h" 2#include "SQRNetworkManager_Vita.h" 3#include "SonyVoiceChat_Vita.h" 4#include "Common/Network/Sony/PlatformNetworkManagerSony.h" 5 6#include <np.h> 7#include <rudp.h> 8#include <np/np_basic.h> 9#include <libnetctl.h> 10#include <netcheck_dialog.h> 11 12#include "PSVita\PSVitaExtras\Conf.h" 13#include "Common\Network\Sony\SonyHttp.h" 14#include "..\..\..\Minecraft.World\C4JThread.h" 15 16// image used for the invite gui, filesize must be smaller than SCE_NP_MESSAGE_DIALOG_MAX_INDEX_ICON_SIZE ( 64K ) 17#define SESSION_IMAGE_PATH "app0:PSVita/session_image.png" 18 19int (* SQRNetworkManager_Vita::s_SignInCompleteCallbackFn)(void *pParam, bool bContinue, int pad) = NULL; 20void * SQRNetworkManager_Vita::s_SignInCompleteParam = NULL; 21sce::Toolkit::NP::PresenceDetails SQRNetworkManager_Vita::s_lastPresenceInfo; 22int SQRNetworkManager_Vita::s_resendPresenceCountdown = 0; 23bool SQRNetworkManager_Vita::s_presenceStatusDirty = false; 24bool SQRNetworkManager_Vita::s_signInCompleteCallbackIfFailed = false; 25SQRNetworkManager_Vita::PresenceSyncInfo SQRNetworkManager_Vita::s_lastPresenceSyncInfo = { 0 }; 26SQRNetworkManager_Vita::PresenceSyncInfo SQRNetworkManager_Vita::c_presenceSyncInfoNULL = { 0 }; 27//SceNpBasicAttachmentDataId SQRNetworkManager_Vita::s_lastInviteIdToRetry = SCE_NP_BASIC_INVALID_ATTACHMENT_DATA_ID; 28long long SQRNetworkManager_Vita::s_roomStartTime = 0; 29bool SQRNetworkManager_Vita::b_inviteRecvGUIRunning = false; 30SQRNetworkManager_Vita::PresenceSyncInfo* SQRNetworkManager_Vita::m_gameBootInvite; 31SQRNetworkManager_Vita::PresenceSyncInfo SQRNetworkManager_Vita::m_gameBootInvite_data; 32bool SQRNetworkManager_Vita::m_bCallPSNSignInCallback=false; 33bool SQRNetworkManager_Vita::m_bJoinablePresenceWaitingForOnline = false; 34SceAppUtilNpBasicJoinablePresenceParam SQRNetworkManager_Vita::m_joinablePresenceParam; 35bool SQRNetworkManager_Vita::m_bSendingInviteMessage; 36 37// static const int sc_UserEventHandle = 0; 38 39//unsigned int SQRNetworkManager_Vita::RoomSyncData::playerCount = 0; 40 41// This maps internal to extern states, and needs to match element-by-element the eSQRNetworkManagerInternalState enumerated type 42const SQRNetworkManager_Vita::eSQRNetworkManagerState SQRNetworkManager_Vita::m_INTtoEXTStateMappings[SQRNetworkManager_Vita::SNM_INT_STATE_COUNT] = 43{ 44 SNM_STATE_INITIALISING, // SNM_INT_STATE_UNINITIALISED 45 SNM_STATE_INITIALISING, // SNM_INT_STATE_SIGNING_IN 46 SNM_STATE_INITIALISING, // SNM_INT_STATE_STARTING_CONTEXT 47 SNM_STATE_INITIALISE_FAILED, // SNM_INT_STATE_INITIALISE_FAILED 48 SNM_STATE_IDLE, // SNM_INT_STATE_IDLE 49 SNM_STATE_IDLE, // SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT 50 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT 51 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER 52 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_SERVER_SEARCH_SERVER_ERROR 53 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_SERVER_FOUND 54 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_SERVER_SEARCH_CREATING_CONTEXT 55 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED 56 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_SEARCHING_FOR_WORLD 57 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_WORLD_FOUND 58 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM 59 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS 60 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED 61 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT 62 SNM_STATE_HOSTING, // SNM_INT_STATE_HOSTING_WAITING_TO_PLAY 63 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT 64 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER 65 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_SERVER_SEARCH_SERVER_ERROR 66 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_SERVER_FOUND 67 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_SERVER_SEARCH_CREATING_CONTEXT 68 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED 69 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_JOIN_ROOM 70 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED 71 SNM_STATE_JOINING, // SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS 72 SNM_STATE_ENDING, // SNM_INT_STATE_SERVER_DELETING_CONTEXT 73 SNM_STATE_STARTING, // SNM_INT_STATE_STARTING 74 SNM_STATE_PLAYING, // SNM_INT_STATE_PLAYING 75 SNM_STATE_LEAVING, // SNM_INT_STATE_LEAVING 76 SNM_STATE_LEAVING, // SNM_INT_STATE_LEAVING_FAILED 77 SNM_STATE_ENDING, // SNM_INT_STATE_ENDING 78}; 79 80SQRNetworkManager_Vita::SQRNetworkManager_Vita(ISQRNetworkManagerListener *listener) 81{ 82 m_state = SNM_INT_STATE_UNINITIALISED; 83 m_stateExternal = SNM_STATE_INITIALISING; 84 m_nextIdleReasonIsFull = false; 85 m_friendSearchState = SNM_FRIEND_SEARCH_STATE_IDLE; 86 m_serverContextValid = false; 87 m_isHosting = false; 88 m_currentSmallId = 0; 89 memset( m_aRoomSlotPlayers, 0, sizeof(m_aRoomSlotPlayers) ); 90 m_listener = listener; 91 m_soc = -1; 92 m_resendExternalRoomDataCountdown = 0; 93 m_matching2initialised = false; 94 m_matchingContextValid = false; 95 m_inviteIndex = 0; 96 m_doBootInviteCheck = true; 97 m_bSendingInviteMessage = false; 98 m_isInSession = false; 99 m_offlineGame = false; 100 m_offlineSQR = false; 101 m_aServerId = NULL; 102 m_gameBootInvite = NULL; 103 m_onlineStatus = false; 104 m_bLinkDisconnected = false; 105 m_bShuttingDown = false; 106 107 InitializeCriticalSection(&m_csRoomSyncData); 108 InitializeCriticalSection(&m_csPlayerState); 109 InitializeCriticalSection(&m_csStateChangeQueue); 110 InitializeCriticalSection(&m_csMatching); 111 InitializeCriticalSection(&m_csAckQueue); 112 113 memset( &m_roomSyncData,0,sizeof(m_roomSyncData)); // MGH - added to fix problem when joining a full room, and the sync data wasn't populated 114 115 // int ret = sceKernelCreateEqueue(&m_basicEventQueue, "SQRNetworkManager_Vita EQ"); 116 // assert(ret == SCE_OK); 117 // ret = sceKernelAddUserEvent(m_basicEventQueue, sc_UserEventHandle); 118 // assert(ret == SCE_OK); 119 // 120 // m_basicEventThread = new C4JThread(&BasicEventThreadProc,this,"Basic Event Handler"); 121 // m_basicEventThread->Run(); 122} 123 124// First stage of initialisation. This initialises a few things that don't require the user to be signed in, and then kicks of the network start dialog utility. 125// Initialisation continues in InitialiseAfterOnline once this completes. 126void SQRNetworkManager_Vita::Initialise() 127{ 128#define NP_IN_GAME_MESSAGE_POOL_SIZE ( 16 * 1024 ) 129 m_bShuttingDown = false; 130 int32_t ret = 0; 131 // int32_t libCtxId = 0; 132 // ret = sceNpInGameMessageInitialize(NP_IN_GAME_MESSAGE_POOL_SIZE, NULL); 133 // assert (ret >= 0); 134 // libCtxId = ret; 135 136 assert( m_state == SNM_INT_STATE_UNINITIALISED ); 137 138 139 //Initialize libnetctl - already done in SonyHttp_Vita::init 140 // app.DebugPrintf("sceNetCtlInit\n"); 141 // ret = sceNetCtlInit(); 142 // if( ( ret < 0 && ret != SCE_NET_CTL_ERROR_NOT_TERMINATED ) || ForceErrorPoint( SNM_FORCE_ERROR_NET_CTL_INIT ) ) 143 // { 144 // SetState(SNM_INT_STATE_INITIALISE_FAILED); 145 // return; 146 // } 147 148 m_hid=0; 149 app.DebugPrintf("sceNetCtlInetRegisterCallback\n"); 150 ret = sceNetCtlInetRegisterCallback(&NetCtlCallback,this,&m_hid); 151 assert(ret == SCE_OK); 152 153 // Initialise RUDP 154 const int RUDP_POOL_SIZE = (500 * 1024); // TODO - find out what we need, this size is copied from library reference 155 uint8_t *rudp_pool = (uint8_t *)malloc(RUDP_POOL_SIZE); 156 app.DebugPrintf("sceRudpInit\n"); 157 ret = sceRudpInit(rudp_pool, RUDP_POOL_SIZE); 158 if( ( ret < 0 ) || ForceErrorPoint( SNM_FORCE_ERROR_RUDP_INIT ) ) 159 { 160 SetState(SNM_INT_STATE_INITIALISE_FAILED); 161 return; 162 } 163 164 SetState(SNM_INT_STATE_SIGNING_IN); 165 // AttemptPSNSignIn(NULL, NULL); 166 167 // SonyHttp::init(); 168 169 // SceNpCommunicationConfig npConf ; 170 // npConf.commId = &s_npCommunicationId; 171 // npConf.commPassphrase = &s_npCommunicationPassphrase; 172 // npConf.commSignature = &s_npCommunicationSignature; 173 // ret = sceNpInit(&npConf, NULL); 174 // if (ret < 0 && ret != SCE_NP_ERROR_ALREADY_INITIALIZED) 175 // { 176 // app.DebugPrintf("sceNpInit failed, ret=%x\n", ret); 177 // assert(0); 178 // } 179 180 app.DebugPrintf("sceRudpEnableInternalIOThread\n"); 181 ret = sceRudpEnableInternalIOThread(RUDP_THREAD_STACK_SIZE, SCE_KERNEL_DEFAULT_PRIORITY); 182 if(ret < 0) 183 { 184 app.DebugPrintf("sceRudpEnableInternalIOThread failed with error code 0x%08x\n", ret); 185 assert(0); 186 } 187 // Already online? the callback won't catch this, so carry on initialising now 188 if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) 189 { 190 InitialiseAfterOnline(); 191 } 192 else 193 { 194 // On PS3 we'd be running the netstart dialog here, but we don't want to do that on Vita since we could be switching from ad-hoc mode 195 SetState(SNM_INT_STATE_INITIALISE_FAILED); 196 m_offlineSQR = true; 197 } 198 SonyVoiceChat_Vita::init(); 199 200 m_bIsInitialised = true; 201} 202 203bool SQRNetworkManager_Vita::IsInitialised() 204{ 205 return m_bIsInitialised; 206} 207void SQRNetworkManager_Vita::UnInitialise() 208{ 209 int ret; 210 // on changing to adhoc, we need to shutdown all PSN networking init 211 212 // shutdown voice chat 213 SonyVoiceChat_Vita::shutdown(); 214 215 app.DebugPrintf("sceNpMatching2ContextStop\n"); 216 int err = sceNpMatching2ContextStop(m_matchingContext); 217 218 app.DebugPrintf("sceNpMatching2Term\n"); 219 sceNpMatching2DestroyContext(m_matchingContext); 220 221 app.DebugPrintf("sceNpMatching2Term\n"); 222 ret = sceNpMatching2Term(); 223 224 app.DebugPrintf("sceRudpEnd\n"); 225 ret = sceRudpEnd(); 226 227 // shut down NP lib 228 app.DebugPrintf("sceNetCtlInetUnregisterCallback\n"); 229 ret = sceNetCtlInetUnregisterCallback(m_hid); 230 231 //app.DebugPrintf("sceNetCtlTerm\n"); 232 //sceNetCtlTerm(); 233 234 SetState(SNM_INT_STATE_UNINITIALISED); 235 m_bIsInitialised = false; 236 m_bShuttingDown = false; 237 238} 239 240void SQRNetworkManager_Vita::Terminate() 241{ 242 // If playing, attempt to nicely leave the room before shutting down so that our friends won't still think this game is in progress 243 if( ( m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS ) || 244 ( m_state == SNM_INT_STATE_HOSTING_WAITING_TO_PLAY ) || 245 ( m_state == SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS ) || 246 ( m_state == SNM_INT_STATE_PLAYING ) ) 247 { 248 if( !m_offlineGame ) 249 { 250 LeaveRoom(true); 251 int count = 200; 252 do 253 { 254 Tick(); 255 Sleep(10); 256 count--; 257 } while( ( count > 0 ) && ( m_state != SNM_INT_STATE_IDLE ) ); 258 app.DebugPrintf(CMinecraftApp::USER_RR,"Attempted to leave room, %dms used\n",count * 10); 259 } 260 } 261 262 app.DebugPrintf("sceRudpEnd\n"); 263 int ret = sceRudpEnd(); 264 app.DebugPrintf("sceNpMatching2Term\n"); 265 ret = sceNpMatching2Term(); 266 // Terminate event thread by sending it a non-zero value for data 267 // sceKernelTriggerUserEvent(m_basicEventQueue, sc_UserEventHandle, (void*)1); 268 269 270 // do 271 // { 272 // Sleep(10); 273 // } while( m_basicEventThread->isRunning() ); 274} 275 276// Second stage of initialisation, that requires NP Manager to be online & the player to be signed in. This kicks of the creation of a context 277// for Np Matching 2. Initialisation is finally complete when we get a callback to ContextCallback. The SQRNetworkManager_Vita is then finally moved 278// into SNM_INT_STATE_IDLE at this stage. 279void SQRNetworkManager_Vita::InitialiseAfterOnline() 280{ 281 // MGH - added, so we don't init the matching2 stuff in trial mode - devtrack #5921 282 if(!ProfileManager.IsFullVersion()) 283 return; 284 285 // SceNpId npId; 286 // int option = 0; 287 288 // We should only be doing this if we have come in from an initialisation stage (SQRNetworkManager_Vita::Initialise) or we've had a network disconnect and are coming in from an offline state. 289 // Don't do anything otherwise - this mainly to catch a bit of a corner case in the initialisation phase where potentially we could register for the callback that would call this with sceNpManagerRegisterCallback. 290 // and could then really quickly go online so that the there becomes two paths (via the callback or SQRNetworkManager_Vita::Initialise) by which this could be called 291 if( ( m_state != SNM_INT_STATE_SIGNING_IN ) && !(( m_state == SNM_INT_STATE_IDLE ) && m_offlineSQR) ) 292 { 293 // If we aren't going to continue on with this sign-in but are expecting a callback, then let the game know that we have completed the bit we are expecting to do. This 294 // will happen whilst in game, when we want to be able to sign into PSN, but don't expect the full matching stuff to get set up. 295 if( s_SignInCompleteCallbackFn ) 296 { 297 s_SignInCompleteCallbackFn(s_SignInCompleteParam,true,0); 298 s_SignInCompleteCallbackFn = NULL; 299 } 300 return; 301 } 302 303 // Initialize matching2 with default settings 304 //int sceNetAdhocMatchingInit(SceSize poolsize,void *poolptr); 305 306 app.DebugPrintf("sceNpMatching2Init\n"); 307 int ret = sceNpMatching2Init(0, 0, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, 0); 308 309 if( ( ret < 0 ) || ForceErrorPoint( SNM_FORCE_ERROR_MATCHING2_INIT ) ) 310 { 311 SetState(SNM_INT_STATE_INITIALISE_FAILED); 312 return; 313 } 314 app.DebugPrintf("SQRNetworkManager::InitialiseAfterOnline - matching context is now valid\n"); 315 m_matching2initialised = true; 316 317 // Get NP ID of the signed-in user 318 SceNpId npID; 319 int primaryPad = ProfileManager.GetPrimaryPad(); 320 if(primaryPad >=0 && ProfileManager.IsSignedInLive(primaryPad)) 321 { 322 ProfileManager.GetSceNpId(primaryPad, &npID); 323 } 324 else 325 { 326 SetState(SNM_INT_STATE_INITIALISE_FAILED); 327 return; 328 } 329 330 app.DebugPrintf("sceNpMatching2CreateContext\n"); 331 ret = sceNpMatching2CreateContext(&npID, GetSceNpCommsId(), &s_npCommunicationPassphrase, &m_matchingContext); 332 //ret = sceNpMatching2CreateContext(&npID, NULL, NULL, &m_matchingContext); 333 334 if( ( ret < 0 ) || ForceErrorPoint( SNM_FORCE_ERROR_CREATE_MATCHING_CONTEXT ) ) 335 { 336 SetState(SNM_INT_STATE_INITIALISE_FAILED); 337 return; 338 } 339 m_matchingContextValid = true; 340 341 bool bRet = RegisterCallbacks(); 342 if( ( !bRet ) || ForceErrorPoint( SNM_FORCE_ERROR_REGISTER_CALLBACKS ) ) 343 { 344 SetState(SNM_INT_STATE_INITIALISE_FAILED); 345 return; 346 } 347 348 // State should be starting context until the callback that this has been created happens 349 SetState(SNM_INT_STATE_STARTING_CONTEXT); 350 351 // Start the context 352 // Set time-out time to 10 seconds 353 app.DebugPrintf("sceNpMatching2ContextStart\n"); 354 ret = sceNpMatching2ContextStart(m_matchingContext, (10*1000*1000)); 355 356 if( ( ret < 0 ) || ForceErrorPoint( SNM_FORCE_ERROR_CONTEXT_START_ASYNC ) ) 357 { 358 SetState(SNM_INT_STATE_INITIALISE_FAILED); 359 } 360} 361 362 363// General tick function to be called from main game loop - any internal tick functions should be called from here. 364void SQRNetworkManager_Vita::Tick() 365{ 366 TickWriteAcks(); 367 OnlineCheck(); 368 sceNetCtlCheckCallback(); 369 updateNetCheckDialog(); 370 ServerContextTick(); 371 RoomCreateTick(); 372 FriendSearchTick(); 373 TickRichPresence(); 374 TickJoinablePresenceData(); 375 // TickInviteGUI(); // TODO 376 377 if( ( m_gameBootInvite ) && ( s_safeToRespondToGameBootInvite ) ) 378 { 379 m_listener->HandleInviteReceived( ProfileManager.GetPrimaryPad(), m_gameBootInvite ); 380 m_gameBootInvite = NULL; 381 } 382 383 ErrorHandlingTick(); 384 // If we ever fail to send the external room data, we start a countdown so that we attempt to resend. Not sure how likely it is that updating this will fail without the whole network being broken, 385 // but if in particular we don't update the flag to say that the session is joinable, then nobody is ever going to see this session. 386 if( m_resendExternalRoomDataCountdown ) 387 { 388 if( m_state == SNM_INT_STATE_PLAYING ) 389 { 390 m_resendExternalRoomDataCountdown--; 391 if( m_resendExternalRoomDataCountdown == 0 ) 392 { 393 UpdateExternalRoomData(); 394 } 395 } 396 else 397 { 398 m_resendExternalRoomDataCountdown = 0; 399 } 400 } 401 402 // ProfileManager.SetNetworkStatus(GetOnlineStatus()); 403 404 // Client only - do the final transition to a starting & playing state once we have fully joined the room, And told the game about all the local players so they are also all valid 405 if( m_state == SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS ) 406 { 407 if( m_localPlayerJoined == m_localPlayerCount ) 408 { 409 // Since we're now fully joined, we can update our presence info so that our friends could find us in this game. This data was set up 410 // at the point that we joined the game (either from search info, or an invitation). 411 UpdateRichPresenceCustomData(&s_lastPresenceSyncInfo, sizeof(PresenceSyncInfo)); 412 SetState( SNM_INT_STATE_STARTING); 413 SetState( SNM_INT_STATE_PLAYING ); 414 } 415 } 416 417 if( m_state == SNM_INT_STATE_SERVER_DELETING_CONTEXT ) 418 { 419 // make sure we've removed all the remote players and killed the udp connections before we bail out 420 if(m_RudpCtxToPlayerMap.size() == 0) 421 ResetToIdle(); 422 } 423 424 EnterCriticalSection(&m_csStateChangeQueue); 425 while(m_stateChangeQueue.size() > 0 ) 426 { 427 if( m_listener ) 428 { 429 m_listener->HandleStateChange(m_stateChangeQueue.front().m_oldState, m_stateChangeQueue.front().m_newState, m_stateChangeQueue.front().m_idleReasonIsSessionFull); 430 if( m_stateChangeQueue.front().m_newState == SNM_STATE_IDLE ) 431 { 432 m_isInSession = false; 433 } 434 } 435 m_stateExternal = m_stateChangeQueue.front().m_newState; 436 m_stateChangeQueue.pop(); 437 } 438 LeaveCriticalSection(&m_csStateChangeQueue); 439 440 // 4J-PB - SQRNetworkManager_PS3::AttemptPSNSignIn was causing crashes in Iggy by calling LoadMovie from a callback, so call it frmo the tick instead 441 if(m_bCallPSNSignInCallback) 442 { 443 m_bCallPSNSignInCallback=false; 444 if( s_signInCompleteCallbackIfFailed ) 445 { 446 s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 447 s_SignInCompleteCallbackFn = NULL; 448 } 449 else if(s_SignInCompleteCallbackFn) 450 { 451 s_SignInCompleteCallbackFn(s_SignInCompleteParam, true, 0); 452 s_SignInCompleteCallbackFn = NULL; 453 } 454 } 455 456} 457 458// Detect any states which reflect internal error states, do anything required, and transition away again 459void SQRNetworkManager_Vita::ErrorHandlingTick() 460{ 461 switch( m_state ) 462 { 463 case SNM_INT_STATE_INITIALISE_FAILED: 464 if( s_SignInCompleteCallbackFn ) 465 { 466 if( s_signInCompleteCallbackIfFailed ) 467 { 468 s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 469 } 470 s_SignInCompleteCallbackFn = NULL; 471 } 472 app.DebugPrintf("Network error: SNM_INT_STATE_INITIALISE_FAILED\n"); 473 if( m_isInSession && m_offlineGame) // m_offlineSQR ) // MGH - changed this to m_offlineGame, as m_offlineSQR can be true when running an online game but the init has failed because the servers are down 474 { 475 // This is a fix for an issue where a player attempts (and fails) to sign in, whilst in an offline game. This was setting the state to idle, which in turn 476 // sets the game to Not be in a session anymore (but the game wasn't generally aware of, and so keeps playing). Howoever, the game's connections use 477 // their tick to determine whether to empty their queues or not and so no communications (even though they don't actually use this network manager for local connections) 478 // were happening. 479 SetState(SNM_INT_STATE_PLAYING); 480 } 481 else 482 { 483 m_offlineSQR = true; 484 SetState(SNM_INT_STATE_IDLE); 485 } 486 break; 487 case SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED: 488 app.DebugPrintf("Network error: SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED\n"); 489 ResetToIdle(); 490 break; 491 case SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED: 492 app.DebugPrintf("Network error: SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED\n"); 493 DeleteServerContext(); 494 break; 495 case SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED: 496 app.DebugPrintf("Network error: SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED\n"); 497 ResetToIdle(); 498 break; 499 case SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED: 500 app.DebugPrintf("Network error: SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED\n"); 501 DeleteServerContext(); 502 break; 503 case SNM_INT_STATE_LEAVING_FAILED: 504 app.DebugPrintf("Network error: SNM_INT_STATE_LEAVING_FAILED\n"); 505 DeleteServerContext(); 506 break; 507 } 508 509} 510 511// Start hosting a game, by creating a room & joining it. We explicity create a server context here (via GetServerContext) as Sony suggest that 512// this means we have greater control of representing when players are actually "online". The creation of the room is carried out in a callback 513// after that server context is made (ServerContextValidCallback_CreateRoom). 514// hostIndex is the index of the user that is hosting the session, and localPlayerMask has bit 0 - 3 set to indicate the full set of local players joining the game. 515// extData and extDataSize define the initial state of room data that is externally visible (eg by players searching for rooms, but not in it) 516void SQRNetworkManager_Vita::CreateAndJoinRoom(int hostIndex, int localPlayerMask, void *extData, int extDataSize, bool offline) 517{ 518 // hostIndex should always be in the mask 519 assert( ( ( 1 << hostIndex ) & localPlayerMask ) != 0 ); 520 521 m_isHosting = true; 522 m_joinExtData = extData; 523 m_joinExtDataSize = extDataSize; 524 m_offlineGame = offline; 525 m_resendExternalRoomDataCountdown = 0; 526 m_isInSession= true; 527 528 // Default value for room, which we can use for offlinae games 529 m_room = 0; 530 531 // Initialise room data that will be synchronised. Slot 0 is always reserved for the host. We don't know the 532 // room member until the room is actually created so this will be set/updated at that point 533 memset( &m_roomSyncData, 0, sizeof(m_roomSyncData) ); 534 m_roomSyncData.setPlayerCount(1); 535 m_roomSyncData.players[0].m_smallId = m_currentSmallId++; 536 m_roomSyncData.players[0].m_localIdx = hostIndex; 537 538 // Remove the host player that we've already added, then add any other local players specified in the mask 539 localPlayerMask &= ~( ( 1 << hostIndex ) & localPlayerMask ); 540 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 541 { 542 if( localPlayerMask & ( 1 << i ) ) 543 { 544 m_roomSyncData.players[m_roomSyncData.getPlayerCount()].m_smallId = m_currentSmallId++; 545 m_roomSyncData.players[m_roomSyncData.getPlayerCount()].m_localIdx = i; 546 m_roomSyncData.setPlayerCount(m_roomSyncData.getPlayerCount()+1); 547 } 548 } 549 m_localPlayerCount = m_roomSyncData.getPlayerCount(); 550 551 // For offline games, we can jump straight to the state that says we've just created the room (or would have, for an online game) 552 if( m_offlineGame ) 553 { 554 SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS); 555 } 556 else 557 { 558 // Kick off the sequence of events required for an online game, starting with getting the server context 559 m_isInSession = GetServerContext(); 560 } 561} 562 563// Updates the externally visible data that was associated with the room when it was created with CreateAndJoinRoom. 564void SQRNetworkManager_Vita::UpdateExternalRoomData() 565{ 566 if( m_offlineGame ) return; 567 if( m_isHosting ) 568 { 569 SceNpMatching2SetRoomDataExternalRequest reqParam; 570 memset( &reqParam, 0, sizeof(reqParam) ); 571 reqParam.roomId = m_room; 572 SceNpMatching2BinAttr roomBinAttr; 573 memset(&roomBinAttr, 0, sizeof(roomBinAttr)); 574 roomBinAttr.id = SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID; 575 roomBinAttr.ptr = m_joinExtData; 576 roomBinAttr.size = m_joinExtDataSize; 577 reqParam.roomBinAttrExternalNum = 1; 578 reqParam.roomBinAttrExternal = &roomBinAttr; 579 580 app.DebugPrintf("sceNpMatching2SetRoomDataExternal\n"); 581 int ret = sceNpMatching2SetRoomDataExternal ( m_matchingContext, &reqParam, NULL, &m_setRoomDataRequestId ); 582 app.DebugPrintf(CMinecraftApp::USER_RR,"sceNpMatching2SetRoomDataExternal returns 0x%x, number of players %d\n",ret,((char *)m_joinExtData)[174]); 583 if( ( ret < 0 ) || ForceErrorPoint( SNM_FORCE_ERROR_SET_EXTERNAL_ROOM_DATA ) ) 584 { 585 // If we ever fail to send the external room data, we start a countdown so that we attempt to resend. Not sure how likely it is that updating this will fail without the whole network being broken, 586 // but if in particular we don't update the flag to say that the session is joinable, then nobody is ever going to see this session. 587 m_resendExternalRoomDataCountdown = 60; 588 } 589 } 590} 591 592// Determine if the friend room manager is busy. If it isn't busy, then other operations (searching for a friend, reading the found friend's room lists) may safely be performed 593bool SQRNetworkManager_Vita::FriendRoomManagerIsBusy() 594{ 595 return (m_friendSearchState != SNM_FRIEND_SEARCH_STATE_IDLE); 596} 597 598// Initiate a search for rooms that the signed in user's friends are in. This is an asynchronous operation, this function returns after it kicks off a search across all game servers 599// for any of the player's friends. 600bool SQRNetworkManager_Vita::FriendRoomManagerSearch() 601{ 602 if( m_state != SNM_INT_STATE_IDLE ) return false; 603 604 // Don't start another search if we're already searching... 605 if( m_friendSearchState != SNM_FRIEND_SEARCH_STATE_IDLE ) 606 { 607 return false; 608 } 609 610 // Free up any external data that we received from the previous search 611 for( int i = 0; i < m_aFriendSearchResults.size(); i++ ) 612 { 613 if(m_aFriendSearchResults[i].m_RoomExtDataReceived) 614 free(m_aFriendSearchResults[i].m_RoomExtDataReceived); 615 m_aFriendSearchResults[i].m_RoomExtDataReceived = NULL; 616 } 617 618 m_friendSearchState = SNM_FRIEND_SEARCH_STATE_GETTING_FRIEND_COUNT; 619 m_friendCount = 0; 620 m_aFriendSearchResults.clear(); 621 622 // Get friend list - doing this in another thread as it can lock up for a few seconds 623 m_getFriendCountThread = new C4JThread(&GetFriendsThreadProc,this,"GetFriendsThreadProc"); 624 m_getFriendCountThread->Run(); 625 626 return true; 627} 628 629bool SQRNetworkManager_Vita::FriendRoomManagerSearch2() 630{ 631 if( m_friendCount == 0 ) 632 { 633 m_friendSearchState = SNM_FRIEND_SEARCH_STATE_IDLE; 634 return false; 635 } 636 637 if( m_aFriendSearchResults.size() > 0 ) 638 { 639 // If we have some results, then we also want to make sure that we don't have any duplicate rooms here if more than one friend is playing in the same room. 640 unordered_set<SceNpMatching2RoomId> uniqueRooms; 641 for( unsigned int i = 0; i < m_aFriendSearchResults.size(); i++ ) 642 { 643 if(m_aFriendSearchResults[i].m_RoomFound) 644 { 645 uniqueRooms.insert( m_aFriendSearchResults[i].m_RoomId ); 646 } 647 } 648 649 // Tidy the results up further based on this 650 for( unsigned int i = 0; i < m_aFriendSearchResults.size(); ) 651 { 652 if( uniqueRooms.find(m_aFriendSearchResults[i].m_RoomId) == uniqueRooms.end() ) 653 { 654 free(m_aFriendSearchResults[i].m_RoomExtDataReceived); 655 m_aFriendSearchResults[i] = m_aFriendSearchResults.back(); 656 m_aFriendSearchResults.pop_back(); 657 } 658 else 659 { 660 uniqueRooms.erase(m_aFriendSearchResults[i].m_RoomId); 661 i++; 662 } 663 } 664 } 665 m_friendSearchState = SNM_FRIEND_SEARCH_STATE_IDLE; 666 return true; 667} 668 669void SQRNetworkManager_Vita::FriendSearchTick() 670{ 671 // Move onto next state if we're done getting our friend count 672 if( m_friendSearchState == SNM_FRIEND_SEARCH_STATE_GETTING_FRIEND_COUNT ) 673 { 674 if( !m_getFriendCountThread->isRunning() ) 675 { 676 m_friendSearchState = SNM_FRIEND_SEARCH_STATE_GETTING_FRIEND_INFO; 677 delete m_getFriendCountThread; 678 m_getFriendCountThread = NULL; 679 FriendRoomManagerSearch2(); 680 } 681 } 682} 683 684// The handler for basic events can't actually get the events themselves, this has to be done on another thread. Instead, we send a sys_event_t to a queue on This thread, 685// which has a single data item used which we can use to determine whether to terminate this thread or get a basic event & handle that. 686int SQRNetworkManager_Vita::BasicEventThreadProc( void *lpParameter ) 687{ 688 PSVITA_STUBBED; 689 return 0; 690 // SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)lpParameter; 691 // 692 // int ret = SCE_OK; 693 // SceKernelEvent event; 694 // int outEv; 695 // 696 // do 697 // { 698 // ret = sceKernelWaitEqueue(manager->m_basicEventQueue, &event, 1, &outEv, NULL); 699 // 700 // // If the sys_event_t we've sent here from the handler has a non-zero data1 element, this is to signify that we should terminate the thread 701 // if( event.udata == 0 ) 702 // { 703 // // int iEvent; 704 // // SceNpUserInfo from; 705 // // uint8_t buffer[SCE_NP_BASIC_MAX_MESSAGE_SIZE]; 706 // // size_t bufferSize = SCE_NP_BASIC_MAX_MESSAGE_SIZE; 707 // // int ret = sceNpBasicGetEvent(&iEvent, &from, &buffer, &bufferSize); 708 // // if( ret == 0 ) 709 // // { 710 // // if( iEvent == SCE_NP_BASIC_EVENT_INCOMING_BOOTABLE_INVITATION ) 711 // // { 712 // // // 4J Stu - Don't do this here as it can be very disruptive to gameplay. Players can bring this up from LoadOrJoinMenu, PauseMenu and InGameInfoMenu 713 // // //sceNpBasicRecvMessageCustom(SCE_NP_BASIC_MESSAGE_MAIN_TYPE_INVITE, SCE_NP_BASIC_RECV_MESSAGE_OPTIONS_INCLUDE_BOOTABLE, SYS_MEMORY_CONTAINER_ID_INVALID); 714 // // } 715 // // if( iEvent == SCE_NP_BASIC_EVENT_RECV_INVITATION_RESULT ) 716 // // { 717 // // SceNpBasicExtendedAttachmentData *result = (SceNpBasicExtendedAttachmentData *)buffer; 718 // // if(result->userAction == SCE_NP_BASIC_MESSAGE_ACTION_ACCEPT ) 719 // // { 720 // // manager->GetInviteDataAndProcess(result->data.id); 721 // // } 722 // // } 723 // // app.DebugPrintf("Incoming basic event of type %d\n",iEvent); 724 // // } 725 // } 726 // 727 // } while(event.udata == 0 ); 728 // return 0; 729} 730 731int SQRNetworkManager_Vita::GetFriendsThreadProc( void* lpParameter ) 732{ 733 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)lpParameter; 734 735 int ret = 0; 736 manager->m_aFriendSearchResults.clear(); 737 manager->m_friendCount = 0; 738 if(!ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) 739 { 740 app.DebugPrintf("getFriendslist failed, not signed into Live! \n"); 741 return 0; 742 } 743 744 745 ret = sceNpBasicGetFriendListEntryCount(&manager->m_friendCount); 746 if( ( ret < 0 ) || manager->ForceErrorPoint( SNM_FORCE_ERROR_GET_FRIEND_LIST_ENTRY_COUNT ) ) 747 { 748 // This is likely when friend list hasn't been received from the server yet - will be returning SCE_NP_BASIC_ERROR_BUSY in this case 749 manager->m_friendCount = 0; 750 } 751 752 753 // There shouldn't ever be more than 100 friends returned but limit here just in case 754 if( manager->m_friendCount > 100 ) manager->m_friendCount = 100; 755 756 SceNpId* friendIDs = NULL; 757 if(manager->m_friendCount > 0) 758 { 759 // grab all the friend IDs first 760 friendIDs = new SceNpId[manager->m_friendCount]; 761 SceSize numRecieved; 762 ret = sceNpBasicGetFriendListEntries(0, friendIDs, manager->m_friendCount, &numRecieved); 763 if (ret < 0) 764 { 765 app.DebugPrintf("sceNpBasicGetFriendListEntries() failed: ret = 0x%x\n", ret); 766 manager->m_friendCount = 0; 767 } 768 else 769 { 770 assert(numRecieved == manager->m_friendCount); 771 } 772 } 773 774 775 // It is possible that the size of the friend list might vary from what we just received, so only add in friends that we successfully get an entry for 776 for( unsigned int i = 0; i < manager->m_friendCount; i++ ) 777 { 778 static SceNpBasicGamePresence presenceDetails; 779 static SceNpBasicFriendContextState contextState; 780 int ret = sceNpBasicGetFriendContextState(&friendIDs[i], &contextState); 781 if (ret < 0) 782 { 783 app.DebugPrintf("sceNpBasicGetFriendContextState() failed: ret = 0x%x\n", ret); 784 contextState = SCE_NP_BASIC_FRIEND_CONTEXT_STATE_UNKNOWN; 785 } 786 if(contextState == SCE_NP_BASIC_FRIEND_CONTEXT_STATE_IN_CONTEXT) // using the same SceNpCommunicationId, so playing Minecraft 787 { 788 ret = sceNpBasicGetGamePresenceOfFriend(&friendIDs[i], &presenceDetails); 789 if( ( ret == 0 ) && ( !manager->ForceErrorPoint( SNM_FORCE_ERROR_GET_FRIEND_LIST_ENTRY ) ) ) 790 { 791 FriendSearchResult result; 792 memcpy(&result.m_NpId, &friendIDs[i], sizeof(SceNpId)); 793 result.m_RoomFound = false; 794 795 // Only include the friend's game if its the same network id ( this also filters out generally Zeroed PresenceSyncInfo, which we do when we aren't in an active game session) 796 // if( presenceDetails.size == sizeof(PresenceSyncInfo) ) 797 { 798 PresenceSyncInfo *pso = (PresenceSyncInfo *)presenceDetails.inGamePresence.data; 799 if( pso->netVersion == MINECRAFT_NET_VERSION ) 800 { 801 if( !pso->inviteOnly ) 802 { 803 result.m_RoomFound = true; 804 result.m_RoomId = pso->m_RoomId; 805 result.m_ServerId = pso->m_ServerId; 806 807 CPlatformNetworkManagerSony::MallocAndSetExtDataFromSQRPresenceInfo(&result.m_RoomExtDataReceived, pso); 808 manager->m_aFriendSearchResults.push_back(result); 809 } 810 } 811 } 812 } 813 } 814 } 815 816 if(friendIDs) 817 delete friendIDs; 818 return 0; 819} 820 821// Get count of rooms that friends are playing in. Only valid when FriendRoomManagerIsBusy() returns false 822int SQRNetworkManager_Vita::FriendRoomManagerGetCount() 823{ 824 assert( m_friendSearchState == SNM_FRIEND_SEARCH_STATE_IDLE ); 825 return m_aFriendSearchResults.size(); 826} 827 828// Get details of a found session that a friend is playing in. 0 < idx < FriendRoomManagerGetCount(). Only valid when FriendRoomManagerIsBusy() returns false 829void SQRNetworkManager_Vita::FriendRoomManagerGetRoomInfo(int idx, SQRNetworkManager_Vita::SessionSearchResult *searchResult) 830{ 831 assert( idx < m_aFriendSearchResults.size() ); 832 assert( m_friendSearchState == SNM_FRIEND_SEARCH_STATE_IDLE ); 833 834 searchResult->m_NpId = m_aFriendSearchResults[idx].m_NpId; 835 searchResult->m_sessionId.m_RoomId = m_aFriendSearchResults[idx].m_RoomId; 836 searchResult->m_sessionId.m_ServerId = m_aFriendSearchResults[idx].m_ServerId; 837 searchResult->m_extData = m_aFriendSearchResults[idx].m_RoomExtDataReceived; 838} 839 840// Get overall state of the network manager. 841SQRNetworkManager_Vita::eSQRNetworkManagerState SQRNetworkManager_Vita::GetState() 842{ 843 return m_stateExternal;; 844} 845 846bool SQRNetworkManager_Vita::IsHost() 847{ 848 return m_isHosting; 849} 850 851bool SQRNetworkManager_Vita::IsReadyToPlayOrIdle() 852{ 853 return (( m_state == SNM_INT_STATE_HOSTING_WAITING_TO_PLAY ) || ( m_state == SNM_INT_STATE_PLAYING ) || ( m_state == SNM_INT_STATE_IDLE ) ); 854} 855 856 857// Consider as "in session" from the moment that a game is created or joined, until the point where the game itself has been told via state change that we are now idle. The 858// game code requires IsInSession to return true as soon as it has asked to do one of these things (even if the state system hasn't really caught up with this request yet), and 859// it also requires that it is informed of the state changes leading up to not being in the session, before this should report false. 860bool SQRNetworkManager_Vita::IsInSession() 861{ 862 return m_isInSession; 863} 864 865// Get count of players currently in the session 866int SQRNetworkManager_Vita::GetPlayerCount() 867{ 868 return m_roomSyncData.getPlayerCount(); 869} 870 871// Get count of players who are in the session, but not local to this machine 872int SQRNetworkManager_Vita::GetOnlinePlayerCount() 873{ 874 int onlineCount = 0; 875 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 876 { 877 if( m_roomSyncData.players[i].m_roomMemberId != m_localMemberId ) 878 { 879 onlineCount++; 880 } 881 } 882 return onlineCount; 883} 884 885SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerByIndex(int idx) 886{ 887 if( idx < MAX_ONLINE_PLAYER_COUNT ) 888 { 889 return GetPlayerIfReady(m_aRoomSlotPlayers[idx]); 890 } 891 else 892 { 893 return NULL; 894 } 895} 896 897SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerBySmallId(int idx) 898{ 899 EnterCriticalSection(&m_csRoomSyncData); 900 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 901 { 902 if( m_roomSyncData.players[i].m_smallId == idx ) 903 { 904 SQRNetworkPlayer *player = GetPlayerIfReady(m_aRoomSlotPlayers[i]); 905 LeaveCriticalSection(&m_csRoomSyncData); 906 return player; 907 } 908 } 909 LeaveCriticalSection(&m_csRoomSyncData); 910 return NULL; 911} 912 913SQRNetworkPlayer *SQRNetworkManager_Vita::GetLocalPlayerByUserIndex(int idx) 914{ 915 EnterCriticalSection(&m_csRoomSyncData); 916 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 917 { 918 if( ( m_roomSyncData.players[i].m_roomMemberId == m_localMemberId ) && ( m_roomSyncData.players[i].m_localIdx == idx ) ) 919 { 920 SQRNetworkPlayer *player = GetPlayerIfReady(m_aRoomSlotPlayers[i]); 921 LeaveCriticalSection(&m_csRoomSyncData); 922 return player; 923 } 924 } 925 LeaveCriticalSection(&m_csRoomSyncData); 926 return NULL; 927} 928 929SQRNetworkPlayer *SQRNetworkManager_Vita::GetHostPlayer() 930{ 931 EnterCriticalSection(&m_csRoomSyncData); 932 SQRNetworkPlayer *player = GetPlayerIfReady(m_aRoomSlotPlayers[0]); 933 LeaveCriticalSection(&m_csRoomSyncData); 934 return player; 935} 936 937SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerIfReady(SQRNetworkPlayer *player) 938{ 939 if( player == NULL ) return NULL; 940 941 if( player->IsReady() ) return player; 942 943 return NULL; 944} 945 946// Update state internally 947 948#ifdef _DEBUG 949static const char szNetState[35][60]= 950{ 951 "SNM_INT_STATE_UNINITIALISED", 952 "SNM_INT_STATE_SIGNING_IN", 953 "SNM_INT_STATE_STARTING_CONTEXT", 954 "SNM_INT_STATE_INITIALISE_FAILED", 955 "SNM_INT_STATE_IDLE", 956 "SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT", 957 "SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT", 958 "SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER", 959 "SNM_INT_STATE_HOSTING_SERVER_SEARCH_SERVER_ERROR", 960 "SNM_INT_STATE_HOSTING_SERVER_FOUND", 961 "SNM_INT_STATE_HOSTING_SERVER_SEARCH_CREATING_CONTEXT", 962 "SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED", 963 "SNM_INT_STATE_HOSTING_CREATE_ROOM_SEARCHING_FOR_WORLD", 964 "SNM_INT_STATE_HOSTING_CREATE_ROOM_WORLD_FOUND", 965 "SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM", 966 "SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS", 967 "SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED", 968 "SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT", 969 "SNM_INT_STATE_HOSTING_WAITING_TO_PLAY", 970 "SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT", 971 "SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER", 972 "SNM_INT_STATE_JOINING_SERVER_SEARCH_SERVER_ERROR", 973 "SNM_INT_STATE_JOINING_SERVER_FOUND", 974 "SNM_INT_STATE_JOINING_SERVER_SEARCH_CREATING_CONTEXT", 975 "SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED", 976 "SNM_INT_STATE_JOINING_JOIN_ROOM", 977 "SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED", 978 "SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS", 979 "SNM_INT_STATE_SERVER_DELETING_CONTEXT", 980 "SNM_INT_STATE_STARTING", 981 "SNM_INT_STATE_PLAYING", 982 "SNM_INT_STATE_LEAVING", 983 "SNM_INT_STATE_LEAVING_FAILED", 984 "SNM_INT_STATE_ENDING", 985 "SNM_INT_STATE_COUNT" 986}; 987 988#endif 989void SQRNetworkManager_Vita::SetState(SQRNetworkManager_Vita::eSQRNetworkManagerInternalState state) 990{ 991#ifdef _DEBUG 992 app.DebugPrintf("SQRNetworkManager_Vita::SetState [%s]\n",szNetState[state]); 993#endif 994 995 eSQRNetworkManagerState oldState = m_INTtoEXTStateMappings[m_state]; 996 eSQRNetworkManagerState newState = m_INTtoEXTStateMappings[state]; 997 bool setIdleReasonSessionFull = false; 998 if( ( state == SNM_INT_STATE_IDLE ) && m_nextIdleReasonIsFull ) 999 { 1000 setIdleReasonSessionFull = true; 1001 m_nextIdleReasonIsFull = false; 1002 } 1003 m_state = state; 1004 // Queue any important (ie externally relevant) state changes - we will do a call back for these in our main tick. Don't do it directly here 1005 // as we could be coming from any thread at this stage, with any stack size etc. and so we don't generally want to expect the game to be able to handle itself in such circumstances. 1006 if( ( newState != oldState ) || setIdleReasonSessionFull ) 1007 { 1008 EnterCriticalSection(&m_csStateChangeQueue); 1009 m_stateChangeQueue.push(StateChangeInfo(oldState,newState,setIdleReasonSessionFull)); 1010 LeaveCriticalSection(&m_csStateChangeQueue); 1011 } 1012} 1013 1014void SQRNetworkManager_Vita::ResetToIdle() 1015{ 1016 app.DebugPrintf("------------------ResetToIdle--------------------\n"); 1017 // If we're the client, remove any networked players properly ( this will destory their rupd context etc.) 1018 if( !m_isHosting ) 1019 { 1020 RemoveNetworkPlayers((1 << MAX_LOCAL_PLAYER_COUNT)-1); 1021 } 1022 m_serverContextValid = false; 1023 m_isHosting = false; 1024 m_currentSmallId = 0; 1025 EnterCriticalSection(&m_csRoomSyncData); 1026 for(int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1027 { 1028 delete m_aRoomSlotPlayers[i]; 1029 } 1030 memset( m_aRoomSlotPlayers, 0, sizeof(m_aRoomSlotPlayers) ); 1031 memset( &m_roomSyncData,0,sizeof(m_roomSyncData)); 1032 LeaveCriticalSection(&m_csRoomSyncData); 1033 SetState(SNM_INT_STATE_IDLE); 1034 SonyVoiceChat_Vita::checkFinished(); 1035} 1036 1037// Join a room that was found with FriendRoomManagerSearch. 0 < idx < FriendRoomManagerGetCount(). Only valid when FriendRoomManagerIsBusy() returns false 1038bool SQRNetworkManager_Vita::JoinRoom(SQRNetworkManager_Vita::SessionSearchResult *searchResult, int localPlayerMask) 1039{ 1040 // Set up the presence info we would like to synchronise out when we have fully joined the game 1041 CPlatformNetworkManagerSony::SetSQRPresenceInfoFromExtData(&s_lastPresenceSyncInfo, searchResult->m_extData, searchResult->m_sessionId.m_RoomId, searchResult->m_sessionId.m_ServerId); 1042 return JoinRoom(searchResult->m_sessionId.m_RoomId, searchResult->m_sessionId.m_ServerId, localPlayerMask, NULL); 1043} 1044 1045// Join room with a specified roomId. This is used when joining from an invite, as well as by the previous method 1046bool SQRNetworkManager_Vita::JoinRoom(SceNpMatching2RoomId roomId, SceNpMatching2ServerId serverId, int localPlayerMask, const SQRNetworkManager_Vita::PresenceSyncInfo *presence) 1047{ 1048 // The presence info will be directly passed in if we are joining from an invite, otherwise it has already been set up. This is synchronised out when we have fully joined the game. 1049 if( presence ) 1050 { 1051 memcpy( &s_lastPresenceSyncInfo, presence, sizeof(PresenceSyncInfo) ); 1052 } 1053 1054 m_isInSession = true; 1055 1056 m_isHosting = false; 1057 m_offlineGame = false; 1058 m_roomToJoin = roomId; 1059 m_localPlayerJoinMask = localPlayerMask; 1060 m_localPlayerCount = 0; 1061 m_localPlayerJoined = 0; 1062 1063 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 1064 { 1065 if( localPlayerMask & ( 1 << i ) ) m_localPlayerCount++; 1066 } 1067 1068 return GetServerContext( serverId ); 1069} 1070 1071void SQRNetworkManager_Vita::StartGame() 1072{ 1073 assert( ( m_state == SNM_INT_STATE_HOSTING_WAITING_TO_PLAY ) || (( m_state == SNM_INT_STATE_IDLE ) && m_offlineSQR) ); 1074 1075 SetState( SNM_INT_STATE_STARTING); 1076 SetState( SNM_INT_STATE_PLAYING); 1077} 1078 1079void SQRNetworkManager_Vita::LeaveRoom(bool bActuallyLeaveRoom) 1080{ 1081 if( m_offlineGame ) 1082 { 1083 if( m_state != SNM_INT_STATE_PLAYING ) return; 1084 1085 SetState(SNM_INT_STATE_LEAVING); 1086 SetState(SNM_INT_STATE_ENDING); 1087 ResetToIdle(); 1088 return; 1089 } 1090 1091 UpdateRichPresenceCustomData(& c_presenceSyncInfoNULL, sizeof(PresenceSyncInfo) ); 1092 1093 // SonyVoiceChat::shutdown(); 1094 1095 // Attempt to leave the room if we are in any of the states we could be in if we have successfully created it 1096 if( bActuallyLeaveRoom ) 1097 { 1098 if( ( m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS ) || 1099 ( m_state == SNM_INT_STATE_HOSTING_WAITING_TO_PLAY ) || 1100 ( m_state == SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS ) || 1101 ( m_state == SNM_INT_STATE_PLAYING ) ) 1102 { 1103 SceNpMatching2LeaveRoomRequest reqParam; 1104 memset( &reqParam, 0, sizeof(reqParam) ); 1105 reqParam.roomId = m_room; 1106 1107 SetState(SNM_INT_STATE_LEAVING); 1108 app.DebugPrintf("sceNpMatching2LeaveRoom\n"); 1109 int ret = sceNpMatching2LeaveRoom( m_matchingContext, &reqParam, NULL, &m_leaveRoomRequestId ); 1110 if( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_LEAVE_ROOM) ) 1111 { 1112 SetState(SNM_INT_STATE_LEAVING_FAILED); 1113 } 1114 } 1115 else if ( m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM ) 1116 { 1117 // Haven't created the room yet, but will have created the server context so need to recover from that 1118 DeleteServerContext(); 1119 } 1120 else 1121 { 1122 SetState(SNM_INT_STATE_IDLE); 1123 } 1124 } 1125 else 1126 { 1127 // We have created a room but have now had some kind of connection error which means that we've been dropped out of the room and it has been destroyed, so 1128 // no need to leave it again since it doesn't exist anymore. Still need to destroy server context which may be valid 1129 DeleteServerContext(); 1130 } 1131} 1132 1133void SQRNetworkManager_Vita::EndGame() 1134{ 1135} 1136 1137bool SQRNetworkManager_Vita::SessionHasSpace(int spaceRequired) 1138{ 1139 return( ( m_roomSyncData.getPlayerCount() + spaceRequired ) <= MAX_ONLINE_PLAYER_COUNT ); 1140} 1141 1142bool SQRNetworkManager_Vita::AddLocalPlayerByUserIndex(int idx) 1143{ 1144 if( m_isHosting ) 1145 { 1146 if( m_roomSyncData.getPlayerCount() == MAX_ONLINE_PLAYER_COUNT ) return false; 1147 1148 // Host's players are always at the start of the sync data, so we just need to find the first entry that isn't us to determine what we want to insert before 1149 int insertAtIdx = m_roomSyncData.getPlayerCount(); 1150 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1151 { 1152 if( m_roomSyncData.players[i].m_roomMemberId != m_localMemberId ) 1153 { 1154 insertAtIdx = i; 1155 break; 1156 } 1157 else 1158 { 1159 // Don't add the same local index twice 1160 if( m_roomSyncData.players[i].m_localIdx == idx ) 1161 { 1162 return false; 1163 } 1164 } 1165 } 1166 1167 // Make room for a new entry... 1168 for( int i = m_roomSyncData.getPlayerCount(); i > insertAtIdx; i-- ) 1169 { 1170 m_roomSyncData.players[i] = m_roomSyncData.players[i-1]; 1171 } 1172 m_roomSyncData.players[insertAtIdx].m_localIdx = idx; 1173 m_roomSyncData.players[insertAtIdx].m_roomMemberId = m_localMemberId; 1174 m_roomSyncData.players[insertAtIdx].m_smallId = m_currentSmallId++; 1175 1176 m_roomSyncData.setPlayerCount(m_roomSyncData.getPlayerCount()+1); 1177 1178 // And do any adjusting necessary to the mappings from this room data, to the SQRNetworkPlayers. 1179 // This will also create the required new SQRNetworkPlayer and do all the callbacks that requires etc. 1180 MapRoomSlotPlayers(); 1181 1182 // Sync this back out to our networked clients... 1183 SyncRoomData(); 1184 1185 // no connections being made because we're all on the host, so add this player to the existing connections 1186 SonyVoiceChat_Vita::connectPlayerToAll(idx); 1187 return true; 1188 } 1189 else 1190 { 1191 // Don't attempt to join if our client's view of the players indicates that there aren't any free slots 1192 if( m_roomSyncData.getPlayerCount() == MAX_ONLINE_PLAYER_COUNT ) return false; 1193 1194 // Add the requested player to the mask of local players currently in the game, and update this data - this 1195 // will also then resync with the server which can respond appropriately 1196 int mask = 1 << idx; 1197 if( m_localPlayerJoinMask & mask ) return false; 1198 1199 m_localPlayerJoinMask |= mask; 1200 1201 SceNpMatching2SetRoomMemberDataInternalRequest reqParam; 1202 SceNpMatching2BinAttr binAttr; 1203 1204 memset(&reqParam, 0, sizeof(reqParam)); 1205 memset(&binAttr, 0, sizeof(binAttr)); 1206 1207 binAttr.id = SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID; 1208 binAttr.ptr = &m_localPlayerJoinMask; 1209 binAttr.size = sizeof(m_localPlayerJoinMask); 1210 1211 reqParam.roomId = m_room; 1212 reqParam.memberId = m_localMemberId; 1213 reqParam.roomMemberBinAttrInternalNum = 1; 1214 reqParam.roomMemberBinAttrInternal = &binAttr; 1215 1216 app.DebugPrintf("sceNpMatching2SetRoomMemberDataInternal\n"); 1217 int ret = sceNpMatching2SetRoomMemberDataInternal( m_matchingContext, &reqParam, NULL, &m_setRoomMemberInternalDataRequestId ); 1218 1219 if( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SET_ROOM_MEMBER_DATA_INTERNAL) ) 1220 { 1221 return false; 1222 } 1223 1224 // Create the client's end of the rudp connections... note that m_roomSyncData.players[0].m_roomMemberId is always be the host's room member id. 1225 bool rudpOk = CreateRudpConnections(m_room, m_roomSyncData.players[0].m_roomMemberId, mask, m_localMemberId ); 1226 1227 if( rudpOk ) 1228 { 1229 bool ret = CreateVoiceRudpConnections( m_room, m_roomSyncData.players[0].m_roomMemberId, mask); 1230 assert(ret); 1231 return true; 1232 } 1233 else 1234 { 1235 m_localPlayerJoinMask &= (~mask); 1236 return false; 1237 } 1238 } 1239} 1240 1241bool SQRNetworkManager_Vita::RemoveLocalPlayerByUserIndex(int idx) 1242{ 1243 if( m_isHosting ) 1244 { 1245 EnterCriticalSection(&m_csRoomSyncData); 1246 1247 int roomSlotPlayerCount = m_roomSyncData.getPlayerCount(); 1248 1249 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1250 { 1251 if( ( m_roomSyncData.players[i].m_roomMemberId == m_localMemberId ) && 1252 ( m_roomSyncData.players[i].m_localIdx == idx ) ) 1253 { 1254 // Shuffle all remaining entries up... 1255 m_roomSyncData.setPlayerCount(m_roomSyncData.getPlayerCount()-1); 1256 for( int j = i; j < m_roomSyncData.getPlayerCount(); j++ ) 1257 { 1258 m_roomSyncData.players[j] = m_roomSyncData.players[j+1]; 1259 } 1260 1261 // Zero last element that isn't part of the currently sized array anymore 1262 memset(&m_roomSyncData.players[m_roomSyncData.getPlayerCount()],0,sizeof(PlayerSyncData)); 1263 1264 // And do any adjusting necessary to the mappings from this room data, to the SQRNetworkPlayers. 1265 // This will also delete the SQRNetworkPlayer and do all the callbacks that requires etc. 1266 MapRoomSlotPlayers(roomSlotPlayerCount); 1267 m_aRoomSlotPlayers[m_roomSyncData.getPlayerCount()] = NULL; 1268 1269 // Sync this back out to our networked clients... 1270 SyncRoomData(); 1271 1272 SonyVoiceChat_Vita::disconnectLocalPlayer(idx); 1273 1274 LeaveCriticalSection(&m_csRoomSyncData); 1275 return true; 1276 } 1277 } 1278 LeaveCriticalSection(&m_csRoomSyncData); 1279 return false; 1280 } 1281 else 1282 { 1283 // Remove the requested player from the mask of local players currently in the game, and update this data - this 1284 // will also then resync with the server which can respond appropriately 1285 int mask = 1 << idx; 1286 if( ( m_localPlayerJoinMask & mask ) == 0 ) return false; 1287 1288 m_localPlayerJoinMask &= ~mask; 1289 1290 SceNpMatching2SetRoomMemberDataInternalRequest reqParam; 1291 SceNpMatching2BinAttr binAttr; 1292 1293 memset(&reqParam, 0, sizeof(reqParam)); 1294 memset(&binAttr, 0, sizeof(binAttr)); 1295 1296 binAttr.id = SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID; 1297 binAttr.ptr = &m_localPlayerJoinMask; 1298 binAttr.size = sizeof(m_localPlayerJoinMask); 1299 1300 reqParam.roomId = m_room; 1301 reqParam.memberId = m_localMemberId; 1302 reqParam.roomMemberBinAttrInternalNum = 1; 1303 reqParam.roomMemberBinAttrInternal = &binAttr; 1304 1305 int ret = sceNpMatching2SetRoomMemberDataInternal( m_matchingContext, &reqParam, NULL, &m_setRoomMemberInternalDataRequestId ); 1306 1307 if( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SET_ROOM_MEMBER_DATA_INTERNAL2) ) 1308 { 1309 return false; 1310 } 1311 1312 RemoveNetworkPlayers( mask ); 1313 1314 return true; 1315 } 1316} 1317 1318 1319extern uint8_t *mallocAndCreateUTF8ArrayFromString(int iID); 1320 1321// Bring up a Gui to send an invite so a player that the user can select. This invite will contain the room Id so that 1322void SQRNetworkManager_Vita::SendInviteGUI() 1323{ 1324 if(ProfileManager.IsSystemUIDisplayed()) 1325 { 1326 app.DebugPrintf("SendInviteGUI failed, SysUI is already up \n"); 1327 return; 1328 } 1329 1330 //Set invitation information - this is now exactly the same as the presence information that we synchronise out. 1331 1332 // If we joined a game, we'll have already set s_lastPresenceSyncInfo up (whether we came in from an invite, or joining a game we discovered). If we were hosting, 1333 // then we'll need to set this up now from the external dasta. 1334 if( m_isHosting ) 1335 { 1336 CPlatformNetworkManagerSony::SetSQRPresenceInfoFromExtData(&s_lastPresenceSyncInfo, m_joinExtData, m_room, m_serverId); 1337 } 1338 1339 sce::Toolkit::NP::MessageData messData; 1340 memset(&messData,0,sizeof(messData)); 1341 1342 char *subject = (char*)mallocAndCreateUTF8ArrayFromString(IDS_INVITATION_SUBJECT_MAX_18_CHARS); 1343 char *body = (char*)mallocAndCreateUTF8ArrayFromString(IDS_INVITATION_BODY); 1344 messData.attachment = (SceChar8*)&s_lastPresenceSyncInfo;; 1345 messData.attachmentSize = sizeof(PresenceSyncInfo); 1346 messData.body.assign(body); 1347 messData.iconPath.assign(SESSION_IMAGE_PATH); 1348 messData.expireMinutes = 0; 1349 1350 int ret = sce::Toolkit::NP::Messaging::Interface::sendMessage(&messData, SCE_TOOLKIT_NP_MESSAGE_TYPE_CUSTOM_DATA); 1351 if(ret < SCE_TOOLKIT_NP_SUCCESS ) 1352 { 1353 app.DebugPrintf("Send Message failed 0x%x ...\n",ret); 1354 assert(0); 1355 return; 1356 } 1357 else 1358 { 1359 m_bSendingInviteMessage = true; 1360 ProfileManager.SetSysUIShowing( true ); 1361 } 1362} 1363 1364 1365void SQRNetworkManager_Vita::RecvInviteGUI() 1366{ 1367 if(ProfileManager.IsSystemUIDisplayed()) 1368 { 1369 app.DebugPrintf("RecvInviteGUI failed, SysUI is already up \n"); 1370 return; 1371 } 1372 1373 int ret = sce::Toolkit::NP::Messaging::Interface::displayReceivedMessages(SCE_TOOLKIT_NP_MESSAGE_TYPE_CUSTOM_DATA); 1374 if(ret < SCE_TOOLKIT_NP_SUCCESS ) 1375 { 1376 app.DebugPrintf("displayReceivedMessages 0x%x ...\n",ret); 1377 assert(0); 1378 return; 1379 } 1380 else 1381 { 1382 ProfileManager.SetSysUIShowing( true ); 1383 } 1384 1385 1386 // int ret = sceGameCustomDataDialogInitialize(); 1387 // if(ret != SCE_OK) 1388 // { 1389 // app.DebugPrintf("sceGameCustomDataDialogInitialize() failed. ret = 0x%x\n", ret); 1390 // } 1391 // else 1392 // { 1393 // 1394 // SceGameCustomDataDialogParam dialogParam; 1395 // SceGameCustomDataDialogDataParam dataParam; 1396 // 1397 // sceGameCustomDataDialogParamInit( &dialogParam ); 1398 // memset( &dataParam, 0x00, sizeof( SceGameCustomDataDialogDataParam ) ); 1399 // dialogParam.mode = SCE_GAME_CUSTOM_DATA_DIALOG_MODE_RECV; 1400 // dialogParam.dataParam = &dataParam; 1401 // dialogParam.userId = ProfileManager.getUserID(ProfileManager.GetPrimaryPad()); 1402 // ret = sceGameCustomDataDialogOpen( &dialogParam ); 1403 // 1404 // if( SCE_OK != ret ) 1405 // { 1406 // app.DebugPrintf("sceGameCustomDataDialogOpen() failed. ret = 0x%x\n", ret); 1407 // } 1408 // else 1409 // { 1410 // b_inviteRecvGUIRunning = true; 1411 // } 1412 // } 1413} 1414 1415 1416void SQRNetworkManager_Vita::TickInviteGUI() 1417{ 1418 PSVITA_STUBBED; 1419 // if(b_inviteRecvGUIRunning) 1420 // { 1421 // SceCommonDialogStatus status = sceGameCustomDataDialogUpdateStatus(); 1422 // 1423 // if( SCE_COMMON_DIALOG_STATUS_FINISHED == status ) 1424 // { 1425 // SceGameCustomDataDialogOnlineIdList sentOnlineIdList; 1426 // memset( &sentOnlineIdList, 0x0, sizeof(SceGameCustomDataDialogOnlineIdList)); 1427 // SceGameCustomDataDialogResult dialogResult; 1428 // memset( &dialogResult, 0x0, sizeof(SceGameCustomDataDialogResult) ); 1429 // dialogResult.sentOnlineIds = &sentOnlineIdList; 1430 // 1431 // int32_t ret = sceGameCustomDataDialogGetResult( &dialogResult ); 1432 // 1433 // if( SCE_OK != ret ) 1434 // { 1435 // app.DebugPrintf( "***** sceGameCustomDataDialogGetResult error:0x%x\n", ret); 1436 // } 1437 // sceGameCustomDataDialogClose(); 1438 // sceGameCustomDataDialogTerminate(); 1439 // b_inviteRecvGUIRunning = false; 1440 // } 1441 // } 1442} 1443 1444// Get the data for an invite into a statically allocated array of invites, and pass a pointer of this back up to the game. Elements in the array are used in a circular fashion, to save any issues with handling freeing of this invite data as the 1445// qnet equivalent of this seems to just assume that the data persists forever. 1446void SQRNetworkManager_Vita::GetInviteDataAndProcess(sce::Toolkit::NP::MessageAttachment* pInvite) 1447{ 1448 1449 app.DebugPrintf("GameCustomData attachment size : %d\n", pInvite->getAttachmentSize()); 1450 if(pInvite->getAttachmentSize() == sizeof(m_gameBootInvite_data)) 1451 { 1452 memcpy(&m_gameBootInvite_data, pInvite->getAttachmentData(), sizeof(m_gameBootInvite_data)); 1453 m_gameBootInvite = &m_gameBootInvite_data; 1454 } 1455} 1456 1457void SQRNetworkManager_Vita::GetJoinablePresenceDataAndProcess(SceAppUtilNpBasicJoinablePresenceParam* pJoinablePresenceData) 1458{ 1459 memcpy(&m_joinablePresenceParam, pJoinablePresenceData, sizeof(SceAppUtilNpBasicJoinablePresenceParam)); 1460 if(s_safeToRespondToGameBootInvite && ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) 1461 { 1462 ProcessJoinablePresenceData(); 1463 } 1464 else 1465 { 1466 m_bJoinablePresenceWaitingForOnline = true; 1467 } 1468} 1469 1470void SQRNetworkManager_Vita::ProcessJoinablePresenceData() 1471{ 1472 static SceNpBasicGamePresence presenceDetails; 1473 int ret = sceNpBasicGetGamePresenceOfFriend(&m_joinablePresenceParam.npId, &presenceDetails); 1474 if( ret == 0 ) 1475 { 1476 PresenceSyncInfo *pso = (PresenceSyncInfo *)presenceDetails.inGamePresence.data; 1477 memcpy(&m_gameBootInvite_data, pso, sizeof(m_gameBootInvite_data)); 1478 m_gameBootInvite = &m_gameBootInvite_data; 1479 } 1480 m_bJoinablePresenceWaitingForOnline = false; 1481} 1482 1483 1484 1485 1486// This case happens when we were in the main menus when we got an invite, and weren't signed in... now can proceed with the normal flow of code for this situation 1487// The pair of methods MustSignInReturned_1 & PSNSignInReturned_1 handle this 1488int MustSignInReturnedPresenceInvite(void *pParam,int iPad,C4JStorage::EMessageResult result) 1489{ 1490 if(result==C4JStorage::EMessage_ResultAccept) 1491 { 1492 SQRNetworkManager_Vita::AttemptPSNSignIn(&SQRNetworkManager_Vita::PSNSignInReturnedPresenceInvite, pParam,true); 1493 } 1494 return 0; 1495} 1496 1497int SQRNetworkManager_Vita::PSNSignInReturnedPresenceInvite(void* pParam, bool bContinue, int iPad) 1498{ 1499 INVITE_INFO *inviteInfo = (INVITE_INFO *)pParam; 1500 1501 // If the invite data isn't set up yet (indicated by it being all zeroes, easiest detected via the net version), then try and get it again... this can happen if we got 1502 // the invite whilst signed out 1503 1504 if( bContinue ) 1505 { 1506 m_bJoinablePresenceWaitingForOnline = true; 1507 } 1508 return 0; 1509} 1510 1511 1512 1513void SQRNetworkManager_Vita::TickJoinablePresenceData() 1514{ 1515 if(s_safeToRespondToGameBootInvite && m_bJoinablePresenceWaitingForOnline) 1516 { 1517 if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) 1518 ProcessJoinablePresenceData(); 1519 else 1520 { 1521 m_bJoinablePresenceWaitingForOnline = false; // will be set to true again if we sign in succesfully 1522 // Determine why they're not "signed in live" 1523 // MGH - we need to add a new message at some point for connecting when already signed in 1524 // if (ProfileManager.IsSignedInPSN(ProfileManager.GetPrimaryPad())) 1525 // { 1526 // // Signed in to PSN but not connected (no internet access) 1527 // UINT uiIDA[1]; 1528 // uiIDA[0] = IDS_OK; 1529 // ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); 1530 // } 1531 // else 1532 { 1533 // Not signed in to PSN 1534 UINT uiIDA[1]; 1535 uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT; 1536 ui.RequestAlertMessage( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(), &MustSignInReturnedPresenceInvite, NULL); 1537 } 1538 1539 } 1540 1541 } 1542} 1543 1544bool SQRNetworkManager_Vita::UpdateInviteData(SQRNetworkManager_Vita::PresenceSyncInfo *invite) 1545{ 1546 PSVITA_STUBBED; 1547 return false; 1548 1549 // size_t dataSize = sizeof(SQRNetworkManager_Vita::PresenceSyncInfo); 1550 // int ret = sceNpBasicRecvMessageAttachmentLoad(s_lastInviteIdToRetry, invite, &dataSize); 1551 // return (ret == 0); 1552} 1553 1554// This method is a helper used in MapRoomSlotPlayers - tries to find a player that matches: 1555// (1) the playerType 1556// (2) if playerType is remote, memberId 1557// (3) localPlayerIdx 1558// The reason we don't care about memberid when the player isn't remote is that it doesn't matter (since we know the player is either on this machine, or it is the host and there's only one of those), 1559// and there's a period when starting up the host game where it doesn't accurately know the memberId for its own local players 1560void SQRNetworkManager_Vita::FindOrCreateNonNetworkPlayer(int slot, int playerType, SceNpMatching2RoomMemberId memberId, int localPlayerIdx, int smallId) 1561{ 1562 for(AUTO_VAR(it, m_vecTempPlayers.begin()); it != m_vecTempPlayers.end(); it++ ) 1563 { 1564 if( ((*it)->m_type == playerType ) && ( (*it)->m_localPlayerIdx == localPlayerIdx ) ) 1565 { 1566 if( ( playerType != SQRNetworkPlayer::SNP_TYPE_REMOTE ) || ( (*it)->m_roomMemberId == memberId ) ) 1567 { 1568 SQRNetworkPlayer *player = *it; 1569 m_vecTempPlayers.erase(it); 1570 m_aRoomSlotPlayers[ slot ] = player; 1571 return; 1572 } 1573 } 1574 } 1575 // Create the player - non-network players can be considered complete as soon as we create them as we aren't waiting on their network connections becoming complete, so can flag them as such and notify via callback 1576 PlayerUID *pUID = NULL; 1577 PlayerUID localUID; 1578 if( ( playerType == SQRNetworkPlayer::SNP_TYPE_LOCAL ) || 1579 m_isHosting && ( playerType == SQRNetworkPlayer::SNP_TYPE_HOST ) ) 1580 { 1581 // Local players can establish their UID at this point 1582 ProfileManager.GetXUID(localPlayerIdx,&localUID,true); 1583 pUID = &localUID; 1584 } 1585 SQRNetworkPlayer *player = new SQRNetworkPlayer(this, (SQRNetworkPlayer::eSQRNetworkPlayerType)playerType, m_isHosting, memberId, localPlayerIdx, 0, pUID ); 1586 // For offline games, set name directly from gamertag as the PlayerUID will be full of zeroes. 1587 if( m_offlineGame ) 1588 { 1589 player->SetName(ProfileManager.GetGamertag(localPlayerIdx)); 1590 } 1591 NonNetworkPlayerComplete( player, smallId); 1592 m_aRoomSlotPlayers[ slot ] = player; 1593 HandlePlayerJoined( player ); 1594} 1595 1596// For data sending on the local machine, used to send between host and localplayers on the host 1597void SQRNetworkManager_Vita::LocalDataSend(SQRNetworkPlayer *playerFrom, SQRNetworkPlayer *playerTo, const void *data, unsigned int dataSize) 1598{ 1599 assert(m_isHosting); 1600 if(m_listener) 1601 { 1602 m_listener->HandleDataReceived( playerFrom, playerTo, (unsigned char *)data, dataSize ); 1603 } 1604} 1605 1606int SQRNetworkManager_Vita::GetSessionIndex(SQRNetworkPlayer *player) 1607{ 1608 int roomSlotPlayerCount = m_roomSyncData.getPlayerCount(); 1609 for( int i = 0; i < roomSlotPlayerCount; i++ ) 1610 { 1611 if( m_aRoomSlotPlayers[i] == player ) return i; 1612 } 1613 return 0; 1614} 1615 1616// Updates m_aRoomSlotPlayers, based on what is in m_roomSyncData. This needs to be updated when room members join & leave, and when any SQRNetworkPlayer is created externally that this should be mapping to 1617void SQRNetworkManager_Vita::MapRoomSlotPlayers(int roomSlotPlayerCount/*=-1*/) 1618{ 1619 EnterCriticalSection(&m_csRoomSyncData); 1620 1621 // If we pass an explicit roomSlotPlayerCount, it is because we are removing a player, and this is the count of slots that there were *before* the removal. 1622 bool zeroLastSlot = false; 1623 if( roomSlotPlayerCount == -1 ) 1624 { 1625 roomSlotPlayerCount = m_roomSyncData.getPlayerCount(); 1626 } 1627 else 1628 { 1629 zeroLastSlot = true; 1630 } 1631 1632 if( m_isHosting ) 1633 { 1634 for( int i = 0; i < roomSlotPlayerCount; i++ ) 1635 { 1636 if( m_aRoomSlotPlayers[i] ) 1637 { 1638 // On host, remote players are created and destroyed by the Rudp connections being established and removed, so don't go deleting them here. Other types are managed by this mapping. 1639 // Note that m_vecTempPlayers is used as a pool of players to consider by FindOrCreateNonNetworkPlayer 1640 if( m_aRoomSlotPlayers[i]->m_type != SQRNetworkPlayer::SNP_TYPE_REMOTE ) 1641 { 1642 m_vecTempPlayers.push_back(m_aRoomSlotPlayers[i]); 1643 m_aRoomSlotPlayers[i] = NULL; 1644 } 1645 } 1646 } 1647 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1648 { 1649 if( i == 0 ) 1650 { 1651 // Special case - slot 0 is always the host 1652 FindOrCreateNonNetworkPlayer( i, SQRNetworkPlayer::SNP_TYPE_HOST, m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx, m_roomSyncData.players[i].m_smallId); 1653 m_roomSyncData.players[i].m_UID = m_aRoomSlotPlayers[i]->GetUID(); // On host, UIDs flow from player data -> m_roomSyncData 1654 } 1655 else 1656 { 1657 if( m_roomSyncData.players[i].m_roomMemberId == m_localMemberId ) 1658 { 1659 FindOrCreateNonNetworkPlayer( i, SQRNetworkPlayer::SNP_TYPE_LOCAL, m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx, m_roomSyncData.players[i].m_smallId); 1660 m_roomSyncData.players[i].m_UID = m_aRoomSlotPlayers[i]->GetUID(); // On host, UIDs flow from player data -> m_roomSyncData 1661 } 1662 else 1663 { 1664 m_aRoomSlotPlayers[i] = GetPlayerFromRoomMemberAndLocalIdx( m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx ); 1665 // If we're the host, then we allocated the small id so can flag now if we've got a player to flag... 1666 if( m_aRoomSlotPlayers[i] ) 1667 { 1668 NetworkPlayerSmallIdAllocated(m_aRoomSlotPlayers[i], m_roomSyncData.players[i].m_smallId); 1669 } 1670 } 1671 } 1672 } 1673 1674 if( zeroLastSlot ) 1675 { 1676 if( roomSlotPlayerCount ) 1677 { 1678 m_aRoomSlotPlayers[ roomSlotPlayerCount - 1 ] = 0; 1679 } 1680 } 1681 1682 // Also update the externally visible room data for the current slots 1683 if (m_listener ) 1684 { 1685 m_listener->HandleResyncPlayerRequest(m_aRoomSlotPlayers); 1686 } 1687 } 1688 else 1689 { 1690 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1691 { 1692 if( m_aRoomSlotPlayers[i] ) 1693 { 1694 // On clients, local players are created and destroyed by the Rudp connections being established and removed, so don't go deleting them here. Other types are managed by this mapping. 1695 // Note that m_vecTempPlayers is used as a pool of players to consider by FindOrCreateNonNetworkPlayer 1696 if( m_aRoomSlotPlayers[i]->m_type != SQRNetworkPlayer::SNP_TYPE_LOCAL ) 1697 { 1698 m_vecTempPlayers.push_back(m_aRoomSlotPlayers[i]); 1699 m_aRoomSlotPlayers[i] = NULL; 1700 } 1701 } 1702 } 1703 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1704 { 1705 if( i == 0 ) 1706 { 1707 // Special case - slot 0 is always the host 1708 FindOrCreateNonNetworkPlayer( i, SQRNetworkPlayer::SNP_TYPE_HOST, m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx, m_roomSyncData.players[i].m_smallId); 1709 m_aRoomSlotPlayers[i]->SetUID(m_roomSyncData.players[i].m_UID); // On client, UIDs flow from m_roomSyncData->player data 1710 } 1711 else 1712 { 1713 if( m_roomSyncData.players[i].m_roomMemberId == m_localMemberId ) 1714 { 1715 // This player is local to this machine - don't bother setting UID from sync data, as it will already have been set accurately when we (locally) made this player 1716 m_aRoomSlotPlayers[i] = GetPlayerFromRoomMemberAndLocalIdx( m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx ); 1717 // If we've got the room sync data back from the server, then we've got our smallId. Set flag for this. 1718 if( m_aRoomSlotPlayers[i] ) 1719 { 1720 NetworkPlayerSmallIdAllocated(m_aRoomSlotPlayers[i], m_roomSyncData.players[i].m_smallId); 1721 } 1722 } 1723 else 1724 { 1725 FindOrCreateNonNetworkPlayer( i, SQRNetworkPlayer::SNP_TYPE_REMOTE, m_roomSyncData.players[i].m_roomMemberId, m_roomSyncData.players[i].m_localIdx, m_roomSyncData.players[i].m_smallId); 1726 m_aRoomSlotPlayers[i]->SetUID(m_roomSyncData.players[i].m_UID); // On client, UIDs flow from m_roomSyncData->player data 1727 } 1728 } 1729 } 1730 } 1731 // Clear up any non-network players that are no longer required - this would be a good point to notify of players leaving when we support that 1732 // FindOrCreateNonNetworkPlayer will have pulled any players that we Do need out of m_vecTempPlayers, so the ones that are remaining are no longer in the game 1733 for(AUTO_VAR(it, m_vecTempPlayers.begin()); it != m_vecTempPlayers.end(); it++ ) 1734 { 1735 if( m_listener ) 1736 { 1737 m_listener->HandlePlayerLeaving(*it); 1738 } 1739 delete (*it); 1740 } 1741 m_vecTempPlayers.clear(); 1742 1743 LeaveCriticalSection(&m_csRoomSyncData); 1744} 1745 1746// On host, update the room sync data with UIDs that are in the players 1747void SQRNetworkManager_Vita::UpdateRoomSyncUIDsFromPlayers() 1748{ 1749 EnterCriticalSection(&m_csRoomSyncData); 1750 if( m_isHosting ) 1751 { 1752 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1753 { 1754 if( m_aRoomSlotPlayers[i] ) 1755 { 1756 m_roomSyncData.players[i].m_UID = m_aRoomSlotPlayers[i]->GetUID(); 1757 } 1758 } 1759 } 1760 1761 LeaveCriticalSection(&m_csRoomSyncData); 1762} 1763 1764// On the client, move UIDs from the room sync data out to the players. 1765void SQRNetworkManager_Vita::UpdatePlayersFromRoomSyncUIDs() 1766{ 1767 EnterCriticalSection(&m_csRoomSyncData); 1768 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1769 { 1770 if( m_aRoomSlotPlayers[i] ) 1771 { 1772 if( i == 0 ) 1773 { 1774 // Special case - slot 0 is always the host 1775 m_aRoomSlotPlayers[i]->SetUID(m_roomSyncData.players[i].m_UID); 1776 } 1777 else 1778 { 1779 // Don't sync local players as we already set those up with their UID in the first place... 1780 if( m_roomSyncData.players[i].m_roomMemberId != m_localMemberId ) 1781 { 1782 m_aRoomSlotPlayers[i]->SetUID(m_roomSyncData.players[i].m_UID); 1783 } 1784 } 1785 } 1786 } 1787 LeaveCriticalSection(&m_csRoomSyncData); 1788} 1789 1790// Host only - add remote players to our internal storage of player slots, and synchronise this with other room members. 1791bool SQRNetworkManager_Vita::AddRemotePlayersAndSync( SceNpMatching2RoomMemberId memberId, int playerMask, bool *isFull/*==NULL*/ ) 1792{ 1793 assert( m_isHosting ); 1794 1795 EnterCriticalSection(&m_csRoomSyncData); 1796 1797 // Establish whether we have enough room to add the players 1798 int addCount = 0; 1799 for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) 1800 { 1801 if( playerMask & ( 1 << i ) ) 1802 { 1803 addCount++; 1804 } 1805 } 1806 1807 if( ( m_roomSyncData.getPlayerCount() + addCount ) > MAX_ONLINE_PLAYER_COUNT ) 1808 { 1809 if( isFull ) 1810 { 1811 *isFull = true; 1812 } 1813 LeaveCriticalSection(&m_csRoomSyncData); 1814 return false; 1815 } 1816 1817 // We want to keep all players from a particular machine together, so search through the room sync data to see if we can find 1818 // any pre-existing players from this machine. 1819 int firstIdx = -1; 1820 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 1821 { 1822 if( m_roomSyncData.players[i].m_roomMemberId == memberId ) 1823 { 1824 firstIdx = i; 1825 break; 1826 } 1827 } 1828 1829 // We'll just be inserting at the end unless we've got a pre-existing player to insert after. Even then there might be no following 1830 // players. 1831 int insertIdx = m_roomSyncData.getPlayerCount(); 1832 if( firstIdx > -1 ) 1833 { 1834 for( int i = firstIdx; i < m_roomSyncData.getPlayerCount(); i++ ) 1835 { 1836 if( m_roomSyncData.players[i].m_roomMemberId != memberId ) 1837 { 1838 insertIdx = i; 1839 break; 1840 } 1841 } 1842 } 1843 1844 // Add all remote players determined from the player mask to our own slots of active players 1845 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 1846 { 1847 if( playerMask & ( 1 << i ) ) 1848 { 1849 // Shift any following players along... 1850 for( int j = m_roomSyncData.getPlayerCount(); j > insertIdx; j-- ) 1851 { 1852 m_roomSyncData.players[j] = m_roomSyncData.players[j-1]; 1853 } 1854 PlayerSyncData *player = &m_roomSyncData.players[ insertIdx ]; 1855 player->m_smallId = m_currentSmallId++; 1856 player->m_roomMemberId = memberId; 1857 player->m_localIdx = i; 1858 m_roomSyncData.setPlayerCount(m_roomSyncData.getPlayerCount()+1); 1859 insertIdx++; 1860 } 1861 } 1862 1863 // Update mapping from the room slot players to SQRNetworkPlayer instances 1864 MapRoomSlotPlayers(); 1865 1866 // And then synchronise this out to all other machines 1867 SyncRoomData(); 1868 1869 LeaveCriticalSection(&m_csRoomSyncData); 1870 1871 return true; 1872} 1873 1874// Host only - remove all remote players belonging to the supplied memberId, and in the supplied mask, and synchronise this with other room members 1875void SQRNetworkManager_Vita::RemoveRemotePlayersAndSync( SceNpMatching2RoomMemberId memberId, int mask ) 1876{ 1877 assert( m_isHosting ); 1878 EnterCriticalSection(&m_csRoomSyncData); 1879 1880 // Remove any applicable players, keeping remaining players in order 1881 for( int i = 0; i < m_roomSyncData.getPlayerCount(); ) 1882 { 1883 if( ( m_roomSyncData.players[ i ].m_roomMemberId == memberId ) && ( ( 1 << m_roomSyncData.players[ i ].m_localIdx ) & mask ) ) 1884 { 1885 SQRNetworkPlayer *player = GetPlayerFromRoomMemberAndLocalIdx( memberId, m_roomSyncData.players[ i ].m_localIdx ); 1886 if( player ) 1887 { 1888 // Get Rudp context for this player, close that context down ( which will in turn close the socket if required) 1889 int ctx = player->m_rudpCtx; 1890 int err = sceRudpTerminate( ctx ); 1891 assert(err == SCE_OK); 1892 if( m_listener ) 1893 { 1894 m_listener->HandlePlayerLeaving(player); 1895 } 1896 // Delete the player itself and the mapping from context to player map as this context is no longer valid 1897 delete player; 1898 m_RudpCtxToPlayerMap.erase(ctx); 1899 1900 removePlayerFromVoiceChat(player); 1901 } 1902 m_roomSyncData.setPlayerCount(m_roomSyncData.getPlayerCount()-1); 1903 // Shuffled entries up into the space that we have just created 1904 for( int j = i ; j < m_roomSyncData.getPlayerCount(); j++ ) 1905 { 1906 m_roomSyncData.players[j] = m_roomSyncData.players[j + 1]; 1907 m_aRoomSlotPlayers[j] = m_aRoomSlotPlayers[j + 1]; 1908 } 1909 // Zero last element, that isn't part of the currently sized array anymore 1910 memset(&m_roomSyncData.players[m_roomSyncData.getPlayerCount()],0,sizeof(PlayerSyncData)); 1911 m_aRoomSlotPlayers[m_roomSyncData.getPlayerCount()] = NULL; 1912 } 1913 else 1914 { 1915 i++; 1916 } 1917 } 1918 LeaveCriticalSection(&m_csRoomSyncData); 1919 1920 // Update mapping from the room slot players to SQRNetworkPlayer instances 1921 MapRoomSlotPlayers(); 1922 1923 1924 // And then synchronise this out to all other machines 1925 SyncRoomData(); 1926 1927 // if(GetOnlinePlayerCount() == 0) 1928 // SonyVoiceChat::shutdown(); 1929} 1930 1931// Client only - remove all network players matching the supplied mask 1932void SQRNetworkManager_Vita::RemoveNetworkPlayers( int mask ) 1933{ 1934 assert( !m_isHosting ); 1935 1936 for(AUTO_VAR(it, m_RudpCtxToPlayerMap.begin()); it != m_RudpCtxToPlayerMap.end(); ) 1937 { 1938 SQRNetworkPlayer *player = it->second; 1939 if( (player->m_roomMemberId == m_localMemberId ) && ( ( 1 << player->m_localPlayerIdx ) & mask ) ) 1940 { 1941 // Get Rudp context for this player, close that context down ( which will in turn close the socket if required) 1942 int ctx = it->first; 1943 int err = sceRudpTerminate( ctx ); 1944 assert(err == SCE_OK); 1945 if( m_listener ) 1946 { 1947 m_listener->HandlePlayerLeaving(player); 1948 } 1949 // Delete any reference to this player from the player mappings 1950 for( int i = 0; i < MAX_ONLINE_PLAYER_COUNT; i++ ) 1951 { 1952 if( m_aRoomSlotPlayers[i] == player ) 1953 { 1954 m_aRoomSlotPlayers[i] = NULL; 1955 } 1956 } 1957 // And delete the reference from the ctx->player map 1958 it = m_RudpCtxToPlayerMap.erase(it); 1959 1960 removePlayerFromVoiceChat(player); 1961 1962 // Delete the player itself and the mapping from context to player map as this context is no longer valid 1963 delete player; 1964 } 1965 else 1966 { 1967 it++; 1968 } 1969 } 1970 assert(m_RudpCtxToPlayerMap.size() == 0); 1971} 1972 1973// Host only - update the memberId of the local players, and synchronise with other room members 1974void SQRNetworkManager_Vita::SetLocalPlayersAndSync() 1975{ 1976 assert( m_isHosting ); 1977 for( int i = 0; i < m_localPlayerCount; i++ ) 1978 { 1979 m_roomSyncData.players[i].m_roomMemberId = m_localMemberId; 1980 } 1981 1982 // Update mapping from the room slot players to SQRNetworkPlayer instances 1983 MapRoomSlotPlayers(); 1984 1985 // And then synchronise this out to all other machines 1986 SyncRoomData(); 1987 1988} 1989 1990// Host only - sync the room data with other machines 1991void SQRNetworkManager_Vita::SyncRoomData() 1992{ 1993 if( m_offlineGame ) return; 1994 1995 UpdateRoomSyncUIDsFromPlayers(); 1996 1997 SceNpMatching2SetRoomDataInternalRequest reqParam; 1998 memset( &reqParam, 0, sizeof(reqParam) ); 1999 reqParam.roomId = m_room; 2000 SceNpMatching2BinAttr roomBinAttr; 2001 memset(&roomBinAttr, 0, sizeof(roomBinAttr)); 2002 roomBinAttr.id = SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID; 2003 roomBinAttr.ptr = &m_roomSyncData; 2004 roomBinAttr.size = sizeof( m_roomSyncData ); 2005 reqParam.roomBinAttrInternalNum = 1; 2006 reqParam.roomBinAttrInternal = &roomBinAttr; 2007 sceNpMatching2SetRoomDataInternal ( m_matchingContext, &reqParam, NULL, &m_setRoomDataRequestId ); 2008} 2009 2010// Check if the matching context is valid, and if not attempt to create one. If to do this requires starting an asynchronous process, then sets the internal state to the state passed in 2011// before doing this. 2012// Returns true on success. 2013bool SQRNetworkManager_Vita::GetMatchingContext(eSQRNetworkManagerInternalState asyncState) 2014{ 2015 if( m_matchingContextValid ) return true; 2016 2017 int ret = 0; 2018 if( !m_matching2initialised) 2019 { 2020 app.DebugPrintf("sceNpMatching2Init\n"); 2021 ret = sceNpMatching2Init(0, 0, SCE_KERNEL_THREAD_CPU_AFFINITY_MASK_DEFAULT, 0); 2022 } 2023 if( ret < 0 ) 2024 { 2025 app.DebugPrintf("SQRNetworkManager::GetMatchingContext - sceNpMatching2Init2 failed with code 0x%08x\n", ret); 2026 return false; 2027 } 2028 m_matching2initialised = true; 2029 2030 // Get NP ID of the signed-in user 2031 SceNpId npId; 2032 app.DebugPrintf("GetSceNpId\n"); 2033 2034 /*ret = */ProfileManager.GetSceNpId(ProfileManager.GetPrimaryPad(), &npId); 2035 2036 2037 // Create context 2038 app.DebugPrintf("sceNpMatching2CreateContext\n"); 2039 ret = sceNpMatching2CreateContext(&npId, &s_npCommunicationId, &s_npCommunicationPassphrase, &m_matchingContext/*, option*/); 2040 //ret = sceNpMatching2CreateContext(&npId, NULL,NULL, &m_matchingContext/*, option*/); 2041 if( ret < 0 ) 2042 { 2043 app.DebugPrintf("SQRNetworkManager::GetMatchingContext - sceNpMatching2CreateContext failed with code 0x%08x\n", ret); 2044 return false; 2045 } 2046 if( ret < 0 ) return false; 2047 2048 app.DebugPrintf("RegisterCallbacks\n"); 2049 if( !RegisterCallbacks() ) 2050 { 2051 app.DebugPrintf("SQRNetworkManager::GetMatchingContext - RegisterCallbacks failed\n"); 2052 return false; 2053 } 2054 2055 // Set internal state & kick off async process that will actually start the context. 2056 SetState(asyncState); 2057 app.DebugPrintf("sceNpMatching2ContextStart\n"); 2058 ret = sceNpMatching2ContextStart(m_matchingContext, (10*1000*1000)); 2059 if( ret < 0 ) 2060 { 2061 // Put state back so that the caller isn't expecting a callback from sceNpMatching2ContextStartAsync completing to happen 2062 SetState(SNM_INT_STATE_IDLE); 2063 app.DebugPrintf("SQRNetworkManager::GetMatchingContext - sceNpMatching2ContextStartAsync failed with code 0x%08x\n", ret); 2064 return false; 2065 } 2066 2067 app.DebugPrintf("SQRNetworkManager::GetMatchingContext - matching context is now valid\n"); 2068 m_matchingContextValid = true; 2069 return true; 2070} 2071 2072// Starts the process of obtaining a server context. This is an asynchronous operation, at the end of which (if successful), we'll be creating 2073// a room. General procedure followed here is as suggested by Sony - we get a list of servers, then pick a random one, and see if it is available. 2074// If not we just cycle round trying other random ones until we either find an available one or fail. 2075bool SQRNetworkManager_Vita::GetServerContext() 2076{ 2077 assert(m_state == SNM_INT_STATE_IDLE); 2078 assert(m_serverContextValid == false); 2079 2080 // Check that the matching context is valid & recreate if necessary 2081 if( !GetMatchingContext(SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT) ) return false; 2082 // If this caused an async thing to be started up, then we've done as much as we can here - the rest of the code will happen when the async matching 2 context starting completes 2083 // ( event SCE_NP_MATCHING2_CONTEXT_EVENT_Start is received ) 2084 if( m_state == SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT ) return true; 2085 2086 return GetServerContext2(); 2087} 2088 2089// Code split out from previous method, so we can also call from creating matching context if required 2090bool SQRNetworkManager_Vita::GetServerContext2() 2091{ 2092 2093 m_aServerId = (SceNpMatching2ServerId *)realloc( m_aServerId, sizeof(SceNpMatching2ServerId) * 1 ); 2094 SceNpMatching2Server server; 2095 app.DebugPrintf("sceNpMatching2GetServerLocal\n"); 2096 int err = sceNpMatching2GetServerLocal(m_matchingContext, &server); 2097 assert(server.status == SCE_NP_MATCHING2_SERVER_STATUS_AVAILABLE); 2098 *m_aServerId = server.serverId; 2099 if(err != SCE_OK) 2100 { 2101 m_serverCount = 0; 2102 assert(0); 2103 } 2104 m_serverCount = 1; 2105 2106 SetState(SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER); 2107 return SelectRandomServer(); 2108} 2109 2110// Overloaded method for (as before) obtaining a server context. This version is so that can also get a server context for a specific server rather than a random one, 2111// using mainly the same code by making a single element list. This is used when joining an existing room. 2112bool SQRNetworkManager_Vita::GetServerContext(SceNpMatching2ServerId serverId) 2113{ 2114 if(m_state == SNM_INT_STATE_STARTING_CONTEXT) 2115 { 2116 // MGH - added for devtrack 5936 : race between the context starting after going online, and trying to start it here, so skip this one if we're already starting. 2117 m_serverCount = 1; 2118 m_totalServerCount = m_serverCount; 2119 m_aServerId = (SceNpMatching2ServerId *)realloc(m_aServerId, sizeof(SceNpMatching2ServerId) * m_serverCount ); 2120 m_aServerId[0] = serverId; 2121 SetState(SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT); 2122 return true; 2123 } 2124 assert(m_state == SNM_INT_STATE_IDLE); 2125 assert(m_serverContextValid == false); 2126 2127 // Check that the matching context is valid & recreate if necessary 2128 if( !GetMatchingContext(SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT) ) 2129 { 2130 app.DebugPrintf("SQRNetworkManager::GetServerContext - Failed due to no matching context\n"); 2131 return false; 2132 } 2133 2134 // 4J Stu - If this state is set, then we have successfully created a new context but it won't have started yet 2135 // Therefore the sceNpMatching2GetServerIdListLocal call will fail. If we just skip this check everything should be good. 2136 // if( m_state != SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT ) 2137 // { 2138 // // Get list of server IDs of servers allocated to the application. We don't actually need to do this, but it is as good a way as any to try a matching2 service and check that 2139 // // the context *really* is valid. 2140 // int serverCount = sceNpMatching2GetServerIdListLocal( m_matchingContext, NULL, 0 ); 2141 // // If an error is returned here, we need to destroy and recerate our server - if this goes ok we should come back through this path again 2142 // if( ( serverCount == SCE_NP_MATCHING2_ERROR_CONTEXT_UNAVAILABLE ) || // This error has been seen (occasionally) in a normal working environment 2143 // ( serverCount == SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED ) ) // Also checking for this as a means of simulating the previous error 2144 // { 2145 // sceNpMatching2DestroyContext(m_matchingContext); 2146 // m_matchingContextValid = false; 2147 // if( !GetMatchingContext(SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT) ) return false; 2148 // } 2149 // } 2150 m_serverCount = 1; 2151 m_totalServerCount = m_serverCount; 2152 m_aServerId = (SceNpMatching2ServerId *)realloc(m_aServerId, sizeof(SceNpMatching2ServerId) * m_serverCount ); 2153 m_aServerId[0] = serverId; 2154 2155 // If one of the previous GetMatchingContext calls caused an async thing to be started up, then we've done as much as we can here - the rest of the code will happen when the async matching 2 context starting completes 2156 // ( event SCE_NP_MATCHING2_CONTEXT_EVENT_Start is received ) 2157 if( m_state == SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT ) return true; 2158 2159 SetState(SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER); 2160 return SelectRandomServer(); 2161} 2162 2163// Tick to update the search for a server which is available, for the creation of a server context. 2164void SQRNetworkManager_Vita::ServerContextTick() 2165{ 2166 switch( m_state ) 2167 { 2168 case SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER: 2169 case SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER: 2170 break; 2171 case SNM_INT_STATE_HOSTING_SERVER_SEARCH_SERVER_ERROR: 2172 case SNM_INT_STATE_JOINING_SERVER_SEARCH_SERVER_ERROR: 2173 // Attempt to keep searching if a single server failed 2174 SetState((m_state==SNM_INT_STATE_HOSTING_SERVER_SEARCH_SERVER_ERROR)?SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER:SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER); 2175 if(!SelectRandomServer()) 2176 { 2177 SetState((m_state==SNM_INT_STATE_HOSTING_SERVER_SEARCH_SERVER_ERROR)?SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED:SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED); 2178 } 2179 break; 2180 case SNM_INT_STATE_HOSTING_SERVER_FOUND: 2181 m_serverContextValid = true; 2182 ServerContextValid_CreateRoom(); 2183 break; 2184 2185 case SNM_INT_STATE_JOINING_SERVER_FOUND: 2186 m_serverContextValid = true; 2187 ServerContextValid_JoinRoom(); 2188 break; 2189 default: 2190 break; 2191 } 2192} 2193 2194// Tick the process of creating a room. 2195void SQRNetworkManager_Vita::RoomCreateTick() 2196{ 2197 switch( m_state ) 2198 { 2199 case SNM_INT_STATE_HOSTING_CREATE_ROOM_SEARCHING_FOR_WORLD: 2200 break; 2201 case SNM_INT_STATE_HOSTING_CREATE_ROOM_WORLD_FOUND: 2202 { 2203 SceNpMatching2CreateJoinRoomRequest reqParam; 2204 SceNpMatching2SignalingOptParam optSignalingParam; 2205 SceNpMatching2BinAttr roomBinAttrExt; 2206 SceNpMatching2BinAttr roomBinAttr; 2207 memset(&reqParam, 0, sizeof(reqParam)); 2208 memset(&optSignalingParam, 0, sizeof( optSignalingParam) ); 2209 memset(&roomBinAttr, 0, sizeof(roomBinAttr)); 2210 memset(&roomBinAttrExt, 0, sizeof(roomBinAttrExt)); 2211 2212 reqParam.worldId = m_worldId; 2213 reqParam.flagAttr = SCE_NP_MATCHING2_ROOM_FLAG_ATTR_NAT_TYPE_RESTRICTION; 2214 reqParam.sigOptParam = &optSignalingParam; 2215 reqParam.maxSlot = MAX_ONLINE_PLAYER_COUNT; 2216 2217 reqParam.roomBinAttrInternalNum = 1; 2218 reqParam.roomBinAttrInternal = &roomBinAttr; 2219 reqParam.roomBinAttrExternalNum = 1; 2220 reqParam.roomBinAttrExternal = &roomBinAttrExt; 2221 2222 roomBinAttr.id = SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID; 2223 roomBinAttr.ptr = &m_roomSyncData; 2224 roomBinAttr.size = sizeof( m_roomSyncData ); 2225 2226 roomBinAttrExt.id = SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID; 2227 roomBinAttrExt.ptr = m_joinExtData; 2228 roomBinAttrExt.size = m_joinExtDataSize; 2229 2230 optSignalingParam.type = SCE_NP_MATCHING2_SIGNALING_TYPE_MESH; 2231 optSignalingParam.hubMemberId = 0; // Room owner is the hub of the star 2232 SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM); 2233 app.DebugPrintf(CMinecraftApp::USER_RR,">> Creating room start\n"); 2234 s_roomStartTime = System::currentTimeMillis(); 2235 app.DebugPrintf("sceNpMatching2CreateJoinRoom\n"); 2236 int ret = sceNpMatching2CreateJoinRoom( m_matchingContext, &reqParam, NULL, &m_createRoomRequestId ); 2237 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_CREATE_JOIN_ROOM) ) 2238 { 2239 SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED); 2240 } 2241 } 2242 break; 2243 case SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM: 2244 break; 2245 case SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS: 2246 SetState(SNM_INT_STATE_HOSTING_WAITING_TO_PLAY); 2247 2248 // Now we know the local member id we can update our local players 2249 SetLocalPlayersAndSync(); 2250 break; 2251 case SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED: 2252 break; 2253 default: 2254 break; 2255 } 2256} 2257 2258// For a player using the network to communicate, flag as having its connection complete. This wraps the player's own functionality, so that we can determine if this 2259// call is transitioning us from not ready to ready, and call a registered callback. 2260void SQRNetworkManager_Vita::NetworkPlayerConnectionComplete(SQRNetworkPlayer *player) 2261{ 2262 EnterCriticalSection(&m_csPlayerState); 2263 bool wasReady = player->IsReady(); 2264 bool wasClientReady = player->HasConnectionAndSmallId(); 2265 player->ConnectionComplete(); 2266 bool isReady = player->IsReady(); 2267 bool isClientReady = player->HasConnectionAndSmallId(); 2268 if( !m_isHosting ) 2269 { 2270 // For clients, if we are ready (up the the point of having received our small id) then confirm to the host that this is the case, which makes us now fully ready at this end 2271 if( ( !wasClientReady ) && ( isClientReady ) ) 2272 { 2273 player->ConfirmReady(); 2274 isReady = true; 2275 } 2276 } 2277 LeaveCriticalSection(&m_csPlayerState); 2278 2279 if( ( !wasReady ) && ( isReady ) ) 2280 { 2281 HandlePlayerJoined( player ); 2282 } 2283} 2284 2285// For a player using the network to communicate, set its small id, thereby flagging it as having one allocated 2286void SQRNetworkManager_Vita::NetworkPlayerSmallIdAllocated(SQRNetworkPlayer *player, unsigned char smallId) 2287{ 2288 EnterCriticalSection(&m_csPlayerState); 2289 bool wasReady = player->IsReady(); 2290 bool wasClientReady = player->HasConnectionAndSmallId(); 2291 player->SmallIdAllocated(smallId); 2292 bool isReady = player->IsReady(); 2293 bool isClientReady = player->HasConnectionAndSmallId(); 2294 if( !m_isHosting ) 2295 { 2296 // For clients, if we are ready (up the the point of having received our small id) then confirm to the host that this is the case, which makes us now fully ready at this end 2297 if( ( !wasClientReady ) && ( isClientReady ) ) 2298 { 2299 player->ConfirmReady(); 2300 isReady = true; 2301 } 2302 } 2303 LeaveCriticalSection(&m_csPlayerState); 2304 2305 if( ( !wasReady ) && ( isReady ) ) 2306 { 2307 HandlePlayerJoined( player ); 2308 } 2309} 2310 2311// On host, for a player using the network to communicate, confirm that its small id has now been received back 2312void SQRNetworkManager_Vita::NetworkPlayerInitialDataReceived(SQRNetworkPlayer *player, void *data) 2313{ 2314 EnterCriticalSection(&m_csPlayerState); 2315 SQRNetworkPlayer::InitSendData *ISD = (SQRNetworkPlayer::InitSendData *)data; 2316 bool wasReady = player->IsReady(); 2317 player->InitialDataReceived(ISD); 2318 bool isReady = player->IsReady(); 2319 LeaveCriticalSection(&m_csPlayerState); 2320 // Sync room data back out as we've updated a player's UID here 2321 SyncRoomData(); 2322 2323 if( ( !wasReady ) && ( isReady ) ) 2324 { 2325 HandlePlayerJoined( player ); 2326 } 2327} 2328 2329// For non-network players, flag that it is complete/ready, and assign its small id. We don't want to call any callbacks for these, as that can be explicitly done when local players are added. 2330// Also, we dynamically destroy & recreate local players quite a lot when remapping player slots which would create a lot of messages we don't want. 2331void SQRNetworkManager_Vita::NonNetworkPlayerComplete(SQRNetworkPlayer *player, unsigned char smallId) 2332{ 2333 player->ConnectionComplete(); 2334 player->SmallIdAllocated(smallId); 2335} 2336 2337void SQRNetworkManager_Vita::HandlePlayerJoined(SQRNetworkPlayer *player) 2338{ 2339 if( m_listener ) 2340 { 2341 m_listener->HandlePlayerJoined( player ); 2342 } 2343 // On client, keep a count of how many local players we have told the game about. We can only transition to telling the game that we are playing once the room is set up And all the local players are valid to use. 2344 if( !m_isHosting ) 2345 { 2346 if( player->IsLocal() ) 2347 { 2348 m_localPlayerJoined++; 2349 } 2350 } 2351} 2352 2353// Selects a random server from the current list, removes that server so it won't be searched for again, and then kick off an attempt to find out if that particular server is available. 2354bool SQRNetworkManager_Vita::SelectRandomServer() 2355{ 2356 app.DebugPrintf("SQRNetworkManager_Vita::SelectRandomServer\n"); 2357 2358 assert( (m_state == SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER) || (m_state == SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER) ); 2359 2360 if( m_serverCount == 0 ) 2361 { 2362 SetState((m_state == SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER) ? SNM_INT_STATE_HOSTING_SERVER_SEARCH_FAILED : SNM_INT_STATE_JOINING_SERVER_SEARCH_FAILED); 2363 app.DebugPrintf("SQRNetworkManager::SelectRandomServer - Server count is 0\n"); 2364 return false; 2365 } 2366 2367 // not really selecting a random server, as we've already been allocated one, but calling this to match PS3 2368 int serverIdx; 2369 serverIdx = 0; 2370 m_serverCount--; 2371 m_aServerId[serverIdx] = m_aServerId[m_serverCount]; 2372 2373 // This server is available 2374 SetState((m_state == SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER) ? SNM_INT_STATE_HOSTING_SERVER_FOUND : SNM_INT_STATE_JOINING_SERVER_FOUND); 2375 m_serverId = m_aServerId[serverIdx]; 2376 2377 return true; 2378} 2379 2380// Delete the current server context. Should be called when finished with the current host or client game session. 2381void SQRNetworkManager_Vita::DeleteServerContext() 2382{ 2383 // No server context on PS4, so we just set the state, and then we'll check all the UDP connections have shutdown before setting to idle 2384 if( m_serverContextValid ) 2385 { 2386 m_serverContextValid = false; 2387 SetState(SNM_INT_STATE_SERVER_DELETING_CONTEXT); 2388 } 2389} 2390 2391// Creates a set of Rudp connections by the "active open" method. This requires that both ends of the connection call cellRudpInitiate to fully create a connection. We 2392// create one connection per local play on any remote machine. 2393// 2394// peerMemberId is the room member Id of the remote end of the connection 2395// playersMemberId is the room member Id that the players belong to 2396// ie for the host (when matching incoming connections), these will be the same thing... and for the client, peerMemberId will be the host, whereas playersMemberId will be itself 2397 2398 2399static std::string getIPAddressString(SceNetInAddr add) 2400{ 2401 char str[32]; 2402 unsigned char *vals = (unsigned char*)&add.s_addr; 2403 sprintf(str, "%d.%d.%d.%d", (int)vals[0], (int)vals[1], (int)vals[2], (int)vals[3]); 2404 return std::string(str); 2405} 2406 2407bool SQRNetworkManager_Vita::CreateSocket() 2408{ 2409 // First get details of the UDPP2P connection that has been established 2410 // int connStatus; 2411 SceNetSockaddrIn sinp2pLocal;//, sinp2pPeer; 2412 SceNpMatching2SignalingNetInfo netInfo; 2413 2414 // Local end first... 2415 memset(&sinp2pLocal, 0, sizeof(sinp2pLocal)); 2416 memset(&netInfo, 0 , sizeof(netInfo)); 2417 netInfo.size = sizeof(netInfo); 2418 int ret = sceNpMatching2SignalingGetLocalNetInfo(&netInfo); 2419 if( ret < 0 ) return false; 2420 sinp2pLocal.sin_len = sizeof(sinp2pLocal); 2421 sinp2pLocal.sin_family = SCE_NET_AF_INET; 2422 sinp2pLocal.sin_port = sceNetHtons(SCE_NP_PORT); 2423 sinp2pLocal.sin_addr = netInfo.localAddr; 2424 2425 2426 // Set vport for both ends of connection 2427 sinp2pLocal.sin_vport = sceNetHtons(1); 2428 2429 // Create socket & bind 2430 ret = sceNetSocket("rupdSocket", SCE_NET_AF_INET, SCE_NET_SOCK_DGRAM_P2P, 0); 2431 assert(ret >= 0); 2432 m_soc = ret; 2433 int optval = 1; 2434 ret = sceNetSetsockopt(m_soc, SCE_NET_SOL_SOCKET, SCE_NET_SO_USECRYPTO, &optval, sizeof(optval)); 2435 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SETSOCKOPT_0) ) return false; 2436 ret = sceNetSetsockopt(m_soc, SCE_NET_SOL_SOCKET, SCE_NET_SO_USESIGNATURE, &optval, sizeof(optval)); 2437 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SETSOCKOPT_1) ) return false; 2438 ret = sceNetSetsockopt(m_soc, SCE_NET_SOL_SOCKET, SCE_NET_SO_NBIO, &optval, sizeof(optval)); 2439 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SETSOCKOPT_2) ) return false; 2440 2441 ret = sceNetBind(m_soc, &sinp2pLocal, sizeof(sinp2pLocal)); 2442 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_SOCK_BIND) ) return false; 2443 return true; 2444 2445} 2446 2447 2448bool SQRNetworkManager_Vita::CreateVoiceRudpConnections(SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId peerMemberId, int playerMask) 2449{ 2450 SceNetSockaddrIn sinp2pPeer; 2451 SceNpMatching2SignalingNetInfo netInfo; 2452 int connStatus; 2453 2454 memset(&sinp2pPeer, 0, sizeof(sinp2pPeer)); 2455 sinp2pPeer.sin_len = sizeof(sinp2pPeer); 2456 sinp2pPeer.sin_family = SCE_NET_AF_INET; 2457 int ret = sceNpMatching2SignalingGetConnectionStatus(m_matchingContext, roomId, peerMemberId, &connStatus, &sinp2pPeer.sin_addr, &sinp2pPeer.sin_port); 2458 sinp2pPeer.sin_vport = sceNetHtons(1); 2459 2460 2461 ret = 0; 2462 // Create socket & bind, if we don't already have one 2463 if( m_soc == -1 ) 2464 { 2465 if(CreateSocket() == false) 2466 return false; 2467 } 2468 2469 // create this connection if we don't have it already 2470 SQRVoiceConnection* pConnection = SonyVoiceChat_Vita::getVoiceConnectionFromRoomMemberID(peerMemberId); 2471 if(pConnection == NULL) 2472 { 2473 2474 // Create an Rudp context for the voice connection, this will happen regardless of whether the peer is client or host 2475 int rudpCtx; 2476 ret = sceRudpCreateContext( RudpContextCallback, this, &rudpCtx ); 2477 if(ret < 0){ app.DebugPrintf("sceRudpCreateContext failed : 0x%08x\n", ret); assert(0); } 2478 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_CREATE_RUDP_CONTEXT) ) return false; 2479 2480 // Bind the context to the socket we've just created, and initiate. The initiation needs to happen on both client & host sides of the connection to complete. 2481 ret = sceRudpBind( rudpCtx, m_soc , 5, SCE_RUDP_MUXMODE_P2P ); 2482 if(ret < 0){ app.DebugPrintf("sceRudpBind failed : 0x%08x\n", ret); assert(0); } 2483 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_RUDP_BIND) ) return false; 2484 2485 ret = sceRudpInitiate( rudpCtx, (SceNetSockaddr*)&sinp2pPeer, sizeof(sinp2pPeer), 0); 2486 if(ret < 0){ app.DebugPrintf("sceRudpInitiate failed : 0x%08x\n", ret); assert(0); } 2487 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_RUDP_INIT2) ) return false; 2488 2489 app.DebugPrintf("-----------------------------\n"); 2490 app.DebugPrintf("Voice rudp context created %d connected to %s\n", rudpCtx, getIPAddressString(sinp2pPeer.sin_addr).c_str()); 2491 app.DebugPrintf("-----------------------------\n"); 2492 2493 pConnection = SonyVoiceChat_Vita::addRemoteConnection(rudpCtx, peerMemberId); 2494 } 2495 2496 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 2497 { 2498 bool bMaskVal = ( playerMask & ( 1 << i ) ); 2499 2500 if(bMaskVal || GetLocalPlayerByUserIndex(i)) 2501 SonyVoiceChat_Vita::connectPlayer(pConnection, i); 2502 } 2503 return true; 2504} 2505 2506 2507 2508bool SQRNetworkManager_Vita::CreateRudpConnections(SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId peerMemberId, int playerMask, SceNpMatching2RoomMemberId playersMemberId) 2509{ 2510 // First get details of the UDPP2P connection that has been established 2511 int connStatus; 2512 SceNetSockaddrIn sinp2pPeer; 2513 2514 // get the peer 2515 memset(&sinp2pPeer, 0, sizeof(sinp2pPeer)); 2516 sinp2pPeer.sin_len = sizeof(sinp2pPeer); 2517 sinp2pPeer.sin_family = SCE_NET_AF_INET; 2518 2519 int ret = sceNpMatching2SignalingGetConnectionStatus(m_matchingContext, roomId, peerMemberId, &connStatus, &sinp2pPeer.sin_addr, &sinp2pPeer.sin_port); 2520 app.DebugPrintf(CMinecraftApp::USER_RR,"sceNpMatching2SignalingGetConnectionStatus returned 0x%x, connStatus %d peer add:%s peer port:0x%x\n",ret, connStatus,getIPAddressString(sinp2pPeer.sin_addr).c_str(),sinp2pPeer.sin_port); 2521 2522 // Set vport 2523 sinp2pPeer.sin_vport = sceNetHtons(1); 2524 2525 // Create socket & bind, if we don't already have one 2526 if( m_soc == -1 ) 2527 { 2528 if(CreateSocket() == false) 2529 return false; 2530 } 2531 2532 // Create an Rudp context for each local player that is required. These can be used as individual virtual connections between room members (ie consoles), which are multiplexed 2533 // over the socket we have just made 2534 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 2535 { 2536 if( ( playerMask & ( 1 << i ) ) == 0 ) continue; 2537 2538 int rudpCtx; 2539 2540 // Socket for the local network node created, now can create an Rupd context. 2541 ret = sceRudpCreateContext( RudpContextCallback, this, &rudpCtx ); 2542 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_CREATE_RUDP_CONTEXT) ) return false; 2543 if( m_isHosting ) 2544 { 2545 m_RudpCtxToPlayerMap[ rudpCtx ] = new SQRNetworkPlayer( this, SQRNetworkPlayer::SNP_TYPE_REMOTE, true, playersMemberId, i, rudpCtx, NULL ); 2546 } 2547 else 2548 { 2549 // Local players can establish their UID at this point 2550 PlayerUID localUID; 2551 ProfileManager.GetXUID(i,&localUID,true); 2552 2553 m_RudpCtxToPlayerMap[ rudpCtx ] = new SQRNetworkPlayer( this, SQRNetworkPlayer::SNP_TYPE_LOCAL, false, m_localMemberId, i, rudpCtx, &localUID ); 2554 } 2555 2556 // If we've created a player, then we want to try and patch up any connections that we should have to it 2557 MapRoomSlotPlayers(); 2558 2559 // TODO - set any non-default options for the context. By default, the context is set to have delivery critical and order critical both on 2560 2561 // Bind the context to the socket we've just created, and initiate. The initiation needs to happen on both client & host sides of the connection to complete. 2562 ret = sceRudpBind( rudpCtx, m_soc , 1 + i, SCE_RUDP_MUXMODE_P2P ); 2563 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_RUDP_BIND) ) return false; 2564 2565 ret = sceRudpInitiate( rudpCtx, &sinp2pPeer, sizeof(sinp2pPeer), 0); 2566 if ( ( ret < 0 ) || ForceErrorPoint(SNM_FORCE_ERROR_RUDP_INIT2) ) return false; 2567 } 2568 return true; 2569} 2570 2571 2572SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerFromRudpCtx(int rudpCtx) 2573{ 2574 AUTO_VAR(it,m_RudpCtxToPlayerMap.find(rudpCtx)); 2575 if( it != m_RudpCtxToPlayerMap.end() ) 2576 { 2577 return it->second; 2578 } 2579 return NULL; 2580} 2581 2582 2583 2584SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerFromRoomMemberAndLocalIdx(int roomMember, int localIdx) 2585{ 2586 for(AUTO_VAR(it, m_RudpCtxToPlayerMap.begin()); it != m_RudpCtxToPlayerMap.end(); it++ ) 2587 { 2588 if( (it->second->m_roomMemberId == roomMember ) && ( it->second->m_localPlayerIdx == localIdx ) ) 2589 { 2590 return it->second; 2591 } 2592 } 2593 return NULL; 2594} 2595 2596 2597// This is called as part of the general initialisation of the network manager, to register any callbacks that the sony libraries require. 2598// Returns true if all were registered successfully. 2599bool SQRNetworkManager_Vita::RegisterCallbacks() 2600{ 2601 // Register RUDP event handler 2602 app.DebugPrintf("sceRudpSetEventHandler\n"); 2603 int ret = sceRudpSetEventHandler(RudpEventCallback, this); 2604 if (ret < 0) 2605 { 2606 app.DebugPrintf("SQRNetworkManager::RegisterCallbacks - cellRudpSetEventHandler failed with code 0x%08x\n", ret); 2607 return false; 2608 } 2609 2610 // Register the context callback function 2611 app.DebugPrintf("sceNpMatching2RegisterContextCallback\n"); 2612 ret = sceNpMatching2RegisterContextCallback(ContextCallback, this); 2613 if (ret < 0) 2614 { 2615 app.DebugPrintf("SQRNetworkManager::RegisterCallbacks - sceNpMatching2RegisterContextCallback failed with code 0x%08x\n", ret); 2616 return false; 2617 } 2618 2619 // Register the default request callback & parameters 2620 SceNpMatching2RequestOptParam optParam; 2621 2622 memset(&optParam, 0, sizeof(optParam)); 2623 optParam.cbFunc = DefaultRequestCallback; 2624 optParam.cbFuncArg = this; 2625 optParam.timeout = (30 * 1000 * 1000); 2626 optParam.appReqId = 0; 2627 2628 app.DebugPrintf("sceNpMatching2SetDefaultRequestOptParam\n"); 2629 ret = sceNpMatching2SetDefaultRequestOptParam(m_matchingContext, &optParam); 2630 if (ret < 0) 2631 { 2632 app.DebugPrintf("SQRNetworkManager::RegisterCallbacks - sceNpMatching2SetDefaultRequestOptParam failed with code 0x%08x\n", ret); 2633 return false; 2634 } 2635 2636 // Register signalling callback 2637 app.DebugPrintf("sceNpMatching2RegisterSignalingCallback\n"); 2638 ret = sceNpMatching2RegisterSignalingCallback(m_matchingContext, SignallingCallback, this); 2639 if (ret < 0) 2640 { 2641 return false; 2642 } 2643 2644 // Register room event callback 2645 app.DebugPrintf("sceNpMatching2RegisterRoomEventCallback\n"); 2646 ret = sceNpMatching2RegisterRoomEventCallback(m_matchingContext, RoomEventCallback, this); 2647 if (ret < 0) 2648 { 2649 app.DebugPrintf("SQRNetworkManager::RegisterCallbacks - sceNpMatching2RegisterRoomEventCallback failed with code 0x%08x\n", ret); 2650 return false; 2651 } 2652 2653 return true; 2654} 2655 2656extern bool g_bBootedFromInvite; 2657 2658// This is an implementation of SceNpMatching2ContextCallback. Used to determine whether the matching 2 context is valid or not. 2659void SQRNetworkManager_Vita::ContextCallback(SceNpMatching2ContextId id, SceNpMatching2Event event, SceNpMatching2EventCause eventCause, int errorCode, void *arg) 2660{ 2661 if(CGameNetworkManager::usingAdhocMode()) // MGH - added to fix #5772 2662 return; 2663 2664 2665 int ret; 2666 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 2667 EnterCriticalSection(&manager->m_csMatching); 2668 if (id != manager->m_matchingContext) 2669 { 2670 LeaveCriticalSection(&manager->m_csMatching); 2671 return; 2672 } 2673 2674 switch( event ) 2675 { 2676 case SCE_NP_MATCHING2_CONTEXT_EVENT_STARTED: 2677 app.DebugPrintf("SCE_NP_MATCHING2_CONTEXT_EVENT_STARTED\n"); 2678 if(errorCode < 0) 2679 { 2680 if(manager->m_state == SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT || 2681 manager->m_state == SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT || 2682 manager->m_state == SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT) 2683 { 2684 // matching context failed to start (this can happen when you block the IP addresses of the matching servers on your router 2685 // agent-0101.ww.sp-int.matching.playstation.net (198.107.157.191) 2686 // static-resource.sp-int.community.playstation.net (203.105.77.140) 2687 manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 2688 break; 2689 } 2690 } 2691 // Some special cases to detect when this event is coming in, in case we had to start the matching context because there wasn't a valid context when we went to get a server context. These two 2692 // responses here complete what should then happen to get the server context in each case (for hosting or joining a game) 2693 if( manager->m_state == SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT ) 2694 { 2695 manager->SetState( SNM_INT_STATE_IDLE ); 2696 manager->GetExtDataForRoom(0, NULL, NULL, NULL); 2697 break; 2698 } 2699 2700 if( manager->m_state == SNM_INT_STATE_HOSTING_STARTING_MATCHING_CONTEXT ) 2701 { 2702 manager->GetServerContext2(); 2703 break; 2704 } 2705 if( manager->m_state == SNM_INT_STATE_JOINING_STARTING_MATCHING_CONTEXT ) 2706 { 2707 manager->SetState(SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER); 2708 manager->SelectRandomServer(); 2709 break; 2710 } 2711 if ( manager->m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT ) 2712 { 2713 manager->ServerContextValid_CreateRoom(); 2714 break; 2715 } 2716 // Normal handling of context starting, from standard initialisation procedure 2717 assert( manager->m_state == SNM_INT_STATE_STARTING_CONTEXT ); 2718 if (errorCode < 0) 2719 { 2720 manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 2721 } 2722 else 2723 { 2724 manager->m_offlineSQR = false; 2725 manager->SetState(SNM_INT_STATE_IDLE); 2726 2727 // 4J-PB - SQRNetworkManager_PS3::AttemptPSNSignIn was causing crashes in Iggy by calling LoadMovie from a callback, so call it from the tick instead 2728 m_bCallPSNSignInCallback=true; 2729 // if(s_SignInCompleteCallbackFn) 2730 // { 2731 // s_SignInCompleteCallbackFn(s_SignInCompleteParam, true, 0); 2732 // s_SignInCompleteCallbackFn = NULL; 2733 // } 2734 2735 2736 // Check to see if we were booted from an invite. Only do this once, the first time we have all our networking stuff set up on boot-up 2737 if( manager->m_doBootInviteCheck ) 2738 { 2739 // ORBIS_STUBBED; 2740 // unsigned int type, attributes; 2741 // CellGameContentSize gameSize;` 2742 // char dirName[CELL_GAME_DIRNAME_SIZE]; 2743 // 2744 // if( g_bBootedFromInvite ) 2745 // { 2746 // manager->GetInviteDataAndProcess(SCE_NP_BASIC_SELECTED_INVITATION_DATA); 2747 // manager->m_doBootInviteCheck = false; 2748 // } 2749 } 2750 } 2751 break; 2752 case SCE_NP_MATCHING2_CONTEXT_EVENT_STOPPED: 2753 app.DebugPrintf("SCE_NP_MATCHING2_CONTEXT_EVENT_STOPPED\n"); 2754 // Can happen when we stop the PSN to switch to adhoc mode 2755 //assert(false); 2756 if( manager->m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT ) 2757 { 2758 sceNpMatching2DestroyContext(manager->m_matchingContext); 2759 manager->m_matchingContextValid = false; 2760 if(!manager->GetMatchingContext(SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT)) 2761 { 2762 manager->m_offlineSQR = true; 2763 manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 2764 } 2765 } 2766 break; 2767 case SCE_NP_MATCHING2_CONTEXT_EVENT_START_OVER: 2768 2769 app.DebugPrintf("SCE_NP_MATCHING2_CONTEXT_EVENT_START_OVER\n"); 2770 app.DebugPrintf("SCE_NP_MATCHING2_CONTEXT_EVENT_START_OVER\n"); 2771 app.DebugPrintf("eventCause=%u, errorCode=0x%08x\n", eventCause, errorCode); 2772 app.DebugPrintf("sceNpMatching2DestroyContext\n"); 2773 sceNpMatching2DestroyContext(manager->m_matchingContext); 2774 if(manager->m_state == SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT) // MGH - added this to catch when the context start fails when getting GetExtDataForRoom 2775 { 2776 if(manager->m_FriendSessionUpdatedFn) 2777 manager->m_FriendSessionUpdatedFn(false, manager->m_pParamFriendSessionUpdated); 2778 } 2779 manager->m_matchingContextValid = false; 2780 manager->m_offlineSQR = true; 2781 manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 2782 break; 2783 } 2784 2785 LeaveCriticalSection(&manager->m_csMatching); 2786} 2787 2788// This is an implementation of SceNpMatching2RequestCallback. This callback is used by default for any matching 2 request functions. 2789void SQRNetworkManager_Vita::DefaultRequestCallback(SceNpMatching2ContextId id, SceNpMatching2RequestId reqId, SceNpMatching2Event event, int errorCode, const void *data, void *arg) 2790{ 2791 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 2792 EnterCriticalSection(&manager->m_csMatching); 2793 // int ret; 2794 if( id != manager->m_matchingContext ) 2795 { 2796 LeaveCriticalSection(&manager->m_csMatching); 2797 return; 2798 } 2799 2800 2801 switch( event ) 2802 { 2803 // This is the response to sceNpMatching2GetWorldInfoList, which is called as part of the process to create a room (which needs a world to be created in). We aren't anticipating 2804 // using worlds in a meaningful way so just getting the first world we find on the server here, and then advancing the state so that the tick can get on with the rest of the process. 2805 case SCE_NP_MATCHING2_REQUEST_EVENT_GET_WORLD_INFO_LIST: 2806 { 2807 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_GET_WORLD_INFO_LIST\n"); 2808 SceNpServiceState serviceState; 2809 int retVal = sceNpGetServiceState(&serviceState); 2810 assert(retVal == 0); 2811 assert(serviceState == SCE_NP_SERVICE_STATE_ONLINE); 2812 2813 if( errorCode == SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT ) 2814 { 2815 // If we've already signed out, then we should have detected this already elsewhere and so can silently ignore any errors coming in for pending requests here 2816 break; 2817 } 2818 assert( manager->m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_SEARCHING_FOR_WORLD ); 2819 if( errorCode == 0 ) 2820 { 2821 if( data != 0 ) 2822 { 2823 // Currently just using first world - this may well be all that we need anyway 2824 SceNpMatching2GetWorldInfoListResponse *pWorldList = (SceNpMatching2GetWorldInfoListResponse *)data; 2825 if( pWorldList->worldNum >= 1 ) 2826 { 2827 manager->m_worldId = pWorldList->world[0].worldId; 2828 manager->SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_WORLD_FOUND); 2829 break; 2830 } 2831 } 2832 } 2833 // We get this error when starting a new game after a disconnect occurred in a previous game with at least one remote player. Fix by stopping/starting the matching context. 2834 // We stop the context here, which is picked up in the callback, and started again. Then the start event is picked up and reattempts the sceNpMatching2GetWorldInfoList. 2835 if( errorCode == SCE_NET_ERROR_EAGAIN || errorCode == SCE_NET_ERROR_RESOLVER_ETIMEDOUT || errorCode == SCE_NET_CTL_ERROR_WIFI_DISABLED ) 2836 { 2837 sceNpMatching2ContextStop(manager->m_matchingContext); 2838 manager->SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_RESTART_MATCHING_CONTEXT); 2839 break; 2840 } 2841 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_GET_WORLD_INFO_LIST failed, errorCode 0x%x, data %d\n", errorCode, data); 2842 2843 manager->SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED); 2844 } 2845 break; 2846 // This is the response to sceNpMatching2CreateJoinRoom, which if successful means that we are just about ready to move to an online state as host of a game. The final 2847 // transition actually occurs in the create room tick, on detecting that the state has transitioned to SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS here. 2848 case SCE_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM: 2849 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_CREATE_JOIN_ROOM\n"); 2850 if( errorCode == SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT ) 2851 { 2852 // If we've already signed out, then we should have detected this already elsewhere and so can silently ignore any errors coming in for pending requests here 2853 break; 2854 } 2855 2856 if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()) == false) 2857 { 2858 // MGH - added to catch a case where the user signed out of PSN, but this still called back with no error 2859 break; 2860 } 2861 2862 app.DebugPrintf(CMinecraftApp::USER_RR,">> Creating room complete, time taken %d, error 0x%x\n",System::currentTimeMillis()-s_roomStartTime, errorCode); 2863 assert( manager->m_state == SNM_INT_STATE_HOSTING_CREATE_ROOM_CREATING_ROOM ); 2864 if( errorCode == 0 ) 2865 { 2866 if( data != 0 ) 2867 { 2868 SceNpMatching2CreateJoinRoomResponse *roomData = (SceNpMatching2CreateJoinRoomResponse *)data; 2869 manager->m_localMemberId = roomData->roomDataInternal->memberList.me->memberId; 2870 2871 manager->SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_SUCCESS); 2872 manager->m_room = roomData->roomDataInternal->roomId; 2873 break; 2874 } 2875 } 2876 manager->SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED); 2877 break; 2878 // This is the response to sceNpMatching2JoinRoom, which is called as the final stage of the process started when calling the JoinRoom method. If this is successful, then 2879 // the state can change to SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS. We can transition out of that state once we have told the application that all the local players 2880 // have joined. 2881 case SCE_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM: 2882 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_JOIN_ROOM\n"); 2883 assert( manager->m_state == SNM_INT_STATE_JOINING_JOIN_ROOM); 2884 if( errorCode == 0 ) 2885 { 2886 if( data != 0 ) 2887 { 2888 SceNpMatching2JoinRoomResponse *roomData = (SceNpMatching2JoinRoomResponse *)data; 2889 2890 manager->m_localMemberId = roomData->roomDataInternal->memberList.me->memberId; 2891 manager->m_room = roomData->roomDataInternal->roomId; 2892 // SonyVoiceChat::init(manager); 2893 // Copy over initial room sync data 2894 for( int i = 0; i < roomData->roomDataInternal->roomBinAttrInternalNum; i++ ) 2895 { 2896 if( roomData->roomDataInternal->roomBinAttrInternal[i].data.id == SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID ) 2897 { 2898 assert( roomData->roomDataInternal->roomBinAttrInternal[i].data.size == sizeof( manager->m_roomSyncData ) ); 2899 memcpy( &manager->m_roomSyncData, roomData->roomDataInternal[i].roomBinAttrInternal[0].data.ptr, sizeof( manager->m_roomSyncData ) ); 2900 2901 // manager->UpdatePlayersFromRoomSyncUIDs(); 2902 // Update mapping from the room slot players to SQRNetworkPlayer instances 2903 manager->MapRoomSlotPlayers(); 2904 break; 2905 } 2906 } 2907 manager->SetState(SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS); 2908 break; 2909 } 2910 } 2911 manager->SetState(SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED); 2912 if(errorCode == SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL) // MGH - added to fix "host has exited" error when 2 players go after the final slot 2913 { 2914 app.DebugPrintf("setting DisconnectPacket::eDisconnect_ServerFull\n"); 2915 Minecraft::GetInstance()->connectionDisconnected(ProfileManager.GetPrimaryPad(), DisconnectPacket::eDisconnect_ServerFull); 2916 app.SetDisconnectReason(DisconnectPacket::eDisconnect_ServerFull); // MGH - added to fix when joining from an invite 2917 } 2918 break; 2919 // This is the response to sceNpMatching2GetRoomMemberDataInternal.This only happens on the host, as a response to an incoming connection being established, when we 2920 // kick off the request for room member internal data so that we can determine what local players that remote machine is intending to bring into the game. At this point we can 2921 // activate the host end of each of the Rupd connection that this machine requires. We can also update our player slot data (which gets syncronised back out to other room members) at this point. 2922 case SCE_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_MEMBER_DATA_INTERNAL: 2923 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_MEMBER_DATA_INTERNAL\n"); 2924 if( manager->m_state == SNM_INT_STATE_INITIALISE_FAILED || 2925 manager->m_state == SNM_INT_STATE_IDLE || 2926 manager->m_state == SNM_INT_STATE_LEAVING || 2927 manager->m_state == SNM_INT_STATE_ENDING ) 2928 { 2929 // MGH - I've caught this being triggered after join has already failed, and then UDP connections are created that aren't killed off 2930 // so just break out here if we're not in the expected state 2931 // fixes devtrack #5807 2932 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_MEMBER_DATA_INTERNAL - manager->GetState() : %d\n", manager->GetState() ); 2933 break; 2934 } 2935 if( errorCode == 0 ) 2936 { 2937 2938 if( data != 0 ) 2939 { 2940 SceNpMatching2GetRoomMemberDataInternalResponse *pRoomMemberData = (SceNpMatching2GetRoomMemberDataInternalResponse *)data; 2941 assert( pRoomMemberData->roomMemberDataInternal->roomMemberBinAttrInternalNum == 1 ); 2942 2943 if( manager->m_isHosting ) 2944 { 2945 int playerMask = *((int *)(pRoomMemberData->roomMemberDataInternal->roomMemberBinAttrInternal->data.ptr)); 2946 2947 bool isFull = false; 2948 bool success1 = manager->AddRemotePlayersAndSync( pRoomMemberData->roomMemberDataInternal->memberId, playerMask, &isFull ); 2949 bool success2; 2950 if( success1 ) 2951 { 2952 success2 = manager->CreateRudpConnections(manager->m_room, pRoomMemberData->roomMemberDataInternal->memberId, playerMask, pRoomMemberData->roomMemberDataInternal->memberId); 2953 if( success2 ) 2954 { 2955 bool ret = manager->CreateVoiceRudpConnections( manager->m_room, pRoomMemberData->roomMemberDataInternal->memberId, 0); 2956 assert(ret == true); 2957 break; 2958 } 2959 } 2960 // Something has gone wrong adding these players to the room - kick out the player 2961 SceNpMatching2KickoutRoomMemberRequest reqParam; 2962 // SceNpMatching2PresenceOptionData optParam; 2963 memset(&reqParam,0,sizeof(reqParam)); 2964 reqParam.roomId = manager->m_room; 2965 reqParam.target = pRoomMemberData->roomMemberDataInternal->memberId; 2966 // Set flag to indicate whether we were kicked for being out of room or not 2967 reqParam.optData.data[0] = isFull ? 1 : 0; 2968 reqParam.optData.len = 1; 2969 int ret = sceNpMatching2KickoutRoomMember(manager->m_matchingContext, &reqParam, NULL, &manager->m_kickRequestId); 2970 app.DebugPrintf(CMinecraftApp::USER_RR,"sceNpMatching2KickoutRoomMember returns error 0x%x\n",ret); 2971 } 2972 else 2973 { 2974 if(pRoomMemberData->roomMemberDataInternal->roomMemberBinAttrInternal->data.ptr == NULL) 2975 { 2976 // the host doesn't send out data, so this must be the host we're connecting to 2977 2978 // If we are the client, then we locally know what Rupd connections we need (from m_localPlayerJoinMask) and can kick this off. 2979 manager->m_hostMemberId = pRoomMemberData->roomMemberDataInternal->memberId; 2980 bool ret = manager->CreateRudpConnections( manager->m_room, pRoomMemberData->roomMemberDataInternal->memberId, manager->m_localPlayerJoinMask, manager->m_localMemberId); 2981 if( ret == false ) 2982 { 2983 manager->DeleteServerContext(); 2984 } 2985 else 2986 { 2987 bool ret = manager->CreateVoiceRudpConnections( manager->m_room, pRoomMemberData->roomMemberDataInternal->memberId, manager->m_localPlayerJoinMask); 2988 assert(ret == true); 2989 } 2990 } 2991 else 2992 { 2993 // client <-> client 2994 bool ret = manager->CreateVoiceRudpConnections( manager->m_room, pRoomMemberData->roomMemberDataInternal->memberId, manager->m_localPlayerJoinMask); 2995 assert(ret == true); 2996 } 2997 } 2998 2999 } 3000 } 3001 break; 3002 case SCE_NP_MATCHING2_REQUEST_EVENT_LEAVE_ROOM: 3003 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_LEAVE_ROOM\n"); 3004 // This is the response to sceNpMatching2LeaveRoom - from the Sony docs, this doesn't ever fail so no need to do error checking here 3005 // SonyVoiceChat::signalDisconnected(); 3006 assert(manager->m_state == SNM_INT_STATE_LEAVING ); 3007 manager->DeleteServerContext(); 3008 break; 3009 // This is the response to SceNpMatching2GetRoomDataExternalListRequest, which happens when we request the full details of a room we are interested in joining 3010 case SCE_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST: 3011 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_GET_ROOM_DATA_EXTERNAL_LIST\n"); 3012 if( errorCode == 0 ) 3013 { 3014 if( data != 0 ) 3015 { 3016 SceNpMatching2GetRoomDataExternalListResponse *pExternalData = (SceNpMatching2GetRoomDataExternalListResponse *)data; 3017 SceNpMatching2RoomDataExternal *pRoomExtData = pExternalData->roomDataExternal; 3018 if( pExternalData->roomDataExternalNum == 1 ) 3019 { 3020 if(pRoomExtData->roomBinAttrExternalNum == 1 ) 3021 { 3022 memcpy(manager->m_pExtDataToUpdate, pRoomExtData->roomBinAttrExternal[0].ptr,pRoomExtData->roomBinAttrExternal[0].size); 3023 manager->m_FriendSessionUpdatedFn(true, manager->m_pParamFriendSessionUpdated); 3024 } 3025 else 3026 { 3027 manager->m_FriendSessionUpdatedFn(false, manager->m_pParamFriendSessionUpdated); 3028 } 3029 } 3030 else 3031 { 3032 manager->m_FriendSessionUpdatedFn(false, manager->m_pParamFriendSessionUpdated); 3033 } 3034 } 3035 else 3036 { 3037 manager->m_FriendSessionUpdatedFn(false, manager->m_pParamFriendSessionUpdated); 3038 } 3039 } 3040 else 3041 { 3042 manager->m_FriendSessionUpdatedFn(false, manager->m_pParamFriendSessionUpdated); 3043 } 3044 break; 3045 case SCE_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_EXTERNAL: 3046 app.DebugPrintf("SCE_NP_MATCHING2_REQUEST_EVENT_SET_ROOM_DATA_EXTERNAL\n"); 3047 if( ( errorCode != 0 ) || manager->ForceErrorPoint(SNM_FORCE_ERROR_SET_ROOM_DATA_CALLBACK) ) 3048 { 3049 app.DebugPrintf(CMinecraftApp::USER_RR,"Error updating external data 0x%x (from SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal event in callback)\n",errorCode); 3050 // If we ever fail to send the external room data, we start a countdown so that we attempt to resend. Not sure how likely it is that updating this will fail without the whole network being broken, 3051 // but if in particular we don't update the flag to say that the session is joinable, then nobody is ever going to see this session. 3052 manager->m_resendExternalRoomDataCountdown = 60; 3053 } 3054 break; 3055 }; 3056 3057 LeaveCriticalSection(&manager->m_csMatching); 3058} 3059 3060void SQRNetworkManager_Vita::RoomEventCallback(SceNpMatching2ContextId id, SceNpMatching2RoomId roomId, SceNpMatching2Event event, const void *data, void *arg) 3061{ 3062 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3063 3064 // bool gotEventData = false; 3065 switch( event ) 3066 { 3067 case SCE_NP_MATCHING2_ROOM_EVENT_MEMBER_JOINED: 3068 break; 3069 case SCE_NP_MATCHING2_ROOM_EVENT_MEMBER_LEFT: 3070 break; 3071 case SCE_NP_MATCHING2_ROOM_EVENT_KICKEDOUT: 3072 { 3073 // SonyVoiceChat::signalRoomKickedOut(); 3074 // We've been kicked out. This server has rejected our attempt to join, most likely because there wasn't enough space in the server to have us. There's a flag set 3075 // so we can determine which thing has happened 3076 // assert ( dataSize <= SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomUpdateInfo ); 3077 // int ret = sceNpMatching2GetEventData( manager->m_matchingContext, eventKey, manager->cRoomDataUpdateInfo, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomUpdateInfo); 3078 // app.DebugPrintf(CMinecraftApp::USER_RR,"SCE_NP_MATCHING2_ROOM_EVENT_Kickedout, sceNpMatching2GetEventData returning 0x%x\n",ret); 3079 3080 bool bIsFull = false; 3081 if( ( data ) && !manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_DATA) ) 3082 { 3083 // gotEventData = true; 3084 SceNpMatching2RoomUpdateInfo *pUpdateInfo = (SceNpMatching2RoomUpdateInfo *)(data); 3085 if( pUpdateInfo->optData.len == 1 ) 3086 { 3087 if( pUpdateInfo->optData.data[0] == 1 ) 3088 { 3089 bIsFull = true; 3090 } 3091 } 3092 } 3093 app.DebugPrintf(CMinecraftApp::USER_RR,"IsFull determined to be %d\n",bIsFull); 3094 if( bIsFull ) 3095 { 3096 manager->m_nextIdleReasonIsFull = true; 3097 } 3098 manager->ResetToIdle(); 3099 } 3100 break; 3101 case SCE_NP_MATCHING2_ROOM_EVENT_ROOM_DESTROYED: 3102 // SonyVoiceChat::signalRoomDestroyed(); 3103 3104 { 3105 SceNpMatching2RoomUpdateInfo *pUpdateInfo = (SceNpMatching2RoomUpdateInfo *)data; 3106 app.DebugPrintf("SCE_NP_MATCHING2_ROOM_EVENT_RoomDestroyed\n"); 3107 if( pUpdateInfo ) 3108 { 3109 app.DebugPrintf("Further info: Error 0x%x, cause %d\n",pUpdateInfo->errorCode,pUpdateInfo->eventCause); 3110 } 3111 // If we're hosting, then handle this a bit like a disconnect, in that we will shift the game into an offline game - but don't need to actually leave the room 3112 // since that has been destroyed and so isn't there to be left anymore. Don't do this if we are disconnected though, as we've already handled this. 3113 if( ( manager->m_isHosting ) && !manager->m_bLinkDisconnected ) 3114 { 3115 // MGH - we're not receiving an SCE_NP_MATCHING2_SIGNALING_EVENT_DEAD after this so we have to remove all the remote players 3116 while(manager->m_RudpCtxToPlayerMap.size()) 3117 { 3118 SQRNetworkPlayer* pRemotePlayer = manager->m_RudpCtxToPlayerMap.begin()->second; 3119 manager->RemoveRemotePlayersAndSync( pRemotePlayer->m_roomMemberId, 15 ); 3120 } 3121 3122 // MGH - added a check for the PSN sign in state, we don't seem to get the signed out matching2 error here 3123 bool bSignedInPSN = ProfileManager.IsSignedInPSN(ProfileManager.GetPrimaryPad()); 3124 bool bSignedOutError = pUpdateInfo && (pUpdateInfo->eventCause==SCE_NP_MATCHING2_EVENT_CAUSE_NP_SIGNED_OUT); 3125 3126 if(bSignedOutError || (bSignedInPSN == false) ) 3127 { 3128 manager->m_listener->HandleDisconnect(true,true); 3129 } 3130 else 3131 { 3132 manager->m_listener->HandleDisconnect(true); 3133 } 3134 } 3135 } 3136 break; 3137 case SCE_NP_MATCHING2_ROOM_EVENT_ROOM_OWNER_CHANGED: 3138 break; 3139 case SCE_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_DATA_INTERNAL: 3140 // We are using the room internal data to synchronise the player data stored in m_roomSyncData from the host to clients. 3141 // The host is the thing creating the internal room data, so it doesn't need to update itself. 3142 if( !manager->m_isHosting ) 3143 { 3144 // assert ( dataSize <= SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomDataInternalUpdateInfo ); 3145 // int ret = sceNpMatching2GetEventData( manager->m_matchingContext, eventKey, manager->cRoomDataInternal, SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomDataInternalUpdateInfo); 3146 if( ( data) && !manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_DATA) ) 3147 { 3148 // gotEventData = true; 3149 SceNpMatching2RoomDataInternalUpdateInfo *pRoomData = (SceNpMatching2RoomDataInternalUpdateInfo *)(data); 3150 for(int i = 0; i < pRoomData->newRoomBinAttrInternalNum; i++) 3151 { 3152 if( pRoomData->newRoomBinAttrInternal[i]->data.id == SCE_NP_MATCHING2_ROOM_BIN_ATTR_INTERNAL_1_ID ) 3153 { 3154 assert( pRoomData->newRoomBinAttrInternal[i]->data.size == sizeof( manager->m_roomSyncData ) ); 3155 memcpy( &manager->m_roomSyncData, pRoomData->newRoomBinAttrInternal[i]->data.ptr, sizeof( manager->m_roomSyncData ) ); 3156 3157 // manager->UpdatePlayersFromRoomSyncUIDs(); 3158 // Update mapping from the room slot players to SQRNetworkPlayer instances 3159 manager->MapRoomSlotPlayers(); 3160#if 0 3161 { 3162 printf("New player sync data arrived\n"); 3163 for(int i = 0; i < manager->m_roomSyncData.getPlayerCount(); i++ ) 3164 { 3165 printf("%d: small %d, machine %d, local %d\n",i, manager->m_roomSyncData.players[i].m_smallId, manager->m_roomSyncData.players[i].m_roomMemberId, manager->m_roomSyncData.players[i].m_localIdx); 3166 } 3167 } 3168#endif 3169 break; 3170 } 3171 } 3172 break; 3173 } 3174 // TODO - handle error here? What could we do? 3175 } 3176 3177 break; 3178 case SCE_NP_MATCHING2_ROOM_EVENT_UPDATED_ROOM_MEMBER_DATA_INTERNAL: 3179 if( /*( errorCode == 0 ) && */(!manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL1) ) ) 3180 { 3181 // We'll get this sync'd round all the connected clients, but we only care about it on the host where we can use it to work out if any RUDP connections need to be made or released 3182 if( manager->m_isHosting ) 3183 { 3184 // assert( dataSize <= SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberDataInternalUpdateInfo ); 3185 // int ret = sceNpMatching2GetEventData(manager->m_matchingContext, eventKey, (void *)(manager->cRoomMemberDataInternalUpdate), SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberDataInternalUpdateInfo); 3186 if( ( data ) && (!manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL2) ) ) 3187 { 3188 // gotEventData = true; 3189 SceNpMatching2RoomMemberDataInternalUpdateInfo *pRoomMemberData = (SceNpMatching2RoomMemberDataInternalUpdateInfo *)(data); 3190 assert( pRoomMemberData->newRoomMemberBinAttrInternalNum == 1 ); 3191 3192 int playerMask = *((int *)(pRoomMemberData->newRoomMemberBinAttrInternal[0]->data.ptr)); 3193 int oldMask = manager->GetOldMask( pRoomMemberData->newRoomMemberDataInternal->memberId ); 3194 int addedMask = manager->GetAddedMask(playerMask, oldMask ); 3195 int removedMask = manager->GetRemovedMask(playerMask, oldMask ); 3196 3197 if( addedMask != 0 ) 3198 { 3199 bool success = manager->AddRemotePlayersAndSync( pRoomMemberData->newRoomMemberDataInternal->memberId, addedMask ); 3200 if( success ) 3201 { 3202 success = manager->CreateRudpConnections(manager->m_room, pRoomMemberData->newRoomMemberDataInternal->memberId, addedMask, pRoomMemberData->newRoomMemberDataInternal->memberId); 3203 } 3204 if( ( !success ) || (manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL3) ) ) 3205 { 3206 // Failed for some reason - signal back to the client that this is the case, by updating its internal data back again, rather than have 3207 // it wait for a timeout on its rudp connection initialisation. 3208 SceNpMatching2SetRoomMemberDataInternalRequest reqParam; 3209 SceNpMatching2BinAttr binAttr; 3210 3211 memset(&reqParam, 0, sizeof(reqParam)); 3212 memset(&binAttr, 0, sizeof(binAttr)); 3213 3214 binAttr.id = SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID; 3215 binAttr.ptr = &oldMask; 3216 binAttr.size = sizeof(oldMask); 3217 3218 reqParam.roomId = manager->m_room; 3219 reqParam.memberId = pRoomMemberData->newRoomMemberDataInternal->memberId; 3220 reqParam.roomMemberBinAttrInternalNum = 1; 3221 reqParam.roomMemberBinAttrInternal = &binAttr; 3222 3223 int ret = sceNpMatching2SetRoomMemberDataInternal( manager->m_matchingContext, &reqParam, NULL, &manager->m_setRoomMemberInternalDataRequestId ); 3224 } 3225 else 3226 { 3227 success = manager->CreateVoiceRudpConnections( manager->m_room, pRoomMemberData->newRoomMemberDataInternal->memberId, 0); 3228 assert(success); 3229 } 3230 3231 } 3232 3233 if( removedMask != 0 ) 3234 { 3235 manager->RemoveRemotePlayersAndSync( pRoomMemberData->newRoomMemberDataInternal->memberId, removedMask ); 3236 } 3237 3238 break; 3239 } 3240 } 3241 else 3242 { 3243 // If, as a client, we receive an updated room member data this could be for two reason. 3244 // (1) Another client in the game has updated their own data as someone has joined/left the session 3245 // (2) The server has set someone's data back, due to a failed attempt to join a game 3246 // We're only interested in scenario (2), when the data that has been updated is our own, in which case we know to abandon creating rudp connections etc. for a new player 3247 // assert( dataSize <= SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberDataInternalUpdateInfo ); 3248 // int ret = sceNpMatching2GetEventData(manager->m_matchingContext, eventKey, (void *)(manager->cRoomMemberDataInternalUpdate), SCE_NP_MATCHING2_EVENT_DATA_MAX_SIZE_RoomMemberDataInternalUpdateInfo); 3249 if( ( data ) && (!manager->ForceErrorPoint(SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL4) ) ) 3250 { 3251 // gotEventData = true; 3252 SceNpMatching2RoomMemberDataInternalUpdateInfo *pRoomMemberData = (SceNpMatching2RoomMemberDataInternalUpdateInfo *)(data); 3253 assert( pRoomMemberData->newRoomMemberBinAttrInternalNum == 1 ); 3254 if( pRoomMemberData->newRoomMemberDataInternal->memberId == manager->m_localMemberId ) 3255 { 3256 int playerMask = *((int *)(pRoomMemberData->newRoomMemberBinAttrInternal[0]->data.ptr)); 3257 if( playerMask != manager->m_localPlayerJoinMask ) 3258 { 3259 int playersToRemove = manager->m_localPlayerJoinMask & (~playerMask); 3260 manager->RemoveNetworkPlayers( playersToRemove ); 3261 if( manager->m_listener ) 3262 { 3263 for( int i = 0; i < MAX_LOCAL_PLAYER_COUNT; i++ ) 3264 { 3265 if( playersToRemove & ( 1 << i ) ) 3266 { 3267 manager->m_listener->HandleAddLocalPlayerFailed(i); 3268 break; 3269 } 3270 } 3271 } 3272 } 3273 } 3274 } 3275 3276 } 3277 } 3278 break; 3279 case SCE_NP_MATCHING2_ROOM_EVENT_UPDATED_SIGNALING_OPT_PARAM: 3280 break; 3281 }; 3282 3283 // // If we didn't get the event data, then we need to clear it, or the system even queue will overflow 3284 // if( !gotEventData ) 3285 // { 3286 // sceNpMatching2ClearEventData(manager->m_matchingContext, eventKey); 3287 // } 3288} 3289 3290// This is an implementation of SceNpMatching2SignalingCallback. We configure our too automatically create a star network of connections with the host at the hub, and can respond here to 3291// the connections being set up to layer sockets and Rudp on top. 3292void SQRNetworkManager_Vita::SignallingCallback(SceNpMatching2ContextId ctxId, SceNpMatching2RoomId roomId, SceNpMatching2RoomMemberId peerMemberId, SceNpMatching2Event event, int error_code, void *arg) 3293{ 3294 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3295 3296 switch( event ) 3297 { 3298 case SCE_NP_MATCHING2_SIGNALING_EVENT_DEAD: 3299 { 3300 if( manager->m_isHosting ) 3301 { 3302 // Remove any players associated with this peer 3303 manager->RemoveRemotePlayersAndSync( peerMemberId, 15 ); 3304 } 3305 else 3306 { 3307 SQRVoiceConnection* pVoice = SonyVoiceChat_Vita::getVoiceConnectionFromRoomMemberID(peerMemberId); 3308 if(pVoice) 3309 { 3310 SonyVoiceChat_Vita::disconnectRemoteConnection(pVoice); 3311 } 3312 if(peerMemberId == manager->m_hostMemberId || pVoice == NULL) // MGH - added check for voice, as we sometime get here before m_hostMemberId has been filled in 3313 { 3314 // Host has left the game... so its all over for this client too. Finish everything up now, including deleting the server context which belongs to this gaming session 3315 // This also might be a response to a request to leave the game from our end too so don't need to do anything in that case 3316 if( manager->m_state != SNM_INT_STATE_LEAVING ) 3317 { 3318 manager->DeleteServerContext(); 3319 manager->ResetToIdle(); 3320 } 3321 } 3322 } 3323 } 3324 case SCE_NP_MATCHING2_SIGNALING_EVENT_ESTABLISHED: 3325 { 3326 3327 // MGH - changed this to always get the data now, as we need to know if the connecting peer is the host or not 3328 // If we're the host, then we need to get the data associated with the connecting peer to know what connections we should be trying to match. So 3329 // the actual creation of connections happens when the response for this request is processed. 3330 3331 SceNpMatching2GetRoomMemberDataInternalRequest reqParam; 3332 memset( &reqParam, 0, sizeof(reqParam)); 3333 reqParam.roomId = roomId; 3334 reqParam.memberId = peerMemberId; 3335 SceNpMatching2AttributeId attrs[1] = {SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID}; 3336 reqParam.attrId = attrs; 3337 reqParam.attrIdNum = 1; 3338 3339 sceNpMatching2GetRoomMemberDataInternal( manager->m_matchingContext, &reqParam, NULL, &manager->m_roomMemberDataRequestId); 3340 } 3341 break; 3342 } 3343} 3344 3345 3346// Implementation of SceNpBasicEventHandler 3347int SQRNetworkManager_Vita::BasicEventCallback(int event, int retCode, uint32_t reqId, void *arg) 3348{ 3349 PSVITA_STUBBED; 3350 // SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3351 // // We aren't allowed to actually get the event directly from this callback, so send our own internal event to a thread dedicated to doing this 3352 // sceKernelTriggerUserEvent(m_basicEventQueue, sc_UserEventHandle, NULL); 3353 3354 return 0; 3355} 3356 3357// Implementation of SceNpManagerCallback 3358void SQRNetworkManager_Vita::OnlineCheck() 3359{ 3360 static bool s_bFullVersion = ProfileManager.IsFullVersion(); 3361 if(s_bFullVersion != ProfileManager.IsFullVersion()) 3362 { 3363 s_bFullVersion = ProfileManager.IsFullVersion(); 3364 // we've switched from trial to full version here, if we're already online, call InitialiseAfterOnline, as this is now returns immediately in trial mode (devtrack #5921) 3365 if(GetOnlineStatus() == true) 3366 { 3367 InitialiseAfterOnline(); 3368 } 3369 } 3370 3371 bool bSignedIn = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()); 3372 if(GetOnlineStatus() == false) 3373 { 3374 if(bSignedIn) 3375 { 3376 SceNpServiceState serviceState; 3377 int retVal = sceNpGetServiceState(&serviceState); 3378 assert(retVal == 0); 3379 assert(serviceState == SCE_NP_SERVICE_STATE_ONLINE); 3380 InitialiseAfterOnline(); 3381 } 3382 } 3383 else 3384 { 3385 if(bSignedIn == false) 3386 m_listener->HandleDisconnect(false); 3387 } 3388 UpdateOnlineStatus(bSignedIn); 3389} 3390 3391// Implementation of CellSysutilCallback 3392void SQRNetworkManager_Vita::SysUtilCallback(uint64_t status, uint64_t param, void *userdata) 3393{ 3394 // SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)userdata; 3395 // struct CellNetCtlNetStartDialogResult netstart_result; 3396 // int ret = 0; 3397 // netstart_result.size = sizeof(netstart_result); 3398 // switch(status) 3399 // { 3400 // case CELL_SYSUTIL_NET_CTL_NETSTART_FINISHED: 3401 // ret = cellNetCtlNetStartDialogUnloadAsync(&netstart_result); 3402 // if(ret < 0) 3403 // { 3404 // manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 3405 // if( s_SignInCompleteCallbackFn ) 3406 // { 3407 // if( s_signInCompleteCallbackIfFailed ) 3408 // { 3409 // s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 3410 // } 3411 // s_SignInCompleteCallbackFn = NULL; 3412 // } 3413 // return; 3414 // } 3415 // 3416 // if( netstart_result.result != 0 ) 3417 // { 3418 // // Failed, or user may have decided not to sign in - maybe need to differentiate here 3419 // manager->SetState(SNM_INT_STATE_INITIALISE_FAILED); 3420 // if( s_SignInCompleteCallbackFn ) 3421 // { 3422 // if( s_signInCompleteCallbackIfFailed ) 3423 // { 3424 // s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 3425 // } 3426 // s_SignInCompleteCallbackFn = NULL; 3427 // } 3428 // } 3429 // 3430 // break; 3431 // case CELL_SYSUTIL_NET_CTL_NETSTART_UNLOADED: 3432 // break; 3433 // case CELL_SYSUTIL_NP_INVITATION_SELECTED: 3434 // manager->GetInviteDataAndProcess(SCE_NP_BASIC_SELECTED_INVITATION_DATA); 3435 // break; 3436 // default: 3437 // break; 3438 // } 3439} 3440 3441 3442void SQRNetworkManager_Vita::updateNetCheckDialog() 3443{ 3444 if(ProfileManager.IsSystemUIDisplayed()) 3445 { 3446 if( sceNetCheckDialogGetStatus() == SCE_COMMON_DIALOG_STATUS_FINISHED ) 3447 { 3448 //Check for errors 3449 SceNetCheckDialogResult netCheckResult; 3450 int ret = sceNetCheckDialogGetResult(&netCheckResult); 3451 app.DebugPrintf("NetCheckDialogResult = 0x%x\n", netCheckResult.result); 3452 ret = sceNetCheckDialogTerm(); 3453 app.DebugPrintf("NetCheckDialogTerm ret = 0x%x\n", ret); 3454 ProfileManager.SetSysUIShowing( false ); 3455 3456 bool bConnectedOK = (netCheckResult.result == SCE_COMMON_DIALOG_RESULT_OK); 3457 if(bConnectedOK) 3458 { 3459 SceNetCtlInfo info; 3460 sceNetCtlInetGetInfo(SCE_NET_CTL_INFO_DEVICE, &info); 3461 if(info.device == SCE_NET_CTL_DEVICE_PHONE) // 3G connection, we're not going to allow this 3462 { 3463 app.DebugPrintf("Online with 3G connection!!\n"); 3464 ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_WIFI_REQUIRED_OPERATION, 0 ); 3465 bConnectedOK = false; 3466 } 3467 } 3468 app.DebugPrintf("------------>>>>>>>> sceNetCheckDialog finished\n"); 3469 3470 if( bConnectedOK ) 3471 { 3472 if( s_SignInCompleteCallbackFn ) 3473 { 3474 s_SignInCompleteCallbackFn(s_SignInCompleteParam,true,0); 3475 s_SignInCompleteCallbackFn = NULL; 3476 } 3477 } 3478 else 3479 { 3480 // SCE_COMMON_DIALOG_RESULT_USER_CANCELED 3481 // SCE_COMMON_DIALOG_RESULT_ABORTED 3482 3483 // Failed, or user may have decided not to sign in - maybe need to differentiate here 3484 SetState(SNM_INT_STATE_INITIALISE_FAILED); 3485 if( s_SignInCompleteCallbackFn ) 3486 { 3487 if( s_signInCompleteCallbackIfFailed ) 3488 { 3489 s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 3490 } 3491 s_SignInCompleteCallbackFn = NULL; 3492 } 3493 } 3494 } 3495 } 3496} 3497 3498// Implementation of CellRudpContextEventHandler. This is associate with an Rudp context every time one is created, and can be used to determine the status of each 3499// Rudp connection. We create one context/connection per local player on the non-hosting consoles. 3500void SQRNetworkManager_Vita::RudpContextCallback(int ctx_id, int event_id, int error_code, void *arg) 3501{ 3502 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3503 switch(event_id) 3504 { 3505 case SCE_RUDP_CONTEXT_EVENT_CLOSED: 3506 { 3507 SQRVoiceConnection* pVoice = SonyVoiceChat_Vita::GetVoiceConnectionFromRudpCtx(ctx_id); 3508 if(pVoice) 3509 { 3510 pVoice->m_bConnected = false; 3511 } 3512 else 3513 { 3514 app.DebugPrintf(CMinecraftApp::USER_RR,"RUDP closed - event error 0x%x\n",error_code); 3515 if( !manager->m_isHosting ) 3516 { 3517 if( manager->m_state == SNM_INT_STATE_JOINING_WAITING_FOR_LOCAL_PLAYERS ) 3518 { 3519 manager->LeaveRoom(true); 3520 } 3521 } 3522 } 3523 } 3524 break; 3525 case SCE_RUDP_CONTEXT_EVENT_ESTABLISHED: 3526 { 3527 SQRNetworkPlayer *player = manager->GetPlayerFromRudpCtx(ctx_id); 3528 if( player ) 3529 { 3530 // Flag connection stage as being completed for this player 3531 manager->NetworkPlayerConnectionComplete(player); 3532 } 3533 else 3534 { 3535 SonyVoiceChat_Vita::setConnected(ctx_id); 3536 } 3537 } 3538 break; 3539 case SCE_RUDP_CONTEXT_EVENT_ERROR: 3540 break; 3541 case SCE_RUDP_CONTEXT_EVENT_WRITABLE: 3542 { 3543 SQRNetworkPlayer *player = manager->GetPlayerFromRudpCtx(ctx_id); 3544 // This event signifies that room has opened up in the write buffer, so attempt to send something 3545 if( player ) 3546 { 3547 player->SendMoreInternal(); 3548 } 3549 else 3550 { 3551 SQRVoiceConnection* pVoice = SonyVoiceChat_Vita::GetVoiceConnectionFromRudpCtx(ctx_id); 3552 assert(pVoice); 3553 } 3554 } 3555 break; 3556 case SCE_RUDP_CONTEXT_EVENT_READABLE: 3557 if( manager->m_listener ) 3558 { 3559 SQRVoiceConnection* pVoice = SonyVoiceChat_Vita::GetVoiceConnectionFromRudpCtx(ctx_id); 3560 if(pVoice) 3561 { 3562 pVoice->readRemoteData(); 3563 } 3564 else 3565 { 3566 SQRNetworkPlayer *playerIncomingData = manager->GetPlayerFromRudpCtx( ctx_id ); 3567 unsigned int dataSize = playerIncomingData->GetPacketDataSize(); 3568 // If we're the host, and this player hasn't yet had its small id confirmed, then the first byte sent to us should be this id 3569 if( manager->m_isHosting ) 3570 { 3571 SQRNetworkPlayer *playerFrom = manager->GetPlayerFromRudpCtx( ctx_id ); 3572 if( playerFrom && !playerFrom->HasSmallIdConfirmed() ) 3573 { 3574 if( dataSize >= sizeof(SQRNetworkPlayer::InitSendData) ) 3575 { 3576 SQRNetworkPlayer::InitSendData ISD; 3577 int bytesRead = playerFrom->ReadDataPacket( &ISD, sizeof(SQRNetworkPlayer::InitSendData)); 3578 if( bytesRead == sizeof(SQRNetworkPlayer::InitSendData) ) 3579 { 3580 manager->NetworkPlayerInitialDataReceived(playerFrom, &ISD); 3581 dataSize -= sizeof(SQRNetworkPlayer::InitSendData); 3582 } 3583 else 3584 { 3585 assert(false); 3586 } 3587 } 3588 else 3589 { 3590 assert(false); 3591 } 3592 } 3593 } 3594 3595 if( dataSize > 0 ) 3596 { 3597 unsigned char *data = new unsigned char [ dataSize ]; 3598 int bytesRead = playerIncomingData->ReadDataPacket( data, dataSize ); 3599 if( bytesRead > 0 ) 3600 { 3601 SQRNetworkPlayer *playerFrom, *playerTo; 3602 if( manager->m_isHosting ) 3603 { 3604 // Data always going from a remote player, to the host 3605 playerFrom = manager->GetPlayerFromRudpCtx( ctx_id ); 3606 playerTo = manager->m_aRoomSlotPlayers[0]; 3607 } 3608 else 3609 { 3610 // Data always going from host player, to a local player 3611 playerFrom = manager->m_aRoomSlotPlayers[0]; 3612 playerTo = manager->GetPlayerFromRudpCtx( ctx_id ); 3613 } 3614 if( ( playerFrom != NULL ) && ( playerTo != NULL ) ) 3615 { 3616 manager->m_listener->HandleDataReceived( playerFrom, playerTo, data, bytesRead ); 3617 } 3618 } 3619 delete [] data; 3620 } 3621 } 3622 } 3623 break; 3624 case SCE_RUDP_CONTEXT_EVENT_FLUSHED: 3625 break; 3626 } 3627} 3628 3629// Implementation of CellRudpEventHandler 3630#ifdef __PS3__ 3631int SQRNetworkManager_Vita::RudpEventCallback(int event_id, int soc, uint8_t const *data, size_t datalen, struct sockaddr const *addr, socklen_t addrlen, void *arg) 3632#else 3633int SQRNetworkManager_Vita::RudpEventCallback(int event_id, int soc, uint8_t const *data, size_t datalen, struct SceNetSockaddr const *addr, SceNetSocklen_t addrlen, void *arg) 3634#endif 3635{ 3636 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3637 if( event_id == SCE_RUDP_EVENT_SOCKET_RELEASED ) 3638 { 3639 assert( soc == manager->m_soc ); 3640 sceNetSocketClose(soc); 3641 manager->m_soc = -1; 3642 } 3643 return 0; 3644} 3645 3646void SQRNetworkManager_Vita::NetCtlCallback(int eventType, void *arg) 3647{ 3648 SQRNetworkManager_Vita *manager = (SQRNetworkManager_Vita *)arg; 3649 // Oddly, the disconnect event comes in with a new state of "CELL_NET_CTL_STATE_Connecting"... looks like the event is more important than the state to 3650 // determine what has just happened 3651 if( eventType == SCE_NET_CTL_EVENT_TYPE_DISCONNECTED)// CELL_NET_CTL_EVENT_LINK_DISCONNECTED ) 3652 { 3653 manager->m_bLinkDisconnected = true; 3654 manager->m_listener->HandleDisconnect(false); 3655 } 3656 else //if( event == CELL_NET_CTL_EVENT_ESTABLISH ) 3657 { 3658 manager->m_bLinkDisconnected = false; 3659 } 3660 3661} 3662 3663// Called when the context has been created, and we are intending to create a room. 3664void SQRNetworkManager_Vita::ServerContextValid_CreateRoom() 3665{ 3666 // First find a world 3667 SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_SEARCHING_FOR_WORLD); 3668 3669 SceNpMatching2GetWorldInfoListRequest reqParam; 3670 3671 // Request parameters 3672 memset(&reqParam, 0, sizeof(reqParam)); 3673 reqParam.serverId = m_serverId; 3674 3675 int ret = -1; 3676 if( !ForceErrorPoint(SNM_FORCE_ERROR_GET_WORLD_INFO_LIST) ) 3677 { 3678 app.DebugPrintf("sceNpMatching2GetWorldInfoList\n"); 3679 m_getWorldRequestId=0; 3680 ret = sceNpMatching2GetWorldInfoList( m_matchingContext, &reqParam, NULL, &m_getWorldRequestId); 3681 } 3682 if (ret < 0) 3683 { 3684 SetState(SNM_INT_STATE_HOSTING_CREATE_ROOM_FAILED); 3685 return; 3686 } 3687} 3688 3689// Called when the context has been created, and we are intending to join a pre-existing room. 3690void SQRNetworkManager_Vita::ServerContextValid_JoinRoom() 3691{ 3692 // assert( m_state == SNM_INT_STATE_JOINING_SERVER_SEARCH_CREATING_CONTEXT ); 3693 3694 SetState(SNM_INT_STATE_JOINING_JOIN_ROOM); 3695 3696 // Join the room, passing the local player mask as initial binary data so that the host knows what local players are here 3697 SceNpMatching2JoinRoomRequest reqParam; 3698 SceNpMatching2BinAttr binAttr; 3699 memset(&reqParam, 0, sizeof(reqParam)); 3700 memset(&binAttr, 0, sizeof(binAttr)); 3701 binAttr.id = SCE_NP_MATCHING2_ROOMMEMBER_BIN_ATTR_INTERNAL_1_ID; 3702 binAttr.ptr = &m_localPlayerJoinMask; 3703 binAttr.size = sizeof(m_localPlayerJoinMask); 3704 3705 reqParam.roomId = m_roomToJoin; 3706 reqParam.roomMemberBinAttrInternalNum = 1; 3707 reqParam.roomMemberBinAttrInternal = &binAttr; 3708 3709 int ret = sceNpMatching2JoinRoom( m_matchingContext, &reqParam, NULL, &m_joinRoomRequestId ); 3710 if ( (ret < 0) || ForceErrorPoint(SNM_FORCE_ERROR_JOIN_ROOM) ) 3711 { 3712 if( ret == SCE_NP_MATCHING2_SERVER_ERROR_NAT_TYPE_MISMATCH) 3713 { 3714 app.SetDisconnectReason( DisconnectPacket::eDisconnect_NATMismatch ); 3715 } 3716 SetState(SNM_INT_STATE_JOINING_JOIN_ROOM_FAILED); 3717 } 3718} 3719 3720const SceNpCommunicationId* SQRNetworkManager_Vita::GetSceNpCommsId() 3721{ 3722 return &s_npCommunicationId; 3723} 3724 3725const SceNpCommunicationSignature* SQRNetworkManager_Vita::GetSceNpCommsSig() 3726{ 3727 return &s_npCommunicationSignature; 3728} 3729 3730const SceNpTitleId* SQRNetworkManager_Vita::GetSceNpTitleId() 3731{ 3732 PSVITA_STUBBED; 3733 return NULL; 3734 // return &s_npTitleId; 3735} 3736 3737const SceNpTitleSecret* SQRNetworkManager_Vita::GetSceNpTitleSecret() 3738{ 3739 PSVITA_STUBBED; 3740 return NULL; 3741 // return &s_npTitleSecret; 3742} 3743 3744int SQRNetworkManager_Vita::GetOldMask(SceNpMatching2RoomMemberId memberId) 3745{ 3746 int oldMask = 0; 3747 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 3748 { 3749 if( m_roomSyncData.players[i].m_roomMemberId == memberId ) 3750 { 3751 oldMask |= (1 << m_roomSyncData.players[i].m_localIdx); 3752 } 3753 } 3754 return oldMask; 3755} 3756 3757int SQRNetworkManager_Vita::GetAddedMask(int newMask, int oldMask) 3758{ 3759 return newMask & ~oldMask; 3760} 3761 3762int SQRNetworkManager_Vita::GetRemovedMask(int newMask, int oldMask) 3763{ 3764 return oldMask & ~newMask; 3765} 3766 3767 3768void SQRNetworkManager_Vita::GetExtDataForRoom( SceNpMatching2RoomId roomId, void *extData, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ) 3769{ 3770 static SceNpMatching2GetRoomDataExternalListRequest reqParam; 3771 static SceNpMatching2RoomId aRoomId[1]; 3772 static SceNpMatching2AttributeId attr[1]; 3773 3774 // All parameters will be NULL if this is being called a second time, after creating a new matching context via one of the paths below (using GetMatchingContext). 3775 // NULL parameters therefore basically represents an attempt to retry the last sceNpMatching2GetRoomDataExternalList 3776 if( extData != NULL ) 3777 { 3778 aRoomId[0] = roomId; 3779 attr[0] = SCE_NP_MATCHING2_ROOM_BIN_ATTR_EXTERNAL_1_ID; 3780 3781 memset(&reqParam, 0, sizeof(reqParam)); 3782 reqParam.roomId = aRoomId; 3783 reqParam.roomIdNum = 1; 3784 reqParam.attrIdNum = 1; 3785 reqParam.attrId = attr; 3786 3787 m_FriendSessionUpdatedFn = FriendSessionUpdatedFn; 3788 m_pParamFriendSessionUpdated = pParam; 3789 m_pExtDataToUpdate = extData; 3790 } 3791 3792 // Check there's a valid matching context and possibly recreate here 3793 if( !GetMatchingContext(SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT) ) 3794 { 3795 // No matching context, and failed to try and make one. We're really broken here. 3796 m_FriendSessionUpdatedFn(false, m_pParamFriendSessionUpdated); 3797 return; 3798 } 3799 3800 // Kicked off an asynchronous thing that will create a matching context, and then call this method back again (with NULL params) once done, so we can reattempt. Don't do anything more now. 3801 if( m_state == SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT ) 3802 { 3803 app.DebugPrintf("Having to recreate matching context, setting state to SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT\n"); 3804 return; 3805 } 3806 3807 int ret = sceNpMatching2GetRoomDataExternalList( m_matchingContext, &reqParam, NULL, &m_roomDataExternalListRequestId ); 3808 3809 // If we hadn't properly detected that a matching context was unvailable, we might still get an error indicating that it is from the previous call. Handle similarly, but we need 3810 // to destroy the context first. 3811 if( ret == SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED ) // Also checking for this as a means of simulating the previous error 3812 { 3813 sceNpMatching2DestroyContext(m_matchingContext); 3814 m_matchingContextValid = false; 3815 if( !GetMatchingContext(SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT) ) 3816 { 3817 // No matching context, and failed to try and make one. We're really broken here. 3818 m_FriendSessionUpdatedFn(false, m_pParamFriendSessionUpdated); 3819 return; 3820 }; 3821 // Kicked off an asynchronous thing that will create a matching context, and then call this method back again (with NULL params) once done, so we can reattempt. Don't do anything more now. 3822 if( m_state == SNM_INT_STATE_IDLE_RECREATING_MATCHING_CONTEXT ) 3823 { 3824 return; 3825 } 3826 } 3827 3828 if( ret != 0 ) 3829 { 3830 m_FriendSessionUpdatedFn(false, m_pParamFriendSessionUpdated); 3831 } 3832} 3833 3834 3835#ifdef _CONTENT_PACKAGE 3836bool SQRNetworkManager_Vita::ForceErrorPoint(eSQRForceError error) 3837{ 3838 return false; 3839} 3840#else 3841bool SQRNetworkManager_Vita::aForceError[SNM_FORCE_ERROR_COUNT] = 3842{ 3843 false, // SNM_FORCE_ERROR_NP2_INIT 3844 false, // SNM_FORCE_ERROR_NET_INITIALIZE_NETWORK 3845 false, // SNM_FORCE_ERROR_NET_CTL_INIT 3846 false, // SNM_FORCE_ERROR_RUDP_INIT 3847 false, // SNM_FORCE_ERROR_NET_START_DIALOG 3848 false, // SNM_FORCE_ERROR_MATCHING2_INIT 3849 false, // SNM_FORCE_ERROR_REGISTER_NP_CALLBACK 3850 false, // SNM_FORCE_ERROR_GET_NPID 3851 false, // SNM_FORCE_ERROR_CREATE_MATCHING_CONTEXT 3852 false, // SNM_FORCE_ERROR_REGISTER_CALLBACKS 3853 false, // SNM_FORCE_ERROR_CONTEXT_START_ASYNC 3854 false, // SNM_FORCE_ERROR_SET_EXTERNAL_ROOM_DATA 3855 false, // SNM_FORCE_ERROR_GET_FRIEND_LIST_ENTRY_COUNT 3856 false, // SNM_FORCE_ERROR_GET_FRIEND_LIST_ENTRY 3857 false, // SNM_FORCE_ERROR_GET_USER_INFO_LIST 3858 false, // SNM_FORCE_ERROR_LEAVE_ROOM 3859 false, // SNM_FORCE_ERROR_SET_ROOM_MEMBER_DATA_INTERNAL 3860 false, // SNM_FORCE_ERROR_SET_ROOM_MEMBER_DATA_INTERNAL2 3861 false, // SNM_FORCE_ERROR_CREATE_SERVER_CONTEXT 3862 false, // SNM_FORCE_ERROR_CREATE_JOIN_ROOM 3863 false, // SNM_FORCE_ERROR_GET_SERVER_INFO 3864 false, // SNM_FORCE_ERROR_DELETE_SERVER_CONTEXT 3865 false, // SNM_FORCE_ERROR_SETSOCKOPT_0 3866 false, // SNM_FORCE_ERROR_SETSOCKOPT_1 3867 false, // SNM_FORCE_ERROR_SETSOCKOPT_2 3868 false, // SNM_FORCE_ERROR_SOCK_BIND 3869 false, // SNM_FORCE_ERROR_CREATE_RUDP_CONTEXT 3870 false, // SNM_FORCE_ERROR_RUDP_BIND 3871 false, // SNM_FORCE_ERROR_RUDP_INIT2 3872 false, // SNM_FORCE_ERROR_GET_ROOM_EXTERNAL_DATA 3873 false, // SNM_FORCE_ERROR_GET_SERVER_INFO_DATA 3874 false, // SNM_FORCE_ERROR_GET_WORLD_INFO_DATA 3875 false, // SNM_FORCE_ERROR_GET_CREATE_JOIN_ROOM_DATA 3876 false, // SNM_FORCE_ERROR_GET_USER_INFO_LIST_DATA 3877 false, // SNM_FORCE_ERROR_GET_JOIN_ROOM_DATA 3878 false, // SNM_FORCE_ERROR_GET_ROOM_MEMBER_DATA_INTERNAL 3879 false, // SNM_FORCE_ERROR_GET_ROOM_EXTERNAL_DATA2 3880 false, // SNM_FORCE_ERROR_CREATE_SERVER_CONTEXT_CALLBACK 3881 false, // SNM_FORCE_ERROR_SET_ROOM_DATA_CALLBACK 3882 false, // SNM_FORCE_ERROR_UPDATED_ROOM_DATA 3883 false, // SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL1 3884 false, // SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL2 3885 false, // SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL3 3886 false, // SNM_FORCE_ERROR_UPDATED_ROOM_MEMBER_DATA_INTERNAL4 3887 false, // SNM_FORCE_ERROR_GET_WORLD_INFO_LIST 3888 false, // SNM_FORCE_ERROR_JOIN_ROOM 3889}; 3890 3891bool SQRNetworkManager_Vita::ForceErrorPoint(eSQRForceError err) 3892{ 3893 return aForceError[err]; 3894} 3895#endif 3896 3897void SQRNetworkManager_Vita::AttemptPSNSignIn(int (*SignInCompleteCallbackFn)(void *pParam, bool bContinue, int pad), void *pParam, bool callIfFailed/*=false*/) 3898{ 3899 if(CGameNetworkManager::usingAdhocMode()) 3900 { 3901 SQRNetworkManager_AdHoc_Vita::AttemptPSNSignIn(SignInCompleteCallbackFn, pParam, callIfFailed); 3902 return; 3903 } 3904 s_SignInCompleteCallbackFn = SignInCompleteCallbackFn; 3905 s_signInCompleteCallbackIfFailed = callIfFailed; 3906 s_SignInCompleteParam = pParam; 3907 3908 SceNetCheckDialogParam param; 3909 memset(&param, 0x00, sizeof(param)); 3910 sceNetCheckDialogParamInit(&param); 3911 param.mode = SCE_NETCHECK_DIALOG_MODE_PSN_ONLINE; 3912 param.defaultAgeRestriction = ProfileManager.GetMinimumAge(); 3913 3914 // ------------------------------------------------------------- 3915 // MGH - this code is duplicated in the adhoc manager now too, so any changes will have to be made there too 3916 // ------------------------------------------------------------- 3917 //CD - Only add if EU sku, not SCEA or SCEJ 3918 if( app.GetProductSKU() == e_sku_SCEE ) 3919 { 3920 //CD - Added Country age restrictions 3921 SceNetCheckDialogAgeRestriction restrictions[5]; 3922 memset( restrictions, 0x0, sizeof(SceNetCheckDialogAgeRestriction) * 5 ); 3923 //Germany 3924 restrictions[0].age = ProfileManager.GetGermanyMinimumAge(); 3925 memcpy( restrictions[0].countryCode, "de", 2 ); 3926 //Russia 3927 restrictions[1].age = ProfileManager.GetRussiaMinimumAge(); 3928 memcpy( restrictions[1].countryCode, "ru", 2 ); 3929 //Australia 3930 restrictions[2].age = ProfileManager.GetAustraliaMinimumAge(); 3931 memcpy( restrictions[2].countryCode, "au", 2 ); 3932 //Japan 3933 restrictions[3].age = ProfileManager.GetJapanMinimumAge(); 3934 memcpy( restrictions[3].countryCode, "jp", 2 ); 3935 //Korea 3936 restrictions[4].age = ProfileManager.GetKoreaMinimumAge(); 3937 memcpy( restrictions[4].countryCode, "kr", 2 ); 3938 //Set 3939 param.ageRestriction = restrictions; 3940 param.ageRestrictionCount = 5; 3941 } 3942 3943 memcpy(&param.npCommunicationId.data, &s_npCommunicationId, sizeof(s_npCommunicationId)); 3944 param.npCommunicationId.term = '\0'; 3945 param.npCommunicationId.num = 0; 3946 3947 int ret = sceNetCheckDialogInit(&param); 3948 3949 ProfileManager.SetSysUIShowing( true ); 3950 app.DebugPrintf("------------>>>>>>>> sceNetCheckDialogInit : PSN Mode\n"); 3951 3952 if( ret < 0 ) 3953 { 3954 if(s_SignInCompleteCallbackFn) // MGH - added after crash on PS4 3955 { 3956 if( s_signInCompleteCallbackIfFailed ) 3957 { 3958 s_SignInCompleteCallbackFn(s_SignInCompleteParam,false,0); 3959 } 3960 s_SignInCompleteCallbackFn = NULL; 3961 } 3962 } 3963} 3964 3965int SQRNetworkManager_Vita::SetRichPresence(const void *data) 3966{ 3967 const sce::Toolkit::NP::PresenceDetails *newPresenceInfo = (const sce::Toolkit::NP::PresenceDetails *)data; 3968 3969 s_lastPresenceInfo.status = newPresenceInfo->status; 3970 // s_lastPresenceInfo.userInfo = newPresenceInfo->userInfo; 3971 s_lastPresenceInfo.presenceType = SCE_NP_BASIC_IN_GAME_PRESENCE_TYPE_DEFAULT; 3972 3973 s_presenceStatusDirty = true; 3974 if(s_resendPresenceCountdown == 0) 3975 { 3976 s_resendPresenceCountdown = 5; // wait a few ticks before setting the rich presence value, so if there's a few being set at one time (like on game startup) we can send them all in a single call 3977 } 3978 3979 // Return as if no error happened no matter what, as we'll be resending ourselves if we need to and don't want the calling system to retry 3980 return 0; 3981} 3982 3983void SQRNetworkManager_Vita::UpdateRichPresenceCustomData(void *data, unsigned int dataBytes) 3984{ 3985 assert(dataBytes <= SCE_NP_BASIC_IN_GAME_PRESENCE_DATA_SIZE_MAX ); 3986 memcpy(s_lastPresenceInfo.data, data, dataBytes); 3987 s_lastPresenceInfo.size = dataBytes; 3988 3989 s_presenceStatusDirty = true; 3990 if(s_resendPresenceCountdown == 0) 3991 { 3992 s_resendPresenceCountdown = 5; // wait a few ticks before setting the rich presence value, so if there's a few being set at one time (like on game startup) we can send them all in a single call 3993 } 3994} 3995 3996void SQRNetworkManager_Vita::TickRichPresence() 3997{ 3998 if( s_resendPresenceCountdown ) 3999 { 4000 s_resendPresenceCountdown--; 4001 if( s_resendPresenceCountdown == 0 ) 4002 { 4003 SendLastPresenceInfo(); 4004 } 4005 } 4006} 4007 4008void SQRNetworkManager_Vita::SendLastPresenceInfo() 4009{ 4010 // Don't attempt to send if we are already waiting to resend 4011 if( s_resendPresenceCountdown ) return; 4012 4013 // MGH - On Vita, change this to use SCE_NP_BASIC_IN_GAME_PRESENCE_TYPE_GAME_JOINING at some point 4014 4015 // On PS4 we can't set the status and the data at the same time 4016 if( s_presenceStatusDirty == false) 4017 { 4018 return; // nothing to be done. 4019 } 4020 4021 int err = 0; 4022 // check if we're connected to the PSN first 4023 if(ProfileManager.IsSignedInLive(0))//ProfileManager.getQuadrant(s_lastPresenceInfo.userInfo.userId))) 4024 { 4025 s_lastPresenceInfo.presenceType = SCE_NP_BASIC_IN_GAME_PRESENCE_TYPE_DEFAULT; 4026 // MGH - if we have data being sent, that means we're in an online game, so let others join from our presence info on the XMB 4027 if(s_lastPresenceInfo.size > 0 ) 4028 { 4029 // make sure it's not an invite only game 4030 PresenceSyncInfo *pso = (PresenceSyncInfo *)s_lastPresenceInfo.data; 4031 if(!pso->inviteOnly) 4032 { 4033 s_lastPresenceInfo.presenceType = SCE_NP_BASIC_IN_GAME_PRESENCE_TYPE_GAME_JOINING; 4034 } 4035 } 4036 err = sce::Toolkit::NP::Presence::Interface::setPresence(&s_lastPresenceInfo); 4037 } 4038 4039 if( err != SCE_TOOLKIT_NP_SUCCESS ) 4040 { 4041 s_resendPresenceCountdown = (20 * 65); // Bit over a minute before attempting to resend, we should get a new token every minute 4042 } 4043 else 4044 { 4045 s_presenceStatusDirty = false; 4046 } 4047} 4048 4049void SQRNetworkManager_Vita::SetPresenceFailedCallback() 4050{ 4051 s_presenceStatusDirty = true; 4052 s_resendPresenceCountdown = (20 * 65); // Bit over a minute before attempting to resend, we should get a new token every minute 4053} 4054 4055void SQRNetworkManager_Vita::SetPresenceDataStartHostingGame() 4056{ 4057 if( m_offlineGame ) 4058 { 4059 SQRNetworkManager_Vita::UpdateRichPresenceCustomData(&c_presenceSyncInfoNULL, sizeof(SQRNetworkManager_Vita::PresenceSyncInfo) ); 4060 } 4061 else 4062 { 4063 SQRNetworkManager_Vita::PresenceSyncInfo presenceInfo; 4064 CPlatformNetworkManagerSony::SetSQRPresenceInfoFromExtData( &presenceInfo, m_joinExtData, m_room, m_serverId ); 4065 SQRNetworkManager_Vita::UpdateRichPresenceCustomData(&presenceInfo, sizeof(SQRNetworkManager_Vita::PresenceSyncInfo) ); 4066 // OrbisNPToolkit::createNPSession(); 4067 } 4068} 4069 4070int SQRNetworkManager_Vita::GetJoiningReadyPercentage() 4071{ 4072 if ( (m_state == SNM_INT_STATE_HOSTING_SEARCHING_FOR_SERVER) || (m_state == SNM_INT_STATE_JOINING_SEARCHING_FOR_SERVER) ) 4073 { 4074 int completed = ( m_totalServerCount - m_serverCount ) - 1; 4075 int pc = ( completed * 100 ) / m_totalServerCount; 4076 if( pc < 0 ) pc = 0; 4077 if( pc > 100 ) pc = 100; 4078 return pc; 4079 } 4080 else 4081 { 4082 return 100; 4083 } 4084} 4085 4086void SQRNetworkManager_Vita::removePlayerFromVoiceChat( SQRNetworkPlayer* pPlayer ) 4087{ 4088 if(pPlayer->IsLocal()) 4089 { 4090 SonyVoiceChat_Vita::disconnectLocalPlayer(pPlayer->GetLocalPlayerIndex()); 4091 } 4092 else 4093 { 4094 int numRemotePlayersLeft = 0; 4095 for( int i = 0; i < MAX_ONLINE_PLAYER_COUNT; i++ ) 4096 { 4097 if( m_aRoomSlotPlayers[i] ) 4098 { 4099 if( m_aRoomSlotPlayers[i] != pPlayer ) 4100 { 4101 if(m_aRoomSlotPlayers[i]->m_roomMemberId == pPlayer->m_roomMemberId) 4102 numRemotePlayersLeft++; 4103 } 4104 } 4105 } 4106 if(numRemotePlayersLeft == 0) 4107 { 4108 // no players left on the remote machine once we remove this one 4109 SQRVoiceConnection* pVoice = SonyVoiceChat_Vita::getVoiceConnectionFromRoomMemberID(pPlayer->m_roomMemberId); 4110 if(pVoice) 4111 SonyVoiceChat_Vita::disconnectRemoteConnection(pVoice); 4112 } 4113 } 4114} 4115 4116 4117SQRNetworkPlayer *SQRNetworkManager_Vita::GetPlayerByXuid(PlayerUID xuid) 4118{ 4119 EnterCriticalSection(&m_csRoomSyncData); 4120 for( int i = 0; i < m_roomSyncData.getPlayerCount(); i++ ) 4121 { 4122 if( m_roomSyncData.players[i].m_UID == xuid ) 4123 { 4124 SQRNetworkPlayer *player = GetPlayerIfReady(m_aRoomSlotPlayers[i]); 4125 LeaveCriticalSection(&m_csRoomSyncData); 4126 return player; 4127 } 4128 } 4129 LeaveCriticalSection(&m_csRoomSyncData); 4130 return NULL; 4131} 4132