Gameplay Ability System Magnitude Modifier Calculation in Blueprints

Hi, I am trying to create a new custom Magnitude Modifier Calculation class in Blueprint but every node I try to call it always comes up as a read-only error.
Am I doing something wrong?

I am attaching a basic call that I want to make inside the calculation, but everything comes up with this error.

Any idea?

1 Like

It looks like you’re trying to call it on “Self” where it should be called on the actor that contains the calculation, have you tried referencing that actor?

I thought about that, but apparently it only accepts a Gameplay Mod Magnitude Calculation object, which is exactly self in this case

2023-02-17 10 23 33

I have the same issue, you find out why self isn’t accepted ?

Not really, doesn’t accept anything really. Wondering if it’s a bug or just missing functionality from blueprint

try marking your function as const

it’s in the details panel if you click on the start of the function

it has no detail panel :frowning: I mean it’s there but there no actual stuff in on the function class.

Inside the calculation modifier i tried to use the bool generate const class but still the same error so don’t know what’s up with this

first, make sure your using UE 5.1.1 or above, this might have been broken in previous versions of the engine

if you’re using the current version, then I would go to the Unreal Slackers discord and try to find an expert on this stuff. I looked at the source code and i can’t understand why it’s asking for a target, but i’m kinda new to this stuff

float FAttributeBasedFloat::CalculateMagnitude(const FGameplayEffectSpec& InRelevantSpec) const
{
	const FGameplayEffectAttributeCaptureSpec* CaptureSpec = InRelevantSpec.CapturedRelevantAttributes.FindCaptureSpecByDefinition(BackingAttribute, true);
	checkf(CaptureSpec, TEXT("Attempted to calculate an attribute-based float from spec: %s that did not have the required captured attribute: %s"), 
		*InRelevantSpec.ToSimpleString(), *BackingAttribute.ToSimpleString());

	float AttribValue = 0.f;

	// Base value can be calculated w/o evaluation parameters
	if (AttributeCalculationType == EAttributeBasedFloatCalculationType::AttributeBaseValue)
	{
		CaptureSpec->AttemptCalculateAttributeBaseValue(AttribValue);
	}
	// Set up eval params to handle magnitude or bonus magnitude calculations
	else
	{
		FAggregatorEvaluateParameters EvaluationParameters;
		EvaluationParameters.SourceTags = InRelevantSpec.CapturedSourceTags.GetAggregatedTags();
		EvaluationParameters.TargetTags = InRelevantSpec.CapturedTargetTags.GetAggregatedTags();
		EvaluationParameters.AppliedSourceTagFilter = SourceTagFilter;
		EvaluationParameters.AppliedTargetTagFilter = TargetTagFilter;

		if (AttributeCalculationType == EAttributeBasedFloatCalculationType::AttributeMagnitude)
		{
			CaptureSpec->AttemptCalculateAttributeMagnitude(EvaluationParameters, AttribValue);
		}
		else if (AttributeCalculationType == EAttributeBasedFloatCalculationType::AttributeBonusMagnitude)
		{
			CaptureSpec->AttemptCalculateAttributeBonusMagnitude(EvaluationParameters, AttribValue);
		}
		else if (AttributeCalculationType == EAttributeBasedFloatCalculationType::AttributeMagnitudeEvaluatedUpToChannel)
		{
			const bool bRequestingValidChannel = UAbilitySystemGlobals::Get().IsGameplayModEvaluationChannelValid(FinalChannel);
			ensure(bRequestingValidChannel);
			const EGameplayModEvaluationChannel ChannelToUse = bRequestingValidChannel ? FinalChannel : EGameplayModEvaluationChannel::Channel0;

			CaptureSpec->AttemptCalculateAttributeMagnitudeUpToChannel(EvaluationParameters, ChannelToUse, AttribValue);
		}
	}

	// if a curve table entry is specified, use the attribute value as a lookup into the curve instead of using it directly
	static const FString CalculateMagnitudeContext(TEXT("FAttributeBasedFloat::CalculateMagnitude"));
	if (AttributeCurve.IsValid(CalculateMagnitudeContext))
	{
		AttributeCurve.Eval(AttribValue, &AttribValue, CalculateMagnitudeContext);
	}

	const float SpecLvl = InRelevantSpec.GetLevel();
	FString ContextString = FString::Printf(TEXT("FAttributeBasedFloat::CalculateMagnitude from spec %s"), *InRelevantSpec.ToSimpleString());
	return ((Coefficient.GetValueAtLevel(SpecLvl, &ContextString) * (AttribValue + PreMultiplyAdditiveValue.GetValueAtLevel(SpecLvl, &ContextString))) + PostMultiplyAdditiveValue.GetValueAtLevel(SpecLvl, &ContextString));
}

