How to batch multiple component updates outside of Tick?

I’m developing a simulation with thousands of NPC actors (that normally aren’t even rendered) with custom game logic.

I think it would be inefficient to do all the logic inside components that get instantiated once for every actor and executed on every tick. Even if I manage to throttle down the execution inside Tick to some reasonable value (once per second, for example), it still doesn’t seem right, and also I cannot leverage any custom parallelism.

So, I thought that it would be great to attempt some kind of Systems -> Components approach.

Essentially, for every custom game logic FooComponent I would have a class called FooSystem.

The FooComponent itself is just a property bag and has almost no logic. It might be connected to rendering and have some light processing in Tick, but still all the heavy lifting will be done in FooSystem.

The FooSystem is running in a separate “game loop” (another thread, most probably with lower priority than the main thread because rendering is more important than game logic latency). It somehow collects all the actors in the scene that have FooComponent and then processes them in batched manner, maybe even leveraging Unreal’s ParallelFor or SSE instructions.

One concern is keeping the list of FooComponent alive and avoiding to query the scene on every iteration. Maybe I could manage this attaching to Actor creation / destroy events? Not sure.

Another concern is thread-safety - how to safely update FooComponent properties (which might be attached to blueprints) from my FooSystem?

How to organize multiple systems - FooSystem, BarSystem - should I run each on a separate thread or it might be an overkill?

And finally, how to correctly integrate it into Unreal project - what class should FooSystem extend (if any) and how should it be started / stopped safely? What about networking? (I know that this game logic will run only on the server side).

Has anyone experience with implementing something like that? Am I reinventing the wheel here?

We use a custom TCP library (not Unreal replication) so we just queue the incoming messages, then read the message queue during GameMode.Tick().

You could do the same thing with your simulation in a separate thread. Actually we use TCP to communicate with a background simulation so it is pretty much what you are doing. :slight_smile: