TScriptInterface and DefaultToSelf (UE 5.0)
Issue UE-97884 already pointed out that the function metadata specifier DefaultToSelf
does not behave as expected with TScriptInteface<>
-based arguments.
This commit fixed that, but only for UK2Node_BaseAsyncTask
nodes!
All other K2Node
types still need to explicitly connect to a Self
node!
The solution would be to always spawn an intermediate Self
node and hook it up to the TScriptInterface<>
pin if has the DefaultToSelf
specifier (somewhere at K2Node::ExpandNode
) during compilation.
An option to accept the 'default' case of KCST_SwitchValue without throwing a script exception + warning log. (UE 5.0)
FBlueprintCompiledStatement* SelectStatement = new FBlueprintCompiledStatement();
SelectStatement->Type = KCST_SwitchValue;
...
Triggering the default case (last RHS term) is currently always considered a non-fatal error. But what if you deliberately want to expose a default case pin?
Think of having a custom Select node that exposes a 'default' pin while not treating it as some kind of error.
Traversing class hierarchies while the class remains unloaded (UE 5.0)
I always intuitively expected this to be possible (since all UCLASS classes are fully reflected anyway), but in hindsight, Game code would never even need this, and getting a parent class pointer from a loaded class instance would be much faster anyway.Â
however, it would still be fun to have!
Here's a possible implementation (assuming FUnrealTypeDefinitionInfo
was public and included inside a Runtime module):
class FDemoClass
{
public:
/** Traverse the inheritance hierarchy of the object referred to by a soft class pointer, loaded or unloaded. */
template <typename Predicate>
static bool TraverseSoftClassHierarchyByPredicate(Predicate Pred, TSoftClassPtr<UObject> SoftClass, bool bIncludeSuper = true);
};
template <typename Predicate>
bool FGameplayLocationStaticsHelpers::TraverseSoftClassHierarchyByPredicate(Predicate Pred, TSoftClassPtr<UObject> SoftClass, bool bIncludeSuper)
{
if (bIncludeSuper)
{
/* Case if the by Class referenced object happened to be loaded in memory */
for (const UClass* ClassItr = SoftClass.Get(); ClassItr; ClassItr = ClassItr->GetSuperClass())
{
if (Invoke(Pred, ClassItr))
{
return true;
}
}
/* Case if the by Class referenced object was unloaded, which is actually assumed */
const FUnrealClassDefinitionInfo* ClassDef = FUnrealClassDefinitionInfo::FindClass(*SoftClass.GetAssetName());
for (; ClassDef; ClassDef = ClassDef->GetSuperClass())
{
if (Invoke(Pred, TSoftClassPtr{ ClassDef->GetPathName() }))
{
return true;
}
}
}
else
{
/* Case if the by Class referenced object happened to be loaded in memory */
if (Invoke(Pred, SoftClass.Get()))
{
return true;
}
/* Case if the by Class referenced object was unloaded, which is actually assumed */
const FUnrealClassDefinitionInfo* ClassDef = FUnrealClassDefinitionInfo::FindClass(*SoftClass.GetAssetName());
if (Invoke(Pred, TSoftClassPtr{ ClassDef->GetPathName() }))
{
return true;
}
}
return false;
}