GameplayAbilities questions

It’s bit unrelated but I have question about GameplayTags.

Assuming that we have tag Damage.Fire

And do:
HasTag(TagIn, EGameplayTagMatchType::IncludeParentTags, EGameplayTagMatchType::Explicit);
Does it mean that:

  1. Only Fire part will be checked.
  2. Against every single tag in my container. like:
    Condition.Fire.Something ?

And it will be match since there is Fire in between.

So Explicit means only leaf most tag ?

So I want want to match hierarchy exactly I should use IncludeParentTags as both argument ?

I’d really prefer to use an actual release if possible, as I’m working with several designers/artists. The problem, as it exists in the current 4.7 build, affects more than just ending an ability. Anything that requires looking at an instance of the ability is off-limits - like checking the cooldown of an ability. What are the chances of a fix for this making it into 4.7?

I don’t think you’ll see any fixes to the ability system getting added to 4.7 at this point. Once we’ve branched a build for a major release we generally want to minimize the additional changes that we bring into the branch. Every change that gets merged brings some risk that it will break something. When things like bug fixes get merged in we need to weigh the benefits with the potential for creating new problems. Because the ability system isn’t considered ready for outside use we don’t generally want to absorb much risk to bring in fixes late in the game. Any fixes you do see in the main branch at this point you can safely expect in 4.8.

Iniside

For most cases I’d recommend calling MatchesAny or MatchesAll on the gameplay tag container instead of calling HasTag directly. Exact matches always return true. If the tag to be matched is a subset of a tag in the container then it will return true if TagMatchType is set to IncludeParentTags. If the tag container contains a tag that is a subset of the tag to be matched then it will return true if TagToCheckMatchType is IncludeParentTags.

Here are some examples to illustrate the possible results. Let’s assume that our tag container contains exactly one tag, “A.B.C”.

HasTag(“A.B.C”, Explicit, Explicit) returns true.
HasTag(“A.B”, Explicit, Explicit) returns false.
HasTag(“A.B.C.D”, Explicit, Explicit) returns false.
HasTag(“E.B.C”, Explicit, Explicit) returns false.
HasTag(“A.B.C”, IncludeParentTags, IncludeParentTags) returns true.
HasTag(“A.B”, IncludeParentTags, IncludeParentTags) returns true.
HasTag(“A.B.C.D”, IncludeParentTags, IncludeParentTags) returns true.
HasTag(“E.B.C”, IncludeParentTags, IncludeParentTags) returns false.
HasTag(“A.B.C”, IncludeParentTags, Explicit) returns true.
HasTag(“A.B”, IncludeParentTags, Explicit) returns true.
HasTag(“A.B.C.D”, IncludeParentTags, Explicit) returns false.
HasTag(“E.B.C”, IncludeParentTags, Explicit) returns false.
HasTag(“A.B.C”, Explicit, IncludeParentTags) returns true.
HasTag(“A.B”, Explicit, IncludeParentTags) returns false.
HasTag(“A.B.C.D”, Explicit, IncludeParentTags) returns true.
HasTag(“E.B.C”, Explicit, IncludeParentTags) returns false.

In your example where you want to compare Damage.Fire against a container that contains Condition.Fire.Something you would always return false. Explicit means to check the whole tag for an exact match.

Ok, thanks for the heads up. We’ll start using the promoted branch then!

@anonymous_user_21e09c97 K

Thanks for explanation. I’m using HasTag, mainly because I come have things identified only by FGameplayTag (don’t need container, nor I want someone using more than one tag).

