Multithreading Gameplay Logic (Part1)
/So I've been racking my brain about the best way to implement multithreaded gameplay logic, and I've come to two main solutions. The first solution is a message based approach in which entities, and components, can update their own logic, but must pass messages to other entities/components to update their state. A few examples of this are in (1), (2), (3). The second approach, the one which I will be discussing today , relies on an entity component system methodology to multithreading.
My ECS updating strategy is split between "components" and "service providers". An example of a component is a skeletalmeshcomponent , which handles animating skinned meshes, and an input component, which handles dispatching input events. The responsibility of a "service provider" is to determine the data access policy and the updating logic of a specific component type.
Example of a Skeletal Mesh Component and it's relevant services provider.
The services provider interface contains three functions; "GetRequiredServices" , "ModifyTickEnvironment", and "Tick". The first function's responsibility is to determine the types of data that will be accessed during a tick phase. For example, a PlayerControllerComponent's responsibility is to update the player's pawn from given input, so the services provider will state that it requires the CInputComponent's service provider to updated first. The second function states which tick phase the services provider supports, i.e pre-physics , post-physics,...etc. The last function handles gameplay logic.
Example of GetRequiredServices for ai controller and player controller component
Example of modify tick environment for skeletal mesh components
Example for tick logic for skeletal mesh components.
So now onto the pros and cons of this approach.
Pros
1) Makes asynchronous processing ridiculously simple.
2) Data access patterns are explicit
3) Batched processing gives room for Data Oriented optimizations
Cons
1) Incapable of handling update order on a per entity basis (i.e parent and child)
2) Increased number of sync points (between each component type) reduce chances of full CPU optimization.
It's difficult for me to determine if the pros outweigh the cons of this approach. It seems that most game engines (openly sourced) ignore the importance of updating parent entities prior to their children. While unreal engine handles it and Jason Gregory explains the importance of the approach , a simple google search will show that many have issues with Unity choosing to ignore execution order. For now , I believe that I will be keeping this on the backburner until I learn how other's handle this glaring issue with the ECS approach.