44. Infinite Effect Application and Removal

This commit is contained in:
Edward R. Gonzalez 2024-04-24 16:21:22 -04:00
parent caae7fd758
commit a218d86c23
7 changed files with 127 additions and 72 deletions

Binary file not shown.

View File

@ -1,6 +1,7 @@
#include "GasaEffectActor.h"
#include "GasaAbilitySystemComponent_Inlines.h"
#include "GasaContainers.h"
using namespace Gasa;
AGasaEffectActor::AGasaEffectActor()
@ -9,21 +10,24 @@ AGasaEffectActor::AGasaEffectActor()
RootComponent = CreateDefaultSubobject<USceneComponent>("Root");
InstantEffectUsage = DefaultEffectUsagePolicy;
InstantEffectUsage = EInstantEffectUsagePolicy::DoNotApply;
DurationEffectUsage = DefaultEffectUsagePolicy;
InfiniteEffectUsage = DefaultEffectUsagePolicy;
bDestroyOnEffectRemoval = false;
}
void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass)
void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass, bool bRemoveOnEndOverlap)
{
UGasaAbilitySystemComp* AS = GetAbilitySystem(Actor, true);
FGameplayEffectContextHandle
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (bRemoveOnEndOverlap)
ActiveEffectsToRemove.Add(ActiveEffect, AS);
}
void AGasaEffectActor::OnOverlap(AActor* Actor)
@ -33,40 +37,37 @@ void AGasaEffectActor::OnOverlap(AActor* Actor)
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
if (InstantEffectClass.Get())
{
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::ApplyOnOverlap))
if (InstantEffectClass && InstantEffectUsage == EInstantEffectUsagePolicy::ApplyOnOverlap)
{
FGameplayEffectSpecHandle Spec= AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap))
if (DurationEffectClass)
{
AS->RemoveActiveGameplayEffectBySourceEffect( InstantEffectClass, AS );
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::ApplyOnOverlap))
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( DurationEffectClass, 1.0f, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
ActiveDuration = ActiveEffect;
}
if (ActiveDuration.IsValid() && Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
AS->RemoveActiveGameplayEffect(ActiveDuration);
}
if (DurationEffectClass.Get())
if (InfiniteEffectClass)
{
if (Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::ApplyOnOverlap))
bool bApplyOnOverlap = Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::ApplyOnOverlap);
if (bApplyOnOverlap)
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InfiniteEffectClass, 1.0f, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(InfiniteEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
ActiveInfinite = ActiveEffect;
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap))
if (ActiveInfinite.IsValid() && Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnOverlap))
{
AS->RemoveActiveGameplayEffectBySourceEffect( DurationEffectClass, AS );
}
}
if (InfiniteEffectClass.Get())
{
if (Bitfield_IsSet(InfiniteEffectUsage, (int32)EEffectUsagePolicy::ApplyOnOverlap))
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap))
{
AS->RemoveActiveGameplayEffectBySourceEffect( InfiniteEffectClass, AS );
if (ActiveInfinite.IsValid())
AS->RemoveActiveGameplayEffect(ActiveInfinite);
}
}
}
@ -78,40 +79,46 @@ void AGasaEffectActor::OnEndOverlap(AActor* Actor)
Context = AS->MakeEffectContext();
Context.AddSourceObject(Actor);
if (InstantEffectClass.Get())
{
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::ApplyOnEndOverlap))
if (InstantEffectClass && InstantEffectUsage == EInstantEffectUsagePolicy::ApplyOnEndOverlap)
{
FGameplayEffectSpecHandle Spec= AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
if (DurationEffectClass)
{
AS->RemoveActiveGameplayEffectBySourceEffect( InstantEffectClass, AS );
}
}
if (DurationEffectClass.Get())
if (Bitfield_IsSet(DurationEffectUsage, EEffectUsagePolicy::ApplyOnEndOverlap))
{
if (Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::ApplyOnEndOverlap))
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( DurationEffectClass, 1.0f, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap))
ActiveDuration = ActiveEffect;
}
if (ActiveDuration.IsValid() && Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
AS->RemoveActiveGameplayEffect(ActiveDuration);
}
if (InfiniteEffectClass)
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
if (Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::ApplyOnEndOverlap))
{
AS->RemoveActiveGameplayEffectBySourceEffect( DurationEffectClass, AS );
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InfiniteEffectClass, 1.0f, Context );
FActiveGameplayEffectHandle ActiveEffect = AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
if (Bitfield_IsSet(InfiniteEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap))
ActiveInfinite = ActiveEffect;
}
}
if (InfiniteEffectClass.Get())
if (ActiveInfinite.IsValid() && Bitfield_IsSet(InfiniteEffectUsage, EEffectUsagePolicy::RemoveOnEndOverlap))
{
if (Bitfield_IsSet(InfiniteEffectUsage, (int32)EEffectUsagePolicy::ApplyOnEndOverlap))
if (ActiveInfinite.IsValid())
AS->RemoveActiveGameplayEffect(ActiveInfinite);
}
}
TArray<FActiveGameplayEffectHandle> EffectsRemoved;
for (ActiveEffectEntry ActiveEffect : ActiveEffectsToRemove)
{
FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context );
AS->ApplyGameplayEffectSpecToSelf( * Spec.Data );
}
if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnEndOverlap))
{
AS->RemoveActiveGameplayEffectBySourceEffect( InfiniteEffectClass, AS );
}
if (ActiveEffect.Value != AS)
continue;
AS->RemoveActiveGameplayEffect(ActiveEffect.Key, 1);
EffectsRemoved.Add(ActiveEffect.Key);
}
RemoveKeys(ActiveEffectsToRemove, EffectsRemoved);
}

