AttributeSets in Blueprint possible?

Hey everyone,
Thanks to the great post from KZJ [Go Read it if you’d like, it’s awesome][1], I’ve been able to handle most of the functions around the abilitysystem only in blueprint.
One last thing is still kind of a problem to me : the original AttributeSet.

If I create a class deriving from UAttributeSet using CPP, I can have access to these float values in the “modifiers” tab on a gameplay effect

But, if I derive from AttributeSet in blueprint, and add a float to it. I don’t have it listed.

Is there something I’m missing or there’s just no way you can achieve this in blueprint atm.

Thanks for your help!

With some modification to the engine code, you can. We are currently using this method in our project, however I believe the Epic guys chose not to support this for a reason, so use at your own risk.

SGameplayAttributeWidget.cpp

Location: Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilitiesEditor\Private\SGameplayAttributeWidget.cpp

Search for if (Class->IsChildOf(UAttributeSet::StaticClass(), you should locate it in the method SAttributeListWidget::UpdatePropertyOptions(), at line 266 if you are using version 4.18.3.

Replace the entire if block with the following code:

if (Class->IsChildOf(UAttributeSet::StaticClass()))
{
	// Allow entire classes to be filtered globally
	if (Class->HasMetaData(TEXT("HideInDetailsView")))
	{
		continue;
	}

	if (Class->ClassGeneratedBy)
	{
		const FString SkeletonPrefix(TEXT("SKEL_"));
		const FString ReinstantializedPrefix(TEXT("REINST_"));

		// skip skeletion classes and reinstantialized classes
		if (Class->GetName().StartsWith(SkeletonPrefix) || Class->GetName().StartsWith(ReinstantializedPrefix))
		{
			continue;
		}
	}

	for (TFieldIterator<UProperty> PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt; ++PropertyIt)
	{
		UProperty *Property = *PropertyIt;

		if (Class->ClassGeneratedBy)
		{
			if (Property->GetName() == TEXT("UberGraphFrame"))
			{
				continue;
			}
		}

		// if we have a search string and this doesn't match, don't show it
		if (AttributeTextFilter.IsValid() && !AttributeTextFilter->PassesFilter(*Property))
		{
			continue;
		}

		// don't show attributes that are filtered by meta data
		if (!FilterMetaData.IsEmpty() && Property->HasMetaData(*FilterMetaData))
		{
			continue;
		}

		// Allow properties to be filtered globally (never show up)
		if (Property->HasMetaData(TEXT("HideInDetailsView")))
		{
			continue;
		}

		FString DisplayName;
		if (Class->ClassGeneratedBy)
		{
			// remove "_C" at the end of a BP class
			DisplayName = FString::Printf(TEXT("%s.%s"), *Class->GetName().LeftChop(2), *Property->GetName());
		}
		else
		{
			DisplayName = FString::Printf(TEXT("%s.%s"), *Class->GetName(), *Property->GetName());
		}

		TSharedPtr<FAttributeViewerNode> SelectableProperty = MakeShareable(new FAttributeViewerNode(Property, DisplayName));
		PropertyOptions.Add(SelectableProperty);
	}
}

This will allow you to choose attributes defined in blueprint attribute sets.

However, if you use these BP attributes, like in gameplay effect modifiers, you may find them became strange references to TRASHCLASS members after saving and reopening the editor, and crash your game. This could be one reason why the system doesn’t support BP attributes for now. While I believe this must be caused by a deeper reason, here is a workaround:

AttributeSet.cpp

Location: Engine\Plugins\Runtime\GameplayAbilities\Source\GameplayAbilities\Private\AttributeSet.cpp

Go to the end of the FGameplayAttribute::PostSerialize() method, and append the following code:

if (Attribute)
{
	UClass* AttributeSetClass = CastChecked<UClass>(Attribute->GetOuter());
	UBlueprint* AttributeBlueprint = Cast<UBlueprint>(AttributeSetClass->ClassGeneratedBy);
	if (AttributeBlueprint && AttributeBlueprint->GeneratedClass != AttributeSetClass)
	{
		UProperty* ReplacedProperty = FindFieldChecked<UProperty>(AttributeBlueprint->GeneratedClass, Attribute->GetFName());
		this->SetUProperty(ReplacedProperty);
	}
}

This fixes corrupted attribute references by replacing them with their correct counterparts.

It’s not supported at the moment. It’s better to declare attributes in c++.