Game Integration
Why do I need a Matchmaker and/or Lobby?
A Lobby Service (📦 Nakama by Heroic Labs) system plays a crucial role in online multiplayer games for various technical reasons.
Player management
A lobby or matchmaker system helps manage players by grouping them into appropriate matches based on various criteria such as skill level, geographical location, or game preferences. This ensures a balanced and enjoyable gaming experience for all players involved.
Backend
You do not want your player to communicate directly with your backend and you want to offer a centralized point for them to access. Imagine you have an API token that start a VM in a certain provider, you do not want the Token hardcoded in the Game Client, accessible to any players!
Security
Using a centralized lobby or matchmaker system helps maintain control over the game's security. By filtering and validating player connections, a matchmaker can prevent unauthorized access, protect user data, and mitigate potential cheating or hacking attempts.
Game session management
A lobby or matchmaker system manages game sessions by creating, updating, and terminating them as needed. This ensures that players can join or leave games seamlessly, and the game instances can be efficiently managed by the system.

You Don't Need One Right Away! (Development mode)
During the development phase, you might not need a fully-fledged lobby or matchmaker system for several technical reasons:
Simplified testing environment
In the initial stages of development, you might focus on implementing and testing the core game mechanics and networking features. By avoiding the complexity of a lobby or matchmaker system, you can more easily test and debug your game with a smaller group of players, often within your development team.
Faster iteration
Without a lobby or matchmaker, you can make quick changes to your game code and test new features or fixes without worrying about the impact on the matchmaking process. This allows for a more agile development approach, enabling your team to iterate and refine the game mechanics more rapidly.
Resource allocation
Developing a full-scale lobby or matchmaker system requires considerable time and resources. By delaying the implementation of these components, you can allocate your resources more efficiently, focusing on the core gameplay and networking features first.
Scalability concerns
In the early stages of development, you likely won't have a large number of players to manage. As a result, a basic system for connecting players or even manual connections for testing purposes may be sufficient. However, as your game grows and attracts more players, a lobby or matchmaker system will become increasingly necessary to manage player connections and ensure a smooth gameplay experience.
It's crucial to design your game architecture to accommodate a lobby or matchmaker system in the future. This forward-thinking approach will make it easier to integrate these components when you're ready to test your game with a larger group of players, ensuring a smoother transition and a more polished final product.
Interacting with Edgegap’s API
Edgegap offer a simple API to interact with the Relay Sessions to authorize your players to connect to the closest relay for low latency.

To interact with the API, you'll need to provide an Authorization Header Token in your requests.
This is accessible from the sidebar on the dashboard.

