第一次提交
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
// ...
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
|
||||
|
||||
#include "GGA_GameplayAttributeStructLibrary.h"
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user