Multiplayer
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:
BrainNativeServicessigns the player in (SignInGuest, orSignInProviderwith a Steam, Game Center or Play Games proof). Call itsPump()every frame.BrainNativeRankedQueue.Join(queue, build, utcOffsetMinutes)searches;Assignedgives the match and seat.TryRequestNativeIntentanswers aBrainNativeConnectionIntentfor that match.BrainNativeClient.Create(intent, budget, clock, seat)connects, andBrainNativeLoop.Attachpumps 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).