How many game server can/should run on Multiplay ?

Hi,

We are considering using Multiplay for our multiplayer game. This is the first time we are making multiplier game with somewhat a big scope and I have some interrogation about using Multiplay.

So, in our game, a player can create a new multiplayer session, invite some friends and then play a specific game mode together. When the game mode finished, they can continue with another game mode or just leave the session, which terminate the multiplayer.

What I have in mind is : a a player create a multiplayer session, allocate a new server on Multiplay that will run the game build. When the session is done, deallocate the server.

So, if we have let say 1000 multiplayer sessions at a given time, that is 1000 allocated servers on Multiplay.

Is that something that is expected for a game on Multiplay ? I would say yes, but I’m not sure if this kind of usage is expected on Multiplay …

Or maybe a single server can run multiple game instances at a time ?

I’m not sure if, as a developer, I am responsible of the actual server allocation, or all of that is done by Multiplay and I’m only requesting for a new slot.

Good day @BSimonSweet ,

Thanks for your questions it is great to hear you are checking out our Multiplayer tools and hope they help save you time so you can focus on development.

The usage you describe (1000 sessions to 1000 servers) is the standard workflow most developers will implement and once your match or game session is over then the server should be deallocated in some way if it is no longer in use, you can either deallocate it and return it to the pool but you will need to implement logic to handle cleanup, or you can simply exit zero and we will auto deallocate the server.

This behaviour keeps server count low as possible as we can keep track of all games and thus our scaling system keeps the server density high. (Server density is the ratio of servers to virtual machine in our backend).

A basic example here would be an fps where you play X amount of rounds for Y minutes and then once the match is over the server is deallocated (note currently allocations only last for 1 hour but let us know via support ticket if you need this adjusted)

To get into the session you can use our Matchmaker which will let the player create a ticket for their chosen queue/pool
If your server allows additional players to connect through the lifetime of the server you can use Backfill to keep the player count topped up.

At the end of the game session your client once it recognises it is no longer in a game session can fire off another matchmaking ticket, its up to you how you want to implement this, maybe after the previous session ends you want to just send the client back to the main menu of the game or your client can auto matchmake (it will need to request another ticket) if the player generally plays multiple sessions in a row

You should find these resources particularly useful
https://docs.unity.com/game-server-hosting/en/manual/concepts/allocations
https://docs.unity.com/matchmaker/en/manual/use-the-matchmaker
https://docs.unity.com/matchmaker/en/manual/queues-and-pools
https://docs.unity.com/matchmaker/en/manual/matchmaker-and-multiplay-sample

Amazing response, thank you very much !

So if a game session reach 1 hour, the server will automatically shutdown ? We considering having an online world where players could join anytime, so the server would need to run for an extended period of time. Can this scenario be envisaged, if we ask support for this ?

Hey @BSimonSweet , not automatically shutdown but when the timeout occurs the server will become deallocated which puts it into the available state, this means that the server is ready to receieve a new allocation and thus the next time it is allocated its server.json will be updated with the new Allocation ID, if your server binary is running but not in a state to handle the new allocation inevitably players will struggle to get into a session.

Allocation timeout is here as a protection and should be seen as a last resort really. If there is some issue which leaves the server allocated then we can clean up the allocation, ideally it will be set to a length that occurs generally after when your game session has ended.
Lets say you have a game that has a 15 minute session we might set a 1 hour timeout because we would never expect the server to be allocated for that long.

We can increase this Allocation timeout in our backend but you will need to submit a ticket to us so that we can adjust the setting for you, there are plans to let you do this via unity dashboard in the near future.
Ultimately if your server is going to be active for a long period there is no reason that we could not set your allocation timeout to 24 hrs if you really wanted, but a caveat here is that we are not currently geared toward persistent servers.

If out of interest you have any platform features you think we are missing you can view and submit features at our roadmap here :slight_smile: Multiplayer Roadmap

1 Like

@jackw_unity could you give more information about the allocation and deallocation process?
I couldn’t find much about it in the documentation, how should I request a deallocation through the GSH sdk?

