Brainstorm: How to tell how many people are playing your game

Discussion in 'Game Development (Technical)' started by Raptisoft, Aug 17, 2004.

  1. Raptisoft

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    804
    Likes Received:
    0
    Hi all,

    I'm looking for general ideas and a "right way" to do something. I know a couple ways to do it, but they all seem pretty poor.

    I'm about to publish an ActiveX version of Hamsterball. What I want to know at any given time is, how many people are playing it at a given time?

    The first thing that springs to mind is, fire off an http request when the game starts, and another when the game ends. One increments a counter, the other decrements it. Fairly easy, right? The snarl here, though, is what if someone turns off their computer while playing? Boom, instant perma-count.

    So, any suggestions? I'd love to do it with a PHP or other method, hitting "onload" or something.
     
  2. gmcbay

    Indie Author

    Joined:
    Jul 28, 2004
    Messages:
    280
    Likes Received:
    0
    You could use a lazy timeout.

    The game sends an http request to the server every X minutes. The server adds an entry to the 'active users' list, with a timestamp and possibly some unique number the game sent (you could also log by IP, but you might get numbers that are slightly off because more than one player is behind the same NAT, etc). Then the server periodically looks at the list of 'active users' and culls out any that haven't updated in the past X + Y minutes, where Y is some grace period.

    This type of scheme could (will likely, in fact) be slightly off at any specific time, but given the nature of TCP/IP, I don't think any other method will work any better, and this should be easy to implement.
     
  3. Raptisoft

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    804
    Likes Received:
    0
    Well, here's a method I was thinking of... I don't want to log individual IPs, because then this becomes some huge horrid database instead of a simple integer value per game name.

    I'm thinking, the game will send an 'increment' ping to the server each minute (as well as a 'decrement' ping when the game is done).

    Every minute, the game database will reset itself to zero (thus waiting for the next minute of pings). It'll do this, naturally, just based on the ping requests, it won't actually run all the time (i.e. if we get a ping request, and it's been a minute since the last reset, it'll reset again).

    When it resets, it will store the info for the PREVIOUS minute somewhere, and that's the info I look at.

    Can you see holes in that method? It sounds a bit unorthodox, but very server lightweight. I don't need a 100% accurate count, just a general idea.
     
  4. gmcbay

    Indie Author

    Joined:
    Jul 28, 2004
    Messages:
    280
    Likes Received:
    0
    Nothing obviously bad jumps out at me when thinking about your proposed method.

    The only bit of it that gives me any pause is that if you have tons of users playing at once, the bandwidth could be fairly substantial even for just pings, but that's a bit of a self correcting problem as if you've got anywhere near that number of players playing at once, bandwidth costs are probably the least of your worries.
     
  5. Raptisoft

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    804
    Likes Received:
    0
    Well, I could easily stretch the pings out to ten minutes too, if I didn't mind that my numbers were only ten minute current.

    I was trying to think of what cracks might slip through... for instance, a player signs on... the server clears the number ten seconds after he registers-- but he still would be in the past number. I guess the issue would just be that all numbers would be x minutes out of date (depending on my ping duration) and I might miss some people completely if they only play for a few minutes. Well, no, that wouldn't happen either, because they would say hello when they sign on, and then not for another x duration... and which time the server would still register them into the 'last sweep' number.

    Hm... I will have to think through it a bit more, just to see if anything crazy is in it. It sounds too good to be true, because it'd be low bandwidth, low memory, and the whole shebang could run over http.
     
  6. Matthew

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    493
    Likes Received:
    0
    The simplest solution I can think of:

    Every 15 minutes, the game sends an HTTP request. Server-side, the current timestamp is recorded. The number of active players is the number of timestamps newer than 15 minutes ago.

    You don't need any logic past this to do a rough count--stuff like increment/decrement logic, keeping track of which players are which so they update their initial timestamp, etc. Your database could very easily be a timestamp column (and a game ID column if you had multiple products in web form). Even a few million records is a trivial amount of storage, and you could always scrub the database nightly.
     
  7. Raptisoft

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    804
    Likes Received:
    0
    Hmmmm... I don't think that sounds better than the other method, which can basically be stored as three ints: Players to display (last cycle), Players now (current cycle) and time of last flush.

    I see the pseudocode as being something like this:

    <When ping request comes in>
    Is current time > last time + 10 minutes?
    Yes: Put current player count into 'old' count. Reset current count to 1
    No: Add one to current player count.

    <When leave request comes in>
    Current Count -= 1

    <When asking to display>
    Display 'old' count.

    * * *

    And again, the game pings the server every 10 minutes. So, I can't have 'stuck' numbers in case of a player crashing or unexpectedly shutting down (since the number constantly resets when pings come in). All data would be ten minutes old, but I can handle that. There's also the possibility of some slipups-- someone pinging right on the border of time and therefore something weird happening... but I think the number of slipups would be pretty low.
     
  8. Matthew

    Indie Author

    Joined:
    Jul 29, 2004
    Messages:
    493
    Likes Received:
    0
    Either way works just as well, as I think. I just have a personal preference to collection information and act on it seperately, rather than do logic at the collection level. There's really only two SQL statements to do something like this:

    To log a timestamp for a particular game/product (could also set a variable like $now = time() in PHP, instead of using SQL functions):

    Code:
    INSERT INTO active_players (
     game_id
     ,timestamp
    )
    VALUES (
     1
     ,unix_timestamp()
    )
    
    To get the current number of players (900 seconds needs to match the client reporting frequency):

    Code:
    SELECT count(*) as countActivePlayers
    FROM active_players
    WHERE game_id = 1
     AND timestamp > unix_timestamp() - 900
    
    I see the benefits as being more accurate statistics (still a ping window to deal with, but can generate the active count anytime), and the ability to add more functionality on top (could log a unique machine hash or identifier to detect player session length and get stats on repeat visitors).
     
  9. oNyx

    Original Member

    Joined:
    Jul 26, 2004
    Messages:
    1,212
    Likes Received:
    0
    It's not that difficult actually. Especially if you can tolerate some small fluctuations (which only occur very rarely).

    -If the game starts it sends a http request. Eg nowplaying.php?game=2&c=1 (game is the game id and c is the count, which you can ignore for now)

    -Every 5 minutes (from game start time) you send another request... nowplaying.php?game=2&c=2 (c inrementing)

    So far nothing new. Except that counter, which can be used later for getting more interesting statistics like 5 people playing for <=5min, 9 for <=10min and 4 for <=15 min ;)

    Ok. Serversided you'll need to store the count and the start timestamp of this 5 minute "slice".

    Whenever a request occours you compare the current time with that old time stamp. If the elapsed time is smaller than 5 minutes, you'll just increase the counter otherwise you start a new "5 minute time slice" and set the counter to 1 (for that request you just got). The new "old" timestamp gets the time of the old one + 5 minutes (if less than 10 minutes passed by).

    And that fluctuation, I talked about? Well, if someone starts playing on the edge of one of those time slices he can either fall into the old slice or into the new one (depending on his ping).

    I would also add status codes. Eg "100 OK" and "200 STOP". If the game gets a "100 OK" it continues with pinging and if it gets a "200 STOP" it won't send any further requests. This way you can easily switch it off (for the most part), if you need to.

    edit:

    Matthew's version looks also pretty good :)
     
    #9 oNyx, Aug 17, 2004
    Last edited: Aug 17, 2004
  10. gmcbay

    Indie Author

    Joined:
    Jul 28, 2004
    Messages:
    280
    Likes Received:
    0
    oNyx,

    That is essentially the same method I gave up above.

    In retrospect, however, I think Raptisoft's lightweight counter makes the most sense, given that he doesn't need stats that are super accurate and I don't think any of the other methods give any real-world benefit (given his specific needs) for the added complexity.
     
  11. Nemesis

    Original Member

    Joined:
    Jul 27, 2004
    Messages:
    273
    Likes Received:
    0
    in-memory IP list?

    Raptisoft,

    If you go for the route of keeping a list of active players by IP, you don't really need to store them on a database but rather, store the player count at intervals only.

    You could keep the active IP list in memory, say in a session variable if using PHP or JSP or whatever.

    The entries could be timestamped so any game that doesn't ping within a set interval will have it's IP removed from the list.

    This would also allow you to derive other statistics such as players playing for no more than 10 minutes, 20 minutes, over an hour, preferred playing time etc.

    As I said earlier, to gather a count statistic, all you would need to do is to take counts of the in-memory list and store it in your permanent database timestamped at set intervals or time increments. To gather other statistics you simply take counts of filtered versions of the in-memory list.

    I think this solution will give reasonably good results and wil handle cases when the games not exited properly or user PC crashes. Also, it will not require you to keep a large (persistent) database of IP's.
     
  12. Dom

    Dom
    Original Member

    Joined:
    Aug 5, 2004
    Messages:
    116
    Likes Received:
    0
    We use a similar method to count the number of players & the length of play for the java games on our site (peak was 20,000 in one day).
    All we do is record (via PHP) a specific HTML call to the server at startup which increments a 'start' count, and on exit, we have a destructor in a static class (gets auto-called on game exit, there are better ways) that sends a single HTML message back saying that the game is over. It doesn't always get through, around 5% of games never report back, either as they are playing past the counter reset point (midnight), the message got genuinely lost, or they are playing for more than 24 hours (my personal favourite reason).

    The current players is just the difference between the counts (accounting for the error mentioned above) and the bandwidth is the minimum it needs to be.

    - Dom
     

Share This Page

  • About Indie Gamer

    When the original Dexterity Forums closed in 2004, Indie Gamer was born and a diverse community has grown out of a passion for creating great games. Here you will find over 10 years of in-depth discussion on game design, the business of game development, and marketing/sales. Indie Gamer also provides a friendly place to meet up with other Developers, Artists, Composers and Writers.
  • Buy us a beer!

    Indie Gamer is delicately held together by a single poor bastard who thankfully gets help from various community volunteers. If you frequent this site or have found value in something you've learned here, help keep the site running by donating a few dollars (for beer of course)!

    Sure, I'll Buy You a Beer