第一次提交

This commit is contained in:
不明不惑
2026-03-03 01:23:02 +08:00
commit 3e434877e8
1053 changed files with 102411 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
using UnrealBuildTool;
public class GenericGameplayAttributes : ModuleRules
{
public GenericGameplayAttributes(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Engine",
"GameplayTags","GameplayAbilities","GameplayTasks"
}
);
}
}

View File

@@ -0,0 +1,332 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Attributes/AS_Combat.h"
#include "Net/UnrealNetwork.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GGA_GameplayAttributesHelper.h"
#include "GGA_AttributeSystemComponent.h"
namespace AS_Combat
{
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Damage, TEXT("GGF.Attribute.CombatSet.Damage"), "The damage that will apply to target")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(DamageNegation, TEXT("GGF.Attribute.CombatSet.DamageNegation"), "The damage reduction(percentage) for incoming health damage")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(GuardDamageNegation, TEXT("GGF.Attribute.CombatSet.GuardDamageNegation"), "The damage reduction(percentage) for incoming health damage while guarding")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(StaminaDamage, TEXT("GGF.Attribute.CombatSet.StaminaDamage"), "The stamina damage that will apply to target")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(StaminaDamageNegation, TEXT("GGF.Attribute.CombatSet.StaminaDamageNegation"), "The damage reduction(percentage) for incoming stamina damage")
}
UAS_Combat::UAS_Combat()
{
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Combat::Damage,GetDamageAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Combat::DamageNegation,GetDamageNegationAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Combat::GuardDamageNegation,GetGuardDamageNegationAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Combat::StaminaDamage,GetStaminaDamageAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Combat::StaminaDamageNegation,GetStaminaDamageNegationAttribute());
}
void UAS_Combat::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, Damage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, DamageNegation, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, GuardDamageNegation, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, StaminaDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, StaminaDamageNegation, COND_None, REPNOTIFY_Always);
}
void UAS_Combat::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePreAttributeChange(this,Attribute,NewValue);
}
}
}
bool UAS_Combat::PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data)
{
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
return ASS->ReceivePreGameplayEffectExecute(this, Data);
}
}
return Super::PreGameplayEffectExecute(Data);
}
void UAS_Combat::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
Super::PostAttributeChange(Attribute, OldValue, NewValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostAttributeChange(this, Attribute, OldValue, NewValue);
}
}
}
void UAS_Combat::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostGameplayEffectExecute(this,Data);
}
}
}
void UAS_Combat::AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue,
const FGameplayAttribute& AffectedAttributeProperty)
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
const float CurrentMaxValue = MaxAttribute.GetCurrentValue();
if (!FMath::IsNearlyEqual(CurrentMaxValue, NewMaxValue) && AbilityComp)
{
// Change current value to maintain the current Val / Max percent
const float CurrentValue = AffectedAttribute.GetCurrentValue();
float NewDelta = (CurrentMaxValue > 0.f) ? (CurrentValue * NewMaxValue / CurrentMaxValue) - CurrentValue : NewMaxValue;
AbilityComp->ApplyModToAttributeUnsafe(AffectedAttributeProperty, EGameplayModOp::Additive, NewDelta);
}
}
FGameplayAttribute UAS_Combat::Bp_GetDamageAttribute()
{
return ThisClass::GetDamageAttribute();
}
float UAS_Combat::Bp_GetDamage() const
{
return GetDamage();
}
void UAS_Combat::Bp_SetDamage(float NewValue)
{
SetDamage(NewValue);
}
void UAS_Combat::Bp_InitDamage(float NewValue)
{
InitDamage(NewValue);
}
void UAS_Combat::OnRep_Damage(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, Damage, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetDamageAttribute(),GetDamage(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Combat::Bp_GetDamageNegationAttribute()
{
return ThisClass::GetDamageNegationAttribute();
}
float UAS_Combat::Bp_GetDamageNegation() const
{
return GetDamageNegation();
}
void UAS_Combat::Bp_SetDamageNegation(float NewValue)
{
SetDamageNegation(NewValue);
}
void UAS_Combat::Bp_InitDamageNegation(float NewValue)
{
InitDamageNegation(NewValue);
}
void UAS_Combat::OnRep_DamageNegation(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, DamageNegation, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetDamageNegationAttribute(),GetDamageNegation(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Combat::Bp_GetGuardDamageNegationAttribute()
{
return ThisClass::GetGuardDamageNegationAttribute();
}
float UAS_Combat::Bp_GetGuardDamageNegation() const
{
return GetGuardDamageNegation();
}
void UAS_Combat::Bp_SetGuardDamageNegation(float NewValue)
{
SetGuardDamageNegation(NewValue);
}
void UAS_Combat::Bp_InitGuardDamageNegation(float NewValue)
{
InitGuardDamageNegation(NewValue);
}
void UAS_Combat::OnRep_GuardDamageNegation(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, GuardDamageNegation, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetGuardDamageNegationAttribute(),GetGuardDamageNegation(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Combat::Bp_GetStaminaDamageAttribute()
{
return ThisClass::GetStaminaDamageAttribute();
}
float UAS_Combat::Bp_GetStaminaDamage() const
{
return GetStaminaDamage();
}
void UAS_Combat::Bp_SetStaminaDamage(float NewValue)
{
SetStaminaDamage(NewValue);
}
void UAS_Combat::Bp_InitStaminaDamage(float NewValue)
{
InitStaminaDamage(NewValue);
}
void UAS_Combat::OnRep_StaminaDamage(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, StaminaDamage, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetStaminaDamageAttribute(),GetStaminaDamage(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Combat::Bp_GetStaminaDamageNegationAttribute()
{
return ThisClass::GetStaminaDamageNegationAttribute();
}
float UAS_Combat::Bp_GetStaminaDamageNegation() const
{
return GetStaminaDamageNegation();
}
void UAS_Combat::Bp_SetStaminaDamageNegation(float NewValue)
{
SetStaminaDamageNegation(NewValue);
}
void UAS_Combat::Bp_InitStaminaDamageNegation(float NewValue)
{
InitStaminaDamageNegation(NewValue);
}
void UAS_Combat::OnRep_StaminaDamageNegation(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, StaminaDamageNegation, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetStaminaDamageNegationAttribute(),GetStaminaDamageNegation(),OldValue.GetCurrentValue());
}
}
}

View File

@@ -0,0 +1,251 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Attributes/AS_Health.h"
#include "Net/UnrealNetwork.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GGA_GameplayAttributesHelper.h"
#include "GGA_AttributeSystemComponent.h"
namespace AS_Health
{
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Health, TEXT("GGF.Attribute.HealthSet.Health"), "Current health of an actor.(actor的当前生命值)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(MaxHealth, TEXT("GGF.Attribute.HealthSet.MaxHealth"), "Max health value of an actor.(actor的最大生命值)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(IncomingHealing, TEXT("GGF.Attribute.HealthSet.IncomingHealing"), "Incoming healing. This is mapped directly to +Health.(即将到来的恢复值,映射为+Health)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(IncomingDamage, TEXT("GGF.Attribute.HealthSet.IncomingDamage"), "Incoming damage. This is mapped directly to -Health(即将到来的伤害值,映射为-Health)")
}
UAS_Health::UAS_Health()
{
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Health::Health,GetHealthAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Health::MaxHealth,GetMaxHealthAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Health::IncomingHealing,GetIncomingHealingAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Health::IncomingDamage,GetIncomingDamageAttribute());
}
void UAS_Health::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, MaxHealth, COND_None, REPNOTIFY_Always);
}
void UAS_Health::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetHealthAttribute())
{
NewValue = FMath::Clamp(NewValue,0,GetMaxHealth());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePreAttributeChange(this,Attribute,NewValue);
}
}
}
bool UAS_Health::PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data)
{
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
return ASS->ReceivePreGameplayEffectExecute(this, Data);
}
}
return Super::PreGameplayEffectExecute(Data);
}
void UAS_Health::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
Super::PostAttributeChange(Attribute, OldValue, NewValue);
if (Attribute == GetMaxHealthAttribute())
{
AdjustAttributeForMaxChange(Health, OldValue, NewValue, GetHealthAttribute());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostAttributeChange(this, Attribute, OldValue, NewValue);
}
}
}
void UAS_Health::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(),0,GetMaxHealth()));
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostGameplayEffectExecute(this,Data);
}
}
}
void UAS_Health::AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue,
const FGameplayAttribute& AffectedAttributeProperty)
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
const float CurrentMaxValue = MaxAttribute.GetCurrentValue();
if (!FMath::IsNearlyEqual(CurrentMaxValue, NewMaxValue) && AbilityComp)
{
// Change current value to maintain the current Val / Max percent
const float CurrentValue = AffectedAttribute.GetCurrentValue();
float NewDelta = (CurrentMaxValue > 0.f) ? (CurrentValue * NewMaxValue / CurrentMaxValue) - CurrentValue : NewMaxValue;
AbilityComp->ApplyModToAttributeUnsafe(AffectedAttributeProperty, EGameplayModOp::Additive, NewDelta);
}
}
FGameplayAttribute UAS_Health::Bp_GetHealthAttribute()
{
return ThisClass::GetHealthAttribute();
}
float UAS_Health::Bp_GetHealth() const
{
return GetHealth();
}
void UAS_Health::Bp_SetHealth(float NewValue)
{
SetHealth(NewValue);
}
void UAS_Health::Bp_InitHealth(float NewValue)
{
InitHealth(NewValue);
}
void UAS_Health::OnRep_Health(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, Health, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetHealthAttribute(),GetHealth(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Health::Bp_GetMaxHealthAttribute()
{
return ThisClass::GetMaxHealthAttribute();
}
float UAS_Health::Bp_GetMaxHealth() const
{
return GetMaxHealth();
}
void UAS_Health::Bp_SetMaxHealth(float NewValue)
{
SetMaxHealth(NewValue);
}
void UAS_Health::Bp_InitMaxHealth(float NewValue)
{
InitMaxHealth(NewValue);
}
void UAS_Health::OnRep_MaxHealth(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, MaxHealth, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetMaxHealthAttribute(),GetMaxHealth(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Health::Bp_GetIncomingHealingAttribute()
{
return ThisClass::GetIncomingHealingAttribute();
}
float UAS_Health::Bp_GetIncomingHealing() const
{
return GetIncomingHealing();
}
void UAS_Health::Bp_SetIncomingHealing(float NewValue)
{
SetIncomingHealing(NewValue);
}
FGameplayAttribute UAS_Health::Bp_GetIncomingDamageAttribute()
{
return ThisClass::GetIncomingDamageAttribute();
}
float UAS_Health::Bp_GetIncomingDamage() const
{
return GetIncomingDamage();
}
void UAS_Health::Bp_SetIncomingDamage(float NewValue)
{
SetIncomingDamage(NewValue);
}

View File

@@ -0,0 +1,209 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Attributes/AS_Mana.h"
#include "Net/UnrealNetwork.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GGA_GameplayAttributesHelper.h"
#include "GGA_AttributeSystemComponent.h"
namespace AS_Mana
{
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Mana, TEXT("GGF.Attribute.ManaSet.Mana"), "Current mana of an actor.(actor的当前魔法值)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(MaxMana, TEXT("GGF.Attribute.ManaSet.MaxMana"), "Max mana value of an actor.(actor的最大魔法值)")
}
UAS_Mana::UAS_Mana()
{
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Mana::Mana,GetManaAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Mana::MaxMana,GetMaxManaAttribute());
}
void UAS_Mana::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, Mana, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, MaxMana, COND_None, REPNOTIFY_Always);
}
void UAS_Mana::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetManaAttribute())
{
NewValue = FMath::Clamp(NewValue,0,GetMaxMana());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePreAttributeChange(this,Attribute,NewValue);
}
}
}
bool UAS_Mana::PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data)
{
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
return ASS->ReceivePreGameplayEffectExecute(this, Data);
}
}
return Super::PreGameplayEffectExecute(Data);
}
void UAS_Mana::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
Super::PostAttributeChange(Attribute, OldValue, NewValue);
if (Attribute == GetMaxManaAttribute())
{
AdjustAttributeForMaxChange(Mana, OldValue, NewValue, GetManaAttribute());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostAttributeChange(this, Attribute, OldValue, NewValue);
}
}
}
void UAS_Mana::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetManaAttribute())
{
SetMana(FMath::Clamp(GetMana(),0,GetMaxMana()));
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostGameplayEffectExecute(this,Data);
}
}
}
void UAS_Mana::AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue,
const FGameplayAttribute& AffectedAttributeProperty)
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
const float CurrentMaxValue = MaxAttribute.GetCurrentValue();
if (!FMath::IsNearlyEqual(CurrentMaxValue, NewMaxValue) && AbilityComp)
{
// Change current value to maintain the current Val / Max percent
const float CurrentValue = AffectedAttribute.GetCurrentValue();
float NewDelta = (CurrentMaxValue > 0.f) ? (CurrentValue * NewMaxValue / CurrentMaxValue) - CurrentValue : NewMaxValue;
AbilityComp->ApplyModToAttributeUnsafe(AffectedAttributeProperty, EGameplayModOp::Additive, NewDelta);
}
}
FGameplayAttribute UAS_Mana::Bp_GetManaAttribute()
{
return ThisClass::GetManaAttribute();
}
float UAS_Mana::Bp_GetMana() const
{
return GetMana();
}
void UAS_Mana::Bp_SetMana(float NewValue)
{
SetMana(NewValue);
}
void UAS_Mana::Bp_InitMana(float NewValue)
{
InitMana(NewValue);
}
void UAS_Mana::OnRep_Mana(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, Mana, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetManaAttribute(),GetMana(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Mana::Bp_GetMaxManaAttribute()
{
return ThisClass::GetMaxManaAttribute();
}
float UAS_Mana::Bp_GetMaxMana() const
{
return GetMaxMana();
}
void UAS_Mana::Bp_SetMaxMana(float NewValue)
{
SetMaxMana(NewValue);
}
void UAS_Mana::Bp_InitMaxMana(float NewValue)
{
InitMaxMana(NewValue);
}
void UAS_Mana::OnRep_MaxMana(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, MaxMana, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetMaxManaAttribute(),GetMaxMana(),OldValue.GetCurrentValue());
}
}
}

