Apologies if this has been answered elsewhere, my searching is failing me. I’m attempting to move blueprint code into native and, as part of that, I need to take existing components added in blueprints and create their equivalent UPROPERTY variables in the native class. The c++ header tool creates the exact definition it’s currently using, but simply putting that in the c++ class results in the kismet compiler creating duplicates, rather than fixing up existing references like it does with non-component variables that match exactly.
What is the intended way of achieving this? We need this performed on a large scale and so hand-copying all component modifications is an infeasible amount of effort. If this is not implemented by the engine, is there a way we can automate fixing up the references (and avoid creating duplicates) so that those components will no longer be exclusive to the blueprints?
(Side note: this question isn’t 5.6 specific, but EPS asks for a version and that’s the one we’re on currently.)
Unfortunately, even if you give components the same name, the engine sees them as different components.
I’ve found a couple discussions that have some ideas for moving blueprint components to C++. That being said, they all have duplicates that need to be deleted.
Discussion 1: Ideas of moving bp components to cpp such as implementation inheritance.
Discussion 2: Mentions needing to do it manually, but as a workaround would be to keep the components in bp and instead of moving them entirely, we get references to them and use those references in cpp. The references can be found through things like FindComponentByClass. (Here’s a video on that)
Discussion 3: Same name (Move Blueprint actor components to C++ w/o losing reference) as discussion 2, but on reddit had a slightly different approach where they still manually create the component in cpp with CreateDefaultSubobject but use +PropertyRedirects in the DefaultEngine.ini to ensure all references to the old component are pointing to the new cpp class.
I’d say there is no intended way that preserves references without duplicates. The reference in discussion 1 with implementation inheritance would most likely be the closest, but that still has the step of deleting the bp component class.
My recommendation to make it so that those components will no longer be exclusive to the blueprints would be to use something like FindComponentByClass as mentioned in the tutorial video.
Thanks for the references. I took some time to review them, but I think they aren’t quite what our scenario requires.
To clarify: we have components with native component classes added in a BP subclass of a native actor class. The desire is to have that exact component use CreateDefaultSubobject in the native constructor (for performance reasons, in addition to simply being more convenient to access in other c++ code). For example: suppose there is a UNiagaraComponent that a VFX artist added to BlueprintA which is derived from ANativeClassA derived from AActor. This UNiagaraComponent would then have it’s properties overridden in each of the child blueprints (BlueprintA_Child1, BlueprintA_Child2, etc.). We would want ANativeClassA to construct that exact same component in it’s constructor, without us having to redo the properties on BlueprintA_Child1, BlueprintA_Child2, etc. by hand.
If I understand correctly, Discussion 1 and 2 are solving a different problem.
Discussion 3 sounds halfway there, as this provide us with an avenue to construct an equivalent component in c++ and fixup references in the blueprint, however the component’s data is not copied to the native component and as such any overrides in all derived blueprint classes are lost. If there was a method we could use to migrate the data over, that would be a viable solution for us.
(Side note: I will be OOO until Dec 1 in case EPS automatically closes this. In that event, I’ll reopen when I’m back in-office.)
You would need to setup something to copy over the data from the old BP component to the c++ component due to the engine seeing it as a new component.
An example would be to copy the data of the old BP component on PostLoad of the new c++ component and once it’s copied you’d delete the extra BP component.
There is also this function; UEngine::CopyPropertiesForUnrelatedObjects that you can use to attempt to copy as many properties as possible from the old object to the new one.
For your convenience here’s some references for scripting related discussions
Hmm, it appears that CopyPropertiesForUnrelatedObjects expects actors, even though the parameters are UObject*, so it doesn’t do anything for the components. Is there something similar that would work to copy components’ properties?
Edit: scratch that, I think I’m following this logic incorrectly and components should be valid. That said, it seems to not actually copy the component properties as I would expect regardless.
Ah, perhaps it’s only valid to call it in PostLoad. I attempted to call it afterwards in PreInitializeComponents since I hit the check in UObject::ProcessEvent due to trying to get a reference to the blueprint component via a BlueprintImplementableEvent. Is there a way I can reference that BP component safely in PostLoad?
Another update: I also attempted to get the component in PostLoad via USubobjectDataSubsystem::Get()->GatherSubobjectData(Blueprint->GeneratedClass->GetDefaultObject(), Handles), but the components don’t have their blueprint-assigned values populated at this point.
Ah, actually, perhaps the values are there in time (since it looks like the `Asset` value is copied on a UNiagaraComponent I moved to c++) and I’m just encountering this bug where user parameters from c++ components don’t show in the editor: [Content removed]
Stepping in for John as I was chatting with some colleagues about this issue, and wanted to send over their thoughts on the matter!
They’re going to have to write some code up to perform this migration, probably external to the class. Native classes are loaded before BP classes, so PostLoad won’t work for this. It’ll have to be a separate script they can trigger in editor after the engine’s fully initialized and all of those classes are loaded. I’d add the component to the native base class with CreateDefaultSubobject and then script the transition as follows:
Cast the object in the `FAssetData` to a `UBlueprintGeneratedClass*`
Loop through the `USCS_Node` array returned by the BP generated class’s `SimpleConstructionScript->GetAllNodes()`, filtering for the native component class you’re looking for by checking if the node’s `ComponentClass` field matches or is a child of the component class you’re looking for
If you have a match, call `GetActualComponentTemplate()` on the node. Cast that to your native class and you’ll have the BP-added component’s CDO with its properties filled out.
Copy the properties from that to the component you added to the native base class. Make sure to dirty and save the asset.
The issue you sent over should be resolved by 5.6, I see the last reply mention further tests on 5.2 and main failed to reproduce the issue, so not sure if that’s the same bug?
Thanks, yeah I’m not sure it’s the same exact bug, but the symptoms seem to be the same either way. The User Parameters on the NiagaraComponent I was testing with fail to show on the c++ component even with `UPROPERTY(BlueprintReadWrite, EditAnywhere, Instanced, Category=“Default”, meta = (AllowPrivateAccess = true))`.
That said, I’m fairly sure the data is actually there to be copied, it was just this issue with the User Parameters that made me think it was incomplete. I’ll see if I can find other cases of natively added UNiagaraComponents to see if that’s true everywhere or if it’s something unique to this scenario.
I wanted to check-in to see if the information from our colleagues helped out, or if you had any additional information regarding the UNiagaraComponents.
Yes, I was able to use the USubobjectDataSubsystem to GatherSubobjectData from the UBlueprintGeneratedClass’ CDO which allowed me to iterate over the components and copy their blueprint values.
The one missing piece for us to be able to use this is the fact that NiagaraComponents added in c++ don’t have their User Parameters editable in the details panel, so even though we can copy this information, we lose the ability to modify it later if we nativize them.
I see in UNiagaraComponent::SynchronizeWithSourceSystem that the C++ component has the expected user parameters, but so far I have not found what’s preventing them from showing in the editor. I initially suspected it may have something to do with BP-added components having PostLoad called when the blueprint was opened (whereas the natively-added components call PostLoad at engine startup) since the UNiagaraComponent::PostLoad calls UNiagaraComponent::SynchronizeWithSourceSystem, but further investigation is making me doubt that’s the core issue.
As for the missing piece I did find this discussion mentioning that it seems to be happening for some users, but not others and things they have tried. If you are able to right-click and copy the User Parameters and they are there as the original poster of the discussion mentioned, it most likely isn’t an issue with PostLoad as you said, but I’ll double check with my colleagues to see what they think.
You could check out one user’s example project from that discussion to see if their user params show up in the bp for you since it didn’t show up for some users.
Please let me know if the discussion resolves anything for you, thank you!
Thanks for the additional info. We’re able to reproduce this issue with the User Parameters not showing for native components even in the latest engine release. This appears to be a bug in the engine’s detail customization for niagara components, so I’ve created a bug report for this. That report can be tracked here if/when it’s approved for public visibility: Unreal Engine Issues and Bug Tracker (UE\-361556)
There is no ETA as priorities for bugs and features can shift at any time. We don’t provide updates on EPS, but progress can be followed on that public issue tracker page. I’ll close this case, but feel free to respond here if you have follow-up questions.
Sorry for the delay, I was OOO for several weeks there.
It appears that the data is still present as I can right click -> copy the User Parameters and get data. However, pasting new data there is never saved, which means that we would be unable to actually modify them if we were to perform the nativization. Likely whatever is preventing them from showing is also preventing it from serializing the data.