Allows you to retrieve actor component configuration and data from a Blueprint Generated Class, similar to the Class Default Object for C++ Classes. There are optional optimizations for filtering by name, and for returning multiple components.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
| const UActorComponent* UMyFunctionLibrary::GetClassComponentTemplate(FName& FoundComponentName, const TSubclassOf<AActor> ActorClass, const TSubclassOf<UActorComponent> ComponentClass, const FName ComponentName /*= NAME_None*/)
{
if (IsValid(ActorClass) && IsValid(ComponentClass))
{
UBlueprintGeneratedClass* CurrentBPClass = Cast<UBlueprintGeneratedClass>(ActorClass);
while (CurrentBPClass)
{
// Not all BP's have an SCS (apparently)
if (CurrentBPClass->SimpleConstructionScript)
{
if (ComponentName != NAME_None)
{
// Find Matching Node
const USCS_Node* FoundNode = CurrentBPClass->SimpleConstructionScript->FindSCSNode(ComponentName);
if (FoundNode && FoundNode->ComponentClass->IsChildOf(ComponentClass))
{
if (const UActorComponent* FoundComponent = FoundNode->GetActualComponentTemplate(CurrentBPClass))
{
FoundComponentName = ComponentName;
return FoundComponent;
}
}
}
else
{
// No specified name, just return first component class that matches.
const TArray<USCS_Node*>& AllSCSNodes = CurrentBPClass->SimpleConstructionScript->GetAllNodes();
for (const USCS_Node* NodeItr : AllSCSNodes)
{
if (NodeItr->ComponentClass->IsChildOf(ComponentClass))
{
FoundComponentName = NodeItr->GetVariableName();
return NodeItr->GetActualComponentTemplate(CurrentBPClass);
}
}
}
}
// Didn't find an explicit entry in this class, check inherited component overrides.
if (UInheritableComponentHandler* Handler = CurrentBPClass->GetInheritableComponentHandler(false))
{
if (ComponentName != NAME_None)
{
const FComponentKey FoundKey = Handler->FindKey(ComponentName);
if (FoundKey.IsValid())
{
if (const UActorComponent* FoundComponent = Handler->GetOverridenComponentTemplate(FoundKey))
{
FoundComponentName = ComponentName;
return FoundComponent;
}
}
}
else
{
TArray<FComponentOverrideRecord>::TIterator InheritedComponentItr = Handler->CreateRecordIterator();
for (InheritedComponentItr; InheritedComponentItr; ++InheritedComponentItr)
{
const FComponentOverrideRecord& Record = *InheritedComponentItr;
if (Record.ComponentClass->IsChildOf(ComponentClass) && Record.ComponentTemplate)
{
FoundComponentName = Record.ComponentKey.GetSCSVariableName();
return Record.ComponentTemplate;
}
}
}
}
// Wasn't found in this class or it's inherited vars. Check the Super BP Class
CurrentBPClass = Cast<UBlueprintGeneratedClass>(CurrentBPClass->GetSuperClass());
}
// If we get this far, didn't find a Blueprint template. Get the component properties from the native CDO if possible.
if (const AActor* CDO = ActorClass.GetDefaultObject())
{
if (ComponentName == NAME_None)
{
if (const UActorComponent* FoundComponent = CDO->FindComponentByClass(ComponentClass))
{
FoundComponentName = ComponentName;
return FoundComponent;
}
}
else
{
for (const UActorComponent* ComponentItr : CDO->GetComponents())
{
if (ComponentItr->GetFName() == ComponentName && ComponentItr->GetClass()->IsChildOf(ComponentClass))
{
FoundComponentName = ComponentItr->GetFName();
return ComponentItr;
}
return nullptr;
}
}
}
}
FoundComponentName = NAME_None;
return nullptr;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
| TArray<UActorComponent*> UST_CoreStatics::GetClassComponentTemplates(TArray<FName>& FoundComponentNames, const TSubclassOf<AActor> ActorClass, const TSubclassOf<UActorComponent> ComponentClass)
{
/* Use a Map to avoid reinsertion of the same overridden template in a parent */
TMap<FName, UActorComponent*> ComponentMap = {};
// Check Classes
if (IsValid(ActorClass) && IsValid(ComponentClass))
{
// Insert Native Components First
if (const AActor* CDO = ActorClass.GetDefaultObject())
{
for (UActorComponent* ComponentItr : CDO->GetComponents())
{
if (ComponentItr->GetClass()->IsChildOf(ComponentClass))
{
ComponentMap.Emplace(ComponentItr->GetFName(), ComponentItr);
}
}
}
// Now find Blueprint Components and/or overrides
UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(ActorClass);
if (BPClass)
{
// Move to the Top-Most BP Class, then move downards
TArray<UBlueprintGeneratedClass*, TInlineAllocator<4>> GeneratedClasses;
while (BPClass)
{
GeneratedClasses.Emplace(BPClass);
BPClass = Cast<UBlueprintGeneratedClass>(BPClass->GetSuperClass());
}
// Now go from top-most parent to lowest descendant, checking for overrides on the way
for (int32 Idx = GeneratedClasses.Num() - 1; Idx >= 0; Idx--)
{
// Not all BP's have an SCS (apparently)
UBlueprintGeneratedClass* CurrentBPClass = Cast<UBlueprintGeneratedClass>(ActorClass);
if (CurrentBPClass->SimpleConstructionScript)
{
// No specified name, just return first component class that matches.
const TArray<USCS_Node*>& AllSCSNodes = CurrentBPClass->SimpleConstructionScript->GetAllNodes();
for (const USCS_Node* NodeItr : AllSCSNodes)
{
if (NodeItr->ComponentClass->IsChildOf(ComponentClass))
{
ComponentMap.FindOrAdd(NodeItr->GetVariableName(), NodeItr->GetActualComponentTemplate(CurrentBPClass));
}
}
}
// Search Inherited Components
if (UInheritableComponentHandler* Handler = CurrentBPClass->GetInheritableComponentHandler())
{
TArray<FComponentOverrideRecord>::TIterator InheritedComponentItr = Handler->CreateRecordIterator();
for (InheritedComponentItr; InheritedComponentItr; ++InheritedComponentItr)
{
const FComponentOverrideRecord& Record = *InheritedComponentItr;
if (Record.ComponentClass->IsChildOf(ComponentClass) && Record.ComponentTemplate)
{
ComponentMap.FindOrAdd(Record.ComponentKey.GetSCSVariableName(), Record.ComponentTemplate);
}
}
}
}
}
}
ComponentMap.GenerateKeyArray(FoundComponentNames);
TArray<UActorComponent*> ReturnVal = {};
ComponentMap.GenerateValueArray(ReturnVal);
return ReturnVal;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| /*
* Gets the template component on the actor class with the given component class.
* Supports Blueprint Classes
*
* @param ActorClass - The Actor Blueprint/Native Class
* @param ComponentClass - The expected type of actor component.
* @param ComponentName - If specified, makes the search faster and only includes components with the given name.
*/
UFUNCTION(BlueprintCallable, Category = "Helpers", meta = (DeterminesOutputType = "ComponentClass"))
static const UActorComponent* GetClassComponentTemplate(FName& FoundComponentName, const TSubclassOf<AActor> ActorClass, const TSubclassOf<UActorComponent> ComponentClass, const FName ComponentName = NAME_None);
/*
* Gets all template components on the actor class with the given component class.
* Supports Blueprint Classes
*
* @param ActorClass - The Actor Blueprint/Native Class
* @param ComponentClass - The expected type of actor component.
*/
UFUNCTION(BlueprintCallable, Category = "Helpers", meta = (DeterminesOutputType = "ComponentClass"))
static TArray<UActorComponent*> GetClassComponentTemplates(TArray<FName>& FoundComponentNames, const TSubclassOf<AActor> ActorClass, const TSubclassOf<UActorComponent> ComponentClass);
|