profiles

Profiles (Display Names)

A display name per account, separate from the login name: the player sets it, game code may set it too, and anyone signed in reads the names of a batch of accounts in one request - offline players included, which is what a friends list, a ranking or a member roster needs. Names are trimmed, length-limited, refused with control or invisible characters, unique by default across case and look-alike forms, and anything further (a word filter, reserved names) is the game's IProfileNamePolicy. Optionally shown as the account's online name when it signs in. Durable across restarts.

Category Social Seams 2 Services 1 Options 1 Wire ids 4 Unity types 1
Server
services.AddCrossplayProfiles();
Unity package
com.crossplay.profiles
Depends on
core

Seams you implement 1

Crossplay calls these; your game supplies them. Each ships an inert or permissive default, so register yours before services.AddCrossplayProfiles(); and it wins.

IProfileNamePolicy game SPI

What a display name may be, beyond length and characters - a word filter, reserved names, a paid rename. Register yours before AddCrossplayProfiles.

  • bool Allows(long accountId, string name)

    True when accountId may take name (already trimmed and length-checked). Only the player's own wire request asks; the server's SetName is trusted.

Providers you can swap 1

Infrastructure seams. Crossplay ships a working implementation of each — replacing one changes where data lives or how it moves, never a game rule.

IProfileStore provider

Where names live. The default keeps them in memory; persistence composes a durable one.

  • void Save(long accountId, string name, string nameKey)

    Stores the account's name and its folded key, replacing any previous one.

  • bool TryGetName(long accountId, out string name)

    The account's stored name.

  • bool TryGetOwner(string nameKey, out long accountId)

    The account holding a name, by its folded key (see Key).

Services you call 1

Crossplay implements these. Resolve them from DI and call them from your own systems.

IProfileService

Display names, server side. Game code reads names here and may set one (trusted: no name policy).

  • event Action<long, string> NameChanged

    An account's name changed: (account, new name).

  • ushort SetName(long accountId, string name)

    Sets an account's name from game code: length, characters and uniqueness still apply, the name policy does not. Returns 0, or a ProfileNotificationCodes value.

  • bool TryGetName(long accountId, out string name)

    The account's display name.

Configuration 1

Every tunable lives in an options object — there are no magic numbers to hunt for.

ProfilesOptions

Profiles tuning, bound from Crossplay:Profiles.

  • bool FallbackToUsername { get; set; }

    When an account has no stored name, the names lookup answers its LOGIN username instead (off by default). For a game whose display name IS the login name: every account has a name from its first day, including ones that have not signed in since the game started storing names. Turning it on shows login names to every signed-in player - the same thing Activity, Conversations, Elections, Forums and Guild already show - so it suits a game where the username is public by design. A stored name always wins.

  • int MaxLookupIds { get; set; }

    Most distinct accounts one names request may read; the rest of the request is ignored.

  • int MaxNameLength { get; set; }

    Longest name accepted, in characters, after trimming.

  • int MinNameLength { get; set; }

    Shortest name accepted, in characters, after trimming.

  • bool ShowAsOnlineName { get; set; }

    Also use the stored name as the account's ONLINE display name (Core's directory, which Friends, Chat, Party and Guild show) when it signs in and when it changes. A name another online session already holds is left alone there, exactly as Core's own rule has it.

  • bool UniqueNames { get; set; }

    No two accounts may hold the same name. Compared case-insensitively and after Unicode compatibility folding, so look-alike forms of one name count as the same. On by default: a shared name is how one player passes as another.

  • bool UseForAccountNames { get; set; }

    Make the stored name the one Activity, Conversations, Elections, Forums and Guild show for an account (off by default: they keep showing the login username). It adds a name, it does not replace the username: login and "send to a player by name" still use the username, and an account with no stored name still shows it.

Wire messages 4

The protocol this piece speaks. Ids are allocated per piece so they can never collide.

8001 ProfileSetNameRequest

Client -> server: set my display name. The reply is a ProfileResult.

8002 ProfileResult

Server -> client: the result of a ProfileSetNameRequest.

8003 ProfileNamesRequest

Client -> server: the display names of a batch of accounts (capped server-side; duplicates collapse). The reply is a ProfileNames.

8004 ProfileNames

Server -> client: the reply to a ProfileNamesRequest. An account with no name set is left out, so "no such account" and "no name yet" look the same.

Unity services you inject 1

Crossplay binds these in the client context. Inject and call them from your own MonoBehaviours and presenters.

IProfileClient

Client SDK for Profiles - display names. Each call is one awaitable request (Core's request/reply helper - it never throws; a timeout completes unsuccessfully). An account with no name set is simply missing from a names reply; what to show instead is the game's. Nothing is pushed and nothing is cached: keep what you read. Pure SDK, no UI.

  • UniTask<ProfileResult> SetNameAsync(string name, CancellationToken ct = default)

    Sets your display name. On success the reply carries the name as stored (trimmed).

  • UniTask<ProfileNames> NamesAsync(long[] accountIds, CancellationToken ct = default)

    The display names of a batch of accounts (the server caps the batch; duplicates collapse).