diff --git a/Project/Binaries/Win64/UnrealEditor-GasaEditor.dll b/Project/Binaries/Win64/UnrealEditor-GasaEditor.dll index 60e8a91..4d654af 100644 --- a/Project/Binaries/Win64/UnrealEditor-GasaEditor.dll +++ b/Project/Binaries/Win64/UnrealEditor-GasaEditor.dll @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a08006e998e3135977ef15159599f237160d46f7bcee5853af42580a568a7464 +oid sha256:ef0d986b42a1e5d7d498a61a2581c529981967d5586dcd1b7a6b49253204b7dc size 79360 diff --git a/Project/Source/Gasa/AbilitySystem/GasaEffectActor.cpp b/Project/Source/Gasa/AbilitySystem/GasaEffectActor.cpp index f52d498..0931380 100644 --- a/Project/Source/Gasa/AbilitySystem/GasaEffectActor.cpp +++ b/Project/Source/Gasa/AbilitySystem/GasaEffectActor.cpp @@ -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("Root"); - InstantEffectUsage = DefaultEffectUsagePolicy; + InstantEffectUsage = EInstantEffectUsagePolicy::DoNotApply; DurationEffectUsage = DefaultEffectUsagePolicy; InfiniteEffectUsage = DefaultEffectUsagePolicy; + + bDestroyOnEffectRemoval = false; } -void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf EffectClass) +void AGasaEffectActor::ApplyEffectToActor(AActor* Actor, TSubclassOf 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 ); + FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( EffectClass, 1.0f, Context ); + 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 (InstantEffectClass && InstantEffectUsage == EInstantEffectUsagePolicy::ApplyOnOverlap) { - if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::ApplyOnOverlap)) - { - FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context ); - AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); - } - if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap)) - { - AS->RemoveActiveGameplayEffectBySourceEffect( InstantEffectClass, AS ); - } + FGameplayEffectSpecHandle Spec= AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context ); + AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); } - 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 ); - AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); - } - if (Bitfield_IsSet(InstantEffectUsage, (int32)EEffectUsagePolicy::RemoveOnOverlap)) - { - AS->RemoveActiveGameplayEffectBySourceEffect( DurationEffectClass, AS ); + 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 (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 ); - 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( 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 (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 ); - AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); + FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( DurationEffectClass, 1.0f, Context ); + 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 EffectsRemoved; + for (ActiveEffectEntry ActiveEffect : ActiveEffectsToRemove) { - if (Bitfield_IsSet(DurationEffectUsage, (int32)EEffectUsagePolicy::ApplyOnEndOverlap)) - { - FGameplayEffectSpecHandle Spec = AS->MakeOutgoingSpec( InstantEffectClass, 1.0f, Context ); - AS->ApplyGameplayEffectSpecToSelf( * Spec.Data ); - } - 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 ); - } + if (ActiveEffect.Value != AS) + continue; + AS->RemoveActiveGameplayEffect(ActiveEffect.Key, 1); + EffectsRemoved.Add(ActiveEffect.Key); } + RemoveKeys(ActiveEffectsToRemove, EffectsRemoved); } diff --git a/Project/Source/Gasa/AbilitySystem/GasaEffectActor.h b/Project/Source/Gasa/AbilitySystem/GasaEffectActor.h index 5976110..2697ae0 100644 --- a/Project/Source/Gasa/AbilitySystem/GasaEffectActor.h +++ b/Project/Source/Gasa/AbilitySystem/GasaEffectActor.h @@ -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 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 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 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; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Gameplay Effects") + bool bDestroyOnEffectRemoval; + + TMap ActiveEffectsToRemove; + using ActiveEffectEntry = TTuple; + + FActiveGameplayEffectHandle ActiveDuration; + FActiveGameplayEffectHandle ActiveInfinite; + AGasaEffectActor(); UFUNCTION(BlueprintCallable, Category = "Gameplay Effects") - void ApplyEffectToActor(AActor* Actor, TSubclassOf EffectClass ); + void ApplyEffectToActor(AActor* Actor, TSubclassOf EffectClass, bool bRemoveOnEndOverlap = false); UFUNCTION(BlueprintCallable) void OnOverlap(AActor* Actor); diff --git a/Project/Source/Gasa/Game/GasaGameInstance.h b/Project/Source/Gasa/Game/GasaGameInstance.h index 0c401c0..ded896a 100644 --- a/Project/Source/Gasa/Game/GasaGameInstance.h +++ b/Project/Source/Gasa/Game/GasaGameInstance.h @@ -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") diff --git a/Project/Source/Gasa/GasaCommon.h b/Project/Source/Gasa/GasaCommon.h index 3344200..7edf149 100644 --- a/Project/Source/Gasa/GasaCommon.h +++ b/Project/Source/Gasa/GasaCommon.h @@ -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 + inline + bool Bitfield_IsSet(int32 Bitfield, EnumType Mask) + { + bool Result = int32(Mask) == (Bitfield & int32(Mask)); + return Result; + } + template inline void Bitfield_Set ( int32& Bitfield, EnumType BitToAdd ) { Bitfield |= int32(BitToAdd); } + template inline void Bitfield_Remove( int32& Bitfield, EnumType BitToRemove ) { Bitfield &= (! int32(BitToRemove)); } + template inline void Bitfield_Toggle( int32& Bitfield, EnumType BitToToggle ) { Bitfield ^= int32(BitToToggle); } } #pragma endregion Bitfields diff --git a/Project/Source/Gasa/GasaContainers.cpp b/Project/Source/Gasa/GasaContainers.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Project/Source/Gasa/GasaContainers.h b/Project/Source/Gasa/GasaContainers.h new file mode 100644 index 0000000..770212d --- /dev/null +++ b/Project/Source/Gasa/GasaContainers.h @@ -0,0 +1,14 @@ +#pragma once + +#include "GasaCommon.h" + +template +inline +void RemoveKeys(TMap Map, TArray Keys) +{ + for (KeyType& Key : Keys ) + { + Map.Remove(Key); + } +} + \ No newline at end of file