It appears that CDO OwnedComponents
arrays are not being correctly populated for user created blueprint objects, and any calls made to GetComponents()
on a CDO will return an empty TSet. This breaks the method used to get an object’s default components from the CDO.
Consider the following example code:
void TestCDOGetComponents()
{
for (TActorIterator<AActor> ActorItr(GWorld->GetWorld()); ActorItr; ++ActorItr)
{
AActor* CDOActor = CastChecked<AActor>( ActorItr->GetClass()->GetDefaultObject());
TSet<UActorComponent*> CDOComponents = CDOActor->GetComponents();
UE_LOG(LogTemp, Warning, TEXT("%s"), *CDOActor->GetName());
UE_LOG(LogTemp, Warning, TEXT("%d"), CDOComponents.Num());
for( UActorComponent* Component : CDOComponents)
{
UE_LOG(LogTemp, Warning, TEXT("%s"), *Component->GetName());
}
}
}
This should print the number and name of each of the CDOs associated with every object in the world, however it will only print 0 for each object as CDOActor->GetComponents()
will always return an empty TSet.
This is used in ActorRecording.cpp and appears to be the cause of UE-42309 as the ShouldRemovePredicate
inline class (line 134) will always return true causing SyncedTrackedComponents
to fail to populate the TrackedComponents
array.
Reproduction:
-
Create a blueprint with at least one actor component other than the default scene root,
-
place the blueprint in a blank level,
-
run the function above,
-
note the user created blueprint does not list any owned components.
EDIT: Please note this occurs for non-engine default CDO objects. ie Blueprints the user has mad themselves in editor. Added repro steps.
1 Like
As an aside is this the official channel for bug reporting?
Yes, it is. Sometimes they take a while. Also it might be good to outline the consequences of this bug a bit more.
Do you have a fix already?
I will verify whether this is causing the sequence recording duplication issues and attempt a fix of that.
EDIT: The sequencer bug seems to also appear for actors that are no user created blueprints. So I am not sure whether this is actually root of the issue.
Hi Clayton,
Sorry for the delayed response. I tried to reproduce the issue that you described, but it appeared to be working for me. I may have created my setup a little differently from you, though. This is what I did.
- Created a new code Actor class.
- Added a
UActorComponent
to the class.
- Added the function you supplied to the class.
- Created a Blueprint of the new class in the Editor.
- Placed a few instances of the Blueprint into the level.
- Started PIE.
This resulted in the output from the function in step 3 being output to the log for each instance of the Blueprint in the level. For any object in the level that contained a UActorComponent
, it would show the appropriate number that it contained and the name of each one. Where does my setup differ from yours?
This occurs on blueprint objects created and having components added in the Editor. Components added through c++ seem to work normally.
Thank you for the clarification. I think I can see what you were describing, now. I need to do some additional tests on this, but I don’t think this behavior is correct.
Hi Clayton,
I was able to get some more information about what is going on here. This behavior is currently expected (though it is not the way we would like it to work). What is happening is that any components that are added to a Blueprint in the Editor do not actually exist in the Blueprint’s CDO. They are only instanced on a spawned Actor when the Actor’s construction script is run. Components that are added to the code class the Blueprint is derived from will exist in the Blueprint’s CDO. We would like to have the CDO contain all of a Blueprint’s components, including any added directly to the Blueprint, but that likely will not be done soon.
1 Like
Thanks again for your info and communication on this.
The behavior you have described makes sense, and the actual bug we were hitting due to this has been fixed. I will post here if I find any additional info.
In case you’re still interested in this (and for reference for everybody else), here’s another thread on it, including source code which works around this limitation: How to get a component from a ClassDefaultObject? - Programming & Scripting - Epic Developer Community Forums
2 Likes