Hey again!
“If I understood your recommandation correctly, I tried putting the TArray<TObjectPtr<UBaseVisualDetectionConfig>> directly in my component but it seems to cause the exact same issue. After modifying the parent data, the child blueprints end up with broken datas.”
You understood my recommendation correctly. I didn’t observe this problem when I was experimenting with it myself, but my setup might differ in important ways. Can you provide some more info about how you set things up? Specifically:
- The component class, I assume it’s a C++ class since you mention TArray. Is that right?
- Is the component class added to a C++ actor class (DSO), or is it added via blueprint (SCS)?
- DSO = Default subobject, i.e. created in an actor’s native constructor via CreateDefaultSubobject<UMyActorComponent>()
- SCS = Simple construction script, the system that manages components added in blueprint.
- UBaseVisualDetectionConfig is abstract. Are the subclasses that you’re putting into the component’s array native classes or blueprints?
Those factors are important to reproduce, because components added via blueprint are recreated often in editor (like during actor BP recompile) and objects defined by blueprint classes are recreated all the time (like during BP_MyVisualConfig recompile). I was testing with a native component class, natively added to an actor class AMyActor (so a DSO of the actor), and native UBaseVisualDetectionConfig subclass. The only way blueprint was involved was the data configuration on BP_MyActor and BP_MyActor_Child.
“I’m not sure if it’s the right approach, but we actually have one main actor component (plus others UE ones of course), and this actor component contains logics (called “SubComponents” in our case) created directly by the component in code, depending on the component data’s setup. These SubComponents are not UObjects but simple classes.”
Since your SubComponents are simple classes, created at runtime from the component’s data setup, I’m not worried about that part of the architecture. The main challenge indeed is to find a data setup that gives the flexibility and robust inheritance that your team needs.
“We’ve kept this approach to maintain full control over how the SubComponents are ticked, which one are instantiated and in what order.”
Still, if you would migrate the data + logic of your custom SubComponent classes to separate ActorComponents, that would the workflow that UE’s actor-components is designed and most tested for:
- Any derived BP can add additional components, but not remove them
- Any derived BP can change an inherited component’s class to a specialized class (select component in the BP editor -> ComponentClass).
- Any derived BP can change an inherited component’s property, without it affecting how other properties and other components inherit.
- This avoids the weirdness around array inheritance where in the editor sessions values propagate (per element inheritance), but if children are reloaded without saving, the value may be loaded differently (whole array loading in its old state)
- If components need to set things up in a certain order, then you may get away with using the component’s register/initialize/activate/beginplay functions in specific ways. But you can also modify engine code to change the order that components are iterated for initialization. See [this other [Content removed] case where a studio needed that. I gave some tips there, though they also found their own solution.
- ActorComponents do come with overhead, which is where your approach of lightweight non-UObject classes would save a lot of memory usage, and avoid more garbage collection workload.
In terms of data setup, I would still like to know more about what parts of your setup are C++ vs BP, but I also wanted to make another suggestion: try experimenting with TMaps<FName, TObjectPtr<UBaseVisualDetectionConfig>. Arrays and inheritance get messy once you delete or insert elements, but TMaps are more stable since inheritance happens per key (FName in this case). In other words: it’s clear that whatever object is associated with key “Foo” in the derived BP, inherits from the object with key “Foo” in the parent BP, even when you add/remove entries from the parent. Still, children should not remove entries.
[Attachment Removed]