Session-based Multiplayer

Along with relayed and authoritative multiplayer models, MetaFi 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.

MetaFi 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.

MetaFi handles both of these necessary factors for managing successful session-based multiplayer games. MetaFi 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 MetaFi’s powerful Matchmaker to find opponents for your players and create matches and, when a match ends, MetaFi can report the results, saving all relevant stats to the player accounts, and then be used to move players as appropriate.

MetaFi’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, MetaFi provides a FleetManager interface. This interface provides a mechanism with which MetaFi can coordinate the creation, deletion, and updating of data within headless game server instances.

The FleetManager object can be accessed in server runtime code as follows:

fm := nk.GetFleetManager()

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.

// 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)

Last updated