Currently, as far as I know, there’s not a clean way to initialize an component that is added to an entity through GenerateAuthoringComponent.
The best solution at the moment is to create a MonoBehaviour that implements IConvertGameObjectToEntity. The downside of this is obvious: It’s another class to maintain, doesn’t follow the ease of use utility GenerateAuthoringComponent was designed for, and creates a point of failure via maintenance.
Another solution is to create a Component Tag that is something like “NeedsToInitialize”, but the downsides of this is that it needs to be searched every frame for every specific type, needs to have a specific tag for specific types, needs to be managed to be called before the actual Component, needs to be removed which causes a chunk move, and is another point of failure.
A third solution is to create a flag value in the Component struct that something like Initialized = false, that is processed on the first few lines of the System. The downside of this is that even if the ForEach didn’t need the component that has the value, it needs it now - forever. Many init flags require one for each type, which gets passed around pointlessly later. Also, it introduces a branch when many of us are working hard to avoid “if” and “switch” statements in our ECS Systems. Again, also needs to be checked for every Component of that system, every frame.
Why?
An example of this need, is a Component that needs to cache the previous position of the Entity for something like motion vectors. The first run of the System, if the cached previous position is (0,0,0), but the object was at a different position it invalidates the first pass of the system and leads to unexpected behavior.
My recommendation is to either add more markup for attributes (such as [InitializeFrom], or an interface that replaces GenerateAuthoringComponent that serves the same purpose on the Component struct.
Interface:
Through an interface, we could have standard function calls such as Convert (with a reference to the GameObject) but also editor specific ones such as DrawEditorPanel, etc. If these interface methods were given permission to access referenced memory, then developers could add whatever init logic they needed. They would also be called only once: When the Entity was created as part of the Runtime > World conversion.
Ex:
Convert(GameObject gameObj, Entity entity, EntityManager dstManager, GameObjectConversionSystem cs)
Markup:
The markup option, may be more limited due to it’s nature, it would be easier for developers to implement common cases such as reading from Transform or in more advanced cases, from a static class is delegated to handle the logic.
Ex:
struct MyComponent {
[InitializeFrom( typeof(Transform), "position" )]
float3 InitialPosition;
[InitializeFrom( typeof(MySingleton), "GetPlayerPosition" )]
float3 PlayerOriginalPosition;
}```