Lobby Process

I’m trying to use coherence to set up a start of game workflow. Using the lobby connection Dialog I can have the player create and join a lobby. I need to be able to get the list of players so I can assign them to different teams before the match starts.

I tried doing this with the events OnConnected and OnSync. But it doesn’t seem like the bridge detects the players until the game is launched.
I event tried delaying the method that would fill my player connection objects by a few seconds, but that doesn’t seem to be reliable at all.

Does anyone have a working example of a proper lobby to game process flow that I can model for my prototype?

Hey!

You can get the list of existing players in your lobby by checking the LobbyData structure in your LobbySession object.

You can peruse the lobby connection dialog code, there you can see how we’re using the players list to print it in the connection dialog UI.

If you want to assign players to teams before the match starts, you can do so by updating assigning player attributes (for example, a string with the name of the team)

The OnConnected and OnSynced events are related to when the match has already started and won’t fire when your simply sitting in the Lobby.

Once the Lobby has the state you desired (number of players and assigned teams), you can start the game session by having the owner call the StartGameSession method. There is an example of how this is done in the connection dialog script.

You can read more about the Lobbies in the documentation:

I was able to create a LobbyManager that allows me to listen to some LobbySession Events. More often than not, the documentation seems to leave me more confused than I was before. I am still having a hard time understanding how to set data for each of the players as needed.

This link talks about how one might go about using the player data and the lobby data together, but there’s no code example to show this.

You can use this LobbySession instance to interface with the Lobby itself, you will find methods to leave the Lobby, update your Player Attributes or send a message to other Players. You will also be able to query all the information about the Lobby itself, like every Player present, their Attributes, maximum Players, and other Lobby properties.

There doesn’t seem to be any examples of setting an Attribute specifically for players. Digging through Rider, I see the method AddOrUpdateMyAttributes(). What I can find out with the use of GPT4, it seems like there’s no way to update the attributes of another player directly.

What would be the best way to have my lobby manager set the attribute of which team each player is on?

You cannot edit player attributes from someone else, this is by design and standard practise in Lobby APIs.

You can use aggregators to achieve what you need.

Lets say you have two available teams called blue and red, you create the lobby with one lobby attribute for each, which are aggregated from player attributes.

Creating the lobby:

var redLobbyAttribute = new CloudAttribute(RedTeamTotal, 0, IntAttributeIndex.n2, IntAggregator.Sum, true);
var blueLobbyAttribute = new CloudAttribute(BlueTeamTotal, 0, IntAttributeIndex.n3, IntAggregator.Sum, true);

var createOptions = new CreateLobbyOptions()
{
    LobbyAttributes = new List<CloudAttribute>() { lobbyAttribute, redLobbyAttribute, blueLobbyAttribute },
    MaxPlayers = MaxPlayers,
    Region = selectedRegion
};

// Matchmaking phase
var task = lobbyService.FindOrCreateLobbyAsync(findOptions, createOptions);

This will create the lobby with the attributes I mentioned, which will be aggregated by adding together the player attributes in the indexes n2 for the red team, and n3 for the blue team.

You can then have each player that joins the lobby automatically join a team based on the existing lobby attributes:

void OnJoinedLobby (LobbySession lobbySession)
{
    var playersInBlueTeam = lobbySession.LobbyData.GetAttribute(BlueTeamTotal).Value.GetLongValue();
    var playersInRedTeam = lobbySession.LobbyData.GetAttribute(RedTeamTotal).Value.GetLongValue();
      
    var joinTeam = new CloudAttribute(RedTeam, 1, IntAttributeIndex.n2, IntAggregator.None, true);
      
    if (playersInRedTeam > playersInBlueTeam )
    {
        joinTeam = new CloudAttribute(BlueTeam, 1, IntAttributeIndex.n3, IntAggregator.None, true);
    }
      
    lobbySession.AddOrUpdateMyAttributes(new List<CloudAttribute>() { joinTeam });
}

Does this mean that when the Game Session starts, to retrieve player data, I would still need to access the Lobby Session’s Attributes & Player Attributes?

It definitely seems like a major pain dealing with data through this attribute system. Especially using it in the way suggested to utilize the aggregate features. Above in order to check the player’s assigned team, I would now need to check for both attributes.

Hey R_FOX - when you join a room from a lobby, the lobby will be persisted, so attributes will be available. In your use-case you’re wanting to have each player join a team they were pre-assigned during lobby time, right?

@miguel-coherence or other SDK members Do you have specific advice on this use case?

If you need easier and frequent access to whose team a player is on during the game session, you can save a players team in a synced variable that will be replicated through the replication server. That way you don’t need to check the lobby at all during gameplay.

Going back to my original goal. I am looking for what I would consider a best practice for replicating a gameplay scenario of the following.

