UE5多人MOBA+GAS 番外篇:使用ECC(UGameplayEffectExecutionCalculation)制作伤害计算的流程
文章目录
- 定义一些属性用于作为伤害基础还有获取要打出去的伤害
- 创建一个ECC(里面执行伤害的计算)
- 在执行ECC的GE之前需要修改ECC需要调用的值,也可以不改直接计算
- 在属性中监听ECC输出的那个值然后处理扣血
定义一些属性用于作为伤害基础还有获取要打出去的伤害
伤害的传递位置和接收位置
创建一个ECC(里面执行伤害的计算)
伤害的计算
// 幻雨喜欢小猫咪#pragma once#include "CoreMinimal.h"
#include "GameplayEffectExecutionCalculation.h"
#include "ECC_AttackDamage.generated.h"/*** */
UCLASS()
class UECC_AttackDamage : public UGameplayEffectExecutionCalculation
{GENERATED_BODY()
public:UECC_AttackDamage();virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
};
在DEFINE_ATTRIBUTE_CAPTUREDEF
中第三个输入确定这个属性是来自与施法者还是目标挨打者
DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseDamage, Source, false);
最后要在这里输出伤害
OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UCAttributeSet::GetAttackDamageAttribute(), //获取到伤害属性EGameplayModOp::Additive, //加法BaseDamage //伤害));
用到的属性都走struct FDamageStatics
的流程另外在构造函数的时候也要走RelevantAttributesToCapture.Add(DamageStatics().BaseDamageDef);
的流程。
// 幻雨喜欢小猫咪#include "GAS/Executions/ECC_AttackDamage.h"#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"struct FDamageStatics
{// FGameplayEffectAttributeCaptureDefinition// 基础伤害DECLARE_ATTRIBUTE_CAPTUREDEF(BaseDamage);// 攻击百分比DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPowerCoefficient);// 物理攻击DECLARE_ATTRIBUTE_CAPTUREDEF(AttackPower);// 护甲穿透DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetration);// 护甲穿透百分比DECLARE_ATTRIBUTE_CAPTUREDEF(ArmorPenetrationPercent);// 伤害加深DECLARE_ATTRIBUTE_CAPTUREDEF(DamageAmplification);// 敌方的防御DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);// 伤害减免DECLARE_ATTRIBUTE_CAPTUREDEF(DamageReduction);FDamageStatics(){// 参数:1.属性集 2.属性名 3.目标还是自身 4.是否设置快照(true为创建时获取,false为应用时获取)DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, BaseDamage, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, AttackPowerCoefficient, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, AttackPower, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetration, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, ArmorPenetrationPercent, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageAmplification, Source, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCAttributeSet, Armor, Target, false);DEFINE_ATTRIBUTE_CAPTUREDEF(UCHeroAttributeSet, DamageReduction, Target, false);}
};
// 静态数据访问函数(单例模式)
static FDamageStatics& DamageStatics()
{static FDamageStatics Statics;return Statics;
}UECC_AttackDamage::UECC_AttackDamage()
{// 将属性添加到捕获列表中RelevantAttributesToCapture.Add(DamageStatics().BaseDamageDef);RelevantAttributesToCapture.Add(DamageStatics().AttackPowerDef);RelevantAttributesToCapture.Add(DamageStatics().AttackPowerCoefficientDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorPenetrationPercentDef);RelevantAttributesToCapture.Add(DamageStatics().DamageAmplificationDef);RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);RelevantAttributesToCapture.Add(DamageStatics().DamageReductionDef);
}void UECC_AttackDamage::Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams,FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const
{// 获取游戏效果规范和上下文const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();FGameplayEffectContextHandle EffectContextHandle = Spec.GetContext();// 获取来源和目标标签const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();// 初始化评估参数FAggregatorEvaluateParameters EvaluateParameters;EvaluateParameters.SourceTags = SourceTags;EvaluateParameters.TargetTags = TargetTags;// 计算基础伤害值float BaseDamage = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().BaseDamageDef, EvaluateParameters, BaseDamage);// 获取攻击力float AttackPower = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().AttackPowerDef, EvaluateParameters, AttackPower);// 获取护甲穿透百分比float ArmorPenetrationPercent = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationPercentDef, EvaluateParameters, ArmorPenetrationPercent);// 获取护甲穿透float ArmorPenetration = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorPenetrationDef, EvaluateParameters, ArmorPenetration);// 获取目标护甲float TargetArmor = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvaluateParameters, TargetArmor);// 获取伤害加深float DamageAmp = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageAmplificationDef, EvaluateParameters, DamageAmp);// 获取敌方的伤害减免float DamageReduction = 0.0f;ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().DamageReductionDef, EvaluateParameters, DamageReduction);// 1. 处理固定护甲穿透TargetArmor = FMath::Max(0.0f, TargetArmor - ArmorPenetration);// 2. 处理百分比护甲穿透TargetArmor = FMath::Max(0.0f, TargetArmor * (1.0f - FMath::Min(ArmorPenetrationPercent, 100.0f) / 100.0f));// 3. 计算护甲减免(计算出来的是免伤率)float ArmorReduction = TargetArmor / (TargetArmor + 100.0f);BaseDamage *= (1.0f - FMath::Min(ArmorReduction / 100.0f + DamageReduction/100.0f, 1.0f));// 4. 应用伤害加深(百分比提升)BaseDamage *= (1.0f + DamageAmp / 100.0f);// 5. 输出到AttackDamage属性if (BaseDamage > 0.0f){// 添加输出修饰符OutExecutionOutput.AddOutputModifier(FGameplayModifierEvaluatedData(UCAttributeSet::GetAttackDamageAttribute(), //获取到伤害属性EGameplayModOp::Additive, //加法BaseDamage //伤害));}
}
创建一个伤害GE,该GE只需要在执行里添加一个计算类就能调用了
在执行ECC的GE之前需要修改ECC需要调用的值,也可以不改直接计算
重新构建伤害效果结构体
// 伤害效果定义
USTRUCT(BlueprintType)
struct FGenericDamageEffectDef
{GENERATED_BODY()public:FGenericDamageEffectDef();// 伤害类型UPROPERTY(EditAnywhere)TSubclassOf<UGameplayEffect> DamageEffect;// 基础伤害大小UPROPERTY(EditAnywhere)float BaseDamage;// 属性的百分比伤害加成UPROPERTY(EditAnywhere)TMap<FGameplayTag, float> DamageTypes;// 力的大小UPROPERTY(EditAnywhere)FVector PushVelocity;
};
伤害的应用,可以创建一个ApplyDamage。
void UCGameplayAbility::ApplyDamage(AActor* TargetActor,const FGenericDamageEffectDef& Damage, int Level)
{const UAbilitySystemComponent* ASC = GetAbilitySystemComponentFromActorInfo();AActor* AvatarActor = GetAvatarActorFromActorInfo();// 创建效果上下文, 设置能力 、源对象 和 施加者FGameplayEffectContextHandle ContextHandle = ASC->MakeEffectContext();ContextHandle.SetAbility(this);ContextHandle.AddSourceObject(AvatarActor);ContextHandle.AddInstigator(AvatarActor, AvatarActor);float NewDamage = Damage.BaseDamage;// 通过属性的值来修改伤害值for(auto& Pair : Damage.DamageTypes){bool bFound ;float AttributeValue = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(Pair.Key, bFound);if (bFound){NewDamage += AttributeValue * Pair.Value / 100.f;}}// 修改一下基础伤害的值,供ECC调用GetAbilitySystemComponentFromActorInfo()->SetNumericAttributeBase(UCAttributeSet::GetBaseDamageAttribute(), NewDamage);// 创建效果Spec句柄,指定效果类、能力等级和上下文FGameplayEffectSpecHandle EffectSpecHandle = ASC->MakeOutgoingSpec(Damage.DamageEffect, Level, ContextHandle);// 在目标上应用游戏效果规范ApplyGameplayEffectSpecToTarget(GetCurrentAbilitySpecHandle(),GetCurrentActorInfo(),GetCurrentActivationInfo(),EffectSpecHandle,UAbilitySystemBlueprintLibrary::AbilityTargetDataFromActor(TargetActor));
}
也可以创建一个Make函数,只修改一下伤害(至于Level为啥没用,我还在思考这个数值用怎么样的形式好)
void UCGameplayAbility::MakeDamage(const FGenericDamageEffectDef& Damage, int Level)
{float NewDamage = Damage.BaseDamage;//通过标签设置GE使用的配置for(auto& Pair : Damage.DamageTypes){bool bFound ;float AttributeValue = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(Pair.Key, bFound);if (bFound){NewDamage += AttributeValue * Pair.Value / 100.f;}}GetAbilitySystemComponentFromActorInfo()->SetNumericAttributeBase(UCAttributeSet::GetBaseDamageAttribute(), NewDamage);
}
使用轰炸的时候作为列子,依然保持调用这个蓝图的伤害赋值,只需要调用一下Make函数对基础伤害赋值一下就好了
void UGA_GroundBlast::TargetConfirmed(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{if (!K2_CommitAbility()){K2_EndAbility();return;}// 仅在服务器上执行伤害和击退if (K2_HasAuthority()){MakeDamage(DamageEffectDef,GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));// 对目标应用伤害效果BP_ApplyGameplayEffectToTarget(TargetDataHandle, DamageEffectDef.DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));// 对目标施加推力PushTargets(TargetDataHandle, DamageEffectDef.PushVelocity);}FGameplayCueParameters BlastingGameplayCueParameters;// 设置特效的位置BlastingGameplayCueParameters.Location = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 1).ImpactPoint;// 设置特效的大小BlastingGameplayCueParameters.RawMagnitude = TargetAreaRadius;// 播放冲击特效和摄像机震动GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(BlastGameplayCueTag, BlastingGameplayCueParameters);GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(UCAbilitySystemStatics::GetCameraShakeGameplayCueTag(), BlastingGameplayCueParameters);// 播放释放动画UAnimInstance* OwnerAnimInst = GetOwnerAnimInstance();if (OwnerAnimInst){OwnerAnimInst->Montage_Play(CastMontage);}UE_LOG(LogTemp, Warning, TEXT("技能发射"));K2_EndAbility();
}
如果不调用这个蓝图的赋值Ge的函数的话,可以根据Combo的伤害赋值的方式,换一个赋值伤害的函数
void UGA_GroundBlast::TargetConfirmed(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{if (!K2_CommitAbility()){K2_EndAbility();return;}// 仅在服务器上执行伤害和击退if (K2_HasAuthority()){// 对目标应用伤害效果// BP_ApplyGameplayEffectToTarget(TargetDataHandle, DamageEffectDef.DamageEffect, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));// 获取命中目标的数量TArray<AActor*> HitActors = UAbilitySystemBlueprintLibrary::GetAllActorsFromTargetData(TargetDataHandle);for (int32 i = 0; i < HitActors.Num(); ++i){AActor* HitActor = HitActors[i];// 检查 HitResult 是否有效if (HitActor){UE_LOG(LogTemp, Warning, TEXT("命中Actor: %s"), *HitActor->GetName());ApplyDamage(HitActor, DamageEffectDef, GetAbilityLevel(CurrentSpecHandle, CurrentActorInfo));}}// ApplyDamage// 对目标施加推力PushTargets(TargetDataHandle, DamageEffectDef.PushVelocity);}FGameplayCueParameters BlastingGameplayCueParameters;// 设置特效的位置BlastingGameplayCueParameters.Location = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 1).ImpactPoint;// 设置特效的大小BlastingGameplayCueParameters.RawMagnitude = TargetAreaRadius;// 播放冲击特效和摄像机震动GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(BlastGameplayCueTag, BlastingGameplayCueParameters);GetAbilitySystemComponentFromActorInfo()->ExecuteGameplayCue(UCAbilitySystemStatics::GetCameraShakeGameplayCueTag(), BlastingGameplayCueParameters);// 播放释放动画UAnimInstance* OwnerAnimInst = GetOwnerAnimInstance();if (OwnerAnimInst){OwnerAnimInst->Montage_Play(CastMontage);}UE_LOG(LogTemp, Warning, TEXT("技能发射"));K2_EndAbility();
}
在属性中监听ECC输出的那个值然后处理扣血
伤害的接收在属性的PostGameplayEffectExecute
函数里监听ECC最后输出的属性,然后扣血。(至于为什么我的暴击放在这里这么麻烦的计算呢,我想直接在这里计算出暴击然后调个GC,应该可以吧我还没写呢)
void UCAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{// 伤害if (Data.EvaluatedData.Attribute == GetAttackDamageAttribute()){float NewDamage = GetAttackDamage();SetAttackDamage(0.f);if (NewDamage > 0.f){UAbilitySystemComponent* SourceASC = Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent();if (SourceASC){bool bFound = false;const float EffectiveCriticalHitChance = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeChanceAttribute(), bFound);if (bFound){bFound = false;if (const bool bCriticalHit = FMath::RandRange(1, 100) < EffectiveCriticalHitChance){const float CriticalStrikeDamage = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeDamageAttribute(), bFound);if (bFound){NewDamage *= (1.f + CriticalStrikeDamage / 100.f);UE_LOG(LogTemp, Warning, TEXT("暴击"))}}}}const float NewHealth = GetHealth() - NewDamage;SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));UE_LOG(LogTemp, Warning, TEXT("NewDamage: %f"), NewDamage)// Source是输出者,Target是挨打的// UE_LOG(LogTemp, Warning, TEXT("SourceASCName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->GetName())// UE_LOG(LogTemp, Warning, TEXT("TargetASCName: %s"), *UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Data.Target.AbilityActorInfo->AvatarActor.Get())->GetName())// UE_LOG(LogTemp, Warning, TEXT("SourceName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get()->GetName())// UE_LOG(LogTemp, Warning, TEXT("TargetName: %s"), *Data.Target.AbilityActorInfo->AvatarActor.Get()->GetName())}}
}
创建一个测试用的GE看看能不能行
打了几炮确实可行
在对小兵测试一下,确实是根据施法者的
我的属性值写的有点乱的说
// 幻雨喜欢小猫咪#pragma once#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
#include "CAttributeSet.generated.h"//宏的设置,编译时会默认给变量生成相应的Getter以及Setter函数,当前设置会生成四个函数,获取属性,获取值,设置值,以及初始化值。
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
/*** */
UCLASS()
class UCAttributeSet : public UAttributeSet
{GENERATED_BODY()
public:// 用于声明哪些属性需要在网络中进行复制virtual void GetLifetimeReplicatedProps( TArray< class FLifetimeProperty > & OutLifetimeProps ) const override;// 当Attribute的CurrentValue被改变之前调用virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;// 仅在instant Gameplay Effect使Attribute的BaseValue改变时触发virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData & Data) override;//virtual bool PreGameplayEffectExecute(FGameplayEffectModCallbackData& Data) override;UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health)FGameplayAttributeData Health;ATTRIBUTE_ACCESSORS(UCAttributeSet, Health)UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth)FGameplayAttributeData MaxHealth;ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxHealth)UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana)FGameplayAttributeData Mana;ATTRIBUTE_ACCESSORS(UCAttributeSet, Mana)UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxMana)FGameplayAttributeData MaxMana;ATTRIBUTE_ACCESSORS(UCAttributeSet, MaxMana)// 传值的基础伤害UPROPERTY(ReplicatedUsing = OnRep_BaseDamage)FGameplayAttributeData BaseDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, BaseDamage)// 攻击力系数UPROPERTY(ReplicatedUsing = OnRep_AttackPowerCoefficient)FGameplayAttributeData AttackPowerCoefficient;ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackPowerCoefficient)// 物理伤害UPROPERTY(ReplicatedUsing = OnRep_AttackDamage)FGameplayAttributeData AttackDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackDamage)// 法术伤害UPROPERTY(ReplicatedUsing = OnRep_MagicDamage)FGameplayAttributeData MagicDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicDamage)// 真实伤害UPROPERTY(ReplicatedUsing = OnRep_TrueDamage)FGameplayAttributeData TrueDamage;ATTRIBUTE_ACCESSORS(UCAttributeSet, TrueDamage)/** 攻击力(物理攻击强度) */UPROPERTY(ReplicatedUsing = OnRep_AttackPower)FGameplayAttributeData AttackPower;ATTRIBUTE_ACCESSORS(UCAttributeSet, AttackPower)/** 法术强度(魔法攻击强度) */UPROPERTY(ReplicatedUsing = OnRep_MagicPower)FGameplayAttributeData MagicPower;ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicPower)// 护甲值UPROPERTY(ReplicatedUsing = OnRep_Armor)FGameplayAttributeData Armor;ATTRIBUTE_ACCESSORS(UCAttributeSet, Armor)/** 法术抗性(减少受到的魔法伤害) */UPROPERTY(ReplicatedUsing = OnRep_MagicResistance)FGameplayAttributeData MagicResistance;ATTRIBUTE_ACCESSORS(UCAttributeSet, MagicResistance)// 移动速度UPROPERTY(ReplicatedUsing = OnRep_MoveSpeed)FGameplayAttributeData MoveSpeed;ATTRIBUTE_ACCESSORS(UCAttributeSet, MoveSpeed)// 移动加速度UPROPERTY(ReplicatedUsing = OnRep_MoveAcceleration)FGameplayAttributeData MoveAcceleration;ATTRIBUTE_ACCESSORS(UCAttributeSet, MoveAcceleration)UFUNCTION()void OnRep_Health(const FGameplayAttributeData& OldHealth);UFUNCTION()void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth);UFUNCTION()void OnRep_Mana(const FGameplayAttributeData& OldMana);UFUNCTION()void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana);UFUNCTION()void OnRep_AttackDamage(const FGameplayAttributeData& OldAttackDamage);UFUNCTION()void OnRep_Armor(const FGameplayAttributeData& OldArmor);UFUNCTION()void OnRep_MoveSpeed(const FGameplayAttributeData& OldMoveSpeed);UFUNCTION()void OnRep_MoveAcceleration(const FGameplayAttributeData& OldMoveAcceleration);UFUNCTION()void OnRep_AttackPower(const FGameplayAttributeData& OldAttackPower);UFUNCTION()void OnRep_MagicPower(const FGameplayAttributeData& OldMagicPower);UFUNCTION()void OnRep_MagicResistance(const FGameplayAttributeData& OldMagicResistance);UFUNCTION()void OnRep_AttackPowerCoefficient(const FGameplayAttributeData& OldAttackPowerCoefficient);UFUNCTION()void OnRep_BaseDamage(const FGameplayAttributeData& OldBaseDamage);UFUNCTION()void OnRep_MagicDamage(const FGameplayAttributeData& OldMagicDamage);UFUNCTION()void OnRep_TrueDamage(const FGameplayAttributeData& OldTrueDamage);};
// 幻雨喜欢小猫咪#include "GAS/Core/CAttributeSet.h"
#include "GAS/Core/CHeroAttributeSet.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"void UCAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Health, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Mana, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, BaseDamage, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackPowerCoefficient, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackDamage, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicDamage, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, TrueDamage, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, AttackPower, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicPower, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, Armor, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MagicResistance, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MoveSpeed, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCAttributeSet, MoveAcceleration, COND_None, REPNOTIFY_Always);
}void UCAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{if (Attribute == GetHealthAttribute()){NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());}if (Attribute == GetManaAttribute()){NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());}
}void UCAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{if (Data.EvaluatedData.Attribute == GetHealthAttribute()){SetHealth(FMath::Clamp(GetHealth(), 0, GetMaxHealth()));//SetCachedHealthPercent(GetHealth()/GetMaxHealth());}if (Data.EvaluatedData.Attribute == GetManaAttribute()){SetMana(FMath::Clamp(GetMana(), 0, GetMaxMana()));//SetCachedManaPercent(GetMana()/GetMaxMana());}// 伤害if (Data.EvaluatedData.Attribute == GetAttackDamageAttribute()){float NewDamage = GetAttackDamage();SetAttackDamage(0.f);if (NewDamage > 0.f){UAbilitySystemComponent* SourceASC = Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent();if (SourceASC){bool bFound = false;const float EffectiveCriticalHitChance = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeChanceAttribute(), bFound);if (bFound){bFound = false;if (const bool bCriticalHit = FMath::RandRange(1, 100) < EffectiveCriticalHitChance){const float CriticalStrikeDamage = SourceASC->GetGameplayAttributeValue(UCHeroAttributeSet::GetCriticalStrikeDamageAttribute(), bFound);if (bFound){NewDamage *= (1.f + CriticalStrikeDamage / 100.f);UE_LOG(LogTemp, Warning, TEXT("暴击"))}}}}const float NewHealth = GetHealth() - NewDamage;SetHealth(FMath::Clamp(NewHealth, 0.f, GetMaxHealth()));UE_LOG(LogTemp, Warning, TEXT("NewDamage: %f"), NewDamage)// Source是输出者,Target是挨打的// UE_LOG(LogTemp, Warning, TEXT("SourceASCName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->GetName())// UE_LOG(LogTemp, Warning, TEXT("TargetASCName: %s"), *UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Data.Target.AbilityActorInfo->AvatarActor.Get())->GetName())// UE_LOG(LogTemp, Warning, TEXT("SourceName: %s"), *Data.EffectSpec.GetContext().GetOriginalInstigatorAbilitySystemComponent()->AbilityActorInfo->AvatarActor.Get()->GetName())// UE_LOG(LogTemp, Warning, TEXT("TargetName: %s"), *Data.Target.AbilityActorInfo->AvatarActor.Get()->GetName())}}
}void UCAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Health, OldHealth);
}void UCAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MaxHealth, OldMaxHealth);
}void UCAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Mana, OldMana);
}void UCAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MaxMana, OldMaxMana);
}void UCAttributeSet::OnRep_AttackDamage(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackDamage, OldValue);
}void UCAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, Armor, OldValue);
}void UCAttributeSet::OnRep_MoveSpeed(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MoveSpeed, OldValue);
}void UCAttributeSet::OnRep_MoveAcceleration(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MoveAcceleration, OldValue);
}void UCAttributeSet::OnRep_AttackPower(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackPower, OldValue);
}void UCAttributeSet::OnRep_MagicPower(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicPower, OldValue);
}void UCAttributeSet::OnRep_MagicResistance(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicResistance, OldValue);
}void UCAttributeSet::OnRep_AttackPowerCoefficient(const FGameplayAttributeData& OldAttackPowerCoefficient)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, AttackPowerCoefficient, OldAttackPowerCoefficient);
}void UCAttributeSet::OnRep_BaseDamage(const FGameplayAttributeData& OldBaseDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, BaseDamage, OldBaseDamage);
}void UCAttributeSet::OnRep_MagicDamage(const FGameplayAttributeData& OldMagicDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, MagicDamage, OldMagicDamage);
}void UCAttributeSet::OnRep_TrueDamage(const FGameplayAttributeData& OldTrueDamage)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCAttributeSet, TrueDamage, OldTrueDamage);
}
// 幻雨喜欢小猫咪#pragma once#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "CHeroAttributeSet.generated.h"// 属性访问器宏,自动生成属性的Getter/Setter等
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)/*** 英雄属性集(UCHeroAttributeSet)* 用于管理英雄的成长属性、经验、等级、升级点、金币等* 支持属性同步、属性变化回调等功能*/
UCLASS()
class UCHeroAttributeSet : public UAttributeSet
{GENERATED_BODY()
public:// 属性访问器声明(自动生成标准接口)ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Intelligence) // 智力ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Strength) // 力量ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Experience) // 当前经验ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, PrevLevelExperience) // 上一级所需经验ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, NextLevelExperience) // 下一级所需经验ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Level) // 当前等级ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, UpgradePoint) // 可用升级点ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MaxLevel) // 最大等级ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MaxLevelExperience) // 满级所需经验ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Gold) // 金币ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, StrengthGrowthRate) // 力量成长率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, IntelligenceGrowthRate) // 智力成长率// 英雄的属性配置ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, AttackPowerGrowthRate) // 攻击力成长率(每等级增加的攻击力数值)ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPowerGrowthRate) // 法术强度成长率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, HealthRegen) // 生命回复速率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, HealthRegenGrowthRate) // 生命回复速率成长率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ManaRegen) // 法力回复速率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ManaRegenGrowthRate) // 法力回复速率成长率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ArmorPenetration) // 护甲穿透ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPenetration) // 法术穿透ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, ArmorPenetrationPercent)// 护甲穿透百分比ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicPenetrationPercent)// 法术穿透百分比ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, LifeSteal) // 生命偷取ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, MagicLifeSteal) // 法术吸血ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CooldownReduction) // 冷却缩减ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CriticalStrikeChance) // 暴击率ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, CriticalStrikeDamage) // 暴击伤害ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, Toughness) // 韧性ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, DamageAmplification) // 伤害加深(增加对目标造成的伤害百分比)ATTRIBUTE_ACCESSORS(UCHeroAttributeSet, DamageReduction) // 伤害减免(减少受到的伤害百分比)// 属性同步(网络复制)配置virtual void GetLifetimeReplicatedProps( TArray< class FLifetimeProperty > & OutLifetimeProps ) const override;
// private:// 智力UPROPERTY(ReplicatedUsing = OnRep_Intelligence)FGameplayAttributeData Intelligence;// 力量UPROPERTY(ReplicatedUsing = OnRep_Strength)FGameplayAttributeData Strength;// 当前经验UPROPERTY(ReplicatedUsing = OnRep_Experience)FGameplayAttributeData Experience;// 力量成长率UPROPERTY()FGameplayAttributeData StrengthGrowthRate;// 智力成长率UPROPERTY()FGameplayAttributeData IntelligenceGrowthRate;/** 攻击力成长率(每等级增加的攻击力数值) */UPROPERTY()FGameplayAttributeData AttackPowerGrowthRate;/** 法术强度成长率(每等级增加的法术强度数值) */UPROPERTY()FGameplayAttributeData MagicPowerGrowthRate;/** 生命回复速率(每秒回复的生命值) */UPROPERTY(ReplicatedUsing = OnRep_HealthRegen)FGameplayAttributeData HealthRegen;/** 生命回复速率成长率(每等级增加的生命回复速率) */UPROPERTY()FGameplayAttributeData HealthRegenGrowthRate;/** 法力回复速率(每秒回复的法力值) */UPROPERTY(ReplicatedUsing = OnRep_ManaRegen)FGameplayAttributeData ManaRegen;/** 法力回复速率成长率(每等级增加的法力回复速率) */UPROPERTY()FGameplayAttributeData ManaRegenGrowthRate;/** 护甲穿透(减少目标护甲的效果) */UPROPERTY(ReplicatedUsing = OnRep_ArmorPenetration)FGameplayAttributeData ArmorPenetration;/** 法术穿透(减少目标法术抗性的效果) */UPROPERTY(ReplicatedUsing = OnRep_MagicPenetration)FGameplayAttributeData MagicPenetration;/** 护甲穿透百分比(减少目标护甲的百分比效果) */UPROPERTY(ReplicatedUsing = OnRep_ArmorPenetrationPercent)FGameplayAttributeData ArmorPenetrationPercent;/** 法术穿透百分比(减少目标法术抗性的百分比效果) */UPROPERTY(ReplicatedUsing = OnRep_MagicPenetrationPercent)FGameplayAttributeData MagicPenetrationPercent;/** 生命偷取(造成物理伤害时回复生命值的百分比) */UPROPERTY(ReplicatedUsing = OnRep_LifeSteal)FGameplayAttributeData LifeSteal;/** 法术吸血(造成法术伤害时回复生命值的百分比) */UPROPERTY(ReplicatedUsing = OnRep_MagicLifesteal)FGameplayAttributeData MagicLifeSteal;/** 冷却缩减(减少技能冷却时间的百分比) */UPROPERTY(ReplicatedUsing = OnRep_CooldownReduction)FGameplayAttributeData CooldownReduction;/** 暴击率(普通攻击暴击的几率) */UPROPERTY(ReplicatedUsing = OnRep_CriticalStrikeChance)FGameplayAttributeData CriticalStrikeChance;// 暴击伤害UPROPERTY(ReplicatedUsing = OnRep_CriticalStrikeDamage)FGameplayAttributeData CriticalStrikeDamage;/** 韧性(减少被控制效果影响的时间) */UPROPERTY(ReplicatedUsing = OnRep_Toughness)FGameplayAttributeData Toughness;/** 伤害加深(增加对目标造成的伤害百分比) */UPROPERTY(ReplicatedUsing = OnRep_DamageAmplification)FGameplayAttributeData DamageAmplification;/** 伤害减免(减少受到的伤害百分比) */UPROPERTY(ReplicatedUsing = OnRep_DamageReduction)FGameplayAttributeData DamageReduction;// 上一级所需经验UPROPERTY(ReplicatedUsing = OnRep_PrevLevelExperience)FGameplayAttributeData PrevLevelExperience;// 下一级所需经验UPROPERTY(ReplicatedUsing = OnRep_NextLevelExperience)FGameplayAttributeData NextLevelExperience;// 当前等级UPROPERTY(ReplicatedUsing = OnRep_Level)FGameplayAttributeData Level;// 可用升级点UPROPERTY(ReplicatedUsing = OnRep_UpgradePoint)FGameplayAttributeData UpgradePoint;// 最大等级UPROPERTY(ReplicatedUsing = OnRep_MaxLevel)FGameplayAttributeData MaxLevel;// 满级所需经验UPROPERTY(ReplicatedUsing = OnRep_MaxLevelExperience)FGameplayAttributeData MaxLevelExperience;// 金币UPROPERTY(ReplicatedUsing = OnRep_Gold)FGameplayAttributeData Gold;// 属性同步回调(用于客户端属性变化通知)UFUNCTION()void OnRep_Intelligence(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_Strength(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_Experience(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_PrevLevelExperience(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_NextLevelExperience(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_Level(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_UpgradePoint(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_MaxLevel(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_MaxLevelExperience(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_Gold(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_HealthRegen(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_ManaRegen(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_ArmorPenetration(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_MagicPenetration(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_ArmorPenetrationPercent(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_MagicPenetrationPercent(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_LifeSteal(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_MagicLifeSteal(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_CooldownReduction(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_CriticalStrikeChance(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_CriticalStrikeDamage(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_Toughness(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_DamageAmplification(const FGameplayAttributeData& OldValue);UFUNCTION()void OnRep_DamageReduction(const FGameplayAttributeData& OldValue);
};
// 幻雨喜欢小猫咪#include "GAS/Core/CHeroAttributeSet.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"void UCHeroAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{Super::GetLifetimeReplicatedProps(OutLifetimeProps);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Strength, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Experience, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, PrevLevelExperience, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, NextLevelExperience, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Level, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, UpgradePoint, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MaxLevel, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MaxLevelExperience, COND_None, REPNOTIFY_Always);DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Gold, COND_None, REPNOTIFY_Always);// DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, AttackPowerGrowthRate, COND_None, REPNOTIFY_Always)// DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPowerGrowthRate, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, HealthRegen, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ManaRegen, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPenetration, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, ArmorPenetrationPercent, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicPenetrationPercent, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, LifeSteal, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, MagicLifeSteal, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CooldownReduction, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CriticalStrikeChance, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, CriticalStrikeDamage, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, Toughness, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, DamageAmplification, COND_None, REPNOTIFY_Always)DOREPLIFETIME_CONDITION_NOTIFY(UCHeroAttributeSet, DamageReduction, COND_None, REPNOTIFY_Always)
}void UCHeroAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Intelligence, OldValue);
}void UCHeroAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Strength, OldValue);
}void UCHeroAttributeSet::OnRep_Experience(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Experience, OldValue);
}void UCHeroAttributeSet::OnRep_PrevLevelExperience(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, PrevLevelExperience, OldValue);
}void UCHeroAttributeSet::OnRep_NextLevelExperience(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, NextLevelExperience, OldValue);
}void UCHeroAttributeSet::OnRep_Level(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Level, OldValue);
}void UCHeroAttributeSet::OnRep_UpgradePoint(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, UpgradePoint, OldValue);
}void UCHeroAttributeSet::OnRep_MaxLevel(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MaxLevel, OldValue);
}void UCHeroAttributeSet::OnRep_MaxLevelExperience(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MaxLevelExperience, OldValue);
}void UCHeroAttributeSet::OnRep_Gold(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Gold, OldValue);
}void UCHeroAttributeSet::OnRep_HealthRegen(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, HealthRegen, OldValue);
}void UCHeroAttributeSet::OnRep_ManaRegen(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ManaRegen, OldValue);
}void UCHeroAttributeSet::OnRep_ArmorPenetration(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ArmorPenetration, OldValue);
}void UCHeroAttributeSet::OnRep_MagicPenetration(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicPenetration, OldValue);
}void UCHeroAttributeSet::OnRep_ArmorPenetrationPercent(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, ArmorPenetrationPercent, OldValue);
}void UCHeroAttributeSet::OnRep_MagicPenetrationPercent(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicPenetrationPercent, OldValue);
}void UCHeroAttributeSet::OnRep_LifeSteal(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, LifeSteal, OldValue);
}void UCHeroAttributeSet::OnRep_MagicLifeSteal(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, MagicLifeSteal, OldValue);
}void UCHeroAttributeSet::OnRep_CooldownReduction(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CooldownReduction, OldValue);
}void UCHeroAttributeSet::OnRep_CriticalStrikeChance(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CriticalStrikeChance, OldValue);
}void UCHeroAttributeSet::OnRep_CriticalStrikeDamage(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, CriticalStrikeDamage, OldValue);
}void UCHeroAttributeSet::OnRep_Toughness(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, Toughness, OldValue);
}void UCHeroAttributeSet::OnRep_DamageAmplification(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, DamageAmplification, OldValue);
}void UCHeroAttributeSet::OnRep_DamageReduction(const FGameplayAttributeData& OldValue)
{GAMEPLAYATTRIBUTE_REPNOTIFY(UCHeroAttributeSet, DamageReduction, OldValue);
}