Factorio is an impressive game. I’ve never seen such a raw and visual simulation of items and entities, especially in that scale. Surely they have optimized the hell out of it. It’s also written in C++. A programming language that is known for it’s tremendous throughput of data.
Skimming through the blog posts one thing caught my interest. (https://www.factorio.com/blog/post/fff-39)
“There could never be 1000000 items on belts in Unity I guess.”
Yeah, I think so too, but, is it true? There’s a lot of back and forth when it’s coming to C++ vs C#. In my humble opinion I’d use nothing but C# in games. Games have really really complex systems and mechanics, all intertwined. The strength of C# is it’s ease to create better architecture. As you don’t lose yourself in low level tasks the architecture can be built more strongly, more agile and most often compensate for the loss in speed. The loss in speed is still argued, but lets not get down to it. Lets just say C++ will be faster when it comes to huge data.
But what kind of data is exactly huge? The throughput a SQL server can handle is on a completely different level as Factorio. One could even say it’s quite laughable.
Digging deeper, Factorio uses one thread to update its physics. Really? How smooth it’s running I expected a multi threading system, but as I read on, that’s in the works.
So every crazy programmer has done something like a for(int i = 0;i < 1000000000;i++) loop in his lifetime. Worked as expected, right? Took some time, but went pretty fast. But certainly not smaller than 16.6667ms fast to work for a 60fps game.
Deducting from this Factorio doesn’t loop around 1 million entities. In fact, they use an active Entities list that the physic simulation will loop through in a single thread. Items and Entities that don’t change are put to sleep and removed from the active list pretty quickly.
In a huge multiplayer map I’m having the active count somewhere around 20k. Compared to the 250k entities and 500k connectors that’s a pretty huge optimization in itself to keep it that low. It’s the clever use of game mechanics that support this.
Transport Belts are the most demanding. Every item has to make a distance check to the next to not clip into the item in front of it and it has to be moved with every physic step depending on the actual speed of the belt. No real way around it. Unless the belt is full, in which case it can be put to sleep. And that will be the case most of the time. Updates often only occur when inserters are taking items from the belt. The belt awakes and a chain reaction happens for every belt before it. If the belt is fast enough all the belts are put to sleep again before the inserter takes the next item. Clever stuff!
The optimization can be exploited though if you want. On every belt 8 items have space. To put 1 million items on belts that are moving at the same time you’d need 125k belts alone that are placed in an upwards/downwards motion with fast inserts on the edge that put the items in place. I wanted to test this out ingame but even in the map editor this number is so absurd to achieve that I gave up without any method of automating the process. I will eventually come back to this and finish my map.
Back to Unity, because we already know Factorio does an excellent job of keeping the simulation simple.
To test things out I needed quite a lot of prerequisites.
The self growing QuadtreeManager that holds the actual map data. It’s needed for collision checks and culling to render the map. Skipping this part would only distort the test results.
An Entity class that has a bounding box, coordinates and type.
A simulation thread that does the physic steps, iterating through every active entity and based on the type runs different code.
A transport belt class with at least moving items and distance checks so items don’t overlap when it comes to a halt.
After some trial&error were the main cause was overdoing it I can report that even with 1 million belts I can maintain a steady framerate of 60fps.
Granted, it’s optimized in the way that not every belt is active. If I skip this optimization and 1 million belts are processed the framerates are 0.5-1fps. Ouch! Memory is at a 1.4 gigabytes. Not that great. Lets see how it will hold up as every belt will be filled with items that are moved. As I’m running simulations now I’ll report the physic timings per active entity and memory in part 2.
Right now things are looking better than expected. With my current knowledge I can say something like Factorio is possible in C#. Clever use of programming and extensive optimization is needed but lets be honest, if you’re doing something out of the ordinary that’s always the case.
Read more: Factorio in Unity/C# -Part 1.5 – Interlude