Friday Facts #370 - The journey to Nintendo Switch

Posted by Twinsen, kovarex on 2022-09-23

We have a long history of trying to bring Factorio to other platforms, including consoles and mobile phones (not including April Fools). We even worked with some external companies, but the projects never even got to the point where they would run technically, let alone the complicated part of making the game playable using controllers or touch screen. After all the attempts, we even had a Friday Facts prepared that was going to say something along the lines of "we don't plan to bring Factorio to other platforms".


The journey to Nintendo Switch Twinsen

I am a big fan of the Nintendo Switch system, especially the detachable Joy-Con controllers, which you can hold one in each hand. Porting Factorio to Nintendo Switch was something I had in mind for a very long time. At around February 2021, as we were discussing the future of the team and what project we should work on next, I decided I want to try and port Factorio to Nintendo Switch. After some initial research, it didn't look like it will take too long...

Before I continue the story, I'd like to mention that the project as a whole had a lot of unknowns:

  • Is a technical port possible without a major rewrite of the graphics backend?
  • Can the Nintendo Switch system even run the game at an acceptable performance level?
  • Is it possible to play the game using controllers?
  • Is the project not too big?

We had some history of starting Factorio-related sub-projects that ended up in development hell for years, so my goal for this project was always to try to fail fast, while doing my best to make sure the parts are not just quick and dirty prototypes. If the answer to the questions such as the ones above was a clear no, the project would be cancelled, and there were a few close calls :)

Compilation and first run

So we applied for developer access and got it quickly. And the first problem was up ahead, can I even make Factorio compile for Nintendo Switch? Especially since we use a custom FASTBuild script to build Factorio and all the libraries. Luckily the Nintendo Switch documentation is very detailed. After understanding the many details of the build systems, I managed to create a FASTBuild script that builds Factorio for the Nintendo Switch.

3rd March 2021 - I had the first milestone, all the compilation errors were fixed and the executable would link correctly.
4th March 2021 - I was able to build the full game package and run it on the devkit. It would crash immediately after starting though.

What followed was a lot of fixes and technical problems, such as handling window initialization, audio, filesystem initialization and access, network stack initialization. And with such a big project you never know when the problems end, you just fix the most obvious one and move on to the next, then run the game again and repeat without really knowing where the next crash or error will be.

29th March 2021 - I had a big milestone, the log file read: "1212.940 Factorio initialised". Factorio successfully booted to the main menu.

It was a great feeling, especially since everything seemed to just work all of a sudden. The background simulation was rendered correctly, the sound and music would play, even interacting with the GUI using the touch screen worked. All of the fixes and implementations were now finally visible.

Performance

But those with a sharp eye might notice a problem with "1212.940 Factorio initialised". 1212.940 is the timestamp in seconds. It took the game 20 minutes to load and reach the main menu...

It was a debug build, so the number was not that large, but startup time was something we were dealing with even until the final days before release. Now, the final startup time when the game is installed on internal storage is 70 seconds, but let's not get ahead of ourselves.

The next step was doing all the obvious performance optimizations and deciding if the performance is good enough. There were many optimizations to do but the task was made easier thanks to the development tools. It allowed me to make many Nintendo Switch specific optimizations, and even some optimizations for the PC version. Answering "is the performance good enough" is not an easy question, because, what is "good enough"? I settled for "the average player should be able to finish the game by launching a rocket and the game should maintain 60 UPS". Luckily, the performance met that target, even if it was quite close.

Multiplayer

With that out of the way, the next step was multiplayer determinism. One big goal was that I didn't want to cut multiplayer from the game. Furthermore, I wanted players on PC to play with players on Nintendo Switch. This is the first time we had to make sure the game is deterministic between ARM and x86. We should be fine, C++ is portable, right? Just don't use undefined behaviour. Turns out we use quite a lot of undefined behaviour, both in our main code and in the libraries. For example, when casting a double to an integer, if the value does not fit in the integer, it is considered undefined behaviour and the resulted value is different on ARM and x86 CPUs.

Removing all uses of undefined behaviour is probably a fool's errand, as it would require significant changes throughout the code that would take time and come with a performance impact, all for no immediate practical benefit. So I just hunted down the undefined behaviour cases that actually broke determinism. This was easy enough, as we have plenty of tools we use to test determinism. By comparing the game state CRC for every tick of every test (we have 2,417 tests) between x86 and ARM, I believe I got a pretty good coverage of potential issues. Even after fixing all the issues found, there might still be some multiplayer desyncs, but players should help us find any remaining desyncs.

Controllers

The next big step was making the game playable with controllers. Factorio was developed for 10 years with only keyboard and mouse in mind. We also have 146 controls (mappable actions), while a controller typically has 16 buttons and 2 joysticks. I'm trying to create a control scheme that:

  • Has all the important actions.
  • Is intuitive for new players and existing players.
  • Respects known standards.
  • Makes sure the most common tasks are fast.