Thanks, a lot for it, it really help to clear things out. It could be probably useful, to add your explanation to comments in GameplayTags module (;.

New question!

How should we be querying data about an ability for the UI on a client?

My initial guess was something along these lines:


FText SSpellWidget::GetSpellCooldown() const {
	float cooldownRemaining = 0;

	if (mAbilitySpec.IsValid() && mAbilitySpec->IsActive()) {
		UGameplayAbility* activeAbility = mAbilitySpec->GetPrimaryInstance();

		if (activeAbility && activeAbility->GetCurrentActorInfo()) {
			cooldownRemaining = activeAbility->GetCooldownTimeRemaining(activeAbility->GetCurrentActorInfo());
		}
	}
	
	return FText::FromString(FString::SanitizeFloat(cooldownRemaining > 0 ? cooldownRemaining : 0));
}

The call to IsActive isn’t the correct approach, since a spell that runs an entire chain instantly will immediately reduce the ActiveCount back down to 0. Should I be going purely off the primary instance? It doesn’t seem like the CurrentActorInfo ever gets updated on my clients (but I can see it on the server just fine).

Any tips on where to go from here would be greatly appreciated!

Thanks,

Another couple questions!

  1. I have a GameplayEffect that has the Execute Periodic Effect On Application flag set to true and the Stack Period Reset Policy to Never Reset. My assumption here was that this means it should execute once on application, and then every time the duration is refreshed, no new execution is applied. What I am seeing is that every time the duration is refreshed on the GE, it applies the modifiers.

The specific code is here:


	// Register period callbacks with the timer manager
	if (Owner && (AppliedEffectSpec.GetPeriod() != UGameplayEffect::NO_PERIOD))
	{
		FTimerManager& TimerManager = Owner->GetWorld()->GetTimerManager();
		FTimerDelegate Delegate = FTimerDelegate::CreateUObject(Owner, &UAbilitySystemComponent::ExecutePeriodicEffect, AppliedActiveGE->Handle);
			
		// The timer manager moves things from the pending list to the active list after checking the active list on the first tick so we need to execute here
		if (AppliedEffectSpec.Def->bExecutePeriodicEffectOnApplication)
		{
			TimerManager.SetTimerForNextTick(Delegate);
		}

		if (bSetPeriod)
		{
			TimerManager.SetTimer(AppliedActiveGE->PeriodHandle, Delegate, AppliedEffectSpec.GetPeriod(), true);
		}
	}

Should this look more like this?


	// Register period callbacks with the timer manager
	if (Owner && (AppliedEffectSpec.GetPeriod() != UGameplayEffect::NO_PERIOD))
	{
		FTimerManager& TimerManager = Owner->GetWorld()->GetTimerManager();
		FTimerDelegate Delegate = FTimerDelegate::CreateUObject(Owner, &UAbilitySystemComponent::ExecutePeriodicEffect, AppliedActiveGE->Handle);
			
		if (bSetPeriod)
		{
			if (AppliedEffectSpec.Def->bExecutePeriodicEffectOnApplication)
			{
				TimerManager.SetTimerForNextTick(Delegate);
			}
			else
			{
				TimerManager.SetTimer(AppliedActiveGE->PeriodHandle, Delegate, AppliedEffectSpec.GetPeriod(), true);
			}
		}
	}

  1. If I set the period to 0.0, with the Execute On Application flag set to true, no modifiers ever seem to be applied. I haven’t dug into the code on this, but wanted to confirm that what I’m trying to do logically makes sense (apply once, until duration is up).

  2. Modifiers seem to stick around once the duration is complete. Again, I have not had time to dig into the engine yet, but my assumption was that after the duration of the GE was over, it would undo any modifiers it had applied to attributes. Is this a correct assumption?

For your previous UI question:

As you noticed the cooldown for an ability is usually going to be longer than the lifetime of the ability. For checking cooldowns in the UI I’d recommend using the CDO. You may also find GetCooldownTimeRemainingAndDuration more useful than GetCooldownTimeRemaining for your UI. Here’s a sample snippet of code demonstrating its use:


float CooldownRemaining;
float OriginalCooldown;

Cast<UGameplayAbility>(MyGameplayAbility->GetDefaultObject())->GetCooldownTimeRemainingAndDuration(FGameplayAbilitySpecHandle(), MyAbilitySystemComponent->AbilityActorInfo.Get(), CooldownRemaining, OriginalCooldown);

DisplayNormalizedCooldown(CooldownRemaining / OriginalCooldown);

Where DisplayNormalizedCooldown is a UI function expecting a value between 0 and 1 to show some type of progress bar. If you want to show a counter instead of a bar than you can just stick with GetCooldownTimeRemaining like you’re already doing.

On to your more recent message.

  1. Periodic effects execute once per period for their duration. If you have “Execute Periodic Effect On Application” set to true then it will also execute when it is first applied, otherwise the first execution will be one period after it is applied. The Stack Period Reset Policy and Stack Duration Refresh Policy only apply to stacking effects. If your effect isn’t a stacking effect these don’t do anything. If you have a stacking effect and Stack Period Reset Policy is set to “Reset on Successful Application” then when another copy of the effect is added to the stack the period will be reset. In other words, regardless of how long it was going to take until the next execution of the effect it will now execute one full period from the time the stack count was increased. In the two code snippets the top code is doing the desired behaviour. The change you’re suggesting would mean you can’t execute a periodic effect on application unless bSetPeriod is true. Parameters related to stacking should not change the behaviour of effects that don’t stack.

  2. You are correct. If you want a gameplay effect that applies for a set duration just give it a duration and leave the period at 0.0. This will give you a non-periodic effect that applies its modifiers and any associated tags for its whole duration. In this case the ExecuteOnApplication flag should have no effect.

  3. Modifiers should not stick around after their owning gameplay effect has been removed. I haven’t seen this happening but if you are seeing it please let us know so we can investigate it.

I hope this clears things up.

Thanks for the response Fred!

Yes, I see what you’re saying about… the initial execution would not happen for GE’s not using the stacking section. I totally forgot about that.

So does that mean it’s impossible to do something along these lines?

Say I want an ability that periodically does something… we’ll say once every 5 seconds. So I set the GE to have a period of 5.0. Let’s say I also want it to execute immediately on the initial application - so I check Execute Periodic Effect On Application. Now… I also want the duration to be refreshable, but nothing else to happen (I don’t want the initial execution on refreshes). My assumption here was that I would set the stacking policy as follows:

Stacking Type = Aggregate by Target
Stack Limit Count = 1
Stack Duration Refresh Policy = Refresh on Successful Application
Stack Period Reset Policy = Never Reset

This will refresh the duration and extend the GE as desired, maintaining the period. However, every time it refreshes, it does the initial execution that I wanted to happen JUST at the first application of the GE.

As an example - Let’s say the GE is put on the character every 2.5 seconds for a total duration of 20 seconds (assuming each tick mark is one second of time)

Desired:
|----|----|----|----|

Actual:
|–|–||–|–||–|–||–|–|

Hopefully that illustrates what I was getting at with the incorrect code modification above. How would you achieve something like this?

Thanks for the response, Fred. I’m 's partner and have been tracking this thread. I’m going to post a couple of screenshots of a particular GE that I’ve been working on and the observed behaviors, none of which are what we want :slight_smile:

Purpose of this GE: increase the affected unit’s movement speed by 2x (large magnitude for testing) for a duration; does not stack

I would expect the following to work. I gave it a duration and a magnitude of 2, and set stacking such that it should not be stacking above 1 stack, as desired.

The above configuration does absolutely nothing. The GE is applied but their movement speed remains unchanged.

If I add a period greater than 0 to the same GE and tell it to execute the periodic effect on application, then it works in so far as the affected units have their run speed doubled. However! It also stacks infinitely, despite me having set the stacking rules, and the effect never wears off so they maintain that stacked speed forever.

Here’s that setup:

So, if you could provide some insight as to what we might be doing wrong, that’d be greatly appreciated, as I’ve run out of ideas as to why this either doesn’t work or stacks and doesn’t fall off. Thanks. :slight_smile:

We are also moving on to the visualization of abilities for our game. We are looking at the GameplayCue system, but when trying to blueprint a GameplayCueNotify_HitImpact, the editor crashes when trying to select a gameplay tag. Digging into the GameplayCueManager, it looks like the GameplayCueData is never initialized. What steps do we need to take to get this system initialized and online?

The current version of stacking used in the abilities system is one of the newest parts of the system. As a result you’re more likely to encounter rough edges and bugs here.

,
Unfortunately, yes what you’re describing is currently impossible to implement in a straightforward manner. I can think of a couple really hacky ways to set up your data that would work but I won’t discuss them since I don’t want to encourage those approaches. What you described seems like a very reasonable thing to want to do in the system. We’ll need to figure out the best way to support it.

,
Looking at your first screenshot everything looks ok. My best guess here is something weird going on with the stacking rules. As I said earlier this is the area most likely to have rough edges. When I’ve got a bit more time I’ll try to reproduce the problem. Unfortunately this is a busy time of year so it could take me a couple weeks to get to it.

The behaviour you described for your second screenshot is expected. Effects with an instant duration make permanent changes to the attribute values. You can think of periodic effects as a way to repeatedly execute instant effects. The modifiers aren’t outliving the effect, the actual attribute value has changed.

After spending most of the day reading through the GE code, I now understand where we were going wrong.

Details so that others may avoid the same mistake:

Duration based GEs do not make calls to AttributeSet::Pre/PostGameplayEffectExecute - they make changes directly in the aggregators which is bubbled up through AttributeSet::PreAttributeChange. PostGameplayEffectExecute is ONLY for instant effects/period effects (which as Fred stated above, execute instant effects repeatedly). Unlucky that we were testing using the one attribute that requires some extra code on change to see a visual difference (unlike health, etc), but a worthwhile investigation into the details of the system!

Any advice you guys can give on setting up the GameplayCueManager would still be greatly appreciated!

Sorry to bother, but we could still really use help with this particular issue. We’re making heavy use of gameplay abilities and effects and it seems like using cues to spawn/despawn particles is absolutely the way to go, but as said, we can’t pick a gameplay cue tag without the editor crashing

Update for anyone following this thread and trying to get these systems up and running:

To set up the GameplayCueManager, you need to create a Miscellaneous->DataAsset, make it the GameplayCueManager type and give it a name (MyGameplayCueManager for example).
After that you need to go into DefaultGame.ini and add the following:

[/Script/GameplayAbilities.AbilitySystemGlobals]
GlobalGameplayCueManagerName=/Game/Abilities/MyGameplayCueManager.MyGameplayCueManager (or whatever path is relevant for your project)

This should get a manager properly initialized for you.

No single quote for FStringAssetReference

Please note that there is no quotation mark(') in a line added into config file. I’ve struggled with my mistake for half an hour. :frowning:

Hey guys, question.

Could you show sample implementation of GameplayEffectExecutionCalculation class and GameplayEffectCalculation ?

I see you speak of instanced and non-instanced objects.

Could someone explain me (or give a link) of what are instanced classes / properties? The documentation is pretty short on this subject :slight_smile: https://docs.unrealengine.com/latest/INT/Programming/UnrealArchitecture/Reference/Properties/Specifiers/Instanced/index.html

Thanks :slight_smile:

Iniside,

Part of our process for releasing this system includes writing documentation and examples. When the system is ready for public use you can definitely expect there to be an example of how to implement and use those classes. I don’t think that a simple implementation of these classes in a forum post would be very helpful without the rest of a project to show how it would be used in context.

,

This thread is about a fairly specialized topic. In the interests of keeping it on topic could you create a new thread to ask your questions about instancing classes and properties?

I guess this thread I started some times ago should be OK :slight_smile: DefaultToInstanced - EditInlineNew class / Instanced - EditAnywhere property : edits don't work - C++ - Epic Developer Community Forums