Diary #68 – 1.2.14 Release Notes

Surprise, it’s another update for Iron Village! Iron Village got a big bump in sales recently, which initially looked like an end-of-sale spike, but turned out to be driven by this video by the Geek Cupboard:

It’s awesome to see Iron Village popping up still, but of course more players means more opportunities for bug reports! There were two bugs reported last week:

  1. On Android, the foundation for the Magick Transformer was missing, so the player couldn’t build it.
  2. On the Steam Deck (but also PC), the controller would stop responding when going back to the menu, even though the menu was in focus.

I’m still not 100% sure what happened for #1, especially since I couldn’t reproduce it, but it did highlight the difficulty of debugging on someone else’s Android device. Actually accessing saves isn’t possible right now (each app’s storage is kept secure from any other app accessing it, but that apparently includes the user too), and in order to get any logs you have to ask the user to install adb, plug their phone in, reproduce the bug, and copy/paste the relevant logs. (Hope the player understands what’s relevant!) As you’ll see below, the changes made here are mainly band-aid fixes, UI to better surface issues, and unrelated bugs I encountered.

For #2, the issue was specific to how I implemented the Steam Input API. Whenever an action came in, it would let the ControllerHintManager know – that way, the controls get shown when the player is actively using a controller. I have ControllerHintManager implemented as a singleton: it’s a type of object in the game, but it’s designed so that only one exists at a time. This singleton “pattern” can be implemented a few different ways, but in Iron Village I just use a static variable Instance, and set that when the first instance gets created. The singleton is an unfairly maligned pattern IMO – for a lot of software it does end up encouraging bad design, but there are quite a few places where it can be done more responsibly in game development, especially in smaller projects. Is it a good idea in this instance? IDK, it’s not great, but not terrible.

Anyway, the issue here is that ControllerHintManager only exists in the game itself, not the main menu. The first time you load the menu, this is fine – there is code that checks if Instance is null, and skips talking to the ControllerHintManager. It works fine within the game of course, since the manager actually exists there. When you go back to the main menu though, that deletes the ControllerHintManager, and that’s where the problem starts.

Warning, discussing about programming languages and other details ahead!

The follow up question is this: what does it mean to delete something? In most cases, you’re not actually changing anything about the data in memory or on a hard drive, you just tell the operating system that you don’t need to reserve that space anymore. Eventually something else will probably use that space, but the underlying bits don’t immediately change. That’s the basis of how a lot of data recovery tools work – the “empty” part of the hard drive can still hold data that was previously written.

If Iron Village were using a “lower level” language like C or C++, we might get away with this issue for a little bit: the Instance variable would be pointing to a “deleted” ControllerHintManager, but as long as it hasn’t been overwritten in memory yet, it might work. (This is bad code because it’s undefined behaviour, and could end with the game fully crashing out instead.)

In C# (and a lot of other “higher level” languages), there’s an added layer of memory management and garbage collection. It’s keeping track of what’s been deleted, so if you try and access deleted memory, it throws an error that you’re trying to access a disposed object. Crucially though, our Instance variable isn’t null – it’s pointing to that deleted object! So now when input comes in from the Steam Input API, it tries to talk to the ControllerHintManager, and throws an error. Because of how error throwing works, it skips a lot of code that comes later – including that part that actually acts on that input. (Without any additional code, this would crash the whole game, but the Godot engine tends to catch most exceptions once it’s no longer your code. Sometimes this isolates the problem and lets the rest of the game continue working, other times it just makes things weird.) So every time you try and scroll down, the code tries to contact ControllerHintManager, fails, and gives up.

The solution was just to set the variable back to null whenever the ControllerHintManager gets deleted (i.e. in Godot’s _ExitTree() method), a small change that probably should’ve been done from the beginning. 🙃

Anyway, if you’ve made it this far, here’s the full release notes:

  • Fixed an issue where corn fields (and only corn fields) were being drawn above buildings in front of them.
  • Added an error dialog to the game to display errors that would normally only be seen in the logs. (Note that it doesn’t capture all errors, only those in select sensitive areas of the code, like loading.)
  • Fixed an issue where the Maximum Production Rate button wouldn’t appear in the Railway Status Window immediately after building the Railway HQ.
  • Added code to build the Magick Transformer Site on loading a game if it should be there.
  • Fixed an issue where Steam Input would no longer respond after exiting to the main menu.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *