The joint session feature enables matchmaking among separate sessions. You can use the feature to implement different kinds of gameplay, for example, letting stations form teams and then matching the teams to play together.
The joint session feature is not supported during local communication.
The joint session feature does not support the direct participation in a joint session without participation in one of the original sessions. Stations should join the joint session only after joining a regular session.
This version of the joint session feature only supports the JoinRandomJointSessionAsync() and DestroyJointSessionAsync() functions. The CreateJointSessionAsync(), JoinJointSessionAsync(), and LeaveJointSessionAsync() functions are not yet available with this feature.
The following terms are used when describing the joint session feature.
Glossary | Description |
---|---|
Joint Session | A conjoined session created from matchmaking among two or more separate sessions. |
Joint Session Host |
The station that has administrator privileges for the joint session. Normally, this station also serves as a session host. |
For a sample implementation of team matchmaking, see the clone/TeamMatchmake sample demo.
Figure 6-10. Joint Session Feature State Transitions shows the state transitions for the asynchronous processing of the joint session feature.
At the top, the stations are not joined in any sessions.
In the middle, the stations have joined into regular sessions.
At the bottom, the matchmaking among sessions has completed, and a joint session has been created. The stations now all participate in a giant joint session, but information is retained about the regular session to which each station belongs.
When it is time for stations to leave the joint session, they can revert back to the state of participation in their regular sessions, or they can leave both the joint session and the regular session in a single process.
The connection information (such as NAT traversal results) among all the stations participating in the same session is saved when that session is joined into a joint session and when that session leaves from the joint session, which helps ensure that the migrations complete quickly and efficiently. For example, when the stations migrate from the middle level to the lower level in the figure, stations A0 and A1 (or stations B0 and B1) save each other's connection information, allowing the connection process between the two stations to be quickly completed.
Certain API functions cannot be used during the processes of joining and creating joint sessions and leaving from joint sessions. They include the APIs involved in sending and receiving, and the APIs that take as parameters the station ID and the station index. There is no support for operations when any of these APIs is called during the prohibited period.
This limitation applies to the following API functions. (A list is now being prepared that will include additional APIs.)
The application can use the following methods to determine whether it is a time when sessions are migrating and the API functions cannot be used.
The values for the station indexes corresponding to the station IDs are changed in the process to join or create a joint session and the process to leave a joint session (although in some cases the values remain the same). For a detailed description of the correspondence between station IDs and station indexes, see 1.7. Station IDs.
The following figure shows an example of station IDs and station indexes when a joint session is disbanded. For this example, Session B has joined a joint session created by Session A.
The unique ID for each station's station ID is unique and will not change before or after the joining and disbanding of joint sessions. On the other hand, the station indexes that you can convert to from station IDs are unique only within the separate regular sessions, and they are reassigned upon migration to the joint session. The station index values change for both the Session A stations and the Session B stations (although in some cases they remain the same).
You must handle this situation when using the joint session feature, for example, by using a conversion table that associates station IDs with array indexes for managing game objects for each station in an array (or by preparing a two-dimensional array that divides the arrays by session). For more information, see the clone/TeamMatchmake sample demo.
There are no settings specific to the joint session feature, but for the PiaTransport setting for the maximum number of participating stations, set the maximum number of stations that can be joined together in the joint session (the maximum number of participants when communicating among matched sessions).
Sessions are joined as usual. The search conditions specified with parameters and the settings for creating a session are set for use by the team (not for use by the joint session). For example, for the maximum number of participants, set the number of people on the team.
Set different matchmaking conditions for regular sessions and joint sessions. When changing the settings for regular sessions and joint sessions to distinguish them, use different values for things like the game mode (NexCreateSessionSetting::SetGameMode()).
This version of the joint session feature supports JoinRandomJointSessionAsync(), but does not yet support CreateJointSessionAsync() or JoinJointSessionAsync().
The way to start the asynchronous process to join a joint session is for the session host to call the API for creating and joining joint sessions. The parameter-specified search conditions and session-creation settings are used as the settings for the joint session. The session join invitation is closed during the asynchronous process. The session closes the join-in invitation when the asynchronous process ends regardless of whether the process succeeds. The application can change the join-in invitation state after the asynchronous process ends by calling OpenParticipationAsync(). Call the function as needed.
If random matchmaking is used, have the local station use the Session::IsJointSessionHost() function to check whether it has become the host after joining the joint session.
If the local station is a client, its process of joining the joint session is run automatically when the session host acts to create or join a joint session. Have clients use state change event notifications or the Session::GetStatus() function to check on the progress of joining the joint session.
// Set the session to create.
// We recommend using the GameMode value to distinguish regular sessions from joint sessions. nn::pia::inet::NexCreateSessionSetting createSessionSettingForJoint; createSessionSettingForJoint.SetGameMode(MATCHMAKE_GAME_MODE_GAME); // Game mode value for the joint session. createSessionSettingForJoint.SetMaxParticipants(SAMPLE_GAME_PLAYER_MAX); // Setting for maximum participants after sessions are joined together. createSessionSettingForJoint.SetAttribute(MATCHMAKE_ATTR_INDEX, MATCHMAKE_ATTR_VAL_GAME); // Joint session attributes. // Set the search criteria. const size_t cSearchCriteriaNum = 1; // You can set a maximum of two search criteria for random matchmaking. nn::pia::inet::NexSessionSearchCriteria nexSearchCriteriaArray[cSearchCriteriaNum ]; nexSearchCriteriaArray[0].SetGameMode(MATCHMAKE_GAME_MODE_GAME); // Game mode value for the joint session. nexSearchCriteriaArray[0].SetMaxParticipants(SAMPLE_GAME_PLAYER_MAX); // Setting for maximum participants after sessions are joined together. nexSearchCriteriaArray[0].SetAttribute(MATCHMAKE_ATTR_INDEX, MATCHMAKE_ATTR_VAL_GAME); // Joint session attributes. // Start the asynchronous process for joint session random matchmaking. nn::Result result = nn::pia::session::Session::GetInstance()->JoinRandomJointSessionAsync( &createSessionSettingForJoint, nexSearchCriteriaArray, cSearchCriteriaNum); if (result.IsFailure()) { // Error handling. // Does not fail as long as the session host calls it at the appropriate time. } // When the asynchronous process starts successfully, you must periodically call the Dispatch function to wait on the progress of the asynchronous process. while (nn::pia::session::Session::GetInstance()->IsCompletedJoinRandomJointSession() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // You must call the Scheduler::Dispatch function of NEX for keep-alive communication with the server. nn::nex::Scheduler::GetInstance()->DispatchAll(); } // Check the results of the asynchronous process. result = nn::pia::session::Session::GetInstance()->GetJoinRandomJointSessionResult(); if (result.IsFailure()) { // Error handling. } // When the asynchronous process succeeds, check whether you are the joint session host. This allows you to check whether // you have joined an existing joint session, and have joined with a different team, or // you have created a new joint session and are waiting for a different team. if (nn::pia::session::Session::GetInstance()->IsJointSessionHost()) { // The local station is the joint session host. (In other words, a new joint session was created.) } else { // The local station is not the host. (In other words, an existing joint session has been joined.) } |
// Assume this is a loop for periodic communication processes.
while( loopFlag ) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // You must call the Scheduler::Dispatch function of NEX for keep-alive communication with the server. nn::nex::Scheduler::GetInstance()->DispatchAll(); // Periodic session status check. nn::pia::session::Session::Status sessionStatus = nn::pia::session::Session::GetInstance()->GetStatus(); if (sessionStatus == nn::pia::session::Session::STATUS_DISCONNECTED_SESSION || sessionStatus == nn::pia::session::Session::STATUS_DISCONNECTED_NETWORK) { // Error occurred in communication status. // Error handling. } else if (sessionStatus == nn::pia::session::Session::STATUS_CONNECTED_SESSION) { // Participating in a regular session. } else if (sessionStatus == nn::pia::session::Session::STATUS_MIGRATING_SESSION) { // Migrating from a regular session to a joint session. // If the session host has started the process of creating or joining a joint session, the client automatically enters this state. // Sending and receiving processes are impossible with this status. } else if (sessionStatus == nn::pia::session::Session::STATUS_CONNECTED_JOINT_SESSION) { // Participating in a joint session. } } |
You cannot add a new participant to the session while participating in a joint session. Add the new participant after leaving the joint session. If a device uses the JoinSessionAsync() function in the regular way to attempt to join a session that happens to be participating in a joint session, that device will fail to join the session.
When the joint session host in a joint session calls the DestroyJointSessionAsync() function, that joint session gets disbanded. The hosts of the regular sessions participating in this joint session all leave the joint session, together with the clients participating in their sessions, and all revert to the state of participation in their regular sessions. DestroyJointSessionAsync() fails if called by any station other than the joint session host.
Closes the invitation for joining the joint session and session during the asynchronous process for disbanding a joint session. The session closes the join-in invitation when the asynchronous process ends regardless of whether the process succeeds. The application can change the join-in invitation state after the asynchronous process ends by calling OpenParticipationAsync(). Call the function as needed.
To check on the progress of the transition from the joint session by any station that is not the joint session host, use the state change event notifications or the Session::GetStatus() function.
// Starts the asynchronous process to disband the joint session.
nn::Result result = nn::pia::session::Session::GetInstance()->DestroyJointSessionAsync(); if (result.IsFailure()) { // Error handling // Does not fail, as long as the joint session host calls it at the correct time. } // When the asynchronous process starts successfully, you must periodically call the dispatch function to wait on the progress of the asynchronous process. while (nn::pia::session::Session::GetInstance()->IsCompletedDestroyJointSession() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // You must call the Scheduler::Dispatch function of NEX for keep-alive communication with the server. nn::nex::Scheduler::GetInstance()->DispatchAll(); } // Confirm the results of the asynchronous process. result = nn::pia::session::Session::GetInstance()->GetDestroyJointSessionResult(); if (result.IsFailure()) { // Error handling. } // If the asynchronous process succeeds, the joint session is disbanded and the individual participating sessions are separated. |
The LeaveJointSessionAsync() function has not been prepared yet for this version of the feature.
When the host of a session participating in the joint session calls the LeaveJointSessionAsync() function, the session it is hosting leaves from the joint session. Automatically, the client stations in that same session also begin the process of leaving the joint session. The LeaveJointSessionAsync() function fails if it is called by a client station.
Clients check on the progress of the transition from the joint session using the state change event notifications or the Session::GetStatus() function.
If host migration is disabled and the joint session host calls the LeaveJointSessionAsync() function, all participating stations leave the joint session and return to participating in their regular sessions. Using the example from Figure 6-10. Joint Session Feature State Transitions , if A0 calls LeaveJointSessionAsync() in the bottom-level state, all participating stations (A0, A1, B0, and B1) leave the joint session and transition to the middle-level state.
If host migration is enabled and the joint session host calls the LeaveJointSessionAsync() function, host migration of the joint session host takes place and the joint session continues to persist. Using the example from Figure 6-10. Joint Session Feature State Transitions , if A0 calls LeaveJointSessionAsync() in the bottom-level state, A0 and A1 leave the joint session and transition to the middle-level state, but B0 and B1 continue to communicate in the bottom-level state. Host migration at this time makes B0 the joint session host.
If a session host that is not the joint session host calls the LeaveJointSessionAsync() function, all stations in the session it is hosting leave the joint session, but the joint session continues. Using the example from Figure 6-10. Joint Session Feature State Transitions , if B0 calls LeaveJointSessionAsync() in the bottom-level state, B0 and B1 leave the joint session and transition to the middle-level state, but A0 and A1 continue to communicate in the bottom-level state.
// Start the asynchronous process of transitioning from a joint session to a regular session.
nn::Result result = nn::pia::session::Session::GetInstance()->LeaveJointSessionAsync(); if (result.IsFailure()) { // Error handling. // Does not fail as long as the session host calls it at the correct time. } // When the asynchronous process starts successfully, you must periodically call the dispatch function to wait on the progress of the asynchronous process. while (nn::pia::session::Session::GetInstance()->IsCompletedLeaveJointSession() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // You must call the Scheduler::Dispatch function of NEX for keep-alive communication with the server. nn::nex::Scheduler::GetInstance()->DispatchAll(); } // Confirm the results of the asynchronous process. result = nn::pia::session::Session::GetInstance()->GetLeaveJointSessionResult(); if (result.IsFailure()) { // Error handling. } // If the asynchronous process succeeds, the stations leave the joint session and now become participants in the regular session. |
To leave both the joint session and the original, regular session in one process, call LeaveSessionAsync.
When a client calls LeaveSessionAsync, it leaves both the joint session and the original, regular session, but the other stations remain communicating in the joint session. Using the example from Figure 6-10. Joint Session Feature State Transitions, if A1 calls LeaveSessionAsync in the bottom-level state, it ends communications and transitions to the top-level state, but A0, B0, and B1 continue to communicate in the bottom-level state.
If host migration is disabled and the joint session host calls LeaveSessionAsync, all other participating stations also leave the joint session in addition to their regular sessions. Using the example from Figure 6-10. Joint Session Feature State Transitions, if A0 calls LeaveSessionAsync in the bottom-level state, all participating stations (A0, A1, B0, and B1) leave and transition to the top-level state.
If host migration is disabled and a session host that is not the joint session host calls LeaveSessionAsync, all stations participating in that host's session leave that session, but the joint session continues to persist. Using the example from Figure 6-10. Joint Session Feature State Transitions, if B0 calls LeaveSessionAsync in the bottom-level state, B0 and B1 leave and transition to the top-level state, but A0 and A1 continue to communicate in the bottom-level state.
If host migration is enabled and the joint session host or regular session host calls LeaveSessionAsync, the station that called this function leaves from both the joint session and its regular session and ends communications, but host migration takes place for both the joint session and the regular session, and both continue to persist. Using the example from Figure 6-10. Joint Session Feature State Transitions, if A0 calls LeaveSessionAsync in the bottom-level state, it leaves the sessions and transitions to the top-level state, but A1, B0, and B1 continue to communicate in the bottom-level state. At this time, the host migration process makes A1 the host of both Session A and the joint session.
// Start the asynchronous process of leaving from the joint session.
nn::Result result = nn::pia::session::Session::GetInstance()->LeaveSessionAsync(); if ( result.IsFailure() ) { // Error handling. // Does not fail as long as it is called at the correct time. } // When the asynchronous process starts successfully, you must periodically call the dispatch function to wait on the progress of the asynchronous process. while( nn::pia::session::Session::GetInstance()->IsCompletedLeaveSession() == false ) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // You must call the Scheduler::Dispatch function of NEX for keep-alive communication with the server. nn::nex::Scheduler::GetInstance()->DispatchAll(); } // Confirm the results of the asynchronous process. result = nn::pia::session::Session::GetInstance()->GetLeaveSessionResult(); if ( result.IsFailure() ) { // Error handling. } // If the asynchronous process succeeds, the joint session is disbanded and the individual participating sessions are separated. // Depending on the role of the station that called LeaveSessionAsync, other stations might also end their communications. |
To leave from the session, the session API is called in the usual way.
To change the invitation state of the joint session, you can use either OpenJointSessionAsync and CloseJointSessionAsync or OpenJointSessionParticipationAsync and CloseJointSessionParticipationAsync.
Use these functions in the same way described in 6.7. Basic Features - Changing the Session Invitation State.
When the joint session feature is used by sessions to join and leave from a joint session, events that notify the start and end of processes are generated.
The following notifying events are triggered for processes related to the joint session feature.
Change of the joint session host.
The StationId sent with these event notifications is always STATION_ID_INVALID.
// Example of the state change event callback function when using the joint session feature.
void sampleSessionEventCallback(nn::pia::session::Session::EventType eventType, nn::pia::StationId id) { switch (eventType) { case nn::pia::session::Session::EVENT_JOIN: // The station joined a session. break; case nn::pia::session::Session::EVENT_LEAVE: // The station left a session. break; case nn::pia::session::Session::EVENT_START_SESSION_CREATE_JOINT: // The start of the processes to create a joint session and migrate the session. break; case nn::pia::session::Session::EVENT_END_SESSION_CREATE_JOINT: // The end of the processes to create a joint session and migrate the session. break; case nn::pia::session::Session::EVENT_START_SESSION_JOIN_JOINT: // The start of the processes to join in a joint session and migrate the session. break; case nn::pia::session::Session::EVENT_END_SESSION_JOIN_JOINT: // The end of the processes to create a joint session and migrate the session. break; case nn::pia::session::Session::EVENT_START_SESSION_JOINT_RANDOM: // The start of the processes to join in a joint session using random matchmaking and migrate the session. break; case nn::pia::session::Session::EVENT_END_SESSION_JOINT_RANDOM: // The end of the processes to join in a joint session using random matchmaking and migrate the session. break; case nn::pia::session::Session::EVENT_START_SESSION_DESTROY_JOINT: // The start of the process to disband the joint session and revert back to the original session. break; case nn::pia::session::Session::EVENT_END_SESSION_DESTROY_JOINT: // The end of the process to disband the joint session and revert back to the original session. break; case nn::pia::session::Session::EVENT_START_SESSION_LEAVE_JOINT: // The start of the process to leave the joint session and revert back to the original session. break; case nn::pia::session::Session::EVENT_END_SESSION_LEAVE_JOINT: // The end of the process to leave the joint session and revert back to the original session. break; case nn::pia::session::Session::EVENT_SESSION_MIGRATION_FAILED: // Migration between the original session and the joint session has failed. break; case nn::pia::session::Session::EVENT_JOINT_SESSION_HOST_CHANGED: // When, due to host migration, the station with the specified ID becomes the new joint session host. break; } } |