Alt-F4 #53 - Laziness through Automation
For the very prime real estate of issue #53 of Alt-F4, grandmaster Therenas himself returns to grace us with another article. Following up his previous masterpieces that mostly talk about his own mods, here’s more words about exactly those things. Those words explore the topic of automatically taking screenshots in Factorio. Although it’s really only about 20% technical details, with 40% philosophy and 50% bad jokes. You read that right, it goes to 110%!
Laziness Through Automation
I often struggle to take appropriate screenshots for my mods. It’s a lot of work to set up a scenario in such a way that it’s appealing to look at and that it explains a core concept of the mod in a visual way. In my opinion, a lot of mods don’t have good screenshots, and it’s not because the mod authors don’t care, it’s because it’s really hard to produce good ones. They just need to do a lot of work with a pretty limited ‘language’, even if a picture is worth a thousand words.
Now, even though that all sounds pretty whiny (which it is), the actual issue is not taking the screenshots themselves. It’s fine to spend a couple of hours on them after you spent dozens or hundreds of hours on the mod itself. The actual issue is keeping them updated. Every change you do to the mod should ideally be reflected by updated screenshots; having them be outdated just signals a certain lack of care to me. I might be too much of a stickler though.
How often they need to be updated depends on the individual mod of course. If you’re Bottleneck and don’t change very often, your screenshots won’t fall out of date. If you’re a reasonably complex GUI mod though, practically every release changes your interface by some pixel here or there. Ideally, a five minute UI fix should be accompanied by updated screenshots, but that would make you spend much more time taking screenshots than doing actual work. Nobody wants to do that, and thus screenshots get outdated over time.
Compounding this effect and creating a bit of a virtuous cycle is human psychology. If you know that your screenshots will need to be updated every second release, you’ll just decide to skip updating them, only this once. The next release will have another change anyways, so why bother updating them now, that would be a waste of time. Only when the next release comes, the same psychology will lead you to procrastinate once more. Just this once. Repeat ad infinitum.
Maybe I’m just incredibly lazy and normal people don’t have any issues with this. They’d probably just update their screenshots on a regular schedule, and thus they’ll be pretty up-to-date most of the time. But I find this hard to keep up. In practice, it lead to me updating the screenshots about once every six months, if that. And it bothered me that they were not up-to-date, but the “I’ll just do it next time”-mentality was overpowering in the face of doing work that would be naught a week later.
Still though, I wanted a solution. I needed a solution, if only to absolve me of my self-imposed guilt of having outdated screenshots. It couldn’t be difficult to do of course. The idea of working on myself as a person would not pass muster, I’ll do that next week. Automation was the promised land it seemed, as it often does, and as it sometimes is.
I automated a few processes related to mod development before, most notably the process of bundling up a new release and all the micro-management that comes with that. In that particular case, it’s not even really because I didn’t want to do the same tedious steps for all of my releases (169 and counting for Factory Planner); it’s more about preventing me from making mistakes during that process, which could lead to broken versions getting to users and so on, which would be bad.
Get to the Screenshotting Already!
Alright, alright, let’s get to the fun part. My idea was pretty simple: Write a Python script that launches Factorio into a custom scenario, which then takes over the actual screenshotting part (for which Factorio has a dedicated API call, thankfully), after which the script puts the screenshots into the right folder and maybe crops them a bit. The first part of that is rather easy: I just needed to figure out which command line arguments I needed, to string them together, and the scenario would already be up and running. So far, so good.
The actual scenario is a bit more complicated, though. To be able to take meaningful screenshots, I need to set up various GUIs in various states to show the functionality I want to highlight. Doing this kind of thing for entities on the map is easier, since you can use all the APIs for interacting with the game world that you’d normally use. For GUIs though, which are a bit of a world on their own, you’ll have to come up with your own system.
The biggest issue comes from not being able to just simulate an actual user clicking on your interface. The game does not have any API method for this, since it’s not needed for any actual mod. What it means, though, is that you’ll need to somehow emulate clicks. This is a bit awkward since, unless your mod is set up for this from the start, or just very well-structured, you’ll need to either rewrite your event handler or use rather hacky methods. You might be able to guess which route I took.
After getting the hacks sorted, this whole contraption went as far as launching the game, setting up the interface into an interesting scenario, and taking screenshots of various parts of the UI. I have to point out that all of this is very duct-tape-y and will likely break very easily as the mod’s code changes. Since I wasn’t willing to do things properly, I’ll have to put up with it though. It’s much more fun to build a giant pile of spaghetti code than manually taking the same screenshots over and over anyways, so it’s a win either way.
I was pretty happy with what I had done so far, but still, maximum automation this was not. See, there was still the matter of cropping the screenshots to a smaller size. A lot of the dialogs in Factory Planner are relatively small, and having the game world in the background would be distracting. I could do the cropping part manually, but I didn’t want to. Something something laziness. I had a potential solution in the back of my mind, but it would require some dirty-work.
As the scenario was taking the screenshots, the basic idea was to also record the dimensions of the dialogs whose pictures were being taken. This metadata could then be written to a file as well, and the Python script could use it to crop the screenshots to the right size. This sounds like a great idea in theory, but it runs into a tiny issue in reality: The game doesn’t let you read the dimensions of GUI windows, only write them.
This is forbidden for a good reason, as these dimensions are actually not deterministic in all cases; setting the game to a different language might change the sizes of certain elements, for example. Reading and using these non-deterministic values in multiplayer would lead to desyncs, which would make the mod multiplayer-incompatible, and it’d also break replays. This seemed like a dead end. Was I fated to manually crop screenshots forever? Turns out, I was not.
Now, I couldn’t solve the issue that reading frame dimensions leads to desyncs, that’s just how the game works on a fundamental level. I am, however, not running the game in multiplayer to take these screenshots, and as it turns out, you can already launch the game in a special mode called Instrument Mode that disables multiplayer and enables some unsafe functionality. This seems like the perfect place to slip in a super-secret hidden method that gives me access to the forbidden knowledge of frame dimensions. So I went ahead and put it in. Working for Wube does have its perks, as it turns out.
After several days of piling on the hacks, the beast finally roared to life, fully automating the process of taking screenshots for me. Although fully automating the process is not quite correct. Turns out, it’s still not fully automated. Of course it’s not. Why would I get to be fully satisfied. There’s two steps that I still need to do myself.
The first is quitting the game after the screenshots are taken, so that the Python script can continue. As it turns out, a mod can not make Factorio quit to desktop. That’s entirely reasonable to prevent abuse, even though it would be a nice option to have for Instrument Mode. Either way, hitting Alt-F4 (ding) at the right time is something I can manage manually, I think. One intrusive thought I had was finding a way to make the game crash to quit to desktop. I warned you that this is all a pile of hacks. The issue with that plan is that there’s very few of these bugs in the game, and once they are found, you can be sure the bug-swatter will squash them immediately.
The second is uploading these hot and steamy new screenshots to the mod portal. There is no proper API for manipulating the mod portal listings at the moment, so I’m out of luck there. For now, I’ll have to manually open a browser, delete my screenshots one-by-one, and upload the new ones one-by-one. Quelle tragédie!. Maybe there is hope for an API like this in the future though, we’ll see.
Besides those two things though, I’m pretty happy with how this turned out. I think the juice was worth the squeeze, as I get to harvest the benefits of this script indefinitely. The joys of automation: Infinite gains. At least until the first time it breaks, which is likely very soon. Oh well.
As always, we’re looking for people that want to contribute to Alt-F4, be it by submitting an article or by helping with translation. If you have something interesting in mind that you want to share with the community in a polished way, this is the place to do it. If you’re not too sure about it we’ll gladly help by discussing content ideas and structure questions. If that sounds like something that’s up your alley, join the Discord to get started!