View File

@ -2,18 +2,29 @@
#include "GasaCommon.h"
#include "Actors/GasaActor.h"
#include "ActiveGameplayEffectHandle.h"
#include "GameFramework/Actor.h"
#include "GasaEffectActor.generated.h"
struct FActiveGameplayEffectHandle;
UENUM(BlueprintType)
enum class EInstantEffectUsagePolicy : uint8
{
DoNotApply,
ApplyOnOverlap,
ApplyOnEndOverlap,
};
UENUM(BlueprintType, meta = (Bitflags, UseEnumValuesAsMaskValuesInEditor = "true"))
enum class EEffectUsagePolicy : uint8
{
None = 0 UMETA(Hidden),
ApplyOnOverlap = bit(0),
ApplyOnEndOverlap = bit(1),
RemoveOnOverlap = bit(3),
RemoveOnEndOverlap = bit(4),
RemoveOnOverlap = bit(2),
RemoveOnEndOverlap = bit(3),
};
constexpr int32 DefaultEffectUsagePolicy = (int32(EEffectUsagePolicy::RemoveOnEndOverlap));
@ -27,28 +38,34 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> InstantEffectClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = EEffectUsagePolicy))
int32 InstantEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
EInstantEffectUsagePolicy InstantEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> DurationEffectClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = EEffectUsagePolicy))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EEffectUsagePolicy"))
int32 DurationEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
TSubclassOf<UGameplayEffect> InfiniteEffectClass;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = EEffectUsagePolicy))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EEffectUsagePolicy"))
int32 InfiniteEffectUsage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects")
bool bDestroyOnEffectRemoval = false;
bool bDestroyOnEffectRemoval;
TMap<FActiveGameplayEffectHandle, UAbilitySystemComponent*> ActiveEffectsToRemove;
using ActiveEffectEntry = TTuple<FActiveGameplayEffectHandle, UAbilitySystemComponent*>;
FActiveGameplayEffectHandle ActiveDuration;
FActiveGameplayEffectHandle ActiveInfinite;
AGasaEffectActor();
UFUNCTION(BlueprintCallable, Category = "Gameplay Effects")
void ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass );
void ApplyEffectToActor(AActor* Actor, TSubclassOf<UGameplayEffect> EffectClass, bool bRemoveOnEndOverlap = false);
UFUNCTION(BlueprintCallable)
void OnOverlap(AActor* Actor);

View File

@ -45,7 +45,7 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework")
EGameFrameworkState GameFrameworkState;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework", meta=(Bitmask, BitmaskEnum = EGameFrameworkClassFlag))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameFramework", meta=(Bitmask, BitmaskEnum = "/Script/Gasa.EGameFrameworkClassFlag"))
int32 GameFrameworkClassesState;
UFUNCTION(BlueprintCallable, Category="GameFramework")

View File

@ -80,13 +80,30 @@ namespace Gasa
{
inline
bool Bitfield_IsSet(int32 Bitfield, int32 Bitmask) {
int32 Result = Bitmask == (Bitfield & Bitmask);
return scast(bool, Result);
bool Result = Bitmask == (Bitfield & Bitmask);
return Result;
}
inline
bool Bitfield_IsSetExactly(int32 Bitfield, int32 Bitmask)
{
bool Result = Bitfield == (Bitfield & Bitmask);
return Result;
}
inline void Bitfield_Set ( int32& Bitfield, int32 BitsToAdd ) { Bitfield |= BitsToAdd; }
inline void Bitfield_Remove( int32& Bitfield, int32 BitsToRemove ) { Bitfield &= (! BitsToRemove); }
inline void Bitfield_Toggle( int32& Bitfield, int32 Bitmask ) { Bitfield ^= Bitmask; }
template<typename EnumType>
inline
bool Bitfield_IsSet(int32 Bitfield, EnumType Mask)
{
bool Result = int32(Mask) == (Bitfield & int32(Mask));
return Result;
}
template<typename EnumType> inline void Bitfield_Set ( int32& Bitfield, EnumType BitToAdd ) { Bitfield |= int32(BitToAdd); }
template<typename EnumType> inline void Bitfield_Remove( int32& Bitfield, EnumType BitToRemove ) { Bitfield &= (! int32(BitToRemove)); }
template<typename EnumType> inline void Bitfield_Toggle( int32& Bitfield, EnumType BitToToggle ) { Bitfield ^= int32(BitToToggle); }
}
#pragma endregion Bitfields

View File

View File

@ -0,0 +1,14 @@
#pragma once
#include "GasaCommon.h"
template<typename KeyType, typename ValueType>
inline
void RemoveKeys(TMap<KeyType, ValueType> Map, TArray<KeyType> Keys)
{
for (KeyType& Key : Keys )
{
Map.Remove(Key);
}
}