Matchmaking is a multiplayer introduction feature that finds partners on the Internet for a user to play with.
With NEX, a group of users is called a gathering, and a gathering of users that are playing together or cooperating with each other through matchmaking is called a matchmaking session. This concept is independent of a P2P session.
During matchmaking, you can search for and join matchmaking sessions that match conditions specified by the application. For example, you can search for matchmaking sessions created by a friend or search for matchmaking sessions that have attribute values that the application has independently specified. You can also search for matchmaking sessions by specifying a partner.
Depending on the application, a single user can create and join multiple matchmaking sessions. For example, you could use one matchmaking session to manage P2P communications, another matchmaking session to manage teams, and yet another matchmaking session for messaging between friends. For more information about using matchmaking sessions to manage teams, see 4.10 Joining Multiple Users at the Same Time to a Matchmaking Session.
With NEX, the owner of the matchmaking session is called the owner, and the representative terminal that is receiving participation from other terminals with P2P communication is called the host.
To group users on a broader basis than a single matchmaking session, use a persistent gathering (4.18). With matchmaking sessions, users automatically leave the session when they log out from the server. With persistent gatherings, however, you can keep users grouped in the gathering even if they log out.
Matchmaking includes support for PUSH event notifications through the game server, instant messaging, and a feature for impartially recording match results.
The following steps show the overall flow of the matchmaking process.
NEX communicates with game servers through service client APIs that support the services provided by the game servers, such as matchmaking, rankings, and instant messaging. To initialize each of the service clients, you must set a pointer to a valid Credential
object in the ServiceClient::Bind
function. The following three classes derived from ServiceClient
are the service clients used for matchmaking.
MatchmakeExtensionClient
: Registers, searches for, joins, and handles other similar operations for matchmaking sessions.NATTraversalClient
: Performs NAT traversal. This class is automatically used within the library except during initialization and shutdown.MessagingClient
: Sends and receives instant messages. This class is not needed if instant messaging is not used.Use the NgsFacade::GetCredentials
function to get the Credentials
object after you log in to the game server. Before you log out from the game server, call the ServiceClient::Unbind
function to release the Credentials
object that was set, and then destroy the ServiceClient
object. For more information, see Code 4.1..
Code 4.1. Initializing and Finalizing a Service Client
// Log in to the game server.
LoginGameServer(pNgsFacade);
Credentials* pCredentials = pNgsFacade->GetCredentials();
// Create a ServiceClient instance for each login attempt.
MatchmakeExtensionClient* pClient = qNew MatchmakeExtensionClient();
pClient->Bind(pCredentials);
// Do the processing.
pClient->DoSomething();
// Unbind and destroy the object before logging out.
pClient->Unbind();
qDelete pClient;
// Log out.
LogoutGameServer(pNgsFacade);
Use the MatchmakeExtensionClient::CreateMatchmakeSession
function to register a matchmaking session on a game server (Code 4.2 Example of Configuring and Registering a Matchmaking Session). The client that calls the CreateMatchmakeSession
function automatically joins the matchmaking session as its owner and P2P communication host. The terminal that is not the matchmaking session owner must call the MatchMakingClient::UpdateSessionHost
to become the P2P communication host.
This function takes the following arguments: a pointer to a ProtocolCallContext
object, a GatheringHolder
object that stores a MatchmakeSession
object, a pointer to the gathering ID set when asynchronous processing is completed, a pointer to a common key for P2P communication, and up to 256 characters of detailed information such as the name of the client and the character used.
After you have finished registering a matchmaking session, create a P2P session and wait for other participants to join it. For more information, see 8. Peer-to-Peer Communication.
Comments
The destructor for the GatheringHolder
class deletes the object that it maintains, just as with std::auto_ptr
. For this reason, explicitly call the GatheringHolder::Release
function to reuse the MatchmakeSession
object stored in a GatheringHolder
object.
Code 4.2 Example of Configuring and Registering a Matchmaking Session
static const qUnsignedInt32 s_gameMode = 1;
static const qUnsignedInt16 s_MaxParticipations = 10;
MatchmakeExtensionClient matchmakeClient;
void ExecuteCreateMatchmakeSession()
{
// Set the conditions for the matchmaking session.
MatchmakeSession* pMatchmakeSession = qNew MatchmakeSession();
pMatchmakeSession->SetGameMode(s_gameMode);
pMatchmakeSession->SetAttribute(1, 3);
pMatchmakeSession->SetMatchmakeSystemType(MATCHMAKE_SYSTEM_TYPE_ANYBODY);
pMatchmakeSession->SetMaxParticipants(s_MaxParticipations);
pMatchmakeSession->SetFlag(GatheringFlags::MigrateOwner);
qVector<qUnsignedInt8> applicationBuffer;
applicationBuffer.push_back(1);
pMatchmakeSession->SetApplicationBuffer(applicationBuffer);
pMatchmakeSession->SetDescription(_T("Description"));
pMatchmakeSession->SetOpenParticipation(false);
// Set the MatchmakeSession in the GatheringHolder.
GatheringHolder oGatheringHolder = pMatchmakeSession;
ProtocolCallContext oContext;
GatheringID gatheringID = INVALID_GATHERINGID;
// Common key for P2P communication.
qVector<qByte> sessionKey;
// Register a matchmaking session with the server, and join a session.
if (!matchmakeClient.CreateMatchmakeSession(&oContext, oGatheringHolder, &gatheringID, &sessionKey, _T("create matchmake session")))
{
// Error processing.
return;
}
// Wait for the asynchronous processing result.
oContext.Wait();
if (oContext.GetState()!=CallContext::CallSuccess)
{
// Error processing.
}
}
You can use the following functions to search for a matchmaking session.
Code 4.3 Matchmaking Session Search Functions
// Searching on the specified criteria.
qBool MatchmakeExtensionClient::BrowseMatchmakeSession(
ProtocolCallContext *pContext,
const MatchmakeSessionSearchCriteria& searchCriteria,
const ResultRange& resultRange,
qList<MatchmakeSession>* lstGathering);
// Also, get URLs of the P2P communication hosts that match the specified search conditions.
qBool MatchmakeExtensionClient::BrowseMatchmakeSession(
ProtocolCallContext *pContext,
const MatchmakeSessionSearchCriteria& searchCriteria,
const ResultRange& resultRange,
qList<MatchmakeSession>* lstGathering,
qList<GatheringURLs>* lstGatheringURLs);
// Searching on a matchmaking session ID.
qBool MatchMakingClient::FindByID(ProtocolCallContext *pContext, GatheringID id, GatheringHolder *pGathering);
// Search by the principal ID of the owner.
qBool MatchMakingClient::FindByOwner(ProtocolCallContext *pContext, PrincipalID pidOwner, const ResultRange& resultRange, qList<GatheringHolder> *plstGatherings);
// Searching on the principal IDs of participants.
qBool MatchmakeExtensionClient::GetPlayingSession(ProtocolCallContext *pContext, qList<PrincipalID> lstParticipants, qList<PlayingSession *plstPlayingSession);
The MatchmakeExtensionClient::BrowseMatchmakeSession
function takes the following arguments: a pointer to a ProtocolCallContext
object, a MatchmakeSessionSearchCriteria
class object, a ResultRange
class object, and a pointer to a qList
<MatchmakeSession
> to store the search results. For more information about MatchmakeSessionSearchCriteria
and ResultRange
, see 4.12 Setting the Search Criteria and Range.
When asynchronous processing succeeds, the search results are stored in a qList
<GatheringHolder
>. Although you can call the Get
function on a GatheringHolder
object stored in the list to get a pointer to a Gathering
class object, you can cast to a pointer to the MatchmakeSession
class (Code 4.4).
There is an overloaded MatchmakeExtensionClient::BrowseMatchmakeSession
function that also gets the URL of the matchmaking session's P2P communication host. This function is suited to applications in which the P2P communication host in a single matchmaking session does not change. Conversely, in a single matchmaking session, with applications that anticipate host migration in which the P2P host changes, get the URL of the P2P host with the MatchMakingClient::GetSessionURLs
function immediately prior to the P2P communication.
In addition to searching with specified criteria, you can search with a matchmaking session ID, the principal IDs of participants, and the principal ID of the owner. However, note that you cannot check friend relationships or set any other conditions, such as whether a session is already full.
Warning
The NEX library uses qList <GatheringHolder>
to store search results for matchmaking sessions. STL algorithms that internally assign or call the copy constructor on qList <GatheringHolder>
may cause memory corruption and cannot be used. You can only use begin()
and end()
, in addition to access, increment, and decrement iterators.
Using the MatchMakingClient::GetDetailedParticipants
function, you can get the detailed information that was registered when participants joined. The principal ID of the participant and the detailed information registered when that participant joined are set in a ParticipantDetails
class object.
Code 4.4. Using Criteria to Search for a Matchmaking Session
static const qUnsignedInt32 s_gameMode = 1;
MatchmakeExtensionClient matchmakeClient;
void ExecuteBrowseMatchmakeSession()
{
// Set the search criteria.
MatchmakeSessionSearchCriteria criteria;
criteria.SetGameMode(s_gameMode);
criteria.SetAttribute(1, 3);
criteria.SetMatchMakeSystemType(MATCHMAKE_SYSTEM_TYPE_ANYBODY);
// The search range. By default, this range has an offset of 0 and holds up to 100 items.
ResultRange range;
// Search for sessions.
ProtocolCallContext oContext;
qList<MatchmakeSession> lstMatchmakeSession;
if (pMatchMakingClient->BrowseMatchmakeSession(&oContext, criteria, range, &lstMatchmakeSession))
{
// Error processing.
return;
}
oContext.Wait();
if (oContext.GetState()!=CallContext::CallSuccess)
{
// Error processing.
return;
}
// Display the search results.
for (qList<MatchmakeSession>::iterator itMatchmakeSession = lstMatchmakeSession.begin();
itMatchmakeSession != lstMatchmakeSession.end(); itMatchmakeSession++)
{
NN_LOG("GID:%u num of Participant:\n", itMatchmakeSession->GetID(), itMatchmakeSession->GetParticipantCount());
}
}
Use the MatchmakeExtensionClient::JoinMatchmakeSession
function to join a matchmaking session. This function takes a pointer to a ProtocolCallContext
object, the ID of the matchmaking session to join, a pointer to a common key for P2P communication, and detailed client information.
The game server receiving a request verifies the following and continues processing the participant only if there are no problems.
MATCHMAKE_SYSTEM_TYPE_FRIEND
.
After you have finished joining a matchmaking session, you must join a P2P session separately to run P2P communication. For more information, see Chapter 8 Peer-to-Peer Communication.
Use the MatchMakingClient::EndParticipation
function to leave a matchmaking session. This function takes a pointer to a ProtocolCallContext
object, the ID of the matchmaking session to leave, and detailed client information as arguments.
By default, the matchmaking session is deleted when the owner leaves or logs out. When the GatheringFlags::MigrateOwner
gathering flag is set, the ownership of the session is not deleted, and is migrated to another participant. The matchmaking session is deleted, however, if there are no other participants.
Warning
If you have joined a P2P session, you must leave both the matchmaking session and the P2P session. For more information, see chapter 8 Peer-to-Peer Communication.
When a client uses automatic matchmaking, it joins any matchmaking session that matches the search criteria; or it can register a matchmaking session with those criteria if one does not already exist. You can specify multiple search criteria using a list, and the game server searches by those criteria in order from the start of the list. (The search is halted when a joinable session is found.) A user cannot join the session if either the user is registered on the blacklist of any of the participants, or if any of the participants is registered on the user’s blacklist.
Use the MatchmakeExtensionClient::AutoMatchmake
function to perform automatic matchmaking. This function takes the following arguments: a pointer to a ProtocolCallContext
object, a MatchmakeSessionSearchCriteria
list if multiple search criteria are specified, a GatheringHolder
class object that stores a MatchmakeSession
object, a pointer to a GatheringHolder
class object for storing the asynchronous processing results, and detailed client information. For more information about setting MatchmakeSession
conditions, see 4.10. Setting Matchmaking Session Criteria. For more information about MatchmakeSessionSearchCriteria
, see 4.11. Setting the Search Criteria and Range.
If there is more than one matchmaking session that meets the search criteria, the game server decides which session to join based on the selection method specified by the MatchmakeSessionSearchCriteria::SetSelectionMethod
function. The default is random. The MatchmakeSelectionMethod
value can be set using MatchmakeSessionSearchCriteria::SetSelectionMethod
. For more information about MatchmakeSelectionMethod
, see 4.8.1 Selecting the Matchmaking Session.
When asynchronous processing succeeds, a MatchmakeSession
object is set in the GatheringHolder
class object to indicate which session was either joined or registered. Although you can get a pointer to a Gathering
class object with GatheringHolder::Get
, you can cast to a pointer to a MatchmakeSession
object. To determine whether a client registered a new matchmaking session or joined an existing matchmaking session, check whether the return value of the Gathering::GetOwnerPID
function is the same as the principal ID of the local host.
When the auto-matchmaking feature is used, if there is more than one matchmaking session that meets the search criteria, the game server decides which session to join based on the selection method specified by the MatchmakeSessionSearchCriteria::SetSelectionMethod
function. The default is random. The MatchmakeSelectionMethod
value can be set using MatchmakeSessionSearchCriteria::SetSelectionMethod
. If more than 50 matchmaking sessions meet the search criteria, you can apply the selection method specified by the MatchmakeSessionSearchCriteria::SetSelectionMethod
function to any 50 of the sessions.
If MATCHMAKE_SELECTION_METHOD_RANDOM
is specified, the sessions are selected randomly.
If MATCHMAKE_SELECTION_METHOD_NEAREST_NEIGHBOR
is specified, the matchmaking sessions with the closest attribute value to that in the MatchmakeSession
object passed as an argument to MatchmakeExtensionClient::AutoMatchmake
are selected. The attribute value in the MATCHMAKE_SELECTION_METHOD_NEAREST_NEIGHBOR
index is used. If there is more than one matchmaking session with the same attribute value, the matchmaking sessions are selected in order of gathering ID. If more than 50 matchmaking sessions meet the search criteria, the matchmaking sessions with the closest attribute value are not always the ones to be selected.
If MATCHMAKE_SELECTION_METHOD_BROADEN_RANGE
is specified, the matchmaking session is selected using the range broadening method. A "range" refers one set of integer values from a sequence of integers divided into multiple levels based on threshold values. The default setting assumes the use of the Elo rating system, where integers from 0 to 10000 are divided into 12 different levels: 0-1100, 1101-1240, 1241-1400, 1401-1520, 1521-1620, 1621-1720, 1721-1815, 1816-1925, 1926-2040, 2041-2180, 2181-2300, 2301-10000. Each level is a range. When using the range broadening method, a matchmaking session that has an attribute value within the same range as the attribute value of the MatchmakeSession
object passed as an argument to MatchmakeExtensionClient::AutoMatchmake
is randomly selected from the matchmaking sessions that meet the search criteria. The attribute value in the MATCHMAKE_SESSION_BROADEN_RANGE_ATTRIBUTE_INDEX
index is used. If a matchmaking session in the same range cannot be found, the scope can be expanded to any range adjacent to the current range. A matchmaking session is then randomly selected from the matchmaking sessions that meet the search criteria in the broader range and have the same attribute value in the MATCHMAKE_SESSION_BROADEN_RANGE_ATTRIBUTE_INDEX
index. By default, the range is expanded to the two ranges before and after the current range. For example, based on the ranges given above, if a matchmaking session was not found in the 1401-1520 range, the range would be expanded to 1101-1720. This feature can be used to enable matchmaking with closely ranked players in games that rank players based on a rating score by, for example, setting the attribute value in the MATCHMAKE_SESSION_BROADEN_RANGE_ATTRIBUTE_INDEX
index to the rating score and setting the ranges based on the ranks. Also refer to the WebAPI documentation (12.2.2 API Functions for Range Broadening Auto-Matchmaking Feature).
If MATCHMAKE_SELECTION_METHOD_PROGRESS_SCORE
is specified, the matchmaking session with the closest game progress score to the value set using MatchmakeSession::SetProgressScore
or MatchmakeExtensionClient::UpdateProgressScore
is selected from the matchmaking sessions that meet the search criteria. This feature is useful when, for example, a game accepts new participants for the next match after the current match has already begun. It would allow players to join a match that is almost over rather than one that has just begun, reducing the amount of wait time until the next match. To achieve this, you would set the game progress score to 0 at the beginning of the match, and use the MatchmakeExtensionClient::UpdateProgressScore
function to periodically update the game progress as the match progresses. Note that frequently calling MatchmakeExtensionClient::UpdateProgressScore
increases the load on the server. Update the score at an interval of UPDATE_PROGRESS_SCORE_MINIMUM_INTERVAL_TIME
seconds or longer.
If MATCHMAKE_SELECTION_METHOD_BROADEN_RANGE_WITH_PROGRESS_SCORE
is specified, the matchmaking session is selected using a combination of range broadening and the game progress score. The matchmaking session that has an attribute value within the same range as the attribute value of the MatchmakeSession
object passed as an argument to MatchmakeExtensionClient::AutoMatchmake
, and also has the highest game progress score, is selected from the matchmaking sessions that meet the search criteria. The attribute value in the MATCHMAKE_SESSION_BROADEN_RANGE_ATTRIBUTE_INDEX
index is used. If a matchmaking session in the same range cannot be found, the scope can be expanded to any range adjacent to the current range. The matchmaking session with the highest game progress score is then selected from the matchmaking sessions that meet the search criteria in the broader range.
If MATCHMAKE_SELECTION_METHOD_SCORE_BASED
is specified, the best matchmaking session is selected by applying a score to various parameters. Score conversions are defined in advance. To assign scores for various parameter types, parameters of matchmaking sessions that match the search criteria are compared with the sessions for the user, and the matchmaking session with the highest total score is selected. The following parameters can be used.
You can use multiple score conversion settings by switching a settings index. For example, you can change the assignment of scores by changing the setting index according to the game mode. When multiple MatchmakeSessionSearchCriteria
objects are specified, the first criterion is used as the strictest score conversion, the second is used somewhat less strictly, and so on to enable the best matchmaking session to be found. To use this feature, you must use an overloaded version of the MatchmakeSessionSearchCriteria::SetSelectionMethod
function, which takes a MatchmakeParam
argument. The MatchmakeParam
object specified to this function must also be specified to the MatchmakeSession
using the MatchmakeSession::SetMatchmakeParam
function. The application must set the information such as the user's own rating value, disconnect rate, violation rate, and country for the MatchmakeParam
function. The MatchmakeExtensionClient::AutoMatchmake
function allows you to get the total score from the MatchmakeParam
included in the matchmaking session you are participating in. However, if you are the owner of the session, it means no matchmaking occurred, so you cannot get your total score. If the application calculates the rating value, disconnect rate, and violation rate, consider using MatchmakeReferee
. Also see the web API documentation (Section 12.2.3 API for Auto-Matchmaking by Scoring Feature).
Code 4.5. Using MATCHMAKE_SELECTION_METHOD_SCORE_BASED
MatchmakeParam param;
param.SetSettingIndex(0);
param.SetRatingValue(1500);
MatchmakeSessionSearchCriteria criteria;
criteria.SetMatchmakeSystemType(MATCHMAKE_SYSTEM_TYPE_ANYBODY);
criteria.SetSelectionMethod(MATCHMAKE_SELECTION_METHOD_SCORE_BASED, param);
qList<MatchmakeSessionSearchCriteria> criteriaList;
criteriaList.push_back(criteria);
MatchmakeSession* matchmakeSession = new MatchmakeSession();
matchmakeSession->SetGameMode(0);
matchmakeSession->SetMatchmakeSystemType(MATCHMAKE_SYSTEM_TYPE_ANYBODY);
matchmakeSession->SetMaxParticipants(4);
matchmakeSession->SetMatchmakeParam(param);
GatheringHolder oGatheringHolder = matchmakeSession;
ProtocolCallContext oContext;
GatheringHolder joinedSession;
matchmakeExtensionClient.AutoMatchmake(&oContext, criteriaList, oGatheringHolder, &joinedSession));
To improve the overall success rate of NAT traversal on P2P networks, auto-matchmaking will delay the creation of a new matchmaking session as much as one second if a matchmaking session that meets the search criteria does not exist when calling from a station with a NAT type of EDM or a high failure rate. The auto-matchmaking feature repeatedly searches for matchmaking sessions during the delay period and does not respond to the client. Delaying the creation of a matchmaking session increases the probability of joining an existing matchmaking session and makes the station less likely to become the host. The default delay time is one second. Contact Nintendo if you want to set a time longer than the default of one second.
The creation of a new session is delayed under the following conditions.
The results of the NAT type check and NAT traversal success check for each global IP address are recorded on the game server when the terminal logs out or disconnects. This information is shared between all game servers running NEX 3.5 and later versions. The information expires one week from the last report.
You can force a delay by setting MatchmakeFlags::MatchmakeSessionOption0
to MatchmakeFlags::MATCHMAKE_SESSION_OPTION0_FORCE_AUTOMATCH_DELAY
using the MatchmakeSession::SetOption0Flag
function. If you have set a time longer than the default of one second, be sure to debug your application with this flag enabled.
When a matchmaking session is opened on the game server, a request to participate in the P2P session associated with the matchmaking session can arrive at any time. In particular, when using the auto matchmaking feature, because joining one of the top 10 matchmaking sessions that can be joined is selected randomly on the game server, the possibility of simultaneously joining the same matchmaking session becomes greater.
For this reason, specify that the application accepts join requests for a short interval, and that the application makes every effort to not reject requests to join a P2P session. (Omit the check for excessive numbers of participants that copes with deadline timing shift issues.)
Rejection at the stage of joining a P2P session is a cause of declining matchmaking success rates.
If a state where joining is not possible lasts for a long time, run the MatchmakeExtensionClient::CloseParticipation
and MatchmakeExtensionClient::OpenParticipation
functions.
There are cases where users play with friends they know, or play as teams after gathering a group of players. The multiple user group matchmaking session join allows this functionality.
To join multiple users at once, overload the MatchmakeExtensionClient::AutoMatchmake
, MatchmakeExtensionClient::CreateMatchmakeSession
, and MatchmakeExtensionClient::JoinMatchmakeSession
functions by passing the AutoMatchmakeParam
, CreateMatchmakeSessionParam
, and JoinMatchmakeSessionParam
objects as arguments. For example, you can atomically join yourself and other users with known principal IDs by passing the principal IDs to the JoinMatchmakeSessionParam::SetAdditionalParticipant
function. The result is all users successfully joining, or an error causing all users to fail joining. Use the JoinMatchmakeSessionParam::SetGatheringIdForParticipationCheck
function as an option to check if all users have joined the specified gathering. If you specify JOIN_MATCHMAKE_SESSION_BEHAVIOR_IM_ALREADY_JOINED
in the JoinMatchmakeSessionParam::SetJoinMatchmakeSessionBehavior
function, you can get other users specified in the JoinMatchmakeSessionParam::SetAdditionalParticipant
function joined into the matchmaking session that you have already joined. A NotificationEvents::AddedToGathering
notification is sent to the users who were added.
Parameters such as criteria and additional information searched for by other clients are set in MatchmakeSession
class objects. You can also reset settings with the MatchmakeSession::Reset
function.
The following table lists the parameters that can be set.
Name | Description | Initial Value | Settings Function |
---|---|---|---|
Game mode | A number that indicates matchmaking modes such as ranked matches, free play, and co-op mode. Games are free to use any values. Using game modes to filter matchmaking sessions can enhance search performance on the server. We recommend using as many specific game mode classifications as is feasible for your application. | 0 | SetGameMode |
Matchmaking system type | The matchmaking type. (Either anyone can join or only the friends of the matchmaking session owner can join.) Supports MATCHMAKE_ SYSTEM_ TYPE_ ANYBODY , MATCHMAKE_ SYSTEM_ TYPE_ FRIEND . When MATCHMAKE_ SYSTEM_ TYPE_ FriendOnlyParticipationPolicyArgument:: SetMatchmakeSystemType function. |
MATCHMAKE_ SYSTEM_ TYPE_ INVALID |
SetMatchmakeSystemType |
Attributes | Attribute values that a game can use as its own search criteria, such as a level, the number of rounds, and the purpose of a match. Up to six attributes can be specified. | All 0 |
SetAttribute |
Maximum number of participants | The maximum number of participants for a matchmaking session. No more than the maximum number of participants can join a matchmaking session. | 0 | SetMaxParticipants |
Gathering flags | Flags that specify options for a gathering. The GatheringFlags::MigrateOwner flag may be set to specify if automatic owner migration occurs when the matchmaking session owner leaves a matchmaking session (by logging out from NGS or when executing the EndParticipation function). |
0x0 |
SetFlag and ClearFlag |
Application-defined data | Data that can be freely used by applications. For example, this parameter can be set with up to 512 bytes of data that does not need to be included in the search criteria, such as the matchmaking session state. | NULL |
SetApplicationBuffer |
Description string | A string that describes a matchmaking session. Applications can set this parameter with any value up to 256 characters. | _T(“”) |
SetDescription |
Invitation status flag | Specifies the invitation status of a matchmaking session when it is registered. If this parameter is true , a session waits for new participants when it is registered. If it is false , a session is closed to new participants when it is registered. |
true |
SetOpenParticipation |
Game progress score | Application-defined value that is used if MATCHMAKE_ SELECTION_ METHOD_ PROGRESS_ SCORE is set as the matchmaking session selection method. |
MAX_ |
SetProgressScore |
Options | The options enumerated in MatchmakeFlags:: MatchmakeSessionOption0 to add to the matchmaking session. |
MATCHMAKE_ |
SetOption0Flag |
Matchmaking parameters | Parameters to add to the matchmaking session for use when the matchmaking session selection method is set to MATCHMAKE_ SELECTION_ METHOD_ SCORE_ BASED |
MatchmakeParam | SetMatchmakeParam |
User password | A password required to join a matchmaking session. User passwords can be up to MAX_ MATCHMAKE_ SESSION_ USER_ PASSWORD_ LENGTH (32) characters in length. If you specify an empty string, no password will be set for the matchmaking session. |
_T(“”) |
SetUserPassword |
ID of a persistent gathering to associate | The ID of a persistent gathering to associate with the matchmaking session. Use the PersistentGathering::GetMatchmakeSessionCount function to get the number of matchmaking sessions associated with a persistent gathering. Specify INVALID_ GATHERINGID to leave the matchmaking session unassociated with any persistent gathering. |
INVALID_ |
SetReferPersistentGatheringId |
Comments
If a client registers a matchmaking session to wait for new participants, that client may not get a chance to start P2P communication before another client attempts to start communicating with it. If your application joins a matchmaking session and then uses P2P communication, implement it to register the session closed to new participants and prepare for P2P communication before you change the session to wait for new participants.
Comments
Do not directly change the class variables of the MatchmakeSession
class or its parent, the Gathering
class, using setting functions other than those in Table 4.1 and MatchmakeSession::Reset
, which resets criteria. Operations in this situation are not guaranteed.
Search criteria are set in MatchmakeSessionSearchCriteria
class objects. Table 4.2 shows the search criteria that can be set in MatchmakeSessionSearchCriteria
. The configured search criteria are combined using a bitwise AND. You can also restore the default settings by using the MatchmakeSessionSearchCriteria::Reset
function.
Name | Description | Initial Value | Settings Function |
---|---|---|---|
Game mode | A number that represents types of games. You must specify a value for this option. | None. | SetGameMode |
Matchmaking system type | The matchmaking type. (Either anyone can join or only the friends of the matchmaking session owner can join.) When MATCHMAKE_ is specified, the server checks whether the owner is a friend of the local host. Specifying this item is required. |
None. | SetMatchmakeSystemType |
Attributes | Games can specify up to six of these attributes as independent search criteria. If not specified, the type condition matches any value. Attribute values are evaluated all at once without concern for the index order. Attribute values can be specified with a range by using the SetAttributeWithRange function. |
Arbitrary value | SetAttribute , SetAttributeWithRange |
Flag for excluding full sessions | Specifies whether to exclude full matchmaking sessions. | False | SetVacantOnly |
Flag for excluding sessions with undetermined hosts | Specifies whether to exclude sessions for which a P2P communication host has not been determined. | True | SetExcludeNonHostPid |
Flag for excluding closed sessions | Specifies whether to exclude matchmaking sessions that are closed to new participants. | True | SetExcludeLocked |
How to select the matchmaking session | Specifies how to select which matchmaking session to join when multiple matchmaking sessions satisfy the search criteria. (Used only with automatic matchmaking.) | MATCHMAKE_ SELECTION_ METHOD_ RANDOM |
SetSelectionMethod |
ID of a persistent gathering to associate | Matchmaking sessions associated with the specified persistent gatherings will be included in searches. Specify INVALID_ GATHERING to match on any value. |
INVALID_ |
SetReferPersistentGatheringId |
To specify a search range, set an offset and the maximum size of the search results in a ResultRange
class object. By default, the offset is 0
and the maximum size of an obtained list is 100
. Although matchmaking session IDs are sorted in ascending order in the lists that can be obtained, the server randomly rearranges data that matches the search criteria before returning the result to the client when RESULTRANGE_ANY_OFFSET
is specified as the offset. Use a maximum list size of 100
or less.
If your implementation filters search results from the game server without specifying any search criteria, it cannot perform matchmaking effectively because there is no guarantee that it can get a matchmaking session that meets the desired criteria. Consequently, include search criteria that can be matched perfectly (such as the region and round number), by using attributes that you can specify with the SetAttribute
function on the client without filtering.
Matchmaking search is processing-heavy. Implement matchmaking conditions so that existing matchmaking sessions that are waiting for participants are filled before creating a new matchmaking session. If matchmaking conditions are divided into too many small parts, it can be difficult to complete the gathering process, users are forced to wait longer, and the user experience deteriorates.
Also, actively control to remove the gathering from the search pool. When the maximum number of participants in a matchmaking session is reached, use MatchmakeSessionSearchCriteria::SetVacantOnly
to automatically remove the gathering from the search target. If a game starts before the maximum number of participants is reached, and it is obvious that other players are no longer joining the session during the game (after the game itself started for games that run for a long time), call the MatchmakeExtensionClient::CloseParticipation
function to close the gathering, and remove it from the search target.
Matchmaking sessions can be password locked to limit the session to a defined group of users. If a matchmaking session restricted in this manner is shown in the general matchmaking search results, a large number of restricted matchmaking sessions may be displayed in the search results. When this occurs, users may reload the search results repeatedly to find open matchmaking sessions, increasing server load and decreasing the quality of the user experience. As a result, restricted matchmaking sessions are not displayed in the matchmaking list during searches. Alternatively, we recommend providing a separate method to search for unrestricted matchmaking sessions.
We also recommend an implementation to reduce server load when you want users to add additional people to the session outside of the game by showing the gathering ID as a code, and searching for this code using the MatchMakingClient::FindByID
function, instead of storing the search code in a tag to search.
Matchmaking sessions can be created with a password restriction. There are two types of passwords: a user password, and a system password. A user password is set by the player; the system password is set by the server. The MatchmakeSession::SetUserPassword
function is used to set a user password for a matchmaking session being registered on a server. The MatchmakeExtensionClient::GenerateMatchmakeSessionSystemPassword
function is used to set a system password for a matchmaking session already registered on the server. NotificationEvents::MatchmakeSessionSystemPasswordSet
is notified to members of the matchmaking session when the system password is set. Use the MatchmakeExtensionClient::ClearMatchmakeSessionSystemPassword
function to remove the system password. NotificationEvents::MatchmakeSessionSystemPasswordClear
is notified when the system password is removed. The correct password must be specified to join a matchmaking session protected by a user password or system password. The JoinMatchmakeSessionParam
object with a set password is selected in the JoinMatchmakeSessionParam::SetUserPassword
or JoinMatchmakeSessionParam::SetSystemPassword
function, for the MatchmakeExtensionClient::JoinMatchmakeSession
function taking JoinMatchmakeSessionParam
as an argument. A matchmaking session protected by a system password is automatically hidden from MatchmakeExtensionClient::BrowseMatchmakeSession
. These password protected matchmaking sessions can be searched using MatchMakingClient::FindByID
. The MatchmakeSessionSearchCriteria::SetExcludeUserPasswordSet
function is used to set whether the MatchmakeExtensionClient::BrowseMatchmakeSession
function shows matchmaking sessions protected by user passwords. The system password is useful when a session is waiting for certain players to join. Players that are unexpectedly disconnected from a server can use the system password generated by the MatchmakeExtensionClient::GenerateMatchmakeSessionSystemPassword
function to rejoin the same matchmaking session. User passwords and system passwords cannot be obtained from matchmaking sessions retrieved using the MatchMakingClient::FindByID
or MatchmakeExtensionClient::BrowseMatchmakeSession
functions. The MatchmakeSession::GetUserPassword
function always returns an empty string when called on matchmaking sessions retrieved from the server. However, you can use the MatchmakeSession::GetUserPasswordEnabled
and MatchmakeSession::GetSystemPasswordEnabled
functions to determine whether a user password or system password has been set.
Some criteria can be changed even after the owner of a matchmaking session is registered with the game server.
Use the MatchmakeExtensionClient::OpenParticipation
function to invite clients to join a matchmaking session. This function takes two arguments: a pointer to a ProtocolCallContext
object, and the ID of the matchmaking session to invite clients to join.
When asynchronous processing succeeds, other clients can join the matchmaking session. (When searching for matchmaking sessions, the invitation status flag is true
.) However, new clients cannot join after the maximum number of matchmaking participants is reached.
Although new clients cannot join a session after it has reached its maximum number of participants, a session can also be closed to new clients even if it has not reached the maximum number of participants.
Use the MatchmakeExtensionClient::CloseParticipation
function to close a matchmaking session to new clients. This function takes two arguments: a pointer to a ProtocolCallContext
object, and the ID of the matchmaking session to close to new clients.
When asynchronous processing succeeds, other clients can no longer join the matchmaking session. (When searching for matchmaking sessions, the invitation status flag is false
.) However, clients that have already joined are not affected. Also, note that a ParticipationEvents::Participate
notification may arrive after a successful call to this function due to differences in when the NotificationEvents::ParticipationEvent
event and session participation close process are handled.
Note
Be careful if your application is designed to have users join a P2P session after joining a matchmaking session. Participation in the P2P session may not complete for some time after closing participation in the matchmaking session because the NAT traversal and join P2P session processes themselves take some time to complete. If a client is denied participation when attempting to join a P2P session, it can have an extremely negative effect on the efficiency of the matchmaking process. It is particularly important to consider this effect if you close participation in a matchmaking session before the maximum number of participants has joined. In this case, implement handling using a NotificationEvents::ParticipationEvent
notification and make sure that you do not deny participation in the P2P session if the number of participants in the matchmaking session and the number of participants in the P2P session are different.
Use the MatchMakingClient::MigrateGatheringOwnership
function to transfer ownership of a matchmaking session to another client. This function is usually used when the owner leaves the matchmaking session. When GatheringFlags::MigrateOwner
is specified in the gathering flag, there is no need to call the MatchMakingClient::MigrateGatheringOwnership
function when leaving, because ownership transfer occurs automatically. Only existing members of a matchmaking session can become the new owner.
This function takes the following arguments: a pointer to a ProtocolCallContext
object, the ID of the matchmaking session for which to transfer ownership, and a list of principal IDs for the clients to which ownership is transferred. If the list of principal IDs is empty, a new owner is automatically selected from the clients that have joined the matchmaking session. (As a general rule, use this approach.)
The MatchMakingClient::UpdateGatheringOwnership
or MatchMakingClient::UpdateSessionHost
function can be used by a gathering member to take ownership, if the GatheringFlags::ChangeOwnerByOtherHost
flag is set in the matchmaking session gathering flags. These APIs can be used to make the P2P host and gathering owner the same.
Use the MatchmakeExtensionClient::UpdateMatchmakeSession
function to make changes to matchmaking session information. The overload of the function that takes GatheringHolder
as an argument updates all of the matchmaking session parameters except for the ID, owner, P2P communication host, gathering flags, ID of the related persistent gathering, and common key for P2P communications. The matchmaking system type can only be changed between MATCHMAKE_SYSTEM_TYPE_ANYBODY
and MATCHMAKE_SYSTEM_TYPE_FRIEND
. The overload of the MatchmakeExtensionClient::UpdateMatchmakeSession
function that takes UpdateMatchmakeSessionParam
as an argument only updates the specified matchmaking session parameter.
There are two ways to change attributes: either individually with the MatchmakeExtensionClient::ModifyMatchmakeSessionAttribute
function, or all at the same time with the MatchmakeExtensionClient::UpdateMatchmakeSessionAttribute
function. The ModifyMatchmakeSessionAttribute
function takes the following arguments: a pointer to a ProtocolCallContext
object, the ID of the matchmaking session to change, the index of the attribute to change, and the new attribute value. The UpdateMatchmakeSessionAttribute
function takes the following arguments: a pointer to a ProtocolCallContext
object, the ID of the matchmaking session to change, and an array of new attribute values.
Use the MatchmakeExtensionClient::UpdateApplicationBuffer
function to change application-defined data. This function takes the following arguments: a pointer to a ProtocolCallContext
object, the ID of the matchmaking session to change, and the new data.
Use the MatchMakingClient::UnregisterGathering
function to delete a matchmaking session. This function takes the following arguments: a pointer to a ProtocolCallContext
object, and the ID of the matchmaking session to delete. The matchmaking session is deleted automatically in the following situations.
GatheringFlag::OwnerMigration
is not set in the gathering flag. To prevent meaningless matchmaking sessions from being left on the game server, use the MatchMakingClient::UnregisterGathering
function to delete unnecessary matchmaking sessions.
Use the friend presence library to share the gathering participation state in NEX with friends as presence. The application or friend list can get presence that is shared with friends, and can use that information to join gatherings that a friend is currently participating in. The friend presence library includes the following two processes for helping to join in.
MatchmakeSession
object that matches the NEX gathering participation state in the nn::friends:GameMode
structure, and update the join-in-capable status using the nn::friends:UpdateGameMode
function.MatchmakeExtensionClient::JoinMatchmakeSession
function.
The friend list gathers the presence of friends that are publicizing their status, and displays that status. Both friends, if online, see each other's status and the games they both are playing, even if they are not playing the same game.
If a friend is online, and the public presence indicates that friends allow join-in, the Join game your friend is playing button on that friend's card is enabled. Pressing that button starts the game that the friend is playing, which also ends any game that the first player is already playing.
If an application was started from the friend list, the application can get the fact that it was started from the friend list, and can get the friend key of the friend chosen from the list, after it starts. It gets the current presence of the friend from that friend key, and then uses NEX to use that information to join the gathering that the friend is participating in.
If both players are playing a game that has the same join-in game ID, the application can directly get the parameters for the presence that the friend is publicizing. It uses those parameters to determine whether the friend is accepting the join-in, and uses NEX to join the gathering that the friend is participating in.
The friend presence library helps the player determine whether the friend's presence accepts the join-in, and helps to monitor changes in presence.
In the BSF file, set the join-in game ID in JoinGameId
, and set the join-in game mode mask in JoinGameModeMask
. For more information about these settings, see the ctr_makebanner
manual.
The join-in game ID uses the NEX game server ID. Applications that have set the same value for the join-in game ID can share presence between friends.
The game mode mask is specified as a bit mask, with the lowest value bit being mode 0, and the highest value bit being mode 63, indicating the ability to join. This value is used only to determine when an application is started from the friend list, and has no effect on operations after the application is started.
Use the CTR Master Editor to confirm this value.
An application must be restarted from the HOME Menu for the join-in game ID set in its icon data to take effect. When an SD Card is inserted in the system, the HOME Menu caches icon data on the SD Card. Updates to that data sometimes do not take effect. When this happens, delete the icon data cache. For more information about deleting the icon data cache, see "Using Debug Functionality" under "HOME Menu" in the manual that comes with the CTR-SDK package.
Comments
You can access the HOME Menu from either of the following locations.
- The list of menus in
index.html
of the CTR-SDK package- CTR_SDK\documents\DevHomeMenu\HomeMenu.html
To share presence between friends by using the friend library, both friends must be online and must both set the same join-in game ID.
Although a player can share presence with friends even when the player was logged in in response to a background login request from the system, the online state might not be maintained if the application does not issue a login request. Send a login request using the nn::friends::Login
function before using functionality related to joining.
To correctly communicate the status of the player that indicates they can accept joining, use the nn::friends::UpdateGameMode
function to update the presence of the player whenever the NEX gathering participation status of the player changes.
Specify the following option for each element of the nn::friends:GameMode
structure.
JoinAvailability
enumerator.joinAvailabilityFlag | JOIN_AVAILABILITY_JOINABLE | JOIN_AVAILABILITY_JOINABLE_APP_ONLY | JOIN_AVAILABILITY_NOT_JOINABLE |
---|---|---|---|
Join game that is being played button on the friend list. | Enabled if conditions are met. | Always disabled. | Always disabled. |
nn:: |
true if conditions are met. |
true if conditions are met. |
Always false . |
MatchmakeSession
object while participating.UpdateGameMode
ignores this value even if specified, and the join-in game ID specified in the icon data continues to be used.0
and 63
. Store the game mode value in the MatchmakeSession
object while participating.MatchmakeSession
object while participating. When the matchmaking system type is FRIEND
, update GameMode
if the owner has changed. Knowing whether the player has a friend relationship with the owner is necessary for determining whether joining is possible.MatchmakeSession
object while participating.While there is no limit to the frequency with which you can call the UpdateGameMode
function, to notify the server or a friend of the updated information, an interval of at least 10 seconds from the previous update is necessary. For more information, see 4.3.5.2. Synchronizing the Friend Server or Friend Data in the CTR Programming Manual: Wireless Communication.
Note that even if you renew the presence of a player more often, there is still a delay before it is communicated to a friend.
You can use the nn::GetFriendPresence
function to get a friend's presence. Use the nn::friends::FriendPresence
structure that you get to determine the join-in-capable status of a friend with the nn::friends::FriendPresence::IsJoinable
function. When you use this function, specify a bit mask in the function parameters to indicate which game modes the player can join. If you determine that the player can join, you can specify the NEX gathering ID as the value of the joinGroupId
member and execute the join operation on that gathering.
Handle changes in friend presence by using the nn::friends::AttachToEventNotification
or nn::friends::GetEventNotification
function to monitor presence change notifications. When a presence change notification comes, use the IsJoinable
function to determine whether a player can join again.
If an application is started from the friend list, the nn::friends::IsFromFriendList
function returns true
. In this case, the FriendKey
for the selected friend is also stored in the buffer passed to a parameter. After getting the parameter, get the presence of the friend that the FriendKey
indicates, and rapidly transition to the join-in sequence.
makebanner
. When this happens, set the game mode mask for the icon data to 0
, and specify JOIN_AVAILABILITY_JOINABLE_APP_ONLY
as the joinAvailabilityFlag
value when updating presence. If these settings are not correct, the Join game that is being played button on the friend list is enabled, but it is impossible to start the game.Applications can use blacklists to prevent harassment by specific users. By using a blacklist, a user can:
This is always enabled. You cannot enable or disable it in the application. If you want to disable the blacklist feature due to the design of your application, please contact Nintendo at support@noa.com.
A single player can register up to 100 other players on their blacklist, and has one blacklist per game server (and per application). If a player blacklists more than 100 people, the earliest entries on the blacklist are deleted in the order in which they were registered. (This method is called the first-in-first-out (FIFO) method.) You decide whether to manage the blacklist inside the application on an application-by-application basis.
The MatchmakeExtensionClient::GetPlayingSession
and MatchmakeExtensionClient::FindPersistentGatheringByParticipant
functions always return an empty list when searching for players who are registered to the local host’s blacklist. However, it is not possible to detect whether other participants in that gathering are on the blacklist of the local system.
The MatchmakeExtensionClient::BrowseMatchmakeSession
and MatchMakingClient::FindByID
functions, among others, also do not check whether a participating user is registered to the blacklist of the local system, or has registered the user of a local system to a blacklist. Consequently, you cannot determine whether users in a session are registered to the blacklist of the local system, or the user of the local system is registered to their blacklist, until the call to the MatchmakeExtensionClient::JoinMatchmakeSession
function. Note that the primary purpose of the privacy filter is to prevent harassment by particular users.
Code 4.6. Blacklist Management API
// Add the specified player to the blacklist on the game server.
qBool MatchmakeExtensionClient::AddToBlackList(
ProtocolCallContext* pContext,
const qList<PrincipalID>& PrincipalIDList);
// Delete the specified player from the blacklist on the game server.
qBool MatchmakeExtensionClient::RemoveFromBlackList(
ProtocolCallContext* pContext,
const qList<PrincipalID>& principalIDList);
// Clear the blacklist.
qBool MatchmakeExtensionClient::ClearBlackList(ProtocolCallContext* pContext);
// Get players that the local host has registered on its own blacklist.
qBool MatchmakeExtensionClient::GetMyBlackList(
ProtocolCallContext* pContext,
qList<PrincipalID>* pPrincipalIDList);
A persistent gathering is a mechanism for matchmaking within a specific group of users. You can make a persistent gathering room (where, for example, only students at a specific school can participate), and matchmake within that room.
Although some features are similar to friend features, a user can join a persistent gathering without needing to establish any friendships with anyone. This functionality enables game developers to set up official persistent gatherings for particular game titles, hold tournaments, and so on.
Once created, persistent gatherings remain on the server until they are explicitly deleted. Participation in persistent gatherings is similarly permanent until explicitly modified (when using the default persistent gathering settings). To matchmake users in a persistent gathering with each other, add the ID of that persistent gathering as the ID to associate with the matchmaking session when registering the matchmaking session and then search for or have users join sessions using that ID.
Although persistent gatherings are a type of gathering, whether the join status is permanent is a significant difference from matchmaking session gatherings.
The following examples show possible uses for persistent gatherings.
Persistent gatherings exist independently for each game.
Persistent gatherings and matchmaking sessions differ not only in their lifespans, but also in the following other ways.
Differences | Persistent Gathering | Matchmaking session |
---|---|---|
Deletion timing | The number of members becomes 0 [note 1]. The UnregisterGathering function is called. |
The number of members becomes 0. The UnregisterGathering function is called. |
Leaving timing | The EndParticipation function is called [note 2]. |
The EndParticipation function is called. The user is logged out from the game server. |
Number of participants | Unlimited by default. (A limit can be set.) | Number of clients using P2P communication. |
Notification from the server. | None. | A notification is pushed when a user joins or leaves. |
Messaging | Only possible if the maximum number of participants is set to 32 or fewer (MessagingClient:: SendChat ). |
Possible. (Use the MessagingClient::SendChat function.) |
P2P communication | None. Register and then join a separate matchmaking session, and then switch to P2P mode. | Yes |
Owner migration | None. | Yes |
Blacklist | None. | Yes |
Deadline | None. However, it is possible to set a period during which joining is possible. | Yes |
[1] You can make the gathering persist even when the number of participants reaches 0 by setting GatheringFlags::AllowNoParticipant
in the gathering flags.
[2] You can make users leave a gathering automatically when they are disconnected from the game server (including logging out) by setting GatheringFlags::NoPersistentParticipation
in the gathering flags.
To create a persistent gathering, set the conditions for the persistent gathering in the PersistentGathering
class object, and execute the MatchmakeExtensionClient::CreatePersistentGathering
function. (Do not set any items other than those in Table 4.5 Persistent Gathering Settings. Setting other items may cause unintended results.) If the asynchronous process in the MatchmakeExtensionClient::CreatePersistentGathering
function succeeds, a gathering ID is assigned by the game server so that the persistent gathering can be identified. The user who calls the CreatePersistentGathering
function becomes the owner of that gathering, and automatically joins the gathering. Each user can create up to PERSISTENT_GATHERING_CREATION_MAX
(4) persistent gatherings, and can be a member of up to PERSISTENT_GATHERING_PARTICIPATION_MAX
(16).
The owner of a community can update that community by using the MatchmakeExtensionClient::UpdatePersistentGathering
function, and can delete it by using the MatchMakingClient::UnregisterGathering
function. It is also possible to delete a persistent gathering that has more members than just the owner. When a persistent gathering is deleted, all users who are members of the community leave it.
When an official persistent gathering is created, the owner's principal ID takes a special value (101), and the client that created the gathering can no longer update or delete the gathering. Update or delete the gathering from NMAS. (NMAS is discussed in more detail later.)
Official persistent gatherings created in the development environment are automatically copied into the Lotcheck environment. Please make the required official persistent gatherings available when Lotcheck starts. This will not be copied into the production environment.
Name | Description | Initial Value | Settings Function |
---|---|---|---|
Persistent gathering type | Specify the persistent gathering type: anybody can join, password is required to join, or official persistent gathering. | Open | SetPersistentGatheringType |
Attributes | Games can specify up to six of these attributes as independent search criteria. | 0 | SetAttribute |
Maximum number of participants | When 0 is specified, there is no limit to the maximum number of participants. |
0 | SetMaxParticipants |
Application-defined data | Data that can be freely used by applications. You can set up to 512 bytes of data that does not need to be searchable in this parameter, such as the status of the persistent gathering. | NULL |
SetApplicationBuffer |
Description string | A string describing the persistent gathering. Applications can set this parameter with any value up to 256 characters. | _T(“”) |
SetDescription |
Date from which users can join | Gets the date and time from which users can join the persistent gathering. If DateTime::Never() is specified, there is no limit. |
DateTime:: Never() |
SetParticipationStartDate |
Last day on which users can join | Gets the deadline (date and time) for joining the persistent gathering. If DateTime::Never() is specified, there is no limit. |
DateTime:: Never() |
SetParticipationEndDate |
The following functions can be used to search persistent gatherings. If a result of a search from the FindPersistentGatheringByParticipant
function is on the blacklist of the local host, or if the target participant has used the MatchmakeExtensionClient::UpdatePrivacySetting
function to set the status of their participation in the persistent gathering to 'private', a blank list is returned. Note: Currently, NEX does not support searching for persistent gatherings by attributes.
Code 4.7 Functions for Searching Persistent Gatherings
// Search by ID.
MatchmakeExtensionClient::FindPersistentGatheringByGatheringID(
ProtocolCallContext *pContext,
qList<GatheringID> gatheringIdList,
qList<PersistentGathering> *pPersistentGatheringList);
// Search by participant.
MatchmakeExtensionClient::FindPersistentGatheringByParticipant(
ProtocolCallContext *pContext,
PrincipalID principalId,
const ResultRange& resultRange,
qList<PersistentGathering>* pPersistentGatheringList);
// Search official persistent gatherings. (The persistent gathering type is PERSISTENT_GATHERING_TYPE_OFFICIAL
.)
MatchmakeExtensionClient::FindOfficialPersistentGathering(
ProtocolCallContext *pContext,
qBool isAvailableOnly,
const ResultRange& resultRange,
qList<PersistentGathering>* pPersistentGatheringList);
// Search by the principal ID of the owner.
qBool MatchmakingClient::FindByOwner(ProtocolCallContext *pContext,
PrincipalID pidOwner,
const ResultRange& resultRange,
qList<GatheringHolder> *plstGatherings);
Use the MatchmakeExtensionClient::JoinPersistentGathering
function to join a persistent gathering, and the MatchmakeExtensionClient::EndParticipation
function to leave a persistent gathering. Unlike in a matchmaking session, the owner of a persistent gathering is not notified when a member joins or leaves. A user can only join up to 16 (PERSISTENT_GATHERING_PARTICIPATION_MAX
) persistent gatherings. If the user tries to join more gatherings, the asynchronous process fails with QERROR(RendezVous, PersistentGatheringParticipationMax)
.
To display an identifier for the persistent gathering in the user interface as an ID, you must convert the gathering ID of the persistent gathering to a persistent gathering code. The persistent gathering code is a 14-digit, decimal, integer HMAC value that is assigned based on the gathering ID and unique access key for the game. You must query the game server to determine whether a persistent gathering exists, even if the IsValidPersistentGatheringCode
function determines that the persistent gathering code is valid. You can still use the persistent gathering code conversion function shown in the following code example even when you are not logged in to the game server.
Code 4.8. Persistent Gathering Code Conversion Functions
// Sets the persistent gathering code HMAC key. Specifies the unique access key for a game.
static void MatchmakingClient::SetPersistentGatheringCodeKey(const String& strKey);
// Clears the persistent gathering code HMAC key.
static void MatchmakingClient::ClearPersistentGatheringCodeKey();
// Converts a gathering ID to a persistent gathering code.
static qUnsignedInt64 MatchmakingClient::GatheringIdToPersistentGatheringCode(GatheringID gatheringId);
// Converts a persistent gathering code to a gathering ID.
static GatheringID MatchmakingClient::PersistentGatheringCodeToGatheringId(qUnsignedInt64 persistentGatheringCode);
// Checks whether the community code is valid.
static qBool MatchmakingClient::IsValidPersistentGatheringCode(qUnsignedInt64 persistentGatheringCode);
While persistent gatherings are permanent, it is not possible to do matchmaking at the persistent-gathering level. To perform matchmaking in connection with a persistent gathering, you must register a separate matchmaking session (a persistent gathering matchmaking session) and associate the gathering ID of the persistent gathering with that matchmaking session. When registering a persistent gathering matchmaking session, use the MatchmakeSession::SetReferPersistentGatheringId
function to set the ID of the persistent gathering to associate with the matchmaking session. All other settings have no difference from regular matchmaking.
Registering a persistent gathering matchmaking session increments the persistent gathering matchmaking session count. You can get the count from the PersistentGathering::GetMatchmakeSessionCount
function. (When the session is deleted, the count is decremented.)
Comments
To associate a persistent gathering with a matchmaking session in NEX 3.7 and earlier, you had to set the matchmaking system type to MATCHMAKE_SYSTEM_TYPE_PERSISTENT_GATHERING
and set the ID of the persistent gathering to associate as the 0th attribute when registering a matchmaking session. To maintain compatibility in NEX 3.8 and later, set the matchmaking system type to MATCHMAKE_SYSTEM_TYPE_PERSISTENT_GATHERING
and set the ID of the persistent gathering to associate as the 0th attribute. To automatically set the 0th attribute of new matchmaking sessions to the ID of the persistent gathering to associate when they are registered on the server, specify INVALID_GATHERINGID
as the ID of the persistent gathering to associate. Call the MatchmakeSession::SetReferPersistentGatheringId
function on matchmaking sessions retrieved from the server to get the ID of the associated persistent gathering. The number of persistent gathering matchmaking sessions being held is also counted.
If you are ranking users in a persistent gathering (by using a community ranking), you can use the gathering ID of the persistent gathering as the category. However, it is not possible to use the same categories as in regular ranking. If your persistent gathering uses the 0th to 10th categories for regular ranking, try to ensure that the persistent gathering rankings are assigned to the 11th and later slots.
Persistent gatherings can be created, edited, and deleted using the persistent gathering management functions in the NEX Server Management System (NMAS). The tool supports both the development environment and the production environment.
Use the following URL to access NMAS.
https://nmas.app.nintendowifi.net/nmas/
Use the same login ID and password that you use for OMAS.
A notification event is a message that is sent from a game server to another client when a particular event occurs on the game server. When a client joins a matchmaking session, for example, a message notifies the other clients that have already joined that session.
For a client process to receive notification events, RendezVous::RegisterNotificationEventHandler
must register a NotificationEventHandler
with the client process after it has logged in to the game server. Each time the client process receives a notification event after the handler has been registered, the event is sent to the handler and the ProcessNotificationEvent
system callback is invoked. Although this callback ignores all received notification events by default, you can customize how notification events are processed by sub-classing NotificationEventHandler
and re-implementing the system callbacks.
The following values are passed to the ProcessNotificationEvent
system callback: the principal ID of the client that generated the event, the event type, and a NotificationEvent
class object that stores up to three parameters. NEX uses the following event types (which can be obtained with NotificationEvent::GetType
).
NotificationEvents::ParticipationEvent
: The owner of a matchmaking session is notified when clients join, leave, or is disconnected from the matchmaking session. The default functionality is for the owner of the matchmaking session to be notified. Use GatheringFlags::NotifyParticipationEventsToAllParticipants
to change this, and notify all participants. A value from the ParticipationEvents
enumerated type is set as the subtype, indicating which event occurred: whether a client joined, left, or was disconnected. You can also get the matchmaking session ID with NotificationEvent::GetParam1
; the principal ID of the client that joined, left, or disconnected with NotificationEvent::GetParam2
; and detailed information when clients join or leave a session with NotificationEvent::GetStringParam
.NotificationEvents::OwnershipChangeEvent
: This notification is sent to all of the participants of a matchmaking session when ownership of the session is transferred from one client to another. Get the matchmaking session ID with NotificationEvent::GetParam1
and the principal ID of the new owner with NotificationEvent::GetParam2
.NotificationEvents::GatheringUnregistered
: When a matchmaking session is deleted, all of its participants are notified. Get the matchmaking session ID with the NotificationEvent::GetParam1
function.NotificationEvents::HostChangeEvent
: When host information for matchmaking session P2P communication is updated, the previous host is notified. Get the matchmaking session ID with the NotificationEvent::GetParam1
function.NotificationEvents::GameNotificationEvent
1–8: Presence events that games can use independently.When the MatchmakeExtensionClient::UpdateNotificationData
function is run, a notification event is sent to friends who are logged in to the same game server. For more information, see 4.20. Using Game-Specific Notification Events.NotificationEvents::GameNotificationLogout
: This notification is sent to friends when a user logs out from the game server if the application has set game-defined events. Non-explicit logout actions, such as when the system is powered down, are included.NotificationEvents::GameServerMaintenance
: Signifies the start of game server maintenance. For more information, see 4.21. Handling Game Server Maintenance Notification Events.NotificationEvents::MaintenanceAnnouncement
: Signifies a game server maintenance announcement. For more information, see 4.21. Handling Game Server Maintenance Notification Events.NotificationEvents::AddedToGathering
: Event to notify the local host that it has been added to a gathering. Get the added gathering ID with the NotificationEvent::GetParam1
function and the principal ID of the added user (that is, the principal ID of the local station) with the NotificationEvent::GetParam2
function. The NotificationEvent::GetStringParam
function gets the join message specified when the user that triggered the event joined the session. You can use NotificationEvent::GetSource
to get the principal ID of the user who called RMC.Code 4.9. Subclassing NotificationEventHandler
// Event handler for getting notifications from NGS.
class MyNotificationEventHandler : public NotificationEventHandler {
public:
void ProcessNotificationEvent(const NotificationEvent &oEvent){
switch (oEvent.GetType())
{
case NotificationEvents::ParticipationEvent:
switch (oEvent.GetSubType())
{
case ParticipationEvents::Participate:
NN_LOG("%u join %u\n", oEvent.GetParam2(), oEvent.GetParam1());
break;
case ParticipationEvents::EndParticipation:
NN_LOG("%u end %u\n", oEvent.GetParam2(), oEvent.GetParam1());
break;
case ParticipationEvents::Disconnect:
NN_LOG("%u disconnect %u\n", oEvent.GetParam2(), oEvent.GetParam1());
break;
default:
NN_LOG("unspoorted participation event\n");
break;
}
break;
case NotificationEvents::OwnershipChangeEvent:
NN_LOG("matchmakesession %u changed owner to %u\n", oEvent.GetParam1, oEvent.GetParam2());
break;
case NotificationEvents::GameNotificationEvent1:
NN_LOG("game specific event 1\n");
break;
case GameServerMaintenance:
NN_LOG("game server maintenance event\n");
break;
default:
NN_LOG("unsupported notification event\n");
break;
}
}
};
Games can independently define notification events and send them to friends who are logged in to the same game server. For more information about how these notification events are handled when they are received, see 4.19. Handling Notification Events. This feature has been designed to account for the server, and assumes that implementations send events from users to their communication partners. Do not send events more often than that. Specifically, this feature has the following restrictions.
NotificationEvents::GameNotificationEvent
1–8 as the game-defined event types.Use the MatchmakeExtensionClient::UpdateNotificationData
function to notify friends of game-specific events. This function takes the following arguments: a pointer to a ProtocolCallContext
object, a notification type, and notification data defined independently by a game (two qUnsignedInt32
values and a single string of up to 256 characters). To prevent notification types from overlapping with the system-defined event types, set the values between NotificationEvents::GameNotificationEvent1
and NotificationEvents::GameNotificationEvent8
. When a client disconnects from the game server, every notification event that it registered is automatically deleted from the game server.
Use the MatchmakeExtensionClient::GetFriendNotificationData
function to get friend notification events that have already been registered. This function takes the following arguments: a pointer to a ProtocolCallContext
object, a pointer to a qList
<NotificationEvent
> that stores the asynchronous processing results, and the type of notification to get.
Comments
Use this function only when a client logs in, and then handle notification events while the client is logged in.
The client can be programmed to handle notification events that are triggered when game server maintenance is announced or begins. By handling these events, you can tell users that maintenance is about to start. The maintenance announcement and start events are sent to all terminals logged in to the game server. If a client connects after the announcement or start event has already been sent, the event is sent to the client after login.
WebAPI can be used to set whether a notification is made for the start of maintenance. The default is false
. This stops accepting new matchmaking, regardless of whether clients sent the notification. For details, see enable_maintenance_notification
in the changing matchmaking session settings(Section 12.2.2.9). Maintenance announcement events are only sent for the titles configured to do so. Contact Nintendo if you want to use the maintenance announcement event.
Figure 4.1. Maintenance Workflow and Notification Events
NotificationEvents::MaintenanceAnnouncement
event is sent.NotificationEvent::GetParam1
function takes the maintenance start time in Unix Epoch Time. The server maintenance start time can be retrieved using the DataTime::FromUnixEpochTime
function of the DataTime
class.The time in the event is in UTC. Note that in emergency situations it might not be possible to make the maintenance announcement one hour in advance.
If enable_maintenance_notification
is enabled in the WebAPI matchmaking session configuration when the game server maintenance starts, NotificationEvents::GameServerMaintenance
is sent as a start notification. After the event is sent, perform the following actions to stop the game server from receiving new matchmaking requests.
Then, stop the game server around five to ten minutes later to perform the maintenance.
If matchmaking does not complete within five to ten minutes, the following kinds of actions are available. Determine the best solution for the specifications of your game.
NotificationEvents::GameServerMaintenance
event is received.The messaging feature provides a general way for clients to exchange text and binary messages. Using reliable communication, instant messages are sent to specified users by using the game server. Messages can only be sent to users who are logged in to the game server.
This feature (including the server) was designed on the assumption that it will be used to send messages between users. Do not send messages more frequently than that. Specifically, this feature has the following restrictions.
Use the MessagingClient::SendInstant
function to send a message to a particular client. This function takes the following arguments: a pointer to a ProtocolCallContext
object, the principal ID of the recipient client, and a UserMessageDataHolder
object holding a pointer to a UserMessage
(or TextMessage
or BinaryMessage
) object. (See Code 4.10.)
Use the MessagingClient::SendChat
function to send a message to all the clients that have joined a particular matchmaking session. This function takes the following arguments: a pointer to a ProtocolCallContext
object, the matchmaking session ID of the recipient client, and a UserMessageDataHolder
object holding a pointer to a UserMessage
(or TextMessage
or BinaryMessage
) object.
Comments
The asynchronous call returns success when the message reaches the game server. It is not possible to tell whether the message actually reached the recipient from the result of the asynchronous call. If a message reaches the game server, it is guaranteed to reach the recipient, providing the recipient is connected to the game server.
Note
The MessageClient::SendChat
function supports up to 32 connected clients. Contact Nintendo if you want to use this function with more than 32 clients.
Code 4.10. Sample Code for Sending a Text Message
void SendInstantMessage(MessagingClient *pMessagingClient, PrincipalID target, const String& message)
{
TextMessage *pTextMessage = qNew TextMessage();
UserMessageDataHolder oDataHolder = pTextMessage;
// Set the message.
pTextMessage->SetTextBody(message);
ProtocolCallContext oContext;
if(pMessagingClient->SendInstant(&oContext, pid, oDataHolder))
{
oContext.Wait();
if(oContext.GetState() != CallContext::CallSuccess)
{
// Error handling.
}
}
else
{
// Error handling.
}
}
For a client to receive messages, the MessagingClient::RegisterMessagingNotificationHandler
function must register a MessagingNotificationHandler
with the client process after the MessagingClient::Bind
function is run. Each time the client receives a notification message after the handler is registered, the message is sent to the handler and the DeliverInstantMessage
callback is invoked. To customize how messages are processed, make MessagingNotificationHandler
into a subclass and re-implement the system callback. (For more information, see Code 4.11.)
In the DeliverInstantMessage
callback, use the DataHolder::Get
function to get the stored message. Use DynamicCast
to determine whether the message is an instance of the UserMessage
, TextMessage
, or BinaryMessage
concrete class.
For example, use the TextMessage::DynamicCast
function to tell if the message can be dynamically cast to a TextMessage
object. Similarly, use the BinaryMessage::DynamicCast
function to tell if it is a BinaryMessage
object.
The following example shows a messaging notification handler that determines the type of the message object.
Code 4.11 Making MessagingNotificationHandler
a Subclass
class MyMessagingNotificationHandler: public MessagingNotificationHandler
{
public:
// Overridden from MessagingNotificationHandler.
void DeliverInstantMessage(const DataHolder& hMsg)
{
if (TextMessage::DynamicCast(hMsg.Get()))
{
// If TextMessage::DynamicCast succeeds, a TextMessage object is received.
TextMessage* pTextMsg = static_cast<TextMessage*>( hMsg.Get() );
NN_LOG("from:%u message:%ls \n", pTextMsg->GetSenderID() ,pTextMsg->GetTextBody().CStr());
}
else if (BinaryMessage::DynamicCast(hMsg.Get()))
{
// If BinaryMessage::DynamicCast succeeds, a BinaryMessage object has been received.
BinaryMessage* pBinaryMsg = static_cast<BinaryMessage*>( hMsg.Get() );
NN_LOG("from:%u size:%u \n", pBinaryMsg->GetSenderID() ,pBinaryMsg->GetBufferSize());
}
};
When the current host of a P2P communication session leaves the session, NetZ automatically migrates the host to another participant. Matchmaking sessions record the host information for the P2P communication, and this is cleared when the host leaves the matchmaking session. Host information is required to join the P2P session. Update it as needed. If the host migration extension is being used when the P2P session host is migrated, the game server is notified of that fact, and the information for the matchmaking session P2P communication host is updated. When using the host migration extension feature, the MatchMakingClient::UpdateSessionHost
function is called appropriately for the corresponding matchmaking session when the session host is migrated. The following procedure shows how to use the host migration extension package.
#use <NetZ/src/Core/HostMigration/HostMigrationExt.ddl>
to the .ddl
file.HostMigrationExtension::Register
function after NetZ objects are generated.HostMigrationCallback
by using the generated MatchmakeExtensionClient
and the callback function that is called when host migration occurred — normally either the MatchmakingClient::StaticUpdateSessionHost
or the MatchmakingClient::StaticUpdateSessionHostWithOwner
function.HostMigrationCallback::Register
function.The flowchart in Figure 4.2 shows the sequence of events that starts when a matchmaking session is registered and ends when the host is migrated. If the P2P session ends normally, leave the matchmaking session immediately.
When a client that is not the host is isolated from a P2P session, a host migration occurs with the approval of at least one client that is not the local host. However, if there are only two people in a session and the stations are lost because of an abnormal state by a timeout or other event occurring, since it is unknown whether that client should be promoted to the host, the call to the MatchMakingClient::UpdateSessionHost
function is not made. This state is called isolation and is determined by the HostMigrationCallback::SessionHostIsOrphan
function. If a client is determined to be isolated, have it leave the matchmaking session. If there are only two players in a session when one terminal leaves normally (by using the NetZ::Terminate
function without specifying the NetZ::SetTerminateImmediately
function), an isolated state is not determined. If the host leaves, host migration occurs.
The game can continue because host migration takes place even when clients become isolated, but other clients cannot join the P2P session because a matchmaking session in which the host can join from the outside does not exist. Register a new matchmaking session so that other clients can join. Also, you must destroy the HostMigrationCallback
object, create a new HostMigrationCallback
object, and register a new ID.
Comments
If the host is migrated and the game server is not notified of the new host, the MatchMakingClient::GetSessionURLs
function returns the URL of the previous host (prior to the migration). You must use the host migration extension feature to allow other clients to join the P2P session even after the host has left.
Comments
If your ROM uses both Internet and local communication modes and uses the host migration extension feature when in Internet communication mode, you can skip calling the HostMigrationExtension::Register
function by calling the HostMigrationExtension::Disable
function.
Figure 4.2. Processing Flow From Matchmaking Session Registration to Host Migration
The MatchmakeReferee
feature records results fairly by summarizing match reports sent by clients and checking them all together. This record is called personal statistics.
Personal statistics include the following.
Items other than report mismatches are updated based on the content of reports sent from clients.
The default recording unit is by principal ID, but statistics can be recorded in finer units by registering a NEX unique ID as a primary associated NEX unique ID.
For more information, see Section 11.2 Using NEX Unique IDs With the MatchmakeReferee Feature.
The default functionality if a NEX unique ID is not used is to use the principal ID internally as the primary associated NEX unique ID.
NgsFacade::Login
function.UtilityClient::AcquireNexUniqueIdWithPassword
function.UtilityClient::AssociateNexUniqueIdWithMyPrincipalId
function to declare the primary associated NEX unique ID to be used.MatchmakeRefereeClient::GetOrCreatePersonalStats
function to get or create personal statistics.MatchmakeRefereeClient::GetNotSummarizedRound
function as needed to check whether there is a round that is not summarized yet.MatchmakeRefereeClient::StartRound
function. NotificationEvents::RoundStarted
notifications are sent to round participants, who can get the personal statistics of opponents by calling the MatchmakeRefereeClient::GetStats
function as necessary.MatchmakeRefereeClient::EndRoundWithoutReport
function. MatchmakeRefereeClient::EndRound
function to report the round results for all users as a qVector< MatchmakeRefereePersonalRoundResult >
.NotificationEvents::RoundSummarized
) and display the round results.Comments
If personal statistics are being managed in units of principal IDs, steps 1, 3, and 4 are not needed.
Summarizing the report on the server is done after the reports from all round participants are received (including empty reports from calls to MatchmakeRefereeClient::EndRoundWithoutReport
), or one minute after the first report is received (not including empty reports from calls to MatchmakeRefereeClient::EndRoundWithoutReport
).
The MatchmakeRefereeClient::EndRoundWithoutReport
function is called to allow summarizing to start without having to wait for the one-minute timeout. The feature still works even if this function is not called, but processing to summarize starts late. Make sure to call it in any situation where you cannot call MatchmakeRefereeClient::EndRound
, such as when withdrawing during the round.
In the report summarizing process on the server, the reports sent (qVector< MatchmakeRefereePersonalRoundResult >
) are checked to verify that they match with reports sent by other round participants. The concordance check of qVector
<MatchmakeRefereePersonalRoundResult
> is conducted between those with matching MatchmakeRefereePersonalRoundResult
PIDs. The order of MatchmakeRefereePersonalRoundResult
within qVector
does not need to match between the reports sent by each user. If the data from more than half of the reports matches, that data is used as the final result. This process is called normalization.
The normalized report is held on the server for one hour. You can get the normalized report by calling the MatchmakeRefereeClient::GetRound
function. The personal statistics linked to the primary associated NEX unique ID are updated based on the normalized report. The personal statistics are persistent data. You can get the personal statistics by using the MatchmakeRefereeClient::GetStats
function. For more information about personal statistics, see MatchmakeRefereeStats
.
In the following cases, the round is considered invalid and the personal statistics are not updated.
MatchmakeRefereeClient::EndRoundWithoutReport
function.Asynchronous functions that communicate with the game server could return false
for the following reasons.
CallContext
object was passed as an argument while it was being used by another asynchronous process.ServiceClient::Bind
function has not been run.All asynchronous functions check these reasons in the listed order. Although (1) and (2) are program errors, (3) is caused by the network state. You must log in to the game server again to restore communication with it from this state. For this reason, display the error message "A communication error has occurred" and then shut down communication. For more information, see Code 4.12 Sample Error Handling.
You can get asynchronous processing results with the CallContext::GetOutcome
function. The API Reference Manual describes errors that must be handled by the application for each function. If an undocumented error occurs, use the following code to get the network error code with the ErrorCodeConverter::ConvertToNetworkErrorCode
function, pass the error code to the error/EULA applet, and then shut down communication (Code 4.12).
Code 4.12. Sample Error Handling
MatchmakeExtensionClient client;
ProtocolCallContext context;
// Error handling for function calls.
if(!client.JoinMatchmakeSession(&context, gid, _T("join message")))
{
// A CallContext was passed in while it was still being processed.
NN_ASSERT(context.GetState() != CallContext::CallInProgress);
// Bind has not been run.
NN_ASSERT(client.GetCredentials() != NULL);
// Other, such as the network is not connected.
// Display the message "A communication error occurred." (The error code is unnecessary.)
// Log out and shut down.
}
// Error handling for asynchronous processing.
context.Wait(); //Block and wait here.
if(context.GetState() != CallContext::CallSuccess)
// Note: To cancel the context, you must also make a comparison with CallContext::CallCancelled.
{
qResult result = context.GetOutcome();
// Errors that must be handled by the application.
if(result == QERROR(RendezVous, SessionVoid))
{
// There is no matchmaking session.
}
else if(result == QERROR(RendezVous, SessionFull))
{
// The matchmaking session is full.
}
else
{
u32 code = ErrorCodeConverter::ConvertToNetworkErrorCode(result);
// Start the error/EULA applet.
// Log out and shut down.
}
}
CONFIDENTIAL