The ‘tick’

December 13, 2007 at 11:51 pm (browser based, game design, game development, internet, MySQL, PBBG, PHP, scripting, web game)

This has been a rather popular post and seems to be a big question and topic of debate among developers. I, for one was confused about how to appoarch this when I first posted about it. But after reading comments made by people smarter than me, and learning more about databasing and scripting I feel I am ready to touch the submit again. Some of this will sound very similar to comments made in my original post on the topic mainly because I feel those people had the right idea.

You may call it a cron job, a timed event, or something totally different. I prefer the term tick. I like it because I think of it has an internal clock where each tick of the clock is defined by the creator of the game. So a tick may be a minute or an hour. But the subject of the this post isn’t exactly about what a tick is, but more so how a tick works.

Let’s start with an example. Every 20 minutes I want to give the player 10 more energy. If I were to use a cron job, every 20 minutes the server would grind to a halt pretty much as the cron ran through ever users entry updating their energy field. There is also the possibility of using AJAX. When some people hear this they think using a javascript timer that updates the database every few seconds… That’s a worse idea than the cron job for bring your server running into a wall.  You could use AJAX to update the players data every 5-10 minutes or so. But I think this is still a a rather inefficient  way of updating the data since it only works while the player in online.

The method I am adopting is the last click. This style of ‘faking’ a cron is from what I can tell the most efficient on the server, will cut back on lag, and can handle server down time in a method of your choosing.  The gist of it is that every time a player perform an action in game, it will store the a timestamp of that event. Then on the next click you compare the difference between the store timestamp and the current timestamp and perform the according game functions based on the time past.

“But what if I interact with another character?”

Thanks for asking. Say I go to attack a player that has been offline for 5 hours. As soon as I view that player in a way that is more than their name,  it will update their data (you will likely want to use a different method when looking at score lists or ranking so you don’t have 200 people updating every 15 seconds). You may think this method would be difficult on the server, but with a properly designed database (at least 2nd normal form) and some well written script, this method will allow for your game to be very scalable. In other words, you could have 2,000 or 40,000 members without the need of rewriting all your crons or updating servers every few months.

“But who would I manage a searching or score lists?”

Say you update the top 100 players in several fields every 20 minutes and the search tables every 5. All you would need to do is simply create a small table containing the last updates timestamp. You compare the two, if it fails to equal for than your set interval, ignore it. You just saved yourself updating all those users unnecessarily. A different method may suit you and your design better, you be you the general idea of it.

The last click way of doing this does take longer to be designed and built but in the end this will pay off. Instead of updating 5,000 members in a row all at once you now update 5 every few minutes. You are performing more updates but the requirements on your side won’t be as near as depending, eliminating lag before it occurs.

I hope that was all was clear and addressed some of the questions I have been receiving.

Oh, and by the way; if you disagree with me, please share your method. I write in the blog not just because I want the attention ( 😛 ) but also because I want to help the community grow and develop. So please, share your thoughts and comments… unless they are negative. Then you keep those ^^

Advertisements

