As I’ve alluded to in previous updates, the damage system is still a way off from completion, so that’s what I’ve been working towards over the last month or so. One challenge is to design a system to propagate and accumulate damage in a way that is, if not realistic, at least plausible, as well as making sense to the player (without being frustrating or annoying).
Before I can get to this though, there is a more fundamental problem. Breaking parts off a construction due to damage requires efficient construction modification code, and the existing system just isn’t fast enough.
The first problem I looked at was with the construction list in the world tool UI. Whenever a construction is created or destroyed, this list in the world tool UI gets updated accordingly. When a part gets broken off a construction, it’s re-parented under its own new construction GameObject, and this process was getting slowed down by the world tool UI being updated.
So now the UI elements in this construction list are held in a pre-allocated pool and used / reused as needed, which avoids the performance cost and GC alloc of instantiation when a new entry is added. Also, the UI update code now queues up any new constructions and only adds one element to the UI per frame, this results in a slight visible delay as the player sees the UI updating itself, but avoids a single frame performance spike. In fact I made these changes to all other UI screens too that have a large list of entries (for example, the saved game screens).
Construction modification code optimisations
I’ve now also optimised the construction modification code (actually I had to completely restructure it) to be simpler and more efficient. It now uses fewer server-to-client RPC calls, only one per player operation (operations being things like attaching a part, deleting an attachment, etc.) There are less GC allocs too, as it now reuses many of the temporary data buffers these operations require.
These changes so far have made a big difference. I hacked in a key so I can trigger the deletion of all attachments in a construction for testing purposes, as you can see in the example below. In this example the cost of breaking the attachments went from around 60ms to less than 25ms on my machine, still a significant performance spike, but definitely moving in the right direction.
The major remaining performance cost is with instantiating new construction GameObjects, and also the Rigidbody GameObjects that live under them (as I mentioned before, parts get re-parented to these when they’re broken off an existing construction). So, just like with the UI elements, to solve this I’m going to need pre-allocated pools of these GameObjects. However before I do this, to make life simpler, I need to remove all references to Unity networking stuff from the constructions. Which brings me to another issue…
Unity networking API woes
GearBlocks is still using the old RakNet based Unity networking API, which has been deprecated for a while (and now completely removed from Unity 2018.2). I was waiting for Unity’s replacement for it – UNET, to be a bit more mature before I switched to it, but sadly UNET has now also been deprecated. Apparently there’s another replacement solution coming at some point
in the future. Anyway, I guess it’s a good thing I never switched to UNET, it will be supported for another couple of years I believe, but there doesn’t seem much point using it now. So the upshot is, I’m probably going to have to look for a third party solution.
Whatever networking solution I end up using, one thing is for sure, I really need to abstract the networking API away from the rest of the GearBlocks code as much possible. This is something I should have done in the first place really, it’ll make changing networking APIs much easier in the future.
So to allow for pooled construction GameObjects, and as a first step towards this abstraction, I’ve now implemented my own world object ID system. This allows GameObjects to have a unique ID consistent across the server and all the clients, and is now used by construction and part GameObjects. This allowed me to remove the Unity NetworkView from the construction GameObject (which will make pooling them easier), and move all code for state synchronisation out of the construction and into a central manager that synchronises the state of all constructions together.
The next step in this abstraction effort will be to wrap all the RPC calls (currently scattered throughout the code) behind another interface. As well as meaning there will then only be one place in the code to modify when I change networking APIs, it will also allow me to remove the NetworkView from part GameObjects too.
Explosives go boom
My future plans for GearBlocks mean that the damage system needs to apply damage not only from collision impacts, but also from explosives. So I had some fun adding a simple placeholder explosive that’ll serve as a good test for now. Right now it only applies a force to nearby objects, it doesn’t do any damage yet, that’s something I’ll have to work on soon!