Hello!
I have a question about the UAbilitySystemInterface and why it cannot be implemented in blueprint. I’m wondering why this was done and if you have thoughts on removing it? I noticed when working with GAS in BP, the GetAbilitySystemComponent node calls the static library function which then either goes through the UAbilitySystemInterface or does a find component. Is this so that there is one unique call to get the ASC?
Mostly looking for info, and see if it would be against GAS to make that interface accessible to BP
Hey Darien, I’ll confirm with the team but here are my thoughts for now.
IAbilitySystemInterface mainly serves as an optimization so that an actor’s ASC can be retrieved quickly rather than the fallback method in UAbilitySystemGlobals::GetAbilitySystemComponentFromActor that calls Actor->FindComponentByClass<UAbilitySystemComponent>(). Since performance is the main goal there, I suspect the interface and that function are kept as C++ only because:
- Turning it into a UFUNCTION(BlueprintNativeEvent) introduces some runtime overhead when calling it. Compare how an interface would be called:
UAbilitySystemComponent* ASC = IMyInterface::Execute_GetAbilitySystemComponent(this);
and the resulting callstack:
UnrealEditor-AbilitiesLab.dll!AAbilitiesLabCharacter::GetAbilitySystemComponent_Implementation() Line 172 C++ UnrealEditor-AbilitiesLab.dll!IMyInterface::execGetAbilitySystemComponent(UObject * Context, FFrame & Stack, void * const Z_Param__Result) Line 162 C++ UnrealEditor-CoreUObject.dll!UFunction::Invoke(UObject * Obj, FFrame & Stack, void * const Z_Param__Result) Line 7192 C++ UnrealEditor-CoreUObject.dll!UObject::ProcessEvent(UFunction * Function, void * Parms) Line 2175 C++ UnrealEditor-Engine.dll!AActor::ProcessEvent(UFunction * Function, void * Parameters) Line 1160 C++ UnrealEditor-AbilitiesLab.dll!IMyInterface::Execute_GetAbilitySystemComponent(const UObject * O) Line 127 C++
* That runtime cost, combined with our impression that you will define AbilitySystemComponents in C++ as default subobjects most of the time. So we don’t want to increase the runtime cost for those cases or introduce a second interface function.
I’ll collect more opinions from the team though and will update you.
“Mostly looking for info, and see if it would be against GAS to make that interface accessible to BP”
If you want to change this in the engine, I see no problem with making that change locally (turning the function into UFUNCTION(BlueprintNativeEvent). However, then you will also have to:
- All places where IAbilitySystemInterface::GetAbilitySystemComponent() is called, replace that with IAbilitySystemInterface::Execute_GetAbilitySystemComponent(Object).
- All C++ actors that implement IAbilitySystemInterface should override GetAbilitySystemComponent_Implementation() rather than GetAbilitySystemComponent().
And unless/until we make those same changes in the engine code, you’ll have more changes to maintain when upgrading the engine source.
Zhi’s answer is correct, but to add more context as the person who made this change originally:
Blueprint-implemented native events are fairly slow. The way they work is described in the full interfaces documentation, but essentially it auto-generates a static function that works similarly to how GetAbilitySystemComponentFromActor does. So if you changed GetAbilitySystemComponent to a Native Event it would basically double the cost for no benefit.
There’s also no need for the native event to exist in the first place because GetAbilitySystemComponent on UAbilitySystemBlueprintLibrary is callable from blueprint and will get you the actor’s component if you only have one. Nothing should be using IAbilitySystemInterface directly (although I do see one call in an experimental plugin that I will look to fix), it’s only meant to be used by that one function as an optimization. We can make that more clear in the comments
Hello Ben (And Zhi)!
Thank you for following up with the detailed breakdown. Totally understand the intent now and it clears up the concerns we had. I was mainly unsure if having it be blueprint accessible would be faster than cases where a FindComponent would be necessary. But it seems like that’s not the case. So with that, I’ll keep things as they are. Appreciate the support!
Kind regards,
Darien Caron