ECS Design with shared data and managers

This is a general question / conversation about design using ECS and Systems.
This is a new paradigm for me, I’m used to OOP and design patterns, but I’m having problems designing in a correct way.

Not sure how to mix Systems + Data they generate with typical gameobjects and Management classes and calls from the UI / Lua.

So I have a system that generates data out of the entities. Not specifically modifying the components.

I’m not sure if that data should be stored on the system that generates the data or not. I’m currently storing it on a Singleton. But no other system uses that data.

Then I have some queries that ask stuff about that data. Those calls come from the UI or from Lua, outside of the systems, through a general Manager that contains a lot of info and is shared by all systems. Each world contains one of those managers.

Should I call the Manager and the manager would find the system and use the data stored on it? Should it access the singleton instead? It doesn’t have access to the SystemAPI… Or should that data be somewhere else?.

Who’s responsible for cleaning that data singleton?

Seems like I’m building an Engine, but not specifically using the ECS way… But I’m not sure about any of this!

The key point is to keep things data oriented. You want your data to be structured such that systems can process it efficiently in CPU caches.

Recently I made my BallisticsSystem. I use some important GameObject-based packages including Mirror Networking (with custom network culling) and HurricaneVR, so my guns are controlled by MonoBehaviours. Bullets are fired on the server by getting an instance of the BallisticsSystem (using a static instance) and adding data to a list on that system. This occurs in MonoBehaviour.Update(). The BallisticsSystem then runs in the SimulationSystemGroup, which runs immediately after MonoBehaviour.Update(). It processes the data, and when hits are found (immediately or on future frames), it writes data to a singleton component which is processed by EnemyLifeSystem and then by EnemyAnimationSystem.

I only have one sync point in my systems which is at the start of the SimulationSystemGroup, so my systems can run over for a full frame (these don’t need to). Sync points are the biggest thing to watch out for.

With BallisticsSystem, accessing a static instance of the system is probably faster than singleton components, but I’m using both approaches as I learn Unity’s ECS. If using singleton components, you can access them outside of ECS using an EntityQuery, like this:

this.singletonQuery = World.DefaultGameObjectInjectionWorld.EntityManager.CreateEntityQuery(ComponentType.ReadWrite<EnemyCollisionSystemData>());

RefRW<EnemyCollisionSystemData> enemyCollisionSystemData = this.singletonQuery.GetSingletonRW<EnemyCollisionSystemData>();