Skip to main content

Player Names

Every account has a public name: a gamertag, and a disambiguation that makes the pair unique, so two players can share a gamertag as long as their disambiguations differ. A game reads names by User ID, the int64 it already has for every player, and the signed-in player can choose their own. A player who has never chosen a name reads an empty gamertag.

When you touch this​

When you draw a nametag over a player, list the members of a team or a match, or add a Choose Your Name step to the first launch.

The surface​

UCrowdyPlayers (Game Instance subsystem, Crowdy Players, category Crowdy SDK, Players) has three calls, each also a latent node. Names arrive as FCrowdyPlayerProfile: UserID, Gamertag, Disambiguation. A failure carries an FCrowdyAccountError (Code, Message) and the Message, the same error the account settings calls use.

Blueprint (C++)What it does
Get Player Name (GetPlayerName(UserID, OnResult, OnError))One player's name. A User ID with no player fails with Not Found.
Get Player Names (GetPlayerNames(UserIDs, OnResult, OnError))Up to 100 players' names in one call (UCrowdyPlayers::MaxProfilesPerCall); more fails at once without a request, and none answers an empty list. Unknown User IDs are left out of the answer, so match the rows by UserID, not by position.
Set Player Name (SetPlayerName(Gamertag, Disambiguation, OnResult, OnError))Renames the signed-in player and answers the new name. A pair another player has fails with Name Taken. A gamertag is at most 64 characters, a disambiguation at most 128.

The C++ calls answer on FOnPlayerProfileRead (one profile), FOnPlayerProfilesRead (an array) and FOnPlayersError. The nodes are UCrowdyPlayers_GetPlayerName, UCrowdyPlayers_GetPlayerNames and UCrowdyPlayers_SetPlayerName, whose pins are FPlayerProfileAsyncResult (Profile, Error, Message) and, for the batch, FPlayerProfilesAsyncResult (Profiles, Error, Message).

All three need a signed-in player. Any player may read any other player's name, and nothing else about them.

Show a nametag​

When a player appears, read their name by User ID and put the gamertag on their nametag.

// LanternGameInstance.h
#include "Subsystem/CrowdyPlayers.h"

public:
// A nametag asks for its player's name when the player appears.
void ShowNametag(int64 UserId);

UFUNCTION()
void HandleNametag(FCrowdyPlayerProfile Profile);

UFUNCTION()
void HandlePlayersFailed(FCrowdyAccountError Error, FString Message);

// LanternGameInstance.cpp
void ULanternGameInstance::ShowNametag(int64 UserId)
{
FOnPlayerProfileRead Read;
Read.BindDynamic(this, &ULanternGameInstance::HandleNametag);
FOnPlayersError Failed;
Failed.BindDynamic(this, &ULanternGameInstance::HandlePlayersFailed);
GetSubsystem<UCrowdyPlayers>()->GetPlayerName(UserId, Read, Failed);
}

void ULanternGameInstance::HandleNametag(FCrowdyPlayerProfile Profile)
{
// A player who has not chosen a name has an empty Gamertag.
const FString Shown = Profile.Gamertag.IsEmpty() ? TEXT("A villager") : Profile.Gamertag;
UE_LOG(LogTemp, Log, TEXT("Player %lld is %s"), Profile.UserID, *Shown);
}

void ULanternGameInstance::HandlePlayersFailed(FCrowdyAccountError Error, FString Message)
{
UE_LOG(LogTemp, Warning, TEXT("Could not read the name: %s"), *Message);
}

For a roster, collect the User IDs and make one Get Player Names call rather than one call per player.

Let the player choose a name​

A Choose Your Name screen on the first launch calls Set Player Name with the two fields. When the pair is taken, ask for another disambiguation.

// LanternGameInstance.h
#include "Subsystem/CrowdyPlayers.h"

public:
// The first-launch Choose Your Name screen.
void ChooseName(const FString& Gamertag, const FString& Disambiguation);

UFUNCTION()
void HandleNameChosen(FCrowdyPlayerProfile Profile);

UFUNCTION()
void HandleNameRefused(FCrowdyAccountError Error, FString Message);

// LanternGameInstance.cpp
void ULanternGameInstance::ChooseName(const FString& Gamertag, const FString& Disambiguation)
{
FOnPlayerProfileRead Chosen;
Chosen.BindDynamic(this, &ULanternGameInstance::HandleNameChosen);
FOnPlayersError Refused;
Refused.BindDynamic(this, &ULanternGameInstance::HandleNameRefused);
GetSubsystem<UCrowdyPlayers>()->SetPlayerName(Gamertag, Disambiguation, Chosen, Refused);
}

void ULanternGameInstance::HandleNameChosen(FCrowdyPlayerProfile Profile)
{
UE_LOG(LogTemp, Log, TEXT("You are %s (%s)"), *Profile.Gamertag, *Profile.Disambiguation);
}

void ULanternGameInstance::HandleNameRefused(FCrowdyAccountError Error, FString Message)
{
if (Error.Code == ECrowdyAccountErrorCode::NameTaken)
{
UE_LOG(LogTemp, Warning, TEXT("Someone already has that name. Try another disambiguation."));
return;
}
UE_LOG(LogTemp, Warning, TEXT("The name was not changed: %s"), *Message);
}

Gotchas​

  • Names are not live: read again when you need a current one, for example when a player joins a team or a match.
  • The pair is the unique handle. Show both where players must tell two names apart, such as a friends list.
  • A player's own name is read with their own User ID, from UCrowdyGameSession::GetUserID().
  • Crowdy Studio's Account page sets your own name as the developer.
  • Authentication: signing in, and the account settings that share this page's error type.
  • Teams: the member lists a roster names.