GameEffects and AttributeSet replication

Hey Guys,

I have been playing around with the ability system which seems pretty cool. There is a plethora of things that I don’t understand about it yet but I have it working. I hit a bit of a roadblock and I’m hoping someone can help me out.

I have a bunch of AIs in the game that fight each other by applying gameplay effects for damage. It all seems to work just fine on the server but the attributes don’t appear to be replicated to clients. I have some relevant parts shown below but let me know if there’s anymore that might be needed. I appreciate any help.

Here is what my AttributeSet class looks like:


UCLASS(Blueprintable, BlueprintType)
class RTSPROTOTYPE_API URTS_UnitAttributeSet : public UAttributeSet
{
	GENERATED_UCLASS_BODY()
	
public:
	URTS_UnitAttributeSet(FUnitAttributeData& Attributes);

public:
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float Health;
	
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float HealthMax;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float AttackDamage;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float AttackRange;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float AttackDelay;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Attributes")
	float MovementSpeed;

};
URTS_UnitAttributeSet::URTS_UnitAttributeSet(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
	, Health(0.f)
	, HealthMax(100.f)
	, AttackDamage(0.f)
	, AttackRange(0.f)
	, AttackDelay(0.f)
	, MovementSpeed(0.f)
{
	
}

URTS_UnitAttributeSet::URTS_UnitAttributeSet(FUnitAttributeData& Attributes)
	: Health(Attributes.Health)
	, HealthMax(Attributes.HealthMax)
	, AttackDamage(Attributes.AttackDamage)
	, AttackRange(Attributes.AttackRange)
	, AttackDelay(Attributes.AttackDelay)
	, MovementSpeed(Attributes.MovementSpeed)
{

}

void URTS_UnitAttributeSet::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(URTS_UnitAttributeSet, Health);
	DOREPLIFETIME(URTS_UnitAttributeSet, HealthMax);
	DOREPLIFETIME(URTS_UnitAttributeSet, AttackDamage);
	DOREPLIFETIME(URTS_UnitAttributeSet, AttackRange);
	DOREPLIFETIME(URTS_UnitAttributeSet, AttackDelay);
	DOREPLIFETIME(URTS_UnitAttributeSet, MovementSpeed);
}

Here is how I apply the damage.

I’m going to start by mentioning that the Ability System is still a work in progress and I don’t encourage anyone to use it yet. You aren’t going to find good examples or documentation about it and things you’re relying on may change without notice.

How are you storing the attribute set? If the attribute set itself isn’t replicated then none of its members will be. We generally store them as standard pointers and create them in the Actor’s constructor with something like this:



UPROPERTY(Category=Attributes, VisibleAnywhere, BlueprintReadOnly)
URTS_UnitAttributeSet* UnitAttributeSet;




UnitAttributeSet = ObjectInitializer.CreateDefaultSubobject<URTS_UnitAttributeSet>(this, TEXT("UnitAttributeSet"));


Ya, all the research I’ve done on the system I’ve seen that disclaimer posted, its fine to dig into and I’ll adapt as changes are added. I wasn’t creating the attributeset the way you do in your example which is probably part of the problem I had. I spent a while today playing around with it and I was able to get it working, well actually, it was working the whole time just not as expected.

Here is a screenshot of a simple test I made to check values:

I was using this code to initialize the Attributes using a data asset that gets selected in the editor:



Attributes = Cast<URTS_UnitAttributeSet>(InitStats(URTS_UnitAttributeSet::StaticClass(), AttributeData));

Which brings me to the conclusion that whatever InitStats() returns is not the object that receives replication updates. I discovered that if I wrote the code below in BeginPlay() it updated the Attributes property with the object that does receive replication updates.



Attributes = Cast<URTS_UnitAttributeSet>(GetAttributeSubobject(URTS_UnitAttributeSet::StaticClass()));

I haven’t thought to do it the way you explained even though I should have since that seems to be the standard way of initializing. It is working now using the above code in both snippets of the image now. I would have replied sooner but I just got it working a couple of hours ago. Thanks for the help. :slight_smile: