44. Infinite Effect Application and Removal

This commit is contained in:
Edward R. Gonzalez 2024-04-24 16:21:22 -04:00
parent a604117e95
commit 035ad8de6f
10 changed files with 133 additions and 78 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Project/Content/Levels/StartupMap.umap (Stored with Git LFS)

Binary file not shown.

View File

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

View File

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

View File

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

View File

@ -80,13 +80,30 @@ namespace Gasa
{ {
inline inline
bool Bitfield_IsSet(int32 Bitfield, int32 Bitmask) { bool Bitfield_IsSet(int32 Bitfield, int32 Bitmask) {
int32 Result = Bitmask == (Bitfield & Bitmask); bool Result = Bitmask == (Bitfield & Bitmask);
return scast(bool, Result); 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_Set ( int32& Bitfield, int32 BitsToAdd ) { Bitfield |= BitsToAdd; }
inline void Bitfield_Remove( int32& Bitfield, int32 BitsToRemove ) { Bitfield &= (! BitsToRemove); } inline void Bitfield_Remove( int32& Bitfield, int32 BitsToRemove ) { Bitfield &= (! BitsToRemove); }
inline void Bitfield_Toggle( int32& Bitfield, int32 Bitmask ) { Bitfield ^= Bitmask; } 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 #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);
}
}