GameplayAbilities and you

Hi,
Also from me a big thanks for the great description…

I tried to implement a really simple Mana-Regeneration system, just for the sake of testing things out.
-Create a AttributeSet with “Mana” , “MaxMana” and “ManaRegeneration”
-Create a effect which periodically adds “ManaRegeneration” to Mana
-added the Effect on the “Begin Play” event of the actor

Works like it should right now, but now comes my question.
When i try to clamp my mana to “MaxMana” in the “PreAttributeBaseChange” method it doesnt do anything at all


void UMagicAttributeSet::PreAttributeBaseChange(const FGameplayAttribute& Attribute, float& NewValue) const
{
	if (Attribute.GetUProperty() == FindFieldChecked<UProperty>(UMagicAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(UMagicAttributeSet, Mana)))
	{
		NewValue = FMath::Clamp(NewValue, 0.f, MaxMana);
	}
}

as soon as i do exactly the same in the PreAttributeChange it works like a charm.
Is there any reason why it does nothing in the “PreAttributeBaseChange”?

PreAttributeBaseChange is only triggered when you set the value via FActiveGameplayEffectsContainer::SetAttributeBaseValue. The most common way to invoke this is by going through UAbilitySystemComponent::SetNumericAttributeBase. If you access the attribute set directly, e.g., by using FGameplayAttribute::SetNumericValueChecked, only PreAttributeChange is called, not PreAttributeBaseChange.

I’ve written a small test program to illustrate this. The ManaAttributeSet has four Mana_XXX variables that are either not clamped, clamped by one of the functions (between 0 and 2 for PreAttributeBaseChange and between -1 and 1 for PreAttributeChange) or clamped by both of them. There are two code paths: one that goes through a custom execution and sets the values like this:


	float OldNone{ ASC->GetNumericAttributeBase(FGameplayAttribute(None_Prop)) };
	float OldBaseChangeOnly{ ASC->GetNumericAttributeChecked(FGameplayAttribute(BaseChangeOnly_Prop)) };
	float OldChangeOnly{ ASC->GetNumericAttributeChecked(FGameplayAttribute(ChangeOnly_Prop)) };
	float OldBoth{ ASC->GetNumericAttributeChecked(FGameplayAttribute(Both_Prop)) };
	// UE_LOG(LogTemp, Warning, TEXT("RestoreMana: Old values: %.2f %.2f %.2f %.2f"), OldNone, OldBaseChangeOnly, OldChangeOnly, OldBoth);

	ASC->SetNumericAttributeBase(FGameplayAttribute(None_Prop), OldNone + Delta);
	ASC->SetNumericAttributeBase(FGameplayAttribute(BaseChangeOnly_Prop), OldBaseChangeOnly + Delta);
	ASC->SetNumericAttributeBase(FGameplayAttribute(ChangeOnly_Prop), OldChangeOnly + Delta);
	ASC->SetNumericAttributeBase(FGameplayAttribute(Both_Prop), OldBoth + Delta);

	float NewNone{ ASC->GetNumericAttributeBase(FGameplayAttribute(None_Prop)) };
	float NewBaseChangeOnly{ ASC->GetNumericAttributeChecked(FGameplayAttribute(BaseChangeOnly_Prop)) };
	float NewChangeOnly{ ASC->GetNumericAttributeChecked(FGameplayAttribute(ChangeOnly_Prop)) };
	float NewBoth{ ASC->GetNumericAttributeChecked(FGameplayAttribute(Both_Prop)) };

	UE_LOG(LogTemp, Warning, TEXT("RestoreMana: New values: %.2f %.2f %.2f %.2f"), NewNone, NewBaseChangeOnly, NewChangeOnly, NewBoth);


in this case the output is as expected:


LogTemp:Warning: RestoreMana: New values: 0.40 0.40 0.40 0.40
LogTemp:Warning: RestoreMana: New values: 0.80 0.80 0.80 0.80
LogTemp:Warning: RestoreMana: New values: 1.20 1.20 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 1.60 1.60 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.00 2.00 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.40 2.00 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.80 2.00 1.00 1.00

