Able Ability System Info and Support Thread

Not really. I wrote Able because I found issues with the way GameplayAbilities was setup (it was very much tied to how Paragon was using it). I also never got their Gameplay Abilities Editor to work and the instructions / documentation were pretty lacking (granted this was wayyy back in 4.09-ish, so it may be much better today).

So rather than try to force that square peg into a round hole, I just wrote my own based on tools I used in the Industry and some of the lessons learned during that time. I’d love to see someone who has used both to give an in depth comparison / feedback.

@ you should have a discord channel setup where people can show what has been done with ABLE and support. Anyways love this plugin really helping me as a solo dev on giant projects thank you so much you work is great and can’t believe how good this really is thank you for your time and effort .

Thanks for the kind words. :slight_smile:

I haven’t tried out discord yet. I know some people love them. I’ll look into it. It would be good for the community.

Seems the update dropped today but I cant install it :expressionless: I tell it to install and just nothing happens.

Yeah here too, looks like it’s a nasty launcher bug (today there was an update to v7.7.0). If I correct a hotfix will come soon. I mean, I hope so. ::

Ick, yea, says the update went out. Maybe some weird backend stuff?

Looks like it was just delayed, got it installed now!

I’m a little sad to say that the new ‘cancel ability’ isnt what I wanted and doesnt really solve anything for me in that respect (cant be used with conditionals to cancel the current ability executing the type); oh well I’ll continue to solve it via custom types.

Edit: I suppose could use it by creating an ability, that is just used to cancel other abilities and branching into it.

Possibly?

What conditions are you looking for? Channeling conditions already automatically cancel an ability when they fail. I could potentially add just a generic “Should Cancel Ability” that the Cancel Ability Task calls and you can overload that in C++ or BP.

The conditions I was looking for are velocity or other buttons; but not the same as channeling conditions these cant be limited to a specific time frame, the conditionals that I’d want are basically the same as branched.

best way to explain is with an example, lets say we have a combo attack system that has reset frames in the animation to bring the weapon back to a more central position, we wouldnt want to play this part of that animation if another is queued or if the player is moving because it would just make it feel less responsive, so a cancel task set after the ‘meat’ of the animation and the damage would make sense for this, under the condition that the player is either moving or inputing another combo step. The combo condition is taken care of by the normal branching, but the movement isnt, so we need a real cancel task to handle that with a conditional.

I’m also still experiencing the same issue as before, animations aren’t interrupting with their abilities.

Have you tried the new “Clear Animation Queue” option on the Play Animation call when interrupted?

I have, the only thing that has any effect is checking both the “Is Playing Ability” and “Has Ability Animation”; checking both of these for the state change within the animation blueprint solves the problem in most cases.

Has Ability Animation you definitely should be checking, but Is Playing Ability shouldn’t really matter. The cancel does has to happen within the time frame of the Play Animation Task, so if you are just firing it and forgetting, I could see that cause this.

I am canceling within the time frame of the animation task. I’ve even tried pulling it down to the point it cancels just a few mill seconds after it starts (I should just see a twitch in the animation when its canceled) but it just continues to play as if the ability has never been canceled (unless I check for ‘Is Playing Ability’ that is).

Hey,

I cloned my Project and upgraded it to 4.19 (together with the new Plugin Version). If I try to package it, this error occurs(UBuildTool-Logfile):
[SPOILER]



Performing 1 actions (4 in parallel)
[1/1] Link MyProjectCloned.exe
   Creating library ...\Documents\Unreal Projects\MyProjectCloned 4.19\Binaries\Win64\MyProjectCloned.lib and object ...\Documents\Unreal Projects\MyProjectCloned 4.19\Binaries\Win64\MyProjectCloned.exp
UE4-AbleCore.lib(Module.AbleCore.cpp.obj) : error LNK2019: unresolved external symbol "protected: bool __cdecl UAblCancelAbilityTask::ShouldCancelAbility(class UAblAbility const &)const " (?ShouldCancelAbility@UAblCancelAbilityTask@@IEBA_NAEBVUAblAbility@@@Z) referenced in function "public: virtual void __cdecl UAblCancelAbilityTask::OnTaskStart(struct TWeakObjectPtr<class UAblAbilityContext const ,struct FWeakObjectPtr> const &)const " (?OnTaskStart@UAblCancelAbilityTask@@UEBAXAEBU?$TWeakObjectPtr@$$CBVUAblAbilityContext@@UFWeakObjectPtr@@@@@Z)
...\Documents\Unreal Projects\MyProjectCloned 4.19\Binaries\Win64\MyProjectCloned.exe : fatal error LNK1120: 1 unresolved externals
ERROR: UBT ERROR: Failed to produce item: ...\Documents\Unreal Projects\MyProjectCloned 4.19\Binaries\Win64\MyProjectCloned.exe
Total build time: 30,47 seconds (Local executor: 0,00 seconds)


[/SPOILER]

Am I right to to assume it has to to with this plugin and or did I missed something to do when switching to new Version?

Thanks in advance.

Hi, sometimes when I try to add preview assets in, the blueprints that I click are not alsways loading in, most of the time it fails to load the blueprint in as a preview asset. Any ideas to why this is happening, this is ue4 4.19

Sorry for the silence lately, I was knocked out by the flu last week and I’m just now getting up and around again.

Hmmm, not sure why you’re the only one getting that (or maybe you arn’t). Do you see the ShouldCancelAbility in the AblCancelAbilityTask.cpp?

