logo

ShrimpWorks

// why am I so n00b?

Yes, so everyone’s obsessed with checking their BF2 stats these days ;).

Anyway, I wanted to give my Supybot IRC bot (“Nooblet” on Shadowfire) the ability to check my own and other people’s stats whenever they felt like it. I came up with something like this:

import urllib2
from string import split
from time import time

# the columns you want to request data for. comma-separated string.
info = 'per*,cmb*,twsc,cpcp,cacp,dfcp,kila,heal,rviv,rsup,rpar,tgte,dkas,dsab,cdsc,rank,cmsc,kick,kill,deth,suic,ospm,klpm,klpr,dtpr,bksk,wdsk,bbrs,tcdr,ban,dtpm,lbtl,osaa,vrk,tsql,tsqm,tlwf,mvks,vmks,mvn*,vmr*,fkit,fmap,fveh,fwea,wtm-,wkl-,wdt-,wac-,wkd-,vtm-,vkl-,vdt-,vkd-,vkr-,atm-,awn-,alo-,abr-,ktm-,kkl-,kdt-,kkd-'

# this is my BF2 ID. You can also query the stats server with "nick" rather than "pid", but I've had problems with some characters
pid = '43595724'

opener = urllib2.build_opener()
opener.addheaders = [('User-agent', 'GameSpyHTTP/1.0')]  # otherwise GameSpy's servers will block your request
webData = opener.open('http://bf2web.gamespy.com/ASP/getplayerinfo.aspx?pid=%s&info=%s&nocache=%s'%(pid,info,round(time()))).read()

statsData = split(webData, "\n")

cols = split(statsData[3], "\t")
data = split(statsData[4], "\t")

stats = dict(zip(cols, data))

# you now have a nice dictionary with a few hundred bits of stats data.
print "%s has %s kills and %s deaths and a score of %s" % (stats['nick'],stats['kill'],stats['deth'],stats['scor'])

Thanks to korpse and mithrandi for showing me the “zip” function. It takes the list from the first parameter, and uses those values as keys in a dictionary, the values from the second parameter are then used as values in that dictionary. I was using map(None, keyList, valueList), but zip seems cleaner.

Anyway, if you’re looking for more info on stats querying, try the BF2 Technical Info wiki, or check out SaladFork’s Guide to Creating a BF2 Stat Signature - although it’s in PHP, he does give a nice list of column names and their meanings, you can also grab lists of ranks, weapons, vehicles, etc.

Update: Also see: Battlefield Stats in PHP

Updated: Since this was written, some things changed with the stats system, and the GameSpy application requires you to pass a bunch of columns you want info for. This can help customise the data you get back, so you only request what you need. I’ve included all the columns in the info variable, which you can customise. Make sure it contains only valid columns, or you won’t get any data back at all.

As above, for info on what all the columns etc. mean, check out the BF2 Technical Wiki.

I decided it might be a good idea, from a debugging and administrative point of view, to save the reports people were viewing in my application at work. Since users are distributed all over the country, and I have to communicate with them over the phone with on-the-spot problems, it’s hard and very time consuming to get them to tell me all the parameters etc they’re using to generate a report which they are having problems with (mostly, the data looks like something they weren’t expecting).

Anyway, I thought saving the exact report they are viewing is much easier for me to simply call up while someone’s on the phone, than doing the whole ‘which options did you use?’ thing.

Option one was saving each report to a PDF file on the server, but, that’s pretty inflexible, and also, people can view more than just PDF files with my reporting options (emails can be send direct, zip files can be downloaded, and data can be downloaded in csv format), so that wouldn’t always work out.

So I looked into serializing the actual report object used to generate any of the above report types, since that object contains absolutely all data, totals, titles, info, etc.. Unfortunately, PHP’s built-in serialize() and unserialize() functions don’t work too well with complex data structures (arrays within classes, multi-dimensional arrays, etc, etc), and I couldn’t really work around all that without writing a few GBs of code onto my report class.

SO, I turned to XML. As it turns out, the PEAR ‘suite’ of scripts contains a rather useful XML serialization class -XML_Serializer, which can turn any data structure into an XML string, and for reading those strings back to usable PHP variables and objects.

It’s really quite simple:

$object = new SomeClass();
$object->var1 = "Hello World";
$object->etc();

$serializer = &new XML_Serializer(array("indent" => "  ", "typeHints" => true));
$serializer->serialize($object);
$xml = $serializer->getSerializedData();

$xml now contains the full definition of $object in XML. You can write $xml to a file, save it in a database, whatever you like.

You can then come back later, and load the file/database record/etc into a string, and deserialize it…

$unserializer = &new XML_Unserializer();
$unserializer->unserialize($xml);
$object2 = $unserializer->getUnserializedData();

