question

contact-3 avatar image
contact-3 asked

Best way to port unity - supersocket (ws) - c# server to Playfab [SPECIFIC]

Hi,

I'd like to get into playfab to manage my users credentials, user data, monetization, matchmaking and server load balancing.

Right now we have a functional game that works with a c# custom server https://github.com/kerryjiang/SuperSocket, Unity connects to it through a custom WebSocket logic.

For now we're using a custom Mongo instance to persist players data.

We've seen Photon plugins, it seems we could easily plug our current logic into it (we solely need to matchmake players with others or IA and to send asynchronous messages), we already have a serializable gameState too.

What would be the best way to address our changes and to integrate with playfab/photon ? Is even photon necessary or could we use your own server system directly for room creation/matchmaking/load balancing ? What's the most mature in your own opinion ?

Concerning Load-balancing, is there a way to manage it without creating rooms ? I'd like to keep a list of available player looking for a match and create a room only if two of them "match". Is this a normal behaviour?

Can we create a room with only 1 player for when the player connects to deal with custom account logic without having to implement JS code or to host our own account server logic ?

Anyway it seems we at least need to add Playfab SDK to our unity project.

Lot's of questions :)

Cheers

Custom Game Servers
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

No, matchmaker servers should always keep the list of games and players in memory. Trying to use Shared Group Data for that would fail for two reasons:

1. It's a Web API call and will take a non-trivial amount of time to return. Matchmaking, by necessity, has to be as low-latency as possible.

2. More importantly, this would result in a high frequency of reads and writes to/from the data. That would very likely exceed the rate limit for the API call, resulting in the matchmaker server being unable to query it, due to being throttled.

For a custom matchmaker, I would recommend hosting that separately. Our game server hosting is designed for game session servers. With a matchmaker, if you have so many players that you need more than one server running to manage the load, you would need to make sure they split the player load fairly evenly, so that you don't have the problem of one server having only a small percentage of your user base. Using our game server hosting this way, you would use our matchmaker to get the players into your custom matchmaker, and then use it to get them to the actual game session. If enough players joined that we had to spin up a second instance, you'd have a relatively small number of players on that second machine to start, making for a poor matchmaking experience.

For communication with the client, the server is automatically given a port to use (in the 9xxx range) in the default command line parameters.

As to load/concurrency, we can scale to any number of servers you might need. Again, it takes AWS EC2 up to 10-12 minutes to get us a server, so you do need to have your configuration set to ensure that your peak number of games that could need to start over about a 15 minute period have free slots. If you have configured your game to make sure you don't run out of slots, then yes, there would not be any issue with scaling for any number of concurrent users.

I'm not sure how you're using "replicate" in this context. The common usage in servers refers to duplication of data, which isn't really applicable to custom game servers. Each server is distinct from the others - the base build is loaded onto it, and it maintains its state while running. User data for players is stored in a reliably consistent store which is separate from the custom game servers, so it is always what was last written to it.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image
contact-3 answered

What about using a redis like cache for the matchmaking queue ? This way we could still use playfab hosting and scaling for the matchmakers (with a fairly high value in users slots) so there is no userbase split.

To clarify, my aim is to use playfab only as I want to minimize the use and management of external services.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

Any in-memory data store you like would work, but that doesn't change the fact that each server instance will have separate data. The issue is that if you have enough users looking to join a game that we have to start a second instance of your matchmaker, that's what splits the user base into separate matchmaking queues. And when that happens, at first the second server will have few players, making for a poor matchmaking experience. And since it'll take longer for those players to join games (and so, leave the matchmaker server), that'll mean the player base will be split on matchmaking for quite a while, most likely.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image
contact-3 answered

Right now I managed to let a player ask for a "1player" match and to connect on the returned server, this one doing the redeem/left. There is no split issue for AI matches and regular operations.

I still don't really get how the multiplayer matchmaker works and how it'll "split" the player base even if we use an external in memory storage for the queue. There sur will be some concurrency issues to manage.

I have the feeling that in real life anyway there will be no such thing as the need of two matchmaker servers even on your hosting.

The management of a list of 10k items to match seems relatively cost-less nowadays. And if we reach this amount of CCU looking for a game, well... we'll have other things to think of and splitting won't really be an issue. Using playfab for the matchmaker as I said is mostly for convenience and protection against server failure. I'm not even sure that Dota 2 with 600k CCU has more than ( insert here random percentage) of user LFG at the same time at peek-time.

Il'continue the implementation test and let you know.

Thanks for the great support.

A suggestion for the documentation : It would be really util from a developer point of view to have a sort of comprehensive sequential/visual diagram on how to manage the API for client/server/matchmaking/playfab calls, it took me quite some time to dive in and understand how to deal with it. Samples are great but it's always difficult to jump into someone's else code and way of thinking. Other people that I know trying to understand what were the real services you provide where a bit lost too.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