Are you getting any errors? As long as the blueprint has a static mesh / skeletal mesh - it should load.

No problem, glad you’re getting better.

I’m not that much into c++ coding but I found the “ShouldCancelAbility” at the end of the class inside a *“#if WITH_EDITOR” wrapper and it’s getting called above twice.


*// Copyright (c) 2016 - 2018 Extra Life Studios, LLC. All rights reserved.

#include "Tasks/ablCancelAbilityTask.h"

#include "ablAbility.h"
#include "ablAbilityComponent.h"
#include "ablAbilityContext.h"
#include "AbleCorePrivate.h"

#define LOCTEXT_NAMESPACE "AblAbilityTask"

UAblCancelAbilityTask::UAblCancelAbilityTask(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer),
    m_Ability(),
    m_TagQuery(),
    m_PassiveBehavior(RemoveOneStack),
    m_CancelResult(Interrupted)
{

}

UAblCancelAbilityTask::~UAblCancelAbilityTask()
{

}

void UAblCancelAbilityTask::OnTaskStart(const TWeakObjectPtr<const UAblAbilityContext>& Context) const
{
    check(Context.IsValid());

    Super::OnTaskStart(Context);

    TArray<TWeakObjectPtr<AActor>> TaskTargets;
    GetActorsForTask(Context, TaskTargets);

    for (TWeakObjectPtr<AActor> TargetActor : TaskTargets)
    {
        if (TargetActor.IsValid())
        {
            continue;
        }

        if (UAblAbilityComponent* AbilityComponent = TargetActor->FindComponentByClass<UAblAbilityComponent>())
        {
            if (const UAblAbility* ActiveAbility = AbilityComponent->GetActiveAbility())
            {
                if (**ShouldCancelAbility(*ActiveAbility))**
                {
#if !(UE_BUILD_SHIPPING)
                    if (IsVerbose())
                    {
                        PrintVerbose(FString::Printf(TEXT("Cancelling Ability %s on Actor %s."), *ActiveAbility->GetDisplayName(),
                            *TargetActor->GetName()));
                    }
#endif
                    AbilityComponent->CancelAbility(ActiveAbility, m_CancelResult.GetValue());
                }
            }

            TArray<UAblAbility*> CurrentPassives;
            AbilityComponent->GetCurrentPassiveAbilities(CurrentPassives);

            for (UAblAbility* Passive : CurrentPassives)
            {
                if (**ShouldCancelAbility(*Passive))**
                {
                    switch (m_PassiveBehavior.GetValue())
                    {
                    case RemoveOneStack:
                    case RemoveOneStackWithRefresh:
                    {
                        int32 StackCount = AbilityComponent->GetCurrentStackCountForPassiveAbility(Passive);
                        int32 NewStackCount = FMath::Max(StackCount - 1, 0);

#if !(UE_BUILD_SHIPPING)
                        if (IsVerbose())
                        {
                            PrintVerbose(FString::Printf(TEXT("Setting Passive Ability %s Stack on Actor %s from %d to %d."), *Passive->GetDisplayName(),
                                *TargetActor->GetName(), StackCount, NewStackCount));
                        }
#endif

                        AbilityComponent->SetPassiveStackCount(Passive, NewStackCount, m_PassiveBehavior.GetValue() == RemoveOneStackWithRefresh, m_CancelResult.GetValue());
                    }
                    break;
                    case RemoveEntireStack:
                    default:
                    {
#if !(UE_BUILD_SHIPPING)
                        if (IsVerbose())
                        {
                            PrintVerbose(FString::Printf(TEXT("Cancelling Passive Ability %s on Actor %s."), *Passive->GetDisplayName(),
                                *TargetActor->GetName()));
                        }
#endif
                        AbilityComponent->CancelAbility(Passive, m_CancelResult.GetValue());
                    }
                    break;
                    }
                }
            }
        }
    }

}

TStatId UAblCancelAbilityTask::GetStatId() const
{
    RETURN_QUICK_DECLARE_CYCLE_STAT(UAblCancelAbilityTask, STATGROUP_Able);
}

#if WITH_EDITOR

FText UAblCancelAbilityTask::GetDescriptiveTaskName() const
{
    const FText FormatText = LOCTEXT("AblCancelAbilityTaskFormat", "{0}: {1}");
    FString AbilityName = TEXT("<null>");
    if (*m_Ability)
    {
        if (UAblAbility* Ability = Cast<UAblAbility>(m_Ability->GetDefaultObject()))
        {
            AbilityName = Ability->GetDisplayName();
        }
    }
    else if (!m_TagQuery.IsEmpty())
    {
        AbilityName = m_TagQuery.GetDescription();
    }

    return FText::FormatOrdered(FormatText, GetTaskName(), FText::FromString(AbilityName));
}

**bool UAblCancelAbilityTask::ShouldCancelAbility(const UAblAbility& Ability) cons**t
{
    if (*m_Ability && m_Ability->GetDefaultObject<UAblAbility>()->GetAbilityNameHash() == Ability.GetAbilityNameHash())
    {
        return true;
    }

    if (!m_TagQuery.IsEmpty())
    {
        return Ability.GetAbilityTagContainer().MatchesQuery(m_TagQuery);
    }

    return false;
}

#endif

#undef LOCTEXT_NAMESPACE*

Hope that was what you were asking for!?

Ahhhh, that’s the issue. Just cut and paste that ShouldCancelAbility method outside of the #if WITH_EDITOR block. No idea how that got through submissions, but I’ll get a patch out this weekend.