echo $object2->var1;
$object2->etc();

Quite fun actually :D. You can obviously do a lot of error checking, and other things, but that’s just the basics.

I sat down this afternoon and had a bit of a play with Gran Turismo 4’s Photo Tour option within GT mode. I must admit I’m rather impressed, and although it’s seemingly boring, it turned out to be a rather entertaining exersize.

It basically presents you with a couple of venues from around the world

  • Venice, Tokyo, New York, the Grand Canyon, etc, which are pretty much static scenes, with pre-defined car and camera ‘zones’ within which you may arrange things to you liking. You control the vehicle location, rotation and wheel rotation, and camera location, height, tilt, zoom, focus, etc. After you’ve got your scene arranged just right, you can fiddle with things like colour balance, saturation, etc to get the scene just right.

You then get to take your photo in a lovely high resolution, and save it to a USB flash disk! WOW! Someone finally found something useful to do with the PlayStation 2’s USB ports, aside from whacky controller contraptions. Anyway, once saved, you pop off to your nearest PC and offload your pics (which are saved in JPG format).

A few of my results (I only have cheap cars in my garage at the moment);

Images lost in time

titleMy Cat

date 26 Aug 2005

Because “Weblogs are things with cat pictures in them.”

Lost in time

So ja, it’s been reported that the games SWAT 4 (via the latest patch) and the latest Splinter Cell games both have ’live’ advertising, which download as you play and display stuff, basically no better than banners, on posters, vending machines, billboards, etc. within the games.

Both of these games seem to have been ’enhanced’ by what seems to be a recently launched ‘service’, Massive Incorporated, specifically set up to place advertising within games.

Personally, I have a few problems with this. Firstly, I’ve already payed around R400 for my game. Now as I see it, things like advertising are usuallly used to subsidise either free services (eg: banner ads on many websites), or relatively cheap services (eg: ads on TV and radio). Now why the hell do publishers feel the need to milk even MORE money beyond the R400 a copy they are selling?

Secondly, there is NO opt-out. If you want to play the R400 game you just bought, you have to agree with the fact that you will be downloading these ads and wasting bandwidth on every map/level change, that they will be defacing your game, and you will be sending the advertisers ‘usage statistics’ - how long you looked at each ad, what angle you looked at it from, how far away you were from it, etc. As I read elsewhere (forgotten the URL at the moment), it’s pretty scary that this is the ‘first generation’ of this technology - I can only imagine the kinds of things they’ll track about your playing habbits in the future.

And finally, it’s just plain intrusive. I like seeing often humerous made-up posters where they’re needed - which is normally seldom in most games. I don’t want to see darn Coke ads in my games. Also, I’m sure publishers and advertisers will start pushing developers to include even more and more advertising billboards/posters/vending machines/etc in their levels, until one day you’re sneaking/running/driving/strolling/handing/rolling around some kind of psycho colourful flashing whacked hall of nothing but lame-ass banners and shit. Piss off with that stuff, please.

Aaaanyway, you may have guessed this idea doesn’t appeal to me at all. Unfortunately once the trend is started and the standards are set by a few games, things will only go downhill.

What’s also scary is that both SWAT and Splinter Cell are Unreal engine games :(. At the moment though, neither Epic or Midway have signed on with Massive Inc. it seems.

I only noticed this rather recently.. But you can set up Firefox’s ‘Homepage’ option to open multiple tabs when you open the browser.

Just enter the URLs you want to open by default, separated by the pipe (’|’) character. The same effect can be achieved by opening all the tabs you want, then use the ‘Use Current Page(s)’ button.

So you can now open Google and 200 random websites you probably won’t even look at anyway! Personally, it irritated the hell out of me, but maybe someone would find it useful…

Thanks to a link mithrandi posted in IRC, I’ve discovered this rather useful tool.

Gregarius is a web-based RSS/RDF/ATOM feed aggregator (oops, I didn’t copy/paste that from their homepage :P) which you can install on your own server, and manage as you like.

Setup was a breeze, I just checked out the latest version from their Subversion repo, copied the files over to /var/www, and created a MySQL database. First visit to your Gregarius URL prompts for database access settings, and creates the tables and everything for you.

It has an extremely clean interface, I suspect in fact that it’s highly influenced by WordPress (their “devlog” using WordPress further convinces me), but that’s beside the point. It’s extremely easy to manage categories, add feeds (it automatically fetches a “favicon.ico” file if one’s available as well), etc. I got my whole installation and 10 feeds all setup within around 10 minutes.

It presents the feed items nicely enough, sorted by date, with links to the full versions, as well as descriptions/summaries. It also keeps track of items you’ve left unread, making it easy to come back to them later. Another helpful feature is the ability to search within the feeds it’s downloaded and stored, allowing you to pull up any item at any time, I’ve already found this quite useful.

All-in-all, a pretty great little package. It sure beats Thunderbird’s RSS reader hands down. If you subscribe to any feeds, have the ability to host it (just PHP and MySQL required), and 10 minutes to set it up, throw away your existing RSS readers and get your own Gregarius aggregator up and running :).