Let’s use a Team-Based Hero shooter Battle Royale as an example.

  • When the player starts matchmaking they will end up in a lobby.
  • Players are going to be assigned a team with a couple of other players.
  • Before the match starts each one of the players will get to choose which character avatar they will play the game with.
  • After character avatars have been selected, the game session will load.
  • Various managers should know ALL of the players within the game session. (example: UI elements that would display a list of this data for all players within the match.)
  • After the match, the player match data is sent somewhere to be stored.

Using common practices

  • How would the game assign the teams and character avatars for the players within the lobby?
  • How is the player data information from the lobby passed to a player connection object within the game session?
  • If not passed directly, how can the player connection object determine which lobby player it came from?
  • How does a GameManager gain access to the data for all of the players in the game session?

Hopefully, I am communicating this well. Maybe I am assuming something like the above is common practice, but if not, then it would also be really helpful to know that I’m trying to move in the wrong direction.

I can give high level advice of possible approaches but I don’t think there is a common practise to adhere to that you can follow to a T, each game and use case always have different needs, and every approach will have its pros and cons. It is up to you to decide how you want to handle your data, we just give the tools to do so.

  • How would the game assign the teams and character avatars for the players within the lobby?

The only way to store data within a lobby is to use the attribute system. The main use case for attribute usage is for matchmaking purposes. For example, lets say you want a MMR system in your game, and you want to match players based on a skill rating, you can use the lobby attributes to calculate the average MMR of any given Lobby and matchmake a player against different lobbies based on his own rating.

However, is not the only use case, if you have a very simple lobby system that doesn’t require low-latency high speed replication, you can use the Lobby attributes to store whatever data you need from your Lobby, in your case, the team a player belongs to.

I don’t know how you’re referencing “character avatars” or what specifically this refers to inside Unity, but if you can reference it simply with a string, you can also use the Lobby attributes for that.

If your Lobby system requires more involved replication then you can always start a room together with your Lobby and use the room to replicate whatever data you need.

  • How is the player data information from the lobby passed to a player connection object within the game session?

coherence doesn’t have any specific tools to do this. Player connection objects are described here: Client Connections | SDK 1.2 | Unity Multiplayer SDK Documentation | coherence

You can create a MonoBehaviour, attach it to your client connection prefab, and have it fetch your current team from the Lobby in the Awake method, you can fetch your current team by referencing the coherenceBridge and accessing your current lobby from there.

This is one possible approach off the top of my head that I can come up with, without looking at your actual project.

  • If not passed directly, how can the player connection object determine which lobby player it came from?

This is responsibility of each client. A client connection instance should figure out his own team and replicate it to others.

  • How does a GameManager gain access to the data for all of the players in the game session?

It is all available through the CoherenceBridge.

I’m not entirely sure what you mean by the data for all the players, in the Lobby or when you’re already inside of a room?

Lobby players are available through your current Lobby Session that you can get from the Lobby Service instance, accessible via the CoherenceBridge.CloudService instance, you can see examples of this in the Lobby samples.

If you mean when you’re already connected to a room, like I mentioned previously, you can use the Client Connection prefabs to store specific data about a player. But you can also use another entity of your choosing. This is very game specific to give a one-fits-all solution, but we’re happy to help provide advice if you give specific examples of implementations you’re trying to achieve.

I just want to reiterate the differences between a Lobby and a Room.

A lobby is simply a way to aggregate players, and its main use case is to perform matchmaking for your players based on any given arbitrary player attribute, like I mentioned before, a possible use case is MMR-based matchmaking.

If you do not need to do any matchmaking based on attributes, you may consider not using Lobbies at all, they are not mandatory. You can simply work with the Rooms API.

MMR-based matchmaking will be a mandatory feature for this project.

You can create a MonoBehaviour, attach it to your client connection prefab, and have it fetch your current team from the Lobby in the Awake method, you can fetch your current team by referencing the coherenceBridge and accessing your current lobby from there

This is responsibility of each client. A client connection instance should figure out his own team and replicate it to others.

How? I’m using the bridge’s Connection Prefab feature to create the player connection object. I have the ClientID for the connection. But that ClientID isn’t the same as the Lobby player’s UserID.

I’m not entirely sure what you mean by the data for all the players, in the Lobby or when you’re already inside of a room?

Assuming I can get the required data from the Lobby and store it within an object during the game session, What is a viable solution for having a GameManager that holds references to the players? If fetching that information from the Bridge is the solution, I think I can make that happen.

You don’t need the player user Id or the client id.

The LobbySession instance has a MyPlayer property, you get your current team from there.

The CoherenceBridge.ClientConnections API has a GetMine method, thats it.

Then you do:

CoherenceBridge.ClientConnections.GetMine().GetComponent().MyTeam = LobbySession.MyPlayer.GetAttribute(“my-team”).GetStringValue();

That is just about all you have to do. Obviously over simplified because I don’t know how your code looks, but it shouldn’t be much more complicated than that.

Once you have replicated your own team through the client connection instance, other clients will have done the same, so you can iterate the client connections and check everyones team in each client.

Hope this helps.