The second code path looks like this:



	float OldNone{ ManaAttributeSet->Mana_None.GetCurrentValue() };
	float OldBaseChangeOnly{ ManaAttributeSet->Mana_BaseChangeOnly.GetCurrentValue() };
	float OldChangeOnly{ ManaAttributeSet->Mana_ChangeOnly.GetCurrentValue() };
	float OldBoth{ ManaAttributeSet->Mana_Both.GetCurrentValue() };

	float NewNone{ OldNone + Delta };
	None_Attr.SetNumericValueChecked(NewNone, ManaAttributeSet);
	float NewBaseChangeOnly{ OldBaseChangeOnly + Delta };
	BaseChangeOnly_Attr.SetNumericValueChecked(NewBaseChangeOnly, ManaAttributeSet);
	float NewChangeOnly{ OldChangeOnly + Delta };
	ChangeOnly_Attr.SetNumericValueChecked(NewChangeOnly, ManaAttributeSet);
	float NewBoth{ OldBoth + Delta };
	Both_Attr.SetNumericValueChecked(NewBoth, ManaAttributeSet);


	UE_LOG(LogTemp, Warning, TEXT("RestoreMana: New values: %.2f %.2f %.2f %.2f"), NewNone, NewBaseChangeOnly, NewChangeOnly, NewBoth);

and in that case the output mirrors the behavior you see:


LogTemp:Warning: RestoreMana: New values: 0.40 0.40 0.40 0.40
LogTemp:Warning: RestoreMana: New values: 0.80 0.80 0.80 0.80
LogTemp:Warning: RestoreMana: New values: 1.20 1.20 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 1.60 1.60 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.00 2.00 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.40 2.40 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 2.80 2.80 1.00 1.00
LogTemp:Warning: RestoreMana: New values: 3.20 3.20 1.00 1.00

Only PreAttributeChange clamps the value, PreAttributeBaseChange is not invoked.

Of course the abilities system is complicated enough that you might have come across a totally different effect, but that seemed the most likely explanation to me without any further information :slight_smile:

P.S. A big “thank you” to for the original post from me as well. The abilities system is great for so many things, but a beast to figure out from the source code. Hopefully more people will be able to benefit now that there is documentation available.

I can’t tell you if this is the right way or not, but you could add the tag to an effect and then apply the effect to the actor.

is there a way to globally trigger an ability without the ability having to be given to an actor first?

Well, yes and no :slight_smile:

By default abilities themselves are not instanced, and so they don’t belong to an actor. (They can optionally be instanced by execution or by actor in which case they do have an owner.) However, to actually do something with the ability you need to provide an actor and an ability system component.

Well, actually you need to provide two actors: UGameplayAbility::CanActivateAbility, UGameplayAbility::ActivateAbility, etc. all take an FGameplayAbilityActorInfo as argument. This struct contains attributes for two actors: an Owner and an Avatar. According to the documentation the Owner should not be null whereas the Avatar may be. However, CanActivateAbility checks whether the Avatar is null and returns false if it is. So you cannot really use an ability without providing both Owner and Avatar. These are, e.g., used as instigator and causer, respectively, if your ability creates gameplay effects and the avatar is used as the source for target locations. But I don’t think anything prevents you from using the same actor for both roles.

To activate the ability you want to call UGameplayAbility::ActivateAbility after doing some setup work. Problem is, this method is protected, and there exists no obvious caller in UGameplayAbility. The comments in GameplayAbility.h mention a TryActivateAbility method that achieves this, but this method does not (perhaps no longer?) exist in UGameplayAbility, only in UAbilitySystemComponent. So it seems to me that you cannot actually activate the ability without going through an ability system component. (I might, of course, miss something.)

In summary, I don’t think you can trigger an ability without using some actor and ability system component. But nothing prevents you from having a single “global ability actor” in your world that triggers all abilities that you don’t want to give to individual actors, if that suits your design.

Good idea with the global actor to use to trigger abilities. I do have another question. How do you remove an effect but keep the attribute change that it applied? My issue is that i have a poison gameplay effect that will only apply the modifier when i add Round.End to the actor using the OngoingTagRequirements in the gameplay effect. If the duration is set to instant then it doesn’t apply so i have to set the duration to infinite. Everything works until i remove the gameplay effect. It reverts the attribute change adding the health back to the player. Any ideas?

Also can you connect an actor’s tag container to the ability system component’s tag container (my actor derives off IGameplayTagAssetInterface)? It looks like the ability system has its own tag container so there is no point of having a tag container in the actor since adding tags to that container doesn’t get added to the ability system’s one. So should i even have a tag container in the actor or just work off the ability system component’s one?

Deary me, I wouldn’t have thought that the thread would remain so active. I’ll try to kinda, sorta answer some of the still open questions.

To my knowledge, the tags are attached to the ability system component, rather than the actor the ability system acts through. Which kinda makes sense if you think about it, really. Not like it makes a difference; there isn’t really any convenient way to plainly add a tag, and just a tag, to an ability system that’s exposed to blueprints.

