还是老规矩只贴我不太理解或者重要的,一些简单的GetSet就不贴了
1 AddSpawnedAttribute
这里按顺序放几个模板的定义,关键还是看AddSpawnedAttribute
/** Finds existing AttributeSet */
template <class T >
const T* GetSet() const
{
return (T*)GetAttributeSubobject(T::StaticClass());
}
/** Finds existing AttributeSet. Asserts if it isn't there. */
template <class T >
const T* GetSetChecked() const
{
return (T*)GetAttributeSubobjectChecked(T::StaticClass());
}
/** Adds a new AttributeSet (initialized to default values) */
template <class T >
const T* AddSet()
{
return (T*)GetOrCreateAttributeSubobject(T::StaticClass());
}
/**
* Manually add a new attribute set that is a subobject of this ability system component.
* All subobjects of this component are automatically added during initialization.
*/
template <class T>
const T* AddAttributeSetSubobject(T* Subobject)
{
AddSpawnedAttribute(Subobject);
return Subobject;
}
下边是具体的AddSpawnedAttribute的实现:
如果需要复制就加入ReplicatedSubObject里,然后直接Add到SpawnedAttributes里,最后做一下标记
void UAbilitySystemComponent::AddSpawnedAttribute(UAttributeSet* Attribute)
{
if (!IsValid(Attribute))
{
return;
}
if (SpawnedAttributes.Find(Attribute) == INDEX_NONE)
{
if (IsUsingRegisteredSubObjectList() && IsReadyForReplication())
{
AddReplicatedSubObject(Attribute);
}
SpawnedAttributes.Add(Attribute);
SetSpawnedAttributesListDirty();
}
}
这里贴一下SpawnedAttributes的声明:
private:
/** List of attribute sets */
UPROPERTY(Replicated, ReplicatedUsing = OnRep_SpawnedAttributes, Transient)
TArray<TObjectPtr<UAttributeSet>> SpawnedAttributes;
2 InitStats
这俩还是比较重要的函数,就是用来实现用DataTable初始化attributes的
/** Initializes starting attributes from a data table. Not well supported, a gameplay effect with curve table references may be a better solution */
const UAttributeSet* InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);
UFUNCTION(BlueprintCallable, Category="Skills", meta=(DisplayName="InitStats", ScriptName="InitStats"))
void K2_InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);
核心InitStats:
其实还没到关键,就是调用了AS的InitFromMetaDataTable
const UAttributeSet* UAbilitySystemComponent::InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable)
{
const UAttributeSet* AttributeObj = nullptr;
if (Attributes)
{
AttributeObj = GetOrCreateAttributeSubobject(Attributes);
if (AttributeObj && DataTable)
{
// This const_cast is OK - this is one of the few places we want to directly modify our AttributeSet properties rather
// than go through a gameplay effect
const_cast<UAttributeSet*>(AttributeObj)->InitFromMetaDataTable(DataTable);
}
}
return AttributeObj;
}
所以我们再去看InitFromMetaDataTable:
1.先看这个循环体,我去查了一下,大概是一个迭代器,遍历这个类中的所有属性(在UE反射系统中的)
for( TFieldIterator<FProperty> It(GetClass(), EFieldIteratorFlags::IncludeSuper) ; It ; ++It )
2.循环内的前半部分:
这里的FNumericProperty是FProperty的子类,代表具体数值类型的
然后就是UE中读取DataTable的流程,从这里的代码能看出来MetaData里只有BaseValue有用
FProperty* Property = *It;
FNumericProperty *NumericProperty = CastField<FNumericProperty>(Property);
if (NumericProperty)
{
FString RowNameStr = FString::Printf(TEXT("%s.%s"), *Property->GetOwnerVariant().GetName(), *Property->GetName());
FAttributeMetaData * MetaData = DataTable->FindRow<FAttributeMetaData>(FName(*RowNameStr), Context, false);
if (MetaData)
{
void *Data = NumericProperty->ContainerPtrToValuePtr<void>(this);
NumericProperty->SetFloatingPointPropertyValue(Data, MetaData->BaseValue);
}
}
3.循环体后半部分:
如果是AttributeDataProperty,最后Set的是BaseValue和CurrentValue,值都是数据表里的BaseValue(这么看我之前写的SetBaseValue再SetCurrentValue好像没啥问题)
else if (FGameplayAttribute::IsGameplayAttributeDataProperty(Property))
{
FString RowNameStr = FString::Printf(TEXT("%s.%s"), *Property->GetOwnerVariant().GetName(), *Property->GetName());
FAttributeMetaData * MetaData = DataTable->FindRow<FAttributeMetaData>(FName(*RowNameStr), Context, false);
if (MetaData)
{
FStructProperty* StructProperty = CastField<FStructProperty>(Property);
check(StructProperty);
FGameplayAttributeData* DataPtr = StructProperty->ContainerPtrToValuePtr<FGameplayAttributeData>(this);
check(DataPtr);
DataPtr->SetBaseValue(MetaData->BaseValue);
DataPtr->SetCurrentValue(MetaData->BaseValue);
}
}
3 小结
今天这部分说实话都没啥要注意的(我觉得),为了证明我不是真的短,下边把我今天看完的相关函数全部贴在这,具体实现基本上都是见名知意的,不太懂得看看实现和注释也懂了,基本上都是一些GetSet和标准操作的工具函数
bool HasAttributeSetForAttribute(FGameplayAttribute Attribute) const;
const UAttributeSet* InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);
UFUNCTION(BlueprintCallable, Category="Skills", meta=(DisplayName="InitStats", ScriptName="InitStats"))
void K2_InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);
UFUNCTION(BlueprintPure, Category="Gameplay Attributes")
void GetAllAttributes(TArray<FGameplayAttribute>& OutAttributes);
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Attributes", meta=(DeterminesOutputType = AttributeSetClass))
const UAttributeSet* GetAttributeSet(TSubclassOf<UAttributeSet> AttributeSetClass) const;
UFUNCTION(BlueprintPure, Category = "Gameplay Attributes")
float GetGameplayAttributeValue(FGameplayAttribute Attribute, bool& bFound) const;
UPROPERTY(EditAnywhere, Category="AttributeTest")
TArray<FAttributeDefaults> DefaultStartingData;
void SetSpawnedAttributes(const TArray<UAttributeSet*>& NewAttributeSet);
UE_DEPRECATED(5.1, "This function will be made private. Use Add/Remove SpawnedAttributes instead")
TArray<TObjectPtr<UAttributeSet>>& GetSpawnedAttributes_Mutable();
const TArray<UAttributeSet*>& GetSpawnedAttributes() const;
void AddSpawnedAttribute(UAttributeSet* Attribute);
void RemoveSpawnedAttribute(UAttributeSet* Attribute);
void RemoveAllSpawnedAttributes();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Skills")
FName AffectedAnimInstanceTag;
void SetNumericAttributeBase(const FGameplayAttribute &Attribute, float NewBaseValue);
float GetNumericAttributeBase(const FGameplayAttribute &Attribute) const;
void ApplyModToAttribute(const FGameplayAttribute &Attribute, TEnumAsByte<EGameplayModOp::Type> ModifierOp, float ModifierMagnitude);
void ApplyModToAttributeUnsafe(const FGameplayAttribute &Attribute, TEnumAsByte<EGameplayModOp::Type> ModifierOp, float ModifierMagnitude);
float GetNumericAttribute(const FGameplayAttribute &Attribute) const;
float GetNumericAttributeChecked(const FGameplayAttribute &Attribute) const;
float GetFilteredAttributeValue(const FGameplayAttribute& Attribute, const FGameplayTagRequirements& SourceTags, const FGameplayTagContainer& TargetTags, const TArray<FActiveGameplayEffectHandle>& HandlesToIgnore = TArray<FActiveGameplayEffectHandle>());