LD38 Postmortem

I took part in Ludum Dare 38, the theme was "A Small World". I was coaxed into it by an internet friend, and came up with a technically compelling idea. You can play it for free on itch here.

Screenshot of a pixelated videogame, titled "digital backwater"

Digital Backwater was a mad dash from conception to completion and I enjoyed every minute.

This is a quick postmortem of what happened before I get swept away by work again.

The Idea

The leftovers of digital interactions are all around us: abandoned forums, dwindling chat rooms, folders hiding forgotten in the corner of your desktop, old embarassing comments on social media. I'm intrigued by this phenomenon and wanted to explore it a little.

The idea was to have a persistent, synchronised world between players, and give the players tools to mess it up. The hope was to build a system that would accumulate "detritus" at an accelerated rate, but somehow keep the scope small enough to finish in a day, which was all the time left in the game jam.

What Went Right

  • Concept to Implementation

    The idea sort of just "came together" - there were no really significant hitches getting it working. The biggest task was actually the typing input and getting that into the tilemap in a way that didn't suck.

    For reference, the whole project was done in less than 24 hours clock time, maybe 10 hours work time.

  • Player interaction

    Players just kind of picked it up and ran with it. I quickly got requests to add more glyphs (there was only the alphabet initially). One guy wanted to write his name everywhere. Lots of people like messing the blocks up, a few like putting them back in order. Chat "feels" physical when you're moving around, but because of space constraints, conversations (from what I've seen so far, anyway) are brief.

  • Persistence

    Using firebase for the persistence "just worked", for the most part. Once I had the data model sorted out, I was honestly surprised how smoothly it went. I'm not saying that there weren't hiccups, but multiplayer is rarely simple.

What Went Wrong

  • No Sound

    I ran out of time, plain and simple. Unfortunate as it kinda does take away from the immersion, but this does seem to matter a little less for web games? I'd love there to be some beeping and clicking though, and maybe a little quiet melody as you (and others) move around.

  • Database Design and The Usual Networking Issues

    Firebase has preferred ways of doing things that I hadn't quite thought through before diving in. There's still a few problems that cause issues like block duplication/deletion and in general any shared data seems pretty dangerous. As with any shared concurrent data, race conditions abound.

Firebase

For the synchronisation and persistence, I used libraries from Google's Firebase project.

At it's core, Firebase is a collection of libraries to handle a lot of the "baseline" stuff an app needs (web, mobile and I think desktop too?). They offer analytics, authentication, cloud storage, crash reporting, a nosql database and quite a lot more by the look of it.

I was only interested in the authentication and database, so they're the only things I touched this time around.

The only authentication system I used was the anonymous authentication - basically upon connecting, a user gets a unique ID to use for their session and that's tied to all their database access, can be used for access control and so on. From what I can tell Firebase also has a whole host of other authentication systems built in, which is nice if you're into that.

The database is a json-based nosql "realtime database", which basically means the client keeps a hold of a copy of relevant data and syncs changes to and from the server. There's a few different ways to access that data but because of the local copy, reads and writes don't always have to hit the server straight away, and it will apparently try to reconnect and resync changes if the connection is broken and re-established, working off local data in the meantime.

This isn't so great for real-time stuff but I imagine it's very useful for "normal" apps, and it'd suit less dynamic backend stuff for games too.

That said, I used it for everything - from player movements to the world state. This meant that there was no server to write on my end and let me get the multiplayer code done in a morning. It's somewhat an abuse of their system and I doubt it'd scale super big, but it worked surprisingly well for a jam game :)

That said, it's no magic bullet.

  • The player movement stuff is a little jittery as it is, and the game only has tile-level movement. Looks like it'd be very choppy for high fidelity stuff.

  • This kind of thing is pretty much client-authority by nature. Unless you put something between the browser and firebase (which imo would hurt the convenience of firebase) you've got to keep that in mind. I didn't pay enough attention to that particularly when implementing the map modification, and as a result there's "fun" bugs like duplicating blocks when more than one player is involved.

    That said, you can build validation logic into your database to curb particularly egregious cheating. Anything that would benefit from to direct programatic access the game state at large is going to be better suited to a more traditional server though.

  • Your data is live and fragile, and you can't (or I couldn't find a way to) disconnect clients. That means you probably want to look into adding versioning to your data model where appropriate - handling migration/"upgrade" of persistent data between versions might be tricky.

  • A small stumbling point was that the anonymous authentication can give the same ID to someone if they join in a short window from the same address. I ended up with a user syncing to the same user record from multiple sessions, which consumed a lot of needless bandwidth and caused awful flickering. Basically, you probably don't want to use the user ID as a key for session-specific data.

Thoughts for the future

I've actually been thinking of building a similar system of synchronisation and messaging for web apps - not for persistent data, but for soft-real time stuff. As firebase doesn't seem to handle real time stuff very well (or at least, not very cheaply), maybe those two systems could work in harmony nicely?

Previously...