Forbidden Lore Design Diary #10: The Hard Thing That Turned Out To Be Easy Turns Out To Have Been Hard All Along

Today, I hit an item on my to-do list: is my auto-save only saving after every player turn, or after every mouse action?

Turns out, the answer was “after every mouse action.” So that’s not, you know, great; I’m new to this whole game development thing, but I’m pretty sure saving your game forty times because the user dragged the mouse across the screen is considered sub-optimal design. So I worked to put that autosave command elsewhere.

The input handler seemed like a sensible spot; after I told the engine to handle the enemy turns, I also told it to save. Easy-peasy. However, this introduced me to the concept of “circular dependencies,” which Python finds quite objectionable. Basically, I had to dig into a lot of the weird stuff the tutorial put at the top of many files (like “from __future__ import annotations” and “if TYPE_CHECKING” and other such things) and understand why I needed them. Good news! I now understand why I needed them! Yay learning!

However, I stumbled across a very weird error when I chucked a fireball:

AttributeError: Can't pickle local object 'FireballDamageConsumable.get_action.<locals>.<lambda>'

Baaaah. The code I was using to save the file had beef with the nuances of how some of my stuff works — nuances I barely understood myself. So that looked no damn fun to debug.

But more troubling, I discovered that if I quit the game right after seeing that error, the auto-save file got corrupted and could not be reloaded. Having a game that corrupts its own auto-saves whenever something goes wrong sounds infuriating, so I had to get THAT shit sorted out, too.

Luckily, I had an easy way of generating those corrupted data files on hand.

I posted a question to Stack Overflow, but as one might reasonably expect on a Sunday afternoon, there were no Python nerds willing to lend me a hand. Ah, well.

I researched how to move files around in Python, then whipped-up some code that would move the old auto-save file to a backup and then restore the backup if something went wrong during the save. This code did not work. I spent about an hour tearing you my hair trying to figure out why. I had all these theories; was the filehandle still open? Was I running afoul of an asynchronous race condition? I investigated all that shit only to discover….

A typo. The backup code was looking for the wrong fuckmothering filename.

Once that moment of Software Development was behind me, I started digging into the reasons why the save was fucking-up. Still not sure I know the details why, but the solution turned out to be a package called “dill.” Yes, the code that serializes — “pickles” — the object for me works better when you enhance it with “dill.” Once I figured out how to do that, I was golden.

There’s an old truism in software: for every sufficiently advanced problem, there exists a solution that is simple, elegant, and wrong.

And that’s how my simple, elegant three-line save method turned into something closer to thirty lines, not including blankspace and comments.

I was planning on figuring out some menu stuff today. That’ll have to come next.