The normal way to build a matchmaker server is by having the data on all the players in the queue running in-memory on the matchmaker server itself. That's specifically the model I'm discussing - in that case, if multiple matchmaker servers are in use, the user base is necessarily distributed across them, which is what I'm describing as an issue.

If you're using an external server to host the matchmaking data, I would have to recommend using that server for the matchmaking logic, as well. If the server making the decision is separate from the server with the data, and you have multiple servers making matchmaking decisions based on data from that separate server, you'll have to use locks to ensure you don't wind up with errors in the match decisions, which is going to impact your performance.

But to clarify, I'm not saying you can't host your matchmaker in our service. We have multiple titles that are doing something I described earlier, using a server build for a lobby/matchmaker. And in this case, if you're positive you'll never need more than one server for your matchmaking, this could work just fine. But I'd be remiss if I didn't call out the potential issues it could cause in the high CCU case.

And thanks for the suggestion - we've been discussing internally some improvements we want to make in the documentation, and having more visual flow type of docs are definitely on our list.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image
contact-3 answered

Thanks for pointing this out then. For now it'll be quite sufficient then.

I understand MaxGamesPerHost is the number of server instances that can run on one addressable machine, then what is the Min free Slots configuration for, is it the minimal number of instances with no player on an adressable machine at a given time ?

Concerning the Min player count and Max Player Count, as stated in documentation https://api.playfab.com/docs/custom-game-servers for general purpose server we can set a high value of Max Player Count so thousands of players will be matched together in a game instance.

Now for 2+ player games. The matchmaker will rely on the game mode to match players I guess, so if I want exactly 2 players in a game i'd have to write 2/2 for min/max values.

But then it will be one match per Instance. As you say if spawning a server takes roughly 15minutes then we'll for sure prefer to host several matches on one instance so spawning servers is done less often.

Did I get something wrong ? It's definitely there that we'll have to use our own matchmaker.

2 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image contact-3 commented ·
0 Likes 0 ·
contact-3 avatar image contact-3 commented ·

Do we have to call Register/Deregister server on PlayFab Hosting ? For now it's in the build, to know if we have to externalize it in the tests or keep it in the server code.

0 Likes 0 ·
brendan avatar image
brendan answered

The parameters for the build are here (linked from the tutorial): https://api.playfab.com/Documentation/Admin/method/ModifyServerBuild. In short, the min free slots tells us how many game server instance slots need to be available (available capacity) at any given time. Since it can take AWS 10-12 minutes to get us a new server host when we request one, you should determine the maximum number of players who might be trying to matchmake within about a 15 minute period (your peak usage level) and set the min free slots to make sure you'll always have free capacity available for that many players. Again though, the distinction is a server host is the machine on which multiple instances can run. When you start a new instance (which takes almost no time at all, as long as there's at least one free instance slot), we check if that puts you below the min free slots level, and at that point request a new server host.

For a two player game, you would set the min/max to 2/2. But yes, to optimize your server use, you may well want to have many players join each instance, and then manage the actual sessions in the server logic.

Thanks - we're working on getting the Matchmaker API docs fixed right now. They should be back shortly.

Register/Deregister is specifically for externally hosted servers. If you're using our server hosting, you do not use that, or the heartbeat API call (the three API calls we added specifically for external hosting: https://api.playfab.com/docs/external-server-hosting).

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image
contact-3 answered

So how do I do that.

- First I manually match players together (they are all matched on the matchmaker server). I have X playfabId I know I want to put on the same gameplay server. For all the player I call NotifyMatchmakerPlayerLeft because they left the matchmaker game mode.

- On the matchmaker server , I call StartGame for one player with the wanted game mode then JoinGame with the others and the returned LobbyId.

- When they all arrive in the destination server, where the actual gameplay will be, and that my gameplay is actually started I can RedeemMatchmakerTicket for all the players on the gameplay server.

- When the gameplay is over I call NotifyMatchmakerPlayerLeft for the players and I can send them back to the matchmaker/general server.

