I’m trying to setup GAS attributes in c++, and can’t get my bp-based stamina/health regen effects to consistently stop regenerating at full stamina/health.
I’ve tried clamping the values in PreAttributeChange and PostGameplayEffectExecute function overrides, but the base value still goes up to infinity. Thought maybe I could just remove the effect with a wait for attribute change node in actor bp if new value>= the matching “max _” attribute, but this is unreliable because it seems sometimes the last clamped effect tick doesn’t fire the notify so wait for change doesn’t get a change.
As such, I’m thinking a better approach would be to add a tag to the ability system comp like Attribute.Stamina.Full or some such when it hits max, and use that as a blocking tag on regen effect. And remove it when attribute<max.
Where would such logic go tho? Should it be in PostGameplayEffectExecute function override or somewhere else?
And on that note, if any Epic devs happen to read this: Why isn’t there a native/premade mod op on gameplay effects to Add Current which automatically clamps to the affected attribute’s base value?
I think an appropriate place to put this would indeed be in the PostGameplayEffectExecute function in your UAttributeSet subclass. I did that in a game I worked on and it worked pretty well.
That worked! my function override looks like this if anyone stumbles in after getting weird answers from LLM lol:
void UGoblinAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(), 0.0f, GetMaxHealth()));
}
else if (Data.EvaluatedData.Attribute == GetStaminaAttribute())
{
SetStamina(FMath::Clamp(GetStamina(), 0.0f, GetMaxStamina()));
if (GetStamina() >= GetMaxStamina())
{
StamFullTag = FGameplayTag::RequestGameplayTag(FName("Status.Stamina.Full"));
}
else if (GetStamina() < GetMaxStamina())
{
StamFullTag = FGameplayTag(); // Assign an empty tag to "remove" it
}
}
}
Sorry my c++ is as messy as my blueprints lol. Clamp kinda redundant now too I guess.
It’s a little different from how I did it (I used AddLooseGameplayTag to add it to the AbilitySystemComponent, but if it works, then that’s what matters.
PreAttributeChange only clamps the final value, not the modifier’s base value, so regen can still keep stacking. A cleaner approach is to handle the max check in your AttributeSet and use tags to block the regen effect when the attribute reaches its limit. PostGameplayEffectExecute is a good place to update that state after effects are applied. A native “Add Current with Clamp to Max” modifier would definitely make this much easier.