Facebook integration in Dragon Attack
Always new things to learn! This week, I integrated Facebook highscores into Dragon Attack, so you’ll be able to see your friends’ scores and challenge them to beat yours. I’m hoping this will give the game more lasting appeal, not to mention some ‘virality’.
This is what it currently looks like:
I have mockups for a better looking layout, but you can see that the base idea is there. Susan Alabdjfhfdaij Bushakstein is one of my autogenerated test accounts. Interestingly, these all have really long names, presumably to try and break your UI. And their middle name mostly consists of letters on the home row of a qwerty keyboard. Coincidence? I think not!
These highscores actually took a fair amount of work to implement, so the rest of this post will be rather technical.
The first problem is that you have to juggle two types of access token: one for reading the current score (READ
), one for writing a new one (PUBLISH
). Since the library I’m using (gdx-facebook) stores only a singleton-like “current” token, you have to be careful to sequence all calls to the server and sign in with the right token before each series of calls.
Then there is the lack of atomic operations in the Facebook API itself. You have to fetch the user’s current highscore, compare it to the new score, and post the new score only if it is higher. There is a possible concurrency bug here, which will likely never happen because nobody plays on two devices at the same time, but it still bothers me. And of course we have to post the new score before we fetch the list of other people’s scores, because we want that list to be up to date. (Fortunately, there don’t seem to be significant propagation delays. A side effect of Facebook running largely on MySQL?)
Actually rendering the list also takes a fair number of API calls. First we get all known scores (from a subset of your friends). Then we get all friends (because we need their profile picture URLs), and the user’s own profile picture URL (because they’re not in their own friend list). We merge those, then fetch each profile picture with an individual HTTP request to the CDN. I used to work on a JavaScript-heavy single-page application, and this really goes against the lessons (about performance, and quota usage) that I learned there. I might get some improvement by using the batching API, but still would have to fetch each picture one by one. Right now I’m caching everything in RAM only, hoping that it will be a good compromise between freshness and performance.
This would take some thinking in a language that was actually designed with concurrency and asynchronicity in mind. Java, although it gives you all the tools, is not. The gdx-facebook library gives you callbacks for each operation, which have one success mode and three different failure modes. The HTTP library in libGDX also comes with its own callbacks. Some operations can be parallelized, some must be done in sequence, and some must wait for an entirely different operation to complete first (because of the access token thing). And of course, you have to be careful to make all these callbacks run on the right threads, otherwise libGDX will explode. So in order not to go entirely crazy, I finally caved in and added Google’s excellent Guava library to the project. Its ListenableFuture
and AsyncFunction
make life a whole lot easier – palatable, almost.
Finally there is a potential future problem: in the Facebook model, there can only be one score per user per app. So if I ever want to have multiple levels, or multiple game modes, I’m out of luck. I’m not sure how I’ll solve that if the need arises. I would still use Facebook for authentication, authorization and friends discovery, but would have to store the data elsewhere, like Firebase. But then I’d either have to make all data public (privacy nightmare) or copy over the user’s friend list to serve as an access control list (other privacy nightmare on top of a synchronization nightmare). Yay.