Ok, so this is such an insanely simple thing to do. I once tried looking for a PHP class or package which could write Excel .xls files from data in an array. Well, I found a really ugly class which simply saved a .csv file as .xls. Anyway, I ended up writing my own 4-line function for that:

function arrayToCSV($data) {
    $csv = implode(',', array_keys($data[0])) . '\r\n';
    for ($i = 0; $i < count($data); $i++) {
        $csv .= implode(',', $data[$i]) . '\r\n';
    }
    return $csv;
}

You’ll have to do your own validation for empty arrays and things elsewhere. It returns a string with each record from the array on it’s own line, separated by commas. $data is expected in a format something like this:

$data[] = array('name' => 'Bob', 'age' => 12);
$data[] = array('name' => 'Jack', 'age' => 15);

Which looks something like this: print_r($data):

Array
(
    [0] => Array
        (
            [name] => Bob
            [age] => 12
        )
    [1] => Array
        (
            [name] => Jack
            [age] => 15
        )
)

If you’re using ADODB, you can use this little function to convert the recordset to a suitable array (there are some built-in functions to convert recordsets to arrays, but they all end up giving you pretty useless data).

function rsToArray($rs) {
    $arr = array();
    while (!$rs->EOF) {
        $arr[] = $rs->GetRowAssoc(False);
        $rs->MoveNext();
    }
    return $arr;
}

I must say, I’m rather disappointed with my “SmoothWall experience” so far. I’ve been tasked with setting up a SmoothWall firewall/proxy machine at work, and from what I’ve read, it’s like the best thing since sliced bread.

Unfortunately I cannot agree.

The installation tends to go fine, it partitions the hard disk by itself, installs fairly fast, then steps through a simple setup ‘wizard’. Here we are prompted if we want to enable or disable ADSL. Now, I want SmoothWall to connect via our ADSL line. BUT, it seems the developer’s idea of “ADSL” is in fact “USB ADSL Modem”.

Anyway, after figuring that one out, and after much shuffling of subnets and IPs between the router, SmoothWall, and my PC, I finally get it to use the router as a gateway. I try visiting some sites - DNS lookups fail. I take a look in all the log options on SmoothWall, and find the firewall is blocking DNS traffic, and is trying to route everything through the same (“Green”) NIC, rather than the second (“Red”) one.

Sooo, turns out I can fix this by running the “setup” tool again, and ‘pretending’ to change the IPs, so it resets everything (re-writes the firewall rules maybe?). Cool, everything’s working again. Not quite.

Seems after that, the proxy magically stops working altogether, so from the web interface, I just disable it, and re-enable it. Cool, everything’s working now. Riiiiight.

A few hours later, suddenly the internet is dead. Hmm, seems the firewall is blocking all traffic again and routing though the same NIC. Sooo, I repeat the whole IP change/reset, proxy reset, etc, and everything’s cool.

A few hours later I find myself repeating the whole procedure again.

This is seriously lame, having to practically reboot the entire machine every few hours. So I think maybe I’ll try to set up a PPPoE connection. So I go and configure the router correctly, test ‘dialing up’ with my machine in XP, all’s cool. Now to set up SmoothWall. Running the setup tool again lets me set the “Red” interface to “PPPoE”, and that seems done. Now where do I put my username and password to dial up?

Apparently the “ppp settings” page of the web GUI is where it’s done. Now excuse my ignorance, but this looks like a modem dial-up page, asking for phone numbers, which COM port my modem is on, etc, etc. A bit of searching around the rather un-helpful support forums, reveals that this is indeed where you need to configure PPPoE usernames and passwords. Just leave all settings alone except for login details.

I give it a shot, tell it to connect, nothing happens. Check the logs, and not surprisingly, it’s trying to connect via ttyS0 (COM1).

Now, apparently there’s supposed to be an option to select the correct interface in the drop-list where you select which port your modem is on, on the “PPP Settings” page, but for some magical reason this does not exist for me.

Unfortunately their forums are also not very helpful it seems, and even after composing a very descriptive help request, I get a rather sarcastic “RTFM” response for a subject not covered in the manual.

Basically the manuals are not up to scratch, the support forums are full of leetbois, the options in both the setup tool and web UI are obscure, and the whole thing is bloody useless, needing a darn reboot every few hours. WTF.

I’d love to send the whole thing to hell, but unfortunately I have to get it to work. *sigh*