Skip to content

Streamlining of Entity Component event routing

Choose a tag to compare

@grofit grofit released this 10 May 14:34
· 76 commits to main since this release
7bfb9c6

Entity Component Routing Changes

This release is mainly a refactor around how the internal component changes on entities are handled.

Historically there was quite a lot of layering to the process, you had each entity firing events to indicate that it has had components added/removed etc, then that got passed up to the containing IEntityCollection it was in, then depending on the scenario that would then relay the events onto the IEntityDatabase which would then pass to an IObservableGroupTracker which would decide if the entity needed to be put into or leave a group etc.

The main problems here were that the entity was used as a source of event subscriptions and there was a lot of logic done at the upper layers to work out based on the changes and the components on the entity if it needed to change how it sat in Observable Groups etc,

So as part of the last change we refactored how this worked so there is now an EntityChangeRouter which the Entity notifies directly of changes, then the IObservableGroupTracker implementation (only one of them now) will look at the groups changed, find out what IObservableGroups need to be notified and update them.

This means in the long run the Entity has less responsibility so can be refactored easier, which is something that has been thought about for a long while.

IEntityDatabase removed

Finally for this section this also means there is no longer a need to partition the entities as they used to be done, as the IEntityDatabase was mainly created as a central way to be able to handle multiple IEntityCollections at once, with each one being used as a way to partition entities to reduce event chatter between groups, this did work somewhat but ended up making a large amount of the rest of the infrastructure more complex a you couldnt just have a single IObservableGroup for a group, you had to ensure it was for the specific pools too.

With this being removed it means everything is far more streamlined and we instead just pass around the IEntityCollection which would be the same as the World object in a lot of other ECS systems.

Pooling Changes

Also as part of this we have streamlined some of the pooling mechanisms so there is now an IObjectPool which can be used as a base pool to store long running pooled objects, the ViewPool now uses this, and there is a new EntityPool which allows you to pool entities of a given group type so they can be re-used rather than new ones constantly being needed, which can be very useful for situations where there is a lot of churn in the view layer, but you may want to just keep re-using the same underlying Entity objects and View objects.

There is also a new ComponentDatabaseConfig class that lets you configure how component pools should be initialized and expanded, by default you do not need to worry about this, but as your project grows from tens, to hundreds, to thousands of entities you may want to provide more explicit pooling config so you can allocate more up front and do more with your expansions, as each expansion of pools incurs a large allocation cost to do, so making pools need to expand less often and to larger sizes to fit your needs can yield large benefits, here is an example of that.

image

The image shows a simple scenario where the application starts and 100,000 entities are created and have components added, the top image is pre allocating the required component pool sizes up front to minimize expansions. The middle uses the new defaults which are more meant for hundreds to thousands of entities, not hundreds of thousands but it still allocates less and is faster, then finally the last image is the previous version with its default settings for pooling prior to these changes.

Allocation Improvements

There has also been a small amount of work to improve allocations in various parts of the system. This being said given that EcsR3/Rx uses classes for its entities and components to give you more flexibility, that is always going to mean performance and allocations will never be as low as in ECS frameworks where they are all struct based (you can use structs with EcsR3 though, just most people dont :D )

Anyway as always let us know if you have any problems or notice any oddities, the downstream libs like EcsR3.Unity etc will get updated in time with these new changes.