The standard way to add a granted tag to an ability system of choice is to apply a GameplayEffect that has the tag in question set to be applied to the affected actor(you can set extra tags to grant for each gameplay effect spec, so you can decide dynamically which ones the effect will apply as well, and don’t need an extra GE for every individual tag application). I believe you can also add a granted tag without Gameplay Effect by using the C++ function AddLooseGameplayTag in the AbilitySystemComponent class, however the code comments specifically warn that tags added this way are not replicated automatically, and I am unsure how safe this method is as a whole. Unless you have a good reason not to, I’d think applying a permanent Gameplay Effect spec with your tag of choice added as extra granted tag should about do the trick.

Huh, that’s a tricky question, depending on what you wish to do.

I know instant effect replication uses something funky like that, it treats an instant GameplayEffect as infinite until the server can verify and confirm the application for real, rolling it back if this is not the case. I’m looking through it there, and it seems like you are able to define how a spec behaves by setting its duration in specific ways(infinite duration is defined as -1.0f, instant as 0.0f), and as you can copy the old GameplayEffectSpec due to being a struct with no real deep copy issues, you could probably remove and replace it with an instant variation of it when the time is right.

That sounds like a bit of a weird hack though(I mean, experiments cost nuthin’, just saying it may be a little tryhard), so I suppose the more reasonable answer might be to just set up an ability(either a newly created one for the job or the source ability) to listen for either the removal of the “preview” poison effect and apply a separate, permanent Gameplay Effect with similar modifiers, or to just wait for the Round.End tag to happen to your actor before abilities start unravelling their effects(which could easily be done with ability tasks).

Up to you how you want to do it, really.

You probably could link the containers in some strange way, but there would be little point.

The actor’s tags doesn’t and probably shouldn’t really influence the ability system in any way. You can set up and use an actor tag container for other things if you wish, however. The beauty of gameplay tags as a whole is that they leave few restrictions, they give you a very basic, very general tool and let you do whatever with it.

Any chance you can do a small tutorial about Ability Tasks and how to set them up / use them?

Not much to talk about how to use them. They’re blueprint nodes you can call in Ability graphs that wait for an outside stimuli before continuing, usually possessing an unlabelled top exec route that you may use to continue calling functions within the current frame and labelled exec pins that will run its attached route of functions at a later time, much like how delays work but with thigns other than time, usually. They usually do what they advertise in their name/description, they support multiplayer and will do their predicting and correcting themselves. They will only run for as long as the ability is active, so the End Ability node will prematurely end all pending ability tasks originating from that ability, as well(so you probably want to place things that HAVE to happen, no matter how the ability ended, in the EndAbility function or whatever it was called. One example I could think off probably being purging off a buff that roots you in place as you play your casting animation).

I would think they are rather self-explanatory.

That being said, if your question is about making your own ability tasks and setting up/using them, then I would have no idea how to do that, sorry. Not really feeling having to dissect their source code myself, either, especially considering Gameplay Tasks as a whole are probably a module big enough to cover a small tutorial on their own anyway(especially since their use is not actually limited to the ability system alone). Latent actions in UE4 C++ and, by extension, Gameplay/Ability Tasks are honestly a bunch of crud to understand and set up(I mean, maybe I just suck. That’s always a possibility), so I’m pretty happy about not having to deal with the act of setting them up currently.

Maybe I’ll go through it and write something down some day, but currently I am not really planning on it. The ability tasks built into the system already do about most generic things you could ask for, anyhow.

Does this work with Combos and timed press system?
Or do we have to code them again?

Also, can unreal use notepad++ to deal with code?
Visual studio is just way too heavy.

I recently submitted a pull request that fixes BindAbilityActivationToInputComponent unable to bind actions. You can get it from here: https://github.com/EpicGames/UnrealEngine/pull/3371

I’ve created a wiki page using the text of the OP as it stands right now. I pretty much just copied and pasted directly, fixing the formatting to match the wiki formatting as I went. Feel free to make any modifications to the page if needed.

Thanks to @KZJ for the proper guide and @Jay2645 for the wiki! Gameplay Abilities/Tags are just awesome and the system is so robust that the possibilities are endless!

Here is a quick preview. Testing as client with dedicated server.

Hey everyone,
First, thanks for your answers, more and more I feel like the gameplay effect is the go-to-bridge for anything related to the ability system.

