Renaming Our Company Revealed a Critical Bug
Sep 2022
TL;DR: Our game had a bug that would erase all save files, whenever the file path of the local storage directory contained the character "S". If your Windows username contained an "S", your data would be gone. Luckily renaming our company to one containing an "S" revealed my mistake before our release.
Background
Saving in our game is quite old school. You can only save your game at designated saving spots, which override a game slot (you have 3 slots in total). Our saving system actually has a pretty nifty pub-sub design, with the goal to be robust against game upgrades and asset changes. It basically creates a bunch of save files in a location like ~/.company/game/slotX. The name of a file is created by computing a hash of an object's serializable fields, its type information, version and in-game GUID; resulting in a hex string like 78f2ce21d0.
Suspension Mechanism
Instead of the old-school saving mechanism, which can feel quite punishing at times, we wanted to give players the option to suspend the game at any time, and load back in with (almost) the entire state restored. However, a suspended slot should not give the player an escape hatch for returning to this past state at will. After successfully loading into a suspended slot, the underlying state files would be deleted. For that to work you need to distinguish between normal and suspension files.

And herein lies the bug.

Upon suspending, the saving system inserted an "S" into the name of all suspension files, and when the game was loaded again, all files in the saving directory that contained an "S" would be deleted. I chose the letter "S" because of "suspend", and also because that letter can't be contained in the hex file name. But instead of the file name, I checked the entire path! This was due to me misreading the documentation of .NET's Directory.GetFiles. What a blunder. Now if there's an "S" somewhere in the path, the file would get deleted.
Renaming the Company
It turns out none of our developers had a name starting with "S" (and neither did their OS username). It was only after we changed our company's name (for very unrelated reasons) to one that contained an "S" that the saving system started to fail, as the storage path turned into ~/.Sxxxx/game/slotX. At first I was confused about this regression, because up til now the system held up beautifully to version changes, engine migrations and bigger reworks.
Why did I do that in the first place?
That's a fair question. Obviously my solution isn't particularly good. I just needed a way to distinguish between categories of files without any footguns. I wanted to keep things as simple as possible in order to reduce the error surface. What else could I have done?
  • I could've placed the suspension files into their seperate folder. I didn't want to do that, because the suspension mechanism could be easily gamed by copy-and-pasting the folder after deletion. Looking back, this reasoning was the result of unnecessary paranoia, in part because we didn't even end up implementing any data obfuscation.
  • I could've used a unique symbol like "__suspend" instead of "S". That wouldn't have led me to find and fix my bug though, just make it unlikely to occur. Still an improvement! (Side note: I wanted to keep the marker as short as possible to avoid running into Window's 260 character path length limit).
  • I could've marked suspension files by editing the files' metadata. However, metadata can be annoying to edit on-the-fly, and the APIs to modify metadata are often platform specific.
  • I could have written it in Rust. This is the only correct choice, because rustc would've prevented me from misreading the docs. Hindsight I guess.
Conclusion
The lesson of this story? When choosing a name for your kids, use as many different letters and capitalizations as legally possible. If I had just been named zjStHbFrTuIoPx2Aab I would've spotted my mistake earlier. Maybe once everyone's name looks like a one-time password, we will live in a prosperous world. Until then, triple-check destructive code and never release a game without alpha/beta testing (duh).