Once you have the token, include it in the request headers for all API calls. Don't forget to prefix your API key with token.
If you are not familiar with working with an API, you can refer to this section to assist you in getting started.
Creating a Relay Session
To use Distributed Relay, you need to create a relay session. This is done by sending a POST request to the /v1/relays/sessions endpoint with a JSON payload. Sessions can be created manually, with a matchmaker, with a lobby, or with your own custom service.
This will dynamically select the best available relay for your players in real-time and create authorization for accessing the relay. However, we recommend pre-filtering your matchmaking to group players within the same region to avoid extreme distances between them.
Example Request:
POST - /v1/relays/sessionsThe payload should contain an array of user objects, where each object contains the IP address of a user. You can also include a webhook_url, which is the URL that will receive notifications related to the session.
Example Payload:
{
"users": [
{
"ip": "1.1.1.1"
},
{
"ip": "2.2.2.2"
}
],
"webhook_url": "https://webhook.example.com/notify"
}Example Response:
{
"session_id": "3960c873aafd-S",
"authorization_token": null,
"status": "Initializing",
"ready": false,
"linked": false,
"error": null,
"session_users": [],
"relay": null,
"webhook_url": "https://webhook.example.com/notify"
}Getting Information about the Relay Session
To retrieve session information, send a GET request to the /v1/relays/sessions/{session_id} endpoint with the session_id obtained from the POST request.
Example Request:
GET - /v1/relays/sessions/3960c873aafd-SThe response will contain information about the session, including the session status, users information, and relay information.
The expected response will contain session information like this:
{
"session_id": "3960c873aafd-S",
"authorization_token": 1031196689,
"status": "Linked",
"ready": true,
"linked": true,
"error": null,
"session_users": [
{
"ip_address": "2.2.2.2",
"latitude": 48.8602294921875,
"longitude": 2.34106993675232,
"authorization_token": 3499933322
},
{
"ip_address": "1.1.1.1",
"latitude": -37.7036018371582,
"longitude": 145.180633544922,
"authorization_token": 4261594560
}
],
"relay": {
"ip": "178.79.131.238",
"host": "cc84b011777b.pr.edgegap.net",
"ports": {
"server": {
"port": 31527,
"protocol": "UDP",
"link": "cc84b011777b.pr.edgegap.net:31527"
},
"client": {
"port": 32089,
"protocol": "UDP",
"link": "cc84b011777b.pr.edgegap.net:32089"
}
}
},
"webhook_url": "https://webhook.example.com/notify"
}Getting the Authorization to the closest relay can take a small amount of time, so when the field ready is true you can extract JSON data to use it.
Alternatively, you can use the `webhook_url` parameter when creating a relay session to be notified when the session has either succeeded in being assigned to a relay or has failed to do so.
Terminating a Relay Session
When you decide to end your connection to the relay, you can easily terminate a relay session. You need to send a DELETE request to the following endpoint:
DELETE - /v1/relays/sessions/{session_id}A response with status 204 no content means the session has been successfully deleted. The players will lose access to the relay and you will no longer be charged for that session.
It's important to terminate sessions properly in order to avoid leaving any unused resources allocated, which can impact performance and incur unnecessary costs.
C# Example
This is a C# that your Lobby or Matchmaker could do to create a Relay Session and extract the Data that you would need to return to your game client.
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
namespace LobbyNamespace
{
public class EdgegapAPI
{
private readonly HttpClient _httpClient;
public EdgegapAPI(string apiToken)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Token {apiToken}");
}
public async Task<RelaySessionAuthorization> CreateRelaySession(List<string> ips)
{
var jsonBody = new
{
users = ips.ConvertAll(ip => new { ip })
};
var postResponse = await _httpClient.PostAsJsonAsync("https://api.edgegap.com/v1/relays/sessions", jsonBody);
var postJsonData = await postResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();
if (!postJsonData.ContainsKey("session_id"))
{
throw new Exception("Failed to create relay session");
}
var sessionId = postJsonData["session_id"].ToString();
var retries = 5;
while (retries > 0)
{
var getResponse = await _httpClient.GetAsync($"https://api.edgegap.com/v1/relays/sessions/{sessionId}");
var getJsonData = await getResponse.Content.ReadFromJsonAsync<Dictionary<string, object>>();
var ready = (JsonElement)getJsonData["ready"];
if (ready.ValueKind == JsonValueKind.True)
{
var usersData = (JsonElement)getJsonData["session_users"];
var userAuthorizationTokens = new Dictionary<string, UInt32>();
foreach (var user in usersData.EnumerateArray())
{
var ipAddress = user.GetProperty("ip_address").GetString();
var userAuthorizationToken = user.GetProperty("authorization_token").GetUInt32();
userAuthorizationTokens[ipAddress] = userAuthorizationToken;
}
var relayData = (JsonElement)getJsonData["relay"];
var relayAddress = relayData.GetProperty("host").GetString();
var relayServerPort = relayData.GetProperty("ports").GetProperty("server").GetProperty("port").GetInt32();
var relayClientPort = relayData.GetProperty("ports").GetProperty("client").GetProperty("port").GetInt32();
return new RelaySessionAuthorization
{
SessionAuthorizationToken = sessionId,
UserAuthorizationTokens = userAuthorizationTokens,
RelayAddress = relayAddress,
RelayServerPort = relayServerPort,
RelayClientPort = relayClientPort
};
}
retries--;
await Task.Delay(2000); // wait for 2 second before retrying
}
throw new Exception("Failed to get a ready relay session");
}
}
public class RelaySessionAuthorization
{
public string? SessionAuthorizationToken { get; set; }
public Dictionary<string, UInt32>? UserAuthorizationTokens { get; set; }
public string? RelayAddress { get; set; }
public int RelayServerPort { get; set; }
public int RelayClientPort { get; set; }
}
}You will need to return this information to the corresponding Player.
The Player acting as the Server will need the RelayServerPort and all the other will need the RelayClientPort
using System.Text.Json;
using LobbyNamespace;
class Program
{
static async Task Main(string[] args)
{
// Replace YOUR_API_TOKEN with your actual API token
var apiToken = "YOUR_API_TOKEN";
// 1.1.1.1 is your player acting as a server
// 2.2.2.2 is your player acting as a client
var ips = new List<string> { "1.1.1.1", "2.2.2.2" };
var edgegapAPI = new EdgegapAPI(apiToken);
var relaySessionAuthorization = await edgegapAPI.CreateRelaySession(ips);
// Generate JSON body for server (1.1.1.1)
var serverJsonBody = new
{
relay_address = relaySessionAuthorization.RelayAddress,
port = relaySessionAuthorization.RelayServerPort,
session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["1.1.1.1"]
};
var serverJson = JsonSerializer.Serialize(serverJsonBody);
Console.WriteLine($"JSON body for server (1.1.1.1):\n{serverJson}");
// Generate JSON body for client (2.2.2.2)
var clientJsonBody = new
{
relay_address = relaySessionAuthorization.RelayAddress,
port = relaySessionAuthorization.RelayClientPort,
session_authorization_token = relaySessionAuthorization.SessionAuthorizationToken,
user_authorization_token = relaySessionAuthorization.UserAuthorizationTokens["2.2.2.2"]
};
var clientJson = JsonSerializer.Serialize(clientJsonBody);
Console.WriteLine($"JSON body for client (2.2.2.2):\n{clientJson}");
}
}Interacting with API (cURL or POSTMAN)
While developing your game, you'll need to interact with the API to create, manage, and delete relay sessions. You can use tools like cURL or POSTMAN to send HTTP requests to the API.
cURL is a command-line tool that allows you to make HTTP requests and interact with APIs directly from the terminal. POSTMAN is a popular graphical user interface (GUI) application that simplifies API testing by providing a user-friendly interface to create, send, and analyze HTTP requests.
Here's an example of how to create a relay session using cURL:
curl -X POST -H "Content-Type: application/json" -H "Authorization: Token API_TOKEN" -d '{
"users": [
{
"ip": "1.1.1.1"
},
{
"ip": "2.2.2.2"
}
],
"webhook_url": "https://webhook.example.com/notify"
}' "https://api.edgegap.com/v1/relays/sessions"The API will return you a response that contain data also. You will need to parse this response and extract the data you need.
Last updated
Was this helpful?

