AbilitySystem.EnsureAbilitiesEndGracefully

AbilitySystem.EnsureAbilitiesEndGracefully

#Overview

name: AbilitySystem.EnsureAbilitiesEndGracefully

This variable is created as a Console Variable (cvar).

It is referenced in 3 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of AbilitySystem.EnsureAbilitiesEndGracefully is to provide a safety check mechanism during the shutdown process of the Gameplay Ability System in Unreal Engine 5. It ensures that all GameplayAbilities are gracefully ended when the ClearAllAbilities function is called.

This setting variable is primarily used by the Gameplay Abilities system, which is part of the GameplayAbilities plugin in Unreal Engine 5. It’s specifically utilized within the AbilitySystemComponent class.

The value of this variable is set as a console variable (CVar) in the AbilitySystemComponent_Abilities.cpp file. It’s initialized with a default value of true, but can be changed at runtime through console commands.

The associated variable CVarEnsureAbilitiesEndGracefully directly interacts with this setting. They share the same value and purpose.

Developers must be aware of several important points when using this variable:

  1. When enabled (set to true), it adds additional checking during the ClearAllAbilities process.
  2. It’s particularly useful for debugging and ensuring proper ability cleanup.
  3. It should be disabled if you have NonInstanced abilities designed for multiple concurrent executions, as these may trigger false positives.

Best practices when using this variable include:

  1. Keep it enabled during development and testing phases to catch potential issues with ability lifecycle management.
  2. Disable it in production builds if you’re using NonInstanced abilities with multiple concurrent executions to avoid unnecessary warnings or errors.
  3. Use it in conjunction with proper ability management practices, ensuring that TryActivateAbility and EndAbility calls are always matched.

Regarding the associated variable CVarEnsureAbilitiesEndGracefully:

This is the actual console variable that controls the behavior. It’s used in the ClearAllAbilities function of the UAbilitySystemComponent class. When enabled, it adds additional checks to ensure that all active abilities, particularly NonInstanced ones, have ended properly. This helps identify potential mismatches between TryActivateAbility and EndAbility calls, which could lead to subtle bugs or resource leaks in the ability system.

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp:51

Scope: file

Source code excerpt:

static TAutoConsoleVariable<bool> CVarUpdateMontageSectionIdToPlay(TEXT("AbilitySystem.UpdateMontageSectionIdToPlay"), true, TEXT("During tick, update the section ID that replicated montages should use"));
static TAutoConsoleVariable<bool> CVarReplicateMontageNextSectionId(TEXT("AbilitySystem.ReplicateMontageNextSectionId"), true, TEXT("Apply the replicated next section Id to montages when skipping position replication"));
static TAutoConsoleVariable<bool> CVarEnsureAbilitiesEndGracefully(TEXT("AbilitySystem.EnsureAbilitiesEndGracefully"), true, TEXT("When shutting down (during ClearAllAbilities) we should check if all GameplayAbilities gracefully ended. This should be disabled if you have NonInstanced abilities that are designed for multiple concurrent executions."));

void UAbilitySystemComponent::InitializeComponent()
{
	Super::InitializeComponent();

	// Look for DSO AttributeSets (note we are currently requiring all attribute sets to be subobjects of the same owner. This doesn't *have* to be the case forever.

#Associated Variable and Callsites

This variable is associated with another variable named CVarEnsureAbilitiesEndGracefully. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp:51

Scope: file

Source code excerpt:

static TAutoConsoleVariable<bool> CVarUpdateMontageSectionIdToPlay(TEXT("AbilitySystem.UpdateMontageSectionIdToPlay"), true, TEXT("During tick, update the section ID that replicated montages should use"));
static TAutoConsoleVariable<bool> CVarReplicateMontageNextSectionId(TEXT("AbilitySystem.ReplicateMontageNextSectionId"), true, TEXT("Apply the replicated next section Id to montages when skipping position replication"));
static TAutoConsoleVariable<bool> CVarEnsureAbilitiesEndGracefully(TEXT("AbilitySystem.EnsureAbilitiesEndGracefully"), true, TEXT("When shutting down (during ClearAllAbilities) we should check if all GameplayAbilities gracefully ended. This should be disabled if you have NonInstanced abilities that are designed for multiple concurrent executions."));

void UAbilitySystemComponent::InitializeComponent()
{
	Super::InitializeComponent();

	// Look for DSO AttributeSets (note we are currently requiring all attribute sets to be subobjects of the same owner. This doesn't *have* to be the case forever.

#Loc: <Workspace>/Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp:434

Scope (from outer to inner):

file
function     void UAbilitySystemComponent::ClearAllAbilities

Source code excerpt:


	// Let's add some enhanced checking if requested
	if (CVarEnsureAbilitiesEndGracefully.GetValueOnGameThread())
	{
		for (FGameplayAbilitySpec& Spec : ActivatableAbilities.Items)
		{
			if (Spec.IsActive())
			{
				ensureAlwaysMsgf(Spec.Ability->GetInstancingPolicy() != EGameplayAbilityInstancingPolicy::NonInstanced, TEXT("%hs: %s was still active (ActiveCount = %d). Since it's not instanced, it's likely that TryActivateAbility and EndAbility are not matched."), __func__, *GetNameSafe(Spec.Ability), Spec.ActiveCount);