bool FAttributeBasedFloat::operator==(const FAttributeBasedFloat& Other) const
{
	if (Coefficient != Other.Coefficient ||
		PreMultiplyAdditiveValue != Other.PreMultiplyAdditiveValue ||
		PostMultiplyAdditiveValue != Other.PostMultiplyAdditiveValue ||
		BackingAttribute != Other.BackingAttribute ||
		AttributeCurve != Other.AttributeCurve ||
		AttributeCalculationType != Other.AttributeCalculationType ||
		FinalChannel != Other.FinalChannel)
	{
		return false;
	}
	if (SourceTagFilter.Num() != Other.SourceTagFilter.Num() ||
		!SourceTagFilter.HasAllExact(Other.SourceTagFilter))
	{
		return false;
	}
	if (TargetTagFilter.Num() != Other.TargetTagFilter.Num() ||
		!TargetTagFilter.HasAllExact(Other.TargetTagFilter))
	{
		return false;
	}

	return true;
}

bool FAttributeBasedFloat::operator!=(const FAttributeBasedFloat& Other) const
{
	return !(*this == Other);
}

// --------------------------------------------------------------------------------------------------------------------------------------------------------
//
//	FCustomCalculationBasedFloat
//
// --------------------------------------------------------------------------------------------------------------------------------------------------------

float FCustomCalculationBasedFloat::CalculateMagnitude(const FGameplayEffectSpec& InRelevantSpec) const
{
	const UGameplayModMagnitudeCalculation* CalcCDO = CalculationClassMagnitude->GetDefaultObject<UGameplayModMagnitudeCalculation>();
	check(CalcCDO);

	float CustomBaseValue = CalcCDO->CalculateBaseMagnitude(InRelevantSpec);

	const float SpecLvl = InRelevantSpec.GetLevel();
	FString ContextString = FString::Printf(TEXT("FCustomCalculationBasedFloat::CalculateMagnitude from effect %s"), *CalcCDO->GetName());

	float FinalValue = ((Coefficient.GetValueAtLevel(SpecLvl, &ContextString) * (CustomBaseValue + PreMultiplyAdditiveValue.GetValueAtLevel(SpecLvl, &ContextString))) + PostMultiplyAdditiveValue.GetValueAtLevel(SpecLvl, &ContextString));
	if (FinalLookupCurve.IsValid(ContextString))
	{
		FinalValue = FinalLookupCurve.Eval(FinalValue, ContextString);
	}

	return FinalValue;
}

Thanks, I will check on there and see if I have any luck.
I still don’t get it…

I looked at the c++ classes and nothing points to that self target.
Super odd

since it has “target actor” in the name of the function, i’m guessing it wants to know which actor you want the tags for, and since the function is const, you would have to set a pointer to your Pawn (before this function), and plug that into the target pin

It doesn’t work that way tho. It uses snapshot of the ability event to get Source and Target Values you specify when the effect is triggered. Target and Source info is already present, so target data should be fine to read as well.
Also the error comes up for every node you try to run, not just that the Target Tags, also to get magnitude values and other stuff.

i’m guessing this is supposed to be BlueprintPure instead of BlueprintCallable, but i dont know, the ability stuff is a mystery to me

	UFUNCTION(BlueprintCallable, Category = "Ability|GameplayEffect")
	const FGameplayTagContainer& GetTargetActorTags(const FGameplayEffectSpec& EffectSpec);

you could try to change it and see if it works

Hi, the CalculateBaseMagnitude function you are overriding in your blueprint is a const function. And as far as I know you cannot call a non const function inside it (GetTargetAggregatedTags is not a const function).

But I guess I’m missing something, since I don’t see what those blueprintcallable functions are for if you cannot call them there since they are not const…

Some folks in the Unreal Slackers Discord are saying these functions aren’t currently setup to work properly with Blueprints. Bummer, and I hope the next patch brings them in. Could really use this right now. I’m currently trying to learn how to build my own in C++ and it has been rough.

We ended up creating a custom Mod Magnitude calc class in C++ with those functions working as const, and everything is working as it should.
Bummer, cause it should have been like that from the start.

Hello !

Just go to this method and make it const.

float UGameplayModMagnitudeCalculation::K2_GetCapturedAttributeMagnitude(const FGameplayEffectSpec& EffectSpec, FGameplayAttribute Attribute, const FGameplayTagContainer& SourceTags, const FGameplayTagContainer& TargetTags)

It should fix the issue.

You need the engine source code to do that.