关于UE GAS GameplayEffect中SetByCaller的解析

发布时间 2023-08-28 17:56:46作者: cgsgood

在GAS中,GameplayEffect(简称GE)里面,在涉及到Magnitude的地方,针对Magnitude Calculation Type都会有一个选项“Set By Caller”,其本质,是把Magnitude的具体数值,交由开发者在代码中决定。
image.png
如果设置为“Set By Caller”,它都需要填写一个Data Tag,其本质是,在GameplayEffect实例中,它有一个字典"SetByCallerTagMagnitudes",其声明如下

TMap<FGameplayTag, float> SetByCallerTagMagnitudes;

在ApplyGameplayEffectSpecToOwner时,会有以下计算,本质就是在字典"SetByCallerTagMagnitudes"中获取Magnitude的值。

FActiveGameplayEffectHandle UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf(const FGameplayEffectSpec &Spec, FPredictionKey PredictionKey)
{
// ...
AppliedEffect = ActiveGameplayEffects.ApplyGameplayEffectSpec(Spec, PredictionKey, bFoundExistingStackableGE);
}

FActiveGameplayEffect* FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec(const FGameplayEffectSpec& Spec, FPredictionKey& InPredictionKey, bool& bFoundExistingStackableGE)
{
// ...
if (AppliedEffectSpec.AttemptCalculateDurationFromDef(DefCalcDuration))
{
AppliedEffectSpec.SetDuration(DefCalcDuration, false);
}
}

bool FGameplayEffectSpec::AttemptCalculateDurationFromDef(OUT float& OutDefDuration) const
{
else
{
// The last parameters (false, 1.f) are so that if SetByCaller hasn't been set yet, we don't warn and default
// to 1.f. This is so that the rest of the system doesn't treat the effect as an instant effect. 1.f is arbitrary
// and this makes it illegal to SetByCaller something into an instant effect.
bCalculatedDuration = Def->DurationMagnitude.AttemptCalculateMagnitude(*this, OutDefDuration, false, 1.f);
}

return bCalculatedDuration;
}

bool FGameplayEffectModifierMagnitude::AttemptCalculateMagnitude(const FGameplayEffectSpec& InRelevantSpec, OUT float& OutCalculatedMagnitude, bool WarnIfSetByCallerFail, float DefaultSetbyCaller) const
{
case EGameplayEffectMagnitudeCalculation::SetByCaller:
{
OutCalculatedMagnitude = InRelevantSpec.GetSetByCallerMagnitude(SetByCallerMagnitude.DataTag, WarnIfSetByCallerFail, DefaultSet
}
}

float FGameplayEffectSpec::GetSetByCallerMagnitude(FGameplayTag DataTag, bool WarnIfNotFound, float DefaultIfNotFound) const
{
float Magnitude = DefaultIfNotFound;
const float* Ptr = nullptr;
{
Ptr = SetByCallerTagMagnitudes.Find(DataTag);
}
{
Magnitude = *Ptr;
}

return Magnitude;
}

因为GE中有很多地方可以用到Set By Caller,所以就需要给Set By Caller的Magnitude一个Data Tag,用来区分不同的地方。它是在GE内部使用的Tag。