Correct way of creating game sessions / player sessions

Currently i’m not using flexmatch, but i will in future, so i’m asking this question:

Currently when player want’s to play, lambda function check is there any game session, if yes, return informations about game session back to player so player can connect… if there is no available game session, create new one and than create player session

Create Game Session:

await GameLift.createGameSession({
MaximumPlayerSessionCount: maximumNumberOfPlayersInSession,
FleetId: FleetIds[0]
}).promise().then(data => {
selectedGameSession = data.GameSession;
}).catch(err => {
errorResponse = err;
});

Create Player Session:

await GameLift.createPlayerSession({
GameSessionId: selectedGameSession.GameSessionId,
PlayerId: event.playerid
}).promise().then(data => {
console.log("Created player session ID: ", data.PlayerSession.PlayerSessionId);

            responseObj.status = 'ok';
            responseObj.payload = data.PlayerSession;


        }).catch(err => {
            errorResponse = err;
        });

But if 2 players request for game session in nearly same time, there will be created 2 game sessions for each player one game session… I don’t want that, i wan’t to have one game session with this players…

Can someone guid me how can i solve this problem?

Can this be solved with createGameSessionQueue ?

And over this i want to add matchmaking rules.

Thnx!

The correct GameLift way is to just use FlexMatch

Without FlexMatch theres nothing in GameLift thats going to buffer/combine your create game session requests. You will need to add components that buffer the requests and batch them into game sessions so players can be placed in the same game session (hmm… sounds a little like FlexMatch)

BTW Queues do not really help here because what you are trying to do is is effectively group and match players to game sessions. Queues are designed to find the best resource to create a game session on, so you would end up with the same problem. As an aside, its recommended to always use Queues rather than direct fleet placement anyway (https://docs.aws.amazon.com/gamelift/latest/developerguide/queues-intro.html)

There are lots of different ways to achieve game session request batching from using actual queues like SQS or Kinesis to writing requests to a data store like dynamodb and then have secondary process that processes them using some grouping logic. Servers could also batch internally by passing requests into a memory buffer and then having background threads process in batches (but this doesn’t really match your serverless design).

There are of course a lot of design decisions to make here such as the window to wait for batches, how to match players together etc.

Theres a great blog here with one such design https://aws.amazon.com/blogs/gametech/fitting-the-pattern-serverless-custom-matchmaking-with-amazon-gamelift/

And if you look around for other simple request batching design or matchmaking you will probably get a lot of suggestions.

Out of curiosity, is there a reason you aren’t migrating to FlexMatch for this?

I’m definitely working on flex match, i have read a lot of documentation, so i think that FlexMatch is going to “solve” my problem.

How I understand, with FlexMatch playerSession is not created immediately… once game session is found, for each player with match ticket, session is created and gameSession object is returned to client?

Thnx

I have integrated FlexMatch.

My Rule Set is:

{
“name”: “Deathmatch”,
“ruleLanguageVersion”: “1.0”,
“playerAttributes”: [
{
“name”: “rank”,
“type”: “number”,
“default”: 1
}
],
“teams”: [
{
“name”: “red”,
“minPlayers”: 1,
“maxPlayers”: 10
}
],
“rules”: [
{
“name”: “FairPlayerRank”,
“type”: “distance”,
“measurements”: [
“avg(teams[].players.attributes[rank])"
],
“referenceValue”: "avg(flatten(teams[
].players.attributes[rank]))”,
“maxDistance”: 10
}
],
“expansions”: [
{
“target”: “rules[FairPlayerRank].maxDistance”,
“steps”: [
{
“waitTimeSeconds”: 10,
“value”: 15
},
{
“waitTimeSeconds”: 20,
“value”: 20
},
{
“waitTimeSeconds”: 30,
“value”: 25
}
]
}
]
}

  • What i want to achieve is that i want to put all players with rank difference no more than 10, is this rule set correct?

And when i request match on 3 clients, in the same time, sometimes there are 2 game sessions created, and sometimes is 1 game session with all clients… How can i achieve that all 3 clients are always on same game session?

My test clients have rank:

  • Client 1: 16
  • Client 2: 17
  • Client 3: 13

@Pip

I think the rule set you have is close to what you want. If you wanted the max difference between the min and the max rank in the match to be within 10, the rule should look like:

{
“name”: “FairPlayerRank”,
“type”: “distance”,
“measurements”: [ “min(flatten(teams[].players.attributes[rank]))" ],
“referenceValue”: "max(flatten(teams[
].players.attributes[rank]))”,
“maxDistance”: 10
}

Since you are using expansions, the key thing is to understand how that works today. We always use the age of the newest player in the potential match to determine what to expand to. If we have 3 tickets and one is 11 second old, one 7 seconds, and one 4 seconds we’re going to use the rules at 4 seconds (maxDistance = 10). 15 seconds later (26, 22, 19 seconds age for the tickets) we’ll use 19 second rules for maxDistance of 15. But, if we examined a potential match of just the 26 and 22 second players then the newest is 22 and we’d use the 10 second expansion (maxDistance=20).

Oftentimes if players are arriving slower than your expanding out you will end up with more fragmentation than you may have intended.

If the rule set tweak suggested above doesn’t give the behavior you were expecting you can look at the times the various tickets were created and cross-reference w/ the rules to understand what happened.

Other options to at least consider would be to tweak the expansion schedule – generally the time difference between expansions should get larger with each one for the best results (e.g. instead of 10, 20, 30 second intervals, perhaps 7, 15, 30 would work better). Alternatively, you could examine the backfill or auto-backfill features to form partial matches and then fill them out further incrementally.

Let us know if any of this helps.

@BrianS-aws

I have successfully implemented matchmaking… and my ruleset currently looks like this:

{
  "name": "Deathmatch",
  "ruleLanguageVersion": "1.0",
  "playerAttributes": [
{
  "name": "rank",
  "type": "number",
  "default": 1
},
{
    "name": "accountType",
    "type": "string",
    "default": "regular"
}
  ],
  "teams": [
{
  "name": "red",
  "minPlayers": 1,
  "maxPlayers": 10
}
  ],
  "rules": [
{
  "name": "FairPlayerRank",
  "type": "distance",
  "measurements": [
    "min(flatten(teams[*].players.attributes[rank]))"
  ],
  "referenceValue": "max(flatten(teams[*].players.attributes[rank]))",
  "maxDistance": 10
}
  ],
  "expansions": [
{
  "target": "rules[FairPlayerRank].maxDistance",
  "steps": [
    {
      "waitTimeSeconds": 10,
      "value": 15
    },
    {
      "waitTimeSeconds": 20,
      "value": 20
    },
    {
      "waitTimeSeconds": 30,
      "value": 25
    }
  ]
}
  ]
}

What is the problem:

  1. Get 2 mobile devices (with same playerRank)
  2. Press battle button (request matchmaking) on both devices at the same time

Somehow it happens that players are placed in different sessions.

How can i solve this problem?

Maybe i should tweak expansion waitTime, from 10 do 7?

Thnkx