Happy New Year all!
Over the past couple months I've made a lot of incremental fixes, changes and content additions to my local development version. Every small change has a chance of introducing a bug. So on News Year's Day I started a full playthrough, something I haven't done since launch, with two goals: 1) seeing whether anything has broken and 2) seeing if the collective changes are ready for player testing.
A full playthrough takes quite a while, so I'm only about half way through. I've discovered one new bug that has been in the game for over a year, but was only revealed through a recent change.
Currently, there is a bug where if you load a save, any damage to your ship would instantly repair. So I've fixed that exploit. But in this playthrough I noticed that sometimes I'd reload a save and have damage when there shouldn't have been any.
After investigating, I figured out the cause:
What was going on was that a while ago I added an optimization that cached your most recent save after reading it from disk, so when the player did a quick load or died the save manager could quickly pass that to the game without spending 200ms or so reading it.
The problem is that the various game systems assume that when a game is loaded, they can take any values passed to them and assign them to their respective variables.
For example, if the save file says the player has 2000 RP, then the game sets the player's RP to 2000 RP. This is not a problem and will not cause a bug because RP is an integer and integers are [i]value types[/i]. The game can change the amount of RP that a player has, but there's nothing that will change the value of the number 2000.
But some of the data is more complex. Things like the structure of ships are represented as a bunch of ModuleData's. A ModuleData is a collection of value types (HP, rotation, module type, etc) represented as an "object". An object is a [i]reference type[/i], which means that when you pass it around, you aren't passing around copies of various values, you're passing around an address in memory where those values are stored.
So when I loaded the cached save, the save system handed the ship a list of modules which it used to reconstruct my current ship. But when I flew into battle and the enemy started blasting at me, my modules were still referencing the objects in the cached save for their data. Which meant that the enemies were actually damaging the modules my save game.
Now I had designed the save system very much knowing about the possibility of accidentally referencing save data, which is why the save system uses "cloning" to create copies of the game data. But it only does this on the "save" side. I suspect when I implemented the cache I had forgotten this and thought it also happened on the "load" side.
Anyway, I'll be continuing the playthrough for the next day or two. Depending on how that goes I may either spend more time tweaking, or make it available as an opt-in test build. So stay tuned!
Until next week,
- Kevin