AttributeSet fail to call GetOwningAbilitySystemComponent()

I have two AttributeSet, one for the player class and another for enemy currently. Each AttributeSet has the Health attribute. I also use PostGameplayEffectExecute() to limit the scope of Health attribute in both AttributeSet. However, the player AttributeSet calling PostGameplayEffectExecute() succeeded, the enemy AttributeSet failed.
When playing the level in Engine, I get an error in the output log:

LogOutputDevice: Error: === Handled ensure: ===
LogOutputDevice: Error: Ensure condition failed: AbilityComp [File:E:\Unreal Projects\LostVisage\Source\LostVisage\EnemyAttributeSet.h] [Line: 31]
LogOutputDevice: Error: Stack: 
LogOutputDevice: Error: [Callstack] 0x00007ffb062c84e8 UE4Editor-LostVisage-0007.dll!<lambda_aa91740606708f06f8509233f5471518>::operator()() [E:\Unreal Projects\LostVisage\Source\LostVisage\EnemyAttributeSet.h:31]
LogOutputDevice: Error: [Callstack] 0x00007ffb062b6721 UE4Editor-LostVisage-0007.dll!UEnemyAttributeSet::PostGameplayEffectExecute() [E:\Unreal Projects\LostVisage\Source\LostVisage\EnemyAttributeSet.cpp:39]

According to the message, I found the macro ATTRIBUTE_ACCESSORS() implements a set function, which calls GetOwningAbilitySystemComponent() and ensure():

	FORCEINLINE void SetHealth(float NewVal)
	{
		UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
		if (ensure(AbilityComp))
		{
			AbilityComp->SetNumericAttributeBase(GetHealthAttribute(), NewVal);
		};
	}

Obviously, this code caused the bug. I have no idea why enemy AttributeSet can’t call GetOwningAbilitySystemComponent() successfully.

here is the my implements of GetOwningAbilitySystemComponent(), two AttributeSet have the same implements:

void UEnemyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
	Super::PostGameplayEffectExecute(Data);

	UE_LOG(LogTemp, Warning, TEXT("Enter PostGameplayEffectExecute"));

	if (Data.EvaluatedData.Attribute == GetHealthAttribute())
	{
		SetHealth(FMath::Clamp(GetHealth(), 0.0f, 100.0f));
		UE_LOG(LogTemp, Warning, TEXT("Enter EvaluatedData"));
		UE_LOG(LogTemp, Warning, TEXT("Health before: %f"), GetHealth());
		//SetHealth(0.0f);
		UE_LOG(LogTemp, Warning, TEXT("Health after: %f"), GetHealth());

	}
}

And the melee attack ability to call this:

Thank you so much for your attention!

OK, the reason I found is simply because my enemy class does not inherit IAbilitySystemInterface. The source code here:

    /** Helping function to avoid having to manually cast */
    UAbilitySystemComponent* UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(const AActor* Actor, bool LookForComponent)
    {
    	if (Actor == nullptr)
    	{
    		return nullptr;
    	}
    
    	const IAbilitySystemInterface* ASI = Cast<IAbilitySystemInterface>(Actor);
    	if (ASI)
    	{
    		return ASI->GetAbilitySystemComponent();
    	}
    
    	if (LookForComponent)
    	{
    		/** This is slow and not desirable */
    		ABILITY_LOG(Warning, TEXT("GetAbilitySystemComponentFromActor called on %s that is not IAbilitySystemInterface. This slow!"), *Actor->GetName());
    
    		return Actor->FindComponentByClass<UAbilitySystemComponent>();
    	}
    
    	return nullptr;
    }
2 Likes