Hey!👋 ubyte.dev just recently launched. It's dedicated towards Unreal Engine 5.

Features I wish were possible in Unreal Engine 5

August 30, 2022
Lucas Tchikhinachvili
Such as traversing soft class hierarchies while the underlying class is unloaded.

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;
}
cross linkedin facebook pinterest youtube rss twitter instagram facebook-blank rss-blank linkedin-blank pinterest youtube twitter instagram