I needed to accomplish these while not redesigning the GUI from scratch, and not rewriting huge parts of the game. All this is enough to give you brain damage. Nonetheless, I had an idea of how to do it, since I spent some time planning this before starting the project, to make sure it's even reasonably possible.

The GUI

One of the challenges was how to navigate the GUI. Something that was clearly out of the question was dumbing down the GUI on all platforms for the sake of controllers, like many games do. There are many PC games out there with terrible "console port" GUIs; Factorio's will always be designed with keyboard and mouse in mind first. Another thing that was also out of the question was redoing the GUI for controllers. We have hundreds of GUIs that took years to design and implement, and some are still being changed. Redesigning and changing most of them again would also take years.

So the only remaining solution was to use mostly the same layouts and navigate through widgets using a controller stick. It seems simple, but under the hood there's a pretty complex heuristic algorithm. For example when pressing left on the stick, the algorithm will look through all the interactive widgets on the left, and pick the best one based on factors such current widget and candidate widget bounding boxes, positions, what parent type is it a part of, what is the bounding box of that parent, etc.

Here's a short video of what interacting with the GUI looks like:

Another important part was updating the quickbar. I added a new UI called the "Quick panel". It's a radial menu that is open while holding L (left bumper) and allows quick access to items, tools and panels.

Finishing up

Near the end of August 2021 the main game was fully playable on Nintendo Switch. I work remotely, and at that time we had a meet-up so I took the opportunity to force ask the other team members to play through the game while I watch them, to see how intuitive it is for those who play with a controller for the first time. The feedback was mostly positive and I also had an idea of what parts should be improved.

And with that, the last major part of the port was done. Just polish it and ship it, the game should be ready to launch by the end of the year (2021)... But we are releasing on 28th October 2022, so what happened in the meantime? As expected, things take longer that expected. The ninety-ninety rule (or similar) roughly holds true. Also, remember that I wanted to "fail fast", so I wanted a playable vertical slice as soon as possible. Now it was time to go back and make sure everything was done properly. Plus, there were still many, many small things to do:

  • More playtesting and polishing playing with a controller.
  • Tweaking the heuristic algorithm that navigates the GUI so it's intuitive and works for all our hundreds of GUIs.
  • Making sure all our custom GUI widgets can be interacted with a controller, this includes switches, sliders, train minimap, equipment grid, etc.
  • More optimizations to UPS, FPS and loading times.
  • Experimenting with adding vibrations. The Joy-Con controllers and Nintendo Switch Pro Controller support HD Rumble. After some testing and experimentation I decided it's worth it to use this functionality and add many custom vibrations to enhance the experience.
  • Updating the tutorial campaign, Mini-tutorials, Tips and tricks.
  • Localisation.
  • Age ratings.
  • In-game and server back-end changes to support quick authentication of Nintendo Switch players.
  • Bugs
  • Implementing and making sure Nintendo's requirements were met. Releasing a game on a game console means it needs to comply with many requirements and go through a review process.

Even after the launch, there is much to do. Next to my screen there's a stack of post-it notes with future improvements, possible features and technical debt I need to solve. As mentioned in the announcement last week, after the launch I will also work on controller support for PC and Steam Deck.

It was mostly my pet project and I was the only one working full time on it. I tried to let the rest of the team focus on the expansion and not get in the way, but others helped me out with some things, such as graphics optimizations, audio optimizations, web backend, testing, playtesting, feedback and other small tasks. So as with everything, it's a team effort. Also many contacts at Nintendo offered support with the launch and development. It was an honour to be featured in an event as big as Nintendo Direct.


That's nice, but what about the expansion?! kovarex

It wouldn't be fair to not address the elephant in the room, which is the progress on the expansion. We have been working hard on it and have a lot of progress, but still haven't shared any specifics for the strategic reasons mentioned previously.

In the FFF-367 we specified that we are in Step 4, and now we can say, that we are somewhere deep in Step 5. First, I had a playthrough from start to finish, where we had to assemble and fix systems on the go. It was very rough and long, partially because I had to repeatedly update the factory as we implemented changes.

But the result was the game being playable from start to finish. Having a "skeleton" of the playthrough was critical for managing the team, as people could more efficiently split their effort into more independent sections of the game.

The second playthrough was a week-long office LAN-party in July 2022, where 12 people spent 5 full days racing to finish the game before the end of the week. Some of us took family vacations because of this, so we tried to get the most out of it. You can imagine how intense it was, and how destroyed we were at the end. But it was a great experience, and playing one playthough in one continuous session, gave us an accurate feeling of the overall pacing. The key takeaway was that the game was too long, and some parts were too boring or repetitive.

Since then, we mainly focused on fixing the problems identified. Also, a lot of the things we used in the playthrough technically work, but its look and feel is very simplified as it is a prototype. Imagine an inserter prototype which moves things from A to B, but it is a grey square and doesn't swing its arm. This is the state of a lot things at the moment.

The reason why we still don't share specific details is, that we have to sadly inform you, that it still won't be ready sooner than in a year from now. Once the estimates get reasonably close, we will start dropping some FFFs.


As always, you can let us know what you think at the usual places.