Component registration
“Note that we need this initialization happen even in editor without turning on the game mode.”
Keep in mind that initializing components is a runtime task, so AActor::InitializeComponents(), AActor::PostInitializeComponents, and UActorComponent::InitializeComponent() don’t get called until you start the game. They do run before the actor’s BeginPlay.
If you want to run logic also in the editor without starting play, consider looking at component registration instead. AActor::IncrementalRegisterComponents takes care of component registration. It’s called incremental, because in some contexts, like level streaming, the workload is spread over multiple ticks. Though in other contexts like in the editor, it will force all components to register immediately.
Engine modifications
Unless you’re absolutely avoiding any engine modifications, I would recommend simply modifying the engine to impose an order on how components are registered, instead of bending over backwards. We have been reluctant to make more AActor functions virtual, because of the vtable lookup cost, but it has resulted in rigidity in some places where it makes sense that studios want to customize behavior.
Sorting components before register / initialize
In AActor::IncrementalRegisterComponents, the following lines grab the components from a TSet into a TArray:
TInlineComponentArray<UActorComponent*> Components;
GetComponents(Components);
If you modify the function to sort the array here, it would be a straightforward way to enforce ordering. You may want to do the same sorting in other places like AActor::InitializeComponents(), to enforce ordering when initializing too. FHierarchicalLODBuilder::FindMST() is an example in engine code where HeapSort() is used to sort an array via a custom comparison function. That’s where you could check your custom component class’s priority value.
To minimize performance overhead, you might also want to take some extra steps:
- Make the sorting opt-in per actor class, like a bool setting. Only enable the setting for your classes that need it.
- Write an editor validator to catch devs forgetting to turn the setting on for an actor class, when detecting your custom component that has priority
- Normal components that don’t have a priority, don’t sort those. Sorting costs will become expensive if you do it for all actors in the world, so avoid that cost when you can
- Either remove your custom components from the array and place them sorted at the end
- Or better yet, swap the component references in-place. If custom components A, B, C have to be registered in that order, but X, Y, Z don’t. Then ideally you modify IncrementalRegisterComponents so that input array C, B, X, A, Y, Z gets sorted in-place to A, B, X, C, Y, Z. Hopefully, that example makes sense.
That would be my recommendation.
[Attachment Removed]