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 .
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. ::
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.
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 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).
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?
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
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*
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.