View File

@@ -0,0 +1,251 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "Attributes/AS_Stamina.h"
#include "Net/UnrealNetwork.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "GameplayEffectExtension.h"
#include "GGA_GameplayAttributesHelper.h"
#include "GGA_AttributeSystemComponent.h"
namespace AS_Stamina
{
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Stamina, TEXT("GGF.Attribute.StaminaSet.Stamina"), "Current stamina of an actor.(actor的当前生命值)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(MaxStamina, TEXT("GGF.Attribute.StaminaSet.MaxStamina"), "Max stamina value of an actor.(actor的最大生命值)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(IncomingHealing, TEXT("GGF.Attribute.StaminaSet.IncomingHealing"), "Incoming healing. This is mapped directly to +Stamina.(即将到来的恢复值,映射为+Stamina)")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(IncomingDamage, TEXT("GGF.Attribute.StaminaSet.IncomingDamage"), "Incoming damage. This is mapped directly to -Stamina(即将到来的伤害值,映射为-Stamina)")
}
UAS_Stamina::UAS_Stamina()
{
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Stamina::Stamina,GetStaminaAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Stamina::MaxStamina,GetMaxStaminaAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Stamina::IncomingHealing,GetIncomingHealingAttribute());
UGGA_GameplayAttributesHelper::RegisterTagToAttribute(AS_Stamina::IncomingDamage,GetIncomingDamageAttribute());
}
void UAS_Stamina::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, Stamina, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(ThisClass, MaxStamina, COND_None, REPNOTIFY_Always);
}
void UAS_Stamina::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetStaminaAttribute())
{
NewValue = FMath::Clamp(NewValue,0,GetMaxStamina());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePreAttributeChange(this,Attribute,NewValue);
}
}
}
bool UAS_Stamina::PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data)
{
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
return ASS->ReceivePreGameplayEffectExecute(this, Data);
}
}
return Super::PreGameplayEffectExecute(Data);
}
void UAS_Stamina::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
Super::PostAttributeChange(Attribute, OldValue, NewValue);
if (Attribute == GetMaxStaminaAttribute())
{
AdjustAttributeForMaxChange(Stamina, OldValue, NewValue, GetStaminaAttribute());
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostAttributeChange(this, Attribute, OldValue, NewValue);
}
}
}
void UAS_Stamina::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
if (Data.EvaluatedData.Attribute == GetStaminaAttribute())
{
SetStamina(FMath::Clamp(GetStamina(),0,GetMaxStamina()));
}
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceivePostGameplayEffectExecute(this,Data);
}
}
}
void UAS_Stamina::AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue,
const FGameplayAttribute& AffectedAttributeProperty)
{
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent();
const float CurrentMaxValue = MaxAttribute.GetCurrentValue();
if (!FMath::IsNearlyEqual(CurrentMaxValue, NewMaxValue) && AbilityComp)
{
// Change current value to maintain the current Val / Max percent
const float CurrentValue = AffectedAttribute.GetCurrentValue();
float NewDelta = (CurrentMaxValue > 0.f) ? (CurrentValue * NewMaxValue / CurrentMaxValue) - CurrentValue : NewMaxValue;
AbilityComp->ApplyModToAttributeUnsafe(AffectedAttributeProperty, EGameplayModOp::Additive, NewDelta);
}
}
FGameplayAttribute UAS_Stamina::Bp_GetStaminaAttribute()
{
return ThisClass::GetStaminaAttribute();
}
float UAS_Stamina::Bp_GetStamina() const
{
return GetStamina();
}
void UAS_Stamina::Bp_SetStamina(float NewValue)
{
SetStamina(NewValue);
}
void UAS_Stamina::Bp_InitStamina(float NewValue)
{
InitStamina(NewValue);
}
void UAS_Stamina::OnRep_Stamina(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, Stamina, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetStaminaAttribute(),GetStamina(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Stamina::Bp_GetMaxStaminaAttribute()
{
return ThisClass::GetMaxStaminaAttribute();
}
float UAS_Stamina::Bp_GetMaxStamina() const
{
return GetMaxStamina();
}
void UAS_Stamina::Bp_SetMaxStamina(float NewValue)
{
SetMaxStamina(NewValue);
}
void UAS_Stamina::Bp_InitMaxStamina(float NewValue)
{
InitMaxStamina(NewValue);
}
void UAS_Stamina::OnRep_MaxStamina(const FGameplayAttributeData& OldValue)
{
GAMEPLAYATTRIBUTE_REPNOTIFY(ThisClass, MaxStamina, OldValue);
if (AActor* Actor = GetOwningActor())
{
if (UGGA_AttributeSystemComponent* ASS = Actor->FindComponentByClass<UGGA_AttributeSystemComponent>())
{
ASS->ReceiveAttributeChange(this,GetMaxStaminaAttribute(),GetMaxStamina(),OldValue.GetCurrentValue());
}
}
}
FGameplayAttribute UAS_Stamina::Bp_GetIncomingHealingAttribute()
{
return ThisClass::GetIncomingHealingAttribute();
}
float UAS_Stamina::Bp_GetIncomingHealing() const
{
return GetIncomingHealing();
}
void UAS_Stamina::Bp_SetIncomingHealing(float NewValue)
{
SetIncomingHealing(NewValue);
}
FGameplayAttribute UAS_Stamina::Bp_GetIncomingDamageAttribute()
{
return ThisClass::GetIncomingDamageAttribute();
}
float UAS_Stamina::Bp_GetIncomingDamage() const
{
return GetIncomingDamage();
}
void UAS_Stamina::Bp_SetIncomingDamage(float NewValue)
{
SetIncomingDamage(NewValue);
}

View File

@@ -0,0 +1,106 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "GGA_AttributeSystemComponent.h"
#include "AbilitySystemComponent.h"
#include "GameplayEffect.h"
#include "GameplayEffectExtension.h"
#include "GameplayEffectTypes.h"
DEFINE_LOG_CATEGORY_STATIC(LogGGA_AttributeSystem, Log, All);
// Sets default values for this component's properties
UGGA_AttributeSystemComponent::UGGA_AttributeSystemComponent()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = false;
// ...
}
bool UGGA_AttributeSystemComponent::ReceivePreGameplayEffectExecute(UAttributeSet* AttributeSet, FGameplayEffectModCallbackData& Data)
{
return true;
}
void UGGA_AttributeSystemComponent::ReceivePostGameplayEffectExecute(UAttributeSet* AttributeSet, const FGameplayEffectModCallbackData& Data)
{
if (!AttributeSet)
{
UE_LOG(LogGGA_AttributeSystem, Error, TEXT("Owner AttributeSet isn't valid"));
return;
}
FGameplayEffectContextHandle ContextHandle = Data.EffectSpec.GetContext();
FGGA_GameplayEffectModCallbackData Payload;
Payload.AttributeSet = AttributeSet;
Payload.EvaluatedData = Data.EvaluatedData;
for (const FGameplayEffectModifiedAttribute& ModifiedAttribute : Data.EffectSpec.ModifiedAttributes)
{
FGGA_ModifiedAttribute ModAttribute;
ModAttribute.Attribute = ModifiedAttribute.Attribute;
ModAttribute.TotalMagnitude = ModifiedAttribute.TotalMagnitude;
Payload.ModifiedAttributes.Add(ModAttribute);
}
Payload.SetByCallerNameMagnitudes = Data.EffectSpec.SetByCallerNameMagnitudes;
Payload.SetByCallerTagMagnitudes = Data.EffectSpec.SetByCallerTagMagnitudes;
Payload.ContextHandle = ContextHandle;
Payload.InstigatorActor = Data.EffectSpec.GetContext().GetInstigator();
Payload.TargetActor = Data.Target.AbilityActorInfo->AvatarActor.Get();;
Payload.TargetAsc = &Data.Target;
Payload.AggregatedSourceTags = *Data.EffectSpec.CapturedSourceTags.GetAggregatedTags();
Payload.AggregatedTargetTags = *Data.EffectSpec.CapturedTargetTags.GetAggregatedTags();
OnPostGameplayEffectExecute.Broadcast(Payload);
HandlePostGameplayEffectExecute(Payload);
}
void UGGA_AttributeSystemComponent::ReceivePreAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float& NewValue)
{
NewValue = HandlePreAttributeChange(AttributeSet, Attribute, NewValue);
}
void UGGA_AttributeSystemComponent::ReceivePostAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
HandlePostAttributeChange(AttributeSet, Attribute, OldValue, NewValue);
OnPostAttributeChange.Broadcast(AttributeSet, Attribute, OldValue, NewValue);
}
void UGGA_AttributeSystemComponent::ReceiveAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, const float& NewValue, const float& OldValue)
{
HandleAttributeChange(AttributeSet, Attribute, NewValue, OldValue);
OnAttributeChanged.Broadcast(AttributeSet, Attribute, NewValue, OldValue);
}
float UGGA_AttributeSystemComponent::HandlePreAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float NewValue)
{
return NewValue;
}
void UGGA_AttributeSystemComponent::HandlePostAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
}
void UGGA_AttributeSystemComponent::HandlePostGameplayEffectExecute_Implementation(const FGGA_GameplayEffectModCallbackData& Payload)
{
}
void UGGA_AttributeSystemComponent::HandleAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, const float& NewValue, const float& OldValue)
{
}
// Called when the game starts
void UGGA_AttributeSystemComponent::BeginPlay()
{
Super::BeginPlay();
// ...
}

