Tutorial 165: Friends, presence and gamer pictures

CNA Tutorials  ·  CNA snapshot b0e97bb1

ℹ

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

FeatureAPILocal profile (no server)Server account
Rich presenceSignedInGamer::getPresenceProperty()Settable, never publishedSent to the server during the dispatcher update
Friends listGetFriends(), IsFriend(gamer)GamerPrivilegeExceptionA snapshot read from the server
Friends, messages, gamer cards, party, reviewsGuide::ShowFriends, ShowMessages, ShowComposeMessage, ShowGamerCard, ShowFriendRequest, ShowParty, ShowPlayers, ShowPlayerReviewGamerServicesNotAvailableExceptionGuide pages
ProfileGamer::GetProfile()Local totals onlyScore, zone, reputation, picture
Gamer pictureGamerProfile::GetGamerPicture()nullptrA PNG stream, or nullptr if none is set
Look up a gamertagGamer::GetFromGamertagNotSupportedExceptionA 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. ShowFriendRequest opens the same card leading with the request.
  • Guide::ShowMessages(player) and ShowComposeMessage(player, text, recipients): CNA server messages. ShowPlayerReview records prefer or avoid; ShowPlayers lists recent players; ShowParty manages 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_DIR moves 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 AllowCommunication on messages, game and party invitations, join requests and friend requests, and AllowProfileViewing on reading another member’s profile. Voice follows AllowCommunication on the client.
  • ShowComposeMessage and ShowGameInvite throw GamerPrivilegeException when communication is Blocked, and ShowGamerCard of 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, AllowTradeContent and AllowPremiumContent are 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.