UYLLII

Blog › Engineering

Engineering

Never strand a player: handling old and broken saves in a mobile game

By David2 min read
Moonlit Garden feature graphic

After a big update to Moonlit Garden, the pipe puzzle, I opened the game on my phone to carry on a half-played garden. The play screen was empty. No board, no buttons, nothing to tap.

All the tests had passed.

What happened

The update added coloured lanterns, so each saved garden gained a color array describing which light reaches which flower. My half-played garden was saved by the previous version and had no color array. The renderer read the save, found nothing to draw, and drew nothing.

The tests passed because every test started from a fresh save. None of them loaded a garden written by an older version of the game. The bug was invisible to every check I had, and obvious to the first real player who updated.

The rule

My rule for this now is short: if a saved level is invalid, restart it. Don't strand the player.

In practice:

Losing a half-solved puzzle is mildly annoying. A blank screen with no way out is an uninstall.

Because levels are generated from seeds (the same trick the Word Search engine uses), restarting a level is always possible. That's one more argument for seeded content: there's always a known-good way to rebuild any state.

Test with old saves, deliberately

The flow test now loads an old-format save and a deliberately damaged one on every run, and checks the player lands on a playable board with their progress intact. Any game that changes its save format adds a fixture from the old version.

The same idea shows up across the portfolio:

The general lesson

Most game testing starts from zero: new install, empty save, tutorial. Real players almost never are at zero. They're halfway through something, on a version you shipped weeks ago. If your test suite has no saves from the past, it's testing a player who doesn't exist.