(It seems I don't need to use Matchmaking api such as PlayerJoined etc ...)

So this way I can definitely put 2 x MAX_ROOM_ON_INSTANCE players in the game mode configuration.

Does this seems correct ?

I think we're finally reaching this.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

brendan avatar image
brendan answered

A few adjustments to the above:

You'll be sending those players the info about the server they need to join (the LobbyId) via the matchmaker server, so the order of operations should be to send them that info and then have them leave the matchmaker server (at which point it maeks the NotifyMatchmakerPlayerLeft call).

For RedeemMatchmakerTicket, bear in mind that it would have to be the ticket the client received to join your custom matchmaker server (since you're not using our matchmaker to join the gameplay server). That means that on your gameplay server, you need to make the call using the LobbyId of your matchmaker. This is the other issue I should have highlighted with using our scalable EC2 for your matchmaker - there's really no way for your gameplay servers to communicate with your matchmaker, so a hacker could use GetCurrentGames to find a newly created server and try to join it, passing the matchmaker ticket he gets when he calls Matchmake to get into your matchmaker server. A solution to this would be to use a crypto model to generate a signature on your matchmaker which your gameplay servers would check, using a private key in your game server build.

For your gameplay server build, since you don't want players to join it via our matchmaker, make sure you set StartOpen to false in the Game Mode.

Since you're not using our matchmaker to get players into the gameplay servers, there's no need for those servers to call NotifyMatchmakerPlayerLeft.

Please do use PlayerJoined/PlayerLeft from your gameplay server to indicate when players join and leave them. That will allow us to propagate the active games and archived games lists with the information on which players are/were in each session.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image
contact-3 answered

I'll try to explain better what I'm trying to achieve. In the end I think I'm still using your matchmaker to select the gameplay servers, my "matchmaker" would just be an intermediate. Internal commands are sent throught webSocket. It does not seem to me that my GP server will communicate with the custom matchmaker at all and vice-versa.

I have 3 endpoints, Client, Matchmaker Server, Gameplay Server

First I connect to the matchmaker (this part is done and is working)

Client > PlayFab MatchMake("matchmaker")

Client < Matchmaker ip/lobby

Client > ws (websocket) Matchmaker Server

Client > InternalOpenAccount( playFabId, Ticket, Lobby )

Matchmaker -> PlayFab RedeemTicket( playFabId, Ticket, Lobby )

Now comes the matchmaking : ( I assume here that the server can call MatchMake in behalf of a client )

Matchmaker Server > DoMatch (client 1, 2, ... ) (this is where we match our players, then we ask playfab to find them a GP server)

Matchmaker Server -> PlayFab MatchMake( client 1, CreateIfNoGame )

( QUESTION : Can I get how many slots are left in the gameplay server, or can I ask for a gameplay server that has enough slots for my game ? Or is there a way for players to be assured to play together, such as friends ? I'm concerned by concurrent MatchMake access if several games are created at once. )

MatchmakerServer < Gameplay Server ip/lobbyGP

MatchmakerServer > PlayFab MatchMake ( client 2, lobbyGP), MatchMake ( client 3, lobbyGP ), ...

MatchmakerServer > InternalLFGResult Client 1,2,.. ( IP, LobbyGP, Ticket, InternalGameId )

MatchmakerServer > PlayFab NotifyPlayerLeft (client 1,2, ...) and close WS (Reason : Changing host )

Then clients connect to gameplay server :

Client 1,2,..> ws GamePlayServer ( IP )

Client 1,2,..> Internal join game command (LobbyGP, Ticket, InternalGameId)

GP > PlayFab RedeemTicket( playFabId, Ticket, LobbyGP)

GP > CreateOrJoinGame( InternalGameId )

When game is over

GP > Close WS (Reason : Changing host )

GP > PlayFab NotifyPlayerLeft ( playFabId, LobbyGP )

and we connect back to the matchmaker.

ISSUE 1 : In the case that MatchMake cannot be called in behalf of someone it will be quite simple to do it through clients instead on the server.

Matchmaker => Client 1 Internal Go Find a GameplayServer

Client 1 => matchmake

Client 1 => Internal GPServerToJoin (LobbyId)

Matchmaker => Client 2, .... ( LobbyId )

Client 2 => matchmake

ISSUE 2 : Concurrent matchmake calls for several InternalGame.

Solution 1 : create a game instance for each internal game, but I don't like the fact that 100 games = 100 processes. You tell me but is seems quit counterproductive. If its not then its the simplest way.

Solution 2 : Find a way to reserve seats. (There is no such thing as for playing with friends ? )

4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

contact-3 avatar image contact-3 commented ·

Concerning `GP > CreateOrJoinGame( InternalGameId ) ` of course its an internal CreateOrJoinGame nothing related to playfab

0 Likes 0 ·
contact-3 avatar image contact-3 commented ·

For issue 2 found this : https://community.playfab.com/questions/3806/photon-playfab-matchmaking-parties-invite-friends.html

Server would act as the main client reserving slots for everyone. If it don't manage to reserve enough slots through MatchMake for everyone then it would call startGame.

Slot reservation would be a better option but if it's not available no choice :)

0 Likes 0 ·
contact-3 avatar image contact-3 commented ·

Issue 2 could also be done by updating a "left slot" property in GP server specific data, this data would be updated just after the first MatchMake to GP server to somehow 'reserve' slots. Still concurrency could happen.

I'll have to assure that both operation are done atomically.

0 Likes 0 ·
contact-3 avatar image contact-3 commented ·

ISSUE 3 : Log Retrieval. In the end if we choose to have 2/2 game_mode for 1v1 or 2vE, it would be a better option for log retrieval. Now I'm concerned for 1vE and Matchmaker logs as those instance will probably not end up often (game modes will probably be 1/X). Is there anyway to flush the logs somehow ?

0 Likes 0 ·

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.