One thing I’d like to know is about the AttributeSet. These are CPP only for as far as I can tell (inheriting them in blueprint only allows you to modify the default values -if they are marked as editable in cpp-).
Can somebody tell me why and if there’s any workaround for it?

I also found that I could link a datatable to these attributes via the initstat to set stuff very easily but it only allows me to modify values, not creating new fields.

Cheers and thanks again so much! :slight_smile:

It kind of sucks to properly expose AttributeSet creation to blueprints, because you need to set up lifetime replication in unique ways, require a repnotify function with macro inside for each attribute to guarantee that replication works properly, and the Attribute change functions pretty much require you to identify the attribute that’s currently being changed by checking up the UProperty belonging to them.

I am not convinced that it is impossible or even all that difficult to properly expose the creation of new attribute sets with new attributes within blueprints period, but I would think that it’s barely worth to do it considering it seems like such an annoying extra mile to take when the cpp code is so incredibly trivial(if obnoxiously wordy per attribute) to write, once you are aware of which macros to use where. It’s not like you will keep adding new attributes to your project all the time either, it’s the kind of thing you’re usually done planning and implementing relatively early into the project, with some minor tweaks and additions happening afterwards.

Thanks for this! Timing is perfect as I was kind of stuck of how I would handle my abilities and perk system! I hope I can wrap my artist head around all this haha!
I’m still confused by the keybinding actions as Im making a tactical turned based rpg. What I do now is let the playercontroller handle all input and call event dispatchers to my unitmanager which then checks which unit is active and then running the Try Activate Ability By Class function… Not sure if my implementation will work in the long run but the whole system looks promising! Thanks again for the write up!

So there is one thing I am not quite sure about these - do abilities start montages or do montages start abilities? I’m sure there’s an argument to be made for both (and use-cases for both) but for the general case it seems to be the former. Which makes it all the more confusing that GameplayAbilities don’t have “MontageToPlay” or some such already in them, as it sounds like it’s a fairly common thing to do.

Not sure if I understand the question, or even the problem.

Abilities can start montages by using the ability task fittingly called PlayMontageAndWait, and this is usually what you’re expected to use when dealing with montages in the context of an ability, such as for example a cast animation that plays prior to firing a projectile. Due to being an ability task, it has multiple outputs that help in tying functionality to the montage(4, namely On Completed, On Blend Out, On Interrupted and On Cancelled). The only annoying thing about doing it that way is that you can’t really set up an animation that triggers the rest of the ability’s effect halfway through without playing around with a separate delay task, but that can be solved by splitting the casting montage of choice into a pre-effect and a post-effect montage.

Tying abilities to a cast animation, so the other way around, is usually a suboptimal idea, because abilities should be designed to be as self-contained as you can make them. Having the montage and, by extension, its length be defined outside of the ability seems counterproductive to this goal. Moreover, due to the fact that abilities have access to tasks and can pretty much end themselves whenever they want, there is no real benefit from doing it the other way around than intended.

That being said, I would think that a cosmetic/purely visual animation as a result of a gameplay effect, such as a “flailing and panicking because on fire” animation or some such thing could probably be handled as part of a gameplay cue. Not sure actually. It would make sense to me because these are the kinds of things gameplay cues are used in general and ability systems can only play one montage this way at a time(for fairly obvious reasons), but I don’t know if there’s any important interactions to watch out for(you would probably have to check if you aren’t overwriting a montage a montage ability task before playing such an animation, though. The ability system keeps track of the montage that’s currently playing as a product of a task, but I don’t know the name of the getter function or if it’s evenr eadily available).

But yeah, if your animation isn’t 100% cosmetic, use the ability task. You could even make a child ability class for generic “Play Montage X and, when successful, follow through with effects defined in function Y” kinda abilities.

Hmm, I missed the PlayMontageAndWait function. I was mostly concerned on what t he intent is of the system, and the ability -> montage workflow seems to be the correct answer.

The long story short, is that you should use animations only in cosmetic manner. You should not use them to actually trigger parts of abilities, it’s opposite to what what ability system is trying to do.

I can see point on why you would want to trigger something from montage, like shooting fireball from hand ( if you want it to be perfectly synced), but in that way you limit yourself to perfectly timed animation (which will determine cast time of ability), which isn’t good approach in something like RPG (IMO).

Setting it up to use animation only as presentation layer is probably more complex and I honestly haven’t found good workflow for it yet, but it still going to be more beneficial (at least for me) in long term.

It would nice to actually know how it is handled for casters in Paragon (like Gideon).