简体   繁体   中英

Implementing a game turn-timeout on the server side

At the moment I am writing a turn based game for the iOS platform. The client is written in Objective-C with CocoaTouch, and the server is written in C++ for the Ubuntu Server OS. The server is connected to a MySQL database, in which it stores user & game data.

Right now I wish to implement a time-per-turn restriction, and this has to be done on the server side. When a user takes a turn, the next user will have a maximum of 24 hours to answer, otherwise I want the game to skip this user's turn and move on to the next player. I have some ideas about how to do this, but I am not sure if they are any good. What I've been thinking of is storing the date&time of the last turn taken as an entity related to the Game table on my SQL database. Then I'm thinking of launching a thread on the server which runs until termination, and looks up current time minus every game's last turn, say every minute or so. If it's been more than 24hrs since the last turn was taken, this thread allows the next player in the queue to take their turn, and skips the lazy player.

Does it sound over-complicated? Is there another, more simple way to do this? I know it's been done in many games before, I just don't know how. Thanks in advance!

You probably just want a background process that has a schedule of "next actions" to take, a sort of priority queue you can work through as the events should be triggered.

A single process can handle a lot of independent games if you design the server properly. The architecture would pick up an event, load any associated data, dispatch accordingly, and then go back to waiting for new events.

C++ does have frameworks for this, but you could prototype it in NodeJS or Python's Twisted really quickly.

I don't think you need any threads or background processes at all in this case.

What I see here is a simple algorithm:

  1. When a user logs in to the game/match - check up the last turn ending time in the database,
  2. If the elapsed time from the last turn ending time is greater than 24h, get the current time, substract the time from the database (obviously you need to convert both times into hours) and divide it by 24,
    • If the division yelds an odd number, it's the turn of the other player (player A)
    • If the division yelds an even number, it's the turn of the player B.
  3. Set the database time to databaseTime+division*24

This algorithm can skip multiple turns. When player A finishes his move, and 48h passed, it's players B turn.

Please look at the reactor pattern (boost.asio, ACE). These frameworks are asynchronous, use an event-driven model and require no threads. Below is pseudo code on how you can solve it:

reactor.addTCPListener(acceptSock(), Handler::AcceptSock) // calls AcceptSock when accepting a new TCP connection
rector.addTCPListener(clientSock, Handler::ClientData) // calls ClientData when user is sending the server game stats (its move, status etc)
. 
.
.
later on somewhere
.
.
.
for(set<Game>::Iterator it = games.begin(); it != games.end(); ++it) {
    (it*)->checkTurn() // this call can be responsible for checking the timestamps from the ClientData function
}

Summary:

With the reactor pattern you will be able to have a non-blocking server that can do cleanup tasks when it is not handling IO. That cleanup can be comparing timestamps to switch/pass turns.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM