Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doc section 4.5.14 method 2 I believe is incorrect. #93

Open
MattiaPezzanoAiv opened this issue Nov 28, 2022 · 1 comment
Open

Doc section 4.5.14 method 2 I believe is incorrect. #93

MattiaPezzanoAiv opened this issue Nov 28, 2022 · 1 comment

Comments

@MattiaPezzanoAiv
Copy link

Section 4.5.14 in the doc page recommends creating a UGameplayEffect at runtime, this would be great because it would let me pick which attribute to change making it selectable in the details panel of my ability, or set it dynamically.

My code looks something like this:

UGameplayEffect* UGvGameplayAbility::GetCostGameplayEffect() const
{
    // This snippet is taken from https://github.com/tranek/GASDocumentation#4517-creating-dynamic-gameplay-effects-at-runtime 
    UGameplayEffect* CostGE = NewObject<UGameplayEffect>(GetTransientPackage(), FName(TEXT("Cost")));
    CostGE->DurationPolicy = EGameplayEffectDurationType::Instant;
    CostGE->Modifiers.SetNum(1);
    FGameplayModifierInfo& Info = CostGE->Modifiers[0];
    Info.ModifierMagnitude = FScalableFloat(AbilityCost);
    Info.ModifierOp = EGameplayModOp::Additive;
    Info.Attribute = CostAttribute;
    return CostGE;
}

This seems to be working during CheckCost, but it "fails" when the cost has to be actually applied because the Spec is created using GetCostGameplayEffect()->GetClass(), resulting in an empty gameplay effect being applied, therefore no cost is deducted.

To be more specific what happens in UGameplayAbility::ApplyCost is that ApplyGameplayEffectToOwner is called with the new instance of the gameplay effect as the argument, inside this function though, Effect->GetClass() is called, ending up using the default object.

Hopefully I didn't misunderstand the doc intent. I should also mention that I have read the part where this is discouraged during prediction, although I was trying to do my own tests.
A solution to this would be to override UGameplayAbility::ApplyCost, and rather than invoking ApplyGameplayEffectToOwner, I could create my own FGameplayEffectSpecHandle using the dynamically created instance instead of the default object.
This would look something like the following:

void UGvGameplayAbility::ApplyCost(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
    const FGameplayAbilityActivationInfo ActivationInfo) const
{
    UGameplayEffect* CostGE = GetCostGameplayEffect();
    if (CostGE)
    {
        // ApplyGameplayEffectToOwner(Handle, ActorInfo, ActivationInfo, CostGE, );
        if (CostGE && (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo)))
        {
            FGameplayEffectSpec* GESpec = new FGameplayEffectSpec(CostGE, {}, GetAbilityLevel(Handle, ActorInfo));
            FGameplayEffectSpecHandle SpecHandle(GESpec);
            if (SpecHandle.IsValid())
            {
                ApplyGameplayEffectSpecToOwner(Handle, ActorInfo, ActivationInfo, SpecHandle);
            }
        }
    }
}

Thank you in advance for your response.

@tranek
Copy link
Owner

tranek commented Dec 20, 2022

Unfortunately I lost my test code for that part, so I don't have an answer for you for that specific example.

If you want to continue using a dynamically created GE, I think your approach of overriding ApplyCost() is the way to do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants