[web] Updating Players - Tick / Time / Realtime

Started by
13 comments, last by touch_the_sky 13 years, 2 months ago
I bet you're right with what's popular, the viability of 'real-time', etc., but:

Virtually every page and refresh in this scenario would require a call to your update function.


The above statement is false.

javascript timer that will call update() on completion

You have to be careful & clever there. Done wrong, this could be a potential bad practice / security threat - allowing me to easily skip the timer and call the update() when I please ('Why would I wait 20 mins to have it built / done if I can have it now')


Let's start over.
Some assumptions to make first: we have a browser based rts game - database driven, markup + js on the frontend of course. Let's assume 1000 players for the numbers sake. The game has the usual - displays money + some stats at the top, allows to purchase buildings, army, view & attack other players' kingdoms (takes time until your army reaches enemy). And we try to achieve the 'real-time' gameplay feel.

I'll try to reword the 'build a building' example:

Scenario 1 - The User buys a building:
DB pseudo-structure
1) You have a 'buildings' table in your db
2) Let's not get into the details of what params (table columns) can the buildings have (also skip the obvious columns like ids, etc.). For this 'real-time' example all the columns we should care about are like: building_name, price, status, time_it_takes_to_build, created_at, updated_at
The action
1) User clicks 'Buy Building Blah'
2) You create a new building for this user in the db; you take off the price from the amount of money the user has; you set the status to 'under_construction'; both created_at and updated_at you populate with current server time at this stage. Knowing current server time is a given, it's there for you all the time, no performance probs - it's also a big player in the further part of the story;)
And voila! - you're done, it's pretty much the same thing you would do always - regardless of whether you use Cron or not, so no performance talks here.

Scenario 2 - the infamous page refresh (The User decides to have a look at his buildings, etc.)
1) 'Click'
2) You GET user's building from db - there's a good chance that's gonna be the only db hit (and no updating)
3.1) The building has status of 'under_construction'. Well, right there you already have when the buildings was purchased (created_at), how much time needs to pass for the construction to complete (time_it_takes_to_build) and something you always have, no matter what - current server time. Now it's easy;)
  • 3.1.1) If enough time passed since the created_at till now, only then you update: status => 'complete'; updated_at => current server time. On a page the user sees 'This building was built format_time_nicely(updated_at)'.
  • 3.1.2) If not enough time passed, you echo 'building will be ready in time_remaining' - on the user's machine (after page is loaded) you can grab the number easily and have a nice js countdown (no talking to server there)
3.2) The building has status of 'complete' - no need to explain further, no extra db hits, checking - just display the data you already have

Well, there you go;) Hope you do not see 'updating everywhere' now, but updating ONLY when you actually should be updating. And most important - it's a 'real-time' game, players always see uptaded stuff - there is a feel of 'constant flow', etc.

With 'cron-way' (the way it was put) you would:
1) skip checking times - not really a performance boost there.
2) not have occasional update statement - hmmm.. mild performance boost, especially with all the js / ajax goodness which make 'waiting time' much less obvious and painful for the user

Plus, what seems to be the reason of why I am even talking against Cron here:
1) How do you achieve this 'real-time' effect with Cron, without stupidly low interval (seconds) - big performance issue
2) Imagine this: 1000 players online, 300 refreshes the 'view my buildings' page - the rest stares at the screen doing nothing:
  • Without Cron - could be lightweight / slightly heavier requests (depends if any updates necessary or not). But all the happy players would have the correct, up-to-date info constantly
  • With Cron - lightweight requests, info displayed to users most likely out of date until next Cron job. Then when it happens - you would have to run a giant loop through all the players, checking / updating every single detail - buildings, money, army, fights, etc. Even if most players had nothing to update, you'd still have to go through every single detail.

Hmmm...
Advertisement
@touch_the_sky

Good post, and well thought out. Ratings +1. I think my reply was built mostly around my own experiences, so I apologize. Two notes.

First, I agree with you that 'update checks' will be done and not a full 'update' on each refresh. As a default, I do all security checks inside my function (to ensure they never get called before security checks... which is easy to do with proper classes). So, I was confusing with my terminology when I said update(); would need to be called on each page refresh. In my example, update() would see that not enough time had passed, and quickly exit (but is still called. Minor overhead, but still there). Of course the real key to saving the bottleneck here is by reducing our insert and update statements.

