booldone=false;autologinFailedCallback=[&done](constNError&error){cout<<"Failed to login"<<endl;cout<<error.message<<endl;done=true;};autologinSucceededCallback=[&done,&rtClient](NSessionPtrsession){cout<<"Login successful"<<endl;cout<<session->getAuthToken()<<endl;rtClient->connect(session,true);};stringdeviceId="e872f976-34c1-4c41-88fe-fd6aef118782";client->authenticateDevice(deviceId,opt::nullopt,opt::nullopt,{},loginSucceededCallback,loginFailedCallback);
autoerrorCallback=[](constNError&error){cout<<"An error occurred: "<<error.message<<endl;if(error.code==ErrorCode::ConnectionError){cout<<"The server is currently unavailable. Check internet connection."<<endl;}};client->getAccount(session,successCallback,errorCallback);
// Typically you would get the system's unique device identifier here.
stringdeviceId="e872f976-34c1-4c41-88fe-fd6aef118782";autologinFailedCallback=[&done](constNError&error){cout<<"An error occurred: "<<error.message<<endl;};autologinSucceededCallback=[&done,&rtClient](NSessionPtrsession){cout<<"Successfully authenticated: "<<session->getAuthToken()<<endl;};// Authenticate with the Nakama server using Device Authentication.
client->authenticateDevice(deviceId,opt::nullopt,opt::nullopt,{},loginSucceededCallback,loginFailedCallback);
// Authenticate with the Nakama server using Facebook Authentication.
stringaccessToken="<Token>";boolimportFriends=true;client->authenticateFacebook(accessToken,"mycustomusername",true,importFriends,{},loginSucceededCallback,loginFailedCallback);
autolinkSuccessCallback=[](){cout<<"Successfully linked Device ID authentication to existing player account"<<endl;};autolinkErrorCallback=[](constNError&error){cout<<"Error linking Device ID: "<<error.message<<endl;};// Link Device Authentication to existing player account.
client->linkDevice(session,deviceId,linkSuccessCallback,linkErrorCallback);
链接Facebook身份验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
autolinkSuccessCallback=[](){cout<<"Successfully linked Facebook authentication to existing player account"<<endl;};autolinkErrorCallback=[](constNError&error){cout<<"Error linking Facebook: "<<error.message<<endl;};client->linkFacebook(session,accessToken,importFriends,linkSuccessCallback,linkErrorCallback);
// Check whether a session has expired or is close to expiry.
if(session->isExpired()||session->isExpired(time(0)+24\*60\*60)){autorefreshSuccessCallback=[](NSessionPtrsession){cout<<"Session successfully refreshed"<<endl;};autorefreshErrorCallback=[](constNError&error){// Couldn't refresh the session so reauthenticate.
// client->authenticateDevice(...)
};// Refresh the existing session
client->authenticateRefresh(session,refreshSuccessCallback,refreshErrorCallback);}
autosuccessCallback=[](constNAccount&account){stringusername=account.user.username;stringavatarUrl=account.user.avatarUrl;stringuserId=account.user.id;};autoerrorCallback=[](constNError&error){cout<<"Failed to get user account: "<<error.message<<endl;};client->getAccount(session,successCallback,errorCallback);
autosuccessCallback=[](constNStorageObjectAcks&storageObjectAcks){cout<<"Success writing storage object"<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error writing storage object: "<<error.message<<endl;};hatsStorageObjectfavoriteHats{{"cowboy","alien"}};jsonj;j["hats"]=favoriteHats.hats;NStorageObjectWritewriteObject{collection:"favorites",key:"hats",value:j.dump(),permissionRead:NStoragePermissionRead::OWNER_READ,// Only the server and owner can read
permissionWrite:NStoragePermissionWrite::OWNER_WRITE// The server and owner can write
};client->writeStorageObjects(session,{writeObject},successCallback,errorCallback);
// Assuming we already have a storage object (storageObject).
NStorageObjectWritewriteObject{collection:"favorites",key:"hats",value:"<NewJsonValue>",permissionRead:NStoragePermissionRead::OWNER_READ,// Only the server and owner can read
permissionWrite:NStoragePermissionWrite::OWNER_WRITE,// The server and owner can write
version:storageObject.version};client->writeStorageObjects(session,{writeObject},successCallback,errorCallback);
// Subscribe to the Status event.
NRtDefaultClientListenerlistener;rtClient->setListener(&listener);listener.setStatusPresenceCallback([](constNStatusPresenceEvent&statusPresenceEvent){for(NUserPresencepresence:statusPresenceEvent.joins){cout<<presence.username<<" is online with status: "<<presence.status<<endl;}for(NUserPresencepresence:statusPresenceEvent.leaves){cout<<presence.username<<"went offline"<<endl;}});// Follow mutual friends and get the initial Status of any that are currently online.
autosuccessCallback=[&rtClient](NFriendListPtrfriendList){autofollowSuccessCallback=[](constNStatus&status){for(NUserPresencepresence:status.presences){cout<<presence.username<<" is online with status: "<<presence.status<<endl;}};autofollowErrorCallback=[](constNRtError&error){cout<<"Error following friends: "<<error.message<<endl;};for(NFriendf:friendList->friends){rtClient->followUsers({f.user.id},followSuccessCallback,followErrorCallback);}};autoerrorCallback=[](constNError&error){cout<<"Error listing friends: "<<error.message<<endl;};// Follow mutual friends and get the initial Status of any that are currently online.
client->listFriends(session,1000,NFriend::State::FRIEND,"",successCallback,errorCallback);
autosuccessCallback=[](){cout<<"Successfully updated status"<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error updating status: "<<error.message<<endl;};rtClient->updateStatus("Viewing the Main Menu",successCallback,errorCallback);
autosuccessCallback=[](constNGroup&group){cout<<"Successfully created group: "<<group.id<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error creating group: "<<error.message<<endl;};stringname="Imposters R Us";stringdescription="A group for people who love playing the imposter.";stringavatarUrl="";stringlangTag="";boolopen=true;// public group
intmaxSize=100;client->createGroup(session,name,description,avatarUrl,langTag,open,maxSize,successCallback,errorCallback);
autosuccessCallback=[&session](NGroupListPtrgroupList){for(NGroupgroup:groupList->groups){cout<<group.name<<": "<<(group.open?"Public":"Private")<<endl;}// Get the next page of results using groupList->cursor.
};autoerrorCallback=[](constNError&error){cout<<"Error listing groups: "<<error.message<<endl;};intlimit=20;stringcursor="";client->listGroups(session,"imposter%",limit,cursor,successCallback,errorCallback);
autosuccessCallback=[&client](NGroupUserListPtrgroupUserList){for(NGroupUsergroupUser:groupUserList->groupUsers){client->addGroupUsers(session,"<GroupId>",{groupUser.user.id},nullptr,nullptr);}};autoerrorCallback=[](constNError&error){cout<<"Error listing group users: "<<error.message<<endl;};autolimit=opt::nullopt;NUserGroupStatestate=NUserGroupState::JOIN_REQUEST;stringcursor="";client->listGroupUsers(session,"",limit,state,cursor,successCallback,errorCallback);
autosuccessCallback=[](){cout<<"Successfully promoted group users"<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error promoting group users: "<<error.message<<endl;};client->promoteGroupUsers(session,"<GroupId>",{"<UserId>"},successCallback,errorCallback);
autosuccessCallback=[](){cout<<"Successfully demoted group users"<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error demoting group users: "<<error.message<<endl;};client->demoteGroupUsers(session,"<GroupId>",{"<UserId>"},successCallback,errorCallback);
autosuccessCallback=[](){cout<<"Successfully kicked group users"<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error kicking group users: "<<error.message<<endl;};client->kickGroupUsers(session,"<GroupId>",{"<UserId>"},successCallback,errorCallback);
autosuccessCallback=[](NChannelPtrchannel){cout<<"Connected to dynamic room channel: "<<channel->id<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error connecting to channel: "<<error.message<<endl;};stringroomName="<MatchId>";boolpersistence=false;boolhidden=false;rtClient->joinChat(roomName,NChannelType::ROOM,persistence,hidden,successCallback,errorCallback);
autosuccessCallback=[](NChannelPtrchannel){cout<<"Connected to group channel: "<<channel->id<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error connecting to channel: "<<error.message<<endl;};stringgroupId="<GroupId>";boolpersistence=false;boolhidden=false;rtClient->joinChat(groupId,NChannelType::GROUP,persistence,hidden,successCallback,errorCallback);
autosuccessCallback=[](NChannelPtrchannel){cout<<"Connected to direct message channel: "<<channel->id<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error connecting to channel: "<<error.message<<endl;};stringuserId="<UserId>";boolpersistence=true;boolhidden=false;rtClient->joinChat(userId,NChannelType::DIRECT_MESSAGE,persistence,hidden,successCallback,errorCallback);
autosuccessCallback=[](constNChannelMessageAck&messageAck){cout<<"Successfully sent message: "<<messageAck.messageId<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error sending message: "<<error.message<<endl;};stringchannelId="<ChannelId>";jsonj;j["message"]="I think Red is the imposter!";rtClient->writeChatMessage(channelId,j.dump(),successCallback,errorCallback);jsonj2;j2["emote"]="point";j2["emoteTarget"]="<RedPlayerUserId>";rtClient->writeChatMessage(channelId,j2.dump(),successCallback,errorCallback);
stringchannelId="<ChannelId>";jsonj;j["message"]="I think Red is the imposter!";rtClient->writeChatMessage(channelId,j.dump(),successCallback,errorCallback);
然后改玩家迅速编辑消息来迷惑他人:
1
2
3
4
5
6
autosuccessCallback=[&rtClient](constNChannelMessageAck&messageAck){jsonj;j["message"]="I think BLUE is the imposter!";rtClient->updateChatMessage(messageAck.channelId,messageAck.messageId,j.dump(),nullptr,nullptr);};
autoerrorRtCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error: "<<error.message<<endl;};autolistFriendsSuccessCallback=[&rtClient,&errorRtCallback,&match](NFriendListPtrfriendList){for(NFriendf:friendList->friends){if(!f.user.online){continue;}autojoinChannelSuccessCallback=[&rtClient,&f,&match](NChannelPtrchannel){jsonj;j["message"]="Hey "+f.user.username+", join me for a match!";j["matchId"]=match.matchId;rtClient->writeChatMessage(channel->id,j.dump(),nullptr,nullptr);};boolpersistence=false;boolhidden=false;rtClient->joinChat(f.user.id,NChannelType::DIRECT_MESSAGE,persistence,hidden,joinChannelSuccessCallback,errorRtCallback);}};intlimit=100;NFriend::Statestate=NFriend::State::FRIEND;stringcursor="";client->listFriends(session,limit,state,cursor,listFriendsSuccessCallback,errorCallback);
autosuccessCallback=[](constNMatch&match){cout<<"Successfully joined match: "<<match.matchId<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};stringmatchId="<MatchId>";NStringMapmetadata={{"Region","EU"}};rtClient->joinMatch(matchId,metadata,successCallback,errorCallback);
listener.setMatchmakerMatchedCallback([&rtClient](NMatchmakerMatchedPtrmatchmakerMatched){autosuccessCallback=[](constNMatchmatch){cout<<"Successfully joined match: "<<match.matchId<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};rtClient->joinMatch(matchmakerMatched->matchId,{},successCallback,errorCallback);});autosuccessCallback=[](constNMatchmakerTicket&matchmakerTicket){cout<<"Successfully joined matchmaker: "<<matchmakerTicket.ticket<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};intminPlayers=2;intmaxPlayers=10;stringquery="";NStringMapstringProperties={};NStringDoubleMapnumericProperties={};autocountMultiple=opt::nullopt;rtClient->addMatchmaker(minPlayers,maxPlayers,query,stringProperties,numericProperties,countMultiple,successCallback,errorCallback);
按玩家状态加入比赛
Sagi-shi玩家可以在加入新比赛时更新状态:
1
2
3
4
5
jsonj;j["status"]="Playing a match";j["matchId"]="<MatchID>";rtClient->updateStatus(j.dump(),successCallback,errorCallback);
listener.setStatusPresenceCallback([&rtClient](constNStatusPresenceEvent&statusPresence){for(NUserPresencepresence:statusPresence.joins){autosuccessCallback=[](constNMatch&match){cout<<"Successfully joined match: "<<match.matchId<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};jsonj=json::parse(presence.status);if(j.contains("matchId")){NStringMapmetadata={};rtClient->joinMatch(j["matchId"],metadata,successCallback,errorCallback);}}});
// Assuming a GameObject type
//class GameObject { };
map<string,GameObject*>players={};for(NUserPresenceuserPresence:match.presences){GameObject*gameObject=spawnPlayer();// Instantiate player object
players.insert({userPresence.sessionId,gameObject});}
Sagi-shi使用接收到的比赛显示的在线状态事件,使生成的玩家在离开和加入比赛时保持最新状态:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
listener.setMatchPresenceCallback([&players](constNMatchPresenceEventmatchPresence){// For each player that has joined in this event...
for(NUserPresencepresence:matchPresence.joins){// Spawn a player for this presence and store it in the dictionary by session id.
GameObject*gameObject=spawnPlayer();players.insert({presence.sessionId,gameObject});}// For each player that has left in this event...
for(NUserPresencepresence:matchPresence.leaves){// Remove the player from the game if they've been spawned
if(players.count(presence.sessionId)>0){players.erase(presence.sessionId);}}});
// Assuming a position variable
jsonj;j["x"]=position.x;j["y"]=position.y;j["z"]=position.z;intopCode=1;rtClient->sendMatchData(match.matchId,opCode,j.dump());
listener.setMatchDataCallback([&players](constNMatchData&matchData){switch(matchData.opCode){caseOpCodes::POSITION:{// Get the updated position data
jsonj=json::parse(matchData.data);positionStateposition{j["x"].get<float>(),j["y"].get<float>(),j["z"].get<float>()};// Update the GameObject associated with that player.
if(players.count(matchData.presence.sessionId)>0){// Here we would normally do something like smoothly interpolate to the new position, but for this example let's just set the position directly.
players[matchData.presence.sessionId].position=newVector3(position.x,position.y,position.z);}}default:cout<<"Unsupported opcode";break;}});
autosuccessCallback=[](constNParty&party){cout<<"Successfully created party: "<<party.id<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};boolopen=false;intmaxPlayers=4;rtClient->createParty(open,maxPlayers,successCallback,errorCallback);
listener.setChannelMessageCallback([&rtClient](constNChannelMessage&channelMessage){autosuccessCallback=[](){cout<<"Successfully joined party"<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};jsonj=json::parse(channelMessage.content);if(j.contains("partyId")){rtClient->joinParty(j["partyId"],successCallback,errorCallback);}});
autosuccessCallback=[](){cout<<"Successfully promoted party member"<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};for(NUserPresencepresence:party.presences){if(presence.sessionId!=party.leader.sessionId){rtClient->promotePartyMember(party.id,presence,successCallback,errorCallback);}}
autosuccessCallback=[](){cout<<"Successfully left party"<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};rtClient->leaveParty(party.id,successCallback,errorCallback);
listener.setMatchmakerMatchedCallback([&rtClient](NMatchmakerMatchedPtrmatchmakerMatched){autosuccessCallback=[](constNMatch&match){cout<<"Successfully joined match: "<<match.matchId<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};rtClient->joinMatch(matchmakerMatched->matchId,{},successCallback,errorCallback);});
派对领导者将开始为派对进行匹配:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
autosuccessCallback=[](constNPartyMatchmakerTicket&partyMatchmakerTicket){cout<<"Successfully joined matchmaker as party: "<<partyMatchmakerTicket.ticket<<endl;};autoerrorCallback=[](constNRtError&error){cout<<"Error: "<<error.message<<endl;};intminPlayers=2;intmaxPlayers=10;stringquery="";NStringMapstringProperties={};NStringDoubleMapnumericProperties={};autocountMultiple=opt::nullopt;rtClient->addMatchmakerParty(party.id,query,minPlayers,maxPlayers,stringProperties,numericProperties,countMultiple,successCallback,errorCallback);
autosuccessCallback=[](){cout<<"Successfully joined tournament"<<endl;};autoerrorCallback=[](constNError&error){cout<<"Error: "<<error.message<<endl;};client->joinTournament(session,"<TournamentId>",successCallback,errorCallback);
listener.setNotificationsCallback([](constNNotificationList¬ificationList){constintrewardCode=100;for(NNotificationn:notificationList.notifications){switch(n.code){caserewardCode:cout<<"Congratulations, you won the tournament!"<<endl<<n.subject<<endl<<n.content<<endl;break;default:cout<<"Other notification:"<<endl<<n.subject<<endl<<n.content<<endl;break;}}});