On-the-fly tournament or matches in match

Hi,

I’m not sure what and how to use to do what I want to achieve.
The game will be a kind of battle royale but played by duels.

The two ways I see to do that are :

  1. a player create a tournament, with cutom server code, or join an existing one.
    then uses matchmaking to find an opponent in the tournament.

  2. a player use matchmaking to create or join a “big” match with n players.
    then uses matchmaking to find an opponent which is in the “big” match.

thanks in advance

Hi @mataemon welcome :wave:

Before I can suggest the best approach with Nakama. What sort of matchmaker criteria do you have for the players to compete with each other? Is it an ELO system or more random? Do players have to be online to compete together?

Hi @novabyte and thx for your reponse,
I think it would be random at first (if we get a lot of players we could consider an ELO system…).
Yeah, they have to be online, the duels would be authoritarive active turn-based.

Players chain duels as long as they win, until there’s one player left. Then the “tournament” ends. Players get points according to their position.

I hope I explained clearly enough.
Thanks again

@mataemon I think the best approach for this game design is to have a multiplayer match handler act as the tournament controller. That way you can use the match listings API to find live tournaments to join and then the match handler can split the players up into one on one duels and store results as the tournament progresses until a winner is determined.

The only remaining question is how many players is N players you mention above? Would it be 20-30 players or are we talking about hundreds?

Thank you for your answer, I will go for that.
The N will be about 100 players.

I have an other question, we probably will implement bots to fill the tournament.
How do you think we could implement them?
With lua or go scripts inside nakama ?
Or with standalone program (js or c) using client SDK?

thanks and have a good day

@mataemon At 100 players you’ll have no problem with the tournament controller being a match handler.

How do you think we could implement them?

For some reason we find a lot of game teams end up with separate tools they develop and then deploy to connect to the game servers and simulate real players when against live opponents. We really dislike this approach :slight_smile:

It means that you’ve got another application to deploy and maintain, its costly to run additional servers, and really unnecessary when the bots can be running within the match handler itself. We’d implement it with Go but Lua (or very soon JavaScript) will work just as well.

Hope that helps.

That helps a lot thanks!

1 Like

Hi @novabyte,
just to be sure I got it right. There’s a unique match handler which will manage all the duels messages? (I guess by creating duels ids in messages and managing the list of duels)
Or players join a new match handler for each duels? (Is it possible for a player to join multiple matches simulanteously?)

You mean in the match loop, right?
Not knowing Lua (nor Go), I don’t know what is the best (and cleanest) way to code that, can I implement the bot in an other module?

Thanks again for your answers!

There’s a unique match handler which will manage all the duels messages? (I guess by creating duels ids in messages and managing the list of duels) Or players join a new match handler for each duels? (Is it possible for a player to join multiple matches simulanteously?)

@mataemon I would manage all the duels for that specific tournament in a single match handler for those participants. Think about it like a virtual match system. You have the logical match in Nakama managed by the match handler but within it you code and handle all the individual duel matches and track any state for each of them to be able to reconcile at the end and present winners and scorings.

You mean in the match loop, right? Not knowing Lua (nor Go), I don’t know what is the best (and cleanest) way to code that, can I implement the bot in an other module?

Yes, the bots would take their actions in the match loop. Right now the server supports Lua, and Go to write the game server logic in. Shortly we’ll also support JavaScript to write your logic but there’s no way without learning one of these languages to write server logic for Nakama server.

Thank you @novabyte !
There’s the ultimate question (for this thread), I promise.

I tried to test my bot implementation, so I configured my match with 1 (and only) player. When my player tried to join the match an error occured.
This exception is in the core of Nakama and cannot be override?
I hope there will more than one player against 100 bots, butjust in case…

When my player tried to join the match an error occured. This exception is in the core of Nakama and cannot be override?

@mataemon It would help if you could share the server logs around the error and the specific error you got back in the game client.

EDIT : Here are the server side logs :

{"level":"debug","ts":"2020-11-10T15:49:53.623Z","caller":"server/pipeline.go:62","msg":"Received *rtapi.Envelope_MatchmakerAdd message","uid":"5f0d400f-a5cf-4182-b5df-a1e0354d2ea0","sid":"717f5b65-52fc-4204-98f7-07781f12e168","cid":"0","message":{"MatchmakerAdd":{"min_count":1,"max_count":128,"query":"*"}}}
{"level":"debug","ts":"2020-11-10T15:49:53.624Z","caller":"server/session_ws.go:374","msg":"Sending error message","uid":"5f0d400f-a5cf-4182-b5df-a1e0354d2ea0","sid":"717f5b65-52fc-4204-98f7-07781f12e168","payload":"eyJjaWQiOiIwIiwiZXJyb3IiOnsiY29kZSI6MywibWVzc2FnZSI6IkludmFsaWQgbWluaW11bSBjb3VudCwgbXVzdCBiZSBcdTAwM2U9IDIifX0="}

