As many of you already know, I took last week off from my day job. Partially because we had a ton of family coming into town for the holidays and partially because I wanted to focus on some bigger Mythruna pieces that require undivided attention.
For the most part, this was a good call. I waded into working on the physics engine with a fully aggressive unrealistic schedule that was torn to shreds within hours of beginning.
But, I was able to get some stuff accomplished that would have been difficult otherwise. (Mostly because these things can turn out to be so difficult that I find excuses to avoid them.)
So, when chained to my desk and forced to stare at the problem for hours and hours, I eventually made progress in certain areas that are both critical and paint-peelingly boring to develop.
The goal for the week was to develop the networking layer for the physics engine. There are some pretty hard requirements on how this must perform and operate and I'd been dragging my feet on it for a long time. Furthermore, usually every time I pick up the physics engine code again it takes a few days to wrap my brain around what it's doing.
On the first Saturday, I resurrected the old combat prototype that I was working on some time back that never actually got any combat features except throwing chairs around. This prototype uses the main Mythruna game engine like a library and the main engine had changed quite a bit over the last year. It took me the better part of Saturday to get "CombatRuna" running again but at least I could test that the physics engine was still operating.
From there, I developed a simple prototype for ultimately testing network physics. It's just a simple top-down view of a world with some rollable objects. WASD controls another little block that can run around and push into these objects (and get pushed back, too)... more on that in a second.
One of the critical features of a networked physics engine for a fully open sandbox world is the ability to partition space into "zones" and reliably, accurately, and most of all, performantly keep track of objects in motion. There could be 10s of thousands of objects in the world but the physics engine only needs to worry about the objects that are in motion and the objects nearby that it might collide with. So the world is divided into zones and collision space partitioned accordingly.
I spent all day Sunday designing this piece from my high level notes. I was hours into one detailed design before completely scrapping it. There is no way that it would ever perform well. The strains of hundreds or thousands of objects being moved 60 times a second and requiring figuring out which zone they are in, notifying interested systems, etc. is a problem trickier than it might at first seem. The second design made it to implementation before I got far enough down in the weeds to know that it would have a completely different set of problems. The third design took a different approach and centralized the problems of the second to a more manageable place and it still took me 4-5 hours of design to feel like I'd tackled the issue in an elegant way.
All of that being said, I now at least have a fully functioning zone management system that has almost 0 overhead. Furthermore, it can be used for both network area of interest reduction (the original problem) and collision space activation (the problem I realized this could solve only after I'd implemented it). The current way I do collision detection relies on the fact that the player is always watching his zone and the zones around him... this is why you can bump into a table that sticks into your zone from the zone next to you. This approach actually wouldn't work for collision with physics objects in motion because it's too expensive to keep 9 zones active just for one little moving object. Anyway, the zone manager solves this problem because objects can be in more than one zone at a time while they straddle the borders. But I digress.
There were also a few ancillary problems I solved along the way (this one I promised to get back to above). Player movement is kind of an interesting one.
In the version of the game that you guys play, your input directly controls the location of the camera and there is sort of a light player-specific physics applied to those inputs. The problem is that it is then completely impossible to have the player affected by the other physical objects around him. Players can't bump into each other but more importantly, a rolling boulder would go right through the player... and most critically to me, you couldn't stand on a moving ship without falling off.
The more immediate problem was what happens when a player walks into an object that can move. If it doesn't push the player back appropriately then the physics engine easily runs into cases that are impossible to solve (and lead to explosive results). For example, if you slide into a chair and push it against the wall... you can keep pushing into the chair if it's not pushing back and the physics engine doesn't know how to resolve this chair+wall+immovable force problem.
As it turns out, making the player a physical object just like the others is kind of tricky. Instead of setting absolute position and rotation, the player inputs apply accelerations to the player's physical object. I will tell you that moving yourself with just acceleration and trying to get a similar affect to what we have now is not as straight forward as it may seem.
...but at least I was able to get something working. It was very educational, also.
By the time I had that working and a proper zone manager design partially implemented, the holidays were full-on upon me and I had limited time to get back to coding. Still, at this point, I have my simple test app and the zone manager fully implemented.
The next piece will be the actual networking part that packages up the state of a player's zone and sends it to them many times a second. I'm sure this will present its own surprises but I feel like a) I've already implemented the hard part, and b) the network speed test I put out some time back already had some nice compact state transmission code. In this case, it's not as much a matter of making it work but in keeping the packet size down to minimum levels. So hopefully it is more straight-forward than what I've already accomplished.
I wish I had better news than that but some progress is better than no progress. I hope to get the networking prototype finished in the next week or so and then I can put something out for the donators to help me test. After that, it's just a matter of integrating it into the regular engine.