Natty's primary purpose is to establish connectivity between participants in online games.
The unit of orchestration is a lobby - participants gather into a lobby, and at a player-triggered point in time, Natty will coordinate connections between the players.
Supported games are assumed to work in a server-client model. Whenever possible, Natty will try to designate one of the participants as server. Otherwise, Natty will act as a UDP relay between players.
Self-hosting is only viable if there's at least one player to whom everyone can connect. If there's more than one such player, a selection process must be used to determine who will host.
UDP relaying is used when there's no player capable of hosting. Limits are configured so the application won't be overloaded with too many concurrently running relays.
Before the lobby starts, Natty needs to figure out which hosting method will work for the given lobby.
- When a new lobby is created
- Create a bookkeeping entry for the lobby
- Each entry stores a set of connection attempts
- The connection attempt has a state -
pending
,running
,done
- The connection attempt has an outcome - success or fail
- The connection attempt has a pair of user id's
- The connection attempt has a state -
- When someone joins a lobby
- Generate a new connection attempt for each missing link with a state of
pending
- If there's now n+1 players in the lobby, this step will result in n new items
- Example:
- Lobby has players A, B and C
- Player D joins
- The new entries will be:
- [A-D, B-D, C-D, D-A, D-B, D-C]
- Generate a new connection attempt for each missing link with a state of
- When someone leaves a lobby
- Delete all connection attempts that affect the leaving player
- When a new connection attempt is added
- Ask both participants to do a handshake
- Once both participants ack'd, set attempt state to
running
- Wait for both participants to respond
- Set attempt to success only if both participants respond with success
- Error: if either participant takes too long to ack, fail the attempt
Once the lobby starts, Natty needs to designate a host and orchestrate connection for everyone to the host.
Firstly, the hosting method is determined:
- If there's at least one player to whom anyone can connect, use self-hosting
- Else if the config limit isn't reached, use UDP relay
- Otherwise fail lobby
- Designate a host
- If the lobby owner is viable, designate them
- Otherwise pick an arbitrary viable participant
- Notify designated host, wait for them to ack
- The host should prepare for incoming connections and ack
- Error: if the host takes too long to ack, fail lobby
- Wait for participants to report
- Each participant reports whether they managed to connect
- For each participant failing to connect
- If the config limit isn't reached, create a UDP relay
- Participant should report again
- Else fail the lobby
- If the config limit isn't reached, create a UDP relay
- If all participants succeeded, revel in success
- If there's participants that failed even with UDP relay, fail lobby
- Designate a host
- This will be the lobby owner
- Notify designated host, wait for them to ack
- The host should prepare for incoming connections and ack
- The host is also required to register their remote address at this point
- See UDP Relays doc
- Error: if the host takes too long to ack, fail lobby
- Create a UDP relay for each client
- Wait for participants to report
- If a client fails, fail the lobby
- Rationale: we are already using UDP relays, if someone can't connect, there's nothing more Natty can do
- If a client fails, fail the lobby
By now, lobbies will need to have a state which can be one of the following:
- Gathering
- Lobby is open for players to join
- Diagnostic process is running in the background
- Starting
- Lobby is closed for new joiners
- Natty is orchestrating connection
- Active
- Lobby is closed for new joiners
- Connection has been successfully orchestrated
If a lobby fails for whatever reason, the lobby state is returned to Gathering. This is to make it more convenient for players to retry connection in case something goes wrong in the process.