View File

@@ -0,0 +1,3 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "GGA_GameplayAttributeStructLibrary.h"

View File

@@ -0,0 +1,235 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "GGA_GameplayAttributesHelper.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "UObject/UObjectIterator.h"
#include "AbilitySystemComponent.h"
#include "AbilitySystemGlobals.h"
TMap<FGameplayTag, FGameplayAttribute> UGGA_GameplayAttributesHelper::TagToAttributeMapping = {};
TMap<FGameplayAttribute, FGameplayTag> UGGA_GameplayAttributesHelper::AttributeToTagMapping = {};
const TArray<FGameplayAttribute>& UGGA_GameplayAttributesHelper::GetAllGameplayAttributes()
{
static TArray<FGameplayAttribute> Attributes = FindGameplayAttributes();
return Attributes;
}
TArray<FGameplayAttribute> UGGA_GameplayAttributesHelper::FindGameplayAttributes()
{
TArray<FGameplayAttribute> Attributes;
for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
{
UClass* Class = *ClassIt;
if (Class->IsChildOf(UAttributeSet::StaticClass())/*&& !Class->ClassGeneratedBy*/)
{
for (TFieldIterator<FProperty> PropertyIt(Class, EFieldIteratorFlags::ExcludeSuper); PropertyIt;
++PropertyIt)
{
FProperty* Property = *PropertyIt;
Attributes.Add(FGameplayAttribute(Property));
}
}
}
return Attributes;
}
void UGGA_GameplayAttributesHelper::RegisterTagToAttribute(FGameplayTag Tag, FGameplayAttribute Attribute)
{
if (Tag.IsValid() && Attribute.IsValid())
{
if (!TagToAttributeMapping.Contains(Tag) && !AttributeToTagMapping.Contains(Attribute))
{
TagToAttributeMapping.Emplace(Tag, Attribute);
AttributeToTagMapping.Emplace(Attribute, Tag);
}
}
}
void UGGA_GameplayAttributesHelper::UnregisterTagToAttribute(FGameplayTag Tag, FGameplayAttribute Attribute)
{
if (Tag.IsValid() && Attribute.IsValid())
{
if (TagToAttributeMapping.Contains(Tag) && AttributeToTagMapping.Contains(Attribute))
{
TagToAttributeMapping.Remove(Tag);
AttributeToTagMapping.Remove(Attribute);
}
}
}
FGameplayAttribute UGGA_GameplayAttributesHelper::TagToAttribute(FGameplayTag Tag)
{
return Tag.IsValid() && TagToAttributeMapping.Contains(Tag) ? TagToAttributeMapping[Tag] : FGameplayAttribute();
}
TArray<FGameplayAttribute> UGGA_GameplayAttributesHelper::TagsToAttributes(TArray<FGameplayTag> Tags)
{
TArray<FGameplayAttribute> Attributes;
for (int32 i = 0; i < Tags.Num(); i++)
{
if (TagToAttributeMapping.Contains(Tags[i]))
{
Attributes.Add(TagToAttributeMapping[Tags[i]]);
}
}
return Attributes;
}
FGameplayTag UGGA_GameplayAttributesHelper::AttributeToTag(FGameplayAttribute Attribute)
{
if (Attribute.IsValid())
{
if (AttributeToTagMapping.Contains(Attribute))
{
return AttributeToTagMapping[Attribute];
}
}
return FGameplayTag::EmptyTag;
}
TArray<FGameplayTag> UGGA_GameplayAttributesHelper::AttributesToTags(TArray<FGameplayAttribute> Attributes)
{
TArray<FGameplayTag> Tags;
for (int32 i = 0; i < Attributes.Num(); i++)
{
if (AttributeToTagMapping.Contains(Attributes[i]))
{
Tags.Add(AttributeToTagMapping[Attributes[i]]);
}
}
return Tags;
}
bool UGGA_GameplayAttributesHelper::IsTagOfAttribute(FGameplayTag Tag, FGameplayAttribute Attribute)
{
if (Tag.IsValid() && Attribute.IsValid())
{
if (TagToAttributeMapping.Contains(Tag))
{
return TagToAttributeMapping[Tag] == Attribute;
}
}
return false;
}
bool UGGA_GameplayAttributesHelper::IsAttributeOfTag(FGameplayAttribute Attribute, FGameplayTag Tag)
{
if (Tag.IsValid() && Attribute.IsValid())
{
if (AttributeToTagMapping.Contains(Attribute))
{
return AttributeToTagMapping[Attribute] == Tag;
}
}
return false;
}
void UGGA_GameplayAttributesHelper::SetFloatAttribute(const AActor* Actor, FGameplayAttribute Attribute, float NewValue)
{
if (UAbilitySystemComponent* Asc = UAbilitySystemGlobals::GetAbilitySystemComponentFromActor(Actor))
{
Asc->SetNumericAttributeBase(Attribute, NewValue);
}
}
void UGGA_GameplayAttributesHelper::SetFloatAttributeOnAbilitySystemComponent(UAbilitySystemComponent* AbilitySystem, FGameplayAttribute Attribute, float NewValue)
{
if (IsValid(AbilitySystem))
{
AbilitySystem->SetNumericAttributeBase(Attribute, NewValue);
}
}
float UGGA_GameplayAttributesHelper::GetFloatAttributePercentage(const AActor* Actor, FGameplayTag AttributeTagOne, FGameplayTag AttributeTagTwo, bool& bSuccessfullyFoundAttribute)
{
bool bFoundOne = true;
bool bFoundTwo = true;
float One = GetFloatAttribute(Actor, AttributeTagOne, bFoundOne);
float Two = GetFloatAttribute(Actor, AttributeTagTwo, bFoundTwo);
bSuccessfullyFoundAttribute = bFoundOne && bFoundTwo;
if (!bFoundOne || !bFoundTwo || Two == 0)
{
return 0;
}
return One / Two;
}
float UGGA_GameplayAttributesHelper::GetFloatAttributePercentage_Native(const AActor* Actor, FGameplayAttribute AttributeOne, FGameplayAttribute AttributeTwo, bool& bSuccessfullyFoundAttribute)
{
bool bFoundOne = true;
bool bFoundTwo = true;
float One = UAbilitySystemBlueprintLibrary::GetFloatAttribute(Actor, AttributeOne, bFoundOne);
float Two = UAbilitySystemBlueprintLibrary::GetFloatAttribute(Actor, AttributeTwo, bFoundTwo);
bSuccessfullyFoundAttribute = bFoundOne && bFoundTwo;
if (!bFoundOne || !bFoundTwo || Two == 0)
{
return 0;
}
return One / Two;
}
float UGGA_GameplayAttributesHelper::GetFloatAttribute(const AActor* Actor, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute)
{
return UAbilitySystemBlueprintLibrary::GetFloatAttribute(Actor, TagToAttribute(AttributeTag), bSuccessfullyFoundAttribute);
}
float UGGA_GameplayAttributesHelper::GetFloatAttributeBase(const AActor* Actor, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute)
{
return UAbilitySystemBlueprintLibrary::GetFloatAttributeBase(Actor, TagToAttribute(AttributeTag), bSuccessfullyFoundAttribute);
}
float UGGA_GameplayAttributesHelper::GetFloatAttributeFromAbilitySystemComponent(const UAbilitySystemComponent* AbilitySystem, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute)
{
return UAbilitySystemBlueprintLibrary::GetFloatAttributeFromAbilitySystemComponent(AbilitySystem, TagToAttribute(AttributeTag), bSuccessfullyFoundAttribute);
}
float UGGA_GameplayAttributesHelper::GetFloatAttributeBaseFromAbilitySystemComponent(const UAbilitySystemComponent* AbilitySystem, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute)
{
return UAbilitySystemBlueprintLibrary::GetFloatAttributeBaseFromAbilitySystemComponent(AbilitySystem, TagToAttribute(AttributeTag), bSuccessfullyFoundAttribute);
}
FString UGGA_GameplayAttributesHelper::GetDebugString()
{
FString Output;
Output.Append(TEXT("TagToAttributeMapping:\r"));
for (auto& Pair : TagToAttributeMapping)
{
Output.Append(FString::Format(TEXT("Tag:{0}->Attribute:{1} \r"), {Pair.Key.ToString(), Pair.Value.AttributeName}));
}
return Output;
}
FGameplayAttribute UGGA_GameplayAttributesHelper::GetAttributeFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData)
{
return EvaluatedData.Attribute;
}
EGameplayModOp::Type UGGA_GameplayAttributesHelper::GetModifierOpFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData)
{
return EvaluatedData.ModifierOp;
}
float UGGA_GameplayAttributesHelper::GetMagnitudeFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData)
{
return EvaluatedData.Magnitude;
}
float UGGA_GameplayAttributesHelper::GetModifiedAttributeMagnitude(const TArray<FGGA_ModifiedAttribute>& ModifiedAttributes, FGameplayAttribute InAttribute)
{
float Delta = 0.f;
for (const FGGA_ModifiedAttribute& Mod : ModifiedAttributes)
{
if (Mod.Attribute == InAttribute)
{
Delta += Mod.TotalMagnitude;
}
}
return Delta;
}

