Streaming a Physical World
This week we'll be releasing an update (0.0.5.0) where we've really started to address some issues around low FPS and lag problems, so I thought I might write a bit more of a technical blog post than usual to talk about one of the problems that we face. I will do more of these posts in the future if many of you enjoy it.
One of the big issues we've been dealing with in A Township Tale, is having such a large world, full of physical objects.
Physics in a game is quite an intuitive term. The physics engine, PHYSX , handles objects moving, falling, colliding, bouncing, rolling, etc. These involve insanely complex calculations that, using PhysX, we can for the most part, take completely for granted. We could create a model, put it in the game, and give it some velocity, and watch it move around.
PhysX can handle thousands of objects incredibly well, and they have lots of tricks up their sleeve to help with that. The big one that I'll bring up today is 'sleeping'. To PhysX, every object is either awake, or asleep. If an awake object comes to a stop, PhysX will quite quickly realize it no longer is moving, and mark it as asleep. Now that it's asleep, PhysX can skip over it completely when doing all it's calculations. Until it is moved or given velocity in code, or hit by another object, it will stay sleeping. To do a quick test, I spawned in a pile of Spriggull Legs. Once they all settled down and were marked as asleep, the cost of physics dropped over 90%.
For the sake of a viable GIF, I actually cut down the number of Spriggull Legs here, believe it or not!
If the world were to stay loaded in forever, this wouldn't be such a big deal, as after a period of lag at first, the game would run much better afterwards. As our game world is so big (and getting bigger!), we have to do some funky stuff behind the scenes, not having everything loaded at once.
To do this, we developed a chunking system that allows for us to load in only a section of the world. A chunk is made up of static content (Land formations, houses, etc.), and dynamic content (Creatures, items, weapons, chests, etc.). On the client, only your nearby chunks are loaded. On the server, the nearby chunks of every player are loaded. As you'd expect, the chunks load and deload as clients move around the world.
One of the big issues we'd been having is the immense cost of physics as you move around the map. This was due to every object being 'awake' when a chunk loads, before coming to a rest. Especially in some situations cough after a Spriggull slaughtering cough, there is a pretty large number of objects, resulting in pretty horrific frame-rate drop. Although this cost did settle over time, often it didn't all come to rest, as moving around the map causes it to deload, and reload, once again - awake.
In this update, when a chunk is saved on the server, objects also save whether they're sleeping. When the server then loads in a chunk, it forces the object to sleep (if it was sleeping on save). This provides an incredible optimization on the server - especially with lots of players moving around different areas of the world. On top of this, when the server tells a client to load a chunk, it also includes whether that object is sleeping. This means that the clients can also benefit, by forcing most objects to sleep too.
Overall, the effect of these changes is better performance both for the server, and for players, as they move around the world. Although there is still of course the rendering overhead of hundreds of Spriggull remains, there is no longer a significant physics overhead.
If you're yet to jump into A Township Tale, be sure to check out our DISCORD We'd love to answer your questions!