// Copyright (c) 2026 Reignance Studios. MIT License, see LICENSE. #pragma once #include "CoreMinimal.h" #include "AbilitySystemComponent.h" #include "AttributeSet.h" #include "GKLAttributeSet.generated.h" #define GKL_ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) /** * Health, Stamina and Mana for a multiplayer player. * * - Every gameplay attribute replicates with an OnRep that calls GAMEPLAYATTRIBUTE_REPNOTIFY, * registered with REPNOTIFY_Always, so predicted values on the owning client are confirmed. * - Values are clamped twice: PreAttributeChange clamps what queries return, and * PostGameplayEffectExecute clamps the base value that instant and periodic effects change. * - Damage is a server-only meta attribute: effects add to it, PostGameplayEffectExecute * moves it into Health and sends Event.Death when Health reaches 0. */ UCLASS() class GASKITLITE_API UGKLAttributeSet : public UAttributeSet { GENERATED_BODY() public: UGKLAttributeSet(); virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override; virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override; /** Server only. Refills Health, Stamina and Mana and re-arms the death event. Called on respawn. */ void ResetToMax(); UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Health", ReplicatedUsing = OnRep_Health) FGameplayAttributeData Health; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, Health) UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Health", ReplicatedUsing = OnRep_MaxHealth) FGameplayAttributeData MaxHealth; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, MaxHealth) UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Stamina", ReplicatedUsing = OnRep_Stamina) FGameplayAttributeData Stamina; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, Stamina) UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Stamina", ReplicatedUsing = OnRep_MaxStamina) FGameplayAttributeData MaxStamina; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, MaxStamina) UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Mana", ReplicatedUsing = OnRep_Mana) FGameplayAttributeData Mana; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, Mana) UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Mana", ReplicatedUsing = OnRep_MaxMana) FGameplayAttributeData MaxMana; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, MaxMana) /** Meta attribute, server only, not replicated. */ UPROPERTY(BlueprintReadOnly, Category = "GASKit Lite|Damage") FGameplayAttributeData Damage; GKL_ATTRIBUTE_ACCESSORS(UGKLAttributeSet, Damage) protected: UFUNCTION() void OnRep_Health(const FGameplayAttributeData& OldValue); UFUNCTION() void OnRep_MaxHealth(const FGameplayAttributeData& OldValue); UFUNCTION() void OnRep_Stamina(const FGameplayAttributeData& OldValue); UFUNCTION() void OnRep_MaxStamina(const FGameplayAttributeData& OldValue); UFUNCTION() void OnRep_Mana(const FGameplayAttributeData& OldValue); UFUNCTION() void OnRep_MaxMana(const FGameplayAttributeData& OldValue); private: bool bOutOfHealth = false; };