Second, where I think this will get complicated is if buildings produce some sort of good (such as energy, gold, etc) every x units of time once its completed. If a building produces 1 gold every hour once it finishes building, then the older the game gets, and the more players the game has (and buildings in existance), then the higher the demand the update statements will become. I'd much rather do one giant "update Users set Gold = Gold + Goldmines" statement for all players once per hour than I would a single update against one playerID, but multiple times throughout the hour.

Third, if a player does not log in for a long period of time, and there are many buildings in the queue, then this again creates the need for an ugly update function that steps through each completion time, updating resources, etc as it progresses.

I'm not saying its not possible. Ogame does 'real time' updates, and is popular. But a hidden design element in Ogame is that buildings take progressively longer to build, up to several HOURS to perform after just a few days of play. I'm sure this is to get around the trouble noted in my 2nd point. Talk about having nothing to do :P My argument for Cron and updates no more frequently than once per 15 minutes is that it provides a much cleaner approach with some minor overhead savings. There are several other arguments here to support Cron, but its really for the OP to decide.
Damned new design, wrote a nicer post and hit the wrong button... So here's my main points:

touch_the_sky hit it pretty well, but don't update statuses like that. Player hits 'Create Building', create a DB entry with 'building_complete_time', and use that. You don't have to touch the entry again for maintenance purposes: queries like 'GET player_X_buildings WHERE completed_time > NOW' gets you incompletes, queries like 'GET player_Y_buildings WHERE completed_time < NOW' gets you all active/complete buildings. Calculate remaining time with completed_time - NOW. No issues here with long no login times, no extra DB queries/updates, almost no time/date functions (or, hell, math! just addition/subtraction) if you use *nix timestamps.

CygnusX has a point on realtime gold/energy/people/etc from buildings. Buildings producing goods is a simple compounding interest problem you can best solve by putting in a once-a-day/login/whatever time for those benefits to be gained (or cron, if you're so inclined, especially if you need to run other external maintenance/cleanup that way). If you HAVE to have those gains in realtime, your best bet is probably a separate process/DB to maintain everything separate from the game load, but that's still going to be slightly off and hard to maintain. You're basically running/writing banking software and/or stock markets at that point, and while it's not impossibly hard, it's probably more of a headache than you really want (unless you're that kind of math geek! :-P)

Just think in terms of data for now. Many large games (even running in realtime almost identically to what's described above) end up using regularly scheduled cronjobs and such but it's often a byproduct of load balancing or maintenance (meaning account security, checking for h4ckz, pruning old data, etc). Since those tasks end up getting optimized to hell and back and have to touch every account anyway, some things can be put in there to get a net gain (slower scheduled task, faster per user) in performance. None of that should matter at 1000 (or even 10000, sometimes even 100000 depending on DB size and host) users, though. Splitting any turn-based game (meaning you do X tasks over Y time) into chunks crunchable by an optimized cronjob is typically preferable, though, as it's a few minutes of server strain versus a constant moderate load (visible in page loading).
Thanks everyone. I learned a lot here. I did some research on the real time stuff and it seems if I wanted real time game play I would have to go with Flash or some other container that could be embedded into a website to have a socket server on the back end since javascript io:socket isn't quite there yet. The updating makes a lot of sense and I appreciate the lengthy posts with the examples. I think I will avoid the cron job as I want to be as close to real time as possible and if say the game does get popular and starts to crumble in speed, i'll look into a cron job as a solution or just cap the players and make a server2 instance :).

Hopefully this thread will help out others as well. Thanks! :)
Yep, there was a bit of a discussion going on here;) Cygnus_X, me and jolid made some valid points which should hopefully be useful to other people.

Flash is a bit of a game changer I suppose (not as risky as js in terms of moving some 'heavier lifting' to ther frontend?). Unity or similar may possibly be a good idea (since you've decided to require a plugin anyways), it's not something everyone will have installed cause it's needed for YT, but if the game justifies the requirement with it's looks, etc. (accelerated graphics) you should be fine - haven't used it, but it's said to be really easy to use.

Just an idea which came to my mind - back to js - it may be worth to have a look at some web based, ajax chat clients (gmail messenger, meebo and stuff), the way they operate - they do not require you to download anything, yet they provide a neat real-time chat facility.

This topic is closed to new replies.

Advertisement