定义一些属性用于作为伤害基础还有获取要打出去的伤害

伤害的传递位置和接收位置
在这里插入图片描述

创建一个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);
}
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