Session-based Multiplayer
Along with relayed and authoritative multiplayer models, Nakama additionally supports session-based multiplayer. Session-based multiplayer is a gaming model that structures gameplay into distinct sessions (e.g. matches), each with a clear beginning and end, and each running on dedicated servers such as headless Unity or Unreal instances.
These server instances are created on-demand for each new gameplay session, enabling players join a match and participate in the game for its duration, before then being shutdown at the conclusion of each match. This model is typically only required by complex physics/graphic-laden games, and is particularly popular in competitive games.
Nakama and Session-based multiplayer
Session-based multiplayer games require additional considerations from developers. As each gameplay session is isolated, there is a need for a centralized way to track player progression, stats, achievements, and the like. Matchmaking is crucial for any successful multiplayer game but even more so when it is session-based. Players must not only be quickly connected to a server to join a match, but that server must be one that is location-appropriate to provide the best possible performance and must match players with the correct criteria to provide for balanced, fair, and fun gameplay. Otherwise, players can face unreasonably long wait times to play, risking their abandoning the game, or be matched in non-competitive sessions where the gameplay doesn’t keep them engaged.
Nakama handles both of these necessary factors for managing successful session-based multiplayer games. Nakama can be used to manage the headless instances for your session-based multiplayer game, as well as other aspects of multiplayer gameplay. You can use Nakama’s powerful Matchmaker to find opponents for your players and create matches and, when a match ends, Nakama can report the results, saving all relevant stats to the player accounts, and then be used to move players as appropriate.
Nakama’s powerful APIs and extensible server runtime mean in can be used with any service providing game server fleet and management, providing you the freedom to work with any preferred platforms.
The FleetManager interface
In order to provide developers with a way of interacting with a set of headless game servers, also known as a fleet, Nakama provides a FleetManager
interface. This interface provides a mechanism with which Nakama can coordinate the creation, deletion, and updating of data within headless game server instances.
Out of the box Nakama provides an implementation of the interface for Amazon GameLift, but the interface is designed to be extensible.
Contact us if you would like to see your favorite fleet management service supported by Nakama.
The FleetManager
object can be accessed in server runtime code as follows:
fm := nk.GetFleetManager()
The Fleet Manager is designed to internally manage the state of the fleet of headless game server instances and provide a means of allowing these active instances to be created, deleted, listed, and queried similar to the way Nakama’s Match Listing feature works.
Interacting with the FleetManager
A typical workflow for placing a user into a game session is to search for an active game session using the List
function, providing a search query using the Query Syntax to filter for particular parameters. Active headless game sessions are searched for based on their current properties in near real-time and their connection details can be sent to clients allowing them to join in-progress session-based multiplayer matches.
Finding and joining game sessions
An example of this would be searching for a game session with a game mode of "freeforall"
and a current playerCount
of less than 3. e.g.
query := "+values.GameProperties.gamemode:freeforall +values.player_count:<3"
limit := 1
cursor := ""
instances, _, err := fm.List(ctx, query, limit, cursor)
Once a game session has been found, players can be be placed into it by using the Join
function:
id := "<game session ID>"
userIds := []string{userId}
metadata := map[string]string{
userId: "<player data>",
} // metadata is optional. It can be used to set an arbitrary string that can be retrieved from the Game Session. Each key needs to match an userId present in userIds, otherwise it is ignored.
joinInfo, err := fm.Join(ctx, id string, userIds []string, metadata map[string]string)
Creating game sessions
Where a game session is not available, the Fleet Manager interface can be used to Create
a new game session for a particular individual or set of users. When a request is made to create a new game session, the Fleet Manager will reserve seats within the session for all specified users to ensure there is enough space for all players to join the session appropriately.
When using the Create
function, there is no need to call the Join
function to place players into the game session, joining is implicit.
// The purpose of the callback is to facilitate asynchronous game session creation.
// Typically notifications can be used to let players know the instance is ready.
var callback runtime.FmCreateCallbackFn = func(status runtime.FmCreateStatus, instanceInfo *runtime.InstanceInfo, sessionInfo []*runtime.SessionInfo, metadata map[string]any, createErr error) {
switch status {
case runtime.CreateSuccess:
logger.Info("Headless server instance created")
return
case runtime.CreateTimeout:
logger.WithField("error", createErr.Error()).Error("Failed to create headless server instance, timed out")
default:
logger.WithField("error", createErr.Error()).Error("Failed to create headless server instance")
return
}
}
// User IDs passed to the Create function will be reserved in the game session for a period of time.
maxPlayers := 10
userIds := []string{"UserId1", "UserId2"}
metadata := map[string]interface{}{}
if err = fm.Create(ctx, maxPlayers, userIds, metadata, callback); err != nil {
logger.WithField("error", err.Error()).Error("failed to create new fleet game session")
return "", ErrInternalError
}
Get active game sessions
Running game sessions can be retrieved with the Fleet Manager’s Get
function:
id := "<Game Session ID>"
instance, err := fm.Get(ctx, id)
Delete game sessions
Running game sessions can also be delete with the Fleet Manager’s Delete
function:
id := "<game session ID>"
err := fm.Delete(ctx, id)
Nakama-GameLift integration
The Nakama-GameLift plugin is compatible with Nakama 3.21 and above.
While any games server management service can be used with Nakama, Heroic Labs provides an open-source Nakama-GameLift Plugin that enables easy implementation of session-based multiplayer gameplay with the full benefits and functionality provided by Nakama and Amazon GameLift.
Below is an example of a typical workflow when integrating with Amazon GameLift.
An example of Nakama and Amazon GameLift integration using the FleetManager API
Read the comprehensive integration guide to get started.
Other integrations
We are open to adding more Fleet Manager interfaces in the future, as well as open to contributions from the community. If you are interested in seeing your favorite fleet management service supported by Nakama, we welcome your contributions on GitHub.