View File

@@ -0,0 +1,19 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#include "GenericGameplayAttributes.h"
#define LOCTEXT_NAMESPACE "FGenericGameplayAttributesModule"
void FGenericGameplayAttributesModule::StartupModule()
{
}
void FGenericGameplayAttributesModule::ShutdownModule()
{
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FGenericGameplayAttributesModule, GenericGameplayAttributes)

View File

@@ -0,0 +1,170 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h"
#include "AS_Combat.generated.h"
namespace AS_Combat
{
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Damage)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(DamageNegation)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(GuardDamageNegation)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(StaminaDamage)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(StaminaDamageNegation)
}
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GENERICGAMEPLAYATTRIBUTES_API UAS_Combat : public UAttributeSet
{
GENERATED_BODY()
public:
UAS_Combat();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
virtual bool PreGameplayEffectExecute(struct FGameplayEffectModCallbackData& Data) override;
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
// The damage that will apply to target
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Damage, Category = "Attribute|CombatSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData Damage{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, Damage)
// The damage reduction(percentage) for incoming health damage
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_DamageNegation, Category = "Attribute|CombatSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData DamageNegation{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, DamageNegation)
// The damage reduction(percentage) for incoming health damage while guarding
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_GuardDamageNegation, Category = "Attribute|CombatSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData GuardDamageNegation{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, GuardDamageNegation)
// The stamina damage that will apply to target
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_StaminaDamage, Category = "Attribute|CombatSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData StaminaDamage{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, StaminaDamage)
// The damage reduction(percentage) for incoming stamina damage
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_StaminaDamageNegation, Category = "Attribute|CombatSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData StaminaDamageNegation{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, StaminaDamageNegation)
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetDamageAttribute"), Category = "Attribute|CombatSet")
static FGameplayAttribute Bp_GetDamageAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetDamage"), Category = "Attribute|CombatSet")
float Bp_GetDamage() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetDamage"), Category = "Attribute|CombatSet")
void Bp_SetDamage(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitDamage"), Category = "Attribute|CombatSet")
void Bp_InitDamage(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetDamageNegationAttribute"), Category = "Attribute|CombatSet")
static FGameplayAttribute Bp_GetDamageNegationAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetDamageNegation"), Category = "Attribute|CombatSet")
float Bp_GetDamageNegation() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetDamageNegation"), Category = "Attribute|CombatSet")
void Bp_SetDamageNegation(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitDamageNegation"), Category = "Attribute|CombatSet")
void Bp_InitDamageNegation(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetGuardDamageNegationAttribute"), Category = "Attribute|CombatSet")
static FGameplayAttribute Bp_GetGuardDamageNegationAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetGuardDamageNegation"), Category = "Attribute|CombatSet")
float Bp_GetGuardDamageNegation() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetGuardDamageNegation"), Category = "Attribute|CombatSet")
void Bp_SetGuardDamageNegation(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitGuardDamageNegation"), Category = "Attribute|CombatSet")
void Bp_InitGuardDamageNegation(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetStaminaDamageAttribute"), Category = "Attribute|CombatSet")
static FGameplayAttribute Bp_GetStaminaDamageAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetStaminaDamage"), Category = "Attribute|CombatSet")
float Bp_GetStaminaDamage() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetStaminaDamage"), Category = "Attribute|CombatSet")
void Bp_SetStaminaDamage(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitStaminaDamage"), Category = "Attribute|CombatSet")
void Bp_InitStaminaDamage(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetStaminaDamageNegationAttribute"), Category = "Attribute|CombatSet")
static FGameplayAttribute Bp_GetStaminaDamageNegationAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetStaminaDamageNegation"), Category = "Attribute|CombatSet")
float Bp_GetStaminaDamageNegation() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetStaminaDamageNegation"), Category = "Attribute|CombatSet")
void Bp_SetStaminaDamageNegation(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitStaminaDamageNegation"), Category = "Attribute|CombatSet")
void Bp_InitStaminaDamageNegation(float NewValue);
protected:
/** Helper function to proportionally adjust the value of an attribute when it's associated max attribute changes. (i.e. When MaxHealth increases, Health increases by an amount that maintains the same percentage as before) */
virtual void AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty);
UFUNCTION()
virtual void OnRep_Damage(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_DamageNegation(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_GuardDamageNegation(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_StaminaDamage(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_StaminaDamageNegation(const FGameplayAttributeData& OldValue);
};

View File

@@ -0,0 +1,135 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h"
#include "AS_Health.generated.h"
namespace AS_Health
{
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Health)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(MaxHealth)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(IncomingHealing)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(IncomingDamage)
}
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GENERICGAMEPLAYATTRIBUTES_API UAS_Health : public UAttributeSet
{
GENERATED_BODY()
public:
UAS_Health();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
virtual bool PreGameplayEffectExecute(struct FGameplayEffectModCallbackData& Data) override;
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
// Current health of an actor.(actor的当前生命值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Attribute|HealthSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData Health{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, Health)
// Max health value of an actor.(actor的最大生命值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Attribute|HealthSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData MaxHealth{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, MaxHealth)
// Incoming healing. This is mapped directly to +Health.(即将到来的恢复值,映射为+Health)
UPROPERTY(BlueprintReadOnly,Category = "Attribute|HealthSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData IncomingHealing{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, IncomingHealing)
// Incoming damage. This is mapped directly to -Health(即将到来的伤害值,映射为-Health)
UPROPERTY(BlueprintReadOnly,Category = "Attribute|HealthSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData IncomingDamage{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, IncomingDamage)
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetHealthAttribute"), Category = "Attribute|HealthSet")
static FGameplayAttribute Bp_GetHealthAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetHealth"), Category = "Attribute|HealthSet")
float Bp_GetHealth() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetHealth"), Category = "Attribute|HealthSet")
void Bp_SetHealth(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitHealth"), Category = "Attribute|HealthSet")
void Bp_InitHealth(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetMaxHealthAttribute"), Category = "Attribute|HealthSet")
static FGameplayAttribute Bp_GetMaxHealthAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetMaxHealth"), Category = "Attribute|HealthSet")
float Bp_GetMaxHealth() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetMaxHealth"), Category = "Attribute|HealthSet")
void Bp_SetMaxHealth(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitMaxHealth"), Category = "Attribute|HealthSet")
void Bp_InitMaxHealth(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetIncomingHealingAttribute"), Category = "Attribute|HealthSet")
static FGameplayAttribute Bp_GetIncomingHealingAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetIncomingHealing"), Category = "Attribute|HealthSet")
float Bp_GetIncomingHealing() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetIncomingHealing"), Category = "Attribute|HealthSet")
void Bp_SetIncomingHealing(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetIncomingDamageAttribute"), Category = "Attribute|HealthSet")
static FGameplayAttribute Bp_GetIncomingDamageAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetIncomingDamage"), Category = "Attribute|HealthSet")
float Bp_GetIncomingDamage() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetIncomingDamage"), Category = "Attribute|HealthSet")
void Bp_SetIncomingDamage(float NewValue);
protected:
/** Helper function to proportionally adjust the value of an attribute when it's associated max attribute changes. (i.e. When MaxHealth increases, Health increases by an amount that maintains the same percentage as before) */
virtual void AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty);
UFUNCTION()
virtual void OnRep_Health(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldValue);
};

View File

@@ -0,0 +1,101 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h"
#include "AS_Mana.generated.h"
namespace AS_Mana
{
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Mana)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(MaxMana)
}
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GENERICGAMEPLAYATTRIBUTES_API UAS_Mana : public UAttributeSet
{
GENERATED_BODY()
public:
UAS_Mana();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
virtual bool PreGameplayEffectExecute(struct FGameplayEffectModCallbackData& Data) override;
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
// Current mana of an actor.(actor的当前魔法值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category = "Attribute|ManaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData Mana{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, Mana)
// Max mana value of an actor.(actor的最大魔法值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxMana, Category = "Attribute|ManaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData MaxMana{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, MaxMana)
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetManaAttribute"), Category = "Attribute|ManaSet")
static FGameplayAttribute Bp_GetManaAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetMana"), Category = "Attribute|ManaSet")
float Bp_GetMana() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetMana"), Category = "Attribute|ManaSet")
void Bp_SetMana(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitMana"), Category = "Attribute|ManaSet")
void Bp_InitMana(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetMaxManaAttribute"), Category = "Attribute|ManaSet")
static FGameplayAttribute Bp_GetMaxManaAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetMaxMana"), Category = "Attribute|ManaSet")
float Bp_GetMaxMana() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetMaxMana"), Category = "Attribute|ManaSet")
void Bp_SetMaxMana(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitMaxMana"), Category = "Attribute|ManaSet")
void Bp_InitMaxMana(float NewValue);
protected:
/** Helper function to proportionally adjust the value of an attribute when it's associated max attribute changes. (i.e. When MaxHealth increases, Health increases by an amount that maintains the same percentage as before) */
virtual void AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty);
UFUNCTION()
virtual void OnRep_Mana(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_MaxMana(const FGameplayAttributeData& OldValue);
};

View File

@@ -0,0 +1,135 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "NativeGameplayTags.h"
#include "AS_Stamina.generated.h"
namespace AS_Stamina
{
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Stamina)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(MaxStamina)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(IncomingHealing)
GENERICGAMEPLAYATTRIBUTES_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(IncomingDamage)
}
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GENERICGAMEPLAYATTRIBUTES_API UAS_Stamina : public UAttributeSet
{
GENERATED_BODY()
public:
UAS_Stamina();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
virtual bool PreGameplayEffectExecute(struct FGameplayEffectModCallbackData& Data) override;
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
// Current stamina of an actor.(actor的当前生命值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Stamina, Category = "Attribute|StaminaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData Stamina{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, Stamina)
// Max stamina value of an actor.(actor的最大生命值)
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxStamina, Category = "Attribute|StaminaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData MaxStamina{ 100 };
ATTRIBUTE_ACCESSORS(ThisClass, MaxStamina)
// Incoming healing. This is mapped directly to +Stamina.(即将到来的恢复值,映射为+Stamina)
UPROPERTY(BlueprintReadOnly,Category = "Attribute|StaminaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData IncomingHealing{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, IncomingHealing)
// Incoming damage. This is mapped directly to -Stamina(即将到来的伤害值,映射为-Stamina)
UPROPERTY(BlueprintReadOnly,Category = "Attribute|StaminaSet", Meta = (AllowPrivateAccess = true))
FGameplayAttributeData IncomingDamage{ 0.0 };
ATTRIBUTE_ACCESSORS(ThisClass, IncomingDamage)
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetStaminaAttribute"), Category = "Attribute|StaminaSet")
static FGameplayAttribute Bp_GetStaminaAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetStamina"), Category = "Attribute|StaminaSet")
float Bp_GetStamina() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetStamina"), Category = "Attribute|StaminaSet")
void Bp_SetStamina(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitStamina"), Category = "Attribute|StaminaSet")
void Bp_InitStamina(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetMaxStaminaAttribute"), Category = "Attribute|StaminaSet")
static FGameplayAttribute Bp_GetMaxStaminaAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetMaxStamina"), Category = "Attribute|StaminaSet")
float Bp_GetMaxStamina() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetMaxStamina"), Category = "Attribute|StaminaSet")
void Bp_SetMaxStamina(float NewValue);
UFUNCTION(BlueprintCallable,meta=(DisplayName="InitMaxStamina"), Category = "Attribute|StaminaSet")
void Bp_InitMaxStamina(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetIncomingHealingAttribute"), Category = "Attribute|StaminaSet")
static FGameplayAttribute Bp_GetIncomingHealingAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetIncomingHealing"), Category = "Attribute|StaminaSet")
float Bp_GetIncomingHealing() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetIncomingHealing"), Category = "Attribute|StaminaSet")
void Bp_SetIncomingHealing(float NewValue);
UFUNCTION(BlueprintCallable,BlueprintPure,meta=(DisplayName="GetIncomingDamageAttribute"), Category = "Attribute|StaminaSet")
static FGameplayAttribute Bp_GetIncomingDamageAttribute();
UFUNCTION(BlueprintPure,meta=(DisplayName="GetIncomingDamage"), Category = "Attribute|StaminaSet")
float Bp_GetIncomingDamage() const;
UFUNCTION(BlueprintCallable,meta=(DisplayName="SetIncomingDamage"), Category = "Attribute|StaminaSet")
void Bp_SetIncomingDamage(float NewValue);
protected:
/** Helper function to proportionally adjust the value of an attribute when it's associated max attribute changes. (i.e. When MaxHealth increases, Health increases by an amount that maintains the same percentage as before) */
virtual void AdjustAttributeForMaxChange(FGameplayAttributeData& AffectedAttribute, const FGameplayAttributeData& MaxAttribute, float NewMaxValue, const FGameplayAttribute& AffectedAttributeProperty);
UFUNCTION()
virtual void OnRep_Stamina(const FGameplayAttributeData& OldValue);
UFUNCTION()
virtual void OnRep_MaxStamina(const FGameplayAttributeData& OldValue);
};

View File

@@ -0,0 +1,98 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GGA_GameplayAttributeStructLibrary.h"
#include "Components/ActorComponent.h"
#include "GGA_AttributeSystemComponent.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FGGA_OnPostAttributeChangeSignature, UAttributeSet*, AttributeSet, const FGameplayAttribute&, Attribute, const float, OldValue, const float, NewValue);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FGGA_OnAttributeChangedSignature, UAttributeSet*, AttributeSet, const FGameplayAttribute&, Attribute, const float, NewValue, float, PrevValue);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FGGA_OnPostGameplayEffectExecuteSignature, const FGGA_GameplayEffectModCallbackData&, Data);
/**
* The main component for reacting to changes in gameplay attributes.
* 对游戏属性变化做出反应的主要组件。
*/
UCLASS(ClassGroup=(GGA), BlueprintType, Blueprintable, meta=(BlueprintSpawnableComponent))
class GENERICGAMEPLAYATTRIBUTES_API UGGA_AttributeSystemComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UGGA_AttributeSystemComponent();
void ReceivePreAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float& NewValue);
void ReceivePostAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float OldValue, float NewValue);
bool ReceivePreGameplayEffectExecute(UAttributeSet* AttributeSet, FGameplayEffectModCallbackData& Data);
void ReceivePostGameplayEffectExecute(UAttributeSet* AttributeSet, const FGameplayEffectModCallbackData& Data);
void ReceiveAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, const float& NewValue, const float& OldValue);
UPROPERTY(BlueprintAssignable, Category="Event")
FGGA_OnPostGameplayEffectExecuteSignature OnPostGameplayEffectExecute;
UPROPERTY(BlueprintAssignable, Category="Event")
FGGA_OnPostAttributeChangeSignature OnPostAttributeChange;
/**
* Called whenever an attribute changed, And this event will be fired on both serve and client.
* 属性发生任意变化后调用,此事件会在服务端和客户端都进行调用。
*/
UPROPERTY(BlueprintAssignable, Category="Event")
FGGA_OnAttributeChangedSignature OnAttributeChanged;
protected:
/**
* Called just before any modification happens to an attribute. This is lower level than PreAttributeChange/PostAttributeChange.
* There is no additional context provided here since anything can trigger this. Executed effects, duration based effects, effects being removed, immunity being applied, stacking rules changing, etc.
* This function is meant to enforce things like "Health = Clamp(Health, 0, MaxHealth)" and NOT things like "trigger this extra thing if damage is applied, etc".
* You should return your modified new value.
*
* 在对属性进行任何修改之前调用。它比 PreAttributeChange/PostAttributeChange 更底层。
* 这里没有提供额外的上下文,因为任何事情都可能触发它。已执行的效果、基于持续时间的效果、效果被移除、豁免被应用、堆叠规则改变等。
* 该函数旨在执行 “Health = Clamp(Health,0,MaxHealth) ”之类的操作,而不是 “如果受到伤害,则触发该额外操作 ”之类的操作。
* 你应返回修改后的新值。
*/
UFUNCTION(BlueprintNativeEvent, Category="GGA")
float HandlePreAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float NewValue);
virtual float HandlePreAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float NewValue);
/**
* Called just after any modification happens to an attribute.
* 在属性被修改后调用。
*/
UFUNCTION(BlueprintNativeEvent, Category="GGA")
void HandlePostAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float OldValue, float NewValue);
virtual void HandlePostAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, float OldValue, float NewValue);
/**
* Called just after a GameplayEffect is executed to modify the base value of an attribute. No more changes can be made.
* Note this is only called during an 'execute'. E.g., a modification to the 'base value' of an attribute. It is not called during an application of a GameplayEffect, such as a 5 ssecond +10 movement speed buff.
* 在执行 GameplayEffect 之后调用,以修改属性的基本值。不能再做任何更改。
* 注意只有在 “执行 ”过程中才会调用。例如,修改属性的 “基本值”。在应用 GameplayEffect如 5 秒 +10 移动速度的缓冲)时不会调用。
*/
UFUNCTION(BlueprintNativeEvent, Category="GGA")
void HandlePostGameplayEffectExecute(const FGGA_GameplayEffectModCallbackData& Payload);
virtual void HandlePostGameplayEffectExecute_Implementation(const FGGA_GameplayEffectModCallbackData& Payload);
/**
* Called whenever an attribute changed, And this event will be fired on both serve and client.
* 属性发生任意变化后调用,此事件会在服务端和客户端都进行调用。
*/
UFUNCTION(BlueprintNativeEvent, Category="GGA")
void HandleAttributeChange(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, const float& NewValue, const float& OldValue);
virtual void HandleAttributeChange_Implementation(UAttributeSet* AttributeSet, const FGameplayAttribute& Attribute, const float& NewValue, const float& OldValue);
// Called when the game starts
virtual void BeginPlay() override;
};

View File

@@ -0,0 +1,102 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "AttributeSet.h"
#include "GameplayEffectTypes.h"
#include "GGA_GameplayAttributeStructLibrary.generated.h"
USTRUCT(BlueprintType)
struct GENERICGAMEPLAYATTRIBUTES_API FGGA_ModifiedAttribute
{
GENERATED_BODY()
/** The attribute that has been modified */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="GCS")
FGameplayAttribute Attribute;
/** Total magnitude applied to that attribute */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="GCS")
float TotalMagnitude{0};
};
/**
* Information about PostGameplayEffectExecute event with related objects cached.
* 封装后的关于PostGameplayEffectExecute的回调数据并提取相关对象以方便调用。
*/
USTRUCT(BlueprintType)
struct GENERICGAMEPLAYATTRIBUTES_API FGGA_GameplayEffectModCallbackData
{
GENERATED_BODY()
/**
* The owner AttributeSet from which the event was invoked
* 变化的属性所属的AttributeSet.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TObjectPtr<UAttributeSet> AttributeSet = nullptr;
/**
* Evaluated data about this change.
* 关于这次变化的结果
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
FGameplayModifierEvaluatedData EvaluatedData;
/**
* Any modified attributes.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TArray<FGGA_ModifiedAttribute> ModifiedAttributes;
/**
* Map of set by caller magnitudes
* 执行过程中设置的临时值。
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TMap<FName, float> SetByCallerNameMagnitudes;
/**
* Map of set by caller magnitudes
* 执行过程中设置的临时值。
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TMap<FGameplayTag, float> SetByCallerTagMagnitudes;
/**
* The context of The effect spec that the mod came from
* 触发这次修改的效果实例的上下文。
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
FGameplayEffectContextHandle ContextHandle;
/**
* The instigator actor within context.
* 上下文中的Instigator Actor.
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TWeakObjectPtr<AActor> InstigatorActor = nullptr;
/**
* The target actor within context.
* 上下文中的目标Actor。
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TWeakObjectPtr<AActor> TargetActor = nullptr;
/**
* Target we intend to apply to
* 该效果的施加对象。
*/
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
TObjectPtr<UAbilitySystemComponent> TargetAsc = nullptr;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
FGameplayTagContainer AggregatedSourceTags = FGameplayTagContainer::EmptyContainer;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "GGA")
FGameplayTagContainer AggregatedTargetTags = FGameplayTagContainer::EmptyContainer;
};

View File

@@ -0,0 +1,140 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "GameplayEffectTypes.h"
#include "GameplayTagContainer.h"
#include "GGA_GameplayAttributeStructLibrary.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "GGA_GameplayAttributesHelper.generated.h"
/**
*
*/
UCLASS(meta=(DisplayName="GGA Gameplay Attribute Function Library"))
class GENERICGAMEPLAYATTRIBUTES_API UGGA_GameplayAttributesHelper : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/**
* Gets all gameplay attributes of all attribute sets (attributes declared in 'UAbilitySystemComponent' not included).
* 获取项目中的所有GameplayAttribute.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category="GGA|GameplayAttribute")
static const TArray<FGameplayAttribute>& GetAllGameplayAttributes();
private:
static TArray<FGameplayAttribute> FindGameplayAttributes();
public:
UFUNCTION(BlueprintCallable, Category = "GGA|GameplayAttribute")
static void RegisterTagToAttribute(FGameplayTag Tag, FGameplayAttribute Attribute);
UFUNCTION(BlueprintCallable, Category = "GGA|GameplayAttribute")
static void UnregisterTagToAttribute(FGameplayTag Tag, FGameplayAttribute Attribute);
/**
* Convert gameplay tag to gameplay attribute.
* @param Tag The tag to query.
* @return The gameplay attribute associated with Tag.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static FGameplayAttribute TagToAttribute(FGameplayTag Tag);
/**
* Convert gameplay tags to gameplay attributes.
* @param Tags The attribute tags to query.
* @return The gameplay attributes associated with Tags.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static TArray<FGameplayAttribute> TagsToAttributes(TArray<FGameplayTag> Tags);
/**
* Convert gameplay attribute to gameplay tag.
* @param Attribute The attribute to query.
* @return The gameplay tag associated with Attribute.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static FGameplayTag AttributeToTag(FGameplayAttribute Attribute);
/**
* Convert gameplay attributes to gameplay tags.
* @param Attributes The attributes to query.
* @return The gameplay tags associated with Attributes.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static TArray<FGameplayTag> AttributesToTags(TArray<FGameplayAttribute> Attributes);
/**
* Check if tag is associated with attribute.
* @param Tag Tag to check
* @param Attribute Attribute to check
* @return true if they are associated.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static bool IsTagOfAttribute(FGameplayTag Tag, FGameplayAttribute Attribute);
/**
* Check if attribute is associated with tag .
* @param Attribute Attribute to check
* @param Tag Tag to check
* @return true if they are associated.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static bool IsAttributeOfTag(FGameplayAttribute Attribute, FGameplayTag Tag);
/**
* Set float attribute for actor.
*/
UFUNCTION(BlueprintCallable, Category = "GGA|GameplayAttribute")
static void SetFloatAttribute(const AActor* Actor, FGameplayAttribute Attribute, float NewValue);
UFUNCTION(BlueprintCallable, Category = "GGA|GameplayAttribute", meta=(DisplayName="Set Float Attribute on Asc"))
static void SetFloatAttributeOnAbilitySystemComponent(UAbilitySystemComponent* AbilitySystem, FGameplayAttribute Attribute, float NewValue);
/** Returns the percentage of Attributes from the ability system component belonging to Actor. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute", meta=(DisplayName="Get Float Attribute Percentage(With Tag)"))
static float GetFloatAttributePercentage(const AActor* Actor, FGameplayTag AttributeTagOne, FGameplayTag AttributeTagTwo, bool& bSuccessfullyFoundAttribute);
/** Returns the percentage of Attributes from the ability system component belonging to Actor. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute", meta=(DisplayName="Get Float Attribute Percentage"))
static float GetFloatAttributePercentage_Native(const AActor* Actor, FGameplayAttribute AttributeOne, FGameplayAttribute AttributeTwo, bool& bSuccessfullyFoundAttribute);
/** Returns the value of Attribute from the ability system component belonging to Actor. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static float GetFloatAttribute(const AActor* Actor, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static float GetFloatAttributeBase(const AActor* Actor, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute);
/** Returns the value of Attribute from the ability system component AbilitySystem. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute", meta=(DisplayName="Get Float Attribute from Asc"))
static float GetFloatAttributeFromAbilitySystemComponent(const UAbilitySystemComponent* AbilitySystem, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute", meta=(DisplayName="Get Float Attribute Base from Asc"))
static float GetFloatAttributeBaseFromAbilitySystemComponent(const UAbilitySystemComponent* AbilitySystem, FGameplayTag AttributeTag, bool& bSuccessfullyFoundAttribute);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static FString GetDebugString();
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static FGameplayAttribute GetAttributeFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static EGameplayModOp::Type GetModifierOpFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData);
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "GGA|GameplayAttribute")
static float GetMagnitudeFromEvaluatedData(const FGameplayModifierEvaluatedData& EvaluatedData);
UFUNCTION(BlueprintCallable, BlueprintPure=false, Category = "GGA|GameplayAttribute")
static float GetModifiedAttributeMagnitude(const TArray<FGGA_ModifiedAttribute>& ModifiedAttributes, FGameplayAttribute InAttribute);
protected:
static TMap<FGameplayTag, FGameplayAttribute> TagToAttributeMapping;
static TMap<FGameplayAttribute, FGameplayTag> AttributeToTagMapping;
};

View File

@@ -0,0 +1,13 @@
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
class FGenericGameplayAttributesModule : public IModuleInterface
{
public:
virtual void StartupModule() override;
virtual void ShutdownModule() override;
};