Server/Client architecture for turn-based card game developed with Unity3D

Started by
3 comments, last by DomenicoO 7 years, 9 months ago

Hi to everyone, I'm new in the forum and someone told me to create a new topic here, because it is the right place to looking for the right answer.

I'm having a lot of problem about the logic behind the development of the back-end of a turn-based card game. I understood from a lot of researching that the best solution is to develop an Authoritative Server connected with multiple client (client should be developed with Unity3d). I will probably don't need to send a lot of data from a point to another in the network, so physics and simulation of the game environment are not the problem.

  • The Server should get "Action" from clients, update the internal game state (and check if every action is valid) and then give back to all clients the new state of the game.

  • The Client have to get data from server, create the right GUI and select just the actions that are possibile in a particular situation.

So I need a server that can handle that kind of problem for each match. What kind of technology I should use to do so? Someone say that It could be done with Apache/PHP on a server, but it's really the right solution? I was thinking about Photon* or Bolt, but I think that real-time technology are useless in this situation. Anyway I will probably need of someone that can handle load balancing and traffic.

*For the Matchmaking/lobby/room features, I was thinking to use Steamworks.

Game features: Even if the game is a turn-based game, when it's the turn of Player A, Player B and C can interact with each other (for example they can trade cards). They can even interact with Player A in a certain phase of the A's turn.

EDIT: I'm aiming to publish this game in Steam, so I have to understand also how I can integrate different function in this game from different SDK/source.

Thanks for your time!

Advertisement
Any server technology can be the back-end for a turn-based card game. Web servers/services are very diverse and you should pick one that uses an environment you are familiar with.
(Nginx/PHP, Tomcat/Java, Nodejs/Javascript, Rails/Ruby, Flask/Pyton, Wai/Haskell, IIS/C#, ...)
Separately, any game server can probably also be used for a turn based game. Photon, Bolt, Lidgren, Smartfox, and a bunch of others. If you go that route, you should go with the server technology that has he best client libraries for your engine, and perhaps also pay attention to the server OS (do you prefer Windows or Linux for 24/7 uptime systems?)

Now, if you use Steamworks for match making, you might be better off also using Steamworks for the networking. That, in turn, means you should probably choose a server platform that has a ready-made Steamworks integration, and/or makes it easy to link in C++ code.
Steamworks is great if you want to tie into the existing Steam social community. The matchmaking is OK, but not necessarily a feature that's so special that you have to mutate the whole rest of your architecture just to support it.

You have to figure out whether you actually want a persistent process per "current game" that deals with everything from game rules to player chat, or whether you want the game state to be network-attached in some back end (anything from memcached through Redis to SQL) so that you don't need stateful sessions, and solve chat using some other method (or polling.)
This, too, determines your approach.

The solution that's probably the easiest to implement and easiest to scale, but isn't necessarily the cheapest per hosted game at small scale, would be to store each game instance in Redis, use a simple polling-based protocol over HTTP that polls maybe 1 or 2 times a second, and make "what each person has said" a part of the game state, returned through polling.
The two main operations would then be "get me game state later than X" and "this is my player action at time Y." The front-end web service servers would receive the request, read the game state from Redis, update according to requests/rules, write back to Redis, and then return to the players.
This is a 100% stateless application server, which scales really, really, well. Also, as all game state lives in a single key (could be Redis, or Cassandra, or Riak, or perhaps even MySQL) this will scale (shard) horizontally in a trivial way.
A back-end with time-to-live support (such as Redis EXPIRE keys) lets you forget about a game if neither player has made any move for some number of minutes/hours.
enum Bool { True, False, FileNotFound };

I did a lot of research about what you said.

I worked with Apache/PHP (and MySQL), C# on Unity3d, C and C++, and I know just a bit of Ruby and Java. So I was thinking to the solution using my past experience.

Said so, the first approach that came in my mind was about the idea to use PHP/MySQL, send serialized data from client to the server (action), elaborate the action, update the internal state of the match (search the right record with a matchID) and stop. Every client will request every n-seconds (or every next step in the game) the current state of the match. If a client want to send data for a new action, it will at first request the updated state on the server, check if the action is valid and then send data (then the server will again check the action).
But in this way, If some client doesn't send some kind of request, the server can not change any data about the match. I feel that this solution is very intricate and maybe, in some way, wrong.

Now, I understood that Redis allow me (like the most of nosql db) to store and write/read a lot faster than a SQL. I'm thinking that, at this point, it could be a good idea to use Redis with another sql Db on the same server. Every (steam?) account have to be stored in a permanent way, with all of the data about who payed and played the game. Every match need to be saved and updated really fast, and it's not really important that every step of the match have to be saved in a sqldb. So I should use redis to save every step (current game state) in different record, and I should use Sql Db to store authentication data and other important value about players (email, password, steamid, ...).

If all of this is true, what is the best method to interact with these database and clients?


Of course, thanks a lot for your help.

If some client doesn't send some kind of request, the server can not change any data about the match.


There are two ways of soliving this, for turn-based games.

One is to have some "timeout clock" that knows about active games, and makes a web request that "the clock is ticking for game X" every so often.
This clock process needs to run more permanently than you can do with a simple PHP request handler, and you need some kind of management of when this process dies so it restarts.
You'd also need to tell it about games when they start, and when they stop.

The other is to say that the game only advances when at least one player wants it to advance. Then, make each player request updated state X times per minute/second.
Because at least one player makes requests, the game can advance. When both players close their browsers, or there is a network outage for your server, or whatever -- the game will simply be frozen!
This could be seen as a feature, somewhat depending on the specific rules and implementation of the game.


I understood that Redis allow me (like the most of nosql db) to store and write/read a lot faster than a SQL.



Yes, storing things in RAM without a guaranteed commit to disk is a lot faster! The draw-back is that, if you crash, well, you didn't have a guaranteed commit, so the data may be lost.
Thus, it's usually a good idea to keep permanent data (log of games played, user account information, etc) in a durable transactional store (such as most SQL databases.)
If your game pace is slow enough, that polling for the game state out of SQL does not add undue burden on the database infrastructure, you don't need to use a key/value store for that, at least while starting out.
If there's a single table "current_games" that contain a primary key of game ID and a value of "serialized game state" as JSON or binary data, then that's super easy to migrate out to a key/value store later.
The main thing you lose is the automatic purging of old data which comes from the TTL values on Redis keys.
To implement that, you can have a cron which runs every 10 minutes and deletes rows that have not been modified in the last day, or whatever the right value is for your game.
enum Bool { True, False, FileNotFound };

Well, you gave me every answer I needed to start building a back-end.
If I will publish any time soon this game you will get a free key to play, that's for sure. I hope It is going to be awesome.

Thanks you very much.

This topic is closed to new replies.

Advertisement