and here is what I got with Unity client :

An error has occured while joining the matchmaker: System.Net.WebSockets.WebSocketException (0x80004005): Invalid minimum count, must be >= 2
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <fb001e01371b4adca20013e0ac763896>:0 
  at Nakama.Socket+<AddMatchmakerAsync>d__52.MoveNext () [0x000d8] in <466f65831af84efeb3c23fc78e4fe874>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <fb001e01371b4adca20013e0ac763896>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <fb001e01371b4adca20013e0ac763896>:0 
  at MainGame.Scripts.Matchmaking.MatchmakingManager+<EnterQueueAsync>d__0.MoveNext () [0x00080] in /Users/vincent/dev/projects/Hangman/Assets/MainGame/Scripts/Matchmaking/MatchmakingManager.cs:46 
 #0 GetStacktrace(int)
 #1 DebugStringToFile(DebugStringToFileData const&)
 #2 DebugLogHandler::Internal_Log(LogType, LogOption, core::basic_string<char, core::StringStorageDefault<char> >, Object*)
 #3 DebugLogHandler_CUSTOM_Internal_Log(LogType, LogOption, ScriptingBackendNativeStringPtrOpaque*, ScriptingBackendNativeObjectPtrOpaque*)
 #4  (Mono JIT Code) (wrapper managed-to-native) UnityEngine.DebugLogHandler:Internal_Log (UnityEngine.LogType,UnityEngine.LogOption,string,UnityEngine.Object)
 #5  (Mono JIT Code) System.Runtime.CompilerServices.AsyncMethodBuilderCore/MoveNextRunner:InvokeMoveNext (object)
 #6  (Mono JIT Code) System.Threading.ExecutionContext:Run (System.Threading.ExecutionContext,System.Threading.ContextCallback,object,bool)
 #7  (Mono JIT Code) System.Threading.Tasks.AwaitTaskContinuation:InvokeAction (object)
 #8  (Mono JIT Code) System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation:Run (System.Threading.Tasks.Task,bool)
 #9  (Mono JIT Code) System.Threading.Tasks.Task:FinishStageThree ()
 #10  (Mono JIT Code) System.Threading.Tasks.Task`1<TResult_REF>:TrySetException (object)

“Invalid minimum count, must be >= 2”

@mataemon You can see the error in the logs output. You cannot attempt to find a match with the matchmaker when you’re not looking for at least one other opponent (i.e. yourself + 1 more).

Yes I know, that’s why I asked

This exception is in the core of Nakama and cannot be override?
sorry for my english if I’m not understandable enough.

Now I have an other question, just to be sure I’m doing right
If I use the matchmaker with minCount=2 and maxCount=128, after the second player is matched, the match is created by the matchmaker_matched. And if a third player use the matchmaker, it returns a ticket for a new match.

It would be nice to have the matchmaker wait for an amount of time before creating the match to accept more players.

So for my third player can join the match, I have to make an RPC call to a runtime code which list available matches and return a match. And if it doesn’t return a match then the player use the match maker.
Am I right, is this the only way to do matches with a range of player count?
And there is no way to list matches from the client directly?
So the maxCount is only used to forbid new players to join when match is full?

Now if I want to wait some time before starting the match with bots if needed, I don’t make players joined the match right after beeing matched, and in the match_loop I wait new players to join during some ticks before sending a message to matched players to join the match with x bots and start playing.
Is it the right way to do it?

Sorry for my dumb questions and thanks again

And there is no way to list matches from the client directly?

my bad, I just saw in the code the method client.ListMatchesAsync, I could’nt see it in the docs.

To sum up, for minCount != maxCount case, I see 2 ways of creating an authoritarive match:

  • a player list available matches from the client (or an rpc call), if one is found, he joins it, if there’s no match, he use the matchmaker to create one => The first two players will use the matchmaker, the third and up will join after
  • a player calls an rpc method (like findorcreatematch in the docs) => the matchmeker is never used

the second method seems to be simplier, but it doesn’t use the matchmaker.
What are the pros and cons ?

The matchmaker is usefull only when minCount == maxCount ?

Thanks again

The matchmaker is configured to match as soon as possible as long as the minimum criteria is met. If there are enough players in the pool to satisfy your maxCount then it will do that, if not anything down to minCount is acceptable.

If you want finer control then your 2nd option is best. A “find or create match” RPC function gives you total control of match criteria, size restrictions, and matchmaking behaviour. Have your matches initially be in a “waiting” state until you decide to start gameplay.

I am confused about minCount and maxCount. If minCount = 2 and maxCount = 4 and query = “*”, as soon as 2 players are available, the players are matched. If I use the matchmaker, how can other 2 players join that match? If it’s “as soon as possible”, then what is the point of maxCount?

I hope you understood my misunderstanding.