Since this is my first post, let me briefly introduce myself. I'm Scott, and I run a one-man company called Green-Eyed Games in my spare bedroom. I'm just about to release my first game, "Last Train to Timbuktu!". Gamasutra has been a great resource for me as I first dreamed about, and then actually started Green-Eyed Games, so I hope to be able to contribute back to it in whatever small ways I can.
As a start, I'd like to describe a simple, cheap system I came up with for distributing software updates in the hope that 1) some of you will find it useful, and 2) I'll get some feedback and find out if I'm making a hideous mistake.
A week or two ago as I was working on Last Train to Timbuktu, I started asking myself some inevitable panic-inducing questions: "what if the game turns out to not be balanced as well as I thought? What if people want more difficulty settings? What if there's a bunch of weird bugs I haven't found?" The modern answer to these questions is to just release free downloadable updates as necessary. This is easy if you're working with an app store - Steam and iPhone games update themselves all the time. But Last Train to Timbuktu is going to be sold from my website through FastSpring (though of course I do plan to get it into as many stores as possible). FastSpring has a lot of features, but unfortunately distributing software updates isn't one of them. So, I wanted a way to distribute updates myself.
I run Green-Eyed Games on a shoestring budget, and I don't mean a nice, waxed shoestring for your dress shoes. More like the dirty old one with knots that you never untie and have been meaning to replace for a year. That kind of shoestring. So there's not a lot of money for things like server infrastructure. There's also only one of me, and I'm only doing this during evenings and weekends until I finish grad school, so I don't have a lot of time either.
No time, no money. Good combination. Oh well - creativity thrives with constraints, they say. I came up with a solution that uses four services:
There are three operations in my approach: recording purchases, releasing updates, and notifying customers.
On FastSpring, I added a custom field to my order form to let people choose whether they want to be notified by email about product updates. On my server, I created a database to track products, customers, purchases, and downloads.
When somebody makes a purchase, FastSpring sends a notification to a PHP script on my server. This script checks whether the purchaser wanted to be notified about updates. If they did, it records their email address and the product they purchased, along with a random string that acts as a purchase key.
When I release an update, I upload the installer to a private Amazon S3 bucket and create a new "version" of the product in the database. The version consists of the product id, a string identifying the version, and the canonicalized S3 URL.
A second PHP script facilitates downloads. It accepts three GET parameters: the product, the version, and the random purchase key. The script verifies the purchase by looking up the purchase key. It then looks up the product's S3 address, constructs a query-string authenticated URL with a short expiry time, and redirects the customer's browser to the download. After three download attempts for the same product update with a given purchase key, the script stops redirecting and starts displaying an error.
To notify customers about a product update, I export all the email addresses and purchase keys associated with the product in the database. Then I import that data into a mailing list with a custom field for the purchase key. After writing an email that includes a link to the download script, a mail merge inserts the purchase keys into the download links. Every customer who wanted to hear about the update receives a link with their purchase key and is only one click away from the download.
This system has a lot going for it:
Of course, it isn't perfect. In particular, it doesn't handle returns or refunds. This is because FastSpring's notification system doesn't distinguish between full and partial refunds, and it bundles multiple returns into a single notification. I don't expect returns to be common enough to warrant writing more complicated code to figure out whether to remove purchases from the database. I'll just do it manually as necessary.
So, that's at least one poor indie's update distribution system. If there's any interest in this, I'd be happy to put my PHP scripts up on GitHub with more detailed documentation. For those of you with experience in such things, does this seem like a reasonable system to use? Is there a better, more standard way of distributing updates that I've overlooked?