My team is in a position where we’re trying to figure out whether Unity’s ECS is in a good position for us to start developing on. The game we’re working on has a lot of simulating state and ECS is a really good fit for it. We currently have our version of ECS that’s built on Unity’s Job System and Burst Compiler so I’ve been able to see just how efficient it can run. However we’re lacking features that’s causing me to reevaluate Unity’s ECS before development really starts in earnest.
However going over examples, API lists, and decompiling Unity’s ECS I’m having a hard time answering if Unity ECS has the features that we’ll end up needing in order to deliver on our game. A big wrench that’s thrown is that our game is networked and uses a predicted deterministic lock step networking model (think GGPO but we won’t predict the entire state of the game…similar to how Factorio does it based on their blog posts). We had been working to make our own ECS have easy support for this model but if Unity’s ECS can support it as well then that would save us significant time.
Checksum State
If our game is deterministic then we’ll need a way to detect that we are in sync at least while in development. In some ways ECS makes this easy because it packs state in such a easy to look at way. Would it be easy to checksum whole archetypes? This should also include being able to checksum dynamic buffers as well as a way to custom checksum components that have complex members (like a pointer since that can’t be checksummed by memory). I’m aware of other issues such as padding that can make this tricky but there are ways around that.
Also for sanity sake being able to dump a log of granular checksums so we can have tools to show which components, or even entity, had diverged can help with debugging. Are there sufficient hooks to do this kind of thing in Unity ECS?
Archetype Rollback
We’re not doing full state prediction so some state will predict every frame while others don’t. If in one world then you could imagine there being a Predicting component that specifies certain archetypes as the ones that predict and a predicting system would query to only work on those archetypes. However, once we get the input from other players we need to reset the archetypes that were predicting. I see that there is serialization/deserialization for whole worlds but what about archetypes chunks?
It’s possible instead that we have a predicting and non-predicting worlds instead. But I’ll have to have a clean way to interact between the worlds, for example, EntityCommandBuffer might actually be from arbitrary worlds?
Messaging
This has less to do with our networking model and more of a question of how this would be accomplished in Unity ECS but how does Unity handle messages that sent from one entity to another (or one system that targets another entity). An example might be a system that explodes and damages entities. You could imagine this system gathers up a bunch of entities within radius of the exploding entity and registers damage to those entities. You could imagine it could do this by adding a component to the damaged entities with the damage amount. But what if two exploding entities overlap an entity, wouldn’t we lose one?
Split Up World Into Chunks
Our world will be big enough that we won’t want to simulate the entire thing constantly and can sleep chunks if the players are far enough away. As far as I can immediately tell there are two ways I could try to approach this.
-
Split entities into separate worlds based on their location. Then I could only update the worlds that are ‘awake’. I’ll need a way of wholesale moving entities from one world to another when they move from one chunk to another.
-
Have dynamic tags. I could tag entities with a chunk index for example which would put them into specific archetypes and only run the archetypes that are currently ‘awake’. If tags have to be typed structs though then I’m not sure how I see how I would do this in Unity ECS. Filter based on a shared component maybe?
Unsafe Component Writes
We had to build our own collision system to ensure determinism. This collision system currently runs in its own ‘physics’ world and after it runs it’ll run a sync system that takes its physics position and syncs it to the game simulation system. We do this unsafely by writing directly to the component memory in our own ECS system. This is safe to do because there’s only ever a 1 to 1 relationship between physics entity and simulation entity and won’t be subject to the lost update problem. I can’t immediately find a way that we would do this with Unity ECS. I understand this is ‘risky’ behavior but is there a way to do this?
Save/Load Versioning
It looks like this is supported when looking at the APIs but they aren’t fully fleshed out so I would want to confirm that deserialization/serialization of worlds can work across build versions. What if a components has a member added, removed, or rearranged? Assuming it’s a memory serialization then I imagine this would have issues otherwise.
Update
This one looks supported but wanted to bring it up as it is essential to our model but we have to control the update function tightly. We’ll have to pause it when there aren’t any inputs and step it forward arbitrary amount of times based on the number prediction steps.
Any guidance here would be awesome I’m excited and hopeful the Unity ECS is a good path forward as not reimplementing even a small part of the features would be an amazing time saver!