9 Comments

  1. jmucchiello said,

    This is basically what I said. I don’t think 2nd normal form is appropriate though. When you add a second value (or tick) with a different update interval, things get complicated: Suppose you have villages where 3 resources are farmed. Each rez is farmed at a different interval based on the size of the resources “building”. So a level 4 granary yields 130 wheat per hour and a level 6 iron mine yields 210 iron per hour. What is the update interval? Basically, you need to store the last update of wheat (epoch+100203) and iron (epoch+100201) separately since wheat updates once per 665 seconds and iron is one per 411 seconds. If someone tags that village at epoch+100750, you need to update the iron count by 1 and move its last update to epoch+612. You don’t update the wheat at all. and you tag the records last update as epoch+100750.

    So you DB table might be:
    village_id
    player_id
    village_name
    wheat_count
    wheat_last_update
    iron_count
    iron_last_update
    village_last_update

    As I understand it, that doesn’t even pass 1st normal form. 1NF says there should be a resource table:

    village_Id
    res_type (wheat, iron, etc)
    res_count
    res_last_update

    But that table would have villages*res_type rows and probably grind you to a halt doing multiple row updates and multiple round trips to the database.

    Or, I’m just lazy.

    Epoch: What’s this? In the other discussion, the concept of server outage was addressed. Basically, you don’t store real dates, just “seconds since world goes live”. The epoch is just the number of seconds in the real world since go live time. If the server goes down for 6 hours, you advance the epoch 6 hours so that the lost hours don’t screw your players.

  2. NFX said,

    I think the best way is to use MySQL’s new feature: Scheduled Events.

    It will allow you to do:
    @ 19:46:12 – execute query
    @ 19:47:55 – execute query

    If you do clicks: you will store temporary data in a table, and then upon page-request it will check the end time against current time.

    You will first have to save the end_time to something what I would call the ‘progress table’.

    end_time = current time + production_time

    Then, you actually will have to loop through the progress table to check for completion (per player).

    while (Progress::end_time > current_time) { completion = TRUE; }

    Now the problem with “clicks”, or “page-requests”, is the fact that there must be a page-request in order to check for completion. Not just per player, but also with every player interaction (ie. attacks). If the page-request happens a few seconds later than the actual completion, it will not have updated the correct stats at the correct time, and I’m just not at ease with that. I need the correct, updated player stats ALL the time.

    You also don’t really want to hang on to a loop and execute this loop every page-request per player, it will consume unnecessary bandwidth.

    I’m currently designing an innovative strategy browser based game (AJAX, PHP framework and incorporating some other sweet ideas) and I’m gonna be trying out the MySQL Events. Hoping it will work out during development stages, I will let you guys know!

  3. jmucchiello said,

    During development, your method will be awesome. But it will not scale very well once you have 1000+ things that can happen within the same minute. Good luck.

  4. ernie said,

    I only get to know a clearer picture of what Tick really is now. I was developing Turn based web game all the while and I’m still stick to it.

    I think with a proper coding, things wouldn’t be much difference between the developing stage and real test stage

  5. bardicknowledge said,

    @jmucchiello Sorry for the late reply. Roomie bought a ps3 and it was stealing my all my free time. Anyways, second normal form can be achieved but the wikipedia article on it sucks. I have a DB book at work with a really good definition in it, so I will post it when I go to work next. But from what I understand of 2nd normal form, the main propose is to eliminate redundant data. I may be mistaken, but your goal is to create a table that doesn’t contain functional dependencies on any possible candidate key. I’m no master databaser by any means and need to re-read some docs before I finish my current database.

    But I don’t see a problem with each resource having its own tick.

    village
    player_id
    wheat_tick
    iron_tick
    gold_tick
    wheat_level
    iron_level
    gold_level

    tick_*
    level
    time
    amount

    (A tick_* table would exist for each resource)

    Wheat updates every 10 minutes and gold and iron every 5. I just store the times of their last update. When I log in 56 minutes later, I get the current time and compare it to the last tick events for each resource. So gold update and iron update 11 times and I insert into their tick entries the current time minus one minute. For wheat, it updates 5 times, and I then insert the current time minus 6 minutes. This set up here allows for each resource to maintain itself. It also allows for the resources to have different amounts gain and different ticks based on building levels while still being a 2nf (i think..pretty sure).

    This wouldn’t be that difficult on the database. You first make your compare call. You would select * from village, then select * from tick_* based on the resource level. So 4 queries there with little data. I would then compare the wheat_tick plus the [tick]amount to the current time. If that comparison failed, I move on. If it succeeds, I then only need to run 1 update script.

    I could even do something like this, saving a lot of queries. When you log into the game, your last tick events are stored as session variables. You could do the same with the tick_* amount entry. You would then only perform queries maybe a 10th of the time.

    @NFX I don’t understand what you mean by hanging onto the loop. If you mean about checking for updates to a players military or resources, it’s just a script that is included for each page. If the comparison fails the rest of the script doesn’t run.

    I would like to point out a flaw with using crons by using a real life example. The game torncity at first used crons to update each players stats. But because there were so many players the cron would lag the server down horrible and take about 15 minutes to complete. But the script was meant to run every 10 minutes. In the end players weren’t receiving updates for 2 or 3 hours because the cron was lagging so bad. They have since changed their style of updating players information.

    Like jmucchiello, a cron or mysql event would be great during development but once the server went like and a members start joining the game, crons will start to slow down and take longer to complete, which would end up giving you incorrect timestamps for their updates. Making each account to look after it’s timestamping is not only good OOP programming, but good for your server.

    @ernie “I think with a proper coding, things wouldn’t be much difference between the developing stage and real test stage”. Are youreferring to crons or tick based system? And if you could give your reasoning that would be wonderful ^^

  6. jmucchiello said,

    session vars: They might help, if the most common access to the village is by the user, but you can run into problems when players are control 30+ villages each running 3+ resources as well as build queues. That can be a lot of session data.

    In a game with a lot of PvP, the owner isn’t necessarily the most common person checking out his villages. In that case, the session vars just become a second code path where additional bugs can be introduced.

  7. mobeamer said,

    I’ve used your method and found it very useful. One cavet that has been mentioned in another comment is very true.

    You don’t want to update other players when one player takes an action. Restrict yourself to updating the current logged in user.

    Very few games need a search function where you show the last time the user took an action. And if you have that functionality it’s best to be rid of it now…There is no easy way around that database hog and more then likely is not worth the effort.

    That being said, the only area where I need to look up the last action of a player that is NOT the current logged in player is on the “Who is Online Now” feature.

    For this, I just look at the player’s last action time stamp….if the player is online and taking action, it will be within the last few seconds/min.

    My 2 cents…some of it doesn’t fit with tick based programming but I thought it was applicable.

    mobeamer
    http://www.BattleForcesOnline.com

  8. jmucchiello said,

    You need to update other characters when one player attacks another. Only one of them will be the logged in player (and in tribal wars/ogame style games, no players might be online, a third player may just be witnessing the attack).

    No matter what kind of game there is probably some kind of PvP and all variables related to the battle have to be up-to-date on both sides when you determine the winner.

  9. bardicknowledge said,

    I don’t see how you can attack another player and not update their account. Without updating their stats, it’s as if the time between their last log in and the current time didn’t exist, which would cause more problems.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: