Tutorial 165: Friends, presence and gamer pictures
What you’ll learn: how to publish rich presence, read the friends list, open the Guide's social pages, load gamer pictures, and how privileges, privacy and blocking work with a server account.
Status: everything on this page needs a server account: a CNA Gamer Services server configured as in Tutorial 164 and a player signed in to it. Local offline profiles refuse these calls with XNA’s exceptions. The code follows CNA’s headers at snapshot b0e97bb1 and was not compiled or run for this page.
What each feature needs
| Feature | API | Local profile (no server) | Server account |
|---|---|---|---|
| Rich presence | SignedInGamer::getPresenceProperty() | Settable, never published | Sent to the server during the dispatcher update |
| Friends list | GetFriends(), IsFriend(gamer) | GamerPrivilegeException | A snapshot read from the server |
| Friends, messages, gamer cards, party, reviews | Guide::ShowFriends, ShowMessages, ShowComposeMessage, ShowGamerCard, ShowFriendRequest, ShowParty, ShowPlayers, ShowPlayerReview | GamerServicesNotAvailableException | Guide pages |
| Profile | Gamer::GetProfile() | Local totals only | Score, zone, reputation, picture |
| Gamer picture | GamerProfile::GetGamerPicture() | nullptr | A PNG stream, or nullptr if none is set |
| Look up a gamertag | Gamer::GetFromGamertag | NotSupportedException | A caller-owned Gamer* |
Test getIsSignedInToLiveProperty() before calling the social APIs: it is false for local profiles and guests and true for an account.
1. Publish rich presence
XNA’s Presence property returns an object the game changes in place; CNA keeps that shape with a mutable overload (a CNA extension of the C++ accessor):
#include "Microsoft/Xna/Framework/GamerServices/GamerPresenceMode.hpp"
#include "Microsoft/Xna/Framework/GamerServices/SignedInGamer.hpp"
using namespace Microsoft::Xna::Framework;
using namespace Microsoft::Xna::Framework::GamerServices;
// when the player reaches level 3
GamerPresence& presence = player->getPresenceProperty();
presence.setPresenceModeProperty(GamerPresenceMode::Level);
presence.setPresenceValueProperty(3); // friends read it as text, for example "Level 3"
The change is sent at the next GamerServicesDispatcher::Update, not at the setter. A friend counts as online while their game has shown authenticated activity in the last 90 seconds; every running game sends a heartbeat every 30 seconds, so a friend who quits without signing out still shows online for up to 90 seconds. Away and busy are exactly what the player chose in the Guide’s settings; CNA never infers them from inactivity.
2. Read the friends list
#include "Microsoft/Xna/Framework/GamerServices/FriendCollection.hpp"
#include "Microsoft/Xna/Framework/GamerServices/FriendGamer.hpp"
#include <string>
#include <vector>
// when the friends menu opens, not every frame
std::vector<std::string> lines;
if (player->getIsSignedInToLiveProperty())
{
FriendCollection friends = player->GetFriends(); // asks the server and waits for the answer
for (FriendGamer* f : friends)
{
if (f->getFriendRequestReceivedFromProperty())
lines.push_back(f->getGamertagProperty() + " wants to be friends");
else if (f->getIsOnlineProperty())
lines.push_back(f->getGamertagProperty() + " " + f->getPresenceProperty() +
(f->getIsJoinableProperty() ? " (joinable)" : ""));
}
}
The collection holds accepted friends and pending requests in either direction (getFriendRequestSentToProperty(), getFriendRequestReceivedFromProperty()), with each friend’s online, away, busy and playing state, presence text, whether their session can be joined, invitation flags and getHasVoiceProperty(). It is a snapshot owned by the collection; read it again to see changes. By the source, GetFriends and IsFriend send a request to the server on every call and wait for it, so call them when a menu opens or on a timer, not every frame. A request the server cannot answer throws GamerServicesNotAvailableException.
CNA’s header comment for GetFriends still describes an empty collection; the implementation at this snapshot reads the server for accounts and throws GamerPrivilegeException for local profiles, as described here.
3. Let the Guide do the social work
XNA has no API to read or send messages, accept friend requests or review players: the console’s Guide did that, and CNA’s Guide does it here. A game opens the right page and the player takes it from there:
Guide::ShowFriends(player): friends, pending requests and adding a friend by gamertag.Guide::ShowGamerCard(player, gamer): the gamer’s avatar, score, zone, reputation, presence and relationship, with join, invite, message, review, mute, friend-request and block actions.ShowFriendRequestopens the same card leading with the request.Guide::ShowMessages(player)andShowComposeMessage(player, text, recipients): CNA server messages.ShowPlayerReviewrecords prefer or avoid;ShowPlayerslists recent players;ShowPartymanages a party of up to eight friends.
The Guide also shows toasts for a new message, a friend request, a friend coming online and invitations. A signed-in game keeps one authenticated WebSocket per account to the server’s event channel, which sends only “something changed” hints; the client then re-reads the real state. Polling remains the fallback — invitations and parties every 5 seconds, messages and friends every 15 — and CNA_GAMER_SERVICES_EVENTS=0 turns the channel off.
4. Profiles and gamer pictures
#include "Microsoft/Xna/Framework/GamerServices/GamerProfile.hpp"
#include "Microsoft/Xna/Framework/Graphics/Texture2D.hpp"
#include <memory>
std::unique_ptr<GamerProfile> profile(player->GetProfile()); // caller-owned; waits for the server
std::unique_ptr<System::IO::Stream> png(profile->GetGamerPicture()); // caller-owned, or nullptr
if (png)
picture_ = std::make_unique<Graphics::Texture2D>(
Graphics::Texture2D::FromStream(getGraphicsDeviceProperty(), *png));
BeginGetProfile/EndGetProfile avoid the wait; their result completes during the dispatcher update. Some profile fields are CNA’s own policy, because XNA exposes only the values:
- Gamer picture: set by the operator (
cna-gamer-services-admin <db> picture), a PNG of at most 512×512 pixels and 512 KiB. Downloads are verified by SHA-256 and cached in$XDG_CACHE_HOME/cna/gamer-services/assets(256 MiB, least recently used first;CNA_GAMER_SERVICES_CACHE_DIRmoves it), and access is checked again before a cached picture is served. - Gamer zone is what the member chose in the Guide. Reputation is computed from real player reviews as 5 × prefer / (prefer + avoid), rounded to the nearest quarter star; a member nobody has reviewed reports 0, XNA’s unset value.
- Motto is empty and region is “US”: there is no way to set them.
Gamer::GetFromGamertag(tag) looks another member up and returns a Gamer* the caller owns, which can be passed to ShowGamerCard or GetProfile.
5. Privileges, privacy and blocking
XNA’s GamerPrivileges came from the console’s parental controls. On CNA the operator sets them per account (cna-gamer-services-admin <db> privilege <user> communication friends, for example), the player learns them at sign-in, and current values and blocks are refreshed with the heartbeat:
- The server enforces
AllowCommunicationon messages, game and party invitations, join requests and friend requests, andAllowProfileViewingon reading another member’s profile. Voice followsAllowCommunicationon the client. ShowComposeMessageandShowGameInvitethrowGamerPrivilegeExceptionwhen communication isBlocked, andShowGamerCardof another gamer does when profile viewing is. That Xbox refused exactly these calls is inferred from XNA’s code and documentation, not observed on a console.- A member can block another from the gamer card. A block works both ways: it ends the friendship, withdraws invitations, refuses messages, requests and profile reads, hides each one’s sessions from the other’s searches and mutes voice between them.
AllowUserCreatedContent,AllowTradeContentandAllowPremiumContentare reported but restrict nothing in CNA; a game may read them, as XNA intended.
Evidence and qualification
- CNA’s final audit run of this work (2 October 2026, Linux): the GamerServices suite 649 passed and the Net suite 524 passed, with no failures; the server’s 40 registered tests: 33 passed, 7 network-isolation tests skipped for lack of a test tool, none failed. The passing server tests drive Guide sign-in, social flows, pictures and rich presence through the standard XNA API, and the server’s privacy checks. These are CNA-recorded runs; this site did not re-run them.
- The timings above (90-second online window, 30-second heartbeat, polling intervals) are CNA’s policy; the console’s timing is not documented and is not claimed.
- Not qualified: Windows and macOS, a real wide-area network with NAT, voice on physical audio devices, and avatar pixels on Direct3D and Metal. Public-Internet deployment of the server has not been independently qualified.
- Browser builds have no service, relay or voice, so nothing on this page is available there.
Next
Invite those friends into a game with Tutorial 166. Back to Tutorial 164 for the server connection, or to the Gamer Services overview.