BombSquad Server Stats Example

This example shows how to mod a BombSquad server to add a ‘total kills’ stat which keeps a permanent record of kills for each account that plays on it, as well as a webpage for viewing top kill counts.

The example uses BombSquad version 1.4.143; your mileage may vary on older or newer versions.

Anyway, let’s do it:

  1. Grab the sample code from the bottom of this page, save it to a file called ‘mystats.py’ in the scripts directory of your bombsquad server
  2. change the ‘statsfile’ and ‘htmlfile’ paths at the top of the script to wherever you want your stats to go
  3. add the following few lines in bsGame.py in ScoreScreenActivity’s onBegin() method.   (should be about line 1904 in the latest 1.4.143 builds)

That should do it.  If you do this correctly, your server should print ‘Added X kill entries‘ to the terminal at the end of each round.  You should also wind up with a json file containing a running tally of kills per account along with html snippets to display each account’s name. (the same name they show up on league lists as).

It also writes out an html file showing all names sorted by total kill-count.

..so if you wire up your server to dump this out somewhere world-accessible, you can then set your server’s stat button to point at that url so everyone can see who is the most awesomest dude on your server at any time.  (see this post about the new stats button option)

Note that this code is pretty bare-bones; it could use some error-checking and of course more features, but I wanted to keep it simple and hopefully readable to use as a starting point. Have a look through it, see what its doing, and then feel free to modify it to do something fancier if you’d like.

Some ideas for improvements as an exercise for the reader:

  • perhaps resetting the kill-count once per day or once per week
  • capturing other stats besides just kills
  • if your server gets a lot of players you may want to prune scores or only display the top 100 or something to that effect (or get really fancy and wire it up to a proper database instead of a json file)
  • A not-ultra-ugly-looking top kills page

 

Anyway, I hope this is useful.  Happy hacking!

"""
mystats module for BombSquad version 1.4.143
Provides functionality for dumping player stats to disk between rounds.
To use this, add the following 2 lines to bsGame.ScoreScreenActivity.onBegin():
import mystats
mystats.update(self.scoreSet) 
"""

import threading
import json
import os
import urllib2


# where our stats file and pretty html output will go
statsfile = '/path/to/my/stats.json'
htmlfile = '/path/to/my/statspage.html'

def update(score_set):
     """
    Given a Session's ScoreSet, tallies per-account kills
    and passes them to a background thread to process and
    store.
    """ 
    # look at score-set entries to tally per-account kills for this round
    account_kills = {}
    for p_entry in score_set.getValidPlayers().values():
        account_id = p_entry.getPlayer().get_account_id()
        if account_id is not None:
            account_kills.setdefault(account_id, 0)  # make sure exists
            account_kills[account_id] += p_entry.accumKillCount

    # Ok; now we've got a dict of account-ids and kills.
    # Now lets kick off a background thread to load existing scores
    # from disk, do display-string lookups for accounts that need them,
    # and write everything back to disk (along with a pretty html version)
    # We use a background thread so our server doesn't hitch while doing this.
    UpdateThread(account_kills).start()


class UpdateThread(threading.Thread):
    def __init__(self, account_kills):
        threading.Thread.__init__(self)
        self._account_kills = account_kills

    def run(self):
        # pull our existing stats from disk
        if os.path.exists(statsfile):
            with open(statsfile) as f:
                stats = json.loads(f.read())
        else:
            stats = {}
            
        # now add this batch of kills to our persistant stats
        for account_id, kill_count in self._account_kills.items():
            # add a new entry for any accounts that dont have one
            if account_id not in stats:
                # also lets ask the master-server for their account-display-str.
                # (we only do this when first creating the entry to save time,
                # though it may be smart to refresh it periodically since
                # it may change)
                url = 'http://bombsquadgame.com/accountquery?id=' + account_id
                response = json.loads(
                    urllib2.urlopen(urllib2.Request(url)).read())
                name_html = response['name_html']
                stats[account_id] = {'kills': 0, 'name_html': name_html}
            # now increment their kills whether they were already there or not
            stats[account_id]['kills'] += kill_count
            
        # dump our stats back to disk
        with open(statsfile, 'w') as f:
            f.write(json.dumps(stats))
            
        # lastly, write a pretty html version.
        # our stats url could point at something like this...
        entries = [(a['kills'], a['name_html']) for a in stats.values()]
        # this gives us a list of kills/names sorted high-to-low
        entries.sort(reverse=True)
        with open(htmlfile, 'w') as f:
            f.write('<head><meta charset="UTF-8"></head><body>')
            for entry in entries:
                kills = str(entry[0])
                name = entry[1].encode('utf-8')
                f.write(kills + ' kills : ' + name + '<br>')
            f.write('</body>')
            
        # aaand that's it!  There IS no step 27!
        print 'Added', len(self._account_kills), 'kill entries.'

 

 

The stuff of Eric Froemling