SDK / Unity

Multiplayer

ExperimentalUnity 6000.6+

Brain matches players and runs your game's dedicated servers. Every online match plays on a server of your game that Brain starts for it: the server holds the match's state and alone reports how it ended. Players sign in, find a match, and connect to that server.

Ways to play

Way Players get Config
Ranked queue Skill matchmaking with visible ratings, seasons and a ladder [[matchmaking.queue]] with ranked = true
Casual queue Practice matchmaking by a hidden rating [[matchmaking.queue]]
Private match Play friends by invite code, unrated [matchmaking.private]
Open lobby Create a lobby on a server, or pick one from a list A server build
[[matchmaking.queue]]
id = "ranked"
teams = 2            # teams times team_size players, at most 16
team_size = 1
host = "server"      # your dedicated server
rating = "glicko2"   # none, elo or glicko2
ranked = true        # visible ratings; false keeps the rating hidden
guests = true        # players signed in only as guests may queue
stats = ["goals"]    # numbers your server reports per seat with the result

[[matchmaking.queue]]
id = "casual"        # a bare queue: a hidden-rating 1v1 that guests may join

[matchmaking.private]
seats = 4            # the creator included, 2 by default

ase net add ranked,casual,private,lobbies adds these sections to an existing game, and ase new-game --multiplayer writes them into a new one. Nothing goes live until your next release.

Your dedicated server

Your release publishes a Linux server build of your game alongside its clients, through the servers release target. Brain starts it on its machines when players need a match or a lobby. Regions and capacity are on your game's Settings page in the console, never in the repo.

Players and names

Online play needs the player signed in. The SDK signs in silently at startup with the platform's account where there is one (Steam, Game Center or Play Games), else with the credential this device kept, else as a new guest. Offer guests a way to link Apple or Google, so their account follows them.

  • Never log, print or record player names or ids. Showing a name on screen is fine.
  • When your game shows other players' names, it must let the player report a name and block a player (store rules). Brain ships no buttons for this: put them where your game shows names.
Unity
Signed in Brain.Account.SignedIn
Link Apple or Google Brain.Account.Link("apple")
Report a name Brain.Account.ReportName(name, done)
Block a player Brain.Account.Block(name, done)
List and lift blocks Blocked(done), Unblock(name, done)

Blocked players are never matched together in your game's queues.

Multiplayer in Unity is Experimental. It lives in a separate, lower-level assembly, Ase.Brain.Native, which signs in on its own through BrainNativeServices; it doesn't share the Brain client's account yet. Don't ship a Unity game on it.

The client sequence:

  1. BrainNativeServices signs the player in (SignInGuest, or SignInProvider with a Steam, Game Center or Play Games proof). Call its Pump() every frame.
  2. BrainNativeRankedQueue.Join(queue, build, utcOffsetMinutes) searches; Assigned gives the match and seat.
  3. TryRequestNativeIntent answers a BrainNativeConnectionIntent for that match.
  4. BrainNativeClient.Create(intent, budget, clock, seat) connects, and BrainNativeLoop.Attach pumps it around Unity's FixedUpdate.
using Ase.Brain.Native;
using Unity.Collections;

void FindMatch()
{
    queue.Assigned += assignment => queue.TryRequestNativeIntent(intent =>
    {
        client = BrainNativeClient.Create(intent, budget, clock, assignment.Seat);
        client.ResyncPayload = OnServerState;
        client.ResyncRequested += context => client.CompleteResync(context);
        client.Ready += StartMatch;
        client.Packet = OnServerUpdate;
        loop = BrainNativeLoop.Attach(client);
    });
    queue.Join("ranked", buildId, utcOffsetMinutes);
}

void OnServerState(BrainNativePacketMetadata metadata, ref DataStreamReader payload) { /* apply the server's state */ }
void OnServerUpdate(BrainNativePacketMetadata metadata, ref DataStreamReader payload) { /* apply an update */ }

Send(channel, delivery, payload) answers Accepted, Backpressure, NotReady or another refusal. Accepted means the transport took the bytes; wait for the server's state before you treat a move as official. The payload readers are valid only during the callback: copy what you keep.

Dedicated servers use BrainNativeServer and BrainServerHost: bind your listener on Brain.Server.GamePort, then call Brain.Server.MarkReady(status).