From 408a764560644eaa3b3dcfcca21da1fb50969b22 Mon Sep 17 00:00:00 2001 From: cit110 <840418418@qq.com> Date: Sun, 26 Apr 2026 01:30:00 +0800 Subject: [PATCH] Add PHY gameplay attributes --- Config/DefaultPHYCombat.ini | 5 + .../PHYAttributeCalculationLibrary.cpp | 74 +++++ .../Attributes/PHYAttributeSettings.cpp | 5 + .../Attributes/PHYCombatAttributeSet.cpp | 202 ++++++++++++ .../Attributes/PHYCoreAttributeSet.cpp | 62 ++++ .../Attributes/PHYElementAttributeSet.cpp | 128 ++++++++ .../PHY/Private/Characters/PHYAICharacter.cpp | 7 + .../PHYGameplayTags_Attribute.cpp | 35 ++ Source/PHY/Private/Player/PHYPlayerState.cpp | 7 + .../PHYAttributeCalculationLibrary.h | 167 ++++++++++ .../Attributes/PHYAttributeSet.h | 12 + .../Attributes/PHYAttributeSettings.h | 301 ++++++++++++++++++ .../Attributes/PHYCombatAttributeSet.h | 183 +++++++++++ .../Attributes/PHYCoreAttributeSet.h | 78 +++++ .../Attributes/PHYElementAttributeSet.h | 155 +++++++++ Source/PHY/Public/Characters/PHYAICharacter.h | 27 ++ .../GameplayTags/PHYGameplayTags_Attribute.h | 39 +++ Source/PHY/Public/PHYGameplayTags.h | 1 + Source/PHY/Public/Player/PHYPlayerState.h | 27 ++ 19 files changed, 1515 insertions(+) create mode 100644 Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.cpp create mode 100644 Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSettings.cpp create mode 100644 Source/PHY/Private/AbilitySystem/Attributes/PHYCombatAttributeSet.cpp create mode 100644 Source/PHY/Private/AbilitySystem/Attributes/PHYCoreAttributeSet.cpp create mode 100644 Source/PHY/Private/AbilitySystem/Attributes/PHYElementAttributeSet.cpp create mode 100644 Source/PHY/Private/GameplayTags/PHYGameplayTags_Attribute.cpp create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSet.h create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSettings.h create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYCombatAttributeSet.h create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYCoreAttributeSet.h create mode 100644 Source/PHY/Public/AbilitySystem/Attributes/PHYElementAttributeSet.h create mode 100644 Source/PHY/Public/GameplayTags/PHYGameplayTags_Attribute.h diff --git a/Config/DefaultPHYCombat.ini b/Config/DefaultPHYCombat.ini index 9b3f9a3..eed8fe8 100644 --- a/Config/DefaultPHYCombat.ini +++ b/Config/DefaultPHYCombat.ini @@ -2,3 +2,8 @@ bRequireServerAuthority=True bEnableClientPrediction=True DefaultHitConfirmWindow=0.200000 + +[/Script/PHY.PHYAttributeSettings] +DefaultCoreAttributes=(Strength=10.000000,Dexterity=10.000000,Vitality=10.000000,Intelligence=10.000000,Spirit=10.000000,Perception=10.000000) +CombatFormula=(MaxHealthBase=100.000000,MaxHealthVitality=18.000000,MaxHealthStrength=3.000000,MaxManaBase=60.000000,MaxManaIntelligence=12.000000,MaxManaSpirit=6.000000,MaxStaminaBase=80.000000,MaxStaminaVitality=5.000000,MaxStaminaDexterity=4.000000,PhysicalAttackPowerStrength=2.000000,PhysicalAttackPowerDexterity=0.500000,SpellPowerIntelligence=2.000000,SpellPowerSpirit=0.400000,ArmorVitality=1.200000,ArmorStrength=0.400000,MagicResistanceSpirit=1.100000,MagicResistanceIntelligence=0.300000,AccuracyBase=0.800000,AccuracyPerception=0.006000,AccuracyDexterity=0.002000,EvasionBase=0.030000,EvasionDexterity=0.003000,EvasionPerception=0.001000,CriticalChanceBase=0.050000,CriticalChanceDexterity=0.002000,CriticalChancePerception=0.001500,CriticalDamageBase=1.500000,CriticalDamageStrength=0.004000,CriticalDamagePerception=0.003000,AttackSpeedBase=1.000000,AttackSpeedDexterity=0.010000,CooldownReductionBase=0.000000,CooldownReductionIntelligence=0.001500,CooldownReductionSpirit=0.001000,BlockPowerBase=5.000000,BlockPowerStrength=1.200000,BlockPowerVitality=0.600000,GuardBreakPowerBase=5.000000,GuardBreakPowerStrength=1.100000,GuardBreakPowerPerception=0.400000,PoiseBase=20.000000,PoiseVitality=1.500000,PoiseStrength=0.500000,PoiseDamageBase=5.000000,PoiseDamageStrength=0.800000,PoiseDamageDexterity=0.200000) +ElementFormula=(DamageBonusBase=0.000000,DamageBonusIntelligence=0.001500,DamageBonusPerception=0.000500,ResistanceBase=0.020000,ResistanceSpirit=0.002000,ResistanceVitality=0.000500,PenetrationBase=0.000000,PenetrationPerception=0.001000,PenetrationIntelligence=0.000500) diff --git a/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.cpp b/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.cpp new file mode 100644 index 0000000..5ca5f65 --- /dev/null +++ b/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.cpp @@ -0,0 +1,74 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYAttributeCalculationLibrary) + +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" + +FPHYCoreAttributeSnapshot UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromDefaults() +{ + const FPHYCoreAttributeDefaults& Defaults = GetDefault()->DefaultCoreAttributes; + + FPHYCoreAttributeSnapshot Snapshot; + Snapshot.Strength = Defaults.Strength; + Snapshot.Dexterity = Defaults.Dexterity; + Snapshot.Vitality = Defaults.Vitality; + Snapshot.Intelligence = Defaults.Intelligence; + Snapshot.Spirit = Defaults.Spirit; + Snapshot.Perception = Defaults.Perception; + return Snapshot; +} + +FPHYCoreAttributeSnapshot UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromAttributeSet(const UPHYCoreAttributeSet* CoreAttributes) +{ + if (!CoreAttributes) + { + return MakeCoreSnapshotFromDefaults(); + } + + FPHYCoreAttributeSnapshot Snapshot; + Snapshot.Strength = CoreAttributes->GetStrength(); + Snapshot.Dexterity = CoreAttributes->GetDexterity(); + Snapshot.Vitality = CoreAttributes->GetVitality(); + Snapshot.Intelligence = CoreAttributes->GetIntelligence(); + Snapshot.Spirit = CoreAttributes->GetSpirit(); + Snapshot.Perception = CoreAttributes->GetPerception(); + return Snapshot; +} + +FPHYDerivedCombatAttributes UPHYAttributeCalculationLibrary::CalculateCombatAttributes(const FPHYCoreAttributeSnapshot& CoreAttributes) +{ + const FPHYCombatAttributeFormula& Formula = GetDefault()->CombatFormula; + + FPHYDerivedCombatAttributes Result; + Result.MaxHealth = Formula.MaxHealthBase + CoreAttributes.Vitality * Formula.MaxHealthVitality + CoreAttributes.Strength * Formula.MaxHealthStrength; + Result.MaxMana = Formula.MaxManaBase + CoreAttributes.Intelligence * Formula.MaxManaIntelligence + CoreAttributes.Spirit * Formula.MaxManaSpirit; + Result.MaxStamina = Formula.MaxStaminaBase + CoreAttributes.Vitality * Formula.MaxStaminaVitality + CoreAttributes.Dexterity * Formula.MaxStaminaDexterity; + Result.PhysicalAttackPower = CoreAttributes.Strength * Formula.PhysicalAttackPowerStrength + CoreAttributes.Dexterity * Formula.PhysicalAttackPowerDexterity; + Result.SpellPower = CoreAttributes.Intelligence * Formula.SpellPowerIntelligence + CoreAttributes.Spirit * Formula.SpellPowerSpirit; + Result.Armor = CoreAttributes.Vitality * Formula.ArmorVitality + CoreAttributes.Strength * Formula.ArmorStrength; + Result.MagicResistance = CoreAttributes.Spirit * Formula.MagicResistanceSpirit + CoreAttributes.Intelligence * Formula.MagicResistanceIntelligence; + Result.Accuracy = FMath::Clamp(Formula.AccuracyBase + CoreAttributes.Perception * Formula.AccuracyPerception + CoreAttributes.Dexterity * Formula.AccuracyDexterity, 0.0f, 1.0f); + Result.Evasion = FMath::Clamp(Formula.EvasionBase + CoreAttributes.Dexterity * Formula.EvasionDexterity + CoreAttributes.Perception * Formula.EvasionPerception, 0.0f, 0.6f); + Result.CriticalChance = FMath::Clamp(Formula.CriticalChanceBase + CoreAttributes.Dexterity * Formula.CriticalChanceDexterity + CoreAttributes.Perception * Formula.CriticalChancePerception, 0.0f, 0.6f); + Result.CriticalDamage = FMath::Clamp(Formula.CriticalDamageBase + CoreAttributes.Strength * Formula.CriticalDamageStrength + CoreAttributes.Perception * Formula.CriticalDamagePerception, 1.0f, 3.0f); + Result.AttackSpeed = FMath::Clamp(Formula.AttackSpeedBase + CoreAttributes.Dexterity * Formula.AttackSpeedDexterity, 0.2f, 3.0f); + Result.CooldownReduction = FMath::Clamp(Formula.CooldownReductionBase + CoreAttributes.Intelligence * Formula.CooldownReductionIntelligence + CoreAttributes.Spirit * Formula.CooldownReductionSpirit, 0.0f, 0.6f); + Result.BlockPower = Formula.BlockPowerBase + CoreAttributes.Strength * Formula.BlockPowerStrength + CoreAttributes.Vitality * Formula.BlockPowerVitality; + Result.GuardBreakPower = Formula.GuardBreakPowerBase + CoreAttributes.Strength * Formula.GuardBreakPowerStrength + CoreAttributes.Perception * Formula.GuardBreakPowerPerception; + Result.Poise = Formula.PoiseBase + CoreAttributes.Vitality * Formula.PoiseVitality + CoreAttributes.Strength * Formula.PoiseStrength; + Result.PoiseDamage = Formula.PoiseDamageBase + CoreAttributes.Strength * Formula.PoiseDamageStrength + CoreAttributes.Dexterity * Formula.PoiseDamageDexterity; + return Result; +} + +FPHYDerivedElementAttributes UPHYAttributeCalculationLibrary::CalculateElementAttributes(const FPHYCoreAttributeSnapshot& CoreAttributes) +{ + const FPHYElementAttributeFormula& Formula = GetDefault()->ElementFormula; + + FPHYDerivedElementAttributes Result; + Result.DamageBonus = FMath::Clamp(Formula.DamageBonusBase + CoreAttributes.Intelligence * Formula.DamageBonusIntelligence + CoreAttributes.Perception * Formula.DamageBonusPerception, 0.0f, 2.0f); + Result.Resistance = FMath::Clamp(Formula.ResistanceBase + CoreAttributes.Spirit * Formula.ResistanceSpirit + CoreAttributes.Vitality * Formula.ResistanceVitality, 0.0f, 0.75f); + Result.Penetration = FMath::Clamp(Formula.PenetrationBase + CoreAttributes.Perception * Formula.PenetrationPerception + CoreAttributes.Intelligence * Formula.PenetrationIntelligence, 0.0f, 0.75f); + return Result; +} diff --git a/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSettings.cpp b/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSettings.cpp new file mode 100644 index 0000000..a1933e9 --- /dev/null +++ b/Source/PHY/Private/AbilitySystem/Attributes/PHYAttributeSettings.cpp @@ -0,0 +1,5 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "AbilitySystem/Attributes/PHYAttributeSettings.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYAttributeSettings) diff --git a/Source/PHY/Private/AbilitySystem/Attributes/PHYCombatAttributeSet.cpp b/Source/PHY/Private/AbilitySystem/Attributes/PHYCombatAttributeSet.cpp new file mode 100644 index 0000000..9b3dfea --- /dev/null +++ b/Source/PHY/Private/AbilitySystem/Attributes/PHYCombatAttributeSet.cpp @@ -0,0 +1,202 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "AbilitySystem/Attributes/PHYCombatAttributeSet.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCombatAttributeSet) + +#include "AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h" +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" +#include "GameplayEffectExtension.h" +#include "Net/UnrealNetwork.h" + +UPHYCombatAttributeSet::UPHYCombatAttributeSet() +{ + InitializeFromConfiguredCoreDefaults(); +} + +void UPHYCombatAttributeSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Health, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Mana, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, MaxMana, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Stamina, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, MaxStamina, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, PhysicalAttackPower, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, SpellPower, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Armor, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, MagicResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Accuracy, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Evasion, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, CriticalChance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, CriticalDamage, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, AttackSpeed, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, CooldownReduction, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, BlockPower, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, GuardBreakPower, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, Poise, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCombatAttributeSet, PoiseDamage, COND_None, REPNOTIFY_Always); +} + +void UPHYCombatAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) +{ + Super::PreAttributeChange(Attribute, NewValue); + + if (Attribute == GetHealthAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxHealth()); + } + else if (Attribute == GetManaAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxMana()); + } + else if (Attribute == GetStaminaAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, GetMaxStamina()); + } + else if (Attribute == GetMaxHealthAttribute() || Attribute == GetMaxManaAttribute() || Attribute == GetMaxStaminaAttribute()) + { + NewValue = FMath::Max(NewValue, 1.0f); + } + else if (Attribute == GetAccuracyAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, 1.0f); + } + else if (Attribute == GetEvasionAttribute() || Attribute == GetCriticalChanceAttribute() || Attribute == GetCooldownReductionAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, 0.6f); + } + else if (Attribute == GetCriticalDamageAttribute()) + { + NewValue = FMath::Clamp(NewValue, 1.0f, 5.0f); + } + else if (Attribute == GetAttackSpeedAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.1f, 5.0f); + } + else + { + NewValue = FMath::Max(NewValue, 0.0f); + } +} + +void UPHYCombatAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) +{ + Super::PostGameplayEffectExecute(Data); + + if (Data.EvaluatedData.Attribute == GetHealthAttribute()) + { + SetHealth(FMath::Clamp(GetHealth(), 0.0f, GetMaxHealth())); + } + else if (Data.EvaluatedData.Attribute == GetManaAttribute()) + { + SetMana(FMath::Clamp(GetMana(), 0.0f, GetMaxMana())); + } + else if (Data.EvaluatedData.Attribute == GetStaminaAttribute()) + { + SetStamina(FMath::Clamp(GetStamina(), 0.0f, GetMaxStamina())); + } +} + +void UPHYCombatAttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) +{ + Super::PostAttributeChange(Attribute, OldValue, NewValue); + + if (Attribute == GetMaxHealthAttribute() && GetHealth() > NewValue) + { + SetHealth(NewValue); + } + else if (Attribute == GetMaxManaAttribute() && GetMana() > NewValue) + { + SetMana(NewValue); + } + else if (Attribute == GetMaxStaminaAttribute() && GetStamina() > NewValue) + { + SetStamina(NewValue); + } +} + +void UPHYCombatAttributeSet::InitializeFromConfiguredCoreDefaults() +{ + const FPHYCoreAttributeSnapshot Snapshot = UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromDefaults(); + const FPHYDerivedCombatAttributes Derived = UPHYAttributeCalculationLibrary::CalculateCombatAttributes(Snapshot); + + InitMaxHealth(Derived.MaxHealth); + InitHealth(Derived.MaxHealth); + InitMaxMana(Derived.MaxMana); + InitMana(Derived.MaxMana); + InitMaxStamina(Derived.MaxStamina); + InitStamina(Derived.MaxStamina); + InitPhysicalAttackPower(Derived.PhysicalAttackPower); + InitSpellPower(Derived.SpellPower); + InitArmor(Derived.Armor); + InitMagicResistance(Derived.MagicResistance); + InitAccuracy(Derived.Accuracy); + InitEvasion(Derived.Evasion); + InitCriticalChance(Derived.CriticalChance); + InitCriticalDamage(Derived.CriticalDamage); + InitAttackSpeed(Derived.AttackSpeed); + InitCooldownReduction(Derived.CooldownReduction); + InitBlockPower(Derived.BlockPower); + InitGuardBreakPower(Derived.GuardBreakPower); + InitPoise(Derived.Poise); + InitPoiseDamage(Derived.PoiseDamage); +} + +void UPHYCombatAttributeSet::InitializeFromCoreAttributes(const UPHYCoreAttributeSet* CoreAttributes) +{ + const FPHYCoreAttributeSnapshot Snapshot = UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromAttributeSet(CoreAttributes); + const FPHYDerivedCombatAttributes Derived = UPHYAttributeCalculationLibrary::CalculateCombatAttributes(Snapshot); + + SetMaxHealth(Derived.MaxHealth); + SetHealth(FMath::Clamp(GetHealth(), 0.0f, Derived.MaxHealth)); + SetMaxMana(Derived.MaxMana); + SetMana(FMath::Clamp(GetMana(), 0.0f, Derived.MaxMana)); + SetMaxStamina(Derived.MaxStamina); + SetStamina(FMath::Clamp(GetStamina(), 0.0f, Derived.MaxStamina)); + SetPhysicalAttackPower(Derived.PhysicalAttackPower); + SetSpellPower(Derived.SpellPower); + SetArmor(Derived.Armor); + SetMagicResistance(Derived.MagicResistance); + SetAccuracy(Derived.Accuracy); + SetEvasion(Derived.Evasion); + SetCriticalChance(Derived.CriticalChance); + SetCriticalDamage(Derived.CriticalDamage); + SetAttackSpeed(Derived.AttackSpeed); + SetCooldownReduction(Derived.CooldownReduction); + SetBlockPower(Derived.BlockPower); + SetGuardBreakPower(Derived.GuardBreakPower); + SetPoise(Derived.Poise); + SetPoiseDamage(Derived.PoiseDamage); +} + +#define PHY_COMBAT_REPNOTIFY(PropertyName) \ + void UPHYCombatAttributeSet::OnRep_##PropertyName(const FGameplayAttributeData& OldValue) \ + { \ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCombatAttributeSet, PropertyName, OldValue); \ + } + +PHY_COMBAT_REPNOTIFY(Health) +PHY_COMBAT_REPNOTIFY(MaxHealth) +PHY_COMBAT_REPNOTIFY(Mana) +PHY_COMBAT_REPNOTIFY(MaxMana) +PHY_COMBAT_REPNOTIFY(Stamina) +PHY_COMBAT_REPNOTIFY(MaxStamina) +PHY_COMBAT_REPNOTIFY(PhysicalAttackPower) +PHY_COMBAT_REPNOTIFY(SpellPower) +PHY_COMBAT_REPNOTIFY(Armor) +PHY_COMBAT_REPNOTIFY(MagicResistance) +PHY_COMBAT_REPNOTIFY(Accuracy) +PHY_COMBAT_REPNOTIFY(Evasion) +PHY_COMBAT_REPNOTIFY(CriticalChance) +PHY_COMBAT_REPNOTIFY(CriticalDamage) +PHY_COMBAT_REPNOTIFY(AttackSpeed) +PHY_COMBAT_REPNOTIFY(CooldownReduction) +PHY_COMBAT_REPNOTIFY(BlockPower) +PHY_COMBAT_REPNOTIFY(GuardBreakPower) +PHY_COMBAT_REPNOTIFY(Poise) +PHY_COMBAT_REPNOTIFY(PoiseDamage) + +#undef PHY_COMBAT_REPNOTIFY diff --git a/Source/PHY/Private/AbilitySystem/Attributes/PHYCoreAttributeSet.cpp b/Source/PHY/Private/AbilitySystem/Attributes/PHYCoreAttributeSet.cpp new file mode 100644 index 0000000..7324f33 --- /dev/null +++ b/Source/PHY/Private/AbilitySystem/Attributes/PHYCoreAttributeSet.cpp @@ -0,0 +1,62 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYCoreAttributeSet) + +#include "AbilitySystem/Attributes/PHYAttributeSettings.h" +#include "Net/UnrealNetwork.h" + +UPHYCoreAttributeSet::UPHYCoreAttributeSet() +{ + const FPHYCoreAttributeDefaults& Defaults = GetDefault()->DefaultCoreAttributes; + + InitStrength(Defaults.Strength); + InitDexterity(Defaults.Dexterity); + InitVitality(Defaults.Vitality); + InitIntelligence(Defaults.Intelligence); + InitSpirit(Defaults.Spirit); + InitPerception(Defaults.Perception); +} + +void UPHYCoreAttributeSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Strength, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Dexterity, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Vitality, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Intelligence, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Spirit, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYCoreAttributeSet, Perception, COND_None, REPNOTIFY_Always); +} + +void UPHYCoreAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Strength, OldValue); +} + +void UPHYCoreAttributeSet::OnRep_Dexterity(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Dexterity, OldValue); +} + +void UPHYCoreAttributeSet::OnRep_Vitality(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Vitality, OldValue); +} + +void UPHYCoreAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Intelligence, OldValue); +} + +void UPHYCoreAttributeSet::OnRep_Spirit(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Spirit, OldValue); +} + +void UPHYCoreAttributeSet::OnRep_Perception(const FGameplayAttributeData& OldValue) +{ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYCoreAttributeSet, Perception, OldValue); +} diff --git a/Source/PHY/Private/AbilitySystem/Attributes/PHYElementAttributeSet.cpp b/Source/PHY/Private/AbilitySystem/Attributes/PHYElementAttributeSet.cpp new file mode 100644 index 0000000..e9bda4b --- /dev/null +++ b/Source/PHY/Private/AbilitySystem/Attributes/PHYElementAttributeSet.cpp @@ -0,0 +1,128 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "AbilitySystem/Attributes/PHYElementAttributeSet.h" + +#include UE_INLINE_GENERATED_CPP_BY_NAME(PHYElementAttributeSet) + +#include "AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h" +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" +#include "Net/UnrealNetwork.h" + +UPHYElementAttributeSet::UPHYElementAttributeSet() +{ + InitializeFromConfiguredCoreDefaults(); +} + +void UPHYElementAttributeSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const +{ + Super::GetLifetimeReplicatedProps(OutLifetimeProps); + + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, FireDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, WaterDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, IceDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, LightningDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, EarthDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, WindDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, LightDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, DarkDamageBonus, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, FireResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, WaterResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, IceResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, LightningResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, EarthResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, WindResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, LightResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, DarkResistance, COND_None, REPNOTIFY_Always); + DOREPLIFETIME_CONDITION_NOTIFY(UPHYElementAttributeSet, ElementPenetration, COND_None, REPNOTIFY_Always); +} + +void UPHYElementAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) +{ + Super::PreAttributeChange(Attribute, NewValue); + + if (Attribute == GetFireResistanceAttribute() || Attribute == GetWaterResistanceAttribute() || + Attribute == GetIceResistanceAttribute() || Attribute == GetLightningResistanceAttribute() || + Attribute == GetEarthResistanceAttribute() || Attribute == GetWindResistanceAttribute() || + Attribute == GetLightResistanceAttribute() || Attribute == GetDarkResistanceAttribute() || + Attribute == GetElementPenetrationAttribute()) + { + NewValue = FMath::Clamp(NewValue, 0.0f, 0.75f); + return; + } + + NewValue = FMath::Clamp(NewValue, 0.0f, 2.0f); +} + +void UPHYElementAttributeSet::InitializeFromConfiguredCoreDefaults() +{ + const FPHYCoreAttributeSnapshot Snapshot = UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromDefaults(); + const FPHYDerivedElementAttributes Derived = UPHYAttributeCalculationLibrary::CalculateElementAttributes(Snapshot); + + InitFireDamageBonus(Derived.DamageBonus); + InitWaterDamageBonus(Derived.DamageBonus); + InitIceDamageBonus(Derived.DamageBonus); + InitLightningDamageBonus(Derived.DamageBonus); + InitEarthDamageBonus(Derived.DamageBonus); + InitWindDamageBonus(Derived.DamageBonus); + InitLightDamageBonus(Derived.DamageBonus); + InitDarkDamageBonus(Derived.DamageBonus); + InitFireResistance(Derived.Resistance); + InitWaterResistance(Derived.Resistance); + InitIceResistance(Derived.Resistance); + InitLightningResistance(Derived.Resistance); + InitEarthResistance(Derived.Resistance); + InitWindResistance(Derived.Resistance); + InitLightResistance(Derived.Resistance); + InitDarkResistance(Derived.Resistance); + InitElementPenetration(Derived.Penetration); +} + +void UPHYElementAttributeSet::InitializeFromCoreAttributes(const UPHYCoreAttributeSet* CoreAttributes) +{ + const FPHYCoreAttributeSnapshot Snapshot = UPHYAttributeCalculationLibrary::MakeCoreSnapshotFromAttributeSet(CoreAttributes); + const FPHYDerivedElementAttributes Derived = UPHYAttributeCalculationLibrary::CalculateElementAttributes(Snapshot); + + SetFireDamageBonus(Derived.DamageBonus); + SetWaterDamageBonus(Derived.DamageBonus); + SetIceDamageBonus(Derived.DamageBonus); + SetLightningDamageBonus(Derived.DamageBonus); + SetEarthDamageBonus(Derived.DamageBonus); + SetWindDamageBonus(Derived.DamageBonus); + SetLightDamageBonus(Derived.DamageBonus); + SetDarkDamageBonus(Derived.DamageBonus); + SetFireResistance(Derived.Resistance); + SetWaterResistance(Derived.Resistance); + SetIceResistance(Derived.Resistance); + SetLightningResistance(Derived.Resistance); + SetEarthResistance(Derived.Resistance); + SetWindResistance(Derived.Resistance); + SetLightResistance(Derived.Resistance); + SetDarkResistance(Derived.Resistance); + SetElementPenetration(Derived.Penetration); +} + +#define PHY_ELEMENT_REPNOTIFY(PropertyName) \ + void UPHYElementAttributeSet::OnRep_##PropertyName(const FGameplayAttributeData& OldValue) \ + { \ + GAMEPLAYATTRIBUTE_REPNOTIFY(UPHYElementAttributeSet, PropertyName, OldValue); \ + } + +PHY_ELEMENT_REPNOTIFY(FireDamageBonus) +PHY_ELEMENT_REPNOTIFY(WaterDamageBonus) +PHY_ELEMENT_REPNOTIFY(IceDamageBonus) +PHY_ELEMENT_REPNOTIFY(LightningDamageBonus) +PHY_ELEMENT_REPNOTIFY(EarthDamageBonus) +PHY_ELEMENT_REPNOTIFY(WindDamageBonus) +PHY_ELEMENT_REPNOTIFY(LightDamageBonus) +PHY_ELEMENT_REPNOTIFY(DarkDamageBonus) +PHY_ELEMENT_REPNOTIFY(FireResistance) +PHY_ELEMENT_REPNOTIFY(WaterResistance) +PHY_ELEMENT_REPNOTIFY(IceResistance) +PHY_ELEMENT_REPNOTIFY(LightningResistance) +PHY_ELEMENT_REPNOTIFY(EarthResistance) +PHY_ELEMENT_REPNOTIFY(WindResistance) +PHY_ELEMENT_REPNOTIFY(LightResistance) +PHY_ELEMENT_REPNOTIFY(DarkResistance) +PHY_ELEMENT_REPNOTIFY(ElementPenetration) + +#undef PHY_ELEMENT_REPNOTIFY diff --git a/Source/PHY/Private/Characters/PHYAICharacter.cpp b/Source/PHY/Private/Characters/PHYAICharacter.cpp index 9a0a539..18a5fac 100644 --- a/Source/PHY/Private/Characters/PHYAICharacter.cpp +++ b/Source/PHY/Private/Characters/PHYAICharacter.cpp @@ -4,6 +4,9 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(PHYAICharacter) +#include "AbilitySystem/Attributes/PHYCombatAttributeSet.h" +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" +#include "AbilitySystem/Attributes/PHYElementAttributeSet.h" #include "Class/PHYClassComponent.h" #include "Class/PHYClassSettings.h" #include "GGA_AbilitySystemComponent.h" @@ -15,6 +18,10 @@ APHYAICharacter::APHYAICharacter(const FObjectInitializer& ObjectInitializer) AbilitySystemComponent->SetIsReplicated(true); AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); + CoreAttributeSet = CreateDefaultSubobject(TEXT("CoreAttributeSet")); + CombatAttributeSet = CreateDefaultSubobject(TEXT("CombatAttributeSet")); + ElementAttributeSet = CreateDefaultSubobject(TEXT("ElementAttributeSet")); + ClassComponent = CreateDefaultSubobject(TEXT("ClassComponent")); ClassComponent->SetClassTag(GetDefault()->DefaultAIClassTag); } diff --git a/Source/PHY/Private/GameplayTags/PHYGameplayTags_Attribute.cpp b/Source/PHY/Private/GameplayTags/PHYGameplayTags_Attribute.cpp new file mode 100644 index 0000000..7d43c33 --- /dev/null +++ b/Source/PHY/Private/GameplayTags/PHYGameplayTags_Attribute.cpp @@ -0,0 +1,35 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "GameplayTags/PHYGameplayTags_Attribute.h" + +// 属性 Tag 只表达领域和分类,具体属性读写仍通过 GAS AttributeSet 完成。 +namespace PHYGameplayTags +{ + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core, "Attribute.Core"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Strength, "Attribute.Core.Strength"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Dexterity, "Attribute.Core.Dexterity"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Vitality, "Attribute.Core.Vitality"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Intelligence, "Attribute.Core.Intelligence"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Spirit, "Attribute.Core.Spirit"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Core_Perception, "Attribute.Core.Perception"); + + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat, "Attribute.Combat"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat_Health, "Attribute.Combat.Health"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat_Mana, "Attribute.Combat.Mana"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat_Stamina, "Attribute.Combat.Stamina"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat_Offense, "Attribute.Combat.Offense"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Combat_Defense, "Attribute.Combat.Defense"); + + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element, "Attribute.Element"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Fire, "Attribute.Element.Fire"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Water, "Attribute.Element.Water"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Ice, "Attribute.Element.Ice"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Lightning, "Attribute.Element.Lightning"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Earth, "Attribute.Element.Earth"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Wind, "Attribute.Element.Wind"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Light, "Attribute.Element.Light"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Dark, "Attribute.Element.Dark"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_DamageBonus, "Attribute.Element.DamageBonus"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Resistance, "Attribute.Element.Resistance"); + UE_DEFINE_GAMEPLAY_TAG(Attribute_Element_Penetration, "Attribute.Element.Penetration"); +} diff --git a/Source/PHY/Private/Player/PHYPlayerState.cpp b/Source/PHY/Private/Player/PHYPlayerState.cpp index 970f274..0d703c5 100644 --- a/Source/PHY/Private/Player/PHYPlayerState.cpp +++ b/Source/PHY/Private/Player/PHYPlayerState.cpp @@ -4,6 +4,9 @@ #include UE_INLINE_GENERATED_CPP_BY_NAME(PHYPlayerState) +#include "AbilitySystem/Attributes/PHYCombatAttributeSet.h" +#include "AbilitySystem/Attributes/PHYCoreAttributeSet.h" +#include "AbilitySystem/Attributes/PHYElementAttributeSet.h" #include "Class/PHYClassComponent.h" #include "Class/PHYClassSettings.h" #include "GGA_AbilitySystemComponent.h" @@ -17,6 +20,10 @@ APHYPlayerState::APHYPlayerState(const FObjectInitializer& ObjectInitializer) AbilitySystemComponent->SetIsReplicated(true); AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed); + CoreAttributeSet = CreateDefaultSubobject(TEXT("CoreAttributeSet")); + CombatAttributeSet = CreateDefaultSubobject(TEXT("CombatAttributeSet")); + ElementAttributeSet = CreateDefaultSubobject(TEXT("ElementAttributeSet")); + ClassComponent = CreateDefaultSubobject(TEXT("ClassComponent")); ClassComponent->SetClassTag(GetDefault()->DefaultPlayerClassTag); } diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h new file mode 100644 index 0000000..fdaddd8 --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeCalculationLibrary.h @@ -0,0 +1,167 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintFunctionLibrary.h" +#include "AbilitySystem/Attributes/PHYAttributeSettings.h" +#include "PHYAttributeCalculationLibrary.generated.h" + +class UPHYCoreAttributeSet; + +/** + * @brief 基础属性输入快照,用于 C++、GE 和后续 MMC 共享公式。 + */ +USTRUCT(BlueprintType) +struct FPHYCoreAttributeSnapshot +{ + GENERATED_BODY() + + /** @brief 力量。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Strength = 0.0f; + + /** @brief 灵巧。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Dexterity = 0.0f; + + /** @brief 体魄。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Vitality = 0.0f; + + /** @brief 智力。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Intelligence = 0.0f; + + /** @brief 精神。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Spirit = 0.0f; + + /** @brief 感知。 */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="PHY|Attributes|Core") + float Perception = 0.0f; +}; + +/** + * @brief 次级战斗属性计算结果。 + */ +USTRUCT(BlueprintType) +struct FPHYDerivedCombatAttributes +{ + GENERATED_BODY() + + /** @brief 推导后的生命上限。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float MaxHealth = 0.0f; + + /** @brief 推导后的法力上限。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float MaxMana = 0.0f; + + /** @brief 推导后的耐力上限。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float MaxStamina = 0.0f; + + /** @brief 推导后的物理攻击强度。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float PhysicalAttackPower = 0.0f; + + /** @brief 推导后的法术强度。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float SpellPower = 0.0f; + + /** @brief 推导后的护甲。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float Armor = 0.0f; + + /** @brief 推导后的魔法抗性。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float MagicResistance = 0.0f; + + /** @brief 推导后的命中率。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float Accuracy = 0.0f; + + /** @brief 推导后的闪避率。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float Evasion = 0.0f; + + /** @brief 推导后的暴击率。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float CriticalChance = 0.0f; + + /** @brief 推导后的暴击伤害倍率。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float CriticalDamage = 0.0f; + + /** @brief 推导后的攻击速度倍率。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float AttackSpeed = 0.0f; + + /** @brief 推导后的冷却缩减比例。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float CooldownReduction = 0.0f; + + /** @brief 推导后的格挡强度。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float BlockPower = 0.0f; + + /** @brief 推导后的破防强度。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float GuardBreakPower = 0.0f; + + /** @brief 推导后的韧性。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float Poise = 0.0f; + + /** @brief 推导后的韧性伤害。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Combat") + float PoiseDamage = 0.0f; +}; + +/** + * @brief 元素属性计算结果。 + */ +USTRUCT(BlueprintType) +struct FPHYDerivedElementAttributes +{ + GENERATED_BODY() + + /** @brief 推导后的通用元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Element") + float DamageBonus = 0.0f; + + /** @brief 推导后的通用元素抗性。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Element") + float Resistance = 0.0f; + + /** @brief 推导后的通用元素穿透。 */ + UPROPERTY(BlueprintReadOnly, Category="PHY|Attributes|Element") + float Penetration = 0.0f; +}; + +/** + * @brief 属性公式函数库,避免首期依赖复杂 MMC 资产。 + */ +UCLASS() +class PHY_API UPHYAttributeCalculationLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_BODY() + +public: + /** @brief 从配置默认值创建基础属性快照。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + static FPHYCoreAttributeSnapshot MakeCoreSnapshotFromDefaults(); + + /** @brief 从基础属性集创建基础属性快照。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + static FPHYCoreAttributeSnapshot MakeCoreSnapshotFromAttributeSet(const UPHYCoreAttributeSet* CoreAttributes); + + /** @brief 根据基础属性和配置公式计算次级战斗属性。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + static FPHYDerivedCombatAttributes CalculateCombatAttributes(const FPHYCoreAttributeSnapshot& CoreAttributes); + + /** @brief 根据基础属性和配置公式计算通用元素属性。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + static FPHYDerivedElementAttributes CalculateElementAttributes(const FPHYCoreAttributeSnapshot& CoreAttributes); +}; diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSet.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSet.h new file mode 100644 index 0000000..7a3a308 --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSet.h @@ -0,0 +1,12 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "AbilitySystemComponent.h" +#include "AttributeSet.h" + +#define PHY_ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \ + GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \ + GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \ + GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \ + GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSettings.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSettings.h new file mode 100644 index 0000000..ff851a2 --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYAttributeSettings.h @@ -0,0 +1,301 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "UObject/Object.h" +#include "PHYAttributeSettings.generated.h" + +/** + * @brief 基础属性初始值。 + */ +USTRUCT(BlueprintType) +struct FPHYCoreAttributeDefaults +{ + GENERATED_BODY() + + /** @brief 力量初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Strength = 10.0f; + + /** @brief 灵巧初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Dexterity = 10.0f; + + /** @brief 体魄初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Vitality = 10.0f; + + /** @brief 智力初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Intelligence = 10.0f; + + /** @brief 精神初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Spirit = 10.0f; + + /** @brief 感知初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Core") + float Perception = 10.0f; +}; + +/** + * @brief 次级战斗属性公式系数。 + */ +USTRUCT(BlueprintType) +struct FPHYCombatAttributeFormula +{ + GENERATED_BODY() + + /** @brief 生命上限基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxHealthBase = 100.0f; + + /** @brief 每点体魄提供的生命上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxHealthVitality = 18.0f; + + /** @brief 每点力量提供的生命上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxHealthStrength = 3.0f; + + /** @brief 法力上限基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxManaBase = 60.0f; + + /** @brief 每点智力提供的法力上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxManaIntelligence = 12.0f; + + /** @brief 每点精神提供的法力上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxManaSpirit = 6.0f; + + /** @brief 耐力上限基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxStaminaBase = 80.0f; + + /** @brief 每点体魄提供的耐力上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxStaminaVitality = 5.0f; + + /** @brief 每点灵巧提供的耐力上限。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MaxStaminaDexterity = 4.0f; + + /** @brief 力量对物理攻击的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PhysicalAttackPowerStrength = 2.0f; + + /** @brief 灵巧对物理攻击的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PhysicalAttackPowerDexterity = 0.5f; + + /** @brief 智力对法术强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float SpellPowerIntelligence = 2.0f; + + /** @brief 精神对法术强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float SpellPowerSpirit = 0.4f; + + /** @brief 体魄对护甲的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float ArmorVitality = 1.2f; + + /** @brief 力量对护甲的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float ArmorStrength = 0.4f; + + /** @brief 精神对魔法抗性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MagicResistanceSpirit = 1.1f; + + /** @brief 智力对魔法抗性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float MagicResistanceIntelligence = 0.3f; + + /** @brief 命中基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float AccuracyBase = 0.8f; + + /** @brief 感知对命中的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float AccuracyPerception = 0.006f; + + /** @brief 灵巧对命中的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float AccuracyDexterity = 0.002f; + + /** @brief 闪避基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float EvasionBase = 0.03f; + + /** @brief 灵巧对闪避的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float EvasionDexterity = 0.003f; + + /** @brief 感知对闪避的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float EvasionPerception = 0.001f; + + /** @brief 暴击率基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalChanceBase = 0.05f; + + /** @brief 灵巧对暴击率的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalChanceDexterity = 0.002f; + + /** @brief 感知对暴击率的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalChancePerception = 0.0015f; + + /** @brief 暴击伤害基础倍率。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalDamageBase = 1.5f; + + /** @brief 力量对暴击伤害的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalDamageStrength = 0.004f; + + /** @brief 感知对暴击伤害的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CriticalDamagePerception = 0.003f; + + /** @brief 攻击速度基础倍率。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float AttackSpeedBase = 1.0f; + + /** @brief 灵巧对攻击速度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float AttackSpeedDexterity = 0.01f; + + /** @brief 冷却缩减基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CooldownReductionBase = 0.0f; + + /** @brief 智力对冷却缩减的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CooldownReductionIntelligence = 0.0015f; + + /** @brief 精神对冷却缩减的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float CooldownReductionSpirit = 0.001f; + + /** @brief 格挡强度基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float BlockPowerBase = 5.0f; + + /** @brief 力量对格挡强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float BlockPowerStrength = 1.2f; + + /** @brief 体魄对格挡强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float BlockPowerVitality = 0.6f; + + /** @brief 破防强度基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float GuardBreakPowerBase = 5.0f; + + /** @brief 力量对破防强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float GuardBreakPowerStrength = 1.1f; + + /** @brief 感知对破防强度的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float GuardBreakPowerPerception = 0.4f; + + /** @brief 韧性基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseBase = 20.0f; + + /** @brief 体魄对韧性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseVitality = 1.5f; + + /** @brief 力量对韧性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseStrength = 0.5f; + + /** @brief 韧性伤害基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseDamageBase = 5.0f; + + /** @brief 力量对韧性伤害的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseDamageStrength = 0.8f; + + /** @brief 灵巧对韧性伤害的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Formula") + float PoiseDamageDexterity = 0.2f; +}; + +/** + * @brief 元素属性公式系数。 + */ +USTRUCT(BlueprintType) +struct FPHYElementAttributeFormula +{ + GENERATED_BODY() + + /** @brief 元素伤害加成基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float DamageBonusBase = 0.0f; + + /** @brief 智力对元素伤害加成的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float DamageBonusIntelligence = 0.0015f; + + /** @brief 感知对元素伤害加成的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float DamageBonusPerception = 0.0005f; + + /** @brief 元素抗性基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float ResistanceBase = 0.02f; + + /** @brief 精神对元素抗性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float ResistanceSpirit = 0.002f; + + /** @brief 体魄对元素抗性的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float ResistanceVitality = 0.0005f; + + /** @brief 通用元素穿透基础值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float PenetrationBase = 0.0f; + + /** @brief 感知对通用元素穿透的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float PenetrationPerception = 0.001f; + + /** @brief 智力对通用元素穿透的系数。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes|Element") + float PenetrationIntelligence = 0.0005f; +}; + +/** + * @brief 属性体系配置,首期放入 PHYCombat 以便和战斗公式一起维护。 + */ +UCLASS(Config=PHYCombat, DefaultConfig) +class PHY_API UPHYAttributeSettings : public UObject +{ + GENERATED_BODY() + +public: + /** @brief 基础属性默认初始值。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes") + FPHYCoreAttributeDefaults DefaultCoreAttributes; + + /** @brief 次级战斗属性公式。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes") + FPHYCombatAttributeFormula CombatFormula; + + /** @brief 元素属性公式。 */ + UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="PHY|Attributes") + FPHYElementAttributeFormula ElementFormula; +}; + diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYCombatAttributeSet.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYCombatAttributeSet.h new file mode 100644 index 0000000..6239743 --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYCombatAttributeSet.h @@ -0,0 +1,183 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystem/Attributes/PHYAttributeSet.h" +#include "PHYCombatAttributeSet.generated.h" + +class UPHYCoreAttributeSet; +struct FGameplayEffectModCallbackData; + +/** + * @brief PHY 次级战斗属性集,由基础属性和装备、效果共同驱动。 + */ +UCLASS(BlueprintType) +class PHY_API UPHYCombatAttributeSet : public UAttributeSet +{ + GENERATED_BODY() + +public: + /** @brief 构造战斗属性并按默认基础属性推导首期数值。 */ + UPHYCombatAttributeSet(); + + /** @brief 注册属性复制。 */ + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + + /** @brief 属性变更前限制百分比和资源范围。 */ + virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override; + + /** @brief GameplayEffect 执行后限制资源不超过上限。 */ + virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override; + + /** @brief 属性变更后同步当前资源与上限。 */ + virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override; + + /** @brief 当前生命。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Health, Category="PHY|Attributes|Combat") + FGameplayAttributeData Health; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Health); + + /** @brief 生命上限。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_MaxHealth, Category="PHY|Attributes|Combat") + FGameplayAttributeData MaxHealth; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, MaxHealth); + + /** @brief 当前法力。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Mana, Category="PHY|Attributes|Combat") + FGameplayAttributeData Mana; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Mana); + + /** @brief 法力上限。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_MaxMana, Category="PHY|Attributes|Combat") + FGameplayAttributeData MaxMana; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, MaxMana); + + /** @brief 当前耐力。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Stamina, Category="PHY|Attributes|Combat") + FGameplayAttributeData Stamina; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Stamina); + + /** @brief 耐力上限。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_MaxStamina, Category="PHY|Attributes|Combat") + FGameplayAttributeData MaxStamina; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, MaxStamina); + + /** @brief 物理攻击强度。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_PhysicalAttackPower, Category="PHY|Attributes|Combat") + FGameplayAttributeData PhysicalAttackPower; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, PhysicalAttackPower); + + /** @brief 法术强度。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_SpellPower, Category="PHY|Attributes|Combat") + FGameplayAttributeData SpellPower; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, SpellPower); + + /** @brief 护甲。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Armor, Category="PHY|Attributes|Combat") + FGameplayAttributeData Armor; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Armor); + + /** @brief 魔法抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_MagicResistance, Category="PHY|Attributes|Combat") + FGameplayAttributeData MagicResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, MagicResistance); + + /** @brief 命中率,通常作为 0 到 1 的比例使用。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Accuracy, Category="PHY|Attributes|Combat") + FGameplayAttributeData Accuracy; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Accuracy); + + /** @brief 闪避率,通常作为 0 到 1 的比例使用。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Evasion, Category="PHY|Attributes|Combat") + FGameplayAttributeData Evasion; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Evasion); + + /** @brief 暴击率,通常作为 0 到 1 的比例使用。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_CriticalChance, Category="PHY|Attributes|Combat") + FGameplayAttributeData CriticalChance; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, CriticalChance); + + /** @brief 暴击伤害倍率,1.5 表示 150% 伤害。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_CriticalDamage, Category="PHY|Attributes|Combat") + FGameplayAttributeData CriticalDamage; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, CriticalDamage); + + /** @brief 攻击速度倍率。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_AttackSpeed, Category="PHY|Attributes|Combat") + FGameplayAttributeData AttackSpeed; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, AttackSpeed); + + /** @brief 冷却缩减比例。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_CooldownReduction, Category="PHY|Attributes|Combat") + FGameplayAttributeData CooldownReduction; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, CooldownReduction); + + /** @brief 格挡强度。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_BlockPower, Category="PHY|Attributes|Combat") + FGameplayAttributeData BlockPower; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, BlockPower); + + /** @brief 破防强度。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_GuardBreakPower, Category="PHY|Attributes|Combat") + FGameplayAttributeData GuardBreakPower; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, GuardBreakPower); + + /** @brief 韧性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Poise, Category="PHY|Attributes|Combat") + FGameplayAttributeData Poise; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, Poise); + + /** @brief 韧性伤害。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_PoiseDamage, Category="PHY|Attributes|Combat") + FGameplayAttributeData PoiseDamage; + PHY_ATTRIBUTE_ACCESSORS(UPHYCombatAttributeSet, PoiseDamage); + + /** @brief 按默认配置中的基础属性计算并写入次级属性。 */ + void InitializeFromConfiguredCoreDefaults(); + + /** @brief 按指定基础属性集计算并写入次级属性。 */ + void InitializeFromCoreAttributes(const UPHYCoreAttributeSet* CoreAttributes); + +protected: + /** @brief 复制当前生命变化。 */ + UFUNCTION() void OnRep_Health(const FGameplayAttributeData& OldValue); + /** @brief 复制生命上限变化。 */ + UFUNCTION() void OnRep_MaxHealth(const FGameplayAttributeData& OldValue); + /** @brief 复制当前法力变化。 */ + UFUNCTION() void OnRep_Mana(const FGameplayAttributeData& OldValue); + /** @brief 复制法力上限变化。 */ + UFUNCTION() void OnRep_MaxMana(const FGameplayAttributeData& OldValue); + /** @brief 复制当前耐力变化。 */ + UFUNCTION() void OnRep_Stamina(const FGameplayAttributeData& OldValue); + /** @brief 复制耐力上限变化。 */ + UFUNCTION() void OnRep_MaxStamina(const FGameplayAttributeData& OldValue); + /** @brief 复制物理攻击强度变化。 */ + UFUNCTION() void OnRep_PhysicalAttackPower(const FGameplayAttributeData& OldValue); + /** @brief 复制法术强度变化。 */ + UFUNCTION() void OnRep_SpellPower(const FGameplayAttributeData& OldValue); + /** @brief 复制护甲变化。 */ + UFUNCTION() void OnRep_Armor(const FGameplayAttributeData& OldValue); + /** @brief 复制魔法抗性变化。 */ + UFUNCTION() void OnRep_MagicResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制命中率变化。 */ + UFUNCTION() void OnRep_Accuracy(const FGameplayAttributeData& OldValue); + /** @brief 复制闪避率变化。 */ + UFUNCTION() void OnRep_Evasion(const FGameplayAttributeData& OldValue); + /** @brief 复制暴击率变化。 */ + UFUNCTION() void OnRep_CriticalChance(const FGameplayAttributeData& OldValue); + /** @brief 复制暴击伤害倍率变化。 */ + UFUNCTION() void OnRep_CriticalDamage(const FGameplayAttributeData& OldValue); + /** @brief 复制攻击速度倍率变化。 */ + UFUNCTION() void OnRep_AttackSpeed(const FGameplayAttributeData& OldValue); + /** @brief 复制冷却缩减比例变化。 */ + UFUNCTION() void OnRep_CooldownReduction(const FGameplayAttributeData& OldValue); + /** @brief 复制格挡强度变化。 */ + UFUNCTION() void OnRep_BlockPower(const FGameplayAttributeData& OldValue); + /** @brief 复制破防强度变化。 */ + UFUNCTION() void OnRep_GuardBreakPower(const FGameplayAttributeData& OldValue); + /** @brief 复制韧性变化。 */ + UFUNCTION() void OnRep_Poise(const FGameplayAttributeData& OldValue); + /** @brief 复制韧性伤害变化。 */ + UFUNCTION() void OnRep_PoiseDamage(const FGameplayAttributeData& OldValue); +}; diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYCoreAttributeSet.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYCoreAttributeSet.h new file mode 100644 index 0000000..ce4109f --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYCoreAttributeSet.h @@ -0,0 +1,78 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystem/Attributes/PHYAttributeSet.h" +#include "PHYCoreAttributeSet.generated.h" + +/** + * @brief PHY 基础属性集,作为所有玩家和 AI 的通用根属性。 + */ +UCLASS(BlueprintType) +class PHY_API UPHYCoreAttributeSet : public UAttributeSet +{ + GENERATED_BODY() + +public: + /** @brief 构造基础属性并读取默认配置。 */ + UPHYCoreAttributeSet(); + + /** @brief 注册属性复制。 */ + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + + /** @brief 力量,影响物理攻击、格挡、破防和负重倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Strength, Category="PHY|Attributes|Core") + FGameplayAttributeData Strength; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Strength); + + /** @brief 灵巧,影响暴击、攻速、命中和闪避倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Dexterity, Category="PHY|Attributes|Core") + FGameplayAttributeData Dexterity; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Dexterity); + + /** @brief 体魄,影响生命、护甲、耐力和韧性倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Vitality, Category="PHY|Attributes|Core") + FGameplayAttributeData Vitality; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Vitality); + + /** @brief 智力,影响法术强度、法力和冷却缩减倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Intelligence, Category="PHY|Attributes|Core") + FGameplayAttributeData Intelligence; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Intelligence); + + /** @brief 精神,影响法力、魔法抗性和元素抗性倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Spirit, Category="PHY|Attributes|Core") + FGameplayAttributeData Spirit; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Spirit); + + /** @brief 感知,影响命中、暴击、弱点和穿透倾向。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_Perception, Category="PHY|Attributes|Core") + FGameplayAttributeData Perception; + PHY_ATTRIBUTE_ACCESSORS(UPHYCoreAttributeSet, Perception); + +protected: + /** @brief 复制力量。 */ + UFUNCTION() + void OnRep_Strength(const FGameplayAttributeData& OldValue); + + /** @brief 复制灵巧。 */ + UFUNCTION() + void OnRep_Dexterity(const FGameplayAttributeData& OldValue); + + /** @brief 复制体魄。 */ + UFUNCTION() + void OnRep_Vitality(const FGameplayAttributeData& OldValue); + + /** @brief 复制智力。 */ + UFUNCTION() + void OnRep_Intelligence(const FGameplayAttributeData& OldValue); + + /** @brief 复制精神。 */ + UFUNCTION() + void OnRep_Spirit(const FGameplayAttributeData& OldValue); + + /** @brief 复制感知。 */ + UFUNCTION() + void OnRep_Perception(const FGameplayAttributeData& OldValue); +}; diff --git a/Source/PHY/Public/AbilitySystem/Attributes/PHYElementAttributeSet.h b/Source/PHY/Public/AbilitySystem/Attributes/PHYElementAttributeSet.h new file mode 100644 index 0000000..cbcd135 --- /dev/null +++ b/Source/PHY/Public/AbilitySystem/Attributes/PHYElementAttributeSet.h @@ -0,0 +1,155 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "AbilitySystem/Attributes/PHYAttributeSet.h" +#include "PHYElementAttributeSet.generated.h" + +class UPHYCoreAttributeSet; + +/** + * @brief PHY 元素进攻与防御属性集。 + */ +UCLASS(BlueprintType) +class PHY_API UPHYElementAttributeSet : public UAttributeSet +{ + GENERATED_BODY() + +public: + /** @brief 构造元素属性并按默认基础属性推导首期数值。 */ + UPHYElementAttributeSet(); + + /** @brief 注册属性复制。 */ + virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; + + /** @brief 限制元素比例属性范围。 */ + virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override; + + /** @brief 按默认配置中的基础属性计算并写入元素属性。 */ + void InitializeFromConfiguredCoreDefaults(); + + /** @brief 按指定基础属性集计算并写入元素属性。 */ + void InitializeFromCoreAttributes(const UPHYCoreAttributeSet* CoreAttributes); + + /** @brief 火元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_FireDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData FireDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, FireDamageBonus); + + /** @brief 水元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_WaterDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData WaterDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, WaterDamageBonus); + + /** @brief 冰元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_IceDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData IceDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, IceDamageBonus); + + /** @brief 雷元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_LightningDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData LightningDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, LightningDamageBonus); + + /** @brief 地元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_EarthDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData EarthDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, EarthDamageBonus); + + /** @brief 风元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_WindDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData WindDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, WindDamageBonus); + + /** @brief 光元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_LightDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData LightDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, LightDamageBonus); + + /** @brief 暗元素伤害加成。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_DarkDamageBonus, Category="PHY|Attributes|Element") + FGameplayAttributeData DarkDamageBonus; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, DarkDamageBonus); + + /** @brief 火元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_FireResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData FireResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, FireResistance); + + /** @brief 水元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_WaterResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData WaterResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, WaterResistance); + + /** @brief 冰元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_IceResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData IceResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, IceResistance); + + /** @brief 雷元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_LightningResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData LightningResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, LightningResistance); + + /** @brief 地元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_EarthResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData EarthResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, EarthResistance); + + /** @brief 风元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_WindResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData WindResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, WindResistance); + + /** @brief 光元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_LightResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData LightResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, LightResistance); + + /** @brief 暗元素抗性。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_DarkResistance, Category="PHY|Attributes|Element") + FGameplayAttributeData DarkResistance; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, DarkResistance); + + /** @brief 通用元素穿透,首期不按元素拆分。 */ + UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_ElementPenetration, Category="PHY|Attributes|Element") + FGameplayAttributeData ElementPenetration; + PHY_ATTRIBUTE_ACCESSORS(UPHYElementAttributeSet, ElementPenetration); + +protected: + /** @brief 复制火元素伤害加成变化。 */ + UFUNCTION() void OnRep_FireDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制水元素伤害加成变化。 */ + UFUNCTION() void OnRep_WaterDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制冰元素伤害加成变化。 */ + UFUNCTION() void OnRep_IceDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制雷元素伤害加成变化。 */ + UFUNCTION() void OnRep_LightningDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制地元素伤害加成变化。 */ + UFUNCTION() void OnRep_EarthDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制风元素伤害加成变化。 */ + UFUNCTION() void OnRep_WindDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制光元素伤害加成变化。 */ + UFUNCTION() void OnRep_LightDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制暗元素伤害加成变化。 */ + UFUNCTION() void OnRep_DarkDamageBonus(const FGameplayAttributeData& OldValue); + /** @brief 复制火元素抗性变化。 */ + UFUNCTION() void OnRep_FireResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制水元素抗性变化。 */ + UFUNCTION() void OnRep_WaterResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制冰元素抗性变化。 */ + UFUNCTION() void OnRep_IceResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制雷元素抗性变化。 */ + UFUNCTION() void OnRep_LightningResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制地元素抗性变化。 */ + UFUNCTION() void OnRep_EarthResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制风元素抗性变化。 */ + UFUNCTION() void OnRep_WindResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制光元素抗性变化。 */ + UFUNCTION() void OnRep_LightResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制暗元素抗性变化。 */ + UFUNCTION() void OnRep_DarkResistance(const FGameplayAttributeData& OldValue); + /** @brief 复制通用元素穿透变化。 */ + UFUNCTION() void OnRep_ElementPenetration(const FGameplayAttributeData& OldValue); +}; diff --git a/Source/PHY/Public/Characters/PHYAICharacter.h b/Source/PHY/Public/Characters/PHYAICharacter.h index 64d12ae..b090580 100644 --- a/Source/PHY/Public/Characters/PHYAICharacter.h +++ b/Source/PHY/Public/Characters/PHYAICharacter.h @@ -7,6 +7,9 @@ #include "PHYAICharacter.generated.h" class UGGA_AbilitySystemComponent; +class UPHYCombatAttributeSet; +class UPHYCoreAttributeSet; +class UPHYElementAttributeSet; class UPHYClassComponent; /** @@ -33,6 +36,18 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|AI") UGGA_AbilitySystemComponent* GetAIAbilitySystemComponent() const { return AbilitySystemComponent; } + /** @brief 获取 AI 基础属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYCoreAttributeSet* GetCoreAttributeSet() const { return CoreAttributeSet; } + + /** @brief 获取 AI 战斗属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYCombatAttributeSet* GetCombatAttributeSet() const { return CombatAttributeSet; } + + /** @brief 获取 AI 元素属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYElementAttributeSet* GetElementAttributeSet() const { return ElementAttributeSet; } + /** @brief 获取 AI 职业分类组件。 */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Class") UPHYClassComponent* GetClassComponent() const { return ClassComponent; } @@ -45,6 +60,18 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|AI") TObjectPtr AbilitySystemComponent; + /** @brief AI 通用基础属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr CoreAttributeSet; + + /** @brief AI 通用战斗属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr CombatAttributeSet; + + /** @brief AI 通用元素属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr ElementAttributeSet; + /** @brief AI 职业分类组件,默认不应用玩家职业 Mesh。 */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Class") TObjectPtr ClassComponent; diff --git a/Source/PHY/Public/GameplayTags/PHYGameplayTags_Attribute.h b/Source/PHY/Public/GameplayTags/PHYGameplayTags_Attribute.h new file mode 100644 index 0000000..f038e8d --- /dev/null +++ b/Source/PHY/Public/GameplayTags/PHYGameplayTags_Attribute.h @@ -0,0 +1,39 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "NativeGameplayTags.h" + +/** + * @brief PHY 属性体系原生 Gameplay Tag。 + */ +namespace PHYGameplayTags +{ + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Strength); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Dexterity); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Vitality); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Intelligence); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Spirit); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Core_Perception); + + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat_Health); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat_Mana); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat_Stamina); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat_Offense); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Combat_Defense); + + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Fire); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Water); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Ice); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Lightning); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Earth); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Wind); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Light); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Dark); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_DamageBonus); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Resistance); + UE_DECLARE_GAMEPLAY_TAG_EXTERN(Attribute_Element_Penetration); +} diff --git a/Source/PHY/Public/PHYGameplayTags.h b/Source/PHY/Public/PHYGameplayTags.h index b6a144e..55244f7 100644 --- a/Source/PHY/Public/PHYGameplayTags.h +++ b/Source/PHY/Public/PHYGameplayTags.h @@ -3,6 +3,7 @@ #pragma once #include "GameplayTags/PHYGameplayTags_Ability.h" +#include "GameplayTags/PHYGameplayTags_Attribute.h" #include "GameplayTags/PHYGameplayTags_Class.h" #include "GameplayTags/PHYGameplayTags_Effect.h" #include "GameplayTags/PHYGameplayTags_Event.h" diff --git a/Source/PHY/Public/Player/PHYPlayerState.h b/Source/PHY/Public/Player/PHYPlayerState.h index a6067e4..09f0f13 100644 --- a/Source/PHY/Public/Player/PHYPlayerState.h +++ b/Source/PHY/Public/Player/PHYPlayerState.h @@ -8,6 +8,9 @@ #include "PHYPlayerState.generated.h" class UGGA_AbilitySystemComponent; +class UPHYCombatAttributeSet; +class UPHYCoreAttributeSet; +class UPHYElementAttributeSet; class UPHYClassComponent; /** @@ -31,6 +34,18 @@ public: UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|PlayerState") UGGA_AbilitySystemComponent* GetGGAAbilitySystemComponent() const { return AbilitySystemComponent; } + /** @brief 获取玩家基础属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYCoreAttributeSet* GetCoreAttributeSet() const { return CoreAttributeSet; } + + /** @brief 获取玩家战斗属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYCombatAttributeSet* GetCombatAttributeSet() const { return CombatAttributeSet; } + + /** @brief 获取玩家元素属性集。 */ + UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Attributes") + UPHYElementAttributeSet* GetElementAttributeSet() const { return ElementAttributeSet; } + /** @brief 获取玩家持久职业组件。 */ UFUNCTION(BlueprintCallable, BlueprintPure, Category="PHY|Class") UPHYClassComponent* GetClassComponent() const { return ClassComponent; } @@ -40,6 +55,18 @@ protected: UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|PlayerState") TObjectPtr AbilitySystemComponent; + /** @brief 玩家持久基础属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr CoreAttributeSet; + + /** @brief 玩家持久战斗属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr CombatAttributeSet; + + /** @brief 玩家持久元素属性集,避免职业 AbilitySet 重复添加。 */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Attributes") + TObjectPtr ElementAttributeSet; + /** @brief 玩家持久职业组件,职业不保存在 PlayerCharacter 上。 */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="PHY|Class") TObjectPtr ClassComponent;