开发者

How to design a timer-based web game (like Cafe World)

I need to design and implement a timer-based game (Flash on client, PHP on server), like Cafe World, i.e. user clicks on a button, waits a few seconds, something happens, and then he can click again. It'll be a simulation of a food production line.

There will be N production line elements, each has a separate timer with different duration, and each can cue up to M operations (first starts immediately, next starts when the previous has finished and so on开发者_运维知识库).

How do I implement the server side of that kind of feature with a database backend? Currently I'm thinking about a counter for the cue, "time left" indication for currently active operation and the time of last update. When an operation is requested, I'd update the "time left" and cue counter using the time elapsed from last update. Any thoughts, comments or better ideas?

Best answer gets the bounty.


After reading through your question, other answers, and the discussion, I think I finally have a grasp on what you are asking (hence a new answer).

To begin, you need to track an end-user's session. When the game begins, you will have to start a new PHP session and send some sort of session identifier to the flash game. Whenever the flash game pings the server, it will pass along the session identifier so PHP knows which instance of the game it is working with.

The PHP server itself will be a passive entity -- the flash client will be doing the pushing and pulling of data. Let's say a user queues events X, Y, and Z, and they each take 20 seconds... As soon as the user attempts to queue each event, the flash client notifies the server, and the server either records it in the queue, or returns an error due to validation (ie, too many events in queue).

In addition, the client will poll the server every few seconds to check on the status of events. Every single time the client registers a new event, or polls for status, the server is going to check the timestamps in the queue and mark events as finished/etc, and then send a response to the client. This is much cleaner and much more practical than trying to run a script in the background that attempts to update the database every second in real time. The only downside is that events for a specific session aren't processed until a client reconnects if there has been a disconnect for whatever reason. But regardless of the amount of time in between connections, the user will still perceive the server as updating in real time because data is always refreshed just before it is sent back to the client.

If you have any implementation-specific questions, please feel free to post your database schema and/or your server code.

Update: In response to Pie's comment, there are essentially three ways to mark events as finished... 1.) Mark finished events as finished in the database when the client connects to the server for a request, or 2.) automatically mark events as finished by using a background process, or 3.) a combination of both.

If you follow option one and check your event timestamps and mark finished events upon every client connection, your database will be fully up-to-date when serving the client's request. If you follow option two, a PHP script running minutely on cron can insure that the database is up-to-date even if the client disappears, ensuring that your data is usually less than a minute fresh -- regardless of whether the client is present or not.

Regardless of how you are going to be using the data (high scores table, etc), having a combination of both techniques is probably the best idea. Fresh data is always a plus, and periodic incremental refreshes from a cron script never hurt anyone.

As far as marking events as completed is concerned, you merely need to check the relative start time of the event + the duration of the event against the current time. In a queue, the start time for an event is defined as the duration and cool-off times of all prior uncompleted queued events added to the starting timestamp of the first item in the queue.


Using a "time-left" field is a bad idea, because that can be hacked on the client-side using a program such a Cheat Engine or the likes.

In your database, you record the time of the last event. Your middleware (see Tim's Answer) still performs the validation, but tells the client whether the requested action can be performed or not. All of your validation needs to be done server-side in the middleware. Upon a new request, the middleware can check a database timestamp, see if the required amount of time has passed, and either perform the request or return an error to the client. Doing the interval check at both the server side prevents the case where your client-side validation is compromised through in-memory patches. Never leave validation up to the client alone.


If I have understood your question correctly -- the game rules are implemented by the server; the timers are started at the client; it is the "elapsed time to the user" that is important, not "elapsed time at the server" (ie the user musn't be punished for a laggy connection); but it mustn't let a fake client pretend there is high latency.

In which case, here's my very woolily worded advice:

At the server, only store information the client has sent you and information you have sent the client. (ie, I wouldn't plan on storing a server-calculated "time-left" because it is almost guaranteed to be wrong. In stead, just store "client start time" and "permitted duration" for that "start action" event.)

Look into a solution similar to timeseal http://www.freechess.nl/timeseal.htm to ensure cheating clients would be harder to write. For example, encrypt the timestamps (or the entire message) using a private key in the client and on the server check the received timestamp was encrypted by a valid key.

Depending on how much accidental lag is tolerable, you might want to send the client "potential triggers" rather than "immediate triggers". Ie, rather than sending the client "now customer B leaves without paying (because the player attended to customer A first)", send "if the player attends to customer A first, customer B leaves without paying".

Checking on the server that those rules have occurred correctly at the client is a simple matter of validating the order of events received against the options in the database. So, for the above example, if you see the event "attend to customer A", you expect the next event to be "customer B leaves without paying".

Your database table for the player's game ends up being a glorified event log -- except that it also stores "what can happen next". You take rules from the game rule engine and store them as "next available action state" events.

If you do take the option of sending the client "potential triggers", I'd advice encrypting them too. Otherwise someone will be tempted to write a sniffer so they can write a very simple bot to work out the best available option from the events on offer.


having read through your question and the given answers I suggest you rethink your application architecture. In my opinion you should implement the whole game logic in the client-side application (flash). Your server side application should only handle user logins and the management of the game states. E.g. a player logs in in your flash application -> check on server side if user exists, then return the actual gamestate for this user. Why this proposition: 1. let the users machine do the heavy work not the server machine 2. limit the traffic to and from the server

to handle the security issues I'd suggest you implement a simple "challenge-response authentication" in your data traffic challenge response on wiki


Games like CafeWorld, FarmVille, YoVille and others use a 3-tier architecture. The flash application being a fat(ish!) client with some logic built into it, using data stored on the server, a middle layer which sources the data interface and handles validation rules (such as not being able to use two stoves at once) and a persistence layer which handles the storage of data.

A state is maintained by the client, but the important part is that the client can't write state to the server, only events on the client can trigger changes in the server (middle layer). In this way the middle layer and client both maintain separate timings which are synced at intervals. When these intervals do not line up you will notice in games like FarmVille that you get a message notifying you that the "Game is out of sync".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