You can’t deallocate a server with the SDK, you have to do that with the REST API : Unity Services Web API docs

This API also require Admin right, so you need a Service Account.

Thank you @BSimonSweet !
I did as you said and now I get an error message saying that the call was not authorized.

I created a service account with “Game Server Hosting Allocations Admin” role and I’m using the following code to request the server deallocation:

private string ServiceAccountKey
{
    get
    {
        const string keyId = "...";
        const string secretKey = "...";
        byte[] keyByteArray = Encoding.UTF8.GetBytes($"{keyId}:{secretKey}");
        return Convert.ToBase64String(keyByteArray);
    }
}

IEnumerator _StopServer()
{
    Debug.Log("Shutting down...");

    string uri = "https://multiplay.services.api.unity.com/v1/allocations/";
    string data = $"projects/{ProjectId}/environments/{EnvironmentId}/fleets/{FleetId}/allocations/{allocationId}";

    using (UnityWebRequest www = UnityWebRequest.Delete(uri + data))
    {
        www.SetRequestHeader("Authorization", "Basic " + ServiceAccountKey);

        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
            Debug.Log(www.error);
        else
            Debug.Log("Shutdown successful!");
    }
}

It is because the Service Token can’t be used like that with the Multiplay Lifecyle API. You need a Stateless token first : Admin authentication | Unity Services Web API docs

You will get a bearer token that you can then pass to the HTTP request. You’ll need to set the “Authorization” header to “Bearer”.

Ok, I updated my code to get the stateless token and after a bit of tinkering I still get this response:
HTTP/1.1 403 Forbidden

Do I need some other mean of authentication to make this call?
There is not much in the docs.

IEnumerator _APILogIn()
{
    const string uri = "https://services.api.unity.com/auth/v1/token-exchange";
    string data = $"?projectId={ProjectId}&environmentId={EnvironmentId}";
    const string jsonData = "{\"scopes\":[\"unity.projects.get\",\"unity.projects.create\"]}";

    using (UnityWebRequest www = UnityWebRequest.Post(uri + data, jsonData, "application/json"))
    {
        www.SetRequestHeader("Authorization", "Basic " + ServiceAccountKey);
        yield return www.SendWebRequest();

        if (www.result != UnityWebRequest.Result.Success)
        {
            Debug.Log(www.error);
        }
        else
        {
            authResponse = AuthResponse.CreateFromJSON(www.downloadHandler.text);
            Debug.Log("Authentication completed!");
            Debug.Log("Response: " + www.downloadHandler.text);
            Debug.Log("Token: " + authResponse.StatelessToken);
        }
    }
}

www.SetRequestHeader("Authorization", "Bearer " + ServiceAccountKey);

You must set the “Authorization” header to “Bearer”. Don’t forget the space after “Bearer”.

Tried it with “Bearer” and now I get HTTP/1.1 401 Unauthorized
In the API documentation you sent earlier “Basic” is used to get the token and “Bearer” to use it. I’m a bit confused.
You already helped a lot btw, think I’m on the right track now

Check the role of the Service Account, you might not have the correct one : Unity Services Web API docs

You can unfold the “Authorization” section to see the required one

I already have the allocation permissions. The problem is not with the deallocation itself but that I can’t get the stateless token to make the call

Oh sorry, I didn’t read your code correctly, I was a bit in a hurry, I though you got the stateless token correctly …

Effectively, the “Authorization” header for the Token Exchange must be “Basic” (this code seems ok : How many game server can/should run on Multiplay ? )

I don’t know why you get a “HTTP/1.1 403 Forbidden”. All I can advice you is to check that you create your Service Account for the right project, and that you use the right Guid for the Project ID and Environment ID.

Maybe you can also try to remove the “jsonData” you pass to the request. I don’t know if the scopes are necessary and if the are added to the scopes of the Service Account or if they override it …

No worries man, thank you a lot for your time!
Still no luck though… I opened a ticket with customer service and will post any updates here.

I might be missing something but why don’t you just call Application.Quit() instead of trying to manually self de-allocate?

You